files

package
v1.1.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 28, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package files is the service / use-case layer. It owns the write path and the consistency logic between storage and metadata; layers above it (api) talk only to this package and never reach storage or metadata directly.

Index

Constants

This section is empty.

Variables

View Source
var ErrChecksumMismatch = errors.New("files: checksum mismatch")

ErrChecksumMismatch is surfaced by a verifying download reader when the stored bytes no longer hash to the recorded checksum (Phase 2 integrity).

View Source
var ErrIdempotencyConflict = errors.New("files: idempotency key conflict")

ErrIdempotencyConflict means an upload with the same Idempotency-Key is still in progress. The api layer maps it to 409 — the client should retry shortly.

View Source
var ErrIdempotencyResultGone = errors.New("files: idempotent result deleted")

ErrIdempotencyResultGone means the file an Idempotency-Key produced has since been deleted. Retrying under the same key can never succeed until the key expires, so the api layer maps it to 410 — the client must pick a new key.

View Source
var ErrInvalidID = errors.New("files: invalid id")

ErrInvalidID is returned when an id is not a well-formed file identifier. The api layer maps it to 400 — a malformed id is a client error, not a 500.

View Source
var ErrNotFound = errors.New("files: not found")

ErrNotFound is returned when no live file matches. It is the api layer's only signal for a 404, keeping storage/metadata sentinels below this seam.

Functions

This section is empty.

Types

type File

type File = metadata.File

File is the service-level view of a stored file, returned to the api layer.

type ListFilter

type ListFilter = metadata.ListFilter

ListFilter narrows a List query. Aliased so the api layer can build filters without importing the metadata package directly.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service orchestrates the object store and the metadata repository.

func New

func New(backend storage.Backend, repo metadata.Repository) *Service

New wires the service to its collaborators.

func (*Service) Delete

func (s *Service) Delete(ctx context.Context, id string) error

Delete soft-deletes the file: the row is stamped deleted_at and immediately vanishes from reads (every read path filters deleted_at is null), while the object is purged asynchronously by GC (PLAN §7). Returns ErrNotFound if the file does not exist.

func (*Service) List

func (s *Service) List(ctx context.Context, filter ListFilter) ([]*File, error)

List returns file records matching the filter, newest first. The metadata repository applies tag containment against the GIN index and keyset pagination by id. A malformed cursor is ErrInvalidID — it must be a file id handed out by a previous page.

func (*Service) Metadata

func (s *Service) Metadata(ctx context.Context, id string) (*File, error)

Metadata returns the record for id, or ErrNotFound.

func (*Service) Open

func (s *Service) Open(ctx context.Context, id string) (*File, io.ReadCloser, error)

Open streams the whole object through this process, verifying the SHA-256 as it reads: the returned reader yields ErrChecksumMismatch at EOF if the stored bytes no longer match the recorded checksum. The caller must Close it.

func (*Service) OpenRange

func (s *Service) OpenRange(ctx context.Context, f *File, offset, length int64) (io.ReadCloser, error)

OpenRange streams a byte range [offset, offset+length) of an already-fetched record through this process — the caller resolves f via Metadata first (it needs the size to validate the range), so no second lookup happens here. Partial reads cannot be checksum-verified against the whole-object hash, so the reader is returned unverified. The caller must Close it.

func (*Service) Presign

func (s *Service) Presign(ctx context.Context, id string, ttl time.Duration) (*File, string, error)

Presign returns the record and a time-limited URL that serves the object directly from the store, offloading the transfer from this process.

func (*Service) UpdateMetadata

func (s *Service) UpdateMetadata(ctx context.Context, id string, tags map[string]any, merge bool) (*File, error)

UpdateMetadata writes tags onto a file's JSONB metadata, merging into the existing object or replacing it wholesale. Returns ErrNotFound if absent.

func (*Service) Upload

func (s *Service) Upload(ctx context.Context, in UploadInput) (*File, error)

Upload streams the body to storage, computing its SHA-256 inline, then commits the metadata row. On a metadata failure the freshly-written object is best-effort deleted; a leftover is reclaimed by GC.

func (*Service) UploadIdempotent

func (s *Service) UploadIdempotent(ctx context.Context, key string, in UploadInput) (f *File, replayed bool, err error)

UploadIdempotent performs an upload guarded by a client-supplied idempotency key. The first call for a key uploads and records the result; a retry returns the original result (replayed=true) instead of creating a duplicate. A retry while the first is still in flight — or whose result has since been deleted — returns ErrIdempotencyConflict (the client should retry shortly).

On the replay/conflict paths the request body is intentionally not read; the HTTP server drains it.

type UploadInput

type UploadInput struct {
	Filename    string
	ContentType string
	Size        int64
	Tags        map[string]any
	Body        io.Reader
}

UploadInput carries the request-derived attributes of an upload. Size is the known content length, or -1 if unknown (resolved from storage after write).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL