package client import ( "context" "errors" "math/rand" "path/filepath" "time" "git.kapelle.org/niklas/s3share/internal/db" "git.kapelle.org/niklas/s3share/internal/s3" "git.kapelle.org/niklas/s3share/internal/types" ) var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") type Client struct { db db.DB s3 s3.S3 } func NewClient(db db.DB, s3 s3.S3) *Client { rand.Seed(time.Now().UnixNano()) return &Client{ db: db, s3: s3, } } func createRandomString() string { s := make([]rune, 6) for i := range s { s[i] = letters[rand.Intn(len(letters))] } return string(s) } func (c *Client) CreateValidSlug(ctx context.Context) (string, error) { for i := 0; i < 10; i++ { slug := createRandomString() res, err := c.db.GetShare(ctx, slug) if err != nil { return "", err } if res == nil { return slug, nil } } return "", errors.New("could not create valid slug after 10 tries") } func (c *Client) GetShare(ctx context.Context, slug string) (*types.Share, error) { return c.db.GetShare(ctx, slug) } func (c *Client) CreateShare(ctx context.Context, key string) (*types.Share, error) { slug, err := c.CreateValidSlug(ctx) if err != nil { return nil, err } share := &types.Share{ Slug: slug, Key: key, } exists, err := c.s3.KeyExists(ctx, key) if err != nil { return nil, err } if !exists { return nil, errors.New("key does not exist") } err = c.db.CreateShare(ctx, share) if err != nil { return nil, err } return share, nil } func (c *Client) GetObjectFromShare(ctx context.Context, share *types.Share) (s3.ObjectReader, error) { return c.s3.GetObject(ctx, share.Key) } func (c *Client) DeleteShare(ctx context.Context, slug string) error { return c.db.DeleteShare(ctx, slug) } func (c *Client) GetObjectMetadata(ctx context.Context, key string) (*types.Metadata, error) { metadata, err := c.s3.GetObjectMetadata(ctx, key) if err != nil { return nil, err } if metadata.Filename == "" { metadata.Filename = filepath.Base(key) } return metadata, nil }