owpengram-server/internal/updatecdn/store.go
2026-09-01 12:06:31 +03:00

60 lines
1.3 KiB
Go

package updatecdn
import (
"fmt"
"os"
"sync"
"time"
)
// Store atomically reloads the catalog when the manifest changes. A broken new
// manifest is never mixed with the previous snapshot.
type Store struct {
manifestPath string
filesDir string
mu sync.RWMutex
catalog *Catalog
modTime time.Time
fileSize int64
}
func NewStore(manifestPath, filesDir string) (*Store, error) {
store := &Store{manifestPath: manifestPath, filesDir: filesDir}
if _, err := store.Snapshot(); err != nil {
return nil, err
}
return store, nil
}
func (s *Store) Snapshot() (*Catalog, error) {
info, err := os.Stat(s.manifestPath)
if err != nil {
return nil, fmt.Errorf("stat manifest: %w", err)
}
s.mu.RLock()
if s.catalog != nil && info.ModTime().Equal(s.modTime) && info.Size() == s.fileSize {
catalog := s.catalog
s.mu.RUnlock()
return catalog, nil
}
s.mu.RUnlock()
s.mu.Lock()
defer s.mu.Unlock()
info, err = os.Stat(s.manifestPath)
if err != nil {
return nil, fmt.Errorf("stat manifest: %w", err)
}
if s.catalog != nil && info.ModTime().Equal(s.modTime) && info.Size() == s.fileSize {
return s.catalog, nil
}
catalog, err := LoadCatalog(s.manifestPath, s.filesDir)
if err != nil {
return nil, err
}
s.catalog = catalog
s.modTime = info.ModTime()
s.fileSize = info.Size()
return catalog, nil
}