feat(db): add default rdb layer

This commit is contained in:
hexxa 2022-09-21 15:28:57 +08:00 committed by Hexxa
parent 61757aff4a
commit 5cae5be837
7 changed files with 732 additions and 561 deletions

View file

@ -2,14 +2,15 @@ package sqlite
import ( import (
"context" "context"
"database/sql"
"encoding/json" "encoding/json"
"github.com/ihexxa/quickshare/src/db" "github.com/ihexxa/quickshare/src/db"
) )
func (st *SQLiteStore) getCfg(ctx context.Context) (*db.SiteConfig, error) { func (st *SQLiteStore) getCfg(ctx context.Context, tx *sql.Tx) (*db.SiteConfig, error) {
var configStr string var configStr string
err := st.db.QueryRowContext( err := tx.QueryRowContext(
ctx, ctx,
`select config `select config
from t_config from t_config
@ -31,7 +32,7 @@ func (st *SQLiteStore) getCfg(ctx context.Context) (*db.SiteConfig, error) {
return config, nil return config, nil
} }
func (st *SQLiteStore) setCfg(ctx context.Context, cfg *db.SiteConfig) error { func (st *SQLiteStore) setCfg(ctx context.Context, tx *sql.Tx, cfg *db.SiteConfig) error {
if err := db.CheckSiteCfg(cfg, false); err != nil { if err := db.CheckSiteCfg(cfg, false); err != nil {
return err return err
} }
@ -41,7 +42,7 @@ func (st *SQLiteStore) setCfg(ctx context.Context, cfg *db.SiteConfig) error {
return err return err
} }
_, err = st.db.ExecContext( _, err = tx.ExecContext(
ctx, ctx,
`update t_config `update t_config
set config=? set config=?
@ -52,21 +53,32 @@ func (st *SQLiteStore) setCfg(ctx context.Context, cfg *db.SiteConfig) error {
} }
func (st *SQLiteStore) SetClientCfg(ctx context.Context, cfg *db.ClientConfig) error { func (st *SQLiteStore) SetClientCfg(ctx context.Context, cfg *db.ClientConfig) error {
st.Lock() tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
defer st.Unlock() if err != nil {
return err
}
defer tx.Rollback()
siteCfg, err := st.getCfg(ctx) siteCfg, err := st.getCfg(ctx, tx)
if err != nil { if err != nil {
return err return err
} }
siteCfg.ClientCfg = cfg siteCfg.ClientCfg = cfg
return st.setCfg(ctx, siteCfg) err = st.setCfg(ctx, tx, siteCfg)
if err != nil {
return err
}
return tx.Commit()
} }
func (st *SQLiteStore) GetCfg(ctx context.Context) (*db.SiteConfig, error) { func (st *SQLiteStore) GetCfg(ctx context.Context) (*db.SiteConfig, error) {
st.RLock() tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
defer st.RUnlock() if err != nil {
return nil, err
}
defer tx.Rollback()
return st.getCfg(ctx) return st.getCfg(ctx, tx)
} }

View file

@ -12,13 +12,13 @@ import (
"github.com/ihexxa/quickshare/src/db" "github.com/ihexxa/quickshare/src/db"
) )
func (st *SQLiteStore) getFileInfo(ctx context.Context, itemPath string) (*db.FileInfo, error) { func (st *SQLiteStore) getFileInfo(ctx context.Context, tx *sql.Tx, itemPath string) (*db.FileInfo, error) {
var infoStr string var infoStr string
fInfo := &db.FileInfo{} fInfo := &db.FileInfo{}
var isDir bool var isDir bool
var size int64 var size int64
var shareId string var shareId string
err := st.db.QueryRowContext( err := tx.QueryRowContext(
ctx, ctx,
`select is_dir, size, share_id, info `select is_dir, size, share_id, info
from t_file_info from t_file_info
@ -49,15 +49,21 @@ func (st *SQLiteStore) getFileInfo(ctx context.Context, itemPath string) (*db.Fi
} }
func (st *SQLiteStore) GetFileInfo(ctx context.Context, itemPath string) (*db.FileInfo, error) { func (st *SQLiteStore) GetFileInfo(ctx context.Context, itemPath string) (*db.FileInfo, error) {
st.RLock() tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
defer st.RUnlock() if err != nil {
return nil, err
}
defer tx.Rollback()
return st.getFileInfo(ctx, itemPath) return st.getFileInfo(ctx, tx, itemPath)
} }
func (st *SQLiteStore) ListFileInfos(ctx context.Context, itemPaths []string) (map[string]*db.FileInfo, error) { func (st *SQLiteStore) ListFileInfos(ctx context.Context, itemPaths []string) (map[string]*db.FileInfo, error) {
st.RLock() tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
defer st.RUnlock() if err != nil {
return nil, err
}
defer tx.Rollback()
// TODO: add pagination // TODO: add pagination
placeholders := []string{} placeholders := []string{}
@ -66,7 +72,7 @@ func (st *SQLiteStore) ListFileInfos(ctx context.Context, itemPaths []string) (m
placeholders = append(placeholders, "?") placeholders = append(placeholders, "?")
values = append(values, itemPaths[i]) values = append(values, itemPaths[i])
} }
rows, err := st.db.QueryContext( rows, err := tx.QueryContext(
ctx, ctx,
fmt.Sprintf( fmt.Sprintf(
`select path, is_dir, size, share_id, info `select path, is_dir, size, share_id, info
@ -88,7 +94,6 @@ func (st *SQLiteStore) ListFileInfos(ctx context.Context, itemPaths []string) (m
fInfos := map[string]*db.FileInfo{} fInfos := map[string]*db.FileInfo{}
for rows.Next() { for rows.Next() {
fInfo := &db.FileInfo{} fInfo := &db.FileInfo{}
err = rows.Scan(&itemPath, &isDir, &size, &shareId, &fInfoStr) err = rows.Scan(&itemPath, &isDir, &size, &shareId, &fInfoStr)
if err != nil { if err != nil {
return nil, err return nil, err
@ -111,7 +116,7 @@ func (st *SQLiteStore) ListFileInfos(ctx context.Context, itemPaths []string) (m
return fInfos, nil return fInfos, nil
} }
func (st *SQLiteStore) addFileInfo(ctx context.Context, userId uint64, itemPath string, info *db.FileInfo) error { func (st *SQLiteStore) addFileInfo(ctx context.Context, tx *sql.Tx, userId uint64, itemPath string, info *db.FileInfo) error {
infoStr, err := json.Marshal(info) infoStr, err := json.Marshal(info)
if err != nil { if err != nil {
return err return err
@ -123,7 +128,7 @@ func (st *SQLiteStore) addFileInfo(ctx context.Context, userId uint64, itemPath
} }
dirPath, itemName := path.Split(itemPath) dirPath, itemName := path.Split(itemPath)
_, err = st.db.ExecContext( _, err = tx.ExecContext(
ctx, ctx,
`insert into t_file_info ( `insert into t_file_info (
path, user, location, parent, name, path, user, location, parent, name,
@ -140,20 +145,27 @@ func (st *SQLiteStore) addFileInfo(ctx context.Context, userId uint64, itemPath
} }
func (st *SQLiteStore) AddFileInfo(ctx context.Context, userId uint64, itemPath string, info *db.FileInfo) error { func (st *SQLiteStore) AddFileInfo(ctx context.Context, userId uint64, itemPath string, info *db.FileInfo) error {
st.Lock() tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
defer st.Unlock() if err != nil {
return err
}
defer tx.Rollback()
err := st.addFileInfo(ctx, userId, itemPath, info) err = st.addFileInfo(ctx, tx, userId, itemPath, info)
if err != nil {
return err
}
// increase used space
err = st.setUsed(ctx, tx, userId, true, info.Size)
if err != nil { if err != nil {
return err return err
} }
// increase used space return tx.Commit()
return st.setUsed(ctx, userId, true, info.Size)
} }
func (st *SQLiteStore) delFileInfo(ctx context.Context, itemPath string) error { func (st *SQLiteStore) delFileInfo(ctx context.Context, tx *sql.Tx, itemPath string) error {
_, err := st.db.ExecContext( _, err := tx.ExecContext(
ctx, ctx,
`delete from t_file_info `delete from t_file_info
where path=? where path=?
@ -164,10 +176,13 @@ func (st *SQLiteStore) delFileInfo(ctx context.Context, itemPath string) error {
} }
func (st *SQLiteStore) SetSha1(ctx context.Context, itemPath, sign string) error { func (st *SQLiteStore) SetSha1(ctx context.Context, itemPath, sign string) error {
st.Lock() tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
defer st.Unlock() if err != nil {
return err
}
defer tx.Rollback()
info, err := st.getFileInfo(ctx, itemPath) info, err := st.getFileInfo(ctx, tx, itemPath)
if err != nil { if err != nil {
return err return err
} }
@ -178,7 +193,7 @@ func (st *SQLiteStore) SetSha1(ctx context.Context, itemPath, sign string) error
return err return err
} }
_, err = st.db.ExecContext( _, err = tx.ExecContext(
ctx, ctx,
`update t_file_info `update t_file_info
set info=? set info=?
@ -186,15 +201,21 @@ func (st *SQLiteStore) SetSha1(ctx context.Context, itemPath, sign string) error
infoStr, infoStr,
itemPath, itemPath,
) )
return err if err != nil {
return err
}
return tx.Commit()
} }
func (st *SQLiteStore) DelFileInfo(ctx context.Context, userID uint64, itemPath string) error { func (st *SQLiteStore) DelFileInfo(ctx context.Context, userID uint64, itemPath string) error {
st.Lock() tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
defer st.Unlock() if err != nil {
return err
}
defer tx.Rollback()
// get all children and size // get all children and size
rows, err := st.db.QueryContext( rows, err := tx.QueryContext(
ctx, ctx,
`select path, size `select path, size
from t_file_info from t_file_info
@ -224,13 +245,13 @@ func (st *SQLiteStore) DelFileInfo(ctx context.Context, userID uint64, itemPath
} }
// decrease used space // decrease used space
err = st.setUsed(ctx, userID, false, decrSize) err = st.setUsed(ctx, tx, userID, false, decrSize)
if err != nil { if err != nil {
return err return err
} }
// delete file info entries // delete file info entries
_, err = st.db.ExecContext( _, err = tx.ExecContext(
ctx, ctx,
fmt.Sprintf( fmt.Sprintf(
`delete from t_file_info `delete from t_file_info
@ -239,14 +260,20 @@ func (st *SQLiteStore) DelFileInfo(ctx context.Context, userID uint64, itemPath
), ),
values..., values...,
) )
return err if err != nil {
return err
}
return tx.Commit()
} }
func (st *SQLiteStore) MoveFileInfo(ctx context.Context, userId uint64, oldPath, newPath string, isDir bool) error { func (st *SQLiteStore) MoveFileInfo(ctx context.Context, userId uint64, oldPath, newPath string, isDir bool) error {
st.Lock() tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
defer st.Unlock() if err != nil {
return err
}
defer tx.Rollback()
info, err := st.getFileInfo(ctx, oldPath) info, err := st.getFileInfo(ctx, tx, oldPath)
if err != nil { if err != nil {
if errors.Is(err, db.ErrFileInfoNotFound) { if errors.Is(err, db.ErrFileInfoNotFound) {
// info for file does not exist so no need to move it // info for file does not exist so no need to move it
@ -256,11 +283,18 @@ func (st *SQLiteStore) MoveFileInfo(ctx context.Context, userId uint64, oldPath,
} }
return err return err
} }
err = st.delFileInfo(ctx, oldPath)
err = st.delFileInfo(ctx, tx, oldPath)
if err != nil { if err != nil {
return err return err
} }
return st.addFileInfo(ctx, userId, newPath, info)
err = st.addFileInfo(ctx, tx, userId, newPath, info)
if err != nil {
return err
}
return tx.Commit()
} }
func getLocation(itemPath string) (string, error) { func getLocation(itemPath string) (string, error) {

View file

@ -30,11 +30,14 @@ func (st *SQLiteStore) generateShareID(payload string) (string, error) {
} }
func (st *SQLiteStore) IsSharing(ctx context.Context, dirPath string) (bool, error) { func (st *SQLiteStore) IsSharing(ctx context.Context, dirPath string) (bool, error) {
st.RLock() tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
defer st.RUnlock() if err != nil {
return false, err
}
defer tx.Rollback()
var shareId string var shareId string
err := st.db.QueryRowContext( err = tx.QueryRowContext(
ctx, ctx,
`select share_id `select share_id
from t_file_info from t_file_info
@ -54,11 +57,14 @@ func (st *SQLiteStore) IsSharing(ctx context.Context, dirPath string) (bool, err
} }
func (st *SQLiteStore) GetSharingDir(ctx context.Context, hashID string) (string, error) { func (st *SQLiteStore) GetSharingDir(ctx context.Context, hashID string) (string, error) {
st.RLock() tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
defer st.RUnlock() if err != nil {
return "", err
}
defer tx.Rollback()
var sharedPath string var sharedPath string
err := st.db.QueryRowContext( err = tx.QueryRowContext(
ctx, ctx,
`select path `select path
from t_file_info from t_file_info
@ -79,8 +85,11 @@ func (st *SQLiteStore) GetSharingDir(ctx context.Context, hashID string) (string
} }
func (st *SQLiteStore) AddSharing(ctx context.Context, userId uint64, dirPath string) error { func (st *SQLiteStore) AddSharing(ctx context.Context, userId uint64, dirPath string) error {
st.Lock() tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
defer st.Unlock() if err != nil {
return err
}
defer tx.Rollback()
shareID, err := st.generateShareID(dirPath) shareID, err := st.generateShareID(dirPath)
if err != nil { if err != nil {
@ -92,7 +101,7 @@ func (st *SQLiteStore) AddSharing(ctx context.Context, userId uint64, dirPath st
return err return err
} }
_, err = st.getFileInfo(ctx, dirPath) _, err = st.getFileInfo(ctx, tx, dirPath)
if err != nil && !errors.Is(err, db.ErrFileInfoNotFound) { if err != nil && !errors.Is(err, db.ErrFileInfoNotFound) {
return err return err
} }
@ -106,7 +115,7 @@ func (st *SQLiteStore) AddSharing(ctx context.Context, userId uint64, dirPath st
return err return err
} }
_, err = st.db.ExecContext( _, err = tx.ExecContext(
ctx, ctx,
`insert into t_file_info ( `insert into t_file_info (
path, user, location, parent, name, path, user, location, parent, name,
@ -119,38 +128,53 @@ func (st *SQLiteStore) AddSharing(ctx context.Context, userId uint64, dirPath st
dirPath, userId, location, parentPath, name, dirPath, userId, location, parentPath, name,
true, 0, shareID, infoStr, true, 0, shareID, infoStr,
) )
return err if err != nil {
return err
}
} else {
_, err = tx.ExecContext(
ctx,
`update t_file_info
set share_id=?
where path=?`,
shareID, dirPath,
)
if err != nil {
return err
}
} }
_, err = st.db.ExecContext( return tx.Commit()
ctx,
`update t_file_info
set share_id=?
where path=?`,
shareID, dirPath,
)
return err
} }
func (st *SQLiteStore) DelSharing(ctx context.Context, userId uint64, dirPath string) error { func (st *SQLiteStore) DelSharing(ctx context.Context, userId uint64, dirPath string) error {
st.Lock() tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
defer st.Unlock() if err != nil {
return err
}
defer tx.Rollback()
_, err := st.db.ExecContext( _, err = tx.ExecContext(
ctx, ctx,
`update t_file_info `update t_file_info
set share_id='' set share_id=''
where path=?`, where path=?`,
dirPath, dirPath,
) )
return err if err != nil {
return err
}
return tx.Commit()
} }
func (st *SQLiteStore) ListSharingsByLocation(ctx context.Context, location string) (map[string]string, error) { func (st *SQLiteStore) ListSharingsByLocation(ctx context.Context, location string) (map[string]string, error) {
st.RLock() tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
defer st.RUnlock() if err != nil {
return nil, err
}
defer tx.Rollback()
rows, err := st.db.QueryContext( rows, err := tx.QueryContext(
ctx, ctx,
`select path, share_id `select path, share_id
from t_file_info from t_file_info

View file

@ -8,8 +8,8 @@ import (
"github.com/ihexxa/quickshare/src/db" "github.com/ihexxa/quickshare/src/db"
) )
func (st *SQLiteStore) addUploadInfoOnly(ctx context.Context, userId uint64, tmpPath, filePath string, fileSize int64) error { func (st *SQLiteStore) addUploadInfoOnly(ctx context.Context, tx *sql.Tx, userId uint64, tmpPath, filePath string, fileSize int64) error {
_, err := st.db.ExecContext( _, err := tx.ExecContext(
ctx, ctx,
`insert into t_file_uploading ( `insert into t_file_uploading (
real_path, tmp_path, user, size, uploaded real_path, tmp_path, user, size, uploaded
@ -23,17 +23,20 @@ func (st *SQLiteStore) addUploadInfoOnly(ctx context.Context, userId uint64, tmp
} }
func (st *SQLiteStore) AddUploadInfos(ctx context.Context, userId uint64, tmpPath, filePath string, info *db.FileInfo) error { func (st *SQLiteStore) AddUploadInfos(ctx context.Context, userId uint64, tmpPath, filePath string, info *db.FileInfo) error {
st.Lock() tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
defer st.Unlock() if err != nil {
return err
}
defer tx.Rollback()
userInfo, err := st.getUser(ctx, userId) userInfo, err := st.getUser(ctx, tx, userId)
if err != nil { if err != nil {
return err return err
} else if userInfo.UsedSpace+info.Size > int64(userInfo.Quota.SpaceLimit) { } else if userInfo.UsedSpace+info.Size > int64(userInfo.Quota.SpaceLimit) {
return db.ErrQuota return db.ErrQuota
} }
_, _, _, err = st.getUploadInfo(ctx, userId, filePath) _, _, _, err = st.getUploadInfo(ctx, tx, userId, filePath)
if err == nil { if err == nil {
return db.ErrKeyExisting return db.ErrKeyExisting
} else if err != nil && !errors.Is(err, sql.ErrNoRows) { } else if err != nil && !errors.Is(err, sql.ErrNoRows) {
@ -41,43 +44,56 @@ func (st *SQLiteStore) AddUploadInfos(ctx context.Context, userId uint64, tmpPat
} }
userInfo.UsedSpace += info.Size userInfo.UsedSpace += info.Size
err = st.setUser(ctx, userInfo) err = st.setUser(ctx, tx, userInfo)
if err != nil { if err != nil {
return err return err
} }
return st.addUploadInfoOnly(ctx, userId, tmpPath, filePath, info.Size) err = st.addUploadInfoOnly(ctx, tx, userId, tmpPath, filePath, info.Size)
if err != nil {
return err
}
return tx.Commit()
} }
func (st *SQLiteStore) DelUploadingInfos(ctx context.Context, userId uint64, realPath string) error { func (st *SQLiteStore) DelUploadingInfos(ctx context.Context, userId uint64, realPath string) error {
st.Lock() tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
defer st.Unlock() if err != nil {
return err
}
defer tx.Rollback()
return st.delUploadingInfos(ctx, userId, realPath) err = st.delUploadingInfos(ctx, tx, userId, realPath)
if err != nil {
return err
}
return tx.Commit()
} }
func (st *SQLiteStore) delUploadingInfos(ctx context.Context, userId uint64, realPath string) error { func (st *SQLiteStore) delUploadingInfos(ctx context.Context, tx *sql.Tx, userId uint64, realPath string) error {
_, size, _, err := st.getUploadInfo(ctx, userId, realPath) _, size, _, err := st.getUploadInfo(ctx, tx, userId, realPath)
if err != nil { if err != nil {
// info may not exist // info may not exist
return err return err
} }
err = st.delUploadInfoOnly(ctx, userId, realPath) err = st.delUploadInfoOnly(ctx, tx, userId, realPath)
if err != nil { if err != nil {
return err return err
} }
userInfo, err := st.getUser(ctx, userId) userInfo, err := st.getUser(ctx, tx, userId)
if err != nil { if err != nil {
return err return err
} }
userInfo.UsedSpace -= size userInfo.UsedSpace -= size
return st.setUser(ctx, userInfo) return st.setUser(ctx, tx, userInfo)
} }
func (st *SQLiteStore) delUploadInfoOnly(ctx context.Context, userId uint64, filePath string) error { func (st *SQLiteStore) delUploadInfoOnly(ctx context.Context, tx *sql.Tx, userId uint64, filePath string) error {
_, err := st.db.ExecContext( _, err := tx.ExecContext(
ctx, ctx,
`delete from t_file_uploading `delete from t_file_uploading
where real_path=? and user=?`, where real_path=? and user=?`,
@ -87,28 +103,39 @@ func (st *SQLiteStore) delUploadInfoOnly(ctx context.Context, userId uint64, fil
} }
func (st *SQLiteStore) MoveUploadingInfos(ctx context.Context, userId uint64, uploadPath, itemPath string) error { func (st *SQLiteStore) MoveUploadingInfos(ctx context.Context, userId uint64, uploadPath, itemPath string) error {
st.Lock() tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
defer st.Unlock() if err != nil {
return err
}
defer tx.Rollback()
_, size, _, err := st.getUploadInfo(ctx, userId, itemPath) _, size, _, err := st.getUploadInfo(ctx, tx, userId, itemPath)
if err != nil { if err != nil {
return err return err
} }
err = st.delUploadInfoOnly(ctx, userId, itemPath) err = st.delUploadInfoOnly(ctx, tx, userId, itemPath)
if err != nil { if err != nil {
return err return err
} }
return st.addFileInfo(ctx, userId, itemPath, &db.FileInfo{ err = st.addFileInfo(ctx, tx, userId, itemPath, &db.FileInfo{
Size: size, Size: size,
}) })
if err != nil {
return err
}
return tx.Commit()
} }
func (st *SQLiteStore) SetUploadInfo(ctx context.Context, userId uint64, filePath string, newUploaded int64) error { func (st *SQLiteStore) SetUploadInfo(ctx context.Context, userId uint64, filePath string, newUploaded int64) error {
st.Lock() tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
defer st.Unlock() if err != nil {
return err
}
defer tx.Rollback()
var size, uploaded int64 var size, uploaded int64
err := st.db.QueryRowContext( err = tx.QueryRowContext(
ctx, ctx,
`select size, uploaded `select size, uploaded
from t_file_uploading from t_file_uploading
@ -121,19 +148,24 @@ func (st *SQLiteStore) SetUploadInfo(ctx context.Context, userId uint64, filePat
return db.ErrGreaterThanSize return db.ErrGreaterThanSize
} }
_, err = st.db.ExecContext( _, err = tx.ExecContext(
ctx, ctx,
`update t_file_uploading `update t_file_uploading
set uploaded=? set uploaded=?
where real_path=? and user=?`, where real_path=? and user=?`,
newUploaded, filePath, userId, newUploaded, filePath, userId,
) )
return err if err != nil {
return err
}
return tx.Commit()
} }
func (st *SQLiteStore) getUploadInfo(ctx context.Context, userId uint64, filePath string) (string, int64, int64, error) { func (st *SQLiteStore) getUploadInfo(
ctx context.Context, tx *sql.Tx, userId uint64, filePath string,
) (string, int64, int64, error) {
var size, uploaded int64 var size, uploaded int64
err := st.db.QueryRowContext( err := tx.QueryRowContext(
ctx, ctx,
`select size, uploaded `select size, uploaded
from t_file_uploading from t_file_uploading
@ -148,16 +180,23 @@ func (st *SQLiteStore) getUploadInfo(ctx context.Context, userId uint64, filePat
} }
func (st *SQLiteStore) GetUploadInfo(ctx context.Context, userId uint64, filePath string) (string, int64, int64, error) { func (st *SQLiteStore) GetUploadInfo(ctx context.Context, userId uint64, filePath string) (string, int64, int64, error) {
st.RLock() tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
defer st.RUnlock() if err != nil {
return st.getUploadInfo(ctx, userId, filePath) return "", 0, 0, err
}
defer tx.Rollback()
return st.getUploadInfo(ctx, tx, userId, filePath)
} }
func (st *SQLiteStore) ListUploadInfos(ctx context.Context, userId uint64) ([]*db.UploadInfo, error) { func (st *SQLiteStore) ListUploadInfos(ctx context.Context, userId uint64) ([]*db.UploadInfo, error) {
st.RLock() tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
defer st.RUnlock() if err != nil {
return nil, err
}
defer tx.Rollback()
rows, err := st.db.QueryContext( rows, err := tx.QueryContext(
ctx, ctx,
`select real_path, size, uploaded `select real_path, size, uploaded
from t_file_uploading from t_file_uploading

View file

@ -16,7 +16,7 @@ type SQLiteStore struct {
mtx *sync.RWMutex mtx *sync.RWMutex
} }
func (st *SQLiteStore) setUser(ctx context.Context, user *db.User) error { func (st *SQLiteStore) setUser(ctx context.Context, tx *sql.Tx, user *db.User) error {
var err error var err error
if err = db.CheckUser(user, false); err != nil { if err = db.CheckUser(user, false); err != nil {
return err return err
@ -30,7 +30,7 @@ func (st *SQLiteStore) setUser(ctx context.Context, user *db.User) error {
if err != nil { if err != nil {
return err return err
} }
_, err = st.db.ExecContext( _, err = tx.ExecContext(
ctx, ctx,
`update t_user `update t_user
set name=?, pwd=?, role=?, used_space=?, quota=?, preference=? set name=?, pwd=?, role=?, used_space=?, quota=?, preference=?
@ -46,10 +46,10 @@ func (st *SQLiteStore) setUser(ctx context.Context, user *db.User) error {
return err return err
} }
func (st *SQLiteStore) getUser(ctx context.Context, id uint64) (*db.User, error) { func (st *SQLiteStore) getUser(ctx context.Context, tx *sql.Tx, id uint64) (*db.User, error) {
user := &db.User{} user := &db.User{}
var quotaStr, preferenceStr string var quotaStr, preferenceStr string
err := st.db.QueryRowContext( err := tx.QueryRowContext(
ctx, ctx,
`select id, name, pwd, role, used_space, quota, preference `select id, name, pwd, role, used_space, quota, preference
from t_user from t_user
@ -83,8 +83,11 @@ func (st *SQLiteStore) getUser(ctx context.Context, id uint64) (*db.User, error)
} }
func (st *SQLiteStore) AddUser(ctx context.Context, user *db.User) error { func (st *SQLiteStore) AddUser(ctx context.Context, user *db.User) error {
st.Lock() tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
defer st.Unlock() if err != nil {
return err
}
defer tx.Rollback()
quotaStr, err := json.Marshal(user.Quota) quotaStr, err := json.Marshal(user.Quota)
if err != nil { if err != nil {
@ -94,7 +97,7 @@ func (st *SQLiteStore) AddUser(ctx context.Context, user *db.User) error {
if err != nil { if err != nil {
return err return err
} }
_, err = st.db.ExecContext( _, err = tx.ExecContext(
ctx, ctx,
`insert into t_user (id, name, pwd, role, used_space, quota, preference) values (?, ?, ?, ?, ?, ?, ?)`, `insert into t_user (id, name, pwd, role, used_space, quota, preference) values (?, ?, ?, ?, ?, ?, ?)`,
user.ID, user.ID,
@ -105,26 +108,40 @@ func (st *SQLiteStore) AddUser(ctx context.Context, user *db.User) error {
quotaStr, quotaStr,
preferenceStr, preferenceStr,
) )
return err if err != nil {
return err
}
return tx.Commit()
} }
func (st *SQLiteStore) DelUser(ctx context.Context, id uint64) error { func (st *SQLiteStore) DelUser(ctx context.Context, id uint64) error {
st.Lock() tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
defer st.Unlock() if err != nil {
return err
}
defer tx.Rollback()
_, err := st.db.ExecContext( _, err = tx.ExecContext(
ctx, ctx,
`delete from t_user where id=?`, `delete from t_user where id=?`,
id, id,
) )
return err if err != nil {
return err
}
return tx.Commit()
} }
func (st *SQLiteStore) GetUser(ctx context.Context, id uint64) (*db.User, error) { func (st *SQLiteStore) GetUser(ctx context.Context, id uint64) (*db.User, error) {
st.RLock() tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
defer st.RUnlock() if err != nil {
return nil, err
}
defer tx.Rollback()
user, err := st.getUser(ctx, id) user, err := st.getUser(ctx, tx, id)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -133,12 +150,15 @@ func (st *SQLiteStore) GetUser(ctx context.Context, id uint64) (*db.User, error)
} }
func (st *SQLiteStore) GetUserByName(ctx context.Context, name string) (*db.User, error) { func (st *SQLiteStore) GetUserByName(ctx context.Context, name string) (*db.User, error) {
st.RLock() tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
defer st.RUnlock() if err != nil {
return nil, err
}
defer tx.Rollback()
user := &db.User{} user := &db.User{}
var quotaStr, preferenceStr string var quotaStr, preferenceStr string
err := st.db.QueryRowContext( err = tx.QueryRowContext(
ctx, ctx,
`select id, name, pwd, role, used_space, quota, preference `select id, name, pwd, role, used_space, quota, preference
from t_user from t_user
@ -172,10 +192,13 @@ func (st *SQLiteStore) GetUserByName(ctx context.Context, name string) (*db.User
} }
func (st *SQLiteStore) SetPwd(ctx context.Context, id uint64, pwd string) error { func (st *SQLiteStore) SetPwd(ctx context.Context, id uint64, pwd string) error {
st.Lock() tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
defer st.Unlock() if err != nil {
return err
}
defer tx.Rollback()
_, err := st.db.ExecContext( _, err = tx.ExecContext(
ctx, ctx,
`update t_user `update t_user
set pwd=? set pwd=?
@ -183,20 +206,27 @@ func (st *SQLiteStore) SetPwd(ctx context.Context, id uint64, pwd string) error
pwd, pwd,
id, id,
) )
return err if err != nil {
return err
}
return tx.Commit()
} }
// role + quota // role + quota
func (st *SQLiteStore) SetInfo(ctx context.Context, id uint64, user *db.User) error { func (st *SQLiteStore) SetInfo(ctx context.Context, id uint64, user *db.User) error {
st.Lock() tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
defer st.Unlock() if err != nil {
return err
}
defer tx.Rollback()
quotaStr, err := json.Marshal(user.Quota) quotaStr, err := json.Marshal(user.Quota)
if err != nil { if err != nil {
return err return err
} }
_, err = st.db.ExecContext( _, err = tx.ExecContext(
ctx, ctx,
`update t_user `update t_user
set role=?, quota=? set role=?, quota=?
@ -204,19 +234,26 @@ func (st *SQLiteStore) SetInfo(ctx context.Context, id uint64, user *db.User) er
user.Role, quotaStr, user.Role, quotaStr,
id, id,
) )
return err if err != nil {
return err
}
return tx.Commit()
} }
func (st *SQLiteStore) SetPreferences(ctx context.Context, id uint64, prefers *db.Preferences) error { func (st *SQLiteStore) SetPreferences(ctx context.Context, id uint64, prefers *db.Preferences) error {
st.Lock() tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
defer st.Unlock() if err != nil {
return err
}
defer tx.Rollback()
preferenceStr, err := json.Marshal(prefers) preferenceStr, err := json.Marshal(prefers)
if err != nil { if err != nil {
return err return err
} }
_, err = st.db.ExecContext( _, err = tx.ExecContext(
ctx, ctx,
`update t_user `update t_user
set preference=? set preference=?
@ -224,17 +261,29 @@ func (st *SQLiteStore) SetPreferences(ctx context.Context, id uint64, prefers *d
preferenceStr, preferenceStr,
id, id,
) )
return err if err != nil {
return err
}
return tx.Commit()
} }
func (st *SQLiteStore) SetUsed(ctx context.Context, id uint64, incr bool, capacity int64) error { func (st *SQLiteStore) SetUsed(ctx context.Context, id uint64, incr bool, capacity int64) error {
st.Lock() tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
defer st.Unlock() if err != nil {
return st.setUsed(ctx, id, incr, capacity) return err
}
defer tx.Rollback()
err = st.setUsed(ctx, tx, id, incr, capacity)
if err != nil {
return err
}
return tx.Commit()
} }
func (st *SQLiteStore) setUsed(ctx context.Context, id uint64, incr bool, capacity int64) error { func (st *SQLiteStore) setUsed(ctx context.Context, tx *sql.Tx, id uint64, incr bool, capacity int64) error {
gotUser, err := st.getUser(ctx, id) gotUser, err := st.getUser(ctx, tx, id)
if err != nil { if err != nil {
return err return err
} }
@ -252,7 +301,7 @@ func (st *SQLiteStore) setUsed(ctx context.Context, id uint64, incr bool, capaci
gotUser.UsedSpace = gotUser.UsedSpace - capacity gotUser.UsedSpace = gotUser.UsedSpace - capacity
} }
_, err = st.db.ExecContext( _, err = tx.ExecContext(
ctx, ctx,
`update t_user `update t_user
set used_space=? set used_space=?
@ -260,18 +309,17 @@ func (st *SQLiteStore) setUsed(ctx context.Context, id uint64, incr bool, capaci
gotUser.UsedSpace, gotUser.UsedSpace,
gotUser.ID, gotUser.ID,
) )
if err != nil { return err
return err
}
return nil
} }
func (st *SQLiteStore) ResetUsed(ctx context.Context, id uint64, used int64) error { func (st *SQLiteStore) ResetUsed(ctx context.Context, id uint64, used int64) error {
st.Lock() tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
defer st.Unlock() if err != nil {
return err
}
defer tx.Rollback()
_, err := st.db.ExecContext( _, err = tx.ExecContext(
ctx, ctx,
`update t_user `update t_user
set used_space=? set used_space=?
@ -279,15 +327,16 @@ func (st *SQLiteStore) ResetUsed(ctx context.Context, id uint64, used int64) err
used, used,
id, id,
) )
return err if err != nil {
return err
}
return tx.Commit()
} }
func (st *SQLiteStore) ListUsers(ctx context.Context) ([]*db.User, error) { func (st *SQLiteStore) listUsers(ctx context.Context, tx *sql.Tx) ([]*db.User, error) {
st.RLock()
defer st.RUnlock()
// TODO: support pagination // TODO: support pagination
rows, err := st.db.QueryContext( rows, err := tx.QueryContext(
ctx, ctx,
`select id, name, role, used_space, quota, preference `select id, name, role, used_space, quota, preference
from t_user`, from t_user`,
@ -329,11 +378,24 @@ func (st *SQLiteStore) ListUsers(ctx context.Context) ([]*db.User, error) {
return users, nil return users, nil
} }
func (st *SQLiteStore) ListUserIDs(ctx context.Context) (map[string]string, error) { func (st *SQLiteStore) ListUsers(ctx context.Context) ([]*db.User, error) {
st.RLock() tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
defer st.RUnlock() if err != nil {
return nil, err
}
defer tx.Rollback()
users, err := st.ListUsers(ctx) return st.listUsers(ctx, tx)
}
func (st *SQLiteStore) ListUserIDs(ctx context.Context) (map[string]string, error) {
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
if err != nil {
return nil, err
}
defer tx.Rollback()
users, err := st.listUsers(ctx, tx)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -15,406 +15,6 @@ import (
) )
func TestFileStore(t *testing.T) { func TestFileStore(t *testing.T) {
testSharingMethods := func(t *testing.T, store db.IDBQuickshare) {
dirPaths := []string{"admin/path1", "admin/path1/path2"}
var err error
location := "admin"
ctx := context.TODO()
adminId := uint64(0)
// add some of paths...
err = store.AddFileInfo(ctx, adminId, "admin/path1", &db.FileInfo{
// Shared: false, // deprecated
IsDir: false,
Size: int64(0),
ShareID: "",
Sha1: "",
})
if err != nil {
t.Fatal(err)
}
// add sharings
for _, dirPath := range dirPaths {
err = store.AddSharing(ctx, adminId, dirPath)
if err != nil {
t.Fatal(err)
}
}
// list sharings
dirToID, err := store.ListSharingsByLocation(ctx, location)
if err != nil {
t.Fatal(err)
} else if len(dirToID) != len(dirPaths) {
t.Fatal("share size not match")
}
for _, sharingDir := range dirPaths {
if _, ok := dirToID[sharingDir]; !ok {
t.Fatalf("sharing(%s) not found", sharingDir)
}
mustTrue, err := store.IsSharing(ctx, sharingDir)
if err != nil {
t.Fatal(err)
} else if !mustTrue {
t.Fatalf("get sharing(%t) should exist", mustTrue)
}
info, err := store.GetFileInfo(ctx, sharingDir)
if err != nil {
t.Fatal(err)
} else if len(info.ShareID) != 7 {
t.Fatalf("incorrect ShareID %s", info.ShareID)
}
gotSharingDir, err := store.GetSharingDir(ctx, info.ShareID)
if err != nil {
t.Fatal(err)
} else if sharingDir != gotSharingDir {
t.Fatalf("sharing dir not consist: (%s) (%s)", sharingDir, gotSharingDir)
}
}
// del sharings
for _, dirPath := range dirPaths {
err = store.DelSharing(ctx, adminId, dirPath)
if err != nil {
t.Fatal(err)
}
}
// list sharings
dirToIDAfterDel, err := store.ListSharingsByLocation(ctx, location)
if err != nil {
t.Fatal(err)
} else if len(dirToIDAfterDel) != 0 {
t.Fatalf("share size not match (%+v)", dirToIDAfterDel)
}
for _, dirPath := range dirPaths {
if _, ok := dirToIDAfterDel[dirPath]; ok {
t.Fatalf("sharing(%s) should not exist", dirPath)
}
shared, err := store.IsSharing(ctx, dirPath)
if err != nil {
t.Fatal(err)
} else if shared {
t.Fatalf("get sharing(%t) should not shared but exist", shared)
}
info, err := store.GetFileInfo(ctx, dirPath)
if err != nil {
t.Fatal(err)
} else if len(info.ShareID) != 0 {
t.Fatalf("ShareID should be empty %s", info.ShareID)
}
// shareIDs are removed, use original dirToID to get shareID
originalShareID, ok := dirToID[dirPath]
if !ok {
t.Fatalf("dir (%s) should exist in originalShareID", dirPath)
}
_, err = store.GetSharingDir(ctx, originalShareID)
if !errors.Is(err, db.ErrSharingNotFound) {
t.Fatal("should return ErrSharingNotFound")
}
}
}
testFileInfoMethods := func(t *testing.T, store db.IDBQuickshare) {
pathInfos := map[string]*db.FileInfo{
"admin/origin/item1": &db.FileInfo{
// Shared: false, // deprecated
IsDir: false,
Size: int64(7),
ShareID: "",
Sha1: "item1_sha",
},
"admin/origin/item2": &db.FileInfo{
// Shared: false, // deprecated
IsDir: false,
Size: int64(3),
ShareID: "",
Sha1: "item2_sha",
},
"admin/origin/dir": &db.FileInfo{
// Shared: true, // deprecated
IsDir: true,
Size: int64(0),
ShareID: "mockedShareID",
Sha1: "",
},
}
var err error
adminId := uint64(0)
ctx := context.TODO()
// add infos
usedSpace := int64(0)
itemPaths := []string{}
for itemPath, info := range pathInfos {
err = store.AddFileInfo(ctx, adminId, itemPath, info)
if err != nil {
t.Fatal(err)
}
usedSpace += info.Size
itemPaths = append(itemPaths, itemPath)
}
// get infos
for itemPath, expected := range pathInfos {
info, err := store.GetFileInfo(ctx, itemPath)
if err != nil {
t.Fatal(err)
}
if info.ShareID != expected.ShareID ||
info.IsDir != expected.IsDir ||
info.Sha1 != expected.Sha1 ||
info.Size != expected.Size {
t.Fatalf("info not equaled (%v) (%v)", expected, info)
}
}
// list infos
pathToInfo, err := store.ListFileInfos(ctx, itemPaths)
if err != nil {
t.Fatal(err)
} else if len(pathToInfo) != len(pathInfos) {
t.Fatalf("list result size not match (%v) (%d)", pathToInfo, len(pathInfos))
}
for pathname, info := range pathInfos {
gotInfo, ok := pathToInfo[pathname]
if !ok {
t.Fatalf("path not found (%s)", pathname)
}
if info.ShareID != gotInfo.ShareID ||
info.IsDir != gotInfo.IsDir ||
info.Sha1 != gotInfo.Sha1 ||
info.Size != gotInfo.Size {
t.Fatalf("info not equaled (%v) (%v)", gotInfo, info)
}
}
// set sha1
testSha1 := "sha1"
for itemPath := range pathInfos {
err := store.SetSha1(ctx, itemPath, testSha1)
if err != nil {
t.Fatal(err)
}
info, err := store.GetFileInfo(ctx, itemPath)
if err != nil {
t.Fatal(err)
}
if info.Sha1 != testSha1 {
t.Fatalf("sha not equaled (%v) (%v)", info.Sha1, testSha1)
}
}
// move paths
newPaths := []string{}
for itemPath, info := range pathInfos {
newItemPath := strings.ReplaceAll(itemPath, "origin", "new")
err = store.MoveFileInfo(ctx, adminId, itemPath, newItemPath, info.IsDir)
if err != nil {
t.Fatal(err)
}
newPaths = append(newPaths, newItemPath)
}
// list infos
pathToInfo, err = store.ListFileInfos(ctx, newPaths)
if err != nil {
t.Fatal(err)
} else if len(pathToInfo) != len(pathInfos) {
t.Fatalf("list result size not match (%v) (%d)", pathToInfo, len(pathInfos))
}
// check used space
adminInfo, err := store.GetUser(ctx, adminId)
if err != nil {
t.Fatal(err)
} else if adminInfo.UsedSpace != usedSpace {
t.Fatalf("used space not match (%d) (%d)", adminInfo.UsedSpace, usedSpace)
}
// del info
for _, itemPath := range newPaths {
err = store.DelFileInfo(ctx, adminId, itemPath)
if err != nil {
t.Fatal(err)
}
}
// check used space
adminInfo, err = store.GetUser(ctx, adminId)
if err != nil {
t.Fatal(err)
} else if adminInfo.UsedSpace != int64(0) {
t.Fatalf("used space not match (%d) (%d)", adminInfo.UsedSpace, int64(0))
}
// list infos
pathToInfo, err = store.ListFileInfos(ctx, itemPaths)
if err != nil {
t.Fatal(err)
} else if len(pathToInfo) != 0 {
t.Fatalf("list result should be empty (%v)", pathToInfo)
}
for itemPath := range pathInfos {
_, err := store.GetFileInfo(ctx, itemPath)
if !errors.Is(err, db.ErrFileInfoNotFound) {
t.Fatal(err)
}
}
}
testUploadingMethods := func(t *testing.T, store db.IDBQuickshare) {
pathInfos := map[string]*db.FileInfo{
"admin/origin/item1": &db.FileInfo{
// Shared: false, // deprecated
IsDir: false,
Size: int64(7),
ShareID: "",
Sha1: "",
},
"admin/origin/item2": &db.FileInfo{
// Shared: false, // deprecated
IsDir: false,
Size: int64(3),
ShareID: "",
Sha1: "",
},
"admin/origin/to_delete/item3": &db.FileInfo{
// Shared: false, // deprecated
IsDir: false,
Size: int64(11),
ShareID: "",
Sha1: "",
},
}
var err error
adminId := uint64(0)
ctx := context.TODO()
// add infos
usedSpace := int64(0)
usedSpaceAfterDeleting := int64(0)
itemPaths := []string{}
pathToTmpPath := map[string]string{}
for itemPath, info := range pathInfos {
tmpPath := strings.ReplaceAll(itemPath, "origin", "uploads")
pathToTmpPath[itemPath] = tmpPath
err = store.AddUploadInfos(ctx, adminId, tmpPath, itemPath, info)
if err != nil {
t.Fatal(err)
}
usedSpace += info.Size
if !strings.Contains(itemPath, "delete") {
usedSpaceAfterDeleting += info.Size
}
itemPaths = append(itemPaths, itemPath)
}
// get infos
for itemPath, info := range pathInfos {
gotPath, size, uploaded, err := store.GetUploadInfo(ctx, adminId, itemPath)
if err != nil {
t.Fatal(err)
}
if size != info.Size ||
uploaded != int64(0) ||
gotPath != itemPath {
t.Fatalf("info not equaled (%v)", info)
}
}
// list infos
uploadInfos, err := store.ListUploadInfos(ctx, adminId)
if err != nil {
t.Fatal(err)
} else if len(uploadInfos) != len(pathInfos) {
t.Fatalf("list result size not match (%v) (%d)", uploadInfos, len(pathInfos))
}
for _, uploadInfo := range uploadInfos {
expected, ok := pathInfos[uploadInfo.RealFilePath]
if !ok {
t.Fatalf("path not found (%s)", uploadInfo.RealFilePath)
}
if uploadInfo.Uploaded != int64(0) ||
expected.Size != uploadInfo.Size {
t.Fatalf("info not equaled (%d) (%d)", uploadInfo.Uploaded, uploadInfo.Size)
}
}
// check used space
adminInfo, err := store.GetUser(ctx, adminId)
if err != nil {
t.Fatal(err)
} else if adminInfo.UsedSpace != usedSpace {
t.Fatalf("used space not match (%d) (%d)", adminInfo.UsedSpace, usedSpace)
}
// set uploading
for itemPath, info := range pathInfos {
err := store.SetUploadInfo(ctx, adminId, itemPath, int64(info.Size/2))
if err != nil {
t.Fatal(err)
}
gotPath, size, uploaded, err := store.GetUploadInfo(ctx, adminId, itemPath)
if err != nil {
t.Fatal(err)
}
if gotPath != itemPath || size != info.Size || uploaded != info.Size/2 {
t.Fatal("uploaded info not match")
}
}
// check used space
adminInfo, err = store.GetUser(ctx, adminId)
if err != nil {
t.Fatal(err)
} else if adminInfo.UsedSpace != usedSpace {
t.Fatalf("used space not match (%d) (%d)", adminInfo.UsedSpace, usedSpace)
}
// del info
for itemPath := range pathInfos {
err = store.DelUploadingInfos(ctx, adminId, itemPath)
if err != nil {
t.Fatal(err)
}
}
// check used space
adminInfo, err = store.GetUser(ctx, adminId)
if err != nil {
t.Fatal(err)
} else if adminInfo.UsedSpace != int64(0) {
t.Fatalf("used space not match (%d) (%d)", adminInfo.UsedSpace, int64(0))
}
// list infos
uploadInfos, err = store.ListUploadInfos(ctx, adminId)
if err != nil {
t.Fatal(err)
} else if len(uploadInfos) != 0 {
t.Fatalf("list result size not match (%v) (%d)", uploadInfos, 0)
}
for itemPath := range pathInfos {
_, _, _, err := store.GetUploadInfo(ctx, adminId, itemPath)
if !errors.Is(err, sql.ErrNoRows) {
t.Fatal(err)
}
}
}
t.Run("testing file info store - sqlite", func(t *testing.T) { t.Run("testing file info store - sqlite", func(t *testing.T) {
rootPath, err := ioutil.TempDir("./", "qs_sqlite_test_") rootPath, err := ioutil.TempDir("./", "qs_sqlite_test_")
if err != nil { if err != nil {
@ -443,3 +43,403 @@ func TestFileStore(t *testing.T) {
testUploadingMethods(t, store) testUploadingMethods(t, store)
}) })
} }
func testSharingMethods(t *testing.T, store db.IDBQuickshare) {
dirPaths := []string{"admin/path1", "admin/path1/path2"}
var err error
location := "admin"
ctx := context.TODO()
adminId := uint64(0)
// add some of paths...
err = store.AddFileInfo(ctx, adminId, "admin/path1", &db.FileInfo{
// Shared: false, // deprecated
IsDir: false,
Size: int64(0),
ShareID: "",
Sha1: "",
})
if err != nil {
t.Fatal(err)
}
// add sharings
for _, dirPath := range dirPaths {
err = store.AddSharing(ctx, adminId, dirPath)
if err != nil {
t.Fatal(err)
}
}
// list sharings
dirToID, err := store.ListSharingsByLocation(ctx, location)
if err != nil {
t.Fatal(err)
} else if len(dirToID) != len(dirPaths) {
t.Fatalf("share size not match %d %d", len(dirToID), len(dirPaths))
}
for _, sharingDir := range dirPaths {
if _, ok := dirToID[sharingDir]; !ok {
t.Fatalf("sharing(%s) not found", sharingDir)
}
mustTrue, err := store.IsSharing(ctx, sharingDir)
if err != nil {
t.Fatal(err)
} else if !mustTrue {
t.Fatalf("get sharing(%t) should exist", mustTrue)
}
info, err := store.GetFileInfo(ctx, sharingDir)
if err != nil {
t.Fatal(err)
} else if len(info.ShareID) != 7 {
t.Fatalf("incorrect ShareID %s", info.ShareID)
}
gotSharingDir, err := store.GetSharingDir(ctx, info.ShareID)
if err != nil {
t.Fatal(err)
} else if sharingDir != gotSharingDir {
t.Fatalf("sharing dir not consist: (%s) (%s)", sharingDir, gotSharingDir)
}
}
// del sharings
for _, dirPath := range dirPaths {
err = store.DelSharing(ctx, adminId, dirPath)
if err != nil {
t.Fatal(err)
}
}
// list sharings
dirToIDAfterDel, err := store.ListSharingsByLocation(ctx, location)
if err != nil {
t.Fatal(err)
} else if len(dirToIDAfterDel) != 0 {
t.Fatalf("share size not match (%+v)", dirToIDAfterDel)
}
for _, dirPath := range dirPaths {
if _, ok := dirToIDAfterDel[dirPath]; ok {
t.Fatalf("sharing(%s) should not exist", dirPath)
}
shared, err := store.IsSharing(ctx, dirPath)
if err != nil {
t.Fatal(err)
} else if shared {
t.Fatalf("get sharing(%t) should not shared but exist", shared)
}
info, err := store.GetFileInfo(ctx, dirPath)
if err != nil {
t.Fatal(err)
} else if len(info.ShareID) != 0 {
t.Fatalf("ShareID should be empty %s", info.ShareID)
}
// shareIDs are removed, use original dirToID to get shareID
originalShareID, ok := dirToID[dirPath]
if !ok {
t.Fatalf("dir (%s) should exist in originalShareID", dirPath)
}
_, err = store.GetSharingDir(ctx, originalShareID)
if !errors.Is(err, db.ErrSharingNotFound) {
t.Fatal("should return ErrSharingNotFound")
}
}
}
func testUploadingMethods(t *testing.T, store db.IDBQuickshare) {
pathInfos := map[string]*db.FileInfo{
"admin/origin/item1": &db.FileInfo{
// Shared: false, // deprecated
IsDir: false,
Size: int64(7),
ShareID: "",
Sha1: "",
},
"admin/origin/item2": &db.FileInfo{
// Shared: false, // deprecated
IsDir: false,
Size: int64(3),
ShareID: "",
Sha1: "",
},
"admin/origin/to_delete/item3": &db.FileInfo{
// Shared: false, // deprecated
IsDir: false,
Size: int64(11),
ShareID: "",
Sha1: "",
},
}
var err error
adminId := uint64(0)
ctx := context.TODO()
// add infos
usedSpace := int64(0)
usedSpaceAfterDeleting := int64(0)
itemPaths := []string{}
pathToTmpPath := map[string]string{}
for itemPath, info := range pathInfos {
tmpPath := strings.ReplaceAll(itemPath, "origin", "uploads")
pathToTmpPath[itemPath] = tmpPath
err = store.AddUploadInfos(ctx, adminId, tmpPath, itemPath, info)
if err != nil {
t.Fatal(err)
}
usedSpace += info.Size
if !strings.Contains(itemPath, "delete") {
usedSpaceAfterDeleting += info.Size
}
itemPaths = append(itemPaths, itemPath)
}
// get infos
for itemPath, info := range pathInfos {
gotPath, size, uploaded, err := store.GetUploadInfo(ctx, adminId, itemPath)
if err != nil {
t.Fatal(err)
}
if size != info.Size ||
uploaded != int64(0) ||
gotPath != itemPath {
t.Fatalf("info not equaled (%v)", info)
}
}
// list infos
uploadInfos, err := store.ListUploadInfos(ctx, adminId)
if err != nil {
t.Fatal(err)
} else if len(uploadInfos) != len(pathInfos) {
t.Fatalf("list result size not match (%v) (%d)", uploadInfos, len(pathInfos))
}
for _, uploadInfo := range uploadInfos {
expected, ok := pathInfos[uploadInfo.RealFilePath]
if !ok {
t.Fatalf("path not found (%s)", uploadInfo.RealFilePath)
}
if uploadInfo.Uploaded != int64(0) ||
expected.Size != uploadInfo.Size {
t.Fatalf("info not equaled (%d) (%d)", uploadInfo.Uploaded, uploadInfo.Size)
}
}
// check used space
adminInfo, err := store.GetUser(ctx, adminId)
if err != nil {
t.Fatal(err)
} else if adminInfo.UsedSpace != usedSpace {
t.Fatalf("used space not match (%d) (%d)", adminInfo.UsedSpace, usedSpace)
}
// set uploading
for itemPath, info := range pathInfos {
err := store.SetUploadInfo(ctx, adminId, itemPath, int64(info.Size/2))
if err != nil {
t.Fatal(err)
}
gotPath, size, uploaded, err := store.GetUploadInfo(ctx, adminId, itemPath)
if err != nil {
t.Fatal(err)
}
if gotPath != itemPath || size != info.Size || uploaded != info.Size/2 {
t.Fatal("uploaded info not match")
}
}
// check used space
adminInfo, err = store.GetUser(ctx, adminId)
if err != nil {
t.Fatal(err)
} else if adminInfo.UsedSpace != usedSpace {
t.Fatalf("used space not match (%d) (%d)", adminInfo.UsedSpace, usedSpace)
}
// del info
for itemPath := range pathInfos {
err = store.DelUploadingInfos(ctx, adminId, itemPath)
if err != nil {
t.Fatal(err)
}
}
// check used space
adminInfo, err = store.GetUser(ctx, adminId)
if err != nil {
t.Fatal(err)
} else if adminInfo.UsedSpace != int64(0) {
t.Fatalf("used space not match (%d) (%d)", adminInfo.UsedSpace, int64(0))
}
// list infos
uploadInfos, err = store.ListUploadInfos(ctx, adminId)
if err != nil {
t.Fatal(err)
} else if len(uploadInfos) != 0 {
t.Fatalf("list result size not match (%v) (%d)", uploadInfos, 0)
}
for itemPath := range pathInfos {
_, _, _, err := store.GetUploadInfo(ctx, adminId, itemPath)
if !errors.Is(err, sql.ErrNoRows) {
t.Fatal(err)
}
}
}
func testFileInfoMethods(t *testing.T, store db.IDBQuickshare) {
pathInfos := map[string]*db.FileInfo{
"admin/origin/item1": &db.FileInfo{
// Shared: false, // deprecated
IsDir: false,
Size: int64(7),
ShareID: "",
Sha1: "item1_sha",
},
"admin/origin/item2": &db.FileInfo{
// Shared: false, // deprecated
IsDir: false,
Size: int64(3),
ShareID: "",
Sha1: "item2_sha",
},
"admin/origin/dir": &db.FileInfo{
// Shared: true, // deprecated
IsDir: true,
Size: int64(0),
ShareID: "mockedShareID",
Sha1: "",
},
}
var err error
adminId := uint64(0)
ctx := context.TODO()
// add infos
usedSpace := int64(0)
itemPaths := []string{}
for itemPath, info := range pathInfos {
err = store.AddFileInfo(ctx, adminId, itemPath, info)
if err != nil {
t.Fatal(err)
}
usedSpace += info.Size
itemPaths = append(itemPaths, itemPath)
}
// get infos
for itemPath, expected := range pathInfos {
info, err := store.GetFileInfo(ctx, itemPath)
if err != nil {
t.Fatal(err)
}
if info.ShareID != expected.ShareID ||
info.IsDir != expected.IsDir ||
info.Sha1 != expected.Sha1 ||
info.Size != expected.Size {
t.Fatalf("info not equaled (%v) (%v)", expected, info)
}
}
// list infos
pathToInfo, err := store.ListFileInfos(ctx, itemPaths)
if err != nil {
t.Fatal(err)
} else if len(pathToInfo) != len(pathInfos) {
t.Fatalf("list result size not match (%v) (%d)", pathToInfo, len(pathInfos))
}
for pathname, info := range pathInfos {
gotInfo, ok := pathToInfo[pathname]
if !ok {
t.Fatalf("path not found (%s)", pathname)
}
if info.ShareID != gotInfo.ShareID ||
info.IsDir != gotInfo.IsDir ||
info.Sha1 != gotInfo.Sha1 ||
info.Size != gotInfo.Size {
t.Fatalf("info not equaled (%v) (%v)", gotInfo, info)
}
}
// set sha1
testSha1 := "sha1"
for itemPath := range pathInfos {
err := store.SetSha1(ctx, itemPath, testSha1)
if err != nil {
t.Fatal(err)
}
info, err := store.GetFileInfo(ctx, itemPath)
if err != nil {
t.Fatal(err)
}
if info.Sha1 != testSha1 {
t.Fatalf("sha not equaled (%v) (%v)", info.Sha1, testSha1)
}
}
// move paths
newPaths := []string{}
for itemPath, info := range pathInfos {
newItemPath := strings.ReplaceAll(itemPath, "origin", "new")
err = store.MoveFileInfo(ctx, adminId, itemPath, newItemPath, info.IsDir)
if err != nil {
t.Fatal(err)
}
newPaths = append(newPaths, newItemPath)
}
// list infos
pathToInfo, err = store.ListFileInfos(ctx, newPaths)
if err != nil {
t.Fatal(err)
} else if len(pathToInfo) != len(pathInfos) {
t.Fatalf("list result size not match (%v) (%d)", pathToInfo, len(pathInfos))
}
// check used space
adminInfo, err := store.GetUser(ctx, adminId)
if err != nil {
t.Fatal(err)
} else if adminInfo.UsedSpace != usedSpace {
t.Fatalf("used space not match (%d) (%d)", adminInfo.UsedSpace, usedSpace)
}
// del info
for _, itemPath := range newPaths {
err = store.DelFileInfo(ctx, adminId, itemPath)
if err != nil {
t.Fatal(err)
}
}
// check used space
adminInfo, err = store.GetUser(ctx, adminId)
if err != nil {
t.Fatal(err)
} else if adminInfo.UsedSpace != int64(0) {
t.Fatalf("used space not match (%d) (%d)", adminInfo.UsedSpace, int64(0))
}
// list infos
pathToInfo, err = store.ListFileInfos(ctx, itemPaths)
if err != nil {
t.Fatal(err)
} else if len(pathToInfo) != 0 {
t.Fatalf("list result should be empty (%v)", pathToInfo)
}
for itemPath := range pathInfos {
_, err := store.GetFileInfo(ctx, itemPath)
if !errors.Is(err, db.ErrFileInfoNotFound) {
t.Fatal(err)
}
}
}