Files
Aether/backend/internal/files/quota.go
T
HoneyandClaude Opus 5 31a027c93a feat(aether): initial commit – self-hosted Cloud, Phasen 1–7
Go-Backend (chi, pgx, golang-migrate) + React/TS-Frontend als PWA.
Enthalten: Auth inkl. OIDC, Dateien mit Versionen und Papierkorb,
Freigaben (Links + intern), WebDAV, Gruppenordner, Admin/Theming,
Volltextsuche mit OCR, eigener PDF-Betrachter und WOPI-Office
(Collabora/OnlyOffice).

Nicht im Repo: deploy/.env (Sitzungsschlüssel, DB- und Admin-Passwort)
sowie alle Daten- und Build-Verzeichnisse – siehe .gitignore.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-24 09:25:36 +02:00

64 lines
1.8 KiB
Go
Raw 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 files
import (
"context"
"errors"
"fmt"
"io"
"github.com/google/uuid"
)
// ErrQuotaExceeded wird gemeldet, sobald ein Upload das Speicherkontingent des
// Nutzers überschreitet.
var ErrQuotaExceeded = errors.New("storage quota exceeded")
// quotaReader reicht Daten durch und bricht ab, sobald mehr als `remaining`
// Bytes gelesen wurden. Nötig, weil Uploads gestreamt werden: die tatsächliche
// Größe steht erst am Ende fest, und bis dahin wären die Bytes längst auf der
// Platte. So bricht der Schreibvorgang bereits beim Überschreiten ab statt
// erst hinterher zu prüfen.
type quotaReader struct {
r io.Reader
remaining int64
}
func newQuotaReader(r io.Reader, remaining int64) *quotaReader {
if remaining < 0 {
remaining = 0
}
return &quotaReader{r: r, remaining: remaining}
}
func (q *quotaReader) Read(p []byte) (int, error) {
n, err := q.r.Read(p)
q.remaining -= int64(n)
if q.remaining < 0 {
return n, ErrQuotaExceeded
}
return n, err
}
// RemainingQuota liefert, wie viele Bytes der Nutzer noch schreiben darf, und
// ob sein Kontingent unbegrenzt ist.
//
// `allowance` sind Bytes, die durch diesen Vorgang frei werden – beim
// Überschreiben einer Datei zählt die alte Fassung nicht mehr zum Verbrauch,
// sonst schlüge das Ersetzen einer Datei durch eine gleich große fehl.
//
// Ein Kontingent <= 0 gilt als unbegrenzt.
func (s *Store) RemainingQuota(ctx context.Context, userID uuid.UUID, quotaBytes, allowance int64) (int64, bool, error) {
if quotaBytes <= 0 {
return 0, true, nil
}
used, err := s.UsedBytes(ctx, userID)
if err != nil {
return 0, false, fmt.Errorf("read used bytes: %w", err)
}
remaining := quotaBytes - used + allowance
if remaining < 0 {
remaining = 0
}
return remaining, false, nil
}