84 lines
2.6 KiB
Go
84 lines
2.6 KiB
Go
package link
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"time"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/declaration"
|
|
"github.com/nats-io/nats.go"
|
|
)
|
|
|
|
// FilesBus is a link that can read an object of the bucket the controller keeps a declaration's large files in
|
|
// (novox/hq ADR 0486 §1, §2). Separate from Bus, as HaveBus is: a link that cannot is still a link, and a declaration
|
|
// whose files are given by digest is then refused whole, naming that.
|
|
type FilesBus interface {
|
|
// FileObject is the object of that name, no larger than limit bytes, read within ctx. **Reads by name only**: a
|
|
// node-engine's account may neither list the bucket nor write it (ADR 0486 §2).
|
|
FileObject(ctx context.Context, name string, limit int64) ([]byte, error)
|
|
}
|
|
|
|
type filesKey struct{}
|
|
|
|
// WithFiles is ctx carrying the link a declaration's file references are fetched on.
|
|
func WithFiles(ctx context.Context, bus any) context.Context {
|
|
if f, ok := bus.(FilesBus); ok {
|
|
return context.WithValue(ctx, filesKey{}, f)
|
|
}
|
|
return ctx
|
|
}
|
|
|
|
// FilesFrom is the fetch the apply's context carries, or nil when the node has no such link.
|
|
func FilesFrom(ctx context.Context) func(context.Context, string, int64) ([]byte, error) {
|
|
if f, ok := ctx.Value(filesKey{}).(FilesBus); ok {
|
|
return f.FileObject
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// FileObject reads one object by name from the declaration-files bucket. **Only binds**: the bucket is the controller's
|
|
// to make, so one that is not there is said as what it is. Nothing waits longer than ctx allows.
|
|
func (b OverNATS) FileObject(ctx context.Context, name string, limit int64) ([]byte, error) {
|
|
js := b.JS
|
|
wait := 10 * time.Second
|
|
if at, ok := ctx.Deadline(); ok {
|
|
if wait = time.Until(at); wait <= 0 {
|
|
return nil, context.DeadlineExceeded
|
|
}
|
|
}
|
|
if b.Conn != nil {
|
|
bounded, err := b.Conn.JetStream(nats.MaxWait(wait))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
js = bounded
|
|
}
|
|
store, err := js.ObjectStore(declaration.FileBucket)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("the object bucket %s: %w", declaration.FileBucket, err)
|
|
}
|
|
res, err := store.Get(name, nats.Context(ctx))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer res.Close()
|
|
body, err := io.ReadAll(io.LimitReader(res, limit+1))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if int64(len(body)) > limit {
|
|
return nil, fmt.Errorf("the object is larger than the %d bytes the declaration names", limit)
|
|
}
|
|
return body, nil
|
|
}
|
|
|
|
func (l *natsLink) FileObject(ctx context.Context, name string, limit int64) ([]byte, error) {
|
|
return OverNATS{Conn: l.conn, JS: l.js}.FileObject(ctx, name, limit)
|
|
}
|
|
|
|
var (
|
|
_ FilesBus = OverNATS{}
|
|
_ FilesBus = (*natsLink)(nil)
|
|
)
|