function update

This commit is contained in:
2026-05-19 04:30:14 +00:00
parent 1293bafffa
commit 3f82dfd9e9
13 changed files with 8080 additions and 152 deletions
+105
View File
@@ -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
}