objectstorage

package
v9.1.0 Latest Latest
Warning

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

Go to latest
Published: Aug 3, 2026 License: AGPL-3.0 Imports: 32 Imported by: 0

Documentation

Overview

Example
package main

import (
	"context"
	"fmt"

	"github.com/primandproper/platform-go/v9/uploads"
	"github.com/primandproper/platform-go/v9/uploads/objectstorage"
)

func newExampleManager() *objectstorage.Uploader {
	m, err := objectstorage.NewUploadManager(
		context.Background(),

		&objectstorage.Config{BucketName: "example", Provider: objectstorage.MemoryProvider},
	)
	if err != nil {
		panic(err)
	}

	return m
}

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

	if err := uploads.SaveFile(ctx, mgr, "greeting.txt", []byte("hello world")); err != nil {
		panic(err)
	}

	data, err := uploads.ReadFile(ctx, mgr, "greeting.txt")
	if err != nil {
		panic(err)
	}

	fmt.Println(string(data))
}
Output:
hello world

Index

Examples

Constants

View Source
const (
	// FilesystemProvider indicates we'd like to use the filesystem adapter for blob.
	FilesystemProvider = "filesystem"
	// MemoryProvider indicates we'd like to use the memory adapter for blob.
	MemoryProvider = "memory"
	// S3Provider indicates we'd like to use the s3 adapter for blob.
	S3Provider = "s3"
	// GCPCloudStorageProvider indicates we'd like to use the GCP adapter for blob objectstorage.
	GCPCloudStorageProvider = "gcp"
	// R2Provider indicates we'd like to use the Cloudflare R2 adapter for blob.
	R2Provider = "r2"
	// BackblazeB2Provider indicates we'd like to use the Backblaze B2 adapter for blob.
	BackblazeB2Provider = "backblaze_b2"
)

Variables

View Source
var (
	// ErrNilConfig denotes that the provided configuration is nil.
	ErrNilConfig = platformerrors.New("nil config provided")
	// ErrUnknownProvider denotes that the configured provider is not recognized.
	ErrUnknownProvider = platformerrors.New("unknown storage provider")
)

Functions

func RegisterUploadManager

func RegisterUploadManager(i do.Injector)

RegisterUploadManager registers both *Uploader and uploads.UploadManager with the injector. Prerequisite: *Config must be registered (e.g. via uploadscfg.RegisterStorageConfig).

Types

type BackblazeB2Config

type BackblazeB2Config struct {
	ApplicationKeyID string `env:"APPLICATION_KEY_ID" json:"applicationKeyID,omitempty" yaml:"applicationKeyID,omitempty"`
	ApplicationKey   string `env:"APPLICATION_KEY"    json:"applicationKey,omitempty"   yaml:"applicationKey,omitempty"`
	Region           string `env:"REGION"             json:"region,omitempty"           yaml:"region,omitempty"`
	// contains filtered or unexported fields
}

BackblazeB2Config configures a Backblaze B2-based objectstorage provider.

func (*BackblazeB2Config) ValidateWithContext

func (c *BackblazeB2Config) ValidateWithContext(ctx context.Context) error

ValidateWithContext validates the BackblazeB2Config.

type Config

type Config struct {
	FilesystemConfig  *FilesystemConfig         `env:",init"         envPrefix:"FILESYSTEM_"       json:"filesystem,omitempty"          yaml:"filesystem,omitempty"`
	R2Config          *R2Config                 `env:",init"         envPrefix:"R2_"               json:"r2,omitempty"                  yaml:"r2,omitempty"`
	BackblazeB2Config *BackblazeB2Config        `env:",init"         envPrefix:"BACKBLAZE_B2_"     json:"backblazeB2,omitempty"         yaml:"backblazeB2,omitempty"`
	BucketPrefix      string                    `env:"BUCKET_PREFIX" json:"bucketPrefix,omitempty" yaml:"bucketPrefix,omitempty"`
	BucketName        string                    `env:"BUCKET_NAME"   json:"bucketName,omitempty"   yaml:"bucketName,omitempty"`
	Provider          string                    `env:"PROVIDER"      json:"provider,omitempty"     yaml:"provider,omitempty"`
	CircuitBreaker    circuitbreakingcfg.Config `env:",init"         envPrefix:"CIRCUIT_BREAKING_" json:"circuitBreakerConfig,omitzero" yaml:"circuitBreakerConfig,omitempty"`
	// contains filtered or unexported fields
}

Config configures our UploadManager.

func (*Config) ValidateWithContext

func (c *Config) ValidateWithContext(ctx context.Context) error

ValidateWithContext validates the Config. It first canonicalizes Provider (trim + lowercase) so validation, the conditional sub-config rules, and dispatch in selectBucket all agree — otherwise a value like "S3" or " s3 " would fail validation yet dispatch cleanly.

type DirectoryMode

type DirectoryMode os.FileMode

DirectoryMode is a Unix file mode that parses as octal from configuration.

It exists because os.FileMode is a uint32, and every config decoder reads a bare integer in base 10 — so DIRECTORY_MODE=0700 parsed to decimal 700, which is 0o1274: the sticky bit plus a permission set nobody asked for. Every way anyone writes a Unix mode is octal, so that is what this parses.

func (DirectoryMode) FileMode

func (m DirectoryMode) FileMode() os.FileMode

FileMode returns the mode as an os.FileMode.

func (DirectoryMode) MarshalText

func (m DirectoryMode) MarshalText() ([]byte, error)

MarshalText renders the mode as octal, so a round trip through config is stable.

func (*DirectoryMode) UnmarshalText

func (m *DirectoryMode) UnmarshalText(text []byte) error

UnmarshalText parses a mode in octal, with or without a leading "0" or "0o".

type FilesystemConfig

type FilesystemConfig struct {
	RootDirectory string `env:"ROOT_DIRECTORY" json:"rootDirectory,omitempty" yaml:"rootDirectory,omitempty"`
	// DirectoryMode is the mode for directories the backend creates, parsed as
	// octal. Defaults to 0700 when unset (zero).
	DirectoryMode DirectoryMode `env:"DIRECTORY_MODE" json:"directoryMode,omitempty" yaml:"directoryMode,omitempty"`
	// contains filtered or unexported fields
}

FilesystemConfig configures a filesystem-based objectstorage provider.

func (*FilesystemConfig) ValidateWithContext

func (c *FilesystemConfig) ValidateWithContext(ctx context.Context) error

ValidateWithContext validates the FilesystemConfig.

type Option

type Option func(*options)

Option configures the Uploader this package constructs. The zero configuration works: an absent logger logs nowhere, an absent tracer provider traces nowhere, and an absent metrics provider records nothing.

func WithLogger

func WithLogger(logger logging.Logger) Option

WithLogger attaches a logger.

func WithMetricsProvider

func WithMetricsProvider(metricsProvider metrics.Provider) Option

WithMetricsProvider attaches a metrics provider for the package's counters and histograms.

func WithTracerProvider

func WithTracerProvider(tracerProvider tracing.TracerProvider) Option

WithTracerProvider attaches a tracer provider, enabling spans on every operation.

type R2Config

type R2Config struct {
	AccountID       string `env:"ACCOUNT_ID"        json:"accountID,omitempty"       yaml:"accountID,omitempty"`
	AccessKeyID     string `env:"ACCESS_KEY_ID"     json:"accessKeyID,omitempty"     yaml:"accessKeyID,omitempty"`
	SecretAccessKey string `env:"SECRET_ACCESS_KEY" json:"secretAccessKey,omitempty" yaml:"secretAccessKey,omitempty"`
	// contains filtered or unexported fields
}

R2Config configures a Cloudflare R2-based objectstorage provider.

func (*R2Config) ValidateWithContext

func (c *R2Config) ValidateWithContext(ctx context.Context) error

ValidateWithContext validates the R2Config.

type Uploader

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

Uploader implements the uploads.UploadManager interface.

func NewUploadManager

func NewUploadManager(ctx context.Context, cfg *Config, opts ...Option) (*Uploader, error)

NewUploadManager provides a new uploads.UploadManager.

func (*Uploader) Attributes

func (u *Uploader) Attributes(ctx context.Context, path string) (*uploads.Attributes, error)

Attributes fetches the stored metadata for the object at path.

Example
package main

import (
	"context"
	"fmt"

	"github.com/primandproper/platform-go/v9/uploads"
	"github.com/primandproper/platform-go/v9/uploads/objectstorage"
)

func newExampleManager() *objectstorage.Uploader {
	m, err := objectstorage.NewUploadManager(
		context.Background(),

		&objectstorage.Config{BucketName: "example", Provider: objectstorage.MemoryProvider},
	)
	if err != nil {
		panic(err)
	}

	return m
}

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

	if err := uploads.SaveFile(ctx, mgr, "photo.png", []byte("hello world")); err != nil {
		panic(err)
	}

	attrs, err := mgr.Attributes(ctx, "photo.png")
	if err != nil {
		panic(err)
	}

	fmt.Println(attrs.Size)
}
Output:
11

func (*Uploader) Close

func (u *Uploader) Close() error

Close releases the underlying gocloud bucket, and with it whatever client the provider opened. It does not delete anything.

It is safe to call more than once; gocloud's Close reports an error only on the first call that actually closes.

func (*Uploader) Delete

func (u *Uploader) Delete(ctx context.Context, path string) error

Delete removes the object at path.

func (*Uploader) Exists

func (u *Uploader) Exists(ctx context.Context, path string) (bool, error)

Exists reports whether an object exists at path.

func (*Uploader) List

func (u *Uploader) List(ctx context.Context, prefix string) iter.Seq2[uploads.ObjectInfo, error]

List streams the objects stored under prefix. Objects are fetched lazily as the returned iterator is consumed; the caller may stop early by breaking out of the range loop.

Example
package main

import (
	"context"
	"fmt"
	"sort"

	"github.com/primandproper/platform-go/v9/uploads"
	"github.com/primandproper/platform-go/v9/uploads/objectstorage"
)

func newExampleManager() *objectstorage.Uploader {
	m, err := objectstorage.NewUploadManager(
		context.Background(),

		&objectstorage.Config{BucketName: "example", Provider: objectstorage.MemoryProvider},
	)
	if err != nil {
		panic(err)
	}

	return m
}

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

	for _, name := range []string{"data/a.txt", "data/b.txt", "other/c.txt"} {
		if err := uploads.SaveFile(ctx, mgr, name, []byte("x")); err != nil {
			panic(err)
		}
	}

	// List streams objects lazily; break out of the loop to stop early.
	var paths []string
	for obj, err := range mgr.List(ctx, "data/") {
		if err != nil {
			panic(err)
		}

		paths = append(paths, obj.Path)
	}
	sort.Strings(paths)

	fmt.Println(paths)
}
Output:
[data/a.txt data/b.txt]

func (*Uploader) Open

func (u *Uploader) Open(ctx context.Context, path string) (io.ReadCloser, error)

Open returns a reader for the object at path. The caller is responsible for closing it.

func (*Uploader) OpenRange

func (u *Uploader) OpenRange(ctx context.Context, path string, offset, length int64) (io.ReadCloser, error)

OpenRange returns a reader over length bytes of the object at path, starting at offset. A negative length reads to the end. The caller is responsible for closing it.

func (*Uploader) Save

func (u *Uploader) Save(ctx context.Context, path string, r io.Reader, opts ...uploads.SaveOption) error

Save writes the contents of r to the object at path.

func (*Uploader) SignedURL

func (u *Uploader) SignedURL(ctx context.Context, path string, opts *uploads.SignedURLOptions) (string, error)

SignedURL mints a signed URL granting temporary, direct access to the object at path. Not all providers support signing (e.g. the in-memory and unsigned filesystem backends return an error).

Jump to

Keyboard shortcuts

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