package storage import ( "context" "fmt" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/s3" ) // UsageCounter misst den TATSÄCHLICHEN Speicherverbrauch eines // Postfachs (ARC-09) durch reales Auflisten der zugehörigen Objekte im // physisch getrennten Mandanten-Bucket (ARC-06) unter dem // ARC-04-Postfach-Präfix — kein separat gepflegter Zählerstand, der // von der tatsächlichen Ablage abweichen könnte. type UsageCounter struct { admin *s3.Client } func NewUsageCounter(admin *s3.Client) *UsageCounter { return &UsageCounter{admin: admin} } // UsageBytes summiert die reale Objektgröße aller unter // ArchiveMailboxPrefix(mailbox) abgelegten Objekte im Bucket von // tenantSlug (ARC-06: BucketNameForTenant). Erfüllt strukturell // quota.UsageProvider (ARC-09), ohne dass dieses Paket quota // importieren müsste. func (u *UsageCounter) UsageBytes(ctx context.Context, tenantSlug, mailbox string) (int64, error) { bucket := BucketNameForTenant(tenantSlug) prefix := ArchiveMailboxPrefix(mailbox) var total int64 var continuationToken *string for { out, err := u.admin.ListObjectsV2(ctx, &s3.ListObjectsV2Input{ Bucket: aws.String(bucket), Prefix: aws.String(prefix), ContinuationToken: continuationToken, }) if err != nil { return 0, fmt.Errorf("storage: postfach-verbrauch auflisten: %w", err) } for _, obj := range out.Contents { if obj.Size != nil { total += *obj.Size } } if out.IsTruncated == nil || !*out.IsTruncated { break } continuationToken = out.NextContinuationToken } return total, nil }