Files
2025-09-29 23:04:46 +02:00

90 lines
2.3 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package filesvc
import (
"context"
"crypto/rand"
"errors"
"fmt"
"time"
)
/*** Domain ***/
type ID = string
type File struct {
ID ID `json:"id"`
Name string `json:"name"`
UpdatedAt int64 `json:"updatedAt"` // UnixNano für LWW
Deleted bool `json:"deleted"` // Tombstone für Mesh-Delete
Owner string `json:"owner"` //AdvertURL/NodeID des Erzeugers
}
/*** Fehler ***/
var (
ErrNotFound = errors.New("file not found")
ErrBadInput = errors.New("bad input")
ErrConflict = errors.New("conflict")
ErrForbidden = errors.New("forbidden")
ErrTransient = errors.New("transient")
)
/*** Basis-API (lokal nutzbar) ***/
type Store interface {
// Lesen & Auflisten
Get(ctx context.Context, id ID) (File, error)
List(ctx context.Context, next ID, limit int) (items []File, nextOut ID, err error)
Create(ctx context.Context, name string) (File, error)
Rename(ctx context.Context, id ID, newName string) (File, error) // nur Owner darf
Delete(ctx context.Context, id ID) (File, error) // nur Owner darf
TakeoverOwner(ctx context.Context, id ID, newOwner string) (File, error)
}
/*** Mesh-Replikation ***/
type Snapshot struct {
Items []File `json:"items"`
}
type Replicable interface {
// Snapshot liefert den vollständigen aktuellen Stand (inkl. Tombstones).
Snapshot(ctx context.Context) (Snapshot, error)
// ApplyRemote wendet LWW an. next-ID wird dabei korrekt fortgeschrieben.
ApplyRemote(ctx context.Context, s Snapshot) error
}
/*** Events (optional) ***/
// ChangeEvent kann genutzt werden, um proaktive Mesh-Pushes zu triggern.
// Bei deiner Pull-basierten Anti-Entropy ist es optional.
type ChangeEvent struct {
At time.Time
Item File
}
// Watch gibt Änderungen aus; close(stop) beendet den Stream.
// Eine Noop-Implementierung ist erlaubt, wenn Pull-Sync genügt.
type Watchable interface {
Watch(stop <-chan struct{}) <-chan ChangeEvent
}
/*** Kombiniertes Interface ***/
type MeshStore interface {
Store
Replicable
Watchable // optional kann Noop sein
}
func NewUUIDv4() (string, error) {
b := make([]byte, 16)
if _, err := rand.Read(b); err != nil {
return "", err
}
b[6] = (b[6] & 0x0f) | 0x40 // Version 4
b[8] = (b[8] & 0x3f) | 0x80 // Variant RFC4122
return fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:16]), nil
}