Files
photocli/internal/manifest/jsonl.go
T
Ein Anderssono 2e73d01b40
pipeline / build (push) Has been cancelled
pipeline / test (push) Has been cancelled
v0.5.0: manifests, filters, logging, docs
2026-06-15 00:00:06 +02:00

140 lines
2.7 KiB
Go

package manifest
import (
"encoding/json"
"os"
"path/filepath"
"strings"
"sync"
)
type jsonlManifest struct {
mu sync.Mutex
entries map[string]Entry
path string
file *os.File
syncFunc func() error
}
var jsonlSaveHook func() error
func SetJSONLSaveHook(fn func() error) func() error {
old := jsonlSaveHook
jsonlSaveHook = fn
return old
}
func JSONLPath(dir string) string {
return filepath.Join(dir, "downloads.jsonl")
}
func LoadJSONL(dir string) *jsonlManifest {
m := &jsonlManifest{
entries: make(map[string]Entry),
path: JSONLPath(dir),
}
data, err := os.ReadFile(m.path)
if err != nil {
return m
}
type entryWithID struct {
ID string `json:"id"`
Filename string `json:"filename"`
Size int64 `json:"size"`
Cloud string `json:"cloud"`
Exported int64 `json:"exported"`
}
for _, line := range strings.Split(string(data), "\n") {
line = strings.TrimSpace(line)
if line == "" {
continue
}
var raw entryWithID
if json.Unmarshal([]byte(line), &raw) == nil && raw.ID != "" {
m.entries[raw.ID] = Entry{
Filename: raw.Filename,
Size: raw.Size,
Cloud: raw.Cloud,
Exported: raw.Exported,
}
}
}
return m
}
func (m *jsonlManifest) Has(id string) bool {
m.mu.Lock()
defer m.mu.Unlock()
_, ok := m.entries[id]
return ok
}
func (m *jsonlManifest) Add(id string, filename string, size int64, cloud string) {
m.mu.Lock()
defer m.mu.Unlock()
entry := newEntry(id, filename, size, cloud)
m.entries[id] = entry
if m.file != nil {
data, _ := json.Marshal(struct {
ID string `json:"id"`
Filename string `json:"filename"`
Size int64 `json:"size"`
Cloud string `json:"cloud"`
Exported int64 `json:"exported"`
}{ID: id, Filename: entry.Filename, Size: entry.Size, Cloud: entry.Cloud, Exported: entry.Exported})
m.file.Write(data)
m.file.Write([]byte("\n"))
}
}
func (m *jsonlManifest) Save() error {
m.mu.Lock()
defer m.mu.Unlock()
if m.syncFunc != nil {
return m.syncFunc()
}
if jsonlSaveHook != nil {
return jsonlSaveHook()
}
if m.file != nil {
return m.file.Sync()
}
return nil
}
func (m *jsonlManifest) Close() {
m.mu.Lock()
defer m.mu.Unlock()
if m.file != nil {
m.file.Close()
m.file = nil
}
}
func (m *jsonlManifest) OpenAppend() error {
m.mu.Lock()
defer m.mu.Unlock()
if m.file != nil {
return nil
}
if err := os.MkdirAll(filepath.Dir(m.path), 0755); err != nil {
return err
}
f, err := os.OpenFile(m.path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
return err
}
m.file = f
return nil
}
func (m *jsonlManifest) Entries() map[string]Entry {
m.mu.Lock()
defer m.mu.Unlock()
out := make(map[string]Entry, len(m.entries))
for k, v := range m.entries {
out[k] = v
}
return out
}