github.com/cloudreve/Cloudreve/v3@v3.0.0-20240224133659-3edb00a6484c/pkg/task/tranfer.go (about) 1 package task 2 3 import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "path" 8 "path/filepath" 9 "strings" 10 11 model "github.com/cloudreve/Cloudreve/v3/models" 12 "github.com/cloudreve/Cloudreve/v3/pkg/cluster" 13 "github.com/cloudreve/Cloudreve/v3/pkg/filesystem" 14 "github.com/cloudreve/Cloudreve/v3/pkg/filesystem/fsctx" 15 "github.com/cloudreve/Cloudreve/v3/pkg/util" 16 ) 17 18 // TransferTask 文件中转任务 19 type TransferTask struct { 20 User *model.User 21 TaskModel *model.Task 22 TaskProps TransferProps 23 Err *JobError 24 25 zipPath string 26 } 27 28 // TransferProps 中转任务属性 29 type TransferProps struct { 30 Src []string `json:"src"` // 原始文件 31 SrcSizes map[string]uint64 `json:"src_size"` // 原始文件的大小信息,从机转存时使用 32 Parent string `json:"parent"` // 父目录 33 Dst string `json:"dst"` // 目的目录ID 34 // 将会保留原始文件的目录结构,Src 除去 Parent 开头作为最终路径 35 TrimPath bool `json:"trim_path"` 36 // 负责处理中专任务的节点ID 37 NodeID uint `json:"node_id"` 38 } 39 40 // Props 获取任务属性 41 func (job *TransferTask) Props() string { 42 res, _ := json.Marshal(job.TaskProps) 43 return string(res) 44 } 45 46 // Type 获取任务状态 47 func (job *TransferTask) Type() int { 48 return TransferTaskType 49 } 50 51 // Creator 获取创建者ID 52 func (job *TransferTask) Creator() uint { 53 return job.User.ID 54 } 55 56 // Model 获取任务的数据库模型 57 func (job *TransferTask) Model() *model.Task { 58 return job.TaskModel 59 } 60 61 // SetStatus 设定状态 62 func (job *TransferTask) SetStatus(status int) { 63 job.TaskModel.SetStatus(status) 64 } 65 66 // SetError 设定任务失败信息 67 func (job *TransferTask) SetError(err *JobError) { 68 job.Err = err 69 res, _ := json.Marshal(job.Err) 70 job.TaskModel.SetError(string(res)) 71 72 } 73 74 // SetErrorMsg 设定任务失败信息 75 func (job *TransferTask) SetErrorMsg(msg string, err error) { 76 jobErr := &JobError{Msg: msg} 77 if err != nil { 78 jobErr.Error = err.Error() 79 } 80 job.SetError(jobErr) 81 } 82 83 // GetError 返回任务失败信息 84 func (job *TransferTask) GetError() *JobError { 85 return job.Err 86 } 87 88 // Do 开始执行任务 89 func (job *TransferTask) Do() { 90 // 创建文件系统 91 fs, err := filesystem.NewFileSystem(job.User) 92 if err != nil { 93 job.SetErrorMsg(err.Error(), nil) 94 return 95 } 96 97 successCount := 0 98 errorList := make([]string, 0, len(job.TaskProps.Src)) 99 for _, file := range job.TaskProps.Src { 100 dst := path.Join(job.TaskProps.Dst, filepath.Base(file)) 101 if job.TaskProps.TrimPath { 102 // 保留原始目录 103 trim := util.FormSlash(job.TaskProps.Parent) 104 src := util.FormSlash(file) 105 dst = path.Join(job.TaskProps.Dst, strings.TrimPrefix(src, trim)) 106 } 107 108 if job.TaskProps.NodeID > 1 { 109 // 指定为从机中转 110 111 // 获取从机节点 112 node := cluster.Default.GetNodeByID(job.TaskProps.NodeID) 113 if node == nil { 114 job.SetErrorMsg("Invalid slave node.", nil) 115 } 116 117 // 切换为从机节点处理上传 118 fs.SwitchToSlaveHandler(node) 119 err = fs.UploadFromStream(context.Background(), &fsctx.FileStream{ 120 File: nil, 121 Size: job.TaskProps.SrcSizes[file], 122 Name: path.Base(dst), 123 VirtualPath: path.Dir(dst), 124 Src: file, 125 }, false) 126 } else { 127 // 主机节点中转 128 err = fs.UploadFromPath(context.Background(), file, dst, 0) 129 } 130 131 if err != nil { 132 errorList = append(errorList, err.Error()) 133 } else { 134 successCount++ 135 job.TaskModel.SetProgress(successCount) 136 } 137 } 138 139 if len(errorList) > 0 { 140 job.SetErrorMsg("Failed to transfer one or more file(s).", fmt.Errorf(strings.Join(errorList, "\n"))) 141 } 142 143 } 144 145 // NewTransferTask 新建中转任务 146 func NewTransferTask(user uint, src []string, dst, parent string, trim bool, node uint, sizes map[string]uint64) (Job, error) { 147 creator, err := model.GetActiveUserByID(user) 148 if err != nil { 149 return nil, err 150 } 151 152 newTask := &TransferTask{ 153 User: &creator, 154 TaskProps: TransferProps{ 155 Src: src, 156 Parent: parent, 157 Dst: dst, 158 TrimPath: trim, 159 NodeID: node, 160 SrcSizes: sizes, 161 }, 162 } 163 164 record, err := Record(newTask) 165 if err != nil { 166 return nil, err 167 } 168 newTask.TaskModel = record 169 170 return newTask, nil 171 } 172 173 // NewTransferTaskFromModel 从数据库记录中恢复中转任务 174 func NewTransferTaskFromModel(task *model.Task) (Job, error) { 175 user, err := model.GetActiveUserByID(task.UserID) 176 if err != nil { 177 return nil, err 178 } 179 newTask := &TransferTask{ 180 User: &user, 181 TaskModel: task, 182 } 183 184 err = json.Unmarshal([]byte(task.Props), &newTask.TaskProps) 185 if err != nil { 186 return nil, err 187 } 188 189 return newTask, nil 190 }