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, folder string, name string, mimeType string, reader io.Reader, size int64) (string, error) { path := folder + "/" + name if size > client.maxSize { return "", errors.New("file is too big") } _, err := client.s3.PutObjectWithContext(ctx, client.bucket, client.spaceRoot+"/"+path, 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+"/"+path, minio.StatObjectOptions{}) if err != nil { return "", err } return path, nil } // RemoveFile removes a file from the space func (client *Client) RemoveFile(folder string, name string) error { path := folder + "/" + name return client.s3.RemoveObject(client.bucket, client.spaceRoot+"/"+path) } // 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") } return &Client{ bucket: cfg.Bucket, urlRoot: fmt.Sprintf("https://%s.%s/%s/", cfg.Bucket, cfg.Host, cfg.Root), spaceRoot: cfg.Root, maxSize: cfg.MaxSize, s3: client, }, nil }