Adam Štrauch
3120a8c6ee
All checks were successful
continuous-integration/drone/push Build is passing
180 lines
4.6 KiB
Go
180 lines
4.6 KiB
Go
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
|
|
}
|