diff --git a/src/db/rdb/sqlite/configs.go b/src/db/rdb/default/configs.go similarity index 59% rename from src/db/rdb/sqlite/configs.go rename to src/db/rdb/default/configs.go index 1d69f64..dbf4c43 100644 --- a/src/db/rdb/sqlite/configs.go +++ b/src/db/rdb/default/configs.go @@ -2,14 +2,15 @@ package sqlite import ( "context" + "database/sql" "encoding/json" "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 - err := st.db.QueryRowContext( + err := tx.QueryRowContext( ctx, `select config from t_config @@ -31,7 +32,7 @@ func (st *SQLiteStore) getCfg(ctx context.Context) (*db.SiteConfig, error) { 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 { return err } @@ -41,7 +42,7 @@ func (st *SQLiteStore) setCfg(ctx context.Context, cfg *db.SiteConfig) error { return err } - _, err = st.db.ExecContext( + _, err = tx.ExecContext( ctx, `update t_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 { - st.Lock() - defer st.Unlock() + tx, err := st.db.BeginTx(ctx, &sql.TxOptions{}) + if err != nil { + return err + } + defer tx.Rollback() - siteCfg, err := st.getCfg(ctx) + siteCfg, err := st.getCfg(ctx, tx) if err != nil { return err } 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) { - st.RLock() - defer st.RUnlock() + tx, err := st.db.BeginTx(ctx, &sql.TxOptions{}) + if err != nil { + return nil, err + } + defer tx.Rollback() - return st.getCfg(ctx) + return st.getCfg(ctx, tx) } diff --git a/src/db/rdb/sqlite/files.go b/src/db/rdb/default/files.go similarity index 71% rename from src/db/rdb/sqlite/files.go rename to src/db/rdb/default/files.go index 7b0ae2c..2dc0fbb 100644 --- a/src/db/rdb/sqlite/files.go +++ b/src/db/rdb/default/files.go @@ -12,13 +12,13 @@ import ( "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 fInfo := &db.FileInfo{} var isDir bool var size int64 var shareId string - err := st.db.QueryRowContext( + err := tx.QueryRowContext( ctx, `select is_dir, size, share_id, 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) { - st.RLock() - defer st.RUnlock() + tx, err := st.db.BeginTx(ctx, &sql.TxOptions{}) + 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) { - st.RLock() - defer st.RUnlock() + tx, err := st.db.BeginTx(ctx, &sql.TxOptions{}) + if err != nil { + return nil, err + } + defer tx.Rollback() // TODO: add pagination placeholders := []string{} @@ -66,7 +72,7 @@ func (st *SQLiteStore) ListFileInfos(ctx context.Context, itemPaths []string) (m placeholders = append(placeholders, "?") values = append(values, itemPaths[i]) } - rows, err := st.db.QueryContext( + rows, err := tx.QueryContext( ctx, fmt.Sprintf( `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{} for rows.Next() { fInfo := &db.FileInfo{} - err = rows.Scan(&itemPath, &isDir, &size, &shareId, &fInfoStr) if err != nil { return nil, err @@ -111,7 +116,7 @@ func (st *SQLiteStore) ListFileInfos(ctx context.Context, itemPaths []string) (m 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) if err != nil { return err @@ -123,7 +128,7 @@ func (st *SQLiteStore) addFileInfo(ctx context.Context, userId uint64, itemPath } dirPath, itemName := path.Split(itemPath) - _, err = st.db.ExecContext( + _, err = tx.ExecContext( ctx, `insert into t_file_info ( 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 { - st.Lock() - defer st.Unlock() + tx, err := st.db.BeginTx(ctx, &sql.TxOptions{}) + 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 { return err } - // increase used space - return st.setUsed(ctx, userId, true, info.Size) + return tx.Commit() } -func (st *SQLiteStore) delFileInfo(ctx context.Context, itemPath string) error { - _, err := st.db.ExecContext( +func (st *SQLiteStore) delFileInfo(ctx context.Context, tx *sql.Tx, itemPath string) error { + _, err := tx.ExecContext( ctx, `delete from t_file_info 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 { - st.Lock() - defer st.Unlock() + tx, err := st.db.BeginTx(ctx, &sql.TxOptions{}) + if err != nil { + return err + } + defer tx.Rollback() - info, err := st.getFileInfo(ctx, itemPath) + info, err := st.getFileInfo(ctx, tx, itemPath) if err != nil { return err } @@ -178,7 +193,7 @@ func (st *SQLiteStore) SetSha1(ctx context.Context, itemPath, sign string) error return err } - _, err = st.db.ExecContext( + _, err = tx.ExecContext( ctx, `update t_file_info set info=? @@ -186,15 +201,21 @@ func (st *SQLiteStore) SetSha1(ctx context.Context, itemPath, sign string) error infoStr, itemPath, ) - return err + if err != nil { + return err + } + return tx.Commit() } func (st *SQLiteStore) DelFileInfo(ctx context.Context, userID uint64, itemPath string) error { - st.Lock() - defer st.Unlock() + tx, err := st.db.BeginTx(ctx, &sql.TxOptions{}) + if err != nil { + return err + } + defer tx.Rollback() // get all children and size - rows, err := st.db.QueryContext( + rows, err := tx.QueryContext( ctx, `select path, size from t_file_info @@ -224,13 +245,13 @@ func (st *SQLiteStore) DelFileInfo(ctx context.Context, userID uint64, itemPath } // decrease used space - err = st.setUsed(ctx, userID, false, decrSize) + err = st.setUsed(ctx, tx, userID, false, decrSize) if err != nil { return err } // delete file info entries - _, err = st.db.ExecContext( + _, err = tx.ExecContext( ctx, fmt.Sprintf( `delete from t_file_info @@ -239,14 +260,20 @@ func (st *SQLiteStore) DelFileInfo(ctx context.Context, userID uint64, itemPath ), 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 { - st.Lock() - defer st.Unlock() + tx, err := st.db.BeginTx(ctx, &sql.TxOptions{}) + 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 errors.Is(err, db.ErrFileInfoNotFound) { // 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 } - err = st.delFileInfo(ctx, oldPath) + + err = st.delFileInfo(ctx, tx, oldPath) if err != nil { 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) { diff --git a/src/db/rdb/sqlite/files_sharings.go b/src/db/rdb/default/files_sharings.go similarity index 74% rename from src/db/rdb/sqlite/files_sharings.go rename to src/db/rdb/default/files_sharings.go index e40c246..0528eb3 100644 --- a/src/db/rdb/sqlite/files_sharings.go +++ b/src/db/rdb/default/files_sharings.go @@ -30,11 +30,14 @@ func (st *SQLiteStore) generateShareID(payload string) (string, error) { } func (st *SQLiteStore) IsSharing(ctx context.Context, dirPath string) (bool, error) { - st.RLock() - defer st.RUnlock() + tx, err := st.db.BeginTx(ctx, &sql.TxOptions{}) + if err != nil { + return false, err + } + defer tx.Rollback() var shareId string - err := st.db.QueryRowContext( + err = tx.QueryRowContext( ctx, `select share_id 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) { - st.RLock() - defer st.RUnlock() + tx, err := st.db.BeginTx(ctx, &sql.TxOptions{}) + if err != nil { + return "", err + } + defer tx.Rollback() var sharedPath string - err := st.db.QueryRowContext( + err = tx.QueryRowContext( ctx, `select path 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 { - st.Lock() - defer st.Unlock() + tx, err := st.db.BeginTx(ctx, &sql.TxOptions{}) + if err != nil { + return err + } + defer tx.Rollback() shareID, err := st.generateShareID(dirPath) if err != nil { @@ -92,7 +101,7 @@ func (st *SQLiteStore) AddSharing(ctx context.Context, userId uint64, dirPath st return err } - _, err = st.getFileInfo(ctx, dirPath) + _, err = st.getFileInfo(ctx, tx, dirPath) if err != nil && !errors.Is(err, db.ErrFileInfoNotFound) { return err } @@ -106,7 +115,7 @@ func (st *SQLiteStore) AddSharing(ctx context.Context, userId uint64, dirPath st return err } - _, err = st.db.ExecContext( + _, err = tx.ExecContext( ctx, `insert into t_file_info ( 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, 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( - ctx, - `update t_file_info - set share_id=? - where path=?`, - shareID, dirPath, - ) - return err + return tx.Commit() } func (st *SQLiteStore) DelSharing(ctx context.Context, userId uint64, dirPath string) error { - st.Lock() - defer st.Unlock() + tx, err := st.db.BeginTx(ctx, &sql.TxOptions{}) + if err != nil { + return err + } + defer tx.Rollback() - _, err := st.db.ExecContext( + _, err = tx.ExecContext( ctx, `update t_file_info set share_id='' where path=?`, dirPath, ) - return err + if err != nil { + return err + } + return tx.Commit() } func (st *SQLiteStore) ListSharingsByLocation(ctx context.Context, location string) (map[string]string, error) { - st.RLock() - defer st.RUnlock() + tx, err := st.db.BeginTx(ctx, &sql.TxOptions{}) + if err != nil { + return nil, err + } + defer tx.Rollback() - rows, err := st.db.QueryContext( + rows, err := tx.QueryContext( ctx, `select path, share_id from t_file_info diff --git a/src/db/rdb/sqlite/files_uploadings.go b/src/db/rdb/default/files_uploadings.go similarity index 56% rename from src/db/rdb/sqlite/files_uploadings.go rename to src/db/rdb/default/files_uploadings.go index 86d38fb..17fbcc7 100644 --- a/src/db/rdb/sqlite/files_uploadings.go +++ b/src/db/rdb/default/files_uploadings.go @@ -8,8 +8,8 @@ import ( "github.com/ihexxa/quickshare/src/db" ) -func (st *SQLiteStore) addUploadInfoOnly(ctx context.Context, userId uint64, tmpPath, filePath string, fileSize int64) error { - _, err := st.db.ExecContext( +func (st *SQLiteStore) addUploadInfoOnly(ctx context.Context, tx *sql.Tx, userId uint64, tmpPath, filePath string, fileSize int64) error { + _, err := tx.ExecContext( ctx, `insert into t_file_uploading ( 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 { - st.Lock() - defer st.Unlock() + tx, err := st.db.BeginTx(ctx, &sql.TxOptions{}) + if err != nil { + return err + } + defer tx.Rollback() - userInfo, err := st.getUser(ctx, userId) + userInfo, err := st.getUser(ctx, tx, userId) if err != nil { return err } else if userInfo.UsedSpace+info.Size > int64(userInfo.Quota.SpaceLimit) { return db.ErrQuota } - _, _, _, err = st.getUploadInfo(ctx, userId, filePath) + _, _, _, err = st.getUploadInfo(ctx, tx, userId, filePath) if err == nil { return db.ErrKeyExisting } 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 - err = st.setUser(ctx, userInfo) + err = st.setUser(ctx, tx, userInfo) if err != nil { 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 { - st.Lock() - defer st.Unlock() + tx, err := st.db.BeginTx(ctx, &sql.TxOptions{}) + 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 { - _, size, _, err := st.getUploadInfo(ctx, userId, realPath) +func (st *SQLiteStore) delUploadingInfos(ctx context.Context, tx *sql.Tx, userId uint64, realPath string) error { + _, size, _, err := st.getUploadInfo(ctx, tx, userId, realPath) if err != nil { // info may not exist return err } - err = st.delUploadInfoOnly(ctx, userId, realPath) + err = st.delUploadInfoOnly(ctx, tx, userId, realPath) if err != nil { return err } - userInfo, err := st.getUser(ctx, userId) + userInfo, err := st.getUser(ctx, tx, userId) if err != nil { return err } 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 { - _, err := st.db.ExecContext( +func (st *SQLiteStore) delUploadInfoOnly(ctx context.Context, tx *sql.Tx, userId uint64, filePath string) error { + _, err := tx.ExecContext( ctx, `delete from t_file_uploading 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 { - st.Lock() - defer st.Unlock() + tx, err := st.db.BeginTx(ctx, &sql.TxOptions{}) + 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 { return err } - err = st.delUploadInfoOnly(ctx, userId, itemPath) + err = st.delUploadInfoOnly(ctx, tx, userId, itemPath) if err != nil { return err } - return st.addFileInfo(ctx, userId, itemPath, &db.FileInfo{ + err = st.addFileInfo(ctx, tx, userId, itemPath, &db.FileInfo{ Size: size, }) + if err != nil { + return err + } + + return tx.Commit() } func (st *SQLiteStore) SetUploadInfo(ctx context.Context, userId uint64, filePath string, newUploaded int64) error { - st.Lock() - defer st.Unlock() + tx, err := st.db.BeginTx(ctx, &sql.TxOptions{}) + if err != nil { + return err + } + defer tx.Rollback() var size, uploaded int64 - err := st.db.QueryRowContext( + err = tx.QueryRowContext( ctx, `select size, uploaded from t_file_uploading @@ -121,19 +148,24 @@ func (st *SQLiteStore) SetUploadInfo(ctx context.Context, userId uint64, filePat return db.ErrGreaterThanSize } - _, err = st.db.ExecContext( + _, err = tx.ExecContext( ctx, `update t_file_uploading set uploaded=? where real_path=? and user=?`, 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 - err := st.db.QueryRowContext( + err := tx.QueryRowContext( ctx, `select size, uploaded 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) { - st.RLock() - defer st.RUnlock() - return st.getUploadInfo(ctx, userId, filePath) + tx, err := st.db.BeginTx(ctx, &sql.TxOptions{}) + if err != nil { + 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) { - st.RLock() - defer st.RUnlock() + tx, err := st.db.BeginTx(ctx, &sql.TxOptions{}) + if err != nil { + return nil, err + } + defer tx.Rollback() - rows, err := st.db.QueryContext( + rows, err := tx.QueryContext( ctx, `select real_path, size, uploaded from t_file_uploading diff --git a/src/db/rdb/sqlite/sqlite.go b/src/db/rdb/default/sqlite.go similarity index 100% rename from src/db/rdb/sqlite/sqlite.go rename to src/db/rdb/default/sqlite.go diff --git a/src/db/rdb/sqlite/users.go b/src/db/rdb/default/users.go similarity index 70% rename from src/db/rdb/sqlite/users.go rename to src/db/rdb/default/users.go index 6a68dd1..daf0bf1 100644 --- a/src/db/rdb/sqlite/users.go +++ b/src/db/rdb/default/users.go @@ -16,7 +16,7 @@ type SQLiteStore struct { 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 if err = db.CheckUser(user, false); err != nil { return err @@ -30,7 +30,7 @@ func (st *SQLiteStore) setUser(ctx context.Context, user *db.User) error { if err != nil { return err } - _, err = st.db.ExecContext( + _, err = tx.ExecContext( ctx, `update t_user 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 } -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{} var quotaStr, preferenceStr string - err := st.db.QueryRowContext( + err := tx.QueryRowContext( ctx, `select id, name, pwd, role, used_space, quota, preference 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 { - st.Lock() - defer st.Unlock() + tx, err := st.db.BeginTx(ctx, &sql.TxOptions{}) + if err != nil { + return err + } + defer tx.Rollback() quotaStr, err := json.Marshal(user.Quota) if err != nil { @@ -94,7 +97,7 @@ func (st *SQLiteStore) AddUser(ctx context.Context, user *db.User) error { if err != nil { return err } - _, err = st.db.ExecContext( + _, err = tx.ExecContext( ctx, `insert into t_user (id, name, pwd, role, used_space, quota, preference) values (?, ?, ?, ?, ?, ?, ?)`, user.ID, @@ -105,26 +108,40 @@ func (st *SQLiteStore) AddUser(ctx context.Context, user *db.User) error { quotaStr, preferenceStr, ) - return err + if err != nil { + return err + } + + return tx.Commit() } func (st *SQLiteStore) DelUser(ctx context.Context, id uint64) error { - st.Lock() - defer st.Unlock() + tx, err := st.db.BeginTx(ctx, &sql.TxOptions{}) + if err != nil { + return err + } + defer tx.Rollback() - _, err := st.db.ExecContext( + _, err = tx.ExecContext( ctx, `delete from t_user where id=?`, id, ) - return err + if err != nil { + return err + } + + return tx.Commit() } func (st *SQLiteStore) GetUser(ctx context.Context, id uint64) (*db.User, error) { - st.RLock() - defer st.RUnlock() + tx, err := st.db.BeginTx(ctx, &sql.TxOptions{}) + 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 { 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) { - st.RLock() - defer st.RUnlock() + tx, err := st.db.BeginTx(ctx, &sql.TxOptions{}) + if err != nil { + return nil, err + } + defer tx.Rollback() user := &db.User{} var quotaStr, preferenceStr string - err := st.db.QueryRowContext( + err = tx.QueryRowContext( ctx, `select id, name, pwd, role, used_space, quota, preference 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 { - st.Lock() - defer st.Unlock() + tx, err := st.db.BeginTx(ctx, &sql.TxOptions{}) + if err != nil { + return err + } + defer tx.Rollback() - _, err := st.db.ExecContext( + _, err = tx.ExecContext( ctx, `update t_user set pwd=? @@ -183,20 +206,27 @@ func (st *SQLiteStore) SetPwd(ctx context.Context, id uint64, pwd string) error pwd, id, ) - return err + if err != nil { + return err + } + + return tx.Commit() } // role + quota func (st *SQLiteStore) SetInfo(ctx context.Context, id uint64, user *db.User) error { - st.Lock() - defer st.Unlock() + tx, err := st.db.BeginTx(ctx, &sql.TxOptions{}) + if err != nil { + return err + } + defer tx.Rollback() quotaStr, err := json.Marshal(user.Quota) if err != nil { return err } - _, err = st.db.ExecContext( + _, err = tx.ExecContext( ctx, `update t_user set role=?, quota=? @@ -204,19 +234,26 @@ func (st *SQLiteStore) SetInfo(ctx context.Context, id uint64, user *db.User) er user.Role, quotaStr, id, ) - return err + if err != nil { + return err + } + + return tx.Commit() } func (st *SQLiteStore) SetPreferences(ctx context.Context, id uint64, prefers *db.Preferences) error { - st.Lock() - defer st.Unlock() + tx, err := st.db.BeginTx(ctx, &sql.TxOptions{}) + if err != nil { + return err + } + defer tx.Rollback() preferenceStr, err := json.Marshal(prefers) if err != nil { return err } - _, err = st.db.ExecContext( + _, err = tx.ExecContext( ctx, `update t_user set preference=? @@ -224,17 +261,29 @@ func (st *SQLiteStore) SetPreferences(ctx context.Context, id uint64, prefers *d preferenceStr, 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 { - st.Lock() - defer st.Unlock() - return st.setUsed(ctx, id, incr, capacity) + tx, err := st.db.BeginTx(ctx, &sql.TxOptions{}) + if err != nil { + 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 { - gotUser, err := st.getUser(ctx, id) +func (st *SQLiteStore) setUsed(ctx context.Context, tx *sql.Tx, id uint64, incr bool, capacity int64) error { + gotUser, err := st.getUser(ctx, tx, id) if err != nil { return err } @@ -252,7 +301,7 @@ func (st *SQLiteStore) setUsed(ctx context.Context, id uint64, incr bool, capaci gotUser.UsedSpace = gotUser.UsedSpace - capacity } - _, err = st.db.ExecContext( + _, err = tx.ExecContext( ctx, `update t_user set used_space=? @@ -260,18 +309,17 @@ func (st *SQLiteStore) setUsed(ctx context.Context, id uint64, incr bool, capaci gotUser.UsedSpace, gotUser.ID, ) - if err != nil { - return err - } - - return nil + return err } func (st *SQLiteStore) ResetUsed(ctx context.Context, id uint64, used int64) error { - st.Lock() - defer st.Unlock() + tx, err := st.db.BeginTx(ctx, &sql.TxOptions{}) + if err != nil { + return err + } + defer tx.Rollback() - _, err := st.db.ExecContext( + _, err = tx.ExecContext( ctx, `update t_user set used_space=? @@ -279,15 +327,16 @@ func (st *SQLiteStore) ResetUsed(ctx context.Context, id uint64, used int64) err used, id, ) - return err + if err != nil { + return err + } + + return tx.Commit() } -func (st *SQLiteStore) ListUsers(ctx context.Context) ([]*db.User, error) { - st.RLock() - defer st.RUnlock() - +func (st *SQLiteStore) listUsers(ctx context.Context, tx *sql.Tx) ([]*db.User, error) { // TODO: support pagination - rows, err := st.db.QueryContext( + rows, err := tx.QueryContext( ctx, `select id, name, role, used_space, quota, preference from t_user`, @@ -329,11 +378,24 @@ func (st *SQLiteStore) ListUsers(ctx context.Context) ([]*db.User, error) { return users, nil } -func (st *SQLiteStore) ListUserIDs(ctx context.Context) (map[string]string, error) { - st.RLock() - defer st.RUnlock() +func (st *SQLiteStore) ListUsers(ctx context.Context) ([]*db.User, error) { + tx, err := st.db.BeginTx(ctx, &sql.TxOptions{}) + 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 { return nil, err } diff --git a/src/db/tests/files_test.go b/src/db/tests/files_test.go index 0155935..864e67b 100644 --- a/src/db/tests/files_test.go +++ b/src/db/tests/files_test.go @@ -15,406 +15,6 @@ import ( ) 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) { rootPath, err := ioutil.TempDir("./", "qs_sqlite_test_") if err != nil { @@ -443,3 +43,403 @@ func TestFileStore(t *testing.T) { 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) + } + } +}