diff --git a/src/fileinfostore/file_info_store.go b/src/fileinfostore/file_info_store.go new file mode 100644 index 0000000..50e7d22 --- /dev/null +++ b/src/fileinfostore/file_info_store.go @@ -0,0 +1,52 @@ +package userstore + +import ( + "github.com/ihexxa/quickshare/src/kvstore" +) + +const ( + InitNs = "Init" + SharingNs = "sharing" + InitTimeKey = "initTime" +) + +type IFileInfoStore interface { + AddSharing(dirPath string) error + DelSharing(dirPath string) error + ListSharings(prefix string) (map[string]bool, error) +} + +type FileInfoStore struct { + store kvstore.IKVStore +} + +func NewFileInfoStore(store kvstore.IKVStore) (*FileInfoStore, error) { + _, ok := store.GetStringIn(InitNs, InitTimeKey) + if !ok { + var err error + for _, nsName := range []string{ + InitNs, + SharingNs, + } { + if err = store.AddNamespace(nsName); err != nil { + return nil, err + } + } + } + + return &FileInfoStore{ + store: store, + }, nil +} + +func (us *FileInfoStore) AddSharing(dirPath string) error { + return us.store.SetBoolIn(SharingNs, dirPath, true) +} + +func (us *FileInfoStore) DelSharing(dirPath string) error { + return us.store.DelBoolIn(SharingNs, dirPath) +} + +func (us *FileInfoStore) ListSharings(prefix string) (map[string]bool, error) { + return us.store.ListBoolsByPrefixIn(prefix, SharingNs) +} diff --git a/src/fileinfostore/file_info_store_test.go b/src/fileinfostore/file_info_store_test.go new file mode 100644 index 0000000..848b7f0 --- /dev/null +++ b/src/fileinfostore/file_info_store_test.go @@ -0,0 +1,70 @@ +package userstore + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/ihexxa/quickshare/src/kvstore/boltdbpvd" +) + +func TestUserStores(t *testing.T) { + + testSharingMethods := func(t *testing.T, store IFileInfoStore) { + dirPaths := []string{"admin/path1", "admin/path1/path2"} + var err error + for _, dirPath := range dirPaths { + err = store.AddSharing(dirPath) + if err != nil { + t.Fatal(err) + } + } + + prefix := "admin" + sharingMap, err := store.ListSharings(prefix) + if err != nil { + t.Fatal(err) + } + + for _, sharingDir := range dirPaths { + if !sharingMap[sharingDir] { + t.Fatalf("sharing(%s) not found", sharingDir) + } + } + + for _, dirPath := range dirPaths { + err = store.DelSharing(dirPath) + if err != nil { + t.Fatal(err) + } + } + + sharingMap, err = store.ListSharings(prefix) + if err != nil { + t.Fatal(err) + } + for _, dirPath := range dirPaths { + if sharingMap[dirPath] { + t.Fatalf("sharing(%s) should not exist", dirPath) + } + } + } + + t.Run("testing FileInfoStore", func(t *testing.T) { + rootPath, err := ioutil.TempDir("./", "quickshare_userstore_test_") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(rootPath) + + kvstore := boltdbpvd.New(rootPath, 1024) + defer kvstore.Close() + + store, err := NewFileInfoStore(kvstore) + if err != nil { + t.Fatal("fail to new kvstore", err) + } + + testSharingMethods(t, store) + }) +} diff --git a/src/kvstore/boltdbpvd/provider.go b/src/kvstore/boltdbpvd/provider.go index 671ca12..055ced0 100644 --- a/src/kvstore/boltdbpvd/provider.go +++ b/src/kvstore/boltdbpvd/provider.go @@ -1,6 +1,7 @@ package boltdbpvd import ( + "bytes" "encoding/binary" "errors" "fmt" @@ -154,6 +155,25 @@ func (bp *BoltPvd) ListBoolsIn(ns string) (map[string]bool, error) { return list, err } +func (bp *BoltPvd) ListBoolsByPrefixIn(prefix, ns string) (map[string]bool, error) { + results := map[string]bool{} + + err := bp.db.View(func(tx *bolt.Tx) error { + b := tx.Bucket([]byte(ns)).Cursor() + if b == nil { + return ErrBucketNotFound + } + + prefixBytes := []byte(prefix) + for k, _ := b.Seek(prefixBytes); k != nil && bytes.HasPrefix(k, prefixBytes); k, _ = b.Next() { + results[string(k)] = true + } + return nil + }) + + return results, err +} + func (bp *BoltPvd) GetInt(key string) (int, bool) { x, ok := bp.GetInt64(key) return int(x), ok diff --git a/src/kvstore/kvstore_interface.go b/src/kvstore/kvstore_interface.go index ddbcfce..9de7505 100644 --- a/src/kvstore/kvstore_interface.go +++ b/src/kvstore/kvstore_interface.go @@ -17,6 +17,7 @@ type IKVStore interface { DelBoolIn(ns, key string) error ListBools() (map[string]bool, error) ListBoolsIn(ns string) (map[string]bool, error) + ListBoolsByPrefixIn(prefix, ns string) (map[string]bool, error) GetInt(key string) (int, bool) SetInt(key string, val int) error DelInt(key string) error