package space import ( "context" "errors" "fmt" "git.aiterp.net/rpdata/api/internal/config" "io" minio "github.com/minio/minio-go" ) type Client struct { bucket string urlRoot string spaceRoot string maxSize int64 s3 *minio.Client } func (client *Client) MaxSize() int64 { return client.maxSize } // UploadFile uploads the file to the space. This does not do any checks on it, so the endpoints should // ensure that's all okay. func (client *Client) UploadFile(ctx context.Context, name string, mimeType string, reader io.Reader, size int64) error { if size > client.maxSize { return errors.New("file is too big") } _, err := client.s3.PutObjectWithContext(ctx, client.bucket, client.spaceRoot+"/"+name, reader, size, minio.PutObjectOptions{ ContentType: mimeType, UserMetadata: map[string]string{ "x-amz-acl": "public-read", }, }) if err != nil { return err } _, err = client.s3.StatObject(client.bucket, client.spaceRoot+"/"+name, minio.StatObjectOptions{}) if err != nil { return err } return nil } // RemoveFile removes a file from the space func (client *Client) RemoveFile(name string) error { return client.s3.RemoveObject(client.bucket, client.spaceRoot+"/"+name) } // DownloadFile opens a file for download, using the same path format as the UploadFile function. Remember to Close it! // The returned stream also has `ReaderAt` and `Seeker`, but those are impl. details. func (client *Client) DownloadFile(ctx context.Context, path string) (io.ReadCloser, error) { return client.s3.GetObjectWithContext(ctx, client.bucket, client.spaceRoot+"/"+path, minio.GetObjectOptions{}) } // URLFromPath gets the URL from the path returned by UploadFile func (client *Client) URLFromPath(path string) string { return client.urlRoot + path } // Connect connects to a S3 space. func Connect(cfg config.Space) (*Client, error) { client, err := minio.New(cfg.Host, cfg.AccessKey, cfg.SecretKey, true) if err != nil { return nil, err } exists, err := client.BucketExists(cfg.Bucket) if err != nil { return nil, err } if !exists { return nil, errors.New("bucket not found") } urlRoot := cfg.URLRoot if urlRoot == "" { urlRoot = fmt.Sprintf("https://%s.%s/%s/", cfg.Bucket, cfg.Host, cfg.Root) } else { urlRoot += "/" + cfg.Root + "/" } return &Client{ bucket: cfg.Bucket, urlRoot: urlRoot, spaceRoot: cfg.Root, maxSize: cfg.MaxSize, s3: client, }, nil }