package update import ( domain "RenewCMS/internal/domain/update" "encoding/json" "os" "path/filepath" "sync" ) type JSONJobStore struct { path string mu sync.Mutex } var _ domain.JobStore = &JSONJobStore{} func NewJSONJobStore(path string) *JSONJobStore { store := &JSONJobStore{path: path} store.failInterruptedJob() return store } func (s *JSONJobStore) failInterruptedJob() { job, found := s.read() if !found || !job.IsRunning() { return } job.State = domain.StateFailed job.Error = domain.ErrorKindDownload job.DownloadedBytes = 0 job.TotalBytes = 0 _ = s.write(job) } func (s *JSONJobStore) Load() (domain.Job, bool) { s.mu.Lock() defer s.mu.Unlock() job, found := s.read() if !found { return domain.Job{}, false } if job.State == domain.StateReady && !fileExists(job.StagedBinary) { return domain.Job{}, false } return job, true } func (s *JSONJobStore) Save(job domain.Job) error { s.mu.Lock() defer s.mu.Unlock() return s.write(job) } func (s *JSONJobStore) read() (domain.Job, bool) { content, err := os.ReadFile(s.path) if err != nil { return domain.Job{}, false } var job domain.Job if err := json.Unmarshal(content, &job); err != nil || job.State == "" { return domain.Job{}, false } return job, true } func (s *JSONJobStore) write(job domain.Job) error { content, err := json.Marshal(job) if err != nil { return err } if err := os.MkdirAll(filepath.Dir(s.path), os.ModePerm); err != nil { return err } temporary := s.path + ".tmp" if err := os.WriteFile(temporary, content, statusFilePermissions); err != nil { return err } return os.Rename(temporary, s.path) } func fileExists(path string) bool { if path == "" { return false } info, err := os.Stat(path) return err == nil && !info.IsDir() }