Help us shape the future of Go! Take the 2026 Go Developer Survey

storage

package
v0.30.0 Latest Latest
Warning

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

Go to latest
Published: Oct 19, 2026 License: MIT Imports: 23 Imported by: 2

Documentation

Overview

Package storage reads and writes files on disks: the local filesystem (through os.Root, so paths can never escape the disk) and memory (tests); S3-compatible storage lives in the drivers/s3 module.

disk, err := storage.NewLocal("storage/app/public", "/storage")
path, err := storage.PutUploaded(ctx, disk, fileHeader, "avatars", storage.Images(2<<20))
url := disk.URL(path)

Every disk implements Disk; Clean validates paths, Handler serves a disk over HTTP and TemporaryURL signs links to private files. Streaming, sniffed uploads live in package upload.

See https://github.com/AlexGalhardo/vukem/blob/main/docs/subsystems.md#storage.

Example
package main

import (
	"context"
	"fmt"

	"github.com/AlexGalhardo/vukem/storage"
)

func main() {
	ctx := context.Background()

	// Memory is for tests; apps use storage.NewLocal or drivers/s3.
	disk := storage.NewMemory("/storage")

	_ = storage.PutBytes(ctx, disk, "avatars/1.txt", []byte("hello"))

	data, _ := storage.Get(ctx, disk, "avatars/1.txt")
	paths, _ := disk.List(ctx, "avatars")
	fmt.Println(string(data), paths, disk.URL("avatars/1.txt"))
}
Output:
hello [avatars/1.txt] /storage/avatars/1.txt

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrInvalidPath = errors.New("storage: invalid path")

ErrInvalidPath rejects absolute paths, "..", backslashes and empty names.

View Source
var ErrNotFound = fs.ErrNotExist

ErrNotFound is returned (wrapped) for missing files.

View Source
var ErrUnhealthy = errors.New("storage: disk is not healthy")

ErrUnhealthy reports that a disk did not complete a round trip. Every error Check returns wraps it, and none of them wraps the driver's own: an S3 error carries the endpoint, the bucket and sometimes the access key, and the error a health handler receives is the one a naive handler puts in the response body.

Functions

func Check added in v0.30.0

func Check(ctx context.Context, disk Disk) error

Check reports whether a disk can actually store a file: it writes a small object under a unique key, reads it back, compares the bytes and deletes it. Use it in a readiness check (App.AddHealthCheck), never in a liveness probe — it does real I/O against the remote.

The round trip is the point. The obvious check is whether a known object exists, and that one passes when nothing works: given the wrong credentials several S3 implementations answer "object does not exist" rather than refusing, so an existence check reports a healthy disk while no upload can succeed. Only a write distinguishes the two, and reading the bytes back also catches a disk that is up and returning the wrong object.

The delete runs even when ctx is already done, through context.WithoutCancel, so a probe the client abandoned does not leave an object behind on every request. Errors wrap ErrUnhealthy and never the driver's error.

func Clean

func Clean(p string) (string, error)

Clean validates a relative path and returns it normalized.

Example
package main

import (
	"errors"
	"fmt"

	"github.com/AlexGalhardo/vukem/storage"
)

func main() {
	p, err := storage.Clean("a/./b.txt")
	fmt.Println(p, err)

	_, err = storage.Clean("../etc/passwd")
	fmt.Println(errors.Is(err, storage.ErrInvalidPath))
}
Output:
a/b.txt <nil>
true

func Get

func Get(ctx context.Context, d Disk, p string) ([]byte, error)

Get reads a whole file.

func Handler

func Handler(d Disk, signer *signed.Signer) http.Handler

Handler serves a disk's files under a URL prefix (mount it with http.StripPrefix). Directory listings, dotfiles and files under dot directories are never served; responses carry a sandbox CSP. Pass a Signer to require signed URLs (private files, TemporaryURL).

func PutBytes

func PutBytes(ctx context.Context, d Disk, p string, data []byte) error

PutBytes writes data to p.

func PutUploaded

func PutUploaded(ctx context.Context, d Disk, fh *multipart.FileHeader, dir string, rules UploadRules) (string, error)

PutUploaded stores an uploaded file under dir with a random name and an extension derived from the detected type, after checking its size and type. It returns the stored path. The client's file name is never used.

func TemporaryURL

func TemporaryURL(signer *signed.Signer, prefix, p string, ttl time.Duration) (string, error)

TemporaryURL signs a link to p, served by Handler(disk, signer) mounted at prefix, valid for ttl.

Types

type Disk

type Disk interface {
	Put(ctx context.Context, p string, r io.Reader) error
	Open(ctx context.Context, p string) (io.ReadCloser, error)
	Exists(ctx context.Context, p string) (bool, error)
	Delete(ctx context.Context, p string) error
	// List returns the file paths under dir (recursively), sorted.
	List(ctx context.Context, dir string) ([]string, error)
	// URL is the public URL of p ("" for private disks).
	URL(p string) string
}

Disk stores files under slash-separated relative paths.

type Local

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

Local is a disk on the local filesystem. Every operation goes through an os.Root, so symlinks and ".." cannot leave the directory.

func NewLocal

func NewLocal(dir, baseURL string) (*Local, error)

NewLocal opens (creating it if needed) dir as a disk; baseURL prefixes public URLs ("" for a private disk). Close it on shutdown.

func (*Local) Close

func (l *Local) Close() error

Close releases the directory handle.

func (*Local) Delete

func (l *Local) Delete(_ context.Context, p string) error

Delete implements Disk (missing files are not an error).

func (*Local) Exists

func (l *Local) Exists(_ context.Context, p string) (bool, error)

Exists implements Disk.

func (*Local) List

func (l *Local) List(_ context.Context, dir string) ([]string, error)

List implements Disk.

func (*Local) Open

func (l *Local) Open(_ context.Context, p string) (io.ReadCloser, error)

Open implements Disk.

func (*Local) Put

func (l *Local) Put(_ context.Context, p string, r io.Reader) error

Put implements Disk. The file is written to a hidden temporary name (".name.tmp-…", neither listed nor served) and renamed, so readers never see partial content.

func (*Local) URL

func (l *Local) URL(p string) string

URL implements Disk.

type Memory

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

Memory is an in-memory disk for tests.

func NewMemory

func NewMemory(base string) *Memory

NewMemory returns an empty memory disk; base prefixes URLs ("" = private).

func (*Memory) Delete

func (m *Memory) Delete(_ context.Context, p string) error

Delete implements Disk (missing files are not an error).

func (*Memory) Exists

func (m *Memory) Exists(_ context.Context, p string) (bool, error)

Exists implements Disk.

func (*Memory) List

func (m *Memory) List(_ context.Context, dir string) ([]string, error)

List implements Disk.

func (*Memory) Open

func (m *Memory) Open(_ context.Context, p string) (io.ReadCloser, error)

Open implements Disk.

func (*Memory) Put

func (m *Memory) Put(_ context.Context, p string, r io.Reader) error

Put implements Disk.

func (*Memory) URL

func (m *Memory) URL(p string) string

URL implements Disk.

type UploadRules

type UploadRules struct {
	// MaxSize in bytes (required).
	MaxSize int64
	// Types are allowed MIME types, detected from the content (not the
	// client's Content-Type or file name) (required: an empty list is a
	// configuration error, never "any type").
	Types []string
}

UploadRules restrict PutUploaded.

func Images

func Images(maxSize int64) UploadRules

Images allows JPEG, PNG, GIF and WebP up to maxSize bytes.

Directories

Path Synopsis
Package storagetest is the conformance suite every storage.Disk passes (local and memory in core, S3 in drivers/s3).
Package storagetest is the conformance suite every storage.Disk passes (local and memory in core, S3 in drivers/s3).

Jump to

Keyboard shortcuts

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