package drivers import ( "bytes" "context" "fmt" "io/ioutil" "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" ) // 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 }