Documentation
¶
Overview ¶
Package mediastore records the media objects (audio, images, video) the gateway keeps outside the database and pairs each record with its bytes in a blob store. See docs/adr/0013-media-storage.md.
Index ¶
- Constants
- Variables
- func Inline(contentType string) bool
- func OpenBlobStore(storageType, path string) (blobstore.Store, error)
- func SafeContentType(kind Kind, contentType string) string
- func ValidID(id string) bool
- type Descriptor
- type Kind
- type MemoryStore
- func (s *MemoryStore) Close() error
- func (s *MemoryStore) Delete(_ context.Context, id string) error
- func (s *MemoryStore) Expired(_ context.Context, now time.Time, limit int) ([]*Object, error)
- func (s *MemoryStore) Get(_ context.Context, id string) (*Object, error)
- func (s *MemoryStore) Insert(_ context.Context, object *Object) error
- type MongoDBStore
- func (s *MongoDBStore) Close() error
- func (s *MongoDBStore) Delete(ctx context.Context, id string) error
- func (s *MongoDBStore) Expired(ctx context.Context, now time.Time, limit int) ([]*Object, error)
- func (s *MongoDBStore) Get(ctx context.Context, id string) (*Object, error)
- func (s *MongoDBStore) Insert(ctx context.Context, object *Object) error
- type Object
- type Result
- type SQLStore
- func (s *SQLStore) Close() error
- func (s *SQLStore) Delete(ctx context.Context, id string) error
- func (s *SQLStore) Expired(ctx context.Context, now time.Time, limit int) ([]*Object, error)
- func (s *SQLStore) Get(ctx context.Context, id string) (*Object, error)
- func (s *SQLStore) Insert(ctx context.Context, object *Object) error
- type Service
- func (s *Service) Begin(ctx context.Context, d Descriptor) (*Upload, error)
- func (s *Service) Close() error
- func (s *Service) Delete(ctx context.Context, id string) error
- func (s *Service) Get(ctx context.Context, id string) (*Object, error)
- func (s *Service) Open(ctx context.Context, id string) (*Object, io.ReadSeekCloser, error)
- func (s *Service) Put(ctx context.Context, d Descriptor, r io.Reader) (*Object, error)
- func (s *Service) Sweep(ctx context.Context) (int, error)
- type Source
- type Store
- type Upload
Constants ¶
const ( StorageFilesystem = "filesystem" StorageMemory = "memory" )
Blob storage types an operator can choose with MEDIA_STORAGE_TYPE.
const ( // SweepInterval is how often expired objects are removed. SweepInterval = time.Hour )
Variables ¶
var ErrNotFound = errors.New("media object not found")
ErrNotFound reports a media object that does not exist or has expired.
Functions ¶
func Inline ¶
Inline reports whether a stored content type is safe to serve inline. It is the same allowlist SafeContentType applies, so an object stored before a rule changed is still judged at serve time.
func OpenBlobStore ¶
OpenBlobStore builds the blob store named by storageType: a directory for "filesystem", process memory for "memory".
func SafeContentType ¶
SafeContentType returns the content type an object of kind may be stored under. A type is trusted only when it matches the kind (audio/* for audio, a passive raster type for images, video/* for video); anything else, including a client-declared text/html on an upload, is stored as application/octet-stream so it can never be served as active content.
Types ¶
type Descriptor ¶
type Descriptor struct {
Kind Kind
Source Source
ContentType string
RequestID string
UserPath string
// TTL is how long the object is kept; zero keeps it forever.
TTL time.Duration
}
Descriptor says what an object holds and who it belongs to.
type MemoryStore ¶
type MemoryStore struct {
// contains filtered or unexported fields
}
MemoryStore keeps media records in process memory.
func NewMemoryStore ¶
func NewMemoryStore() *MemoryStore
NewMemoryStore returns an empty in-memory record store.
func (*MemoryStore) Delete ¶
func (s *MemoryStore) Delete(_ context.Context, id string) error
Delete removes the record.
type MongoDBStore ¶
type MongoDBStore struct {
// contains filtered or unexported fields
}
MongoDBStore keeps media records in MongoDB.
func NewMongoDBStore ¶
func NewMongoDBStore(database *mongo.Database) (*MongoDBStore, error)
NewMongoDBStore creates collection indexes if needed.
func (*MongoDBStore) Close ¶
func (s *MongoDBStore) Close() error
Close is a no-op; client lifecycle is managed by the storage layer.
func (*MongoDBStore) Delete ¶
func (s *MongoDBStore) Delete(ctx context.Context, id string) error
Delete removes one record by id.
type Object ¶
type Object struct {
ID string `json:"id" bson:"_id"`
Kind Kind `json:"kind" bson:"kind"`
Source Source `json:"source" bson:"source"`
ContentType string `json:"content_type" bson:"content_type"`
Bytes int64 `json:"bytes" bson:"bytes"`
StorageKey string `json:"storage_key" bson:"storage_key"`
RequestID string `json:"request_id,omitempty" bson:"request_id,omitempty"`
UserPath string `json:"user_path,omitempty" bson:"user_path,omitempty"`
CreatedAt time.Time `json:"created_at" bson:"created_at"`
// ExpiresAt is when the retention sweep removes the object; the zero
// time keeps it forever.
ExpiresAt time.Time `json:"expires_at,omitzero" bson:"expires_at,omitempty"`
}
Object is one stored media payload.
type Result ¶
type Result struct {
Service *Service
}
Result holds the initialized media service.
type SQLStore ¶
type SQLStore struct {
// contains filtered or unexported fields
}
SQLStore keeps media records in SQLite or PostgreSQL.
func NewSQLStore ¶
NewSQLStore creates the media_objects table and indexes if needed.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service stores media: a record per object in a Store and the bytes in a blobstore.Store. It runs the retention sweep until closed.
func NewService ¶
NewService pairs a record store with a blob store and starts the hourly retention sweep.
func (*Service) Get ¶
Get returns an object's record, or ErrNotFound once it has expired. A malformed id is not found without touching the store.
func (*Service) Open ¶
Open returns an object's record and a reader over its bytes. The caller closes the reader.
func (*Service) Sweep ¶
Sweep removes every object whose retention has run out and reports how many it removed. An object that cannot be removed does not stop the others: the sweep works through the batch, then reports the failures together. It stops after a batch with failures rather than reselecting the same objects forever; the next hourly run tries them again. The hourly loop calls it; tests call it directly.
type Source ¶
type Source string
Source records who stored an object, which decides what may read it and how it is retained.
const SourceAudit Source = "audit"
SourceAudit marks media captured for the audit log: the payload of an audio or image request whose body logging is enabled.
type Store ¶
type Store interface {
Insert(ctx context.Context, object *Object) error
// Get returns the record, or ErrNotFound. Expiry is not applied here;
// the service checks it so a swept-but-not-yet-deleted row still reads
// as gone.
Get(ctx context.Context, id string) (*Object, error)
// Delete removes the record; a missing record is ErrNotFound.
Delete(ctx context.Context, id string) error
// Expired returns up to limit records whose expiry passed before now,
// oldest expiry first.
Expired(ctx context.Context, now time.Time, limit int) ([]*Object, error)
Close() error
}
Store persists media object records.
type Upload ¶
type Upload struct {
// contains filtered or unexported fields
}
Upload is an object being written. Bytes go straight to the blob store; the record is written on Commit, so a discarded upload leaves nothing.