package storage import ( "context" "fmt" "io" "time" ) // Service verbindet einen Driver mit der Nutzungsmeldung an Core // (Akzeptanzkriterium 4) — jeder Schreib-/Loeschvorgang ueber Service loest // GENAU EINE Meldung mit der tatsaechlich geschriebenen/geloeschten // Objektgroesse aus. Repository-/Handler-Code (spaetere Kacheln, z.B. // DOC-01) ruft ausschliesslich Service auf, nie einen Driver direkt — das // verhindert einen Schreibpfad, der die Nutzungsmeldung vergisst. type Service struct { driver Driver usage UsageReporter tenantSlug string } func NewService(driver Driver, usage UsageReporter, tenantSlug string) *Service { return &Service{driver: driver, usage: usage, tenantSlug: tenantSlug} } // Put legt das Objekt ab und meldet die geschriebene Groesse als positives // Delta (Pruefung 4). func (s *Service) Put(ctx context.Context, key string, r io.Reader, size int64, contentType string) (int64, error) { written, err := s.driver.Put(ctx, key, r, size, contentType) if err != nil { return 0, err } if err := s.usage.Report(ctx, s.tenantSlug, UsageMetric, written); err != nil { return written, fmt.Errorf("storage: objekt gespeichert, aber nutzungsmeldung fehlgeschlagen: %w", err) } return written, nil } func (s *Service) Get(ctx context.Context, key string) (io.ReadCloser, error) { return s.driver.Get(ctx, key) } // Delete entfernt das Objekt und meldet dessen Groesse als negatives Delta // (Pruefung 4) — dafuer muss der Aufrufer die Groesse kennen (z.B. aus // file_revisions.size_bytes, FDN-02), da Delete selbst die Groesse eines // bereits geloeschten Objekts nicht mehr ermitteln kann. func (s *Service) Delete(ctx context.Context, key string, sizeBytes int64) error { if err := s.driver.Delete(ctx, key); err != nil { return err } if err := s.usage.Report(ctx, s.tenantSlug, UsageMetric, -sizeBytes); err != nil { return fmt.Errorf("storage: objekt geloescht, aber nutzungsmeldung fehlgeschlagen: %w", err) } return nil } func (s *Service) SignedURL(ctx context.Context, key string, ttl time.Duration) (string, error) { return s.driver.SignedURL(ctx, key, ttl) }