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 }