mirror of https://github.com/Xhofe/alist
feat: add task info to resp of add task api (close #5579)
parent
8bdfc7ac8e
commit
026e944cbb
|
@ -39,23 +39,23 @@ var CopyTaskManager *tache.Manager[*CopyTask]
|
||||||
|
|
||||||
// Copy if in the same storage, call move method
|
// Copy if in the same storage, call move method
|
||||||
// if not, add copy task
|
// if not, add copy task
|
||||||
func _copy(ctx context.Context, srcObjPath, dstDirPath string, lazyCache ...bool) (bool, error) {
|
func _copy(ctx context.Context, srcObjPath, dstDirPath string, lazyCache ...bool) (tache.TaskWithInfo, error) {
|
||||||
srcStorage, srcObjActualPath, err := op.GetStorageAndActualPath(srcObjPath)
|
srcStorage, srcObjActualPath, err := op.GetStorageAndActualPath(srcObjPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, errors.WithMessage(err, "failed get src storage")
|
return nil, errors.WithMessage(err, "failed get src storage")
|
||||||
}
|
}
|
||||||
dstStorage, dstDirActualPath, err := op.GetStorageAndActualPath(dstDirPath)
|
dstStorage, dstDirActualPath, err := op.GetStorageAndActualPath(dstDirPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, errors.WithMessage(err, "failed get dst storage")
|
return nil, errors.WithMessage(err, "failed get dst storage")
|
||||||
}
|
}
|
||||||
// copy if in the same storage, just call driver.Copy
|
// copy if in the same storage, just call driver.Copy
|
||||||
if srcStorage.GetStorage() == dstStorage.GetStorage() {
|
if srcStorage.GetStorage() == dstStorage.GetStorage() {
|
||||||
return false, op.Copy(ctx, srcStorage, srcObjActualPath, dstDirActualPath, lazyCache...)
|
return nil, op.Copy(ctx, srcStorage, srcObjActualPath, dstDirActualPath, lazyCache...)
|
||||||
}
|
}
|
||||||
if ctx.Value(conf.NoTaskKey) != nil {
|
if ctx.Value(conf.NoTaskKey) != nil {
|
||||||
srcObj, err := op.Get(ctx, srcStorage, srcObjActualPath)
|
srcObj, err := op.Get(ctx, srcStorage, srcObjActualPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, errors.WithMessagef(err, "failed get src [%s] file", srcObjPath)
|
return nil, errors.WithMessagef(err, "failed get src [%s] file", srcObjPath)
|
||||||
}
|
}
|
||||||
if !srcObj.IsDir() {
|
if !srcObj.IsDir() {
|
||||||
// copy file directly
|
// copy file directly
|
||||||
|
@ -63,7 +63,7 @@ func _copy(ctx context.Context, srcObjPath, dstDirPath string, lazyCache ...bool
|
||||||
Header: http.Header{},
|
Header: http.Header{},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, errors.WithMessagef(err, "failed get [%s] link", srcObjPath)
|
return nil, errors.WithMessagef(err, "failed get [%s] link", srcObjPath)
|
||||||
}
|
}
|
||||||
fs := stream.FileStream{
|
fs := stream.FileStream{
|
||||||
Obj: srcObj,
|
Obj: srcObj,
|
||||||
|
@ -72,19 +72,20 @@ func _copy(ctx context.Context, srcObjPath, dstDirPath string, lazyCache ...bool
|
||||||
// any link provided is seekable
|
// any link provided is seekable
|
||||||
ss, err := stream.NewSeekableStream(fs, link)
|
ss, err := stream.NewSeekableStream(fs, link)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, errors.WithMessagef(err, "failed get [%s] stream", srcObjPath)
|
return nil, errors.WithMessagef(err, "failed get [%s] stream", srcObjPath)
|
||||||
}
|
}
|
||||||
return false, op.Put(ctx, dstStorage, dstDirActualPath, ss, nil, false)
|
return nil, op.Put(ctx, dstStorage, dstDirActualPath, ss, nil, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// not in the same storage
|
// not in the same storage
|
||||||
CopyTaskManager.Add(&CopyTask{
|
t := &CopyTask{
|
||||||
srcStorage: srcStorage,
|
srcStorage: srcStorage,
|
||||||
dstStorage: dstStorage,
|
dstStorage: dstStorage,
|
||||||
srcObjPath: srcObjActualPath,
|
srcObjPath: srcObjActualPath,
|
||||||
dstDirPath: dstDirActualPath,
|
dstDirPath: dstDirActualPath,
|
||||||
})
|
}
|
||||||
return true, nil
|
CopyTaskManager.Add(t)
|
||||||
|
return t, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyBetween2Storages(t *CopyTask, srcStorage, dstStorage driver.Driver, srcObjPath, dstDirPath string) error {
|
func copyBetween2Storages(t *CopyTask, srcStorage, dstStorage driver.Driver, srcObjPath, dstDirPath string) error {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"github.com/alist-org/alist/v3/internal/model"
|
"github.com/alist-org/alist/v3/internal/model"
|
||||||
"github.com/alist-org/alist/v3/internal/op"
|
"github.com/alist-org/alist/v3/internal/op"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
"github.com/xhofe/tache"
|
||||||
)
|
)
|
||||||
|
|
||||||
// the param named path of functions in this package is a mount path
|
// the param named path of functions in this package is a mount path
|
||||||
|
@ -68,7 +69,7 @@ func Move(ctx context.Context, srcPath, dstDirPath string, lazyCache ...bool) er
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func Copy(ctx context.Context, srcObjPath, dstDirPath string, lazyCache ...bool) (bool, error) {
|
func Copy(ctx context.Context, srcObjPath, dstDirPath string, lazyCache ...bool) (tache.TaskWithInfo, error) {
|
||||||
res, err := _copy(ctx, srcObjPath, dstDirPath, lazyCache...)
|
res, err := _copy(ctx, srcObjPath, dstDirPath, lazyCache...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed copy %s to %s: %+v", srcObjPath, dstDirPath, err)
|
log.Errorf("failed copy %s to %s: %+v", srcObjPath, dstDirPath, err)
|
||||||
|
@ -100,12 +101,12 @@ func PutDirectly(ctx context.Context, dstDirPath string, file model.FileStreamer
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func PutAsTask(dstDirPath string, file model.FileStreamer) error {
|
func PutAsTask(dstDirPath string, file model.FileStreamer) (tache.TaskWithInfo, error) {
|
||||||
err := putAsTask(dstDirPath, file)
|
t, err := putAsTask(dstDirPath, file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed put %s: %+v", dstDirPath, err)
|
log.Errorf("failed put %s: %+v", dstDirPath, err)
|
||||||
}
|
}
|
||||||
return err
|
return t, err
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetStoragesArgs struct {
|
type GetStoragesArgs struct {
|
||||||
|
|
|
@ -33,28 +33,29 @@ func (t *UploadTask) Run() error {
|
||||||
var UploadTaskManager *tache.Manager[*UploadTask]
|
var UploadTaskManager *tache.Manager[*UploadTask]
|
||||||
|
|
||||||
// putAsTask add as a put task and return immediately
|
// putAsTask add as a put task and return immediately
|
||||||
func putAsTask(dstDirPath string, file model.FileStreamer) error {
|
func putAsTask(dstDirPath string, file model.FileStreamer) (tache.TaskWithInfo, error) {
|
||||||
storage, dstDirActualPath, err := op.GetStorageAndActualPath(dstDirPath)
|
storage, dstDirActualPath, err := op.GetStorageAndActualPath(dstDirPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.WithMessage(err, "failed get storage")
|
return nil, errors.WithMessage(err, "failed get storage")
|
||||||
}
|
}
|
||||||
if storage.Config().NoUpload {
|
if storage.Config().NoUpload {
|
||||||
return errors.WithStack(errs.UploadNotSupported)
|
return nil, errors.WithStack(errs.UploadNotSupported)
|
||||||
}
|
}
|
||||||
if file.NeedStore() {
|
if file.NeedStore() {
|
||||||
_, err := file.CacheFullInTempFile()
|
_, err := file.CacheFullInTempFile()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "failed to create temp file")
|
return nil, errors.Wrapf(err, "failed to create temp file")
|
||||||
}
|
}
|
||||||
//file.SetReader(tempFile)
|
//file.SetReader(tempFile)
|
||||||
//file.SetTmpFile(tempFile)
|
//file.SetTmpFile(tempFile)
|
||||||
}
|
}
|
||||||
UploadTaskManager.Add(&UploadTask{
|
t := &UploadTask{
|
||||||
storage: storage,
|
storage: storage,
|
||||||
dstDirActualPath: dstDirActualPath,
|
dstDirActualPath: dstDirActualPath,
|
||||||
file: file,
|
file: file,
|
||||||
})
|
}
|
||||||
return nil
|
UploadTaskManager.Add(t)
|
||||||
|
return t, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// putDirect put the file and return after finish
|
// putDirect put the file and return after finish
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/alist-org/alist/v3/internal/op"
|
"github.com/alist-org/alist/v3/internal/op"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/xhofe/tache"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -26,38 +27,38 @@ type AddURLArgs struct {
|
||||||
DeletePolicy DeletePolicy
|
DeletePolicy DeletePolicy
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddURL(ctx context.Context, args *AddURLArgs) error {
|
func AddURL(ctx context.Context, args *AddURLArgs) (tache.TaskWithInfo, error) {
|
||||||
// get tool
|
// get tool
|
||||||
tool, err := Tools.Get(args.Tool)
|
tool, err := Tools.Get(args.Tool)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "failed get tool")
|
return nil, errors.Wrapf(err, "failed get tool")
|
||||||
}
|
}
|
||||||
// check tool is ready
|
// check tool is ready
|
||||||
if !tool.IsReady() {
|
if !tool.IsReady() {
|
||||||
// try to init tool
|
// try to init tool
|
||||||
if _, err := tool.Init(); err != nil {
|
if _, err := tool.Init(); err != nil {
|
||||||
return errors.Wrapf(err, "failed init tool %s", args.Tool)
|
return nil, errors.Wrapf(err, "failed init tool %s", args.Tool)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// check storage
|
// check storage
|
||||||
storage, dstDirActualPath, err := op.GetStorageAndActualPath(args.DstDirPath)
|
storage, dstDirActualPath, err := op.GetStorageAndActualPath(args.DstDirPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.WithMessage(err, "failed get storage")
|
return nil, errors.WithMessage(err, "failed get storage")
|
||||||
}
|
}
|
||||||
// check is it could upload
|
// check is it could upload
|
||||||
if storage.Config().NoUpload {
|
if storage.Config().NoUpload {
|
||||||
return errors.WithStack(errs.UploadNotSupported)
|
return nil, errors.WithStack(errs.UploadNotSupported)
|
||||||
}
|
}
|
||||||
// check path is valid
|
// check path is valid
|
||||||
obj, err := op.Get(ctx, storage, dstDirActualPath)
|
obj, err := op.Get(ctx, storage, dstDirActualPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errs.IsObjectNotFound(err) {
|
if !errs.IsObjectNotFound(err) {
|
||||||
return errors.WithMessage(err, "failed get object")
|
return nil, errors.WithMessage(err, "failed get object")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if !obj.IsDir() {
|
if !obj.IsDir() {
|
||||||
// can't add to a file
|
// can't add to a file
|
||||||
return errors.WithStack(errs.NotFolder)
|
return nil, errors.WithStack(errs.NotFolder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,5 +72,5 @@ func AddURL(ctx context.Context, args *AddURLArgs) error {
|
||||||
tool: tool,
|
tool: tool,
|
||||||
}
|
}
|
||||||
DownloadTaskManager.Add(t)
|
DownloadTaskManager.Add(t)
|
||||||
return nil
|
return t, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package handles
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/xhofe/tache"
|
||||||
"io"
|
"io"
|
||||||
stdpath "path"
|
stdpath "path"
|
||||||
|
|
||||||
|
@ -120,22 +121,20 @@ func FsCopy(c *gin.Context) {
|
||||||
common.ErrorResp(c, err, 403)
|
common.ErrorResp(c, err, 403)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var addedTask []string
|
var addedTasks []tache.TaskWithInfo
|
||||||
for i, name := range req.Names {
|
for i, name := range req.Names {
|
||||||
ok, err := fs.Copy(c, stdpath.Join(srcDir, name), dstDir, len(req.Names) > i+1)
|
t, err := fs.Copy(c, stdpath.Join(srcDir, name), dstDir, len(req.Names) > i+1)
|
||||||
if ok {
|
if t != nil {
|
||||||
addedTask = append(addedTask, name)
|
addedTasks = append(addedTasks, t)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.ErrorResp(c, err, 500)
|
common.ErrorResp(c, err, 500)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(addedTask) > 0 {
|
common.SuccessResp(c, gin.H{
|
||||||
common.SuccessResp(c, fmt.Sprintf("Added %d tasks", len(addedTask)))
|
"tasks": getTaskInfos(addedTasks),
|
||||||
} else {
|
})
|
||||||
common.SuccessResp(c)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type RenameReq struct {
|
type RenameReq struct {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package handles
|
package handles
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/xhofe/tache"
|
||||||
"io"
|
"io"
|
||||||
"net/url"
|
"net/url"
|
||||||
stdpath "path"
|
stdpath "path"
|
||||||
|
@ -57,8 +58,9 @@ func FsStream(c *gin.Context) {
|
||||||
Mimetype: c.GetHeader("Content-Type"),
|
Mimetype: c.GetHeader("Content-Type"),
|
||||||
WebPutAsTask: asTask,
|
WebPutAsTask: asTask,
|
||||||
}
|
}
|
||||||
|
var t tache.TaskWithInfo
|
||||||
if asTask {
|
if asTask {
|
||||||
err = fs.PutAsTask(dir, s)
|
t, err = fs.PutAsTask(dir, s)
|
||||||
} else {
|
} else {
|
||||||
err = fs.PutDirectly(c, dir, s, true)
|
err = fs.PutDirectly(c, dir, s, true)
|
||||||
}
|
}
|
||||||
|
@ -67,7 +69,13 @@ func FsStream(c *gin.Context) {
|
||||||
common.ErrorResp(c, err, 500)
|
common.ErrorResp(c, err, 500)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
common.SuccessResp(c)
|
if t == nil {
|
||||||
|
common.SuccessResp(c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
common.SuccessResp(c, gin.H{
|
||||||
|
"task": getTaskInfo(t),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func FsForm(c *gin.Context) {
|
func FsForm(c *gin.Context) {
|
||||||
|
@ -115,11 +123,12 @@ func FsForm(c *gin.Context) {
|
||||||
Mimetype: file.Header.Get("Content-Type"),
|
Mimetype: file.Header.Get("Content-Type"),
|
||||||
WebPutAsTask: asTask,
|
WebPutAsTask: asTask,
|
||||||
}
|
}
|
||||||
|
var t tache.TaskWithInfo
|
||||||
if asTask {
|
if asTask {
|
||||||
s.Reader = struct {
|
s.Reader = struct {
|
||||||
io.Reader
|
io.Reader
|
||||||
}{f}
|
}{f}
|
||||||
err = fs.PutAsTask(dir, &s)
|
t, err = fs.PutAsTask(dir, &s)
|
||||||
} else {
|
} else {
|
||||||
ss, err := stream.NewSeekableStream(s, nil)
|
ss, err := stream.NewSeekableStream(s, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -132,5 +141,11 @@ func FsForm(c *gin.Context) {
|
||||||
common.ErrorResp(c, err, 500)
|
common.ErrorResp(c, err, 500)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
common.SuccessResp(c)
|
if t == nil {
|
||||||
|
common.SuccessResp(c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
common.SuccessResp(c, gin.H{
|
||||||
|
"task": getTaskInfo(t),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/alist-org/alist/v3/internal/op"
|
"github.com/alist-org/alist/v3/internal/op"
|
||||||
"github.com/alist-org/alist/v3/server/common"
|
"github.com/alist-org/alist/v3/server/common"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/xhofe/tache"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SetAria2Req struct {
|
type SetAria2Req struct {
|
||||||
|
@ -97,8 +98,9 @@ func AddOfflineDownload(c *gin.Context) {
|
||||||
common.ErrorResp(c, err, 403)
|
common.ErrorResp(c, err, 403)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
var tasks []tache.TaskWithInfo
|
||||||
for _, url := range req.Urls {
|
for _, url := range req.Urls {
|
||||||
err := tool.AddURL(c, &tool.AddURLArgs{
|
t, err := tool.AddURL(c, &tool.AddURLArgs{
|
||||||
URL: url,
|
URL: url,
|
||||||
DstDirPath: reqPath,
|
DstDirPath: reqPath,
|
||||||
Tool: req.Tool,
|
Tool: req.Tool,
|
||||||
|
@ -108,6 +110,9 @@ func AddOfflineDownload(c *gin.Context) {
|
||||||
common.ErrorResp(c, err, 500)
|
common.ErrorResp(c, err, 500)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
tasks = append(tasks, t)
|
||||||
}
|
}
|
||||||
common.SuccessResp(c)
|
common.SuccessResp(c, gin.H{
|
||||||
|
"tasks": getTaskInfos(tasks),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package handles
|
||||||
import (
|
import (
|
||||||
"github.com/alist-org/alist/v3/internal/fs"
|
"github.com/alist-org/alist/v3/internal/fs"
|
||||||
"github.com/alist-org/alist/v3/internal/offline_download/tool"
|
"github.com/alist-org/alist/v3/internal/offline_download/tool"
|
||||||
|
"github.com/alist-org/alist/v3/pkg/utils"
|
||||||
"github.com/alist-org/alist/v3/server/common"
|
"github.com/alist-org/alist/v3/server/common"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/xhofe/tache"
|
"github.com/xhofe/tache"
|
||||||
|
@ -33,11 +34,7 @@ func getTaskInfo[T tache.TaskWithInfo](task T) TaskInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTaskInfos[T tache.TaskWithInfo](tasks []T) []TaskInfo {
|
func getTaskInfos[T tache.TaskWithInfo](tasks []T) []TaskInfo {
|
||||||
var infos []TaskInfo
|
return utils.MustSliceConvert(tasks, getTaskInfo[T])
|
||||||
for _, t := range tasks {
|
|
||||||
infos = append(infos, getTaskInfo(t))
|
|
||||||
}
|
|
||||||
return infos
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func taskRoute[T tache.TaskWithInfo](g *gin.RouterGroup, manager *tache.Manager[T]) {
|
func taskRoute[T tache.TaskWithInfo](g *gin.RouterGroup, manager *tache.Manager[T]) {
|
||||||
|
@ -48,6 +45,15 @@ func taskRoute[T tache.TaskWithInfo](g *gin.RouterGroup, manager *tache.Manager[
|
||||||
g.GET("/done", func(c *gin.Context) {
|
g.GET("/done", func(c *gin.Context) {
|
||||||
common.SuccessResp(c, getTaskInfos(manager.GetByState(tache.StateCanceled, tache.StateFailed, tache.StateSucceeded)))
|
common.SuccessResp(c, getTaskInfos(manager.GetByState(tache.StateCanceled, tache.StateFailed, tache.StateSucceeded)))
|
||||||
})
|
})
|
||||||
|
g.POST("/info", func(c *gin.Context) {
|
||||||
|
tid := c.Query("tid")
|
||||||
|
task, ok := manager.GetByID(tid)
|
||||||
|
if !ok {
|
||||||
|
common.ErrorStrResp(c, "task not found", 404)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
common.SuccessResp(c, getTaskInfo(task))
|
||||||
|
})
|
||||||
g.POST("/cancel", func(c *gin.Context) {
|
g.POST("/cancel", func(c *gin.Context) {
|
||||||
tid := c.Query("tid")
|
tid := c.Query("tid")
|
||||||
manager.Cancel(tid)
|
manager.Cancel(tid)
|
||||||
|
|
Loading…
Reference in New Issue