node-api/apps/drivers/s3.go

180 lines
4.6 KiB
Go
Raw Normal View History

package drivers
import (
"bytes"
"context"
"fmt"
"io/ioutil"
"time"
"github.com/minio/minio-go/v7"
"github.com/minio/minio-go/v7/pkg/credentials"
)
const s3LinkExpiration = 72 // in hours
// S3Driver provides basic interface for S3 storage compatible with Driver interface
type S3Driver struct {
// S3 storage related things
S3AccessKey string
S3SecretKey string
S3Endpoint string
S3SSL bool
Bucket string
}
// Returns S3 client structure
func (s *S3Driver) getMinioClient() (*minio.Client, error) {
client, err := minio.New(s.S3Endpoint, &minio.Options{
Creds: credentials.NewStaticV4(s.S3AccessKey, s.S3SecretKey, ""),
Secure: s.S3SSL,
})
if err == nil {
return client, s.prepareBucket(client)
}
return client, err
}
// Create configured bucket if it doesn't exist
func (s *S3Driver) prepareBucket(client *minio.Client) error {
bucketInfos, err := client.ListBuckets(context.Background())
if err != nil {
return err
}
var found bool
for _, info := range bucketInfos {
if info.Name == s.Bucket {
found = true
break
}
}
if !found {
err = client.MakeBucket(context.Background(), s.Bucket, minio.MakeBucketOptions{})
if err != nil {
return err
}
}
return nil
}
// Create creates a new object in the storage with given body
func (s S3Driver) Create(key string, filePath string) error {
client, err := s.getMinioClient()
if err != nil {
return fmt.Errorf("getting minio client error: %v", err)
}
_, err = client.FPutObject(context.TODO(), s.Bucket, key, filePath, minio.PutObjectOptions{})
if err != nil {
return fmt.Errorf("copying object into S3 error: %v", err)
}
return nil
}
// Get copies file from S3 into a local file
// filePath tells the method where the file should be stored
func (s S3Driver) Get(key string, filePath string) error {
client, err := s.getMinioClient()
if err != nil {
return fmt.Errorf("getting minio client error: %v", err)
}
err = client.FGetObject(context.TODO(), s.Bucket, key, filePath, minio.GetObjectOptions{})
if err != nil {
return fmt.Errorf("getting the object from S3 error: %v", err)
}
return nil
}
// Write writes content of body into key
func (s S3Driver) Write(key string, body []byte) error {
client, err := s.getMinioClient()
if err != nil {
return fmt.Errorf("getting minio client error: %v", err)
}
_, err = client.PutObject(context.TODO(), s.Bucket, key, bytes.NewReader(body), int64(len(body)), minio.PutObjectOptions{})
if err != nil {
return fmt.Errorf("getting the object from S3 error: %v", err)
}
return nil
}
// Read returns content of given key
func (s S3Driver) Read(key string) ([]byte, error) {
client, err := s.getMinioClient()
if err != nil {
return []byte(""), fmt.Errorf("getting minio client error: %v", err)
}
object, err := client.GetObject(context.TODO(), s.Bucket, key, minio.GetObjectOptions{})
if err != nil {
return []byte(""), fmt.Errorf("getting the object from S3 error: %v", err)
}
body, err := ioutil.ReadAll(object)
if err != nil {
return []byte(""), fmt.Errorf("reading the object from S3 error: %v", err)
}
return body, nil
}
// List returns list of objects in fiven prefix
func (s S3Driver) List(prefix string) ([]string, error) {
keys := []string{}
client, err := s.getMinioClient()
if err != nil {
return keys, fmt.Errorf("getting minio client error: %v", err)
}
for info := range client.ListObjects(context.TODO(), s.Bucket, minio.ListObjectsOptions{Prefix: ""}) {
keys = append(keys, info.Key)
}
return keys, nil
}
// Delete deletes one object
func (s S3Driver) Delete(key string) error {
client, err := s.getMinioClient()
if err != nil {
return fmt.Errorf("getting minio client error: %v", err)
}
err = client.RemoveObject(context.Background(), s.Bucket, key, minio.RemoveObjectOptions{})
if err != nil {
return fmt.Errorf("removing object error: %v", err)
}
return nil
}
// GetDownloadLink returns URL of object with given key. That URL can be used to download the object.
func (s S3Driver) GetDownloadLink(key string) (string, error) {
client, err := s.getMinioClient()
if err != nil {
return "", fmt.Errorf("getting minio client error: %v", err)
}
expiry := time.Second * s3LinkExpiration * 60 * 60 // 1 day.
presignedURL, err := client.PresignedPutObject(context.Background(), s.Bucket, key, expiry)
if err != nil {
return "", fmt.Errorf("generating presign URL error: %v", err)
}
if s.S3SSL {
return fmt.Sprintf("https://%s%s?%s", s.S3Endpoint, presignedURL.Path, presignedURL.RawQuery), nil
}
return fmt.Sprintf("http://%s%s?%s", s.S3Endpoint, presignedURL.Path, presignedURL.RawQuery), nil
}