function update
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// RemovedItem records a hub item explicitly removed via the dashboard.
|
||||
type RemovedItem struct {
|
||||
Kind string `json:"kind"`
|
||||
Name string `json:"name"`
|
||||
RemovedAt time.Time `json:"removed_at"`
|
||||
}
|
||||
|
||||
type storeData struct {
|
||||
RemovedItems []RemovedItem `json:"removed_items"`
|
||||
}
|
||||
|
||||
// Store is a file-backed JSON store for dashboard-specific state.
|
||||
type Store struct {
|
||||
path string
|
||||
mu sync.Mutex
|
||||
data storeData
|
||||
}
|
||||
|
||||
// New opens or creates the store at path. Returns error only for malformed JSON.
|
||||
func New(path string) (*Store, error) {
|
||||
s := &Store{path: path}
|
||||
if err := s.load(); err != nil && !os.IsNotExist(err) {
|
||||
return nil, fmt.Errorf("store: load %s: %w", path, err)
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *Store) load() error {
|
||||
b, err := os.ReadFile(s.path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(b, &s.data)
|
||||
}
|
||||
|
||||
func (s *Store) save() error {
|
||||
if err := os.MkdirAll(filepath.Dir(s.path), 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
b, err := json.MarshalIndent(s.data, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tmp := s.path + ".tmp"
|
||||
if err := os.WriteFile(tmp, b, 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
return os.Rename(tmp, s.path)
|
||||
}
|
||||
|
||||
// AddRemoved records that kind/name was removed via the dashboard.
|
||||
// Idempotent — duplicate calls are no-ops.
|
||||
func (s *Store) AddRemoved(kind, name string) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
for _, item := range s.data.RemovedItems {
|
||||
if item.Kind == kind && item.Name == name {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
s.data.RemovedItems = append(s.data.RemovedItems, RemovedItem{
|
||||
Kind: kind,
|
||||
Name: name,
|
||||
RemovedAt: time.Now().UTC(),
|
||||
})
|
||||
return s.save()
|
||||
}
|
||||
|
||||
// RemoveTracked clears the tracking record for kind/name (item re-installed).
|
||||
func (s *Store) RemoveTracked(kind, name string) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
var filtered []RemovedItem
|
||||
for _, item := range s.data.RemovedItems {
|
||||
if !(item.Kind == kind && item.Name == name) {
|
||||
filtered = append(filtered, item)
|
||||
}
|
||||
}
|
||||
s.data.RemovedItems = filtered
|
||||
return s.save()
|
||||
}
|
||||
|
||||
// RemovedSet returns a set of item names removed for the given kind.
|
||||
func (s *Store) RemovedSet(kind string) map[string]bool {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
set := make(map[string]bool)
|
||||
for _, item := range s.data.RemovedItems {
|
||||
if item.Kind == kind {
|
||||
set[item.Name] = true
|
||||
}
|
||||
}
|
||||
return set
|
||||
}
|
||||
Reference in New Issue
Block a user