Documentation
¶
Overview ¶
Package filefield is the runtime behind storage-backed model fields (types.File and types.Image): the code `gombit generate` writes for a resource with such a field calls it to grant uploads for the field, accept an uploaded file into a record, and describe it on reads.
A field's value is an object key in App.Storage(). Its Policy (the model's `storage` tag) is the prefix the field owns, the largest file, and the accepted types. Files are owned through storage/claims: an upload grant claims its key (pending), and a record takes a key only for an upload that passes the policy (Accept: upload.Confirm, which checks the bytes) and whose claim its transaction holds (claims.CreateWith), so a client cannot attach a file that was not uploaded for the field, or another record's file. The column's unique index backs that up. Uploads never attached stay pending until claims.Sweep removes them.
Index ¶
- Constants
- Variables
- func Accept(ctx context.Context, store storage.Storage, cl upload.Claimer, key string, ...) error
- func Claims(db *gorm.DB, store storage.Storage, log *zap.Logger) *claims.Claims
- func ForEach(ctx context.Context, n int, fn func(ctx context.Context, i int) error) error
- func KeyOf[T ~string](v *T) string
- func MapCreateError(ctx context.Context, err error, conflict, op string) error
- func MapError(ctx context.Context, err error) error
- func Policy(tag string, kind field.Kind, defaultPrefix string) (upload.Policy, error)
- type FileInfo
- type UploadGrant
- type UploadGrantRequest
Constants ¶
const DefaultMaxBytes = 10 << 20
DefaultMaxBytes is a field's largest file unless its tag says otherwise.
const LinkTTL = 15 * time.Minute
LinkTTL is how long the signed URL of a private file in a read lives.
const MaxKeyBytes = claims.MaxKeyLen
MaxKeyBytes bounds a file column (a generated key is the prefix and 32 hex digits): it keeps the column's unique index within MySQL's limit, and is the longest key a claim holds (claims.MaxKeyLen).
const ResolveConcurrency = 8
ResolveConcurrency bounds how many rows' files a list resolves at once.
Variables ¶
var ImageTypes = []string{"image/png", "image/jpeg", "image/gif", "image/webp"}
ImageTypes are the media types an image field accepts unless its tag says otherwise: the raster formats browsers display and http.DetectContentType recognizes (never SVG, which can carry script).
Functions ¶
func Accept ¶
func Accept(ctx context.Context, store storage.Storage, cl upload.Claimer, key string, p upload.Policy) error
Accept checks that key may become the value of a field with policy p in a record: nothing for no key; otherwise an upload that passes p (upload.Confirm under cl: under p's prefix, stored, within the size, of an accepted type by its bytes). A file that fails is deleted, but only while its claim is pending: never another record's file. Whether this record may take the file is decided when its transaction holds the key (claims.CreateWith fails with claims.ErrNotPending for a file another record holds, or an upload that expired).
func Claims ¶
Claims is the claims the generated handlers own their files through, over db and store, with failures to delete a released file logged to log.
func ForEach ¶
ForEach runs fn for i in [0, n), at most ResolveConcurrency at a time, waits for all of them, and returns the first error (after which the rest see ctx canceled and are not started). The generated list uses it to resolve its rows' files in parallel rather than one storage request after another.
func MapCreateError ¶
MapCreateError maps the error of creating a record with files (claims.CreateWith): a file it cannot take is MapError's conflict; anything else is the database's (database.MapPersistError, with conflict and op as there).
func MapError ¶
MapError maps an error of this package (or of upload, storage and claims) to a D10 error for a handler.
func Policy ¶
Policy parses a field's `storage` tag ("prefix=docs/file/;max_bytes=5242880; types=application/pdf,image/png") into its upload policy. kind is field.File or field.Image (which defaults to ImageTypes; a file field to any type); defaultPrefix is used when the tag names none. Unknown keys are errors, so a typo does not silently loosen a limit.
Types ¶
type FileInfo ¶
type FileInfo struct {
// Key identifies the file; send it back to keep the file on a write.
Key string `json:"key" doc:"The file's key; send it back to keep the file."`
// Filename is the name it was uploaded with.
Filename string `json:"filename,omitempty" doc:"The name the file was uploaded with."`
// Size is its length in bytes.
Size int64 `json:"size" doc:"The file's length in bytes."`
// ContentType is its media type.
ContentType string `json:"content_type,omitempty" doc:"The file's media type."`
// URL downloads it: permanent for a public file, signed and short-lived
// (LinkTTL) otherwise; empty when the store has no URLs.
URL string `json:"url,omitempty" doc:"Where to download the file; a signed URL expires."`
// Missing is true when the record names a file the store no longer has.
Missing bool `json:"missing,omitempty" doc:"The record names a file the store no longer has."`
}
FileInfo is a file as a read returns it.
type UploadGrant ¶
type UploadGrant struct {
Key string `json:"key" doc:"The file's key; submit it as the field's value once uploaded."`
Upload storage.UploadRequest `json:"upload" doc:"Send the file's bytes with this request, before it expires."`
}
UploadGrant is a granted upload as the API returns it: the key to submit as the field's value, and the request that uploads the file.
func Authorize ¶
func Authorize(ctx context.Context, store storage.Storage, cl upload.Claimer, p upload.Policy, r UploadGrantRequest) (UploadGrant, error)
Authorize grants the upload of one file for a field with policy p (upload.Authorize), its key claimed in cl: the client sends the returned request, then submits the grant's key as the field's value.
type UploadGrantRequest ¶
type UploadGrantRequest struct {
Size int64 `json:"size" minimum:"0" doc:"The file's exact length in bytes."`
ContentType string `json:"content_type" doc:"The file's media type."`
Filename string `json:"filename,omitempty" doc:"The file's name, kept for display."`
}
UploadGrantRequest is the body of a request for an upload grant.