156 lines
3.2 KiB
Go
156 lines
3.2 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"`
|
|
Path string `json:"path,omitempty"`
|
|
Size int64 `json:"size"`
|
|
Cloud string `json:"cloud"`
|
|
Checksum string `json:"checksum,omitempty"`
|
|
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 != "" {
|
|
if raw.Path == "" {
|
|
raw.Path = raw.Filename
|
|
}
|
|
m.entries[raw.ID] = Entry{
|
|
ID: raw.ID,
|
|
Filename: raw.Filename,
|
|
Path: raw.Path,
|
|
Size: raw.Size,
|
|
Cloud: raw.Cloud,
|
|
Checksum: raw.Checksum,
|
|
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.AddEntry(newEntry(id, filename, size, cloud))
|
|
}
|
|
|
|
func (m *jsonlManifest) AddEntry(entry Entry) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
if entry.Path == "" {
|
|
entry.Path = entry.Filename
|
|
}
|
|
m.entries[entry.ID] = entry
|
|
if m.file != nil {
|
|
data, _ := json.Marshal(struct {
|
|
ID string `json:"id"`
|
|
Filename string `json:"filename"`
|
|
Path string `json:"path,omitempty"`
|
|
Size int64 `json:"size"`
|
|
Cloud string `json:"cloud"`
|
|
Checksum string `json:"checksum,omitempty"`
|
|
Exported int64 `json:"exported"`
|
|
}{ID: entry.ID, Filename: entry.Filename, Path: entry.Path, Size: entry.Size, Cloud: entry.Cloud, Checksum: entry.Checksum, 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
|
|
}
|