fix(db): add sqlite store back with some fixes
This commit is contained in:
parent
5cae5be837
commit
81e97bdd55
16 changed files with 1696 additions and 286 deletions
|
@ -1,4 +1,4 @@
|
||||||
package sqlite
|
package default
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -8,7 +8,7 @@ import (
|
||||||
"github.com/ihexxa/quickshare/src/db"
|
"github.com/ihexxa/quickshare/src/db"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (st *SQLiteStore) getCfg(ctx context.Context, tx *sql.Tx) (*db.SiteConfig, error) {
|
func (st *DefaultStore) getCfg(ctx context.Context, tx *sql.Tx) (*db.SiteConfig, error) {
|
||||||
var configStr string
|
var configStr string
|
||||||
err := tx.QueryRowContext(
|
err := tx.QueryRowContext(
|
||||||
ctx,
|
ctx,
|
||||||
|
@ -32,7 +32,7 @@ func (st *SQLiteStore) getCfg(ctx context.Context, tx *sql.Tx) (*db.SiteConfig,
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) setCfg(ctx context.Context, tx *sql.Tx, cfg *db.SiteConfig) error {
|
func (st *DefaultStore) 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
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ func (st *SQLiteStore) setCfg(ctx context.Context, tx *sql.Tx, cfg *db.SiteConfi
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) SetClientCfg(ctx context.Context, cfg *db.ClientConfig) error {
|
func (st *DefaultStore) SetClientCfg(ctx context.Context, cfg *db.ClientConfig) error {
|
||||||
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -73,7 +73,7 @@ func (st *SQLiteStore) SetClientCfg(ctx context.Context, cfg *db.ClientConfig) e
|
||||||
return tx.Commit()
|
return tx.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) GetCfg(ctx context.Context) (*db.SiteConfig, error) {
|
func (st *DefaultStore) GetCfg(ctx context.Context) (*db.SiteConfig, error) {
|
||||||
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package sqlite
|
package default
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -12,7 +12,7 @@ import (
|
||||||
"github.com/ihexxa/quickshare/src/db"
|
"github.com/ihexxa/quickshare/src/db"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (st *SQLiteStore) getFileInfo(ctx context.Context, tx *sql.Tx, itemPath string) (*db.FileInfo, error) {
|
func (st *DefaultStore) 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
|
||||||
|
@ -48,7 +48,7 @@ func (st *SQLiteStore) getFileInfo(ctx context.Context, tx *sql.Tx, itemPath str
|
||||||
return fInfo, nil
|
return fInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) GetFileInfo(ctx context.Context, itemPath string) (*db.FileInfo, error) {
|
func (st *DefaultStore) GetFileInfo(ctx context.Context, itemPath string) (*db.FileInfo, error) {
|
||||||
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -58,7 +58,7 @@ func (st *SQLiteStore) GetFileInfo(ctx context.Context, itemPath string) (*db.Fi
|
||||||
return st.getFileInfo(ctx, tx, itemPath)
|
return st.getFileInfo(ctx, tx, itemPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) ListFileInfos(ctx context.Context, itemPaths []string) (map[string]*db.FileInfo, error) {
|
func (st *DefaultStore) ListFileInfos(ctx context.Context, itemPaths []string) (map[string]*db.FileInfo, error) {
|
||||||
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -116,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, tx *sql.Tx, userId uint64, itemPath string, info *db.FileInfo) error {
|
func (st *DefaultStore) 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
|
||||||
|
@ -144,7 +144,7 @@ func (st *SQLiteStore) addFileInfo(ctx context.Context, tx *sql.Tx, userId uint6
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) AddFileInfo(ctx context.Context, userId uint64, itemPath string, info *db.FileInfo) error {
|
func (st *DefaultStore) AddFileInfo(ctx context.Context, userId uint64, itemPath string, info *db.FileInfo) error {
|
||||||
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -164,7 +164,7 @@ func (st *SQLiteStore) AddFileInfo(ctx context.Context, userId uint64, itemPath
|
||||||
return tx.Commit()
|
return tx.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) delFileInfo(ctx context.Context, tx *sql.Tx, itemPath string) error {
|
func (st *DefaultStore) delFileInfo(ctx context.Context, tx *sql.Tx, itemPath string) error {
|
||||||
_, err := tx.ExecContext(
|
_, err := tx.ExecContext(
|
||||||
ctx,
|
ctx,
|
||||||
`delete from t_file_info
|
`delete from t_file_info
|
||||||
|
@ -175,7 +175,7 @@ func (st *SQLiteStore) delFileInfo(ctx context.Context, tx *sql.Tx, itemPath str
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) SetSha1(ctx context.Context, itemPath, sign string) error {
|
func (st *DefaultStore) SetSha1(ctx context.Context, itemPath, sign string) error {
|
||||||
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -207,7 +207,7 @@ func (st *SQLiteStore) SetSha1(ctx context.Context, itemPath, sign string) error
|
||||||
return tx.Commit()
|
return tx.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) DelFileInfo(ctx context.Context, userID uint64, itemPath string) error {
|
func (st *DefaultStore) DelFileInfo(ctx context.Context, userID uint64, itemPath string) error {
|
||||||
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -266,7 +266,7 @@ func (st *SQLiteStore) DelFileInfo(ctx context.Context, userID uint64, itemPath
|
||||||
return tx.Commit()
|
return tx.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) MoveFileInfo(ctx context.Context, userId uint64, oldPath, newPath string, isDir bool) error {
|
func (st *DefaultStore) MoveFileInfo(ctx context.Context, userId uint64, oldPath, newPath string, isDir bool) error {
|
||||||
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package sqlite
|
package default
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -14,7 +14,7 @@ import (
|
||||||
"github.com/ihexxa/quickshare/src/db"
|
"github.com/ihexxa/quickshare/src/db"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (st *SQLiteStore) generateShareID(payload string) (string, error) {
|
func (st *DefaultStore) generateShareID(payload string) (string, error) {
|
||||||
if len(payload) == 0 {
|
if len(payload) == 0 {
|
||||||
return "", db.ErrEmpty
|
return "", db.ErrEmpty
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ func (st *SQLiteStore) generateShareID(payload string) (string, error) {
|
||||||
return fmt.Sprintf("%x", h.Sum(nil))[:7], nil
|
return fmt.Sprintf("%x", h.Sum(nil))[:7], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) IsSharing(ctx context.Context, dirPath string) (bool, error) {
|
func (st *DefaultStore) IsSharing(ctx context.Context, dirPath string) (bool, error) {
|
||||||
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
|
@ -56,7 +56,7 @@ func (st *SQLiteStore) IsSharing(ctx context.Context, dirPath string) (bool, err
|
||||||
return shareId != "", nil
|
return shareId != "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) GetSharingDir(ctx context.Context, hashID string) (string, error) {
|
func (st *DefaultStore) GetSharingDir(ctx context.Context, hashID string) (string, error) {
|
||||||
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -84,7 +84,7 @@ func (st *SQLiteStore) GetSharingDir(ctx context.Context, hashID string) (string
|
||||||
return sharedPath, nil
|
return sharedPath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) AddSharing(ctx context.Context, userId uint64, dirPath string) error {
|
func (st *DefaultStore) AddSharing(ctx context.Context, userId uint64, dirPath string) error {
|
||||||
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -147,7 +147,7 @@ func (st *SQLiteStore) AddSharing(ctx context.Context, userId uint64, dirPath st
|
||||||
return tx.Commit()
|
return tx.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) DelSharing(ctx context.Context, userId uint64, dirPath string) error {
|
func (st *DefaultStore) DelSharing(ctx context.Context, userId uint64, dirPath string) error {
|
||||||
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -167,7 +167,7 @@ func (st *SQLiteStore) DelSharing(ctx context.Context, userId uint64, dirPath st
|
||||||
return tx.Commit()
|
return tx.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) ListSharingsByLocation(ctx context.Context, location string) (map[string]string, error) {
|
func (st *DefaultStore) ListSharingsByLocation(ctx context.Context, location string) (map[string]string, error) {
|
||||||
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package sqlite
|
package default
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -8,7 +8,7 @@ import (
|
||||||
"github.com/ihexxa/quickshare/src/db"
|
"github.com/ihexxa/quickshare/src/db"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (st *SQLiteStore) addUploadInfoOnly(ctx context.Context, tx *sql.Tx, userId uint64, tmpPath, filePath string, fileSize int64) error {
|
func (st *DefaultStore) addUploadInfoOnly(ctx context.Context, tx *sql.Tx, userId uint64, tmpPath, filePath string, fileSize int64) error {
|
||||||
_, err := tx.ExecContext(
|
_, err := tx.ExecContext(
|
||||||
ctx,
|
ctx,
|
||||||
`insert into t_file_uploading (
|
`insert into t_file_uploading (
|
||||||
|
@ -22,7 +22,7 @@ func (st *SQLiteStore) addUploadInfoOnly(ctx context.Context, tx *sql.Tx, userId
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) AddUploadInfos(ctx context.Context, userId uint64, tmpPath, filePath string, info *db.FileInfo) error {
|
func (st *DefaultStore) AddUploadInfos(ctx context.Context, userId uint64, tmpPath, filePath string, info *db.FileInfo) error {
|
||||||
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -57,7 +57,7 @@ func (st *SQLiteStore) AddUploadInfos(ctx context.Context, userId uint64, tmpPat
|
||||||
return tx.Commit()
|
return tx.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) DelUploadingInfos(ctx context.Context, userId uint64, realPath string) error {
|
func (st *DefaultStore) DelUploadingInfos(ctx context.Context, userId uint64, realPath string) error {
|
||||||
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -72,7 +72,7 @@ func (st *SQLiteStore) DelUploadingInfos(ctx context.Context, userId uint64, rea
|
||||||
return tx.Commit()
|
return tx.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) delUploadingInfos(ctx context.Context, tx *sql.Tx, userId uint64, realPath string) error {
|
func (st *DefaultStore) delUploadingInfos(ctx context.Context, tx *sql.Tx, userId uint64, realPath string) error {
|
||||||
_, size, _, err := st.getUploadInfo(ctx, tx, userId, realPath)
|
_, size, _, err := st.getUploadInfo(ctx, tx, userId, realPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// info may not exist
|
// info may not exist
|
||||||
|
@ -92,7 +92,7 @@ func (st *SQLiteStore) delUploadingInfos(ctx context.Context, tx *sql.Tx, userId
|
||||||
return st.setUser(ctx, tx, userInfo)
|
return st.setUser(ctx, tx, userInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) delUploadInfoOnly(ctx context.Context, tx *sql.Tx, userId uint64, filePath string) error {
|
func (st *DefaultStore) delUploadInfoOnly(ctx context.Context, tx *sql.Tx, userId uint64, filePath string) error {
|
||||||
_, err := tx.ExecContext(
|
_, err := tx.ExecContext(
|
||||||
ctx,
|
ctx,
|
||||||
`delete from t_file_uploading
|
`delete from t_file_uploading
|
||||||
|
@ -102,7 +102,7 @@ func (st *SQLiteStore) delUploadInfoOnly(ctx context.Context, tx *sql.Tx, userId
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) MoveUploadingInfos(ctx context.Context, userId uint64, uploadPath, itemPath string) error {
|
func (st *DefaultStore) MoveUploadingInfos(ctx context.Context, userId uint64, uploadPath, itemPath string) error {
|
||||||
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -127,7 +127,7 @@ func (st *SQLiteStore) MoveUploadingInfos(ctx context.Context, userId uint64, up
|
||||||
return tx.Commit()
|
return tx.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) SetUploadInfo(ctx context.Context, userId uint64, filePath string, newUploaded int64) error {
|
func (st *DefaultStore) SetUploadInfo(ctx context.Context, userId uint64, filePath string, newUploaded int64) error {
|
||||||
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -161,7 +161,7 @@ func (st *SQLiteStore) SetUploadInfo(ctx context.Context, userId uint64, filePat
|
||||||
return tx.Commit()
|
return tx.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) getUploadInfo(
|
func (st *DefaultStore) getUploadInfo(
|
||||||
ctx context.Context, tx *sql.Tx, userId uint64, filePath string,
|
ctx context.Context, tx *sql.Tx, userId uint64, filePath string,
|
||||||
) (string, int64, int64, error) {
|
) (string, int64, int64, error) {
|
||||||
var size, uploaded int64
|
var size, uploaded int64
|
||||||
|
@ -179,7 +179,7 @@ func (st *SQLiteStore) getUploadInfo(
|
||||||
return filePath, size, uploaded, nil
|
return filePath, size, uploaded, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) GetUploadInfo(ctx context.Context, userId uint64, filePath string) (string, int64, int64, error) {
|
func (st *DefaultStore) GetUploadInfo(ctx context.Context, userId uint64, filePath string) (string, int64, int64, error) {
|
||||||
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", 0, 0, err
|
return "", 0, 0, err
|
||||||
|
@ -189,7 +189,7 @@ func (st *SQLiteStore) GetUploadInfo(ctx context.Context, userId uint64, filePat
|
||||||
return st.getUploadInfo(ctx, tx, userId, filePath)
|
return st.getUploadInfo(ctx, tx, userId, filePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) ListUploadInfos(ctx context.Context, userId uint64) ([]*db.UploadInfo, error) {
|
func (st *DefaultStore) ListUploadInfos(ctx context.Context, userId uint64) ([]*db.UploadInfo, error) {
|
||||||
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
226
src/db/rdb/default/provider.go
Normal file
226
src/db/rdb/default/provider.go
Normal file
|
@ -0,0 +1,226 @@
|
||||||
|
package default
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ihexxa/quickshare/src/db"
|
||||||
|
_ "github.com/mattn/go-sqlite3"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DefaultDB struct {
|
||||||
|
db.IDB
|
||||||
|
dbPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDefaultDB(driverName, dbPath string) (*DefaultDB, error) {
|
||||||
|
db, err := sql.Open(driverName, dbPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &DefaultDB{
|
||||||
|
IDB: db,
|
||||||
|
dbPath: dbPath,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type DefaultStore struct {
|
||||||
|
db db.IDB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDefaultStore(db db.IDB) (*DefaultStore, error) {
|
||||||
|
return &DefaultStore{
|
||||||
|
db: db,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *DefaultStore) Close() error {
|
||||||
|
return st.db.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *DefaultStore) Lock() {
|
||||||
|
st.mtx.Lock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *DefaultStore) Unlock() {
|
||||||
|
st.mtx.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *DefaultStore) RLock() {
|
||||||
|
st.mtx.RLock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *DefaultStore) RUnlock() {
|
||||||
|
st.mtx.RUnlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *DefaultStore) IsInited() bool {
|
||||||
|
// always try to init the db
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *DefaultStore) Init(ctx context.Context, rootName, rootPwd string, cfg *db.SiteConfig) error {
|
||||||
|
err := st.InitUserTable(ctx, rootName, rootPwd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = st.InitFileTables(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return st.InitConfigTable(ctx, cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *DefaultStore) InitUserTable(ctx context.Context, rootName, rootPwd string) error {
|
||||||
|
_, err := st.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`create table if not exists t_user (
|
||||||
|
id bigint not null,
|
||||||
|
name varchar not null unique,
|
||||||
|
pwd varchar not null,
|
||||||
|
role integer not null,
|
||||||
|
used_space bigint not null,
|
||||||
|
quota varchar not null,
|
||||||
|
preference varchar not null,
|
||||||
|
primary key(id)
|
||||||
|
)`,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = st.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`create index if not exists i_user_name on t_user (name)`,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
admin := &db.User{
|
||||||
|
ID: 0,
|
||||||
|
Name: rootName,
|
||||||
|
Pwd: rootPwd,
|
||||||
|
Role: db.AdminRole,
|
||||||
|
Quota: &db.Quota{
|
||||||
|
SpaceLimit: db.DefaultSpaceLimit,
|
||||||
|
UploadSpeedLimit: db.DefaultUploadSpeedLimit,
|
||||||
|
DownloadSpeedLimit: db.DefaultDownloadSpeedLimit,
|
||||||
|
},
|
||||||
|
Preferences: &db.DefaultPreferences,
|
||||||
|
}
|
||||||
|
visitor := &db.User{
|
||||||
|
ID: db.VisitorID,
|
||||||
|
Name: db.VisitorName,
|
||||||
|
Pwd: rootPwd,
|
||||||
|
Role: db.VisitorRole,
|
||||||
|
Quota: &db.Quota{
|
||||||
|
SpaceLimit: 0,
|
||||||
|
UploadSpeedLimit: db.VisitorUploadSpeedLimit,
|
||||||
|
DownloadSpeedLimit: db.VisitorDownloadSpeedLimit,
|
||||||
|
},
|
||||||
|
Preferences: &db.DefaultPreferences,
|
||||||
|
}
|
||||||
|
for _, user := range []*db.User{admin, visitor} {
|
||||||
|
err = st.AddUser(ctx, user)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *DefaultStore) InitFileTables(ctx context.Context) error {
|
||||||
|
_, err := st.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`create table if not exists t_file_info (
|
||||||
|
path varchar not null,
|
||||||
|
user bigint not null,
|
||||||
|
location varchar not null,
|
||||||
|
parent varchar not null,
|
||||||
|
name varchar not null,
|
||||||
|
is_dir boolean not null,
|
||||||
|
size bigint not null,
|
||||||
|
share_id varchar not null,
|
||||||
|
info varchar not null,
|
||||||
|
primary key(path)
|
||||||
|
)`,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = st.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`create index if not exists t_file_share on t_file_info (share_id, location)`,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = st.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`create table if not exists t_file_uploading (
|
||||||
|
real_path varchar not null,
|
||||||
|
tmp_path varchar not null unique,
|
||||||
|
user bigint not null,
|
||||||
|
size bigint not null,
|
||||||
|
uploaded bigint not null,
|
||||||
|
primary key(real_path)
|
||||||
|
)`,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = st.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`create index if not exists t_file_uploading_path on t_file_uploading (real_path, user)`,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = st.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`create index if not exists t_file_uploading_user on t_file_uploading (user)`,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *DefaultStore) InitConfigTable(ctx context.Context, cfg *db.SiteConfig) error {
|
||||||
|
st.Lock()
|
||||||
|
defer st.Unlock()
|
||||||
|
|
||||||
|
_, err := st.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`create table if not exists t_config (
|
||||||
|
id bigint not null,
|
||||||
|
config varchar not null,
|
||||||
|
modified datetime not null,
|
||||||
|
primary key(id)
|
||||||
|
)`,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cfgStr, err := json.Marshal(cfg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = st.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`insert into t_config
|
||||||
|
(id, config, modified) values (?, ?, ?)`,
|
||||||
|
0, cfgStr, time.Now(),
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package sqlite
|
package default
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -11,12 +11,7 @@ import (
|
||||||
"github.com/ihexxa/quickshare/src/db"
|
"github.com/ihexxa/quickshare/src/db"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SQLiteStore struct {
|
func (st *DefaultStore) setUser(ctx context.Context, tx *sql.Tx, user *db.User) error {
|
||||||
db db.IDB
|
|
||||||
mtx *sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
||||||
|
@ -46,7 +41,7 @@ func (st *SQLiteStore) setUser(ctx context.Context, tx *sql.Tx, user *db.User) e
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) getUser(ctx context.Context, tx *sql.Tx, id uint64) (*db.User, error) {
|
func (st *DefaultStore) 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 := tx.QueryRowContext(
|
err := tx.QueryRowContext(
|
||||||
|
@ -82,7 +77,7 @@ func (st *SQLiteStore) getUser(ctx context.Context, tx *sql.Tx, id uint64) (*db.
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) AddUser(ctx context.Context, user *db.User) error {
|
func (st *DefaultStore) AddUser(ctx context.Context, user *db.User) error {
|
||||||
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -115,7 +110,7 @@ func (st *SQLiteStore) AddUser(ctx context.Context, user *db.User) error {
|
||||||
return tx.Commit()
|
return tx.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) DelUser(ctx context.Context, id uint64) error {
|
func (st *DefaultStore) DelUser(ctx context.Context, id uint64) error {
|
||||||
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -134,7 +129,7 @@ func (st *SQLiteStore) DelUser(ctx context.Context, id uint64) error {
|
||||||
return tx.Commit()
|
return tx.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) GetUser(ctx context.Context, id uint64) (*db.User, error) {
|
func (st *DefaultStore) GetUser(ctx context.Context, id uint64) (*db.User, error) {
|
||||||
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -149,7 +144,7 @@ func (st *SQLiteStore) GetUser(ctx context.Context, id uint64) (*db.User, error)
|
||||||
return user, err
|
return user, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) GetUserByName(ctx context.Context, name string) (*db.User, error) {
|
func (st *DefaultStore) GetUserByName(ctx context.Context, name string) (*db.User, error) {
|
||||||
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -191,7 +186,7 @@ func (st *SQLiteStore) GetUserByName(ctx context.Context, name string) (*db.User
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) SetPwd(ctx context.Context, id uint64, pwd string) error {
|
func (st *DefaultStore) SetPwd(ctx context.Context, id uint64, pwd string) error {
|
||||||
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -214,7 +209,7 @@ func (st *SQLiteStore) SetPwd(ctx context.Context, id uint64, pwd string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// role + quota
|
// role + quota
|
||||||
func (st *SQLiteStore) SetInfo(ctx context.Context, id uint64, user *db.User) error {
|
func (st *DefaultStore) SetInfo(ctx context.Context, id uint64, user *db.User) error {
|
||||||
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -241,7 +236,7 @@ func (st *SQLiteStore) SetInfo(ctx context.Context, id uint64, user *db.User) er
|
||||||
return tx.Commit()
|
return tx.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) SetPreferences(ctx context.Context, id uint64, prefers *db.Preferences) error {
|
func (st *DefaultStore) SetPreferences(ctx context.Context, id uint64, prefers *db.Preferences) error {
|
||||||
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -268,7 +263,7 @@ func (st *SQLiteStore) SetPreferences(ctx context.Context, id uint64, prefers *d
|
||||||
return tx.Commit()
|
return tx.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) SetUsed(ctx context.Context, id uint64, incr bool, capacity int64) error {
|
func (st *DefaultStore) SetUsed(ctx context.Context, id uint64, incr bool, capacity int64) error {
|
||||||
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -282,7 +277,7 @@ func (st *SQLiteStore) SetUsed(ctx context.Context, id uint64, incr bool, capaci
|
||||||
return tx.Commit()
|
return tx.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) setUsed(ctx context.Context, tx *sql.Tx, id uint64, incr bool, capacity int64) error {
|
func (st *DefaultStore) setUsed(ctx context.Context, tx *sql.Tx, id uint64, incr bool, capacity int64) error {
|
||||||
gotUser, err := st.getUser(ctx, tx, id)
|
gotUser, err := st.getUser(ctx, tx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -312,7 +307,7 @@ func (st *SQLiteStore) setUsed(ctx context.Context, tx *sql.Tx, id uint64, incr
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) ResetUsed(ctx context.Context, id uint64, used int64) error {
|
func (st *DefaultStore) ResetUsed(ctx context.Context, id uint64, used int64) error {
|
||||||
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -334,7 +329,7 @@ func (st *SQLiteStore) ResetUsed(ctx context.Context, id uint64, used int64) err
|
||||||
return tx.Commit()
|
return tx.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) listUsers(ctx context.Context, tx *sql.Tx) ([]*db.User, error) {
|
func (st *DefaultStore) listUsers(ctx context.Context, tx *sql.Tx) ([]*db.User, error) {
|
||||||
// TODO: support pagination
|
// TODO: support pagination
|
||||||
rows, err := tx.QueryContext(
|
rows, err := tx.QueryContext(
|
||||||
ctx,
|
ctx,
|
||||||
|
@ -378,7 +373,7 @@ func (st *SQLiteStore) listUsers(ctx context.Context, tx *sql.Tx) ([]*db.User, e
|
||||||
return users, nil
|
return users, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) ListUsers(ctx context.Context) ([]*db.User, error) {
|
func (st *DefaultStore) ListUsers(ctx context.Context) ([]*db.User, error) {
|
||||||
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -388,7 +383,7 @@ func (st *SQLiteStore) ListUsers(ctx context.Context) ([]*db.User, error) {
|
||||||
return st.listUsers(ctx, tx)
|
return st.listUsers(ctx, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) ListUserIDs(ctx context.Context) (map[string]string, error) {
|
func (st *DefaultStore) ListUserIDs(ctx context.Context) (map[string]string, error) {
|
||||||
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
tx, err := st.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -407,17 +402,17 @@ func (st *SQLiteStore) ListUserIDs(ctx context.Context) (map[string]string, erro
|
||||||
return nameToId, nil
|
return nameToId, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) AddRole(role string) error {
|
func (st *DefaultStore) AddRole(role string) error {
|
||||||
// TODO: implement this after adding grant/revoke
|
// TODO: implement this after adding grant/revoke
|
||||||
panic("not implemented")
|
panic("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) DelRole(role string) error {
|
func (st *DefaultStore) DelRole(role string) error {
|
||||||
// TODO: implement this after adding grant/revoke
|
// TODO: implement this after adding grant/revoke
|
||||||
panic("not implemented")
|
panic("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SQLiteStore) ListRoles() (map[string]bool, error) {
|
func (st *DefaultStore) ListRoles() (map[string]bool, error) {
|
||||||
// TODO: implement this after adding grant/revoke
|
// TODO: implement this after adding grant/revoke
|
||||||
panic("not implemented")
|
panic("not implemented")
|
||||||
}
|
}
|
||||||
|
|
72
src/db/rdb/sqlite/configs.go
Normal file
72
src/db/rdb/sqlite/configs.go
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
package sqlite
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/ihexxa/quickshare/src/db"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (st *SQLiteStore) getCfg(ctx context.Context) (*db.SiteConfig, error) {
|
||||||
|
var configStr string
|
||||||
|
err := st.db.QueryRowContext(
|
||||||
|
ctx,
|
||||||
|
`select config
|
||||||
|
from t_config
|
||||||
|
where id=0`,
|
||||||
|
).Scan(&configStr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
config := &db.SiteConfig{}
|
||||||
|
err = json.Unmarshal([]byte(configStr), config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = db.CheckSiteCfg(config, true); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) setCfg(ctx context.Context, cfg *db.SiteConfig) error {
|
||||||
|
if err := db.CheckSiteCfg(cfg, false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cfgBytes, err := json.Marshal(cfg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = st.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`update t_config
|
||||||
|
set config=?
|
||||||
|
where id=0`,
|
||||||
|
string(cfgBytes),
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) SetClientCfg(ctx context.Context, cfg *db.ClientConfig) error {
|
||||||
|
st.Lock()
|
||||||
|
defer st.Unlock()
|
||||||
|
|
||||||
|
siteCfg, err := st.getCfg(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
siteCfg.ClientCfg = cfg
|
||||||
|
|
||||||
|
return st.setCfg(ctx, siteCfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) GetCfg(ctx context.Context) (*db.SiteConfig, error) {
|
||||||
|
st.RLock()
|
||||||
|
defer st.RUnlock()
|
||||||
|
|
||||||
|
return st.getCfg(ctx)
|
||||||
|
}
|
273
src/db/rdb/sqlite/files.go
Normal file
273
src/db/rdb/sqlite/files.go
Normal file
|
@ -0,0 +1,273 @@
|
||||||
|
package sqlite
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ihexxa/quickshare/src/db"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (st *SQLiteStore) getFileInfo(ctx context.Context, itemPath string) (*db.FileInfo, error) {
|
||||||
|
var infoStr string
|
||||||
|
fInfo := &db.FileInfo{}
|
||||||
|
var isDir bool
|
||||||
|
var size int64
|
||||||
|
var shareId string
|
||||||
|
err := st.db.QueryRowContext(
|
||||||
|
ctx,
|
||||||
|
`select is_dir, size, share_id, info
|
||||||
|
from t_file_info
|
||||||
|
where path=?`,
|
||||||
|
itemPath,
|
||||||
|
).Scan(
|
||||||
|
&isDir,
|
||||||
|
&size,
|
||||||
|
&shareId,
|
||||||
|
&infoStr,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return nil, db.ErrFileInfoNotFound
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(infoStr), &fInfo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
fInfo.IsDir = isDir
|
||||||
|
fInfo.Size = size
|
||||||
|
fInfo.ShareID = shareId
|
||||||
|
fInfo.Shared = shareId != ""
|
||||||
|
return fInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) GetFileInfo(ctx context.Context, itemPath string) (*db.FileInfo, error) {
|
||||||
|
st.RLock()
|
||||||
|
defer st.RUnlock()
|
||||||
|
|
||||||
|
return st.getFileInfo(ctx, itemPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) ListFileInfos(ctx context.Context, itemPaths []string) (map[string]*db.FileInfo, error) {
|
||||||
|
st.RLock()
|
||||||
|
defer st.RUnlock()
|
||||||
|
|
||||||
|
// TODO: add pagination
|
||||||
|
placeholders := []string{}
|
||||||
|
values := []any{}
|
||||||
|
for i := 0; i < len(itemPaths); i++ {
|
||||||
|
placeholders = append(placeholders, "?")
|
||||||
|
values = append(values, itemPaths[i])
|
||||||
|
}
|
||||||
|
rows, err := st.db.QueryContext(
|
||||||
|
ctx,
|
||||||
|
fmt.Sprintf(
|
||||||
|
`select path, is_dir, size, share_id, info
|
||||||
|
from t_file_info
|
||||||
|
where path in (%s)
|
||||||
|
`,
|
||||||
|
strings.Join(placeholders, ","),
|
||||||
|
),
|
||||||
|
values...,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var fInfoStr, itemPath, shareId string
|
||||||
|
var isDir bool
|
||||||
|
var size int64
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(fInfoStr), fInfo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
fInfo.IsDir = isDir
|
||||||
|
fInfo.Size = size
|
||||||
|
fInfo.ShareID = shareId
|
||||||
|
fInfo.Shared = shareId != ""
|
||||||
|
fInfos[itemPath] = fInfo
|
||||||
|
}
|
||||||
|
if rows.Err() != nil {
|
||||||
|
return nil, rows.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
return fInfos, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) addFileInfo(ctx context.Context, userId uint64, itemPath string, info *db.FileInfo) error {
|
||||||
|
infoStr, err := json.Marshal(info)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
location, err := getLocation(itemPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
dirPath, itemName := path.Split(itemPath)
|
||||||
|
_, err = st.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`insert into t_file_info (
|
||||||
|
path, user, location, parent, name,
|
||||||
|
is_dir, size, share_id, info
|
||||||
|
)
|
||||||
|
values (
|
||||||
|
?, ?, ?, ?, ?,
|
||||||
|
?, ?, ?, ?
|
||||||
|
)`,
|
||||||
|
itemPath, userId, location, dirPath, itemName,
|
||||||
|
info.IsDir, info.Size, info.ShareID, infoStr,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) AddFileInfo(ctx context.Context, userId uint64, itemPath string, info *db.FileInfo) error {
|
||||||
|
st.Lock()
|
||||||
|
defer st.Unlock()
|
||||||
|
|
||||||
|
err := st.addFileInfo(ctx, userId, itemPath, info)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// increase used space
|
||||||
|
return st.setUsed(ctx, userId, true, info.Size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) delFileInfo(ctx context.Context, itemPath string) error {
|
||||||
|
_, err := st.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`delete from t_file_info
|
||||||
|
where path=?
|
||||||
|
`,
|
||||||
|
itemPath,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) SetSha1(ctx context.Context, itemPath, sign string) error {
|
||||||
|
st.Lock()
|
||||||
|
defer st.Unlock()
|
||||||
|
|
||||||
|
info, err := st.getFileInfo(ctx, itemPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
info.Sha1 = sign
|
||||||
|
|
||||||
|
infoStr, err := json.Marshal(info)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = st.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`update t_file_info
|
||||||
|
set info=?
|
||||||
|
where path=?`,
|
||||||
|
infoStr,
|
||||||
|
itemPath,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) DelFileInfo(ctx context.Context, userID uint64, itemPath string) error {
|
||||||
|
st.Lock()
|
||||||
|
defer st.Unlock()
|
||||||
|
|
||||||
|
// get all children and size
|
||||||
|
rows, err := st.db.QueryContext(
|
||||||
|
ctx,
|
||||||
|
`select path, size
|
||||||
|
from t_file_info
|
||||||
|
where path = ? or path like ?
|
||||||
|
`,
|
||||||
|
itemPath,
|
||||||
|
fmt.Sprintf("%s/%%", itemPath),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var childrenPath string
|
||||||
|
var itemSize int64
|
||||||
|
placeholders := []string{}
|
||||||
|
values := []any{}
|
||||||
|
decrSize := int64(0)
|
||||||
|
for rows.Next() {
|
||||||
|
err = rows.Scan(&childrenPath, &itemSize)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
placeholders = append(placeholders, "?")
|
||||||
|
values = append(values, childrenPath)
|
||||||
|
decrSize += itemSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// decrease used space
|
||||||
|
err = st.setUsed(ctx, userID, false, decrSize)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete file info entries
|
||||||
|
_, err = st.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
fmt.Sprintf(
|
||||||
|
`delete from t_file_info
|
||||||
|
where path in (%s)`,
|
||||||
|
strings.Join(placeholders, ","),
|
||||||
|
),
|
||||||
|
values...,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) MoveFileInfo(ctx context.Context, userId uint64, oldPath, newPath string, isDir bool) error {
|
||||||
|
st.Lock()
|
||||||
|
defer st.Unlock()
|
||||||
|
|
||||||
|
info, err := st.getFileInfo(ctx, oldPath)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, db.ErrFileInfoNotFound) {
|
||||||
|
// info for file does not exist so no need to move it
|
||||||
|
// e.g. folder info is not created before
|
||||||
|
// TODO: but sometimes it could be a bug
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = st.delFileInfo(ctx, oldPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return st.addFileInfo(ctx, userId, newPath, info)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getLocation(itemPath string) (string, error) {
|
||||||
|
// location is taken from item path
|
||||||
|
itemPathParts := strings.Split(itemPath, "/")
|
||||||
|
if len(itemPathParts) == 0 {
|
||||||
|
return "", fmt.Errorf("invalid item path '%s'", itemPath)
|
||||||
|
}
|
||||||
|
return itemPathParts[0], nil
|
||||||
|
}
|
179
src/db/rdb/sqlite/files_sharings.go
Normal file
179
src/db/rdb/sqlite/files_sharings.go
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
package sqlite
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/sha1"
|
||||||
|
"database/sql"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"path"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ihexxa/quickshare/src/db"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (st *SQLiteStore) generateShareID(payload string) (string, error) {
|
||||||
|
if len(payload) == 0 {
|
||||||
|
return "", db.ErrEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := fmt.Sprintf("%s-%d", payload, time.Now().Unix())
|
||||||
|
h := sha1.New()
|
||||||
|
_, err := io.WriteString(h, msg)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("%x", h.Sum(nil))[:7], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) IsSharing(ctx context.Context, dirPath string) (bool, error) {
|
||||||
|
st.RLock()
|
||||||
|
defer st.RUnlock()
|
||||||
|
|
||||||
|
var shareId string
|
||||||
|
err := st.db.QueryRowContext(
|
||||||
|
ctx,
|
||||||
|
`select share_id
|
||||||
|
from t_file_info
|
||||||
|
where path=?`,
|
||||||
|
dirPath,
|
||||||
|
).Scan(
|
||||||
|
&shareId,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return false, db.ErrFileInfoNotFound
|
||||||
|
}
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return shareId != "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) GetSharingDir(ctx context.Context, hashID string) (string, error) {
|
||||||
|
st.RLock()
|
||||||
|
defer st.RUnlock()
|
||||||
|
|
||||||
|
var sharedPath string
|
||||||
|
err := st.db.QueryRowContext(
|
||||||
|
ctx,
|
||||||
|
`select path
|
||||||
|
from t_file_info
|
||||||
|
where share_id=?
|
||||||
|
`,
|
||||||
|
hashID,
|
||||||
|
).Scan(
|
||||||
|
&sharedPath,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return "", db.ErrSharingNotFound
|
||||||
|
}
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return sharedPath, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) AddSharing(ctx context.Context, userId uint64, dirPath string) error {
|
||||||
|
st.Lock()
|
||||||
|
defer st.Unlock()
|
||||||
|
|
||||||
|
shareID, err := st.generateShareID(dirPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
location, err := getLocation(dirPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = st.getFileInfo(ctx, dirPath)
|
||||||
|
if err != nil && !errors.Is(err, db.ErrFileInfoNotFound) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if errors.Is(err, db.ErrFileInfoNotFound) {
|
||||||
|
// insert new
|
||||||
|
parentPath, name := path.Split(dirPath)
|
||||||
|
info := &db.FileInfo{Shared: true} // TODO: deprecate shared in info
|
||||||
|
infoStr, err := json.Marshal(info)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = st.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`insert into t_file_info (
|
||||||
|
path, user, location, parent, name,
|
||||||
|
is_dir, size, share_id, info
|
||||||
|
)
|
||||||
|
values (
|
||||||
|
?, ?, ?, ?, ?,
|
||||||
|
?, ?, ?, ?
|
||||||
|
)`,
|
||||||
|
dirPath, userId, location, parentPath, name,
|
||||||
|
true, 0, shareID, infoStr,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = st.db.ExecContext(
|
||||||
|
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 {
|
||||||
|
st.Lock()
|
||||||
|
defer st.Unlock()
|
||||||
|
|
||||||
|
_, err := st.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`update t_file_info
|
||||||
|
set share_id=''
|
||||||
|
where path=?`,
|
||||||
|
dirPath,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) ListSharingsByLocation(ctx context.Context, location string) (map[string]string, error) {
|
||||||
|
st.RLock()
|
||||||
|
defer st.RUnlock()
|
||||||
|
|
||||||
|
rows, err := st.db.QueryContext(
|
||||||
|
ctx,
|
||||||
|
`select path, share_id
|
||||||
|
from t_file_info
|
||||||
|
where share_id<>'' and location=?`,
|
||||||
|
location,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var pathname, shareId string
|
||||||
|
pathToShareId := map[string]string{}
|
||||||
|
for rows.Next() {
|
||||||
|
err = rows.Scan(&pathname, &shareId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
pathToShareId[pathname] = shareId
|
||||||
|
}
|
||||||
|
if rows.Err() != nil {
|
||||||
|
return nil, rows.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
return pathToShareId, nil
|
||||||
|
}
|
196
src/db/rdb/sqlite/files_uploadings.go
Normal file
196
src/db/rdb/sqlite/files_uploadings.go
Normal file
|
@ -0,0 +1,196 @@
|
||||||
|
package sqlite
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"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(
|
||||||
|
ctx,
|
||||||
|
`insert into t_file_uploading (
|
||||||
|
real_path, tmp_path, user, size, uploaded
|
||||||
|
)
|
||||||
|
values (
|
||||||
|
?, ?, ?, ?, ?
|
||||||
|
)`,
|
||||||
|
filePath, tmpPath, userId, fileSize, 0,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) AddUploadInfos(ctx context.Context, userId uint64, tmpPath, filePath string, info *db.FileInfo) error {
|
||||||
|
st.Lock()
|
||||||
|
defer st.Unlock()
|
||||||
|
|
||||||
|
userInfo, err := st.getUser(ctx, 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)
|
||||||
|
if err == nil {
|
||||||
|
return db.ErrKeyExisting
|
||||||
|
} else if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
userInfo.UsedSpace += info.Size
|
||||||
|
err = st.setUser(ctx, userInfo)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return st.addUploadInfoOnly(ctx, userId, tmpPath, filePath, info.Size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) DelUploadingInfos(ctx context.Context, userId uint64, realPath string) error {
|
||||||
|
st.Lock()
|
||||||
|
defer st.Unlock()
|
||||||
|
|
||||||
|
return st.delUploadingInfos(ctx, userId, realPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) delUploadingInfos(ctx context.Context, userId uint64, realPath string) error {
|
||||||
|
_, size, _, err := st.getUploadInfo(ctx, userId, realPath)
|
||||||
|
if err != nil {
|
||||||
|
// info may not exist
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = st.delUploadInfoOnly(ctx, userId, realPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
userInfo, err := st.getUser(ctx, userId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
userInfo.UsedSpace -= size
|
||||||
|
return st.setUser(ctx, userInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) delUploadInfoOnly(ctx context.Context, userId uint64, filePath string) error {
|
||||||
|
_, err := st.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`delete from t_file_uploading
|
||||||
|
where real_path=? and user=?`,
|
||||||
|
filePath, userId,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) MoveUploadingInfos(ctx context.Context, userId uint64, uploadPath, itemPath string) error {
|
||||||
|
st.Lock()
|
||||||
|
defer st.Unlock()
|
||||||
|
|
||||||
|
_, size, _, err := st.getUploadInfo(ctx, userId, itemPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = st.delUploadInfoOnly(ctx, userId, itemPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return st.addFileInfo(ctx, userId, itemPath, &db.FileInfo{
|
||||||
|
Size: size,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) SetUploadInfo(ctx context.Context, userId uint64, filePath string, newUploaded int64) error {
|
||||||
|
st.Lock()
|
||||||
|
defer st.Unlock()
|
||||||
|
|
||||||
|
var size, uploaded int64
|
||||||
|
err := st.db.QueryRowContext(
|
||||||
|
ctx,
|
||||||
|
`select size, uploaded
|
||||||
|
from t_file_uploading
|
||||||
|
where real_path=? and user=?`,
|
||||||
|
filePath, userId,
|
||||||
|
).Scan(&size, &uploaded)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if newUploaded > size {
|
||||||
|
return db.ErrGreaterThanSize
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = st.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`update t_file_uploading
|
||||||
|
set uploaded=?
|
||||||
|
where real_path=? and user=?`,
|
||||||
|
newUploaded, filePath, userId,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) getUploadInfo(ctx context.Context, userId uint64, filePath string) (string, int64, int64, error) {
|
||||||
|
var size, uploaded int64
|
||||||
|
err := st.db.QueryRowContext(
|
||||||
|
ctx,
|
||||||
|
`select size, uploaded
|
||||||
|
from t_file_uploading
|
||||||
|
where real_path=? and user=?`,
|
||||||
|
filePath, userId,
|
||||||
|
).Scan(&size, &uploaded)
|
||||||
|
if err != nil {
|
||||||
|
return "", 0, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return filePath, size, uploaded, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) ListUploadInfos(ctx context.Context, userId uint64) ([]*db.UploadInfo, error) {
|
||||||
|
st.RLock()
|
||||||
|
defer st.RUnlock()
|
||||||
|
|
||||||
|
rows, err := st.db.QueryContext(
|
||||||
|
ctx,
|
||||||
|
`select real_path, size, uploaded
|
||||||
|
from t_file_uploading
|
||||||
|
where user=?`,
|
||||||
|
userId,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var pathname string
|
||||||
|
var size, uploaded int64
|
||||||
|
infos := []*db.UploadInfo{}
|
||||||
|
for rows.Next() {
|
||||||
|
err = rows.Scan(
|
||||||
|
&pathname,
|
||||||
|
&size,
|
||||||
|
&uploaded,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
infos = append(infos, &db.UploadInfo{
|
||||||
|
RealFilePath: pathname,
|
||||||
|
Size: size,
|
||||||
|
Uploaded: uploaded,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if rows.Err() != nil {
|
||||||
|
return nil, rows.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
return infos, nil
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
@ -126,9 +127,17 @@ func (st *SQLiteStore) InitUserTable(ctx context.Context, rootName, rootPwd stri
|
||||||
Preferences: &db.DefaultPreferences,
|
Preferences: &db.DefaultPreferences,
|
||||||
}
|
}
|
||||||
for _, user := range []*db.User{admin, visitor} {
|
for _, user := range []*db.User{admin, visitor} {
|
||||||
err = st.AddUser(ctx, user)
|
// TODO: not atomic
|
||||||
|
_, err := st.GetUser(ctx, user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
if errors.Is(err, db.ErrUserNotFound) {
|
||||||
|
err = st.AddUser(ctx, user)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,11 +223,20 @@ func (st *SQLiteStore) InitConfigTable(ctx context.Context, cfg *db.SiteConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, err = st.db.ExecContext(
|
|
||||||
ctx,
|
_, err = st.getCfg(ctx)
|
||||||
`insert into t_config
|
if err != nil {
|
||||||
(id, config, modified) values (?, ?, ?)`,
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
0, cfgStr, time.Now(),
|
_, err = st.db.ExecContext(
|
||||||
)
|
ctx,
|
||||||
return err
|
`insert into t_config
|
||||||
|
(id, config, modified) values (?, ?, ?)`,
|
||||||
|
0, cfgStr, time.Now(),
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
361
src/db/rdb/sqlite/users.go
Normal file
361
src/db/rdb/sqlite/users.go
Normal file
|
@ -0,0 +1,361 @@
|
||||||
|
package sqlite
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/ihexxa/quickshare/src/db"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SQLiteStore struct {
|
||||||
|
db db.IDB
|
||||||
|
mtx *sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) setUser(ctx context.Context, user *db.User) error {
|
||||||
|
var err error
|
||||||
|
if err = db.CheckUser(user, false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
quotaStr, err := json.Marshal(user.Quota)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
preferencesStr, err := json.Marshal(user.Preferences)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = st.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`update t_user
|
||||||
|
set name=?, pwd=?, role=?, used_space=?, quota=?, preference=?
|
||||||
|
where id=?`,
|
||||||
|
user.Name,
|
||||||
|
user.Pwd,
|
||||||
|
user.Role,
|
||||||
|
user.UsedSpace,
|
||||||
|
quotaStr,
|
||||||
|
preferencesStr,
|
||||||
|
user.ID,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) getUser(ctx context.Context, id uint64) (*db.User, error) {
|
||||||
|
user := &db.User{}
|
||||||
|
var quotaStr, preferenceStr string
|
||||||
|
err := st.db.QueryRowContext(
|
||||||
|
ctx,
|
||||||
|
`select id, name, pwd, role, used_space, quota, preference
|
||||||
|
from t_user
|
||||||
|
where id=?`,
|
||||||
|
id,
|
||||||
|
).Scan(
|
||||||
|
&user.ID,
|
||||||
|
&user.Name,
|
||||||
|
&user.Pwd,
|
||||||
|
&user.Role,
|
||||||
|
&user.UsedSpace,
|
||||||
|
"aStr,
|
||||||
|
&preferenceStr,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return nil, db.ErrUserNotFound
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(quotaStr), &user.Quota)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = json.Unmarshal([]byte(preferenceStr), &user.Preferences)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) AddUser(ctx context.Context, user *db.User) error {
|
||||||
|
st.Lock()
|
||||||
|
defer st.Unlock()
|
||||||
|
|
||||||
|
quotaStr, err := json.Marshal(user.Quota)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
preferenceStr, err := json.Marshal(user.Preferences)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = st.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`insert into t_user (id, name, pwd, role, used_space, quota, preference) values (?, ?, ?, ?, ?, ?, ?)`,
|
||||||
|
user.ID,
|
||||||
|
user.Name,
|
||||||
|
user.Pwd,
|
||||||
|
user.Role,
|
||||||
|
user.UsedSpace,
|
||||||
|
quotaStr,
|
||||||
|
preferenceStr,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) DelUser(ctx context.Context, id uint64) error {
|
||||||
|
st.Lock()
|
||||||
|
defer st.Unlock()
|
||||||
|
|
||||||
|
_, err := st.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`delete from t_user where id=?`,
|
||||||
|
id,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) GetUser(ctx context.Context, id uint64) (*db.User, error) {
|
||||||
|
st.RLock()
|
||||||
|
defer st.RUnlock()
|
||||||
|
|
||||||
|
user, err := st.getUser(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return user, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) GetUserByName(ctx context.Context, name string) (*db.User, error) {
|
||||||
|
st.RLock()
|
||||||
|
defer st.RUnlock()
|
||||||
|
|
||||||
|
user := &db.User{}
|
||||||
|
var quotaStr, preferenceStr string
|
||||||
|
err := st.db.QueryRowContext(
|
||||||
|
ctx,
|
||||||
|
`select id, name, pwd, role, used_space, quota, preference
|
||||||
|
from t_user
|
||||||
|
where name=?`,
|
||||||
|
name,
|
||||||
|
).Scan(
|
||||||
|
&user.ID,
|
||||||
|
&user.Name,
|
||||||
|
&user.Pwd,
|
||||||
|
&user.Role,
|
||||||
|
&user.UsedSpace,
|
||||||
|
"aStr,
|
||||||
|
&preferenceStr,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return nil, db.ErrUserNotFound
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(quotaStr), &user.Quota)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = json.Unmarshal([]byte(preferenceStr), &user.Preferences)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) SetPwd(ctx context.Context, id uint64, pwd string) error {
|
||||||
|
st.Lock()
|
||||||
|
defer st.Unlock()
|
||||||
|
|
||||||
|
_, err := st.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`update t_user
|
||||||
|
set pwd=?
|
||||||
|
where id=?`,
|
||||||
|
pwd,
|
||||||
|
id,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// role + quota
|
||||||
|
func (st *SQLiteStore) SetInfo(ctx context.Context, id uint64, user *db.User) error {
|
||||||
|
st.Lock()
|
||||||
|
defer st.Unlock()
|
||||||
|
|
||||||
|
quotaStr, err := json.Marshal(user.Quota)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = st.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`update t_user
|
||||||
|
set role=?, quota=?
|
||||||
|
where id=?`,
|
||||||
|
user.Role, quotaStr,
|
||||||
|
id,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) SetPreferences(ctx context.Context, id uint64, prefers *db.Preferences) error {
|
||||||
|
st.Lock()
|
||||||
|
defer st.Unlock()
|
||||||
|
|
||||||
|
preferenceStr, err := json.Marshal(prefers)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = st.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`update t_user
|
||||||
|
set preference=?
|
||||||
|
where id=?`,
|
||||||
|
preferenceStr,
|
||||||
|
id,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) setUsed(ctx context.Context, id uint64, incr bool, capacity int64) error {
|
||||||
|
gotUser, err := st.getUser(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if incr && gotUser.UsedSpace+capacity > int64(gotUser.Quota.SpaceLimit) {
|
||||||
|
return db.ErrReachedLimit
|
||||||
|
}
|
||||||
|
|
||||||
|
if incr {
|
||||||
|
gotUser.UsedSpace = gotUser.UsedSpace + capacity
|
||||||
|
} else {
|
||||||
|
if gotUser.UsedSpace-capacity < 0 {
|
||||||
|
return db.ErrNegtiveUsedSpace
|
||||||
|
}
|
||||||
|
gotUser.UsedSpace = gotUser.UsedSpace - capacity
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = st.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`update t_user
|
||||||
|
set used_space=?
|
||||||
|
where id=?`,
|
||||||
|
gotUser.UsedSpace,
|
||||||
|
gotUser.ID,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) ResetUsed(ctx context.Context, id uint64, used int64) error {
|
||||||
|
st.Lock()
|
||||||
|
defer st.Unlock()
|
||||||
|
|
||||||
|
_, err := st.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`update t_user
|
||||||
|
set used_space=?
|
||||||
|
where id=?`,
|
||||||
|
used,
|
||||||
|
id,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) ListUsers(ctx context.Context) ([]*db.User, error) {
|
||||||
|
st.RLock()
|
||||||
|
defer st.RUnlock()
|
||||||
|
|
||||||
|
// TODO: support pagination
|
||||||
|
rows, err := st.db.QueryContext(
|
||||||
|
ctx,
|
||||||
|
`select id, name, role, used_space, quota, preference
|
||||||
|
from t_user`,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return nil, db.ErrUserNotFound
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close() // TODO: check error
|
||||||
|
|
||||||
|
users := []*db.User{}
|
||||||
|
for rows.Next() {
|
||||||
|
user := &db.User{}
|
||||||
|
var quotaStr, preferenceStr string
|
||||||
|
err = rows.Scan(
|
||||||
|
&user.ID,
|
||||||
|
&user.Name,
|
||||||
|
&user.Role,
|
||||||
|
&user.UsedSpace,
|
||||||
|
"aStr,
|
||||||
|
&preferenceStr,
|
||||||
|
)
|
||||||
|
err = json.Unmarshal([]byte(quotaStr), &user.Quota)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = json.Unmarshal([]byte(preferenceStr), &user.Preferences)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
users = append(users, user)
|
||||||
|
}
|
||||||
|
if rows.Err() != nil {
|
||||||
|
return nil, rows.Err()
|
||||||
|
}
|
||||||
|
return users, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) ListUserIDs(ctx context.Context) (map[string]string, error) {
|
||||||
|
st.RLock()
|
||||||
|
defer st.RUnlock()
|
||||||
|
|
||||||
|
users, err := st.ListUsers(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
nameToId := map[string]string{}
|
||||||
|
for _, user := range users {
|
||||||
|
nameToId[user.Name] = fmt.Sprint(user.ID)
|
||||||
|
}
|
||||||
|
return nameToId, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) AddRole(role string) error {
|
||||||
|
// TODO: implement this after adding grant/revoke
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) DelRole(role string) error {
|
||||||
|
// TODO: implement this after adding grant/revoke
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *SQLiteStore) ListRoles() (map[string]bool, error) {
|
||||||
|
// TODO: implement this after adding grant/revoke
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
40
src/db/tests/common_test.go
Normal file
40
src/db/tests/common_test.go
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
package tests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ihexxa/quickshare/src/db/rdb/sqlite"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSqliteInit(t *testing.T) {
|
||||||
|
t.Run("idemptent initialization - sqlite", func(t *testing.T) {
|
||||||
|
rootPath, err := ioutil.TempDir("./", "qs_sqlite_config_")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(rootPath)
|
||||||
|
|
||||||
|
dbPath := filepath.Join(rootPath, "quickshare.sqlite")
|
||||||
|
sqliteDB, err := sqlite.NewSQLite(dbPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer sqliteDB.Close()
|
||||||
|
|
||||||
|
store, err := sqlite.NewSQLiteStore(sqliteDB)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("fail to new sqlite store", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 2; i++ {
|
||||||
|
err = store.Init(context.TODO(), "admin", "adminPwd", testSiteConfig)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
|
@ -123,4 +123,31 @@ func TestSiteStore(t *testing.T) {
|
||||||
|
|
||||||
testConfigMethods(t, store)
|
testConfigMethods(t, store)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("idemptent initialization - sqlite", func(t *testing.T) {
|
||||||
|
rootPath, err := ioutil.TempDir("./", "qs_sqlite_config_")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(rootPath)
|
||||||
|
|
||||||
|
dbPath := filepath.Join(rootPath, "quickshare.sqlite")
|
||||||
|
sqliteDB, err := sqlite.NewSQLite(dbPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer sqliteDB.Close()
|
||||||
|
|
||||||
|
store, err := sqlite.NewSQLiteStore(sqliteDB)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("fail to new sqlite store", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 2; i++ {
|
||||||
|
err = store.Init(context.TODO(), "admin", "adminPwd", testSiteConfig)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
238
src/server/init_deps.go
Normal file
238
src/server/init_deps.go
Normal file
|
@ -0,0 +1,238 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/sha1"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/ihexxa/gocfg"
|
||||||
|
"github.com/ihexxa/quickshare/src/db/rdb/sqlite"
|
||||||
|
"github.com/natefinch/lumberjack"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"go.uber.org/zap/zapcore"
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
|
||||||
|
"github.com/ihexxa/quickshare/src/cryptoutil/jwt"
|
||||||
|
"github.com/ihexxa/quickshare/src/db"
|
||||||
|
"github.com/ihexxa/quickshare/src/depidx"
|
||||||
|
"github.com/ihexxa/quickshare/src/fs"
|
||||||
|
"github.com/ihexxa/quickshare/src/fs/local"
|
||||||
|
"github.com/ihexxa/quickshare/src/idgen/simpleidgen"
|
||||||
|
"github.com/ihexxa/quickshare/src/iolimiter"
|
||||||
|
"github.com/ihexxa/quickshare/src/search/fileindex"
|
||||||
|
"github.com/ihexxa/quickshare/src/worker/localworker"
|
||||||
|
)
|
||||||
|
|
||||||
|
func InitCfg(cfg gocfg.ICfg, logger *zap.SugaredLogger) (gocfg.ICfg, error) {
|
||||||
|
_, ok := cfg.String("ENV.TOKENSECRET")
|
||||||
|
if !ok {
|
||||||
|
cfg.SetString("ENV.TOKENSECRET", makeRandToken())
|
||||||
|
logger.Info("warning: TOKENSECRET is not set, generated a random token")
|
||||||
|
}
|
||||||
|
|
||||||
|
return cfg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func initLogger(cfg gocfg.ICfg) *zap.SugaredLogger {
|
||||||
|
fileWriter := zapcore.AddSync(&lumberjack.Logger{
|
||||||
|
Filename: path.Join(cfg.GrabString("Fs.Root"), "quickshare.log"),
|
||||||
|
MaxSize: cfg.IntOr("Log.MaxSize", 50), // megabytes
|
||||||
|
MaxBackups: cfg.IntOr("Log.MaxBackups", 2),
|
||||||
|
MaxAge: cfg.IntOr("Log.MaxAge", 31), // days
|
||||||
|
})
|
||||||
|
stdoutWriter := zapcore.AddSync(os.Stdout)
|
||||||
|
|
||||||
|
multiWriter := zapcore.NewMultiWriteSyncer(fileWriter, stdoutWriter)
|
||||||
|
gin.DefaultWriter = multiWriter
|
||||||
|
core := zapcore.NewCore(
|
||||||
|
zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
|
||||||
|
multiWriter,
|
||||||
|
zap.InfoLevel,
|
||||||
|
)
|
||||||
|
return zap.New(core).Sugar()
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeRandToken() string {
|
||||||
|
b := make([]byte, 32)
|
||||||
|
_, err := rand.Read(b)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("make rand token error: %s", err))
|
||||||
|
}
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func mkRoot(rootPath string, logger *zap.SugaredLogger) {
|
||||||
|
info, err := os.Stat(rootPath)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
err = os.MkdirAll(rootPath, 0760)
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatalf("create root path error: %s", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.Fatalf("stat root Path error: %s", err)
|
||||||
|
}
|
||||||
|
} else if !info.IsDir() {
|
||||||
|
logger.Fatalf("can not create %s folder: there is a file with same name", rootPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func initDeps(cfg gocfg.ICfg) *depidx.Deps {
|
||||||
|
var err error
|
||||||
|
logger := initLogger(cfg)
|
||||||
|
|
||||||
|
rootPath := cfg.GrabString("Fs.Root")
|
||||||
|
mkRoot(rootPath, logger)
|
||||||
|
opensLimit := cfg.GrabInt("Fs.OpensLimit")
|
||||||
|
openTTL := cfg.GrabInt("Fs.OpenTTL")
|
||||||
|
readerTTL := cfg.GrabInt("Server.WriteTimeout") / 1000 // millisecond -> second
|
||||||
|
ider := simpleidgen.New()
|
||||||
|
filesystem := local.NewLocalFS(rootPath, 0660, opensLimit, openTTL, readerTTL, ider)
|
||||||
|
|
||||||
|
secret, _ := cfg.String("ENV.TOKENSECRET")
|
||||||
|
jwtEncDec := jwt.NewJWTEncDec(secret)
|
||||||
|
|
||||||
|
quickshareDb, err := initDB(cfg, filesystem)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("failed to init DB: %s", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
limiterCap := cfg.IntOr("Users.LimiterCapacity", 10000)
|
||||||
|
limiterCyc := cfg.IntOr("Users.LimiterCyc", 1000)
|
||||||
|
limiter := iolimiter.NewIOLimiter(limiterCap, limiterCyc, quickshareDb)
|
||||||
|
|
||||||
|
deps := depidx.NewDeps(cfg)
|
||||||
|
deps.SetDB(quickshareDb)
|
||||||
|
deps.SetFS(filesystem)
|
||||||
|
deps.SetToken(jwtEncDec)
|
||||||
|
deps.SetID(ider)
|
||||||
|
deps.SetLog(logger)
|
||||||
|
deps.SetLimiter(limiter)
|
||||||
|
|
||||||
|
queueSize := cfg.GrabInt("Workers.QueueSize")
|
||||||
|
sleepCyc := cfg.GrabInt("Workers.SleepCyc")
|
||||||
|
workerCount := cfg.GrabInt("Workers.WorkerCount")
|
||||||
|
|
||||||
|
workers := localworker.NewWorkerPool(queueSize, sleepCyc, workerCount, logger)
|
||||||
|
workers.Start()
|
||||||
|
deps.SetWorkers(workers)
|
||||||
|
|
||||||
|
searchResultLimit := cfg.GrabInt("Server.SearchResultLimit")
|
||||||
|
fileIndex := fileindex.NewFileTreeIndex(filesystem, "/", searchResultLimit)
|
||||||
|
indexInfo, err := filesystem.Stat(fileIndexPath)
|
||||||
|
indexInited := false
|
||||||
|
if err != nil {
|
||||||
|
if !os.IsNotExist(err) {
|
||||||
|
logger.Warnf("failed to detect file index: %s", err)
|
||||||
|
} else {
|
||||||
|
logger.Warnf("no file index found")
|
||||||
|
}
|
||||||
|
} else if indexInfo.IsDir() {
|
||||||
|
logger.Warnf("file index is folder, not file: %s", fileIndexPath)
|
||||||
|
} else {
|
||||||
|
err = fileIndex.ReadFrom(fileIndexPath)
|
||||||
|
if err != nil {
|
||||||
|
logger.Infof("failed to load file index: %s", err)
|
||||||
|
} else {
|
||||||
|
indexInited = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.Infof("file index inited(%t)", indexInited)
|
||||||
|
deps.SetFileIndex(fileIndex)
|
||||||
|
|
||||||
|
return deps
|
||||||
|
}
|
||||||
|
|
||||||
|
func initDB(cfg gocfg.ICfg, filesystem fs.ISimpleFS) (db.IDBQuickshare, error) {
|
||||||
|
dbPath := cfg.GrabString("Db.DbPath")
|
||||||
|
dbDir := path.Dir(dbPath)
|
||||||
|
|
||||||
|
sqliteDB, err := sqlite.NewSQLite(path.Join(filesystem.Root(), dbPath))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create path for db: %w", err)
|
||||||
|
}
|
||||||
|
dbQuickshare, err := sqlite.NewSQLiteStore(sqliteDB)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create quickshare db: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
inited := true
|
||||||
|
_, err = filesystem.Stat(dbPath)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
|
inited = false
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("failed to stat db: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ok bool
|
||||||
|
var adminName string
|
||||||
|
var pwdHash []byte
|
||||||
|
if !inited {
|
||||||
|
err := filesystem.MkdirAll(dbDir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create path for db: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
adminName, ok = cfg.String("ENV.DEFAULTADMIN")
|
||||||
|
if !ok || adminName == "" {
|
||||||
|
fmt.Println("Please input admin name: ")
|
||||||
|
fmt.Scanf("%s", &adminName)
|
||||||
|
}
|
||||||
|
|
||||||
|
adminPwd, _ := cfg.String("ENV.DEFAULTADMINPWD")
|
||||||
|
if adminPwd == "" {
|
||||||
|
adminPwd, err = generatePwd()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("generate password error: %w", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("password is generated: %s, please update it immediately after login\n", adminPwd)
|
||||||
|
}
|
||||||
|
|
||||||
|
pwdHash, err = bcrypt.GenerateFromPassword([]byte(adminPwd), 10)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("hashing password error: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.SetString("ENV.DEFAULTADMIN", adminName)
|
||||||
|
cfg.SetString("ENV.DEFAULTADMINPWD", string(pwdHash))
|
||||||
|
|
||||||
|
siteCfg := &db.SiteConfig{
|
||||||
|
ClientCfg: &db.ClientConfig{
|
||||||
|
SiteName: cfg.StringOr("Site.ClientCfg.SiteName", "Quickshare"),
|
||||||
|
SiteDesc: cfg.StringOr("Site.ClientCfg.SiteDesc", "Quick and simple file sharing"),
|
||||||
|
Bg: &db.BgConfig{
|
||||||
|
Url: cfg.StringOr("Site.ClientCfg.Bg.Url", ""),
|
||||||
|
Repeat: cfg.StringOr("Site.ClientCfg.Bg.Repeat", "repeat"),
|
||||||
|
Position: cfg.StringOr("Site.ClientCfg.Bg.Position", "center"),
|
||||||
|
Align: cfg.StringOr("Site.ClientCfg.Bg.Align", "fixed"),
|
||||||
|
BgColor: cfg.StringOr("Site.ClientCfg.Bg.BgColor", ""),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err = dbQuickshare.Init(context.TODO(), adminName, string(pwdHash), siteCfg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to init tables: %w %s", err, dbPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dbQuickshare, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func generatePwd() (string, error) {
|
||||||
|
size := 10
|
||||||
|
buf := make([]byte, size)
|
||||||
|
size, err := rand.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("generate pwd error: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("%x", sha1.Sum(buf[:size]))[:6], nil
|
||||||
|
}
|
|
@ -3,13 +3,11 @@ package server
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/sha1"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"path"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
@ -17,25 +15,13 @@ import (
|
||||||
"github.com/gin-contrib/static"
|
"github.com/gin-contrib/static"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/ihexxa/gocfg"
|
"github.com/ihexxa/gocfg"
|
||||||
"github.com/natefinch/lumberjack"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
"go.uber.org/zap/zapcore"
|
|
||||||
"golang.org/x/crypto/bcrypt"
|
|
||||||
|
|
||||||
"github.com/ihexxa/quickshare/src/cryptoutil/jwt"
|
|
||||||
"github.com/ihexxa/quickshare/src/db"
|
|
||||||
"github.com/ihexxa/quickshare/src/db/rdb/sqlite"
|
|
||||||
"github.com/ihexxa/quickshare/src/depidx"
|
"github.com/ihexxa/quickshare/src/depidx"
|
||||||
"github.com/ihexxa/quickshare/src/fs"
|
"github.com/ihexxa/quickshare/src/fs"
|
||||||
"github.com/ihexxa/quickshare/src/fs/local"
|
|
||||||
"github.com/ihexxa/quickshare/src/handlers/fileshdr"
|
"github.com/ihexxa/quickshare/src/handlers/fileshdr"
|
||||||
"github.com/ihexxa/quickshare/src/handlers/multiusers"
|
"github.com/ihexxa/quickshare/src/handlers/multiusers"
|
||||||
"github.com/ihexxa/quickshare/src/handlers/settings"
|
"github.com/ihexxa/quickshare/src/handlers/settings"
|
||||||
"github.com/ihexxa/quickshare/src/idgen/simpleidgen"
|
|
||||||
"github.com/ihexxa/quickshare/src/iolimiter"
|
|
||||||
"github.com/ihexxa/quickshare/src/kvstore"
|
"github.com/ihexxa/quickshare/src/kvstore"
|
||||||
"github.com/ihexxa/quickshare/src/search/fileindex"
|
|
||||||
"github.com/ihexxa/quickshare/src/worker/localworker"
|
|
||||||
qsstatic "github.com/ihexxa/quickshare/static"
|
qsstatic "github.com/ihexxa/quickshare/static"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -51,8 +37,9 @@ func NewServer(cfg gocfg.ICfg) (*Server, error) {
|
||||||
gin.SetMode(gin.ReleaseMode)
|
gin.SetMode(gin.ReleaseMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
deps, adminName := initDeps(cfg)
|
deps := initDeps(cfg)
|
||||||
router := gin.Default()
|
router := gin.Default()
|
||||||
|
adminName := cfg.GrabString("ENV.DEFAULTADMIN")
|
||||||
router, err := initHandlers(router, adminName, cfg, deps)
|
router, err := initHandlers(router, adminName, cfg, deps)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("init handlers error: %w", err)
|
return nil, fmt.Errorf("init handlers error: %w", err)
|
||||||
|
@ -82,176 +69,13 @@ func NewServer(cfg gocfg.ICfg) (*Server, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func mkRoot(rootPath string) {
|
|
||||||
info, err := os.Stat(rootPath)
|
|
||||||
if err != nil {
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
err = os.MkdirAll(rootPath, 0760)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("mk root path error: %s", err))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
panic(fmt.Sprintf("stat root Path error: %s", err))
|
|
||||||
}
|
|
||||||
} else if !info.IsDir() {
|
|
||||||
panic(fmt.Sprintf("can not create %s folder: there is a file with same name", rootPath))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func initDeps(cfg gocfg.ICfg) (*depidx.Deps, string) {
|
|
||||||
var err error
|
|
||||||
logger := initLogger(cfg)
|
|
||||||
|
|
||||||
secret, ok := cfg.String("ENV.TOKENSECRET")
|
|
||||||
if !ok {
|
|
||||||
secret = makeRandToken()
|
|
||||||
logger.Info("warning: TOKENSECRET is not set, will generate token")
|
|
||||||
}
|
|
||||||
|
|
||||||
rootPath := cfg.GrabString("Fs.Root")
|
|
||||||
mkRoot(rootPath)
|
|
||||||
opensLimit := cfg.GrabInt("Fs.OpensLimit")
|
|
||||||
openTTL := cfg.GrabInt("Fs.OpenTTL")
|
|
||||||
readerTTL := cfg.GrabInt("Server.WriteTimeout") / 1000 // millisecond -> second
|
|
||||||
|
|
||||||
ider := simpleidgen.New()
|
|
||||||
filesystem := local.NewLocalFS(rootPath, 0660, opensLimit, openTTL, readerTTL, ider)
|
|
||||||
jwtEncDec := jwt.NewJWTEncDec(secret)
|
|
||||||
|
|
||||||
quickshareDb, adminName, err := initDB(cfg, filesystem)
|
|
||||||
if err != nil {
|
|
||||||
logger.Errorf("failed to init DB: %s", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
limiterCap := cfg.IntOr("Users.LimiterCapacity", 10000)
|
|
||||||
limiterCyc := cfg.IntOr("Users.LimiterCyc", 1000)
|
|
||||||
limiter := iolimiter.NewIOLimiter(limiterCap, limiterCyc, quickshareDb)
|
|
||||||
|
|
||||||
deps := depidx.NewDeps(cfg)
|
|
||||||
deps.SetDB(quickshareDb)
|
|
||||||
deps.SetFS(filesystem)
|
|
||||||
deps.SetToken(jwtEncDec)
|
|
||||||
deps.SetID(ider)
|
|
||||||
deps.SetLog(logger)
|
|
||||||
deps.SetLimiter(limiter)
|
|
||||||
|
|
||||||
queueSize := cfg.GrabInt("Workers.QueueSize")
|
|
||||||
sleepCyc := cfg.GrabInt("Workers.SleepCyc")
|
|
||||||
workerCount := cfg.GrabInt("Workers.WorkerCount")
|
|
||||||
|
|
||||||
workers := localworker.NewWorkerPool(queueSize, sleepCyc, workerCount, logger)
|
|
||||||
workers.Start()
|
|
||||||
deps.SetWorkers(workers)
|
|
||||||
|
|
||||||
searchResultLimit := cfg.GrabInt("Server.SearchResultLimit")
|
|
||||||
fileIndex := fileindex.NewFileTreeIndex(filesystem, "/", searchResultLimit)
|
|
||||||
indexInfo, err := filesystem.Stat(fileIndexPath)
|
|
||||||
indexInited := false
|
|
||||||
if err != nil {
|
|
||||||
if !os.IsNotExist(err) {
|
|
||||||
logger.Warnf("failed to detect file index: %s", err)
|
|
||||||
} else {
|
|
||||||
logger.Warnf("no file index found")
|
|
||||||
}
|
|
||||||
} else if indexInfo.IsDir() {
|
|
||||||
logger.Warnf("file index is folder, not file: %s", fileIndexPath)
|
|
||||||
} else {
|
|
||||||
err = fileIndex.ReadFrom(fileIndexPath)
|
|
||||||
if err != nil {
|
|
||||||
logger.Infof("failed to load file index: %s", err)
|
|
||||||
} else {
|
|
||||||
indexInited = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logger.Infof("file index inited(%t)", indexInited)
|
|
||||||
deps.SetFileIndex(fileIndex)
|
|
||||||
|
|
||||||
return deps, adminName
|
|
||||||
}
|
|
||||||
|
|
||||||
func initDB(cfg gocfg.ICfg, filesystem fs.ISimpleFS) (db.IDBQuickshare, string, error) {
|
|
||||||
dbPath := cfg.GrabString("Db.DbPath")
|
|
||||||
dbDir := path.Dir(dbPath)
|
|
||||||
|
|
||||||
err := filesystem.MkdirAll(dbDir)
|
|
||||||
if err != nil {
|
|
||||||
return nil, "", fmt.Errorf("failed to create path for db: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
inited := true
|
|
||||||
_, err = filesystem.Stat(dbPath)
|
|
||||||
if err != nil {
|
|
||||||
if errors.Is(err, os.ErrNotExist) {
|
|
||||||
inited = false
|
|
||||||
} else {
|
|
||||||
return nil, "", fmt.Errorf("failed to stat db: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sqliteDB, err := sqlite.NewSQLite(path.Join(filesystem.Root(), dbPath))
|
|
||||||
if err != nil {
|
|
||||||
return nil, "", fmt.Errorf("failed to create path for db: %w", err)
|
|
||||||
}
|
|
||||||
dbQuickshare, err := sqlite.NewSQLiteStore(sqliteDB)
|
|
||||||
if err != nil {
|
|
||||||
return nil, "", fmt.Errorf("failed to create quickshare db: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var ok bool
|
|
||||||
var adminName string
|
|
||||||
var pwdHash []byte
|
|
||||||
if !inited && cfg.BoolOr("Users.EnableAuth", true) {
|
|
||||||
adminName, ok = cfg.String("ENV.DEFAULTADMIN")
|
|
||||||
if !ok || adminName == "" {
|
|
||||||
fmt.Println("Please input admin name: ")
|
|
||||||
fmt.Scanf("%s", &adminName)
|
|
||||||
}
|
|
||||||
|
|
||||||
adminPwd, _ := cfg.String("ENV.DEFAULTADMINPWD")
|
|
||||||
if adminPwd == "" {
|
|
||||||
adminPwd, err = generatePwd()
|
|
||||||
if err != nil {
|
|
||||||
return nil, "", fmt.Errorf("generate password error: %w", err)
|
|
||||||
}
|
|
||||||
fmt.Printf("password is generated: %s, please update it immediately after login\n", adminPwd)
|
|
||||||
}
|
|
||||||
|
|
||||||
pwdHash, err = bcrypt.GenerateFromPassword([]byte(adminPwd), 10)
|
|
||||||
if err != nil {
|
|
||||||
return nil, "", fmt.Errorf("hashing password error: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !inited {
|
|
||||||
siteCfg := &db.SiteConfig{
|
|
||||||
ClientCfg: &db.ClientConfig{
|
|
||||||
SiteName: cfg.StringOr("Site.ClientCfg.SiteName", "Quickshare"),
|
|
||||||
SiteDesc: cfg.StringOr("Site.ClientCfg.SiteDesc", "Quick and simple file sharing"),
|
|
||||||
Bg: &db.BgConfig{
|
|
||||||
Url: cfg.StringOr("Site.ClientCfg.Bg.Url", ""),
|
|
||||||
Repeat: cfg.StringOr("Site.ClientCfg.Bg.Repeat", "repeat"),
|
|
||||||
Position: cfg.StringOr("Site.ClientCfg.Bg.Position", "center"),
|
|
||||||
Align: cfg.StringOr("Site.ClientCfg.Bg.Align", "fixed"),
|
|
||||||
BgColor: cfg.StringOr("Site.ClientCfg.Bg.BgColor", ""),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
err = dbQuickshare.Init(context.TODO(), adminName, string(pwdHash), siteCfg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, "", fmt.Errorf("failed to init tables: %w %s", err, dbPath)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return dbQuickshare, adminName, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func initHandlers(router *gin.Engine, adminName string, cfg gocfg.ICfg, deps *depidx.Deps) (*gin.Engine, error) {
|
func initHandlers(router *gin.Engine, adminName string, cfg gocfg.ICfg, deps *depidx.Deps) (*gin.Engine, error) {
|
||||||
// handlers
|
// handlers
|
||||||
userHdrs, err := multiusers.NewMultiUsersSvc(cfg, deps)
|
userHdrs, err := multiusers.NewMultiUsersSvc(cfg, deps)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("new users svc error: %w", err)
|
return nil, fmt.Errorf("new users svc error: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = userHdrs.Init(context.TODO(), adminName)
|
_, err = userHdrs.Init(context.TODO(), adminName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to init user handlers: %w", err)
|
return nil, fmt.Errorf("failed to init user handlers: %w", err)
|
||||||
|
@ -277,11 +101,11 @@ func initHandlers(router *gin.Engine, adminName string, cfg gocfg.ICfg, deps *de
|
||||||
if cfg.BoolOr("Server.Debug", false) {
|
if cfg.BoolOr("Server.Debug", false) {
|
||||||
router.Use(static.Serve("/", static.LocalFile(publicPath, false)))
|
router.Use(static.Serve("/", static.LocalFile(publicPath, false)))
|
||||||
} else {
|
} else {
|
||||||
esFS, err := qsstatic.NewEmbedStaticFS()
|
embedFs, err := qsstatic.NewEmbedStaticFS()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
router.Use(static.Serve("/", esFS))
|
router.Use(static.Serve("/", embedFs))
|
||||||
}
|
}
|
||||||
|
|
||||||
// handlers
|
// handlers
|
||||||
|
@ -350,25 +174,6 @@ func initHandlers(router *gin.Engine, adminName string, cfg gocfg.ICfg, deps *de
|
||||||
return router, nil
|
return router, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func initLogger(cfg gocfg.ICfg) *zap.SugaredLogger {
|
|
||||||
fileWriter := zapcore.AddSync(&lumberjack.Logger{
|
|
||||||
Filename: path.Join(cfg.GrabString("Fs.Root"), "quickshare.log"),
|
|
||||||
MaxSize: cfg.IntOr("Log.MaxSize", 50), // megabytes
|
|
||||||
MaxBackups: cfg.IntOr("Log.MaxBackups", 2),
|
|
||||||
MaxAge: cfg.IntOr("Log.MaxAge", 31), // days
|
|
||||||
})
|
|
||||||
stdoutWriter := zapcore.AddSync(os.Stdout)
|
|
||||||
|
|
||||||
multiWriter := zapcore.NewMultiWriteSyncer(fileWriter, stdoutWriter)
|
|
||||||
gin.DefaultWriter = multiWriter
|
|
||||||
core := zapcore.NewCore(
|
|
||||||
zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
|
|
||||||
multiWriter,
|
|
||||||
zap.InfoLevel,
|
|
||||||
)
|
|
||||||
return zap.New(core).Sugar()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) Start() error {
|
func (s *Server) Start() error {
|
||||||
s.signalChan = make(chan os.Signal, 4)
|
s.signalChan = make(chan os.Signal, 4)
|
||||||
signal.Notify(s.signalChan, syscall.SIGINT, syscall.SIGTERM)
|
signal.Notify(s.signalChan, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
@ -430,23 +235,3 @@ func (s *Server) depsFS() fs.ISimpleFS {
|
||||||
func (s *Server) depsKVStore() kvstore.IKVStore {
|
func (s *Server) depsKVStore() kvstore.IKVStore {
|
||||||
return s.deps.KV()
|
return s.deps.KV()
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeRandToken() string {
|
|
||||||
b := make([]byte, 32)
|
|
||||||
_, err := rand.Read(b)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("make rand token error: %s", err))
|
|
||||||
}
|
|
||||||
return string(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func generatePwd() (string, error) {
|
|
||||||
size := 10
|
|
||||||
buf := make([]byte, size)
|
|
||||||
size, err := rand.Read(buf)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("generate pwd error: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("%x", sha1.Sum(buf[:size]))[:6], nil
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue