81 lines
2.2 KiB
Go
81 lines
2.2 KiB
Go
package notifications
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
)
|
|
|
|
type storedSchedules struct {
|
|
Items []Item `json:"items"`
|
|
}
|
|
|
|
func schedulePath(vaultPath string) string {
|
|
return filepath.Join(vaultPath, ".verstak", "notifications", "schedules.json")
|
|
}
|
|
|
|
func (m *Manager) loadLocked() error {
|
|
if m.loaded {
|
|
return nil
|
|
}
|
|
if m.vault == nil {
|
|
return fmt.Errorf("notification vault is not initialized")
|
|
}
|
|
var loaded []Item
|
|
if err := m.vault.WithOpenPath(func(vaultPath string) error {
|
|
path := schedulePath(vaultPath)
|
|
data, err := os.ReadFile(path)
|
|
if os.IsNotExist(err) {
|
|
loaded = []Item{}
|
|
return nil
|
|
}
|
|
if err != nil {
|
|
return fmt.Errorf("read notification schedules: %w", err)
|
|
}
|
|
var stored storedSchedules
|
|
if err := json.Unmarshal(data, &stored); err != nil {
|
|
return fmt.Errorf("decode notification schedules: %w", err)
|
|
}
|
|
for _, item := range stored.Items {
|
|
if err := validateRequests(item.PluginID, []Request{{ID: item.ID, DueAt: item.DueAt, Title: item.Title, Body: item.Body}}); err != nil {
|
|
return fmt.Errorf("invalid stored notification schedule: %w", err)
|
|
}
|
|
loaded = append(loaded, item)
|
|
}
|
|
sortItems(loaded)
|
|
return nil
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
m.items = loaded
|
|
m.loaded = true
|
|
return nil
|
|
}
|
|
|
|
func (m *Manager) writeLocked(items []Item) error {
|
|
if m.vault == nil {
|
|
return fmt.Errorf("notification vault is not initialized")
|
|
}
|
|
return m.vault.WithOpenPath(func(vaultPath string) error {
|
|
data, err := json.MarshalIndent(storedSchedules{Items: items}, "", " ")
|
|
if err != nil {
|
|
return fmt.Errorf("encode notification schedules: %w", err)
|
|
}
|
|
path := schedulePath(vaultPath)
|
|
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
|
return fmt.Errorf("create notification schedule directory: %w", err)
|
|
}
|
|
temporary := filepath.Join(filepath.Dir(path), fmt.Sprintf(".schedules.%d.tmp", time.Now().UnixNano()))
|
|
if err := os.WriteFile(temporary, data, 0o644); err != nil {
|
|
return fmt.Errorf("write notification schedules: %w", err)
|
|
}
|
|
if err := os.Rename(temporary, path); err != nil {
|
|
_ = os.Remove(temporary)
|
|
return fmt.Errorf("replace notification schedules: %w", err)
|
|
}
|
|
return nil
|
|
})
|
|
}
|