mirror of https://github.com/Xhofe/alist
parent
f2727095d9
commit
74f8295960
2
go.mod
2
go.mod
|
@ -55,7 +55,7 @@ require (
|
|||
github.com/u2takey/ffmpeg-go v0.5.0
|
||||
github.com/upyun/go-sdk/v3 v3.0.4
|
||||
github.com/winfsp/cgofuse v1.5.1-0.20230130140708-f87f5db493b5
|
||||
github.com/xhofe/tache v0.1.1
|
||||
github.com/xhofe/tache v0.1.2
|
||||
github.com/xhofe/wopan-sdk-go v0.1.3
|
||||
github.com/zzzhr1990/go-common-entity v0.0.0-20221216044934-fd1c571e3a22
|
||||
golang.org/x/crypto v0.25.0
|
||||
|
|
2
go.sum
2
go.sum
|
@ -506,6 +506,8 @@ github.com/xhofe/gsync v0.0.0-20230917091818-2111ceb38a25 h1:eDfebW/yfq9DtG9RO3K
|
|||
github.com/xhofe/gsync v0.0.0-20230917091818-2111ceb38a25/go.mod h1:fH4oNm5F9NfI5dLi0oIMtsLNKQOirUDbEMCIBb/7SU0=
|
||||
github.com/xhofe/tache v0.1.1 h1:O5QY4cVjIGELx3UGh6LbVAc18MWGXgRNQjMt72x6w/8=
|
||||
github.com/xhofe/tache v0.1.1/go.mod h1:iKumPFvywf30FRpAHHCt64G0JHLMzT0K+wyGedHsmTQ=
|
||||
github.com/xhofe/tache v0.1.2 h1:pHrXlrWcbTb4G7hVUDW7Rc+YTUnLJvnLBrdktVE1Fqg=
|
||||
github.com/xhofe/tache v0.1.2/go.mod h1:iKumPFvywf30FRpAHHCt64G0JHLMzT0K+wyGedHsmTQ=
|
||||
github.com/xhofe/wopan-sdk-go v0.1.3 h1:J58X6v+n25ewBZjb05pKOr7AWGohb+Rdll4CThGh6+A=
|
||||
github.com/xhofe/wopan-sdk-go v0.1.3/go.mod h1:dcY9yA28fnaoZPnXZiVTFSkcd7GnIPTpTIIlfSI5z5Q=
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
||||
|
|
|
@ -68,11 +68,7 @@ func InitConfig() {
|
|||
}
|
||||
conf.Conf.TempDir = absPath
|
||||
}
|
||||
err := os.RemoveAll(filepath.Join(conf.Conf.TempDir))
|
||||
if err != nil {
|
||||
log.Errorln("failed delete temp file:", err)
|
||||
}
|
||||
err = os.MkdirAll(conf.Conf.TempDir, 0o777)
|
||||
err := os.MkdirAll(conf.Conf.TempDir, 0o777)
|
||||
if err != nil {
|
||||
log.Fatalf("create temp dir error: %+v", err)
|
||||
}
|
||||
|
@ -104,3 +100,9 @@ func initURL() {
|
|||
}
|
||||
conf.URL = u
|
||||
}
|
||||
|
||||
func CleanTempDir() {
|
||||
if err := os.RemoveAll(conf.Conf.TempDir); err != nil {
|
||||
log.Errorln("failed delete temp file: ", err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import "github.com/alist-org/alist/v3/cmd/flags"
|
|||
func InitData() {
|
||||
initUser()
|
||||
initSettings()
|
||||
initTasks()
|
||||
if flags.Dev {
|
||||
initDevData()
|
||||
initDevDo()
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
package data
|
||||
|
||||
import (
|
||||
"github.com/alist-org/alist/v3/internal/db"
|
||||
"github.com/alist-org/alist/v3/internal/model"
|
||||
)
|
||||
|
||||
var initialTaskItems []model.TaskItem
|
||||
|
||||
func initTasks() {
|
||||
InitialTasks()
|
||||
|
||||
for i := range initialTaskItems {
|
||||
item := &initialTaskItems[i]
|
||||
taskitem, _ := db.GetTaskDataByType(item.Key)
|
||||
if taskitem == nil {
|
||||
db.CreateTaskData(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func InitialTasks() []model.TaskItem {
|
||||
initialTaskItems = []model.TaskItem{
|
||||
{Key: "copy", PersistData: "[]"},
|
||||
{Key: "download", PersistData: "[]"},
|
||||
{Key: "transfer", PersistData: "[]"},
|
||||
}
|
||||
return initialTaskItems
|
||||
}
|
|
@ -2,14 +2,18 @@ package bootstrap
|
|||
|
||||
import (
|
||||
"github.com/alist-org/alist/v3/internal/conf"
|
||||
"github.com/alist-org/alist/v3/internal/db"
|
||||
"github.com/alist-org/alist/v3/internal/fs"
|
||||
"github.com/alist-org/alist/v3/internal/offline_download/tool"
|
||||
"github.com/xhofe/tache"
|
||||
)
|
||||
|
||||
func InitTaskManager() {
|
||||
fs.UploadTaskManager = tache.NewManager[*fs.UploadTask](tache.WithWorks(conf.Conf.Tasks.Upload.Workers), tache.WithMaxRetry(conf.Conf.Tasks.Upload.MaxRetry))
|
||||
fs.CopyTaskManager = tache.NewManager[*fs.CopyTask](tache.WithWorks(conf.Conf.Tasks.Copy.Workers), tache.WithMaxRetry(conf.Conf.Tasks.Copy.MaxRetry))
|
||||
tool.DownloadTaskManager = tache.NewManager[*tool.DownloadTask](tache.WithWorks(conf.Conf.Tasks.Download.Workers), tache.WithMaxRetry(conf.Conf.Tasks.Download.MaxRetry))
|
||||
tool.TransferTaskManager = tache.NewManager[*tool.TransferTask](tache.WithWorks(conf.Conf.Tasks.Transfer.Workers), tache.WithMaxRetry(conf.Conf.Tasks.Transfer.MaxRetry))
|
||||
fs.UploadTaskManager = tache.NewManager[*fs.UploadTask](tache.WithWorks(conf.Conf.Tasks.Upload.Workers), tache.WithMaxRetry(conf.Conf.Tasks.Upload.MaxRetry)) //upload will not support persist
|
||||
fs.CopyTaskManager = tache.NewManager[*fs.CopyTask](tache.WithWorks(conf.Conf.Tasks.Copy.Workers), tache.WithPersistFunction(db.GetTaskDataFunc("copy", conf.Conf.Tasks.Copy.TaskPersistant), db.UpdateTaskDataFunc("copy", conf.Conf.Tasks.Copy.TaskPersistant)), tache.WithMaxRetry(conf.Conf.Tasks.Copy.MaxRetry))
|
||||
tool.DownloadTaskManager = tache.NewManager[*tool.DownloadTask](tache.WithWorks(conf.Conf.Tasks.Download.Workers), tache.WithPersistFunction(db.GetTaskDataFunc("download", conf.Conf.Tasks.Download.TaskPersistant), db.UpdateTaskDataFunc("download", conf.Conf.Tasks.Download.TaskPersistant)), tache.WithMaxRetry(conf.Conf.Tasks.Download.MaxRetry))
|
||||
tool.TransferTaskManager = tache.NewManager[*tool.TransferTask](tache.WithWorks(conf.Conf.Tasks.Transfer.Workers), tache.WithPersistFunction(db.GetTaskDataFunc("transfer", conf.Conf.Tasks.Transfer.TaskPersistant), db.UpdateTaskDataFunc("transfer", conf.Conf.Tasks.Transfer.TaskPersistant)), tache.WithMaxRetry(conf.Conf.Tasks.Transfer.MaxRetry))
|
||||
if len(tool.TransferTaskManager.GetAll()) == 0 { //prevent offline downloaded files from being deleted
|
||||
CleanTempDir()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,8 +47,9 @@ type LogConfig struct {
|
|||
}
|
||||
|
||||
type TaskConfig struct {
|
||||
Workers int `json:"workers" env:"WORKERS"`
|
||||
MaxRetry int `json:"max_retry" env:"MAX_RETRY"`
|
||||
Workers int `json:"workers" env:"WORKERS"`
|
||||
MaxRetry int `json:"max_retry" env:"MAX_RETRY"`
|
||||
TaskPersistant bool `json:"task_persistant" env:"TASK_PERSISTANT"`
|
||||
}
|
||||
|
||||
type TasksConfig struct {
|
||||
|
@ -130,19 +131,22 @@ func DefaultConfig() *Config {
|
|||
TlsInsecureSkipVerify: true,
|
||||
Tasks: TasksConfig{
|
||||
Download: TaskConfig{
|
||||
Workers: 5,
|
||||
MaxRetry: 1,
|
||||
Workers: 5,
|
||||
MaxRetry: 1,
|
||||
TaskPersistant: true,
|
||||
},
|
||||
Transfer: TaskConfig{
|
||||
Workers: 5,
|
||||
MaxRetry: 2,
|
||||
Workers: 5,
|
||||
MaxRetry: 2,
|
||||
TaskPersistant: true,
|
||||
},
|
||||
Upload: TaskConfig{
|
||||
Workers: 5,
|
||||
},
|
||||
Copy: TaskConfig{
|
||||
Workers: 5,
|
||||
MaxRetry: 2,
|
||||
Workers: 5,
|
||||
MaxRetry: 2,
|
||||
TaskPersistant: true,
|
||||
},
|
||||
},
|
||||
Cors: Cors{
|
||||
|
|
|
@ -12,7 +12,7 @@ var db *gorm.DB
|
|||
|
||||
func Init(d *gorm.DB) {
|
||||
db = d
|
||||
err := AutoMigrate(new(model.Storage), new(model.User), new(model.Meta), new(model.SettingItem), new(model.SearchNode))
|
||||
err := AutoMigrate(new(model.Storage), new(model.User), new(model.Meta), new(model.SettingItem), new(model.SearchNode), new(model.TaskItem))
|
||||
if err != nil {
|
||||
log.Fatalf("failed migrate database: %s", err.Error())
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
package db
|
||||
|
||||
import (
|
||||
"github.com/alist-org/alist/v3/internal/model"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func GetTaskDataByType(type_s string) (*model.TaskItem, error) {
|
||||
task := model.TaskItem{Key: type_s}
|
||||
if err := db.Where(task).First(&task).Error; err != nil {
|
||||
return nil, errors.Wrapf(err, "failed find task")
|
||||
}
|
||||
return &task, nil
|
||||
}
|
||||
|
||||
func UpdateTaskData(t *model.TaskItem) error {
|
||||
return errors.WithStack(db.Model(&model.TaskItem{}).Where("key = ?", t.Key).Update("persist_data", t.PersistData).Error)
|
||||
}
|
||||
|
||||
func CreateTaskData(t *model.TaskItem) error {
|
||||
return errors.WithStack(db.Create(t).Error)
|
||||
}
|
||||
|
||||
func GetTaskDataFunc(type_s string, enabled bool) func() ([]byte, error) {
|
||||
if !enabled {
|
||||
return nil
|
||||
}
|
||||
task, err := GetTaskDataByType(type_s)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return func() ([]byte, error) {
|
||||
return []byte(task.PersistData), nil
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateTaskDataFunc(type_s string, enabled bool) func([]byte) error {
|
||||
if !enabled {
|
||||
return nil
|
||||
}
|
||||
return func(data []byte) error {
|
||||
s := string(data)
|
||||
if s == "null" || s == "" {
|
||||
s = "[]"
|
||||
}
|
||||
return UpdateTaskData(&model.TaskItem{Key: type_s, PersistData: s})
|
||||
}
|
||||
}
|
|
@ -3,6 +3,9 @@ package fs
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
stdpath "path"
|
||||
|
||||
"github.com/alist-org/alist/v3/internal/conf"
|
||||
"github.com/alist-org/alist/v3/internal/driver"
|
||||
"github.com/alist-org/alist/v3/internal/model"
|
||||
|
@ -11,20 +14,21 @@ import (
|
|||
"github.com/alist-org/alist/v3/pkg/utils"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/xhofe/tache"
|
||||
"net/http"
|
||||
stdpath "path"
|
||||
)
|
||||
|
||||
type CopyTask struct {
|
||||
tache.Base
|
||||
Status string `json:"status"`
|
||||
srcStorage, dstStorage driver.Driver
|
||||
srcObjPath, dstDirPath string
|
||||
Status string `json:"-"` //don't save status to save space
|
||||
SrcObjPath string `json:"src_path"`
|
||||
DstDirPath string `json:"dst_path"`
|
||||
srcStorage driver.Driver `json:"-"`
|
||||
dstStorage driver.Driver `json:"-"`
|
||||
SrcStorageMp string `json:"src_storage_mp"`
|
||||
DstStorageMp string `json:"dst_storage_mp"`
|
||||
}
|
||||
|
||||
func (t *CopyTask) GetName() string {
|
||||
return fmt.Sprintf("copy [%s](%s) to [%s](%s)",
|
||||
t.srcStorage.GetStorage().MountPath, t.srcObjPath, t.dstStorage.GetStorage().MountPath, t.dstDirPath)
|
||||
return fmt.Sprintf("copy [%s](%s) to [%s](%s)", t.SrcStorageMp, t.SrcObjPath, t.DstStorageMp, t.DstDirPath)
|
||||
}
|
||||
|
||||
func (t *CopyTask) GetStatus() string {
|
||||
|
@ -32,7 +36,17 @@ func (t *CopyTask) GetStatus() string {
|
|||
}
|
||||
|
||||
func (t *CopyTask) Run() error {
|
||||
return copyBetween2Storages(t, t.srcStorage, t.dstStorage, t.srcObjPath, t.dstDirPath)
|
||||
var err error
|
||||
if t.srcStorage == nil {
|
||||
t.srcStorage, err = op.GetStorageByMountPath(t.SrcStorageMp)
|
||||
}
|
||||
if t.dstStorage == nil {
|
||||
t.dstStorage, err = op.GetStorageByMountPath(t.DstStorageMp)
|
||||
}
|
||||
if err != nil {
|
||||
return errors.WithMessage(err, "failed get storage")
|
||||
}
|
||||
return copyBetween2Storages(t, t.srcStorage, t.dstStorage, t.SrcObjPath, t.DstDirPath)
|
||||
}
|
||||
|
||||
var CopyTaskManager *tache.Manager[*CopyTask]
|
||||
|
@ -79,10 +93,12 @@ func _copy(ctx context.Context, srcObjPath, dstDirPath string, lazyCache ...bool
|
|||
}
|
||||
// not in the same storage
|
||||
t := &CopyTask{
|
||||
srcStorage: srcStorage,
|
||||
dstStorage: dstStorage,
|
||||
srcObjPath: srcObjActualPath,
|
||||
dstDirPath: dstDirActualPath,
|
||||
srcStorage: srcStorage,
|
||||
dstStorage: dstStorage,
|
||||
SrcObjPath: srcObjActualPath,
|
||||
DstDirPath: dstDirActualPath,
|
||||
SrcStorageMp: srcStorage.GetStorage().MountPath,
|
||||
DstStorageMp: dstStorage.GetStorage().MountPath,
|
||||
}
|
||||
CopyTaskManager.Add(t)
|
||||
return t, nil
|
||||
|
@ -107,10 +123,12 @@ func copyBetween2Storages(t *CopyTask, srcStorage, dstStorage driver.Driver, src
|
|||
srcObjPath := stdpath.Join(srcObjPath, obj.GetName())
|
||||
dstObjPath := stdpath.Join(dstDirPath, srcObj.GetName())
|
||||
CopyTaskManager.Add(&CopyTask{
|
||||
srcStorage: srcStorage,
|
||||
dstStorage: dstStorage,
|
||||
srcObjPath: srcObjPath,
|
||||
dstDirPath: dstObjPath,
|
||||
srcStorage: srcStorage,
|
||||
dstStorage: dstStorage,
|
||||
SrcObjPath: srcObjPath,
|
||||
DstDirPath: dstObjPath,
|
||||
SrcStorageMp: srcStorage.GetStorage().MountPath,
|
||||
DstStorageMp: dstStorage.GetStorage().MountPath,
|
||||
})
|
||||
}
|
||||
t.Status = "src object is dir, added all copy tasks of objs"
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package model
|
||||
|
||||
type TaskItem struct {
|
||||
Key string `json:"key"`
|
||||
PersistData string `gorm:"type:text" json:"persist_data"`
|
||||
}
|
|
@ -76,6 +76,7 @@ func AddURL(ctx context.Context, args *AddURLArgs) (tache.TaskWithInfo, error) {
|
|||
DstDirPath: args.DstDirPath,
|
||||
TempDir: tempDir,
|
||||
DeletePolicy: deletePolicy,
|
||||
Toolname: args.Tool,
|
||||
tool: tool,
|
||||
}
|
||||
DownloadTaskManager.Add(t)
|
||||
|
|
|
@ -14,19 +14,26 @@ import (
|
|||
|
||||
type DownloadTask struct {
|
||||
tache.Base
|
||||
Url string `json:"url"`
|
||||
DstDirPath string `json:"dst_dir_path"`
|
||||
TempDir string `json:"temp_dir"`
|
||||
DeletePolicy DeletePolicy `json:"delete_policy"`
|
||||
|
||||
Status string `json:"status"`
|
||||
Signal chan int `json:"-"`
|
||||
GID string `json:"-"`
|
||||
Url string `json:"url"`
|
||||
DstDirPath string `json:"dst_dir_path"`
|
||||
TempDir string `json:"temp_dir"`
|
||||
DeletePolicy DeletePolicy `json:"delete_policy"`
|
||||
Toolname string `json:"toolname"`
|
||||
Status string `json:"-"`
|
||||
Signal chan int `json:"-"`
|
||||
GID string `json:"-"`
|
||||
tool Tool
|
||||
callStatusRetried int
|
||||
}
|
||||
|
||||
func (t *DownloadTask) Run() error {
|
||||
if t.tool == nil {
|
||||
tool, err := Tools.Get(t.Toolname)
|
||||
if err != nil {
|
||||
return errors.WithMessage(err, "failed get tool")
|
||||
}
|
||||
t.tool = tool
|
||||
}
|
||||
if err := t.tool.Run(t); !errs.IsNotSupportError(err) {
|
||||
if err == nil {
|
||||
return t.Complete()
|
||||
|
@ -142,9 +149,10 @@ func (t *DownloadTask) Complete() error {
|
|||
file := files[i]
|
||||
TransferTaskManager.Add(&TransferTask{
|
||||
file: file,
|
||||
dstDirPath: t.DstDirPath,
|
||||
tempDir: t.TempDir,
|
||||
deletePolicy: t.DeletePolicy,
|
||||
DstDirPath: t.DstDirPath,
|
||||
TempDir: t.TempDir,
|
||||
DeletePolicy: t.DeletePolicy,
|
||||
FileDir: file.Path,
|
||||
})
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -2,6 +2,9 @@ package tool
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/alist-org/alist/v3/internal/model"
|
||||
"github.com/alist-org/alist/v3/internal/op"
|
||||
"github.com/alist-org/alist/v3/internal/stream"
|
||||
|
@ -9,21 +12,27 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/xhofe/tache"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
type TransferTask struct {
|
||||
tache.Base
|
||||
FileDir string `json:"file_dir"`
|
||||
DstDirPath string `json:"dst_dir_path"`
|
||||
TempDir string `json:"temp_dir"`
|
||||
DeletePolicy DeletePolicy `json:"delete_policy"`
|
||||
file File
|
||||
dstDirPath string
|
||||
tempDir string
|
||||
deletePolicy DeletePolicy
|
||||
}
|
||||
|
||||
func (t *TransferTask) Run() error {
|
||||
// check dstDir again
|
||||
storage, dstDirActualPath, err := op.GetStorageAndActualPath(t.dstDirPath)
|
||||
var err error
|
||||
if (t.file == File{}) {
|
||||
t.file, err = GetFile(t.FileDir)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to get file %s", t.FileDir)
|
||||
}
|
||||
}
|
||||
storage, dstDirActualPath, err := op.GetStorageAndActualPath(t.DstDirPath)
|
||||
if err != nil {
|
||||
return errors.WithMessage(err, "failed get storage")
|
||||
}
|
||||
|
@ -44,7 +53,7 @@ func (t *TransferTask) Run() error {
|
|||
Mimetype: mimetype,
|
||||
Closers: utils.NewClosers(rc),
|
||||
}
|
||||
relDir, err := filepath.Rel(t.tempDir, filepath.Dir(t.file.Path))
|
||||
relDir, err := filepath.Rel(t.TempDir, filepath.Dir(t.file.Path))
|
||||
if err != nil {
|
||||
log.Errorf("find relation directory error: %v", err)
|
||||
}
|
||||
|
@ -53,7 +62,7 @@ func (t *TransferTask) Run() error {
|
|||
}
|
||||
|
||||
func (t *TransferTask) GetName() string {
|
||||
return fmt.Sprintf("transfer %s to [%s]", t.file.Path, t.dstDirPath)
|
||||
return fmt.Sprintf("transfer %s to [%s]", t.file.Path, t.DstDirPath)
|
||||
}
|
||||
|
||||
func (t *TransferTask) GetStatus() string {
|
||||
|
@ -61,7 +70,7 @@ func (t *TransferTask) GetStatus() string {
|
|||
}
|
||||
|
||||
func (t *TransferTask) OnSucceeded() {
|
||||
if t.deletePolicy == DeleteOnUploadSucceed || t.deletePolicy == DeleteAlways {
|
||||
if t.DeletePolicy == DeleteOnUploadSucceed || t.DeletePolicy == DeleteAlways {
|
||||
err := os.Remove(t.file.Path)
|
||||
if err != nil {
|
||||
log.Errorf("failed to delete file %s, error: %s", t.file.Path, err.Error())
|
||||
|
@ -70,7 +79,7 @@ func (t *TransferTask) OnSucceeded() {
|
|||
}
|
||||
|
||||
func (t *TransferTask) OnFailed() {
|
||||
if t.deletePolicy == DeleteOnUploadFailed || t.deletePolicy == DeleteAlways {
|
||||
if t.DeletePolicy == DeleteOnUploadFailed || t.DeletePolicy == DeleteAlways {
|
||||
err := os.Remove(t.file.Path)
|
||||
if err != nil {
|
||||
log.Errorf("failed to delete file %s, error: %s", t.file.Path, err.Error())
|
||||
|
|
|
@ -26,3 +26,16 @@ func GetFiles(dir string) ([]File, error) {
|
|||
}
|
||||
return files, nil
|
||||
}
|
||||
|
||||
func GetFile(path string) (File, error) {
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return File{}, err
|
||||
}
|
||||
return File{
|
||||
Name: info.Name(),
|
||||
Size: info.Size(),
|
||||
Path: path,
|
||||
Modified: info.ModTime(),
|
||||
}, nil
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue