Documentation
¶
Index ¶
- Variables
- func NewProxyMiddleware(service storage.Service, acl storage.FileACL) app.Middleware
- func NewResource(db orm.DB, service storage.Service, claimStore store.ClaimStore, ...) api.Resource
- func NewService(cfg *config.StorageConfig, appCfg *config.AppConfig) (storage.Service, error)
- type AbortUploadParams
- type CompleteUploadParams
- type CompleteUploadResult
- type InitUploadParams
- type InitUploadResult
- type ProxyMiddleware
- type Resource
- func (r *Resource) AbortUpload(ctx fiber.Ctx, principal *security.Principal, params AbortUploadParams) error
- func (r *Resource) CompleteUpload(ctx fiber.Ctx, principal *security.Principal, params CompleteUploadParams) error
- func (r *Resource) InitUpload(ctx fiber.Ctx, principal *security.Principal, params InitUploadParams) error
- func (r *Resource) UploadPart(ctx fiber.Ctx, principal *security.Principal, params UploadPartParams) error
- type UploadPartParams
- type UploadPartResult
Constants ¶
This section is empty.
Variables ¶
var ErrUnsupportedStorageProvider = errors.New("unsupported storage provider")
var Module = fx.Module( "vef:storage", fx.Provide( fx.Annotate( NewService, fx.OnStart(func(ctx context.Context, service storage.Service) error { if initializer, ok := service.(contract.Initializer); ok { if err := initializer.Init(ctx); err != nil { return fmt.Errorf("failed to initialize storage service: %w", err) } } return nil }), ), fx.Annotate( NewResource, fx.ResultTags(`group:"vef:api:resources"`), ), fx.Annotate( NewProxyMiddleware, fx.ResultTags(`group:"vef:app:middlewares"`), ), newDefaultFileACL, newDefaultURLKeyMapper, ), migration.Module, store.Module, worker.Module, )
Functions ¶
func NewProxyMiddleware ¶
func NewResource ¶
func NewResource( db orm.DB, service storage.Service, claimStore store.ClaimStore, partStore store.UploadPartStore, cfg *config.StorageConfig, ) api.Resource
func NewService ¶
Types ¶
type AbortUploadParams ¶ added in v0.23.0
type CompleteUploadParams ¶ added in v0.23.0
type CompleteUploadResult ¶ added in v0.23.0
type CompleteUploadResult struct {
storage.ObjectInfo
OriginalFilename string `json:"originalFilename"`
}
CompleteUploadResult bundles the backend ObjectInfo with the framework-tracked OriginalFilename. Returning a wrapper rather than the bare ObjectInfo keeps backend abstractions clean of framework concepts while still giving callers a single response shape that covers everything they need to render the upload.
type InitUploadParams ¶ added in v0.23.0
type InitUploadParams struct {
api.P
Filename string `json:"filename" validate:"required,max=255"`
Size int64 `json:"size" validate:"required,min=1"`
ContentType string `json:"contentType" validate:"max=127"`
Public bool `json:"public"`
}
InitUploadParams declares an upload intent. Every upload goes through the chunked protocol — small files simply end up with PartCount=1. Size is required so the framework can compute the part plan and validate against the configured upload cap before opening any backend session. ContentType is persisted onto the final object; Public controls the key prefix.
type InitUploadResult ¶ added in v0.23.0
type InitUploadResult struct {
Key string `json:"key"`
ClaimID string `json:"claimId"`
UploadID string `json:"uploadId"`
OriginalFilename string `json:"originalFilename"`
PartSize int64 `json:"partSize"`
PartCount int `json:"partCount"`
ExpiresAt time.Time `json:"expiresAt"`
}
InitUploadResult tells the client how to deliver the parts. The client uploads each part via the upload_part action (multipart/form-data proxied through the framework) and finalizes with complete_upload. OriginalFilename is the client-supplied filename echoed back; the framework persists it on the claim row, not in backend user-metadata, so callers can rely on it independent of the storage backend.
type ProxyMiddleware ¶
type ProxyMiddleware struct {
// contains filtered or unexported fields
}
func (*ProxyMiddleware) Apply ¶
func (p *ProxyMiddleware) Apply(router fiber.Router)
func (*ProxyMiddleware) Name ¶
func (*ProxyMiddleware) Name() string
func (*ProxyMiddleware) Order ¶
func (*ProxyMiddleware) Order() int
type Resource ¶
func (*Resource) AbortUpload ¶ added in v0.23.0
func (r *Resource) AbortUpload(ctx fiber.Ctx, principal *security.Principal, params AbortUploadParams) error
AbortUpload cancels an in-flight upload. The handler aborts the backend multipart session, deletes any object bytes the backend may have published, then in a single transaction drops the part rows and the claim row. AbortMultipart and DeleteObject are both treated idempotently — retrying abort_upload on a partially-cleaned state still ends with the claim row removed.
func (*Resource) CompleteUpload ¶ added in v0.23.0
func (r *Resource) CompleteUpload(ctx fiber.Ctx, principal *security.Principal, params CompleteUploadParams) error
CompleteUpload finalizes a chunked upload. The handler reads the recorded parts from the database (clients never replay ETags themselves), verifies the part count matches the original plan, instructs the backend to assemble the object, then atomically marks the claim 'uploaded' and clears its part rows.
Idempotency: a retried complete_upload that arrives after the backend session is already closed surfaces ErrUploadSessionNotFound; the handler then re-stats the object to confirm it exists and commits the same MarkUploaded + DeleteByClaim transaction so the claim still ends in a consumable state.
func (*Resource) InitUpload ¶ added in v0.23.0
func (r *Resource) InitUpload(ctx fiber.Ctx, principal *security.Principal, params InitUploadParams) error
InitUpload opens an upload session. Every upload — including small files that end up with a single part — flows through the same init → upload_part → complete protocol; this keeps the client and server logic uniform regardless of file size.
The flow:
- validate the declared size against the configured cap;
- compute the part plan from the backend's authoritative PartSize;
- INSERT the claim (status='pending') first so a backend failure leaves no orphan multipart session;
- open the backend multipart session and bind its UploadID to the claim row (best-effort cleanup on failure).
If the backend does not implement Multipart, init_upload is rejected outright — there is no fallback path in the unified protocol.
func (*Resource) UploadPart ¶ added in v0.23.0
func (r *Resource) UploadPart(ctx fiber.Ctx, principal *security.Principal, params UploadPartParams) error
UploadPart proxies a single multipart part through the framework to the backend. The handler validates ownership, the claim's pending status, and the part-number range before opening the backend stream; a successful PutPart is then mirrored to the upload_part table so complete_upload can drive the assemble step from the database (clients never round-trip ETags themselves).
type UploadPartParams ¶ added in v0.23.0
type UploadPartParams struct {
api.P
File *multipart.FileHeader
ClaimID string `json:"claimId" validate:"required"`
PartNumber int `json:"partNumber" validate:"required,min=1"`
}
UploadPartParams accepts multipart/form-data carrying a single part of an in-progress chunked upload. ClaimID and PartNumber identify which slot of which session the bytes belong to; the file payload is streamed through to the backend's PutPart.
type UploadPartResult ¶ added in v0.23.0
UploadPartResult echoes the part position and recorded byte count. The backend ETag is intentionally NOT returned to the client: it is persisted server-side on the upload_part row so complete_upload can reconstruct the parts list without trusting client state.