package jobs import ( "context" "sync" "sync/atomic" "time" ) type Status string const ( StatusQueued Status = "queued" StatusDownloading Status = "downloading" StatusExtracting Status = "extracting" StatusReady Status = "ready" StatusMoving Status = "moving" StatusCompleted Status = "completed" StatusFailed Status = "failed" StatusCancelled Status = "cancelled" ) type Snapshot struct { ID string `json:"id"` SourceURL string `json:"sourceUrl"` FileName string `json:"fileName"` Status Status `json:"status"` Message string `json:"message"` BytesDone int64 `json:"bytesDone"` BytesTotal int64 `json:"bytesTotal"` CreatedAt time.Time `json:"createdAt"` } type Job struct { id string sourceURL string displayURL string directory string autoExtract bool createdAt time.Time jobContext context.Context cancel context.CancelFunc workers sync.WaitGroup mutex sync.Mutex status Status message string fileName string deleted bool bytesDone atomic.Int64 bytesTotal atomic.Int64 } func (job *Job) SetTotal(total int64) { job.bytesTotal.Store(total) } func (job *Job) Add(delta int64) { job.bytesDone.Add(delta) } func (job *Job) SetFileName(name string) { job.mutex.Lock() defer job.mutex.Unlock() job.fileName = name } func (job *Job) resetProgress() { job.bytesDone.Store(0) job.bytesTotal.Store(0) } func (job *Job) setStatus(status Status, message string) { job.mutex.Lock() defer job.mutex.Unlock() if job.deleted { return } job.status = status job.message = message } func (job *Job) currentStatus() Status { job.mutex.Lock() defer job.mutex.Unlock() return job.status } func (job *Job) begin(from, to Status) bool { job.mutex.Lock() defer job.mutex.Unlock() if job.deleted || job.status != from { return false } job.status = to job.message = "" job.workers.Add(1) return true } func (job *Job) markDeleted() bool { job.mutex.Lock() defer job.mutex.Unlock() if job.status == StatusMoving { return false } job.deleted = true job.status = StatusCancelled return true } func (job *Job) snapshot() Snapshot { job.mutex.Lock() defer job.mutex.Unlock() return Snapshot{ ID: job.id, SourceURL: job.displayURL, FileName: job.fileName, Status: job.status, Message: job.message, BytesDone: job.bytesDone.Load(), BytesTotal: job.bytesTotal.Load(), CreatedAt: job.createdAt, } }