mirror of https://github.com/cloudreve/Cloudreve
Fix: aria2 RPC retry / return NoT_FOUND error while listing not existed path
parent
7a6c84a115
commit
f235ad1def
|
@ -29,6 +29,7 @@ type Download struct {
|
||||||
|
|
||||||
// 数据库忽略字段
|
// 数据库忽略字段
|
||||||
StatusInfo rpc.StatusInfo `gorm:"-"`
|
StatusInfo rpc.StatusInfo `gorm:"-"`
|
||||||
|
Task *Task `gorm:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// AfterFind 找到下载任务后的钩子,处理Status结构
|
// AfterFind 找到下载任务后的钩子,处理Status结构
|
||||||
|
@ -38,6 +39,10 @@ func (task *Download) AfterFind() (err error) {
|
||||||
err = json.Unmarshal([]byte(task.Attrs), &task.StatusInfo)
|
err = json.Unmarshal([]byte(task.Attrs), &task.StatusInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if task.TaskID != 0 {
|
||||||
|
task.Task, _ = GetTasksByID(task.TaskID)
|
||||||
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,10 +77,15 @@ func GetDownloadsByStatus(status ...int) []Download {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDownloadsByStatusAndUser 根据状态检索和用户ID下载
|
// GetDownloadsByStatusAndUser 根据状态检索和用户ID下载
|
||||||
|
// page 为 0 表示列出所有,非零时分页
|
||||||
// TODO 测试
|
// TODO 测试
|
||||||
func GetDownloadsByStatusAndUser(uid uint, status ...int) []Download {
|
func GetDownloadsByStatusAndUser(page, uid uint, status ...int) []Download {
|
||||||
var tasks []Download
|
var tasks []Download
|
||||||
DB.Where("user_id = ? and status in (?)", uid, status).Find(&tasks)
|
dbChain := DB
|
||||||
|
if page > 0 {
|
||||||
|
dbChain = dbChain.Limit(10).Offset((page - 1) * 10).Order("updated_at DESC")
|
||||||
|
}
|
||||||
|
dbChain.Where("user_id = ? and status in (?)", uid, status).Find(&tasks)
|
||||||
return tasks
|
return tasks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,8 +41,16 @@ func (task *Task) SetError(err string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTasksByStatus 根据状态检索任务
|
// GetTasksByStatus 根据状态检索任务
|
||||||
func GetTasksByStatus(status int) []Task {
|
func GetTasksByStatus(status ...int) []Task {
|
||||||
var tasks []Task
|
var tasks []Task
|
||||||
DB.Where("status = ?", status).Find(&tasks)
|
DB.Where("status in (?)", status).Find(&tasks)
|
||||||
return tasks
|
return tasks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTasksByID 根据ID检索任务
|
||||||
|
// TODO 测试
|
||||||
|
func GetTasksByID(id interface{}) (*Task, error) {
|
||||||
|
task := &Task{}
|
||||||
|
result := DB.Where("id = ?", id).First(task)
|
||||||
|
return task, result.Error
|
||||||
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ type Monitor struct {
|
||||||
Interval time.Duration
|
Interval time.Duration
|
||||||
|
|
||||||
notifier chan StatusEvent
|
notifier chan StatusEvent
|
||||||
|
retried int
|
||||||
}
|
}
|
||||||
|
|
||||||
// StatusEvent 状态改变事件
|
// StatusEvent 状态改变事件
|
||||||
|
@ -68,11 +69,20 @@ func (monitor *Monitor) Loop() {
|
||||||
func (monitor *Monitor) Update() bool {
|
func (monitor *Monitor) Update() bool {
|
||||||
status, err := Instance.Status(monitor.Task)
|
status, err := Instance.Status(monitor.Task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
monitor.retried++
|
||||||
util.Log().Warning("无法获取下载任务[%s]的状态,%s", monitor.Task.GID, err)
|
util.Log().Warning("无法获取下载任务[%s]的状态,%s", monitor.Task.GID, err)
|
||||||
monitor.setErrorStatus(err)
|
|
||||||
monitor.RemoveTempFolder()
|
// 十次重试后认定为任务失败
|
||||||
return true
|
if monitor.retried > 10 {
|
||||||
|
util.Log().Warning("无法获取下载任务[%s]的状态,超过最大重试次数限制,%s", monitor.Task.GID, err)
|
||||||
|
monitor.setErrorStatus(err)
|
||||||
|
monitor.RemoveTempFolder()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
monitor.retried = 0
|
||||||
|
|
||||||
// 磁力链下载需要跟随
|
// 磁力链下载需要跟随
|
||||||
if len(status.FollowedBy) > 0 {
|
if len(status.FollowedBy) > 0 {
|
||||||
|
|
|
@ -253,9 +253,8 @@ func (fs *FileSystem) ListDeleteFiles(ctx context.Context, ids []uint) error {
|
||||||
func (fs *FileSystem) List(ctx context.Context, dirPath string, pathProcessor func(string) string) ([]Object, error) {
|
func (fs *FileSystem) List(ctx context.Context, dirPath string, pathProcessor func(string) string) ([]Object, error) {
|
||||||
// 获取父目录
|
// 获取父目录
|
||||||
isExist, folder := fs.IsPathExist(dirPath)
|
isExist, folder := fs.IsPathExist(dirPath)
|
||||||
// 不存在时返回空的结果
|
|
||||||
if !isExist {
|
if !isExist {
|
||||||
return []Object{}, nil
|
return nil, ErrPathNotExist
|
||||||
}
|
}
|
||||||
fs.SetTargetDir(&[]model.Folder{*folder})
|
fs.SetTargetDir(&[]model.Folder{*folder})
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,6 @@ type DownloadListResponse struct {
|
||||||
UpdateInterval int `json:"interval"`
|
UpdateInterval int `json:"interval"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Status int `json:"status"`
|
Status int `json:"status"`
|
||||||
UserID uint `json:"uid"`
|
|
||||||
Error string `json:"error"`
|
|
||||||
Dst string `json:"dst"`
|
Dst string `json:"dst"`
|
||||||
Total uint64 `json:"total"`
|
Total uint64 `json:"total"`
|
||||||
Downloaded uint64 `json:"downloaded"`
|
Downloaded uint64 `json:"downloaded"`
|
||||||
|
@ -21,6 +19,58 @@ type DownloadListResponse struct {
|
||||||
Info rpc.StatusInfo `json:"info"`
|
Info rpc.StatusInfo `json:"info"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FinishedListResponse 已完成任务条目
|
||||||
|
type FinishedListResponse struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Status int `json:"status"`
|
||||||
|
Dst string `json:"dst"`
|
||||||
|
Error string `json:"error"`
|
||||||
|
Total uint64 `json:"total"`
|
||||||
|
Files []rpc.FileInfo `json:"files"`
|
||||||
|
TaskStatus int `json:"task_status"`
|
||||||
|
TaskError string `json:"task_error"`
|
||||||
|
CreateTime string `json:"create"`
|
||||||
|
UpdateTime string `json:"update"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// BuildFinishedListResponse 构建已完成任务条目
|
||||||
|
func BuildFinishedListResponse(tasks []model.Download) Response {
|
||||||
|
resp := make([]FinishedListResponse, 0, len(tasks))
|
||||||
|
|
||||||
|
for i := 0; i < len(tasks); i++ {
|
||||||
|
fileName := tasks[i].StatusInfo.BitTorrent.Info.Name
|
||||||
|
if len(tasks[i].StatusInfo.Files) == 1 {
|
||||||
|
fileName = path.Base(tasks[i].StatusInfo.Files[0].Path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 过滤敏感信息
|
||||||
|
for i2 := 0; i2 < len(tasks[i].StatusInfo.Files); i2++ {
|
||||||
|
tasks[i].StatusInfo.Files[i2].Path = path.Base(tasks[i].StatusInfo.Files[i2].Path)
|
||||||
|
}
|
||||||
|
|
||||||
|
download := FinishedListResponse{
|
||||||
|
Name: fileName,
|
||||||
|
Status: tasks[i].Status,
|
||||||
|
Error: tasks[i].Error,
|
||||||
|
Dst: tasks[i].Dst,
|
||||||
|
Total: tasks[i].TotalSize,
|
||||||
|
Files: tasks[i].StatusInfo.Files,
|
||||||
|
TaskStatus: -1,
|
||||||
|
UpdateTime: tasks[i].UpdatedAt.Format("2006-01-02 15:04:05"),
|
||||||
|
CreateTime: tasks[i].CreatedAt.Format("2006-01-02 15:04:05"),
|
||||||
|
}
|
||||||
|
|
||||||
|
if tasks[i].Task != nil {
|
||||||
|
download.TaskError = tasks[i].Task.Error
|
||||||
|
download.TaskStatus = tasks[i].Task.Status
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = append(resp, download)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Response{Data: resp}
|
||||||
|
}
|
||||||
|
|
||||||
// BuildDownloadingResponse 构建正在下载的列表响应
|
// BuildDownloadingResponse 构建正在下载的列表响应
|
||||||
func BuildDownloadingResponse(tasks []model.Download) Response {
|
func BuildDownloadingResponse(tasks []model.Download) Response {
|
||||||
resp := make([]DownloadListResponse, 0, len(tasks))
|
resp := make([]DownloadListResponse, 0, len(tasks))
|
||||||
|
@ -43,8 +93,6 @@ func BuildDownloadingResponse(tasks []model.Download) Response {
|
||||||
UpdateInterval: interval,
|
UpdateInterval: interval,
|
||||||
Name: fileName,
|
Name: fileName,
|
||||||
Status: tasks[i].Status,
|
Status: tasks[i].Status,
|
||||||
UserID: tasks[i].UserID,
|
|
||||||
Error: tasks[i].Error,
|
|
||||||
Dst: tasks[i].Dst,
|
Dst: tasks[i].Dst,
|
||||||
Total: tasks[i].TotalSize,
|
Total: tasks[i].TotalSize,
|
||||||
Downloaded: tasks[i].DownloadedSize,
|
Downloaded: tasks[i].DownloadedSize,
|
||||||
|
|
|
@ -77,7 +77,7 @@ func Record(job Job) (*model.Task, error) {
|
||||||
|
|
||||||
// Resume 从数据库中恢复未完成任务
|
// Resume 从数据库中恢复未完成任务
|
||||||
func Resume() {
|
func Resume() {
|
||||||
tasks := model.GetTasksByStatus(Queued)
|
tasks := model.GetTasksByStatus(Queued, Processing)
|
||||||
if len(tasks) == 0 {
|
if len(tasks) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,3 +92,14 @@ func ListDownloading(c *gin.Context) {
|
||||||
c.JSON(200, ErrorResponse(err))
|
c.JSON(200, ErrorResponse(err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListFinished 获取已完成的任务
|
||||||
|
func ListFinished(c *gin.Context) {
|
||||||
|
var service aria2.DownloadListService
|
||||||
|
if err := c.ShouldBindQuery(&service); err == nil {
|
||||||
|
res := service.Finished(c, CurrentUser(c))
|
||||||
|
c.JSON(200, res)
|
||||||
|
} else {
|
||||||
|
c.JSON(200, ErrorResponse(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -341,3 +341,14 @@ func GetUploadCredential(c *gin.Context) {
|
||||||
c.JSON(200, ErrorResponse(err))
|
c.JSON(200, ErrorResponse(err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SearchFile 搜索文件
|
||||||
|
func SearchFile(c *gin.Context) {
|
||||||
|
var service explorer.ItemDecompressService
|
||||||
|
if err := c.ShouldBindJSON(&service); err == nil {
|
||||||
|
res := service.CreateDecompressTask(c)
|
||||||
|
c.JSON(200, res)
|
||||||
|
} else {
|
||||||
|
c.JSON(200, ErrorResponse(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -271,6 +271,8 @@ func InitMasterRouter() *gin.Engine {
|
||||||
file.POST("compress", controllers.Compress)
|
file.POST("compress", controllers.Compress)
|
||||||
// 创建文件解压缩任务
|
// 创建文件解压缩任务
|
||||||
file.POST("decompress", controllers.Decompress)
|
file.POST("decompress", controllers.Decompress)
|
||||||
|
// 创建文件解压缩任务
|
||||||
|
file.GET("search/:type/:keywords", controllers.SearchFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 离线下载任务
|
// 离线下载任务
|
||||||
|
@ -286,6 +288,8 @@ func InitMasterRouter() *gin.Engine {
|
||||||
aria2.DELETE("task/:gid", controllers.CancelAria2Download)
|
aria2.DELETE("task/:gid", controllers.CancelAria2Download)
|
||||||
// 获取正在下载中的任务
|
// 获取正在下载中的任务
|
||||||
aria2.GET("downloading", controllers.ListDownloading)
|
aria2.GET("downloading", controllers.ListDownloading)
|
||||||
|
// 获取已完成的任务
|
||||||
|
aria2.GET("finished", controllers.ListFinished)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 目录
|
// 目录
|
||||||
|
|
|
@ -19,12 +19,20 @@ type DownloadTaskService struct {
|
||||||
|
|
||||||
// DownloadListService 下载列表服务
|
// DownloadListService 下载列表服务
|
||||||
type DownloadListService struct {
|
type DownloadListService struct {
|
||||||
|
Page uint `form:"page"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finished 获取已完成的任务
|
||||||
|
func (service *DownloadListService) Finished(c *gin.Context, user *model.User) serializer.Response {
|
||||||
|
// 查找下载记录
|
||||||
|
downloads := model.GetDownloadsByStatusAndUser(service.Page, user.ID, aria2.Error, aria2.Complete, aria2.Canceled, aria2.Unknown)
|
||||||
|
return serializer.BuildFinishedListResponse(downloads)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Downloading 获取正在下载中的任务
|
// Downloading 获取正在下载中的任务
|
||||||
func (service *DownloadListService) Downloading(c *gin.Context, user *model.User) serializer.Response {
|
func (service *DownloadListService) Downloading(c *gin.Context, user *model.User) serializer.Response {
|
||||||
// 查找下载记录
|
// 查找下载记录
|
||||||
downloads := model.GetDownloadsByStatusAndUser(user.ID, aria2.Downloading, aria2.Paused, aria2.Ready)
|
downloads := model.GetDownloadsByStatusAndUser(service.Page, user.ID, aria2.Downloading, aria2.Paused, aria2.Ready)
|
||||||
return serializer.BuildDownloadingResponse(downloads)
|
return serializer.BuildDownloadingResponse(downloads)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ func (service *DirectoryService) ListDirectory(c *gin.Context) serializer.Respon
|
||||||
// 获取子项目
|
// 获取子项目
|
||||||
objects, err := fs.List(ctx, service.Path, nil)
|
objects, err := fs.List(ctx, service.Path, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return serializer.Err(serializer.CodeCreateFolderFailed, err.Error(), err)
|
return serializer.Err(serializer.CodeNotSet, err.Error(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var parentID uint
|
var parentID uint
|
||||||
|
|
Loading…
Reference in New Issue