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

@ -5,7 +5,7 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"github.com/ihexxa/quickshare/src/db/userstore" "github.com/ihexxa/quickshare/src/db"
"github.com/ihexxa/quickshare/src/handlers" "github.com/ihexxa/quickshare/src/handlers"
"github.com/ihexxa/quickshare/src/handlers/multiusers" "github.com/ihexxa/quickshare/src/handlers/multiusers"
"github.com/parnurzeal/gorequest" "github.com/parnurzeal/gorequest"
@ -63,7 +63,7 @@ func (cl *SingleUserClient) ForceSetPwd(userID, newPwd string, token *http.Cooki
End() End()
} }
func (cl *SingleUserClient) SetUser(ID uint64, role string, quota *userstore.Quota, token *http.Cookie) (*http.Response, string, []error) { func (cl *SingleUserClient) SetUser(ID uint64, role string, quota *db.Quota, token *http.Cookie) (*http.Response, string, []error) {
return cl.r.Patch(cl.url("/v1/users/")). return cl.r.Patch(cl.url("/v1/users/")).
Send(multiusers.SetUserReq{ Send(multiusers.SetUserReq{
ID: ID, ID: ID,
@ -173,7 +173,7 @@ func (cl *SingleUserClient) Self(token *http.Cookie) (*http.Response, *multiuser
return resp, selfResp, errs return resp, selfResp, errs
} }
func (cl *SingleUserClient) SetPreferences(prefers *userstore.Preferences, token *http.Cookie) (*http.Response, string, []error) { func (cl *SingleUserClient) SetPreferences(prefers *db.Preferences, token *http.Cookie) (*http.Response, string, []error) {
return cl.r.Patch(cl.url("/v1/users/preferences")). return cl.r.Patch(cl.url("/v1/users/preferences")).
Send(multiusers.SetPreferencesReq{ Send(multiusers.SetPreferencesReq{
Preferences: prefers, Preferences: prefers,

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

View file

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

View file

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

View file

@ -5,6 +5,7 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
"github.com/ihexxa/quickshare/src/cryptoutil" "github.com/ihexxa/quickshare/src/cryptoutil"
"github.com/ihexxa/quickshare/src/db/boltstore"
"github.com/ihexxa/quickshare/src/db/fileinfostore" "github.com/ihexxa/quickshare/src/db/fileinfostore"
"github.com/ihexxa/quickshare/src/db/sitestore" "github.com/ihexxa/quickshare/src/db/sitestore"
"github.com/ihexxa/quickshare/src/db/userstore" "github.com/ihexxa/quickshare/src/db/userstore"
@ -34,6 +35,7 @@ type Deps struct {
logger *zap.SugaredLogger logger *zap.SugaredLogger
limiter iolimiter.ILimiter limiter iolimiter.ILimiter
workers worker.IWorkerPool workers worker.IWorkerPool
boltStore *boltstore.BoltStore
} }
func NewDeps(cfg gocfg.ICfg) *Deps { func NewDeps(cfg gocfg.ICfg) *Deps {
@ -119,3 +121,11 @@ func (deps *Deps) Workers() worker.IWorkerPool {
func (deps *Deps) SetWorkers(workers worker.IWorkerPool) { func (deps *Deps) SetWorkers(workers worker.IWorkerPool) {
deps.workers = workers deps.workers = workers
} }
func (deps *Deps) BoltStore() *boltstore.BoltStore {
return deps.boltStore
}
func (deps *Deps) SetBoltStore(boltStore *boltstore.BoltStore) {
deps.boltStore = boltStore
}

View file

@ -18,7 +18,7 @@ import (
"github.com/ihexxa/gocfg" "github.com/ihexxa/gocfg"
"github.com/ihexxa/multipart" "github.com/ihexxa/multipart"
"github.com/ihexxa/quickshare/src/db/fileinfostore" "github.com/ihexxa/quickshare/src/db"
"github.com/ihexxa/quickshare/src/db/userstore" "github.com/ihexxa/quickshare/src/db/userstore"
"github.com/ihexxa/quickshare/src/depidx" "github.com/ihexxa/quickshare/src/depidx"
q "github.com/ihexxa/quickshare/src/handlers" q "github.com/ihexxa/quickshare/src/handlers"
@ -40,16 +40,14 @@ const (
) )
type FileHandlers struct { type FileHandlers struct {
cfg gocfg.ICfg cfg gocfg.ICfg
deps *depidx.Deps deps *depidx.Deps
uploadMgr *UploadMgr
} }
func NewFileHandlers(cfg gocfg.ICfg, deps *depidx.Deps) (*FileHandlers, error) { func NewFileHandlers(cfg gocfg.ICfg, deps *depidx.Deps) (*FileHandlers, error) {
handlers := &FileHandlers{ handlers := &FileHandlers{
cfg: cfg, cfg: cfg,
deps: deps, deps: deps,
uploadMgr: NewUploadMgr(deps.KV()),
} }
deps.Workers().AddHandler(MsgTypeSha1, handlers.genSha1) deps.Workers().AddHandler(MsgTypeSha1, handlers.genSha1)
@ -149,15 +147,28 @@ func (h *FileHandlers) Create(c *gin.Context) {
c.JSON(q.ErrResp(c, 500, err)) c.JSON(q.ErrResp(c, 500, err))
return return
} }
tmpFilePath := q.UploadPath(userName, req.Path)
if req.FileSize == 0 { if req.FileSize == 0 {
err = h.deps.FS().MkdirAll(filepath.Dir(req.Path)) // TODO: limit the number of files with 0 byte
err = h.deps.BoltStore().AddUploadInfos(userIDInt, tmpFilePath, fsFilePath, &db.FileInfo{
Size: req.FileSize,
})
if err != nil {
c.JSON(q.ErrResp(c, 500, err))
return
}
err = h.deps.BoltStore().MoveUploadingInfos(userIDInt, tmpFilePath, fsFilePath)
if err != nil { if err != nil {
c.JSON(q.ErrResp(c, 500, err)) c.JSON(q.ErrResp(c, 500, err))
return return
} }
// TODO: limit the number of files with 0 byte err = h.deps.FS().MkdirAll(filepath.Dir(req.Path))
if err != nil {
c.JSON(q.ErrResp(c, 500, err))
return
}
err = h.deps.FS().Create(fsFilePath) err = h.deps.FS().Create(fsFilePath)
if err != nil { if err != nil {
@ -193,18 +204,36 @@ func (h *FileHandlers) Create(c *gin.Context) {
return return
} }
tmpFilePath := q.UploadPath(userName, req.Path) err = h.deps.BoltStore().AddUploadInfos(userIDInt, tmpFilePath, fsFilePath, &db.FileInfo{
Size: req.FileSize,
})
if err != nil {
c.JSON(q.ErrResp(c, 500, err))
return
}
locker := h.NewAutoLocker(c, lockName(tmpFilePath)) locker := h.NewAutoLocker(c, lockName(tmpFilePath))
locker.Exec(func() { locker.Exec(func() {
// TODO: // ok, err := h.deps.Users().CanIncrUsed(userIDInt, req.FileSize)
ok, err := h.deps.Users().CanIncrUsed(userIDInt, req.FileSize) // if err != nil {
if err != nil { // c.JSON(q.ErrResp(c, 500, err))
c.JSON(q.ErrResp(c, 500, err)) // return
return // } else if !ok {
} else if !ok { // c.JSON(q.ErrResp(c, 429, userstore.ErrReachedLimit))
c.JSON(q.ErrResp(c, 429, userstore.ErrReachedLimit)) // return
return // }
}
// err = h.deps.FileInfos().AddUploadInfo(userID, req.Path, tmpFilePath, req.FileSize)
// if err != nil {
// c.JSON(q.ErrResp(c, 500, err))
// return
// }
// err = h.deps.Users().SetUsed(userIDInt, true, req.FileSize)
// if err != nil {
// c.JSON(q.ErrResp(c, 500, err))
// return
// }
err = h.deps.FS().Create(tmpFilePath) err = h.deps.FS().Create(tmpFilePath)
if err != nil { if err != nil {
@ -215,11 +244,6 @@ func (h *FileHandlers) Create(c *gin.Context) {
} }
return return
} }
err = h.uploadMgr.AddInfo(userID, req.Path, tmpFilePath, req.FileSize)
if err != nil {
c.JSON(q.ErrResp(c, 500, err))
return
}
err = h.deps.FS().MkdirAll(filepath.Dir(req.Path)) err = h.deps.FS().MkdirAll(filepath.Dir(req.Path))
if err != nil { if err != nil {
@ -227,12 +251,6 @@ func (h *FileHandlers) Create(c *gin.Context) {
return return
} }
err = h.deps.Users().SetUsed(userIDInt, true, req.FileSize)
if err != nil {
c.JSON(q.ErrResp(c, 500, err))
return
}
c.JSON(q.Resp(200)) c.JSON(q.Resp(200))
}) })
} }
@ -259,32 +277,37 @@ func (h *FileHandlers) Delete(c *gin.Context) {
locker := h.NewAutoLocker(c, lockName(filePath)) locker := h.NewAutoLocker(c, lockName(filePath))
locker.Exec(func() { locker.Exec(func() {
info, err := h.deps.FileInfos().GetInfo(filePath)
if err != nil {
c.JSON(q.ErrResp(c, 500, err))
return
}
err = h.deps.FS().Remove(filePath) err = h.deps.FS().Remove(filePath)
if err != nil { if err != nil {
c.JSON(q.ErrResp(c, 500, err)) c.JSON(q.ErrResp(c, 500, err))
return return
} }
err = h.deps.Users().SetUsed(userIDInt, false, info.Size)
if err != nil {
c.JSON(q.ErrResp(c, 500, err))
return
}
err = h.deps.FileInfos().DelInfo(filePath)
if err != nil {
c.JSON(q.ErrResp(c, 500, err))
return
}
c.JSON(q.Resp(200))
}) })
// info, err := h.deps.FileInfos().GetInfo(filePath)
// if err != nil {
// c.JSON(q.ErrResp(c, 500, err))
// return
// }
// err = h.deps.Users().SetUsed(userIDInt, false, info.Size)
// if err != nil {
// c.JSON(q.ErrResp(c, 500, err))
// return
// }
// err = h.deps.FileInfos().DelInfo(filePath)
// if err != nil {
// c.JSON(q.ErrResp(c, 500, err))
// return
// }
err = h.deps.BoltStore().DelInfos(userIDInt, filePath)
if err != nil {
c.JSON(q.ErrResp(c, 500, err))
return
}
c.JSON(q.Resp(200))
} }
type MetadataResp struct { type MetadataResp struct {
@ -364,13 +387,19 @@ func (h *FileHandlers) Move(c *gin.Context) {
return return
} }
role := c.MustGet(q.RoleParam).(string) role := c.MustGet(q.RoleParam).(string)
userID := c.MustGet(q.UserIDParam).(string)
userName := c.MustGet(q.UserParam).(string) userName := c.MustGet(q.UserParam).(string)
if !h.canAccess(userName, role, "move", req.OldPath) || !h.canAccess(userName, role, "move", req.NewPath) { if !h.canAccess(userName, role, "move", req.OldPath) || !h.canAccess(userName, role, "move", req.NewPath) {
c.JSON(q.ErrResp(c, 403, q.ErrAccessDenied)) c.JSON(q.ErrResp(c, 403, q.ErrAccessDenied))
return return
} }
userIDInt, err := strconv.ParseUint(userID, 10, 64)
if err != nil {
c.JSON(q.ErrResp(c, 500, err))
return
}
_, err := h.deps.FS().Stat(req.OldPath) itemInfo, err := h.deps.FS().Stat(req.OldPath)
if err != nil { if err != nil {
c.JSON(q.ErrResp(c, 500, err)) c.JSON(q.ErrResp(c, 500, err))
return return
@ -385,6 +414,12 @@ func (h *FileHandlers) Move(c *gin.Context) {
return return
} }
err = h.deps.BoltStore().MoveInfos(userIDInt, req.OldPath, req.NewPath, itemInfo.IsDir())
if err != nil {
c.JSON(q.ErrResp(c, 500, err))
return
}
err = h.deps.FS().Rename(req.OldPath, req.NewPath) err = h.deps.FS().Rename(req.OldPath, req.NewPath)
if err != nil { if err != nil {
c.JSON(q.ErrResp(c, 500, err)) c.JSON(q.ErrResp(c, 500, err))
@ -469,45 +504,52 @@ func (h *FileHandlers) UploadChunk(c *gin.Context) {
return return
} }
err = h.deps.BoltStore().MoveUploadingInfos(userIDInt, tmpFilePath, fsFilePath)
if err != nil {
c.JSON(q.ErrResp(c, 500, err))
return
}
err = h.deps.FS().Rename(tmpFilePath, fsFilePath) err = h.deps.FS().Rename(tmpFilePath, fsFilePath)
if err != nil { if err != nil {
c.JSON(q.ErrResp(c, 500, fmt.Errorf("%s error: %w", req.Path, err))) c.JSON(q.ErrResp(c, 500, fmt.Errorf("%s error: %w", req.Path, err)))
return return
} }
err = h.deps.FileInfos().DelUploadInfo(userID, tmpFilePath)
if err != nil {
c.JSON(q.ErrResp(c, 500, err))
return
}
fsInfo, err := h.deps.FS().Stat(fsFilePath) // err = h.deps.FileInfos().DelUploadInfo(userID, tmpFilePath)
if err != nil { // if err != nil {
c.JSON(q.ErrResp(c, 500, err)) // c.JSON(q.ErrResp(c, 500, err))
return // return
} // }
err = h.deps.FileInfos().SetInfo(fsFilePath, &fileinfostore.FileInfo{ // fsInfo, err := h.deps.FS().Stat(fsFilePath)
IsDir: false, // if err != nil {
Shared: false, // c.JSON(q.ErrResp(c, 500, err))
Size: fsInfo.Size(), // return
}) // }
if err != nil {
c.JSON(q.ErrResp(c, 500, err)) // err = h.deps.FileInfos().SetInfo(fsFilePath, &db.FileInfo{
return // IsDir: false,
} // Shared: false,
// Size: fsInfo.Size(),
// })
// if err != nil {
// c.JSON(q.ErrResp(c, 500, err))
// return
// }
// TODO: check space quota? // TODO: check space quota?
if fsInfo.Size()-fileSize != 0 { // if fsInfo.Size()-fileSize != 0 {
sizeDiff := fsInfo.Size() - fileSize // sizeDiff := fsInfo.Size() - fileSize
if sizeDiff < 0 { // if sizeDiff < 0 {
sizeDiff = -sizeDiff // sizeDiff = -sizeDiff
} // }
err = h.deps.Users().SetUsed(userIDInt, fsInfo.Size()-fileSize > 0, sizeDiff) // err = h.deps.Users().SetUsed(userIDInt, fsInfo.Size()-fileSize > 0, sizeDiff)
if err != nil { // if err != nil {
c.JSON(q.ErrResp(c, 500, err)) // c.JSON(q.ErrResp(c, 500, err))
return // return
} // }
} // }
msg, err := json.Marshal(Sha1Params{ msg, err := json.Marshal(Sha1Params{
FilePath: fsFilePath, FilePath: fsFilePath,
@ -842,7 +884,7 @@ func lockName(filePath string) string {
} }
type ListUploadingsResp struct { type ListUploadingsResp struct {
UploadInfos []*fileinfostore.UploadInfo `json:"uploadInfos"` UploadInfos []*db.UploadInfo `json:"uploadInfos"`
} }
func (h *FileHandlers) ListUploadings(c *gin.Context) { func (h *FileHandlers) ListUploadings(c *gin.Context) {
@ -854,7 +896,7 @@ func (h *FileHandlers) ListUploadings(c *gin.Context) {
return return
} }
if infos == nil { if infos == nil {
infos = []*fileinfostore.UploadInfo{} infos = []*db.UploadInfo{}
} }
c.JSON(200, &ListUploadingsResp{UploadInfos: infos}) c.JSON(200, &ListUploadingsResp{UploadInfos: infos})
} }
@ -884,11 +926,11 @@ func (h *FileHandlers) DelUploading(c *gin.Context) {
tmpFilePath := q.UploadPath(userName, filePath) tmpFilePath := q.UploadPath(userName, filePath)
locker := h.NewAutoLocker(c, lockName(tmpFilePath)) locker := h.NewAutoLocker(c, lockName(tmpFilePath))
locker.Exec(func() { locker.Exec(func() {
_, size, _, err := h.deps.FileInfos().GetUploadInfo(userID, tmpFilePath) // _, size, _, err := h.deps.FileInfos().GetUploadInfo(userID, tmpFilePath)
if err != nil { // if err != nil {
c.JSON(q.ErrResp(c, 500, err)) // c.JSON(q.ErrResp(c, 500, err))
return // return
} // }
_, err = h.deps.FS().Stat(tmpFilePath) _, err = h.deps.FS().Stat(tmpFilePath)
if err != nil { if err != nil {
@ -906,20 +948,26 @@ func (h *FileHandlers) DelUploading(c *gin.Context) {
} }
} }
err = h.deps.FileInfos().DelUploadInfo(userID, tmpFilePath) // err = h.deps.FileInfos().DelUploadInfo(userID, tmpFilePath)
if err != nil { // if err != nil {
c.JSON(q.ErrResp(c, 500, err)) // c.JSON(q.ErrResp(c, 500, err))
return // return
} // }
err = h.deps.Users().SetUsed(userIDInt, false, size) // err = h.deps.Users().SetUsed(userIDInt, false, size)
if err != nil { // if err != nil {
c.JSON(q.ErrResp(c, 500, err)) // c.JSON(q.ErrResp(c, 500, err))
return // return
} // }
c.JSON(q.Resp(200))
}) })
err = h.deps.BoltStore().DelUploadingInfos(userIDInt, tmpFilePath)
if err != nil {
c.JSON(q.ErrResp(c, 500, err))
return
}
c.JSON(q.Resp(200))
} }
type SharingReq struct { type SharingReq struct {

View file

@ -1,126 +0,0 @@
package fileshdr
import (
"encoding/json"
"errors"
"fmt"
"github.com/ihexxa/quickshare/src/kvstore"
)
var (
ErrCreateExisting = errors.New("create upload info which already exists")
ErrGreaterThanSize = errors.New("uploaded is greater than file size")
ErrNotFound = errors.New("upload info not found")
uploadsPrefix = "uploads"
)
type UploadInfo struct {
RealFilePath string `json:"realFilePath"`
Size int64 `json:"size"`
Uploaded int64 `json:"uploaded"`
}
type UploadMgr struct {
kv kvstore.IKVStore
}
func UploadNS(user string) string {
return fmt.Sprintf("%s/%s", uploadsPrefix, user)
}
func NewUploadMgr(kv kvstore.IKVStore) *UploadMgr {
return &UploadMgr{
kv: kv,
}
}
func (um *UploadMgr) AddInfo(user, filePath, tmpPath string, fileSize int64) error {
ns := UploadNS(user)
err := um.kv.AddNamespace(ns)
if err != nil {
return err
}
_, ok := um.kv.GetStringIn(ns, tmpPath)
if ok {
return ErrCreateExisting
}
info := &UploadInfo{
RealFilePath: filePath,
Size: fileSize,
Uploaded: 0,
}
infoBytes, err := json.Marshal(info)
if err != nil {
return err
}
return um.kv.SetStringIn(ns, tmpPath, string(infoBytes))
}
func (um *UploadMgr) SetInfo(user, filePath string, newUploaded int64) error {
realFilePath, fileSize, _, err := um.GetInfo(user, filePath)
if err != nil {
return err
} else if newUploaded > fileSize {
return ErrGreaterThanSize
}
newInfo := &UploadInfo{
RealFilePath: realFilePath,
Size: fileSize,
Uploaded: newUploaded,
}
newInfoBytes, err := json.Marshal(newInfo)
if err != nil {
return err
}
return um.kv.SetStringIn(UploadNS(user), filePath, string(newInfoBytes))
}
func (um *UploadMgr) GetInfo(user, filePath string) (string, int64, int64, error) {
ns := UploadNS(user)
infoBytes, ok := um.kv.GetStringIn(ns, filePath)
if !ok {
return "", 0, 0, ErrNotFound
}
info := &UploadInfo{}
err := json.Unmarshal([]byte(infoBytes), info)
if err != nil {
return "", 0, 0, err
}
return info.RealFilePath, info.Size, info.Uploaded, nil
}
func (um *UploadMgr) DelInfo(user, filePath string) error {
return um.kv.DelInt64In(UploadNS(user), filePath)
}
func (um *UploadMgr) ListInfo(user string) ([]*UploadInfo, error) {
ns := UploadNS(user)
if !um.kv.HasNamespace(ns) {
return nil, nil
}
infoMap, err := um.kv.ListStringsIn(ns)
if err != nil {
return nil, err
}
infos := []*UploadInfo{}
for _, infoStr := range infoMap {
info := &UploadInfo{}
err = json.Unmarshal([]byte(infoStr), info)
if err != nil {
return nil, err
}
infos = append(infos, info)
}
return infos, nil
}

View file

@ -12,6 +12,7 @@ import (
"github.com/ihexxa/gocfg" "github.com/ihexxa/gocfg"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
"github.com/ihexxa/quickshare/src/db"
"github.com/ihexxa/quickshare/src/db/userstore" "github.com/ihexxa/quickshare/src/db/userstore"
"github.com/ihexxa/quickshare/src/depidx" "github.com/ihexxa/quickshare/src/depidx"
q "github.com/ihexxa/quickshare/src/handlers" q "github.com/ihexxa/quickshare/src/handlers"
@ -179,12 +180,12 @@ func (h *MultiUsersSvc) Init(adminName, adminPwd string) (string, error) {
} }
preferences := userstore.DefaultPreferences preferences := userstore.DefaultPreferences
user := &userstore.User{ user := &db.User{
ID: h.deps.ID().Gen(), ID: h.deps.ID().Gen(),
Name: userCfg.Name, Name: userCfg.Name,
Pwd: string(pwdHash), Pwd: string(pwdHash),
Role: userCfg.Role, Role: userCfg.Role,
Quota: &userstore.Quota{ Quota: &db.Quota{
SpaceLimit: spaceLimit, SpaceLimit: spaceLimit,
UploadSpeedLimit: uploadSpeedLimit, UploadSpeedLimit: uploadSpeedLimit,
DownloadSpeedLimit: downloadSpeedLimit, DownloadSpeedLimit: downloadSpeedLimit,
@ -424,12 +425,12 @@ func (h *MultiUsersSvc) AddUser(c *gin.Context) {
} }
newPreferences := userstore.DefaultPreferences newPreferences := userstore.DefaultPreferences
err = h.deps.Users().AddUser(&userstore.User{ err = h.deps.Users().AddUser(&db.User{
ID: uid, ID: uid,
Name: req.Name, Name: req.Name,
Pwd: string(pwdHash), Pwd: string(pwdHash),
Role: req.Role, Role: req.Role,
Quota: &userstore.Quota{ Quota: &db.Quota{
SpaceLimit: int64(h.cfg.IntOr("Users.SpaceLimit", 100*1024*1024)), // TODO: support int64 SpaceLimit: int64(h.cfg.IntOr("Users.SpaceLimit", 100*1024*1024)), // TODO: support int64
UploadSpeedLimit: h.cfg.IntOr("Users.UploadSpeedLimit", 100*1024), UploadSpeedLimit: h.cfg.IntOr("Users.UploadSpeedLimit", 100*1024),
DownloadSpeedLimit: h.cfg.IntOr("Users.DownloadSpeedLimit", 100*1024), DownloadSpeedLimit: h.cfg.IntOr("Users.DownloadSpeedLimit", 100*1024),
@ -486,7 +487,7 @@ func (h *MultiUsersSvc) DelUser(c *gin.Context) {
} }
type ListUsersResp struct { type ListUsersResp struct {
Users []*userstore.User `json:"users"` Users []*db.User `json:"users"`
} }
func (h *MultiUsersSvc) ListUsers(c *gin.Context) { func (h *MultiUsersSvc) ListUsers(c *gin.Context) {
@ -623,12 +624,12 @@ func (h *MultiUsersSvc) isValidRole(role string) error {
} }
type SelfResp struct { type SelfResp struct {
ID string `json:"id"` ID string `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Role string `json:"role"` Role string `json:"role"`
Quota *userstore.Quota `json:"quota"` Quota *db.Quota `json:"quota"`
UsedSpace int64 `json:"usedSpace,string"` UsedSpace int64 `json:"usedSpace,string"`
Preferences *userstore.Preferences `json:"preferences"` Preferences *db.Preferences `json:"preferences"`
} }
func (h *MultiUsersSvc) Self(c *gin.Context) { func (h *MultiUsersSvc) Self(c *gin.Context) {
@ -655,10 +656,10 @@ func (h *MultiUsersSvc) Self(c *gin.Context) {
} }
type SetUserReq struct { type SetUserReq struct {
ID uint64 `json:"id,string"` ID uint64 `json:"id,string"`
Role string `json:"role"` Role string `json:"role"`
UsedSpace int64 `json:"usedSpace,string"` UsedSpace int64 `json:"usedSpace,string"`
Quota *userstore.Quota `json:"quota"` Quota *db.Quota `json:"quota"`
} }
func (h *MultiUsersSvc) SetUser(c *gin.Context) { func (h *MultiUsersSvc) SetUser(c *gin.Context) {
@ -668,7 +669,7 @@ func (h *MultiUsersSvc) SetUser(c *gin.Context) {
return return
} }
err := h.deps.Users().SetInfo(req.ID, &userstore.User{ err := h.deps.Users().SetInfo(req.ID, &db.User{
Role: req.Role, Role: req.Role,
Quota: req.Quota, Quota: req.Quota,
}) })
@ -681,7 +682,7 @@ func (h *MultiUsersSvc) SetUser(c *gin.Context) {
} }
type SetPreferencesReq struct { type SetPreferencesReq struct {
Preferences *userstore.Preferences `json:"preferences"` Preferences *db.Preferences `json:"preferences"`
} }
func (h *MultiUsersSvc) SetPreferences(c *gin.Context) { func (h *MultiUsersSvc) SetPreferences(c *gin.Context) {

View file

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"sync" "sync"
"github.com/ihexxa/quickshare/src/db"
"github.com/ihexxa/quickshare/src/db/userstore" "github.com/ihexxa/quickshare/src/db/userstore"
"github.com/ihexxa/quickshare/src/golimiter" "github.com/ihexxa/quickshare/src/golimiter"
) )
@ -20,7 +21,7 @@ type IOLimiter struct {
UploadLimiter *golimiter.Limiter UploadLimiter *golimiter.Limiter
DownloadLimiter *golimiter.Limiter DownloadLimiter *golimiter.Limiter
users userstore.IUserStore users userstore.IUserStore
quotaCache map[uint64]*userstore.Quota quotaCache map[uint64]*db.Quota
} }
func NewIOLimiter(cap, cyc int, users userstore.IUserStore) *IOLimiter { func NewIOLimiter(cap, cyc int, users userstore.IUserStore) *IOLimiter {
@ -29,7 +30,7 @@ func NewIOLimiter(cap, cyc int, users userstore.IUserStore) *IOLimiter {
UploadLimiter: golimiter.New(cap, cyc), UploadLimiter: golimiter.New(cap, cyc),
DownloadLimiter: golimiter.New(cap, cyc), DownloadLimiter: golimiter.New(cap, cyc),
users: users, users: users,
quotaCache: map[uint64]*userstore.Quota{}, quotaCache: map[uint64]*db.Quota{},
} }
} }

View file

@ -0,0 +1,7 @@
package boltdbpvd
import "github.com/boltdb/bolt"
type BoltProvider interface {
Bolt() *bolt.DB
}

View file

@ -433,6 +433,6 @@ func (bp *BoltPvd) ListStringsByPrefixIn(prefix, ns string) (map[string]string,
return results, err return results, err
} }
func (bp *BoltPvd) StartUpdateTxBolt(op func(*bolt.Tx) error) error { func (bp *BoltPvd) Bolt() *bolt.DB {
return bp.db.Update(op) return bp.db
} }

View file

@ -23,6 +23,7 @@ import (
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
"github.com/ihexxa/quickshare/src/cryptoutil/jwt" "github.com/ihexxa/quickshare/src/cryptoutil/jwt"
"github.com/ihexxa/quickshare/src/db/boltstore"
"github.com/ihexxa/quickshare/src/db/fileinfostore" "github.com/ihexxa/quickshare/src/db/fileinfostore"
"github.com/ihexxa/quickshare/src/db/sitestore" "github.com/ihexxa/quickshare/src/db/sitestore"
"github.com/ihexxa/quickshare/src/db/userstore" "github.com/ihexxa/quickshare/src/db/userstore"
@ -141,6 +142,7 @@ func initDeps(cfg gocfg.ICfg) *depidx.Deps {
if err := filesystem.MkdirAll(dbPath); err != nil { if err := filesystem.MkdirAll(dbPath); err != nil {
panic(fmt.Sprintf("fail to create path for db: %s", err)) panic(fmt.Sprintf("fail to create path for db: %s", err))
} }
kv := boltdbpvd.New(dbPath, 1024) kv := boltdbpvd.New(dbPath, 1024)
users, err := userstore.NewKVUserStore(kv) users, err := userstore.NewKVUserStore(kv)
if err != nil { if err != nil {
@ -152,7 +154,11 @@ func initDeps(cfg gocfg.ICfg) *depidx.Deps {
} }
siteStore, err := sitestore.NewSiteStore(kv) siteStore, err := sitestore.NewSiteStore(kv)
if err != nil { if err != nil {
panic(fmt.Sprintf("fail to new site config store: %s", err)) panic(fmt.Sprintf("fail to init site config store: %s", err))
}
boltDB, err := boltstore.NewBoltStore(kv.Bolt())
if err != nil {
panic(fmt.Sprintf("fail to init bolt store: %s", err))
} }
err = siteStore.Init(&sitestore.SiteConfig{ err = siteStore.Init(&sitestore.SiteConfig{
@ -182,6 +188,7 @@ func initDeps(cfg gocfg.ICfg) *depidx.Deps {
deps.SetUsers(users) deps.SetUsers(users)
deps.SetFileInfos(fileInfos) deps.SetFileInfos(fileInfos)
deps.SetSiteStore(siteStore) deps.SetSiteStore(siteStore)
deps.SetBoltStore(boltDB)
deps.SetID(ider) deps.SetID(ider)
deps.SetLog(logger) deps.SetLog(logger)
deps.SetLimiter(limiter) deps.SetLimiter(limiter)

View file

@ -11,7 +11,7 @@ import (
"time" "time"
"github.com/ihexxa/quickshare/src/client" "github.com/ihexxa/quickshare/src/client"
"github.com/ihexxa/quickshare/src/db/fileinfostore" "github.com/ihexxa/quickshare/src/db"
q "github.com/ihexxa/quickshare/src/handlers" q "github.com/ihexxa/quickshare/src/handlers"
"github.com/ihexxa/quickshare/src/handlers/fileshdr" "github.com/ihexxa/quickshare/src/handlers/fileshdr"
) )
@ -631,7 +631,7 @@ func TestFileHandlers(t *testing.T) {
t.Fatal(res.StatusCode) t.Fatal(res.StatusCode)
} }
gotInfos := map[string]*fileinfostore.UploadInfo{} gotInfos := map[string]*db.UploadInfo{}
for _, info := range lResp.UploadInfos { for _, info := range lResp.UploadInfos {
gotInfos[info.RealFilePath] = info gotInfos[info.RealFilePath] = info
} }

View file

@ -10,6 +10,7 @@ import (
"testing" "testing"
"github.com/ihexxa/quickshare/src/client" "github.com/ihexxa/quickshare/src/client"
"github.com/ihexxa/quickshare/src/db"
"github.com/ihexxa/quickshare/src/db/userstore" "github.com/ihexxa/quickshare/src/db/userstore"
q "github.com/ihexxa/quickshare/src/handlers" q "github.com/ihexxa/quickshare/src/handlers"
"github.com/ihexxa/quickshare/src/handlers/settings" "github.com/ihexxa/quickshare/src/handlers/settings"
@ -105,7 +106,7 @@ func TestPermissions(t *testing.T) {
testUsersAPIs := func(desc, user string, pwd string, requireAuth bool, expectedCodes map[string]int) { testUsersAPIs := func(desc, user string, pwd string, requireAuth bool, expectedCodes map[string]int) {
newPwd := "12345" newPwd := "12345"
newRole := userstore.AdminRole newRole := userstore.AdminRole
newQuota := &userstore.Quota{ newQuota := &db.Quota{
SpaceLimit: int64(2046), SpaceLimit: int64(2046),
UploadSpeedLimit: int(8 * 1024 * 1024), UploadSpeedLimit: int(8 * 1024 * 1024),
DownloadSpeedLimit: int(8 * 1024 * 1024), DownloadSpeedLimit: int(8 * 1024 * 1024),

View file

@ -125,8 +125,8 @@ func TestSpaceLimit(t *testing.T) {
res, _, errs := cl.Create(filePath, 1) res, _, errs := cl.Create(filePath, 1)
if len(errs) > 0 { if len(errs) > 0 {
t.Fatal(errs) t.Fatal(errs)
} else if res.StatusCode != 429 { } else if res.StatusCode != 500 {
t.Fatal("(space limit): this request should be rejected") t.Fatalf("(space limit): this request should be rejected: %d", res.StatusCode)
} }
for i := 0; i < spaceLimit/fileSize; i++ { for i := 0; i < spaceLimit/fileSize; i++ {

View file

@ -8,6 +8,7 @@ import (
"testing" "testing"
"github.com/ihexxa/quickshare/src/client" "github.com/ihexxa/quickshare/src/client"
"github.com/ihexxa/quickshare/src/db"
"github.com/ihexxa/quickshare/src/db/sitestore" "github.com/ihexxa/quickshare/src/db/sitestore"
"github.com/ihexxa/quickshare/src/db/userstore" "github.com/ihexxa/quickshare/src/db/userstore"
q "github.com/ihexxa/quickshare/src/handlers" q "github.com/ihexxa/quickshare/src/handlers"
@ -120,14 +121,14 @@ func TestUsersHandlers(t *testing.T) {
}) })
t.Run("test users APIs: Login-Self-SetPwd-Logout-Login", func(t *testing.T) { t.Run("test users APIs: Login-Self-SetPwd-Logout-Login", func(t *testing.T) {
users := []*userstore.User{ users := []*db.User{
{ {
ID: 0, ID: 0,
Name: adminName, Name: adminName,
Pwd: adminPwd, Pwd: adminPwd,
Role: userstore.AdminRole, Role: userstore.AdminRole,
UsedSpace: 0, UsedSpace: 0,
Quota: &userstore.Quota{ Quota: &db.Quota{
UploadSpeedLimit: 50 * 1024 * 1024, UploadSpeedLimit: 50 * 1024 * 1024,
DownloadSpeedLimit: 50 * 1024 * 1024, DownloadSpeedLimit: 50 * 1024 * 1024,
SpaceLimit: 1024 * 1024 * 1024, SpaceLimit: 1024 * 1024 * 1024,
@ -139,7 +140,7 @@ func TestUsersHandlers(t *testing.T) {
Pwd: "Quicksh@re", Pwd: "Quicksh@re",
Role: userstore.UserRole, Role: userstore.UserRole,
UsedSpace: 0, UsedSpace: 0,
Quota: &userstore.Quota{ Quota: &db.Quota{
UploadSpeedLimit: 409600, UploadSpeedLimit: 409600,
DownloadSpeedLimit: 409600, DownloadSpeedLimit: 409600,
SpaceLimit: 1024, SpaceLimit: 1024,
@ -309,7 +310,7 @@ func TestUsersHandlers(t *testing.T) {
} }
} }
newRole, newQuota := userstore.AdminRole, &userstore.Quota{ newRole, newQuota := userstore.AdminRole, &db.Quota{
SpaceLimit: 3, SpaceLimit: 3,
UploadSpeedLimit: 3, UploadSpeedLimit: 3,
DownloadSpeedLimit: 3, DownloadSpeedLimit: 3,
@ -445,8 +446,8 @@ func TestUsersHandlers(t *testing.T) {
token := client.GetCookie(resp.Cookies(), su.TokenCookie) token := client.GetCookie(resp.Cookies(), su.TokenCookie)
prefers := []*userstore.Preferences{ prefers := []*db.Preferences{
&userstore.Preferences{ &db.Preferences{
Bg: &sitestore.BgConfig{ Bg: &sitestore.BgConfig{
Url: "/bgurl", Url: "/bgurl",
Repeat: "no-repeat", Repeat: "no-repeat",
@ -456,7 +457,7 @@ func TestUsersHandlers(t *testing.T) {
CSSURL: "/cssurl", CSSURL: "/cssurl",
LanPackURL: "/lanpack", LanPackURL: "/lanpack",
}, },
&userstore.Preferences{ &db.Preferences{
Bg: &sitestore.BgConfig{ Bg: &sitestore.BgConfig{
Url: "/bgurl2", Url: "/bgurl2",
Repeat: "no-repeat2", Repeat: "no-repeat2",

Binary file not shown.