corago/codex-keep/store.go

88 lines
1.8 KiB
Go
Raw Permalink Normal View History

package main
import (
"encoding/json"
"errors"
"fmt"
"os"
"path/filepath"
"syscall"
)
type store struct {
path string
lock *os.File
Watches map[string]*watch `json:"watches"`
}
func openStore(path string) (*store, error) {
if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil {
return nil, err
}
lock, err := os.OpenFile(path+".lock", os.O_CREATE|os.O_RDWR, 0600)
if err != nil {
return nil, err
}
if err := syscall.Flock(int(lock.Fd()), syscall.LOCK_EX|syscall.LOCK_NB); err != nil {
return nil, fmt.Errorf("checkpoint is already in use: %w", errors.Join(err, lock.Close()))
}
s := &store{path: path, lock: lock, Watches: make(map[string]*watch)}
data, err := os.ReadFile(path)
if errors.Is(err, os.ErrNotExist) {
return s, nil
}
if err == nil {
err = json.Unmarshal(data, s)
}
if err == nil && s.Watches == nil {
err = errors.New("checkpoint has no watches")
}
if err != nil {
return nil, errors.Join(err, s.close())
}
2026-10-22 22:05:33 +09:00
for _, w := range s.Watches {
if w.Known && w.Goal != nil && w.Goal.Status.waiting() && w.Turn.Status == "failed" {
if w.Hold != nil && w.Goal.Status == "usageLimited" && w.Hold.Status == "usageLimited" {
w.Hold = nil
}
if w.Hold == nil {
w.Armed = true
}
}
}
return s, nil
}
func (s *store) close() error { return s.lock.Close() }
func (s *store) save() error {
data, err := json.Marshal(s)
if err != nil {
return err
}
f, err := os.CreateTemp(filepath.Dir(s.path), ".state-*")
if err != nil {
return err
}
defer func() { _ = os.Remove(f.Name()) }()
if _, err = f.Write(data); err == nil {
err = f.Sync()
}
closeErr := f.Close()
if err != nil {
return err
}
if closeErr != nil {
return closeErr
}
return os.Rename(f.Name(), s.path)
}
func (s *store) watch(id string) *watch {
w := s.Watches[id]
if w == nil {
w = &watch{}
s.Watches[id] = w
}
return w
}