提交 f235ad1d 编写于 作者: H HFO4

Fix: aria2 RPC retry / return NoT_FOUND error while listing not existed path

上级 7a6c84a1
......@@ -29,6 +29,7 @@ type Download struct {
// 数据库忽略字段
StatusInfo rpc.StatusInfo `gorm:"-"`
Task *Task `gorm:"-"`
}
// AfterFind 找到下载任务后的钩子,处理Status结构
......@@ -38,6 +39,10 @@ func (task *Download) AfterFind() (err error) {
err = json.Unmarshal([]byte(task.Attrs), &task.StatusInfo)
}
if task.TaskID != 0 {
task.Task, _ = GetTasksByID(task.TaskID)
}
return err
}
......@@ -72,10 +77,15 @@ func GetDownloadsByStatus(status ...int) []Download {
}
// GetDownloadsByStatusAndUser 根据状态检索和用户ID下载
// page 为 0 表示列出所有,非零时分页
// TODO 测试
func GetDownloadsByStatusAndUser(uid uint, status ...int) []Download {
func GetDownloadsByStatusAndUser(page, uid uint, status ...int) []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
}
......
......@@ -41,8 +41,16 @@ func (task *Task) SetError(err string) error {
}
// GetTasksByStatus 根据状态检索任务
func GetTasksByStatus(status int) []Task {
func GetTasksByStatus(status ...int) []Task {
var tasks []Task
DB.Where("status = ?", status).Find(&tasks)
DB.Where("status in (?)", status).Find(&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
notifier chan StatusEvent
retried int
}
// StatusEvent 状态改变事件
......@@ -68,11 +69,20 @@ func (monitor *Monitor) Loop() {
func (monitor *Monitor) Update() bool {
status, err := Instance.Status(monitor.Task)
if err != nil {
monitor.retried++
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 {
......
......@@ -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) {
// 获取父目录
isExist, folder := fs.IsPathExist(dirPath)
// 不存在时返回空的结果
if !isExist {
return []Object{}, nil
return nil, ErrPathNotExist
}
fs.SetTargetDir(&[]model.Folder{*folder})
......
......@@ -12,8 +12,6 @@ type DownloadListResponse struct {
UpdateInterval int `json:"interval"`
Name string `json:"name"`
Status int `json:"status"`
UserID uint `json:"uid"`
Error string `json:"error"`
Dst string `json:"dst"`
Total uint64 `json:"total"`
Downloaded uint64 `json:"downloaded"`
......@@ -21,6 +19,58 @@ type DownloadListResponse struct {
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 构建正在下载的列表响应
func BuildDownloadingResponse(tasks []model.Download) Response {
resp := make([]DownloadListResponse, 0, len(tasks))
......@@ -43,8 +93,6 @@ func BuildDownloadingResponse(tasks []model.Download) Response {
UpdateInterval: interval,
Name: fileName,
Status: tasks[i].Status,
UserID: tasks[i].UserID,
Error: tasks[i].Error,
Dst: tasks[i].Dst,
Total: tasks[i].TotalSize,
Downloaded: tasks[i].DownloadedSize,
......
......@@ -77,7 +77,7 @@ func Record(job Job) (*model.Task, error) {
// Resume 从数据库中恢复未完成任务
func Resume() {
tasks := model.GetTasksByStatus(Queued)
tasks := model.GetTasksByStatus(Queued, Processing)
if len(tasks) == 0 {
return
}
......
......@@ -92,3 +92,14 @@ func ListDownloading(c *gin.Context) {
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))
}
}
// 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("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.GET("downloading", controllers.ListDownloading)
// 获取已完成的任务
aria2.GET("finished", controllers.ListFinished)
}
// 目录
......
......@@ -19,12 +19,20 @@ type DownloadTaskService struct {
// DownloadListService 下载列表服务
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 获取正在下载中的任务
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)
}
......
......@@ -28,7 +28,7 @@ func (service *DirectoryService) ListDirectory(c *gin.Context) serializer.Respon
// 获取子项目
objects, err := fs.List(ctx, service.Path, nil)
if err != nil {
return serializer.Err(serializer.CodeCreateFolderFailed, err.Error(), err)
return serializer.Err(serializer.CodeNotSet, err.Error(), err)
}
var parentID uint
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册