Documentation
¶
Overview ¶
Package storage provides a small abstraction over file-like objects stored in local, cloud, and remote backends.
The package is Go-native in API shape: explicit drivers, named disks, and small interfaces with documented semantics.
Preferred construction paths:
- direct use: call a driver module's New(ctx, Config)
- named disks: pass typed driver configs to storage.New
- single disk from generic orchestration: pass a typed driver config to Build
Core semantics:
- List is one-level and non-recursive.
- List with an empty path lists from the disk root or prefix root.
- URL returns a usable access URL when the driver supports it.
- Unsupported operations should return ErrUnsupported.
- Missing objects should be detectable with errors.Is(err, ErrNotFound).
- Path normalization rejects traversal attempts with ErrForbidden.
Driver registration is opt-in. Import the driver modules you need for manager-based construction, or call driver constructors directly.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ( ErrNotFound = storagecore.ErrNotFound ErrForbidden = storagecore.ErrForbidden ErrUnsupported = storagecore.ErrUnsupported )
Functions ¶
func JoinPrefix ¶
JoinPrefix combines a disk prefix with a path using slash separators. @group Paths
Example: join a disk prefix and path
fmt.Println(storage.JoinPrefix("assets", "logo.svg"))
// Output: assets/logo.svg
func NormalizePath ¶
NormalizePath cleans a user path, normalizes separators, and rejects attempts to escape the disk root or prefix root.
The empty string and root-like inputs normalize to the logical root. @group Paths
Example: normalize a user path
p, _ := storage.NormalizePath(" /avatars//user-1.png ")
fmt.Println(p)
// Output: avatars/user-1.png
func RegisterDriver ¶
func RegisterDriver(name string, factory DriverFactory)
RegisterDriver makes a driver available to the Manager. It panics on duplicate registrations. @group Manager
Example: register a custom driver
storage.RegisterDriver("memory", func(ctx context.Context, cfg storage.ResolvedConfig) (storage.Storage, error) {
return nil, nil
})
Types ¶
type Config ¶
type Config struct {
Default DiskName
Disks map[DiskName]DriverConfig
}
Config defines named disks using typed driver configs. @group Manager
Example: define manager config
cfg := storage.Config{
Default: "local",
Disks: map[storage.DiskName]storage.DriverConfig{
"local": localstorage.Config{Root: "/tmp/storage-manager"},
},
}
_ = cfg
type ContextStorage ¶
type ContextStorage interface {
// GetContext reads the object at path using the caller-provided context.
//
// Example: read an object with a timeout
//
// disk, _ := storage.Build(localstorage.Config{
// Root: "/tmp/storage-get-context",
// })
// _ = disk.Put("docs/readme.txt", []byte("hello"))
//
// ctx, cancel := context.WithTimeout(context.Background(), time.Second)
// defer cancel()
//
// cs := disk.(storage.ContextStorage)
// data, _ := cs.GetContext(ctx, "docs/readme.txt")
// fmt.Println(string(data))
// // Output: hello
GetContext(ctx context.Context, p string) ([]byte, error)
// PutContext writes an object at path using the caller-provided context.
PutContext(ctx context.Context, p string, contents []byte) error
// DeleteContext removes the object at path using the caller-provided context.
DeleteContext(ctx context.Context, p string) error
// StatContext returns the entry at path using the caller-provided context.
StatContext(ctx context.Context, p string) (Entry, error)
// ExistsContext reports whether an object exists at path using the caller-provided context.
ExistsContext(ctx context.Context, p string) (bool, error)
// ListContext returns the immediate children under path using the caller-provided context.
ListContext(ctx context.Context, p string) ([]Entry, error)
// WalkContext visits entries recursively using the caller-provided context.
WalkContext(ctx context.Context, p string, fn func(Entry) error) error
// CopyContext copies the object at src to dst using the caller-provided context.
CopyContext(ctx context.Context, src, dst string) error
// MoveContext moves the object at src to dst using the caller-provided context.
MoveContext(ctx context.Context, src, dst string) error
// URLContext returns a usable access URL using the caller-provided context.
URLContext(ctx context.Context, p string) (string, error)
}
ContextStorage exposes context-aware storage operations for cancellation and deadlines. Use Storage for the common path and type-assert to ContextStorage when you need caller-provided context. @group Context
type DiskName ¶
type DiskName = storagecore.DiskName
DiskName is a typed identifier for configured disks. @group Core
Example: declare a disk name
const uploads storage.DiskName = "uploads" fmt.Println(uploads) // Output: uploads
type DriverConfig ¶
type DriverConfig interface {
DriverName() string
ResolvedConfig() ResolvedConfig
}
DriverConfig is implemented by typed driver configs such as local.Config or s3storage.Config. It is the public config boundary for Manager and Build. @group Construction
Example: pass a typed driver config
var cfg storage.DriverConfig = localstorage.Config{
Root: "/tmp/storage-config",
}
_ = cfg
type DriverFactory ¶
type DriverFactory func(ctx context.Context, cfg ResolvedConfig) (Storage, error)
DriverFactory constructs a Storage for a given normalized disk configuration. @group Construction
Example: declare a driver factory
factory := storage.DriverFactory(func(ctx context.Context, cfg storage.ResolvedConfig) (storage.Storage, error) {
return nil, nil
})
_ = factory
type Entry ¶
type Entry = storagecore.Entry
Entry represents an item returned by List.
Path is relative to the storage namespace, not an OS-native path. Directory-like entries are listing artifacts, not a promise of POSIX-style storage semantics. @group Core
Example: inspect a listed entry
entry := storage.Entry{
Path: "docs/readme.txt",
Size: 5,
IsDir: false,
}
fmt.Println(entry.Path, entry.IsDir)
// Output: docs/readme.txt false
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager holds named storage disks. @group Manager
Example: keep a manager for later disk lookups
mgr, _ := storage.New(storage.Config{
Default: "local",
Disks: map[storage.DiskName]storage.DriverConfig{
"local": localstorage.Config{Root: "/tmp/storage-manager"},
},
})
_ = mgr
func New ¶
New constructs a Manager and eagerly initializes all disks. @group Manager
Example: build a manager with named disks
mgr, _ := storage.New(storage.Config{
Default: "local",
Disks: map[storage.DiskName]storage.DriverConfig{
"local": localstorage.Config{Root: "/tmp/storage-local"},
"assets": localstorage.Config{Root: "/tmp/storage-assets", Prefix: "public"},
},
})
_ = mgr
func (*Manager) Default ¶
Default returns the default disk or panics if misconfigured. @group Manager
Example: get the default disk
mgr, _ := storage.New(storage.Config{
Default: "local",
Disks: map[storage.DiskName]storage.DriverConfig{
"local": localstorage.Config{Root: "/tmp/storage-default"},
},
})
fs := mgr.Default()
fmt.Println(fs != nil)
// Output: true
func (*Manager) Disk ¶
Disk returns a named disk or an error if it does not exist. @group Manager
Example: get a named disk
mgr, _ := storage.New(storage.Config{
Default: "local",
Disks: map[storage.DiskName]storage.DriverConfig{
"local": localstorage.Config{Root: "/tmp/storage-default"},
"uploads": localstorage.Config{Root: "/tmp/storage-uploads"},
},
})
fs, _ := mgr.Disk("uploads")
fmt.Println(fs != nil)
// Output: true
type ResolvedConfig ¶
type ResolvedConfig = storagecore.ResolvedConfig
ResolvedConfig is the normalized internal config passed to registered drivers. Users should prefer typed driver configs and treat this as registry adapter glue, not the primary construction API. @group Construction
Example: inspect a resolved config in a driver factory
factory := storage.DriverFactory(func(ctx context.Context, cfg storage.ResolvedConfig) (storage.Storage, error) {
fmt.Println(cfg.Driver)
// Output: memory
return nil, nil
})
_, _ = factory(context.Background(), storage.ResolvedConfig{Driver: "memory"})
type Storage ¶
type Storage interface {
// Get reads the object at path.
//
// Example: read an object
//
// disk, _ := storage.Build(localstorage.Config{
// Root: "/tmp/storage-get",
// })
// _ = disk.Put("docs/readme.txt", []byte("hello"))
//
// data, _ := disk.Get("docs/readme.txt")
// fmt.Println(string(data))
// // Output: hello
Get(p string) ([]byte, error)
// Put writes an object at path, overwriting any existing object.
//
// Example: write an object
//
// disk, _ := storage.Build(localstorage.Config{
// Root: "/tmp/storage-put",
// })
// _ = disk.Put("docs/readme.txt", []byte("hello"))
// fmt.Println("stored")
// // Output: stored
Put(p string, contents []byte) error
// Delete removes the object at path.
//
// Example: delete an object
//
// disk, _ := storage.Build(localstorage.Config{
// Root: "/tmp/storage-delete",
// })
// _ = disk.Put("docs/readme.txt", []byte("hello"))
// _ = disk.Delete("docs/readme.txt")
//
// ok, _ := disk.Exists("docs/readme.txt")
// fmt.Println(ok)
// // Output: false
Delete(p string) error
// Stat returns the entry at path.
//
// Example: stat an object
//
// disk, _ := storage.Build(localstorage.Config{
// Root: "/tmp/storage-stat",
// })
// _ = disk.Put("docs/readme.txt", []byte("hello"))
//
// entry, _ := disk.Stat("docs/readme.txt")
// fmt.Println(entry.Path, entry.Size)
// // Output: docs/readme.txt 5
Stat(p string) (Entry, error)
// Exists reports whether an object exists at path.
//
// Example: check for an object
//
// disk, _ := storage.Build(localstorage.Config{
// Root: "/tmp/storage-exists",
// })
// _ = disk.Put("docs/readme.txt", []byte("hello"))
//
// ok, _ := disk.Exists("docs/readme.txt")
// fmt.Println(ok)
// // Output: true
Exists(p string) (bool, error)
// List returns the immediate children under path.
//
// Example: list a directory
//
// disk, _ := storage.Build(localstorage.Config{
// Root: "/tmp/storage-list",
// })
// _ = disk.Put("docs/readme.txt", []byte("hello"))
//
// entries, _ := disk.List("docs")
// fmt.Println(entries[0].Path)
// // Output: docs/readme.txt
List(p string) ([]Entry, error)
// Walk visits entries recursively when the backend supports it.
//
// Example: walk a backend when supported
//
// disk, _ := storage.Build(localstorage.Config{
// Root: "/tmp/storage-walk",
// })
//
// err := disk.Walk("", func(entry storage.Entry) error {
// fmt.Println(entry.Path)
// return nil
// })
// fmt.Println(errors.Is(err, storage.ErrUnsupported))
// // Output: true
Walk(p string, fn func(Entry) error) error
// Copy copies the object at src to dst.
//
// Example: copy an object
//
// disk, _ := storage.Build(localstorage.Config{
// Root: "/tmp/storage-copy",
// })
// _ = disk.Put("docs/readme.txt", []byte("hello"))
// _ = disk.Copy("docs/readme.txt", "docs/copy.txt")
//
// data, _ := disk.Get("docs/copy.txt")
// fmt.Println(string(data))
// // Output: hello
Copy(src, dst string) error
// Move moves the object at src to dst.
//
// Example: move an object
//
// disk, _ := storage.Build(localstorage.Config{
// Root: "/tmp/storage-move",
// })
// _ = disk.Put("docs/readme.txt", []byte("hello"))
// _ = disk.Move("docs/readme.txt", "docs/archive.txt")
//
// ok, _ := disk.Exists("docs/readme.txt")
// fmt.Println(ok)
// // Output: false
Move(src, dst string) error
// URL returns a usable access URL when the driver supports it.
//
// Example: request an object url
//
// disk, _ := storage.Build(s3storage.Config{
// Bucket: "uploads",
// Region: "us-east-1",
// })
//
// url, _ := disk.URL("docs/readme.txt")
// _ = url
//
// Example: handle unsupported url generation
//
// disk, _ := storage.Build(localstorage.Config{
// Root: "/tmp/storage-url",
// })
//
// _, err := disk.URL("docs/readme.txt")
// fmt.Println(errors.Is(err, storage.ErrUnsupported))
// // Output: true
URL(p string) (string, error)
}
Storage is the public interface for interacting with a storage backend.
Semantics:
- Put overwrites an existing object at the same path.
- List is one-level and non-recursive.
- List with an empty path lists from the disk root or prefix root.
- Walk is recursive.
- URL returns a usable access URL when the driver supports it.
- Copy overwrites the destination object when the backend supports copy semantics.
- Move relocates an object and may be implemented as copy followed by delete.
- Unsupported operations should return ErrUnsupported.
@group Core
Example: use the storage interface
var disk storage.Storage
disk, _ = storage.Build(localstorage.Config{
Root: "/tmp/storage-interface",
})
_ = disk
func Build ¶
func Build(cfg DriverConfig) (Storage, error)
Build constructs a single storage backend from a typed driver config without a Manager. @group Construction
Example: build a single disk
fs, _ := storage.Build(localstorage.Config{
Root: "/tmp/storage-example",
Prefix: "assets",
})
_ = fs
func BuildContext ¶
func BuildContext(ctx context.Context, cfg DriverConfig) (Storage, error)
BuildContext constructs a single storage backend from a typed driver config using the caller-provided context. @group Context
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
driver
|
|
|
dropboxstorage
module
|
|
|
ftpstorage
module
|
|
|
gcsstorage
module
|
|
|
localstorage
module
|
|
|
memorystorage
module
|
|
|
rclonestorage
module
|
|
|
redisstorage
module
|
|
|
s3storage
module
|
|
|
sftpstorage
module
|
|
|
storagecore
module
|
|
|
storagetest
module
|