mirror of
https://git.mills.io/saltyim/saltyim.git
synced 2024-06-25 16:28:20 +00:00
![James Mills](/assets/img/avatar_default.png)
Co-authored-by: James Mills <1290234+prologic@users.noreply.github.com> Reviewed-on: https://git.mills.io/saltyim/saltyim/pulls/184
111 lines
3.0 KiB
Go
111 lines
3.0 KiB
Go
package saltyim
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"fmt"
|
|
"hash/fnv"
|
|
"io"
|
|
"net/http"
|
|
)
|
|
|
|
// BlobOptions are various options that define a blob such its type, filename, whether it is
|
|
// public or not (private by default) and any optional properties that clients can interpret.
|
|
type BlobOptions struct {
|
|
// Key is the locaiton of the blob option, if omitted a hash of the contents is used as the key
|
|
Key string
|
|
|
|
// Type is the mimetype of the blob, if omitted the type is auto detected
|
|
Type string
|
|
|
|
// Public sets whether the blob is public or pviate (default)
|
|
Public bool
|
|
|
|
// Filename sets the blob's friendly filename (if omitted, no filename is used)
|
|
Filename string
|
|
|
|
// Properties sets optional properties of a blob which are up to clients to interpet
|
|
Properties map[string]string
|
|
}
|
|
|
|
// BlobOption is a function type that is used to configure blob options
|
|
type BlobOption func(opts *BlobOptions) error
|
|
|
|
// WithKey sets an explicit key (location) for the blob
|
|
func WithKey(key string) BlobOption {
|
|
return func(opts *BlobOptions) error {
|
|
opts.Key = key
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// BlobService allows a client to store, retrieve and delete blobs of data as well as store
|
|
// properites for a blob that are useful to other clients or users receiving the blob.
|
|
type BlobService interface {
|
|
Write(r io.Reader, opts ...BlobOption) error
|
|
Read(key string) ([]byte, error)
|
|
}
|
|
|
|
// Blobs returns an object that implements the BlobService which uses this client's identity
|
|
// and the broker this client is connected to (normally an instance of `saltyd`).
|
|
func (cli *Client) Blobs() BlobService {
|
|
return &blobService{cli: cli}
|
|
}
|
|
|
|
type blobService struct {
|
|
cli *Client
|
|
}
|
|
|
|
func (svc *blobService) Read(key string) ([]byte, error) {
|
|
cli := svc.cli
|
|
|
|
if cli.me.Endpoint() == nil {
|
|
if err := cli.me.Refresh(); err != nil {
|
|
return nil, fmt.Errorf("unable to find your endpoint for %s: %w", cli.me.String(), err)
|
|
}
|
|
}
|
|
endpoint := cli.me.Endpoint()
|
|
endpoint.Path = fmt.Sprintf("/api/v1/blob/%s", key)
|
|
|
|
data, err := cli.Request(http.MethodGet, endpoint.String(), nil)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error retrieving blob: %w", err)
|
|
}
|
|
|
|
return data, nil
|
|
}
|
|
|
|
func (svc *blobService) Write(r io.Reader, options ...BlobOption) error {
|
|
opts := &BlobOptions{}
|
|
for _, option := range options {
|
|
if err := option(opts); err != nil {
|
|
return fmt.Errorf("error configuring blob options: %w", err)
|
|
}
|
|
}
|
|
|
|
cli := svc.cli
|
|
|
|
if cli.me.Endpoint() == nil {
|
|
if err := cli.me.Refresh(); err != nil {
|
|
return fmt.Errorf("unable to find your endpoint for %s: %w", cli.me.String(), err)
|
|
}
|
|
}
|
|
endpoint := cli.me.Endpoint()
|
|
|
|
data, err := io.ReadAll(r)
|
|
if err != nil {
|
|
return fmt.Errorf("error reading blob contents: %w", err)
|
|
}
|
|
|
|
key := opts.Key
|
|
if key == "" {
|
|
key = base64.StdEncoding.EncodeToString(fnv.New128().Sum(data))
|
|
}
|
|
endpoint.Path = fmt.Sprintf("/api/v1/blob/%s", key)
|
|
|
|
if _, err := cli.Request(http.MethodPut, endpoint.String(), data); err != nil {
|
|
return fmt.Errorf("error creating/updating blob: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|