60 lines
1.3 KiB
Go
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
|
|
}
|