package jobs import ( "encoding/json" "log" "os" "path/filepath" "time" "ddc/internal/fetch" "ddc/internal/files" ) const ( phaseDownloading = "downloading" phasePaused = "paused" phaseFailed = "failed" phaseDone = "done" ) type jobRecord struct { SourceURL string `json:"sourceUrl"` DisplayURL string `json:"displayUrl"` RequestedName string `json:"requestedName,omitempty"` FileName string `json:"fileName"` AutoExtract bool `json:"autoExtract"` Destination string `json:"destination,omitempty"` Subfolder string `json:"subfolder,omitempty"` Phase string `json:"phase"` Message string `json:"message,omitempty"` Download *fetch.State `json:"download,omitempty"` CreatedAt time.Time `json:"createdAt"` } func (job *Job) record() jobRecord { job.mutex.Lock() defer job.mutex.Unlock() record := jobRecord{ SourceURL: job.sourceURL, DisplayURL: job.displayURL, RequestedName: job.requestedName, FileName: job.fileName, AutoExtract: job.autoExtract, Phase: phaseFor(job.status, job.downloaded), Message: job.message, Download: job.downloadState, CreatedAt: job.createdAt, } if job.target != nil { record.Destination = job.target.destination record.Subfolder = job.target.subfolder } return record } func phaseFor(status Status, downloaded bool) string { switch { case downloaded: return phaseDone case status == StatusPaused: return phasePaused case status == StatusFailed: return phaseFailed default: return phaseDownloading } } func (job *Job) saveRecord() { data, err := json.MarshalIndent(job.record(), "", " ") if err != nil { log.Printf("could not encode download %s: %v", job.id, err) return } job.recordMutex.Lock() defer job.recordMutex.Unlock() if err := files.WriteAtomically(filepath.Join(job.directory, files.JobFileName), data); err != nil && !os.IsNotExist(err) { log.Printf("could not save download %s: %v", job.id, err) } } func readRecord(directory string) (jobRecord, bool) { data, err := os.ReadFile(filepath.Join(directory, files.JobFileName)) if err != nil { return jobRecord{}, false } var record jobRecord if err := json.Unmarshal(data, &record); err != nil { return jobRecord{}, false } return record, true } func (job *Job) applyRecord(record jobRecord) { job.sourceURL = record.SourceURL job.displayURL = record.DisplayURL job.requestedName = record.RequestedName job.fileName = record.FileName job.autoExtract = record.AutoExtract if !record.CreatedAt.IsZero() { job.createdAt = record.CreatedAt } if record.Destination != "" { job.target = &moveTarget{destination: record.Destination, subfolder: record.Subfolder} } }