tutus-chain/pkg/storage/storage.go

169 lines
5.2 KiB
Go

package storage
import (
"context"
"io"
"time"
)
// Provider defines the interface for sovereign storage backends.
// Implementations must ensure data sovereignty compliance for government deployments.
//
// Tutus supports multiple storage backends to accommodate national data
// residency requirements:
// - NeoFS: Decentralized storage (can be deployed as private network)
// - Local: Filesystem storage for single-node or NAS deployments
// - S3-compatible: AWS, Azure, GCP, or sovereign cloud providers
// - Custom: Nation-specific storage infrastructure
type Provider interface {
// Name returns the provider identifier (e.g., "neofs", "local", "s3")
Name() string
// Put stores data and returns a unique identifier for retrieval.
// The identifier format is provider-specific.
Put(ctx context.Context, data io.Reader, opts PutOptions) (ObjectID, error)
// Get retrieves data by its identifier.
// Returns ErrNotFound if the object doesn't exist.
Get(ctx context.Context, id ObjectID) (io.ReadCloser, error)
// Delete removes an object from storage.
// Returns ErrNotFound if the object doesn't exist.
Delete(ctx context.Context, id ObjectID) error
// Exists checks if an object exists in storage.
Exists(ctx context.Context, id ObjectID) (bool, error)
// List returns object IDs matching the given prefix.
// Use an empty prefix to list all objects in the container.
List(ctx context.Context, prefix string, opts ListOptions) ([]ObjectInfo, error)
// Head retrieves object metadata without downloading content.
Head(ctx context.Context, id ObjectID) (ObjectInfo, error)
// Close releases any resources held by the provider.
Close() error
}
// BlockStorage extends Provider with blockchain-specific operations.
type BlockStorage interface {
Provider
// PutBlock stores a block with its index for efficient retrieval.
PutBlock(ctx context.Context, index uint32, data []byte) (ObjectID, error)
// GetBlock retrieves a block by its index.
GetBlock(ctx context.Context, index uint32) ([]byte, error)
// GetBlockRange retrieves multiple blocks efficiently.
GetBlockRange(ctx context.Context, start, end uint32) ([][]byte, error)
// GetLatestBlockIndex returns the highest block index in storage.
GetLatestBlockIndex(ctx context.Context) (uint32, error)
}
// StateStorage extends Provider with state snapshot operations.
type StateStorage interface {
Provider
// PutState stores a state snapshot at a specific height.
PutState(ctx context.Context, height uint32, data io.Reader) (ObjectID, error)
// GetState retrieves the state snapshot for a given height.
GetState(ctx context.Context, height uint32) (io.ReadCloser, error)
// GetLatestState returns the most recent state snapshot.
GetLatestState(ctx context.Context) (height uint32, data io.ReadCloser, err error)
}
// ObjectID uniquely identifies an object within a storage provider.
type ObjectID struct {
// Provider is the storage backend identifier
Provider string
// Container is the bucket/container/namespace
Container string
// ID is the unique object identifier within the container
ID string
}
// String returns a URI-style representation of the object ID.
func (o ObjectID) String() string {
return o.Provider + "://" + o.Container + "/" + o.ID
}
// ObjectInfo contains metadata about a stored object.
type ObjectInfo struct {
ID ObjectID
Size int64
ContentType string
Created time.Time
Modified time.Time
Checksum string
Attributes map[string]string
}
// PutOptions configures object storage behavior.
type PutOptions struct {
// ContentType specifies the MIME type of the content
ContentType string
// Attributes are custom key-value metadata
Attributes map[string]string
// Expiration sets automatic deletion time (zero means never)
Expiration time.Time
// Replicas specifies the minimum number of copies (provider-dependent)
Replicas int
}
// ListOptions configures listing behavior.
type ListOptions struct {
// MaxResults limits the number of results (0 = no limit)
MaxResults int
// Cursor for pagination (provider-specific)
Cursor string
// IncludeMetadata fetches full ObjectInfo vs just IDs
IncludeMetadata bool
}
// Registry manages available storage providers.
type Registry struct {
providers map[string]Provider
}
// NewRegistry creates a new provider registry.
func NewRegistry() *Registry {
return &Registry{
providers: make(map[string]Provider),
}
}
// Register adds a storage provider to the registry.
func (r *Registry) Register(p Provider) {
r.providers[p.Name()] = p
}
// Get returns a provider by name.
func (r *Registry) Get(name string) (Provider, bool) {
p, ok := r.providers[name]
return p, ok
}
// List returns all registered provider names.
func (r *Registry) List() []string {
names := make([]string, 0, len(r.providers))
for name := range r.providers {
names = append(names, name)
}
return names
}
// Close closes all registered providers.
func (r *Registry) Close() error {
var lastErr error
for _, p := range r.providers {
if err := p.Close(); err != nil {
lastErr = err
}
}
return lastErr
}