storage

package
v0.23.1 Latest Latest
Warning

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

Go to latest
Published: May 14, 2026 License: Apache-2.0 Imports: 35 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrUnsupportedStorageProvider = errors.New("unsupported storage provider")
View Source
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 NewProxyMiddleware(service storage.Service, acl storage.FileACL) app.Middleware

func NewResource

func NewResource(
	db orm.DB,
	service storage.Service,
	claimStore store.ClaimStore,
	partStore store.UploadPartStore,
	cfg *config.StorageConfig,
) api.Resource

func NewService

func NewService(cfg *config.StorageConfig, appCfg *config.AppConfig) (storage.Service, error)

Types

type AbortUploadParams added in v0.23.0

type AbortUploadParams struct {
	api.P

	ClaimID string `json:"claimId" validate:"required"`
}

type CompleteUploadParams added in v0.23.0

type CompleteUploadParams struct {
	api.P

	ClaimID string `json:"claimId" validate:"required"`
}

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

type Resource struct {
	api.Resource
	// contains filtered or unexported fields
}

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:

  1. validate the declared size against the configured cap;
  2. compute the part plan from the backend's authoritative PartSize;
  3. INSERT the claim (status='pending') first so a backend failure leaves no orphan multipart session;
  4. 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

type UploadPartResult struct {
	PartNumber int   `json:"partNumber"`
	Size       int64 `json:"size"`
}

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.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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