Json database refactoring
This commit is contained in:
@@ -1,15 +1,7 @@
|
|||||||
package database
|
package database
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"git.phc.dm.unipi.it/phc/storage/store"
|
|
||||||
"git.phc.dm.unipi.it/phc/storage/utils"
|
|
||||||
"golang.org/x/exp/slices"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type MonitorWidget struct {
|
type MonitorWidget struct {
|
||||||
@@ -53,391 +45,3 @@ type Database interface {
|
|||||||
SetBucketObject(bucket, id string, r io.Reader) error
|
SetBucketObject(bucket, id string, r io.Reader) error
|
||||||
DeleteBucketObject(bucket, id string) error
|
DeleteBucketObject(bucket, id string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type JsonBucketSettings struct {
|
|
||||||
Path string `json:"path"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type jsonBucket struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Objects []string `json:"objects"`
|
|
||||||
|
|
||||||
Settings *JsonBucketSettings `json:"settings"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type jsonDB struct {
|
|
||||||
file string
|
|
||||||
|
|
||||||
PrefixSize int `json:"prefixSize"`
|
|
||||||
|
|
||||||
DashboardState DashboardState `json:"dashboardState"`
|
|
||||||
Buckets map[string]*jsonBucket `json:"buckets"`
|
|
||||||
|
|
||||||
APIKeys []string `json:"api-keys"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewJSON(file string) Database {
|
|
||||||
db := &jsonDB{
|
|
||||||
file: file,
|
|
||||||
PrefixSize: 2,
|
|
||||||
DashboardState: DashboardState{
|
|
||||||
Widgets: []MonitorWidget{},
|
|
||||||
},
|
|
||||||
Buckets: map[string]*jsonBucket{},
|
|
||||||
APIKeys: []string{},
|
|
||||||
}
|
|
||||||
|
|
||||||
err := db.load()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return db
|
|
||||||
}
|
|
||||||
|
|
||||||
// func writeTransaction[T any](db *jsonDB, transactionFunc func(db *jsonDB) (T, error)) (T, error) {
|
|
||||||
// var zero T
|
|
||||||
// if err := db.load(); err != nil {
|
|
||||||
// return zero, err
|
|
||||||
// }
|
|
||||||
// v, err := transactionFunc(db)
|
|
||||||
// if err := db.store(); err != nil {
|
|
||||||
// return zero, err
|
|
||||||
// }
|
|
||||||
// return v, err
|
|
||||||
// }
|
|
||||||
|
|
||||||
func (db *jsonDB) setup() error {
|
|
||||||
if _, err := os.Stat(db.file); !os.IsNotExist(err) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("missing %q, creating empty database file", db.file)
|
|
||||||
|
|
||||||
f, err := os.Create(db.file)
|
|
||||||
defer f.Close()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
enc := json.NewEncoder(f)
|
|
||||||
enc.SetIndent("", " ")
|
|
||||||
if err := enc.Encode(&db); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *jsonDB) store() error {
|
|
||||||
f, err := os.Create(db.file)
|
|
||||||
defer f.Close()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
enc := json.NewEncoder(f)
|
|
||||||
enc.SetIndent("", " ")
|
|
||||||
if err := enc.Encode(&db); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *jsonDB) load() error {
|
|
||||||
if err := db.setup(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
f, err := os.Open(db.file)
|
|
||||||
defer f.Close()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := json.NewDecoder(f).Decode(&db); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *jsonDB) GetDashboardState() (DashboardState, error) {
|
|
||||||
if err := db.load(); err != nil {
|
|
||||||
return DashboardState{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return db.DashboardState, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *jsonDB) SetDashboardState(state DashboardState) error {
|
|
||||||
if err := db.load(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
db.DashboardState = state
|
|
||||||
|
|
||||||
if err := db.store(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *jsonDB) CreateAPIKey() (string, error) {
|
|
||||||
if err := db.load(); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
key := utils.GenerateRandomString(32)
|
|
||||||
db.APIKeys = append(db.APIKeys, key)
|
|
||||||
|
|
||||||
if err := db.store(); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return key, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *jsonDB) AllAPIKeys() ([]string, error) {
|
|
||||||
if err := db.load(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return db.APIKeys, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *jsonDB) CheckAPIKey(key string) error {
|
|
||||||
if err := db.load(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !slices.Contains(db.APIKeys, key) {
|
|
||||||
return fmt.Errorf("the given api key %q is invalid", key)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *jsonDB) RemoveAPIKey(key string) error {
|
|
||||||
if err := db.load(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
i := slices.Index(db.APIKeys, key)
|
|
||||||
if i == -1 {
|
|
||||||
return fmt.Errorf("the given api key %q is invalid", key)
|
|
||||||
}
|
|
||||||
|
|
||||||
db.APIKeys = append(db.APIKeys[:i], db.APIKeys[i+1:]...)
|
|
||||||
|
|
||||||
if err := db.store(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Bucket Methods
|
|
||||||
//
|
|
||||||
|
|
||||||
func (db *jsonDB) CreateBucket(bucket string, settings any) error {
|
|
||||||
if err := db.load(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, found := db.Buckets[bucket]; found {
|
|
||||||
return fmt.Errorf("bucket named %q already present", bucket)
|
|
||||||
}
|
|
||||||
|
|
||||||
bi := &jsonBucket{
|
|
||||||
Name: bucket,
|
|
||||||
Settings: &JsonBucketSettings{
|
|
||||||
Path: bucket + "/",
|
|
||||||
},
|
|
||||||
Objects: []string{},
|
|
||||||
}
|
|
||||||
|
|
||||||
if settings != nil {
|
|
||||||
bi.Settings = settings.(*JsonBucketSettings)
|
|
||||||
}
|
|
||||||
|
|
||||||
db.Buckets[bucket] = bi
|
|
||||||
|
|
||||||
if err := db.store(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *jsonDB) GetBucketSettings(bucket string) (any, error) {
|
|
||||||
if err := db.load(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, found := db.Buckets[bucket]; !found {
|
|
||||||
return nil, fmt.Errorf("bucket named %q not found", bucket)
|
|
||||||
}
|
|
||||||
|
|
||||||
return db.Buckets[bucket].Settings, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *jsonDB) SetBucketSettings(bucket string, settings any) error {
|
|
||||||
if err := db.load(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
b, found := db.Buckets[bucket]
|
|
||||||
if !found {
|
|
||||||
return fmt.Errorf("bucket named %q not found", bucket)
|
|
||||||
}
|
|
||||||
|
|
||||||
b.Settings = settings.(*JsonBucketSettings)
|
|
||||||
|
|
||||||
log.Printf("[Warning] Bucket %q settings changed but bucket migration is not yet implemented (move the folder yourself)", bucket)
|
|
||||||
|
|
||||||
if err := db.store(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *jsonDB) DeleteBucket(bucket string) error {
|
|
||||||
if err := db.load(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, found := db.Buckets[bucket]; !found {
|
|
||||||
return fmt.Errorf("bucket named %q not found", bucket)
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(db.Buckets, bucket)
|
|
||||||
|
|
||||||
log.Printf("The bucket named %q was removed but its files are still on disk", bucket)
|
|
||||||
|
|
||||||
if err := db.store(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *jsonDB) AllBuckets() ([]string, error) {
|
|
||||||
if err := db.load(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
buckets := make([]string, 0, len(db.Buckets))
|
|
||||||
|
|
||||||
for _, b := range db.Buckets {
|
|
||||||
buckets = append(buckets, b.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return buckets, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *jsonDB) CreateBucketObject(bucket string, r io.Reader) (string, error) {
|
|
||||||
if err := db.load(); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
b, found := db.Buckets[bucket]
|
|
||||||
if !found {
|
|
||||||
return "", fmt.Errorf("bucket named %q not found", bucket)
|
|
||||||
}
|
|
||||||
|
|
||||||
id, err := store.Create(b.Settings.Path, db.PrefixSize, r)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
b.Objects = append(b.Objects, id)
|
|
||||||
|
|
||||||
if err := db.store(); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return id, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *jsonDB) SetBucketObject(bucket, id string, r io.Reader) error {
|
|
||||||
if err := db.load(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
b, found := db.Buckets[bucket]
|
|
||||||
if !found {
|
|
||||||
return fmt.Errorf("bucket named %q not found", bucket)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := db.store(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return store.Update(b.Settings.Path, db.PrefixSize, id, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *jsonDB) GetBucketObject(bucket, id string, w io.Writer) error {
|
|
||||||
if err := db.load(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
b, found := db.Buckets[bucket]
|
|
||||||
if !found {
|
|
||||||
return fmt.Errorf("bucket named %q not found", bucket)
|
|
||||||
}
|
|
||||||
|
|
||||||
return store.Read(b.Settings.Path, db.PrefixSize, id, w)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *jsonDB) DeleteBucketObject(bucket, id string) error {
|
|
||||||
if err := db.load(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
b, found := db.Buckets[bucket]
|
|
||||||
if !found {
|
|
||||||
return fmt.Errorf("bucket named %q not found", bucket)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := store.Delete(b.Settings.Path, db.PrefixSize, id); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
i := slices.Index(b.Objects, id)
|
|
||||||
b.Objects = append(b.Objects[:i], b.Objects[i+1:]...)
|
|
||||||
|
|
||||||
if err := db.store(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *jsonDB) AllBucketObjects(bucket string) ([]string, error) {
|
|
||||||
if err := db.load(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
b, found := db.Buckets[bucket]
|
|
||||||
if !found {
|
|
||||||
return nil, fmt.Errorf("bucket named %q not found", bucket)
|
|
||||||
}
|
|
||||||
|
|
||||||
objects, err := store.All(b.Settings.Path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
b.Objects = objects
|
|
||||||
|
|
||||||
if err := db.store(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return b.Objects, nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,379 @@
|
|||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"git.phc.dm.unipi.it/phc/storage/store"
|
||||||
|
"git.phc.dm.unipi.it/phc/storage/utils"
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
|
)
|
||||||
|
|
||||||
|
type JsonBucketSettings struct {
|
||||||
|
Path string `json:"path"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type jsonBucket struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Objects []string `json:"objects"`
|
||||||
|
|
||||||
|
Settings *JsonBucketSettings `json:"settings"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type jsonDB struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
|
||||||
|
file string
|
||||||
|
|
||||||
|
PrefixSize int `json:"prefixSize"`
|
||||||
|
|
||||||
|
DashboardState DashboardState `json:"dashboardState"`
|
||||||
|
Buckets map[string]*jsonBucket `json:"buckets"`
|
||||||
|
|
||||||
|
APIKeys []string `json:"api-keys"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewJSON(file string) Database {
|
||||||
|
db := &jsonDB{
|
||||||
|
file: file,
|
||||||
|
PrefixSize: 2,
|
||||||
|
DashboardState: DashboardState{
|
||||||
|
Widgets: []MonitorWidget{},
|
||||||
|
},
|
||||||
|
Buckets: map[string]*jsonBucket{},
|
||||||
|
APIKeys: []string{},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := db.load()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return db
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *jsonDB) setup() error {
|
||||||
|
if _, err := os.Stat(db.file); !os.IsNotExist(err) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("missing %q, creating empty database file", db.file)
|
||||||
|
|
||||||
|
f, err := os.Create(db.file)
|
||||||
|
defer f.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
enc := json.NewEncoder(f)
|
||||||
|
enc.SetIndent("", " ")
|
||||||
|
if err := enc.Encode(&db); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *jsonDB) store() error {
|
||||||
|
f, err := os.Create(db.file)
|
||||||
|
defer f.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
enc := json.NewEncoder(f)
|
||||||
|
enc.SetIndent("", " ")
|
||||||
|
if err := enc.Encode(&db); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *jsonDB) load() error {
|
||||||
|
if err := db.setup(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Open(db.file)
|
||||||
|
defer f.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.NewDecoder(f).Decode(&db); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func withValue[T any](
|
||||||
|
transactorFunc func(func() error) error,
|
||||||
|
workFunc func() (T, error)) (T, error) {
|
||||||
|
|
||||||
|
var value T
|
||||||
|
|
||||||
|
if err := transactorFunc(func() error {
|
||||||
|
var err error
|
||||||
|
value, err = workFunc()
|
||||||
|
|
||||||
|
return err
|
||||||
|
}); err != nil {
|
||||||
|
var zero T
|
||||||
|
return zero, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *jsonDB) writeTransaction(workFunc func() error) error {
|
||||||
|
db.mu.Lock()
|
||||||
|
defer db.mu.Unlock()
|
||||||
|
|
||||||
|
if err := db.load(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := workFunc(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.store(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *jsonDB) readTransaction(transactionFunc func() error) error {
|
||||||
|
db.mu.Lock()
|
||||||
|
defer db.mu.Unlock()
|
||||||
|
|
||||||
|
if err := db.load(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := transactionFunc(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *jsonDB) GetDashboardState() (DashboardState, error) {
|
||||||
|
return withValue(db.readTransaction, func() (DashboardState, error) {
|
||||||
|
return db.DashboardState, nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *jsonDB) SetDashboardState(state DashboardState) error {
|
||||||
|
if err := db.load(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
db.DashboardState = state
|
||||||
|
|
||||||
|
if err := db.store(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *jsonDB) CreateAPIKey() (string, error) {
|
||||||
|
return withValue(db.writeTransaction, func() (string, error) {
|
||||||
|
key := utils.GenerateRandomString(32)
|
||||||
|
db.APIKeys = append(db.APIKeys, key)
|
||||||
|
|
||||||
|
return key, nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *jsonDB) AllAPIKeys() ([]string, error) {
|
||||||
|
return withValue(db.readTransaction, func() ([]string, error) {
|
||||||
|
return db.APIKeys, nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *jsonDB) CheckAPIKey(key string) error {
|
||||||
|
return db.readTransaction(func() error {
|
||||||
|
if !slices.Contains(db.APIKeys, key) {
|
||||||
|
return fmt.Errorf("the given api key %q is invalid", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *jsonDB) RemoveAPIKey(key string) error {
|
||||||
|
return db.writeTransaction(func() error {
|
||||||
|
i := slices.Index(db.APIKeys, key)
|
||||||
|
if i == -1 {
|
||||||
|
return fmt.Errorf("the given api key %q is invalid", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
db.APIKeys = append(db.APIKeys[:i], db.APIKeys[i+1:]...)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Bucket Methods
|
||||||
|
//
|
||||||
|
|
||||||
|
func (db *jsonDB) CreateBucket(bucket string, settings any) error {
|
||||||
|
return db.writeTransaction(func() error {
|
||||||
|
if _, found := db.Buckets[bucket]; found {
|
||||||
|
return fmt.Errorf("bucket named %q already present", bucket)
|
||||||
|
}
|
||||||
|
|
||||||
|
bi := &jsonBucket{
|
||||||
|
Name: bucket,
|
||||||
|
Settings: &JsonBucketSettings{
|
||||||
|
Path: bucket + "/",
|
||||||
|
},
|
||||||
|
Objects: []string{},
|
||||||
|
}
|
||||||
|
|
||||||
|
if settings != nil {
|
||||||
|
bi.Settings = settings.(*JsonBucketSettings)
|
||||||
|
}
|
||||||
|
|
||||||
|
db.Buckets[bucket] = bi
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *jsonDB) GetBucketSettings(bucket string) (any, error) {
|
||||||
|
return withValue(db.readTransaction, func() (any, error) {
|
||||||
|
if _, found := db.Buckets[bucket]; !found {
|
||||||
|
return nil, fmt.Errorf("bucket named %q not found", bucket)
|
||||||
|
}
|
||||||
|
|
||||||
|
return db.Buckets[bucket].Settings, nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *jsonDB) SetBucketSettings(bucket string, settings any) error {
|
||||||
|
return db.writeTransaction(func() error {
|
||||||
|
b, found := db.Buckets[bucket]
|
||||||
|
if !found {
|
||||||
|
return fmt.Errorf("bucket named %q not found", bucket)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.Settings = settings.(*JsonBucketSettings)
|
||||||
|
|
||||||
|
log.Printf("[Warning] Bucket %q settings changed but bucket migration is not yet implemented (move the folder yourself)", bucket)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *jsonDB) DeleteBucket(bucket string) error {
|
||||||
|
return db.writeTransaction(func() error {
|
||||||
|
if _, found := db.Buckets[bucket]; !found {
|
||||||
|
return fmt.Errorf("bucket named %q not found", bucket)
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(db.Buckets, bucket)
|
||||||
|
|
||||||
|
log.Printf("The bucket named %q was removed but its files are still on disk", bucket)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *jsonDB) AllBuckets() ([]string, error) {
|
||||||
|
return withValue(db.readTransaction, func() ([]string, error) {
|
||||||
|
buckets := make([]string, 0, len(db.Buckets))
|
||||||
|
|
||||||
|
for _, b := range db.Buckets {
|
||||||
|
buckets = append(buckets, b.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return buckets, nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *jsonDB) CreateBucketObject(bucket string, r io.Reader) (string, error) {
|
||||||
|
return withValue(db.writeTransaction, func() (string, error) {
|
||||||
|
b, found := db.Buckets[bucket]
|
||||||
|
if !found {
|
||||||
|
return "", fmt.Errorf("bucket named %q not found", bucket)
|
||||||
|
}
|
||||||
|
|
||||||
|
id, err := store.Create(b.Settings.Path, db.PrefixSize, r)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
b.Objects = append(b.Objects, id)
|
||||||
|
|
||||||
|
return id, err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *jsonDB) SetBucketObject(bucket, id string, r io.Reader) error {
|
||||||
|
return db.writeTransaction(func() error {
|
||||||
|
b, found := db.Buckets[bucket]
|
||||||
|
if !found {
|
||||||
|
return fmt.Errorf("bucket named %q not found", bucket)
|
||||||
|
}
|
||||||
|
|
||||||
|
return store.Update(b.Settings.Path, db.PrefixSize, id, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *jsonDB) GetBucketObject(bucket, id string, w io.Writer) error {
|
||||||
|
return db.readTransaction(func() error {
|
||||||
|
b, found := db.Buckets[bucket]
|
||||||
|
if !found {
|
||||||
|
return fmt.Errorf("bucket named %q not found", bucket)
|
||||||
|
}
|
||||||
|
|
||||||
|
return store.Read(b.Settings.Path, db.PrefixSize, id, w)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *jsonDB) DeleteBucketObject(bucket, id string) error {
|
||||||
|
return db.writeTransaction(func() error {
|
||||||
|
b, found := db.Buckets[bucket]
|
||||||
|
if !found {
|
||||||
|
return fmt.Errorf("bucket named %q not found", bucket)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := store.Delete(b.Settings.Path, db.PrefixSize, id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
i := slices.Index(b.Objects, id)
|
||||||
|
b.Objects = append(b.Objects[:i], b.Objects[i+1:]...)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *jsonDB) AllBucketObjects(bucket string) ([]string, error) {
|
||||||
|
return withValue(db.writeTransaction, func() ([]string, error) {
|
||||||
|
b, found := db.Buckets[bucket]
|
||||||
|
if !found {
|
||||||
|
return nil, fmt.Errorf("bucket named %q not found", bucket)
|
||||||
|
}
|
||||||
|
|
||||||
|
objects, err := store.All(b.Settings.Path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
b.Objects = objects
|
||||||
|
|
||||||
|
return b.Objects, nil
|
||||||
|
})
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user