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 }