fix(files): add boltdb store and refactor files handlers
This commit is contained in:
parent
044cdea1d4
commit
17b4544487
19 changed files with 751 additions and 402 deletions
|
@ -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,
|
||||||
|
|
377
src/db/boltstore/bolt_store.go
Normal file
377
src/db/boltstore/bolt_store.go
Normal 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)
|
||||||
|
})
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
7
src/kvstore/boltdbpvd/interface.go
Normal file
7
src/kvstore/boltdbpvd/interface.go
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
package boltdbpvd
|
||||||
|
|
||||||
|
import "github.com/boltdb/bolt"
|
||||||
|
|
||||||
|
type BoltProvider interface {
|
||||||
|
Bolt() *bolt.DB
|
||||||
|
}
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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++ {
|
||||||
|
|
|
@ -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",
|
||||||
|
|
BIN
src/server/testdata/test_quickshare.db
vendored
BIN
src/server/testdata/test_quickshare.db
vendored
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue