github.com/kubri/kubri@v0.5.1-0.20240317001612-bda2aaef967e/internal/blob/target.go (about)

     1  package blob
     2  
     3  import (
     4  	"context"
     5  	"io"
     6  	"io/fs"
     7  	"mime"
     8  	"net/url"
     9  	"path"
    10  	"strings"
    11  
    12  	"gocloud.dev/blob"
    13  	"gocloud.dev/gcerrors"
    14  
    15  	"github.com/kubri/kubri/target"
    16  )
    17  
    18  type blobTarget struct {
    19  	bucket  *blob.Bucket
    20  	prefix  string
    21  	baseURL string
    22  }
    23  
    24  func NewTarget(url, prefix, baseURL string) (target.Target, error) {
    25  	b, err := blob.OpenBucket(context.Background(), url)
    26  	if err != nil {
    27  		return nil, err
    28  	}
    29  
    30  	t := &blobTarget{
    31  		bucket:  b,
    32  		prefix:  strings.Trim(prefix, "/"),
    33  		baseURL: strings.TrimRight(baseURL, "/"),
    34  	}
    35  
    36  	return t, nil
    37  }
    38  
    39  func (t *blobTarget) NewWriter(ctx context.Context, filename string) (io.WriteCloser, error) {
    40  	opt := &blob.WriterOptions{ContentType: mime.TypeByExtension(path.Ext(filename))}
    41  	f, err := t.bucket.NewWriter(ctx, path.Join(t.prefix, filename), opt)
    42  	return f, mapError("write", filename, err)
    43  }
    44  
    45  func (t *blobTarget) NewReader(ctx context.Context, filename string) (io.ReadCloser, error) {
    46  	f, err := t.bucket.NewReader(ctx, path.Join(t.prefix, filename), nil)
    47  	return f, mapError("read", filename, err)
    48  }
    49  
    50  func (t *blobTarget) Remove(ctx context.Context, filename string) error {
    51  	return mapError("remove", filename, t.bucket.Delete(ctx, path.Join(t.prefix, filename)))
    52  }
    53  
    54  func (t *blobTarget) Sub(dir string) target.Target {
    55  	return &blobTarget{bucket: t.bucket, prefix: path.Join(t.prefix, strings.Trim(dir, "/")), baseURL: t.baseURL}
    56  }
    57  
    58  func (t *blobTarget) URL(ctx context.Context, filename string) (string, error) {
    59  	if t.baseURL != "" {
    60  		return url.JoinPath(t.baseURL, t.prefix, filename)
    61  	}
    62  
    63  	url, err := t.bucket.SignedURL(ctx, path.Join(t.prefix, filename), &blob.SignedURLOptions{})
    64  	if err != nil {
    65  		return "", mapError("read", filename, err)
    66  	}
    67  
    68  	url, _, _ = strings.Cut(url, "?")
    69  	return url, nil
    70  }
    71  
    72  func mapError(op, name string, err error) error {
    73  	switch gcerrors.Code(err) {
    74  	case gcerrors.OK:
    75  		return nil
    76  	case gcerrors.NotFound:
    77  		return &fs.PathError{Op: op, Path: name, Err: fs.ErrNotExist}
    78  	default:
    79  		return err
    80  	}
    81  }