feat(storage-minio): initial implementation — MinIO/S3 object storage with lifecycle (v1.0.0)
Introduces code.nochebuena.dev/einherjar/storage-minio — the object storage starter for the Einherjar framework. Absorbs the minio package from micro-lib, replacing fmt.Errorf wrapping with core/xerrors. Interfaces (CT-6: one TypeSpec per file): - Provider — PutObject, RemoveObject, GetObject, PresignedGetObject, HandleError - Component — lifecycle.Component + observability.Checkable + Provider + Native() Implementation: - New(logger, cfg) Component — client not created until OnInit - OnInit: minio.New with credentials and transport; bucket existence check - OnStart: BucketExists PING; logs "minio: connected" - OnStop: logs "minio: closing client" (minio-go is stateless; no explicit close) - HealthCheck: BucketExists check; Priority LevelCritical - Native() *miniogo.Client — escape hatch for operations not in Provider - HandleError: maps minio-go errors to xerrors (NotFound, AlreadyExists, Internal) Config (EINHERJAR_MINIO_* env vars): Endpoint(required), AccessKey(required), SecretKey(required), Bucket(required), UseSSL(false), Region(us-east-1) - Component interface embeds observability.Identifiable; identifiable.go implements ModulePath and ModuleVersion via runtime/debug.ReadBuildInfo() — prints in launcher banner
This commit is contained in:
125
README.md
Normal file
125
README.md
Normal file
@@ -0,0 +1,125 @@
|
||||
# einherjar/storage-minio
|
||||
|
||||
[](https://code.nochebuena.dev/einherjar/storage-minio)
|
||||
[](LICENSE)
|
||||
[](https://go.dev)
|
||||
[]()
|
||||
|
||||
> The shield does not care who forged it. It holds what it is given and gives it back unchanged.
|
||||
|
||||
`code.nochebuena.dev/einherjar/storage-minio` is the MinIO/S3 object storage component of the Einherjar framework. It wraps `minio-go/v7` behind a lifecycle-aware `Component` with four common operations — upload, download, delete, and presigned URLs. For anything beyond that scope, `Native()` returns the raw `*miniogo.Client`.
|
||||
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
### Setup
|
||||
|
||||
```go
|
||||
import storageminio "code.nochebuena.dev/einherjar/storage-minio"
|
||||
|
||||
s := storageminio.New(logger, storageminio.DefaultConfig())
|
||||
launcher.Append(s) // OnInit connects; OnStop is a no-op (stateless client)
|
||||
health.Register(s) // BucketExists check; LevelCritical
|
||||
```
|
||||
|
||||
### Uploading
|
||||
|
||||
```go
|
||||
import miniogo "github.com/minio/minio-go/v7"
|
||||
|
||||
info, err := s.PutObject(ctx, "my-bucket", "uploads/photo.jpg", reader, size, miniogo.PutObjectOptions{
|
||||
ContentType: "image/jpeg",
|
||||
})
|
||||
```
|
||||
|
||||
### Downloading
|
||||
|
||||
```go
|
||||
obj, err := s.GetObject(ctx, "my-bucket", "uploads/photo.jpg", miniogo.GetObjectOptions{})
|
||||
if err != nil {
|
||||
return s.HandleError(err)
|
||||
}
|
||||
defer obj.Close()
|
||||
```
|
||||
|
||||
### Presigned URL (time-limited public access)
|
||||
|
||||
```go
|
||||
url, err := s.PresignedGetObject(ctx, "my-bucket", "uploads/photo.jpg", 15*time.Minute, nil)
|
||||
// url is a *url.URL — call url.String() to get the string form
|
||||
```
|
||||
|
||||
### Deleting
|
||||
|
||||
```go
|
||||
err := s.RemoveObject(ctx, "my-bucket", "uploads/photo.jpg", miniogo.RemoveObjectOptions{})
|
||||
```
|
||||
|
||||
### Native escape hatch
|
||||
|
||||
For multipart uploads, bucket management, or any operation not in `Provider`, use the raw client:
|
||||
|
||||
```go
|
||||
native := s.Native() // *miniogo.Client
|
||||
```
|
||||
|
||||
Callers that use `Native()` must import `github.com/minio/minio-go/v7` directly.
|
||||
|
||||
### Error handling
|
||||
|
||||
```go
|
||||
if err := s.HandleError(someErr); err != nil {
|
||||
// minio-go error responses mapped to xerrors:
|
||||
// NoSuchKey / NoSuchBucket → ErrNotFound
|
||||
// AccessDenied → ErrPermissionDenied
|
||||
// context.Canceled → ErrCancelled
|
||||
// context.DeadlineExceeded → ErrDeadlineExceeded
|
||||
}
|
||||
```
|
||||
|
||||
`HandleError` is also available as a package-level function: `storageminio.HandleError(err)`.
|
||||
|
||||
---
|
||||
|
||||
## Environment variables
|
||||
|
||||
| Variable | Required | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `EINHERJAR_MINIO_ENDPOINT` | Yes | — | MinIO/S3 endpoint (host:port or domain) |
|
||||
| `EINHERJAR_MINIO_ACCESS_KEY` | Yes | — | Access key ID |
|
||||
| `EINHERJAR_MINIO_SECRET_KEY` | Yes | — | Secret access key |
|
||||
| `EINHERJAR_MINIO_BUCKET` | Yes | — | Default bucket for health check |
|
||||
| `EINHERJAR_MINIO_USE_SSL` | No | `false` | Use TLS |
|
||||
| `EINHERJAR_MINIO_REGION` | No | `us-east-1` | Bucket region |
|
||||
|
||||
---
|
||||
|
||||
## Dependency graph
|
||||
|
||||
```
|
||||
contracts (zero dependencies)
|
||||
↑
|
||||
core
|
||||
↑
|
||||
storage-minio (contracts, core, minio-go/v7)
|
||||
↑
|
||||
your app
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Verification
|
||||
|
||||
```bash
|
||||
cd storage-minio/
|
||||
go build ./...
|
||||
go vet ./...
|
||||
go test ./...
|
||||
gofmt -l .
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
> *The artifact survives the battle that created it.*
|
||||
> *Store it well. Someone will need it after you are gone.*
|
||||
Reference in New Issue
Block a user