fix(files): add boltdb store and refactor files handlers

This commit is contained in:
hexxa 2022-03-05 00:16:04 +08:00 committed by Hexxa
parent 044cdea1d4
commit 17b4544487
19 changed files with 751 additions and 402 deletions

View file

@ -0,0 +1,377 @@
package boltstore
import (
"encoding/json"
"errors"
"fmt"
"github.com/boltdb/bolt"
"github.com/ihexxa/quickshare/src/db"
)
type BoltStore struct {
boltdb *bolt.DB
}
func NewBoltStore(boltdb *bolt.DB) (*BoltStore, error) {
bs := &BoltStore{
boltdb: boltdb,
}
return bs, nil
}
func (bs *BoltStore) getUserInfo(tx *bolt.Tx, userID uint64) (*db.User, error) {
var err error
usersBucket := tx.Bucket([]byte(db.UsersNs))
if usersBucket == nil {
return nil, db.ErrBucketNotFound
}
uidStr := fmt.Sprint(userID)
infoBytes := usersBucket.Get([]byte(uidStr))
if infoBytes == nil {
return nil, db.ErrKeyNotFound
}
userInfo := &db.User{}
err = json.Unmarshal(infoBytes, userInfo)
if err != nil {
return nil, err
} else if userInfo.ID != userID {
return nil, fmt.Errorf("user id key(%d) info(%d) does match", userID, userInfo.ID)
}
return userInfo, nil
}
func (bs *BoltStore) setUserInfo(tx *bolt.Tx, userID uint64, userInfo *db.User) error {
var err error
usersBucket := tx.Bucket([]byte(db.UsersNs))
if usersBucket == nil {
return db.ErrBucketNotFound
}
userInfoBytes, err := json.Marshal(userInfo)
if err != nil {
return err
}
uidStr := fmt.Sprint(userID)
return usersBucket.Put([]byte(uidStr), userInfoBytes)
}
func (bs *BoltStore) getUploadInfo(tx *bolt.Tx, userID uint64, itemPath string) (*db.UploadInfo, error) {
var err error
uidStr := fmt.Sprint(userID)
userUploadNS := db.UploadNS(uidStr)
uploadInfoBucket := tx.Bucket([]byte(userUploadNS))
if uploadInfoBucket == nil {
return nil, bolt.ErrBucketNotFound
}
uploadInfoBytes := uploadInfoBucket.Get([]byte(itemPath))
if uploadInfoBytes == nil {
return nil, db.ErrKeyNotFound
}
uploadInfo := &db.UploadInfo{}
err = json.Unmarshal(uploadInfoBytes, uploadInfo)
if err != nil {
return nil, err
}
return uploadInfo, nil
}
func (bs *BoltStore) setUploadInfo(tx *bolt.Tx, userID uint64, uploadPath string, uploadInfo *db.UploadInfo, overWrite bool) error {
var err error
uidStr := fmt.Sprint(userID)
userUploadNS := db.UploadNS(uidStr)
uploadInfoBucket := tx.Bucket([]byte(userUploadNS))
if uploadInfoBucket == nil {
uploadInfoBucket, err = tx.CreateBucket([]byte(userUploadNS))
if err != nil {
return err
}
}
existingInfo := uploadInfoBucket.Get([]byte(uploadPath))
if existingInfo != nil && !overWrite {
return db.ErrCreateExisting
}
uploadInfoBytes, err := json.Marshal(uploadInfo)
if err != nil {
return err
}
return uploadInfoBucket.Put([]byte(uploadPath), uploadInfoBytes)
}
func (bs *BoltStore) getFileInfo(tx *bolt.Tx, userID uint64, itemPath string) (*db.FileInfo, error) {
var err error
fileInfoBucket := tx.Bucket([]byte(db.InfoNs))
if fileInfoBucket == nil {
return nil, db.ErrBucketNotFound
}
fileInfoBytes := fileInfoBucket.Get([]byte(itemPath))
if fileInfoBytes == nil {
return nil, db.ErrKeyNotFound
}
fileInfo := &db.FileInfo{}
err = json.Unmarshal(fileInfoBytes, fileInfo)
if err != nil {
return nil, err
}
return fileInfo, nil
}
func (bs *BoltStore) setFileInfo(tx *bolt.Tx, userID uint64, itemPath string, fileInfo *db.FileInfo) error {
var err error
fileInfoBucket := tx.Bucket([]byte(db.InfoNs))
if fileInfoBucket == nil {
return db.ErrBucketNotFound
}
fileInfoBytes, err := json.Marshal(fileInfo)
if err != nil {
return err
}
return fileInfoBucket.Put([]byte(itemPath), fileInfoBytes)
}
func (bs *BoltStore) AddUploadInfos(userID uint64, tmpPath, filePath string, info *db.FileInfo) error {
return bs.boltdb.Update(func(tx *bolt.Tx) error {
var err error
// check space quota
userInfo, err := bs.getUserInfo(tx, userID)
if err != nil {
return err
}
if userInfo.UsedSpace+info.Size > int64(userInfo.Quota.SpaceLimit) {
return errors.New("space limit is reached")
}
// update used space
userInfo.UsedSpace += info.Size
err = bs.setUserInfo(tx, userID, userInfo)
if err != nil {
return err
}
// add upload info
uploadInfo := &db.UploadInfo{
RealFilePath: filePath,
Size: info.Size,
Uploaded: 0,
}
return bs.setUploadInfo(tx, userID, tmpPath, uploadInfo, false)
})
}
func (bs *BoltStore) DelUploadingInfos(userID uint64, uploadPath string) error {
return bs.boltdb.Update(func(tx *bolt.Tx) error {
var err error
// delete upload info
uidStr := fmt.Sprint(userID)
userUploadNS := db.UploadNS(uidStr)
uploadInfoBucket := tx.Bucket([]byte(userUploadNS))
if uploadInfoBucket == nil {
return db.ErrBucketNotFound
}
uploadInfoBytes := uploadInfoBucket.Get([]byte(uploadPath))
if uploadInfoBytes == nil {
return db.ErrKeyNotFound
}
uploadInfo := &db.UploadInfo{}
err = json.Unmarshal(uploadInfoBytes, uploadInfo)
if err != nil {
return err
}
err = uploadInfoBucket.Delete([]byte(uploadPath))
if err != nil {
return err
}
// decr used space
userInfo, err := bs.getUserInfo(tx, userID)
if err != nil {
return err
}
userInfo.UsedSpace -= uploadInfo.Size
return bs.setUserInfo(tx, userID, userInfo)
})
}
func (bs *BoltStore) MoveUploadingInfos(userID uint64, uploadPath, itemPath string) error {
return bs.boltdb.Update(func(tx *bolt.Tx) error {
var err error
// delete upload info
uidStr := fmt.Sprint(userID)
userUploadNS := db.UploadNS(uidStr)
uploadInfoBucket := tx.Bucket([]byte(userUploadNS))
if uploadInfoBucket == nil {
return db.ErrBucketNotFound
}
uploadInfoBytes := uploadInfoBucket.Get([]byte(uploadPath))
if uploadInfoBytes == nil {
return db.ErrKeyNotFound
}
uploadInfo := &db.UploadInfo{}
err = json.Unmarshal(uploadInfoBytes, uploadInfo)
if err != nil {
return err
}
err = uploadInfoBucket.Delete([]byte(uploadPath))
if err != nil {
return err
}
// create file info
fileInfo := &db.FileInfo{
IsDir: false,
Size: uploadInfo.Size,
}
return bs.setFileInfo(tx, userID, itemPath, fileInfo)
})
}
func (bs *BoltStore) delShareID(tx *bolt.Tx, itemPath string) error {
var err error
shareIDBucket := tx.Bucket([]byte(db.ShareIDNs))
if shareIDBucket == nil {
return db.ErrBucketNotFound
}
shareIDtoDir := map[string]string{}
shareIDBucket.ForEach(func(k, v []byte) error {
shareIDtoDir[string(k)] = string(v)
return nil
})
// because before this version, shareIDs are not removed correctly
// so it iterates all shareIDs and cleans remaining entries
for shareID, shareDir := range shareIDtoDir {
if shareDir == itemPath {
err = shareIDBucket.Delete([]byte(shareID))
if err != nil {
return err
}
}
}
return nil
}
func (bs *BoltStore) DelInfos(userID uint64, itemPath string) error {
return bs.boltdb.Update(func(tx *bolt.Tx) error {
var err error
// delete file info
fileInfoBucket := tx.Bucket([]byte(db.InfoNs))
if fileInfoBucket == nil {
return db.ErrBucketNotFound
}
fileInfoBytes := fileInfoBucket.Get([]byte(itemPath))
if fileInfoBucket == nil {
return db.ErrKeyNotFound
}
fileInfo := &db.FileInfo{}
err = json.Unmarshal(fileInfoBytes, fileInfo)
if err != nil {
return err
}
err = fileInfoBucket.Delete([]byte(itemPath))
if err != nil {
return err
}
// decr used space
userInfo, err := bs.getUserInfo(tx, userID)
if err != nil {
return err
}
userInfo.UsedSpace -= fileInfo.Size
err = bs.setUserInfo(tx, userID, userInfo)
if err != nil {
return err
}
// delete share id
if fileInfo.IsDir {
err = bs.delShareID(tx, itemPath)
if err != nil {
return err
}
}
return nil
})
}
func (bs *BoltStore) MoveInfos(userID uint64, oldPath, newPath string, isDir bool) error {
return bs.boltdb.Update(func(tx *bolt.Tx) error {
var err error
fileInfoBucket := tx.Bucket([]byte(db.InfoNs))
if fileInfoBucket == nil {
return db.ErrBucketNotFound
}
fileInfo, err := bs.getFileInfo(tx, userID, oldPath)
if err != nil {
if errors.Is(err, db.ErrKeyNotFound) && isDir {
// the file info for the dir does not exist
return nil
}
return err
}
// delete old shareID
if isDir {
fileInfo.Shared = false
fileInfo.ShareID = ""
err = bs.delShareID(tx, oldPath)
if err != nil {
return err
}
}
// delete old info
err = fileInfoBucket.Delete([]byte(oldPath))
if err != nil {
return err
}
fmt.Println("\n\n\n4", err)
// add new info
return bs.setFileInfo(tx, userID, newPath, fileInfo)
})
}

View file

@ -1,3 +1,65 @@
package db
const SchemaV2 = "v2" // add size to file info
import (
"errors"
"fmt"
"github.com/ihexxa/quickshare/src/db/sitestore"
)
const (
SchemaV2 = "v2" // add size to file info
UsersNs = "users"
InfoNs = "sharing"
ShareIDNs = "sharingKey"
uploadsPrefix = "uploads"
)
var (
ErrBucketNotFound = errors.New("bucket not found")
ErrKeyNotFound = errors.New("key not found")
ErrCreateExisting = errors.New("create upload info which already exists")
)
type FileInfo struct {
IsDir bool `json:"isDir"`
Shared bool `json:"shared"`
ShareID string `json:"shareID"` // for short url
Sha1 string `json:"sha1"`
Size int64 `json:"size"`
}
type Quota struct {
SpaceLimit int64 `json:"spaceLimit,string"`
UploadSpeedLimit int `json:"uploadSpeedLimit"`
DownloadSpeedLimit int `json:"downloadSpeedLimit"`
}
type Preferences struct {
Bg *sitestore.BgConfig `json:"bg"`
CSSURL string `json:"cssURL"`
LanPackURL string `json:"lanPackURL"`
Lan string `json:"lan"`
}
type User struct {
ID uint64 `json:"id,string"`
Name string `json:"name"`
Pwd string `json:"pwd"`
Role string `json:"role"`
UsedSpace int64 `json:"usedSpace,string"`
Quota *Quota `json:"quota"`
Preferences *Preferences `json:"preferences"`
}
type UploadInfo struct {
RealFilePath string `json:"realFilePath"`
Size int64 `json:"size"`
Uploaded int64 `json:"uploaded"`
}
func UploadNS(user string) string {
return fmt.Sprintf("%s/%s", uploadsPrefix, user)
}

View file

@ -11,12 +11,11 @@ import (
"github.com/ihexxa/quickshare/src/db"
"github.com/ihexxa/quickshare/src/kvstore"
"github.com/ihexxa/quickshare/src/kvstore/boltdbpvd"
)
const (
InitNs = "Init"
InfoNs = "sharing"
ShareIDNs = "sharingKey"
InitTimeKey = "initTime"
SchemaVerKey = "SchemaVersion"
SchemaV1 = "v1"
@ -35,36 +34,29 @@ func IsNotFound(err error) bool {
return err == ErrNotFound
}
type FileInfo struct {
IsDir bool `json:"isDir"`
Shared bool `json:"shared"`
ShareID string `json:"shareID"` // for short url
Sha1 string `json:"sha1"`
Size int64 `json:"size"`
}
type IFileInfoStore interface {
AddSharing(dirPath string) error
DelSharing(dirPath string) error
GetSharing(dirPath string) (bool, bool)
ListSharings(prefix string) (map[string]string, error)
GetInfo(itemPath string) (*FileInfo, error)
SetInfo(itemPath string, info *FileInfo) error
GetInfo(itemPath string) (*db.FileInfo, error)
SetInfo(itemPath string, info *db.FileInfo) error
DelInfo(itemPath string) error
SetSha1(itemPath, sign string) error
GetInfos(itemPaths []string) (map[string]*FileInfo, error)
GetInfos(itemPaths []string) (map[string]*db.FileInfo, error)
GetSharingDir(hashID string) (string, error)
// upload info
AddUploadInfo(user, filePath, tmpPath string, fileSize int64) error
SetUploadInfo(user, filePath string, newUploaded int64) error
GetUploadInfo(user, filePath string) (string, int64, int64, error)
DelUploadInfo(user, filePath string) error
ListUploadInfo(user string) ([]*UploadInfo, error)
ListUploadInfo(user string) ([]*db.UploadInfo, error)
}
type FileInfoStore struct {
mtx *sync.RWMutex
store kvstore.IKVStore
mtx *sync.RWMutex
store kvstore.IKVStore
boltdb boltdbpvd.BoltProvider
}
func migrate(fi *FileInfoStore) error {
@ -77,7 +69,7 @@ func migrate(fi *FileInfoStore) error {
switch ver {
case "v0":
// add ShareID to FileInfos
infoStrs, err := fi.store.ListStringsIn(InfoNs)
infoStrs, err := fi.store.ListStringsIn(db.InfoNs)
if err != nil {
return err
}
@ -103,13 +95,13 @@ func migrate(fi *FileInfoStore) error {
}
shareID = dirShareID
err = fi.store.SetStringIn(ShareIDNs, shareID, itemPath)
err = fi.store.SetStringIn(db.ShareIDNs, shareID, itemPath)
if err != nil {
return err
}
}
newInfo := &FileInfo{
newInfo := &db.FileInfo{
IsDir: infoV0.IsDir,
Shared: infoV0.Shared,
ShareID: shareID,
@ -126,7 +118,7 @@ func migrate(fi *FileInfoStore) error {
}
case "v1":
// add size to file info
infoStrs, err := fi.store.ListStringsIn(InfoNs)
infoStrs, err := fi.store.ListStringsIn(db.InfoNs)
if err != nil {
return err
}
@ -145,7 +137,7 @@ func migrate(fi *FileInfoStore) error {
return fmt.Errorf("list sharing error: %w", err)
}
newInfo := &FileInfo{
newInfo := &db.FileInfo{
IsDir: infoV1.IsDir,
Shared: infoV1.Shared,
ShareID: infoV1.ShareID,
@ -174,8 +166,8 @@ func NewFileInfoStore(store kvstore.IKVStore) (*FileInfoStore, error) {
var err error
for _, nsName := range []string{
InitNs,
InfoNs,
ShareIDNs,
db.InfoNs,
db.ShareIDNs,
} {
if !store.HasNamespace(nsName) {
if err = store.AddNamespace(nsName); err != nil {
@ -184,9 +176,12 @@ func NewFileInfoStore(store kvstore.IKVStore) (*FileInfoStore, error) {
}
}
boltdb := store.(boltdbpvd.BoltProvider)
fi := &FileInfoStore{
store: store,
mtx: &sync.RWMutex{},
store: store,
boltdb: boltdb,
mtx: &sync.RWMutex{},
}
if err = migrate(fi); err != nil {
return nil, err
@ -203,7 +198,7 @@ func (fi *FileInfoStore) AddSharing(dirPath string) error {
if !IsNotFound(err) {
return err
}
info = &FileInfo{
info = &db.FileInfo{
IsDir: true,
}
}
@ -213,7 +208,7 @@ func (fi *FileInfoStore) AddSharing(dirPath string) error {
if err != nil {
return err
}
err = fi.store.SetStringIn(ShareIDNs, shareID, dirPath)
err = fi.store.SetStringIn(db.ShareIDNs, shareID, dirPath)
if err != nil {
return err
}
@ -238,14 +233,14 @@ func (fi *FileInfoStore) DelSharing(dirPath string) error {
// because before this version, shareIDs are not removed correctly
// so it iterates all shareIDs and cleans remaining entries
shareIDtoDir, err := fi.store.ListStringsIn(ShareIDNs)
shareIDtoDir, err := fi.store.ListStringsIn(db.ShareIDNs)
if err != nil {
return err
}
for shareID, shareDir := range shareIDtoDir {
if shareDir == dirPath {
err = fi.store.DelStringIn(ShareIDNs, shareID)
err = fi.store.DelStringIn(db.ShareIDNs, shareID)
if err != nil {
return err
}
@ -270,12 +265,12 @@ func (fi *FileInfoStore) GetSharing(dirPath string) (bool, bool) {
}
func (fi *FileInfoStore) ListSharings(prefix string) (map[string]string, error) {
infoStrs, err := fi.store.ListStringsByPrefixIn(prefix, InfoNs)
infoStrs, err := fi.store.ListStringsByPrefixIn(prefix, db.InfoNs)
if err != nil {
return nil, err
}
info := &FileInfo{}
info := &db.FileInfo{}
sharings := map[string]string{}
for itemPath, infoStr := range infoStrs {
err = json.Unmarshal([]byte(infoStr), info)
@ -291,13 +286,13 @@ func (fi *FileInfoStore) ListSharings(prefix string) (map[string]string, error)
return sharings, nil
}
func (fi *FileInfoStore) GetInfo(itemPath string) (*FileInfo, error) {
infoStr, ok := fi.store.GetStringIn(InfoNs, itemPath)
func (fi *FileInfoStore) GetInfo(itemPath string) (*db.FileInfo, error) {
infoStr, ok := fi.store.GetStringIn(db.InfoNs, itemPath)
if !ok {
return nil, ErrNotFound
}
info := &FileInfo{}
info := &db.FileInfo{}
err := json.Unmarshal([]byte(infoStr), info)
if err != nil {
return nil, fmt.Errorf("get file info: %w", err)
@ -305,8 +300,8 @@ func (fi *FileInfoStore) GetInfo(itemPath string) (*FileInfo, error) {
return info, nil
}
func (fi *FileInfoStore) GetInfos(itemPaths []string) (map[string]*FileInfo, error) {
infos := map[string]*FileInfo{}
func (fi *FileInfoStore) GetInfos(itemPaths []string) (map[string]*db.FileInfo, error) {
infos := map[string]*db.FileInfo{}
for _, itemPath := range itemPaths {
info, err := fi.GetInfo(itemPath)
if err != nil {
@ -321,13 +316,13 @@ func (fi *FileInfoStore) GetInfos(itemPaths []string) (map[string]*FileInfo, err
return infos, nil
}
func (fi *FileInfoStore) SetInfo(itemPath string, info *FileInfo) error {
func (fi *FileInfoStore) SetInfo(itemPath string, info *db.FileInfo) error {
infoStr, err := json.Marshal(info)
if err != nil {
return fmt.Errorf("set file info: %w", err)
}
err = fi.store.SetStringIn(InfoNs, itemPath, string(infoStr))
err = fi.store.SetStringIn(db.InfoNs, itemPath, string(infoStr))
if err != nil {
return fmt.Errorf("set file info: %w", err)
}
@ -335,7 +330,7 @@ func (fi *FileInfoStore) SetInfo(itemPath string, info *FileInfo) error {
}
func (fi *FileInfoStore) DelInfo(itemPath string) error {
return fi.store.DelStringIn(InfoNs, itemPath)
return fi.store.DelStringIn(db.InfoNs, itemPath)
}
func (fi *FileInfoStore) SetSha1(itemPath, sign string) error {
@ -347,7 +342,7 @@ func (fi *FileInfoStore) SetSha1(itemPath, sign string) error {
if !IsNotFound(err) {
return err
}
info = &FileInfo{
info = &db.FileInfo{
IsDir: false,
Shared: false,
}
@ -370,7 +365,7 @@ func (fi *FileInfoStore) getShareID(payload string) (string, error) {
}
shareID := fmt.Sprintf("%x", h.Sum(nil))[:7]
shareDir, ok := fi.store.GetStringIn(ShareIDNs, shareID)
shareDir, ok := fi.store.GetStringIn(db.ShareIDNs, shareID)
if !ok {
return shareID, nil
} else if ok && shareDir == payload {
@ -382,7 +377,7 @@ func (fi *FileInfoStore) getShareID(payload string) (string, error) {
}
func (fi *FileInfoStore) GetSharingDir(hashID string) (string, error) {
dirPath, ok := fi.store.GetStringIn(ShareIDNs, hashID)
dirPath, ok := fi.store.GetStringIn(db.ShareIDNs, hashID)
if !ok {
return "", ErrSharingNotFound
}

View file

@ -3,29 +3,17 @@ package fileinfostore
import (
"encoding/json"
"errors"
"fmt"
"github.com/ihexxa/quickshare/src/db"
)
var (
ErrCreateExisting = errors.New("create upload info which already exists")
ErrGreaterThanSize = errors.New("uploaded is greater than file size")
ErrUploadNotFound = errors.New("upload info not found")
uploadsPrefix = "uploads"
)
type UploadInfo struct {
RealFilePath string `json:"realFilePath"`
Size int64 `json:"size"`
Uploaded int64 `json:"uploaded"`
}
func UploadNS(user string) string {
return fmt.Sprintf("%s/%s", uploadsPrefix, user)
}
func (fi *FileInfoStore) AddUploadInfo(user, filePath, tmpPath string, fileSize int64) error {
ns := UploadNS(user)
ns := db.UploadNS(user)
err := fi.store.AddNamespace(ns)
if err != nil {
return err
@ -33,10 +21,10 @@ func (fi *FileInfoStore) AddUploadInfo(user, filePath, tmpPath string, fileSize
_, ok := fi.store.GetStringIn(ns, tmpPath)
if ok {
return ErrCreateExisting
return db.ErrCreateExisting
}
info := &UploadInfo{
info := &db.UploadInfo{
RealFilePath: filePath,
Size: fileSize,
Uploaded: 0,
@ -57,7 +45,7 @@ func (fi *FileInfoStore) SetUploadInfo(user, filePath string, newUploaded int64)
return ErrGreaterThanSize
}
newInfo := &UploadInfo{
newInfo := &db.UploadInfo{
RealFilePath: realFilePath,
Size: fileSize,
Uploaded: newUploaded,
@ -66,17 +54,17 @@ func (fi *FileInfoStore) SetUploadInfo(user, filePath string, newUploaded int64)
if err != nil {
return err
}
return fi.store.SetStringIn(UploadNS(user), filePath, string(newInfoBytes))
return fi.store.SetStringIn(db.UploadNS(user), filePath, string(newInfoBytes))
}
func (fi *FileInfoStore) GetUploadInfo(user, filePath string) (string, int64, int64, error) {
ns := UploadNS(user)
ns := db.UploadNS(user)
infoBytes, ok := fi.store.GetStringIn(ns, filePath)
if !ok {
return "", 0, 0, ErrUploadNotFound
}
info := &UploadInfo{}
info := &db.UploadInfo{}
err := json.Unmarshal([]byte(infoBytes), info)
if err != nil {
return "", 0, 0, err
@ -86,11 +74,11 @@ func (fi *FileInfoStore) GetUploadInfo(user, filePath string) (string, int64, in
}
func (fi *FileInfoStore) DelUploadInfo(user, filePath string) error {
return fi.store.DelInt64In(UploadNS(user), filePath)
return fi.store.DelInt64In(db.UploadNS(user), filePath)
}
func (fi *FileInfoStore) ListUploadInfo(user string) ([]*UploadInfo, error) {
ns := UploadNS(user)
func (fi *FileInfoStore) ListUploadInfo(user string) ([]*db.UploadInfo, error) {
ns := db.UploadNS(user)
if !fi.store.HasNamespace(ns) {
return nil, nil
}
@ -100,9 +88,9 @@ func (fi *FileInfoStore) ListUploadInfo(user string) ([]*UploadInfo, error) {
return nil, err
}
infos := []*UploadInfo{}
infos := []*db.UploadInfo{}
for _, infoStr := range infoMap {
info := &UploadInfo{}
info := &db.UploadInfo{}
err = json.Unmarshal([]byte(infoStr), info)
if err != nil {
return nil, err

View file

@ -7,6 +7,7 @@ import (
"sync"
"time"
"github.com/ihexxa/quickshare/src/db"
"github.com/ihexxa/quickshare/src/db/sitestore"
"github.com/ihexxa/quickshare/src/kvstore"
)
@ -17,7 +18,6 @@ const (
VisitorRole = "visitor"
InitNs = "usersInit"
IDsNs = "ids"
UsersNs = "users"
RoleListNs = "roleList"
InitTimeKey = "initTime"
VisitorID = uint64(1)
@ -34,7 +34,7 @@ var (
ErrReachedLimit = errors.New("reached space limit")
ErrNotFound = errors.New("not found")
DefaultPreferences = Preferences{
DefaultPreferences = db.Preferences{
Bg: &sitestore.BgConfig{
Url: "",
Repeat: "no-repeat",
@ -51,48 +51,25 @@ func IsReachedLimitErr(err error) bool {
return err == ErrReachedLimit
}
type Quota struct {
SpaceLimit int64 `json:"spaceLimit,string"`
UploadSpeedLimit int `json:"uploadSpeedLimit"`
DownloadSpeedLimit int `json:"downloadSpeedLimit"`
}
type Preferences struct {
Bg *sitestore.BgConfig `json:"bg"`
CSSURL string `json:"cssURL"`
LanPackURL string `json:"lanPackURL"`
Lan string `json:"lan"`
}
type UserCfg struct {
Name string `json:"name"`
Role string `json:"role"`
Pwd string `json:"pwd"`
}
type User struct {
ID uint64 `json:"id,string"`
Name string `json:"name"`
Pwd string `json:"pwd"`
Role string `json:"role"`
UsedSpace int64 `json:"usedSpace,string"`
Quota *Quota `json:"quota"`
Preferences *Preferences `json:"preferences"`
}
type IUserStore interface {
Init(rootName, rootPwd string) error
IsInited() bool
AddUser(user *User) error
AddUser(user *db.User) error
DelUser(id uint64) error
GetUser(id uint64) (*User, error)
GetUserByName(name string) (*User, error)
SetInfo(id uint64, user *User) error
GetUser(id uint64) (*db.User, error)
GetUserByName(name string) (*db.User, error)
SetInfo(id uint64, user *db.User) error
CanIncrUsed(id uint64, capacity int64) (bool, error)
SetUsed(id uint64, incr bool, capacity int64) error
SetPwd(id uint64, pwd string) error
SetPreferences(id uint64, settings *Preferences) error
ListUsers() ([]*User, error)
SetPreferences(id uint64, settings *db.Preferences) error
ListUsers() ([]*db.User, error)
ListUserIDs() (map[string]string, error)
AddRole(role string) error
DelRole(role string) error
@ -110,7 +87,7 @@ func NewKVUserStore(store kvstore.IKVStore) (*KVUserStore, error) {
var err error
for _, nsName := range []string{
IDsNs,
UsersNs,
db.UsersNs,
InitNs,
RoleListNs,
} {
@ -129,12 +106,12 @@ func NewKVUserStore(store kvstore.IKVStore) (*KVUserStore, error) {
func (us *KVUserStore) Init(rootName, rootPwd string) error {
var err error
adminPreferences := DefaultPreferences
admin := &User{
admin := &db.User{
ID: 0,
Name: rootName,
Pwd: rootPwd,
Role: AdminRole,
Quota: &Quota{
Quota: &db.Quota{
SpaceLimit: defaultSpaceLimit,
UploadSpeedLimit: defaultUploadSpeedLimit,
DownloadSpeedLimit: defaultDownloadSpeedLimit,
@ -143,12 +120,12 @@ func (us *KVUserStore) Init(rootName, rootPwd string) error {
}
visitorPreferences := DefaultPreferences
visitor := &User{
visitor := &db.User{
ID: VisitorID,
Name: VisitorName,
Pwd: rootPwd,
Role: VisitorRole,
Quota: &Quota{
Quota: &db.Quota{
SpaceLimit: 0,
UploadSpeedLimit: visitorUploadSpeedLimit,
DownloadSpeedLimit: visitorDownloadSpeedLimit,
@ -156,7 +133,7 @@ func (us *KVUserStore) Init(rootName, rootPwd string) error {
Preferences: &visitorPreferences,
}
for _, user := range []*User{admin, visitor} {
for _, user := range []*db.User{admin, visitor} {
err = us.AddUser(user)
if err != nil {
return err
@ -178,12 +155,12 @@ func (us *KVUserStore) IsInited() bool {
return ok
}
func (us *KVUserStore) AddUser(user *User) error {
func (us *KVUserStore) AddUser(user *db.User) error {
us.mtx.Lock()
defer us.mtx.Unlock()
userID := fmt.Sprint(user.ID)
_, ok := us.store.GetStringIn(UsersNs, userID)
_, ok := us.store.GetStringIn(db.UsersNs, userID)
if ok {
return fmt.Errorf("userID (%d) exists", user.ID)
}
@ -203,7 +180,7 @@ func (us *KVUserStore) AddUser(user *User) error {
if err != nil {
return err
}
return us.store.SetStringIn(UsersNs, userID, string(userBytes))
return us.store.SetStringIn(db.UsersNs, userID, string(userBytes))
}
func (us *KVUserStore) DelUser(id uint64) error {
@ -211,11 +188,11 @@ func (us *KVUserStore) DelUser(id uint64) error {
defer us.mtx.Unlock()
userID := fmt.Sprint(id)
infoStr, ok := us.store.GetStringIn(UsersNs, userID)
infoStr, ok := us.store.GetStringIn(db.UsersNs, userID)
if !ok {
return fmt.Errorf("userID (%s) does not exist", userID)
}
user := &User{}
user := &db.User{}
err := json.Unmarshal([]byte(infoStr), user)
if err != nil {
return err
@ -223,24 +200,24 @@ func (us *KVUserStore) DelUser(id uint64) error {
// TODO: add complement operations if part of the actions fails
err1 := us.store.DelStringIn(IDsNs, user.Name)
err2 := us.store.DelStringIn(UsersNs, userID)
err2 := us.store.DelStringIn(db.UsersNs, userID)
if err1 != nil || err2 != nil {
return fmt.Errorf("DelUser: err1(%s) err2(%s)", err1, err2)
}
return nil
}
func (us *KVUserStore) GetUser(id uint64) (*User, error) {
func (us *KVUserStore) GetUser(id uint64) (*db.User, error) {
us.mtx.RLock()
defer us.mtx.RUnlock()
userID := fmt.Sprint(id)
infoStr, ok := us.store.GetStringIn(UsersNs, userID)
infoStr, ok := us.store.GetStringIn(db.UsersNs, userID)
if !ok {
return nil, fmt.Errorf("user (%s) not found", userID)
}
user := &User{}
user := &db.User{}
err := json.Unmarshal([]byte(infoStr), user)
if err != nil {
return nil, err
@ -258,7 +235,7 @@ func (us *KVUserStore) GetUser(id uint64) (*User, error) {
}
func (us *KVUserStore) GetUserByName(name string) (*User, error) {
func (us *KVUserStore) GetUserByName(name string) (*db.User, error) {
us.mtx.RLock()
defer us.mtx.RUnlock()
@ -266,12 +243,12 @@ func (us *KVUserStore) GetUserByName(name string) (*User, error) {
if !ok {
return nil, ErrNotFound
}
infoStr, ok := us.store.GetStringIn(UsersNs, userID)
infoStr, ok := us.store.GetStringIn(db.UsersNs, userID)
if !ok {
return nil, ErrNotFound
}
user := &User{}
user := &db.User{}
err := json.Unmarshal([]byte(infoStr), user)
if err != nil {
return nil, err
@ -290,11 +267,11 @@ func (us *KVUserStore) SetPwd(id uint64, pwd string) error {
defer us.mtx.Unlock()
userID := fmt.Sprint(id)
infoStr, ok := us.store.GetStringIn(UsersNs, userID)
infoStr, ok := us.store.GetStringIn(db.UsersNs, userID)
if !ok {
return fmt.Errorf("user (%d) does not exist", id)
}
gotUser := &User{}
gotUser := &db.User{}
err := json.Unmarshal([]byte(infoStr), gotUser)
if err != nil {
return err
@ -307,19 +284,19 @@ func (us *KVUserStore) SetPwd(id uint64, pwd string) error {
if err != nil {
return err
}
return us.store.SetStringIn(UsersNs, userID, string(infoBytes))
return us.store.SetStringIn(db.UsersNs, userID, string(infoBytes))
}
func (us *KVUserStore) SetPreferences(id uint64, prefers *Preferences) error {
func (us *KVUserStore) SetPreferences(id uint64, prefers *db.Preferences) error {
us.mtx.Lock()
defer us.mtx.Unlock()
userID := fmt.Sprint(id)
infoStr, ok := us.store.GetStringIn(UsersNs, userID)
infoStr, ok := us.store.GetStringIn(db.UsersNs, userID)
if !ok {
return fmt.Errorf("user (%d) does not exist", id)
}
gotUser := &User{}
gotUser := &db.User{}
err := json.Unmarshal([]byte(infoStr), gotUser)
if err != nil {
return err
@ -332,19 +309,19 @@ func (us *KVUserStore) SetPreferences(id uint64, prefers *Preferences) error {
if err != nil {
return err
}
return us.store.SetStringIn(UsersNs, userID, string(infoBytes))
return us.store.SetStringIn(db.UsersNs, userID, string(infoBytes))
}
func (us *KVUserStore) CanIncrUsed(id uint64, capacity int64) (bool, error) {
us.mtx.Lock()
defer us.mtx.Unlock()
userID := fmt.Sprint(id)
infoStr, ok := us.store.GetStringIn(UsersNs, userID)
infoStr, ok := us.store.GetStringIn(db.UsersNs, userID)
if !ok {
return false, fmt.Errorf("user (%d) does not exist", id)
}
gotUser := &User{}
gotUser := &db.User{}
err := json.Unmarshal([]byte(infoStr), gotUser)
if err != nil {
return false, err
@ -360,12 +337,12 @@ func (us *KVUserStore) SetUsed(id uint64, incr bool, capacity int64) error {
defer us.mtx.Unlock()
userID := fmt.Sprint(id)
infoStr, ok := us.store.GetStringIn(UsersNs, userID)
infoStr, ok := us.store.GetStringIn(db.UsersNs, userID)
if !ok {
return fmt.Errorf("user (%d) does not exist", id)
}
gotUser := &User{}
gotUser := &db.User{}
err := json.Unmarshal([]byte(infoStr), gotUser)
if err != nil {
return err
@ -389,19 +366,19 @@ func (us *KVUserStore) SetUsed(id uint64, incr bool, capacity int64) error {
if err != nil {
return err
}
return us.store.SetStringIn(UsersNs, userID, string(infoBytes))
return us.store.SetStringIn(db.UsersNs, userID, string(infoBytes))
}
func (us *KVUserStore) SetInfo(id uint64, user *User) error {
func (us *KVUserStore) SetInfo(id uint64, user *db.User) error {
us.mtx.Lock()
defer us.mtx.Unlock()
userID := fmt.Sprint(id)
infoStr, ok := us.store.GetStringIn(UsersNs, userID)
infoStr, ok := us.store.GetStringIn(db.UsersNs, userID)
if !ok {
return fmt.Errorf("user (%d) does not exist", id)
}
gotUser := &User{}
gotUser := &db.User{}
err := json.Unmarshal([]byte(infoStr), gotUser)
if err != nil {
return err
@ -425,14 +402,14 @@ func (us *KVUserStore) SetInfo(id uint64, user *User) error {
return err
}
return us.store.SetStringIn(UsersNs, userID, string(infoBytes))
return us.store.SetStringIn(db.UsersNs, userID, string(infoBytes))
}
func (us *KVUserStore) ListUsers() ([]*User, error) {
func (us *KVUserStore) ListUsers() ([]*db.User, error) {
us.mtx.RLock()
defer us.mtx.RUnlock()
idToInfo, err := us.store.ListStringsIn(UsersNs)
idToInfo, err := us.store.ListStringsIn(db.UsersNs)
if err != nil {
return nil, err
}
@ -441,9 +418,9 @@ func (us *KVUserStore) ListUsers() ([]*User, error) {
return nil, err
}
users := []*User{}
users := []*db.User{}
for _, infoStr := range idToInfo {
user := &User{}
user := &db.User{}
err = json.Unmarshal([]byte(infoStr), user)
if err != nil {
return nil, err
@ -459,7 +436,7 @@ func (us *KVUserStore) ListUsers() ([]*User, error) {
for _, user := range users {
_, ok := nameToID[user.Name]
if !ok {
err = us.store.DelStringIn(UsersNs, fmt.Sprint(user.ID))
err = us.store.DelStringIn(db.UsersNs, fmt.Sprint(user.ID))
if err != nil {
return nil, err
}