- mail/internal/storage: LocalDriver/S3Driver (bewaehrtes Muster aus DMS FDN-03, bewusste Neuimplementierung - Mail kann DMS nicht importieren), ObjectKey mit festem Pfadschema - Service.Put/GetVerified: Pruefsummenverifikation AN DIESER SCHICHT (Erweiterung gegenueber FDN-03) - SHA-256-Sidecar, sofortige Ruecklese-Verifikation beim Schreiben, Erkennung manipulierter Objekte beim Lesen - HTTPUsageReporter: meldet an Core API-11 (resync-api/LIC-05), identisches Muster wie DMS FDN-03 - 4 Tests real bestanden: byteidentischer Read-back, manipuliertes Objekt erkannt, Lasttest (500 Objekte, 105.8us/Objekt), Nutzungsmeldung bei Schreiben+Loeschen - zusaetzlich echter End-zu-Ende-Beweis gegen den laufenden nexarch-resync-api.service: reales Service-Credential provisioniert, Put->GetVerified->Delete komplett durchlaufen, usage_counters zeigt reales +29/-29-Delta (beide Meldungen real angewendet) Pruefungen siehe mail/docs/ARC-01-PRUEFPROTOKOLL.md
64 lines
1.5 KiB
Go
64 lines
1.5 KiB
Go
package storage
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
)
|
|
|
|
// LocalDriver legt Objekte im lokalen Dateisystem ab — der
|
|
// Entwicklungs-Treiber (Akzeptanzkriterium 1), keine externe
|
|
// Abhängigkeit nötig.
|
|
type LocalDriver struct {
|
|
baseDir string
|
|
}
|
|
|
|
func NewLocalDriver(baseDir string) *LocalDriver {
|
|
return &LocalDriver{baseDir: baseDir}
|
|
}
|
|
|
|
func (d *LocalDriver) path(key string) string {
|
|
return filepath.Join(d.baseDir, filepath.FromSlash(key))
|
|
}
|
|
|
|
func (d *LocalDriver) Put(_ context.Context, key string, r io.Reader, _ int64, _ string) (int64, error) {
|
|
full := d.path(key)
|
|
if err := os.MkdirAll(filepath.Dir(full), 0o755); err != nil {
|
|
return 0, fmt.Errorf("storage: verzeichnis anlegen: %w", err)
|
|
}
|
|
f, err := os.Create(full)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("storage: datei anlegen: %w", err)
|
|
}
|
|
defer func() { _ = f.Close() }()
|
|
|
|
written, err := io.Copy(f, r)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("storage: schreiben: %w", err)
|
|
}
|
|
return written, nil
|
|
}
|
|
|
|
func (d *LocalDriver) Get(_ context.Context, key string) (io.ReadCloser, error) {
|
|
f, err := os.Open(d.path(key))
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return nil, ErrNotFound
|
|
}
|
|
return nil, fmt.Errorf("storage: lesen: %w", err)
|
|
}
|
|
return f, nil
|
|
}
|
|
|
|
func (d *LocalDriver) Delete(_ context.Context, key string) error {
|
|
if err := os.Remove(d.path(key)); err != nil {
|
|
if os.IsNotExist(err) {
|
|
return ErrNotFound
|
|
}
|
|
return fmt.Errorf("storage: löschen: %w", err)
|
|
}
|
|
return nil
|
|
}
|