2021-04-15 22:03:26 +03:00
|
|
|
package s3
|
2020-08-24 00:44:47 +03:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"context"
|
|
|
|
"encoding/json"
|
|
|
|
"io/ioutil"
|
2020-08-26 22:59:22 +03:00
|
|
|
"strings"
|
2020-09-19 02:56:50 +03:00
|
|
|
"time"
|
2021-04-15 20:26:17 +03:00
|
|
|
|
2021-04-15 21:15:42 +03:00
|
|
|
"github.com/lus/pasty/internal/config"
|
|
|
|
"github.com/lus/pasty/internal/shared"
|
2021-04-15 20:26:17 +03:00
|
|
|
"github.com/minio/minio-go/v7"
|
|
|
|
"github.com/minio/minio-go/v7/pkg/credentials"
|
2020-08-24 00:44:47 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
// S3Driver represents the AWS S3 storage driver
|
|
|
|
type S3Driver struct {
|
2020-08-24 20:18:05 +03:00
|
|
|
client *minio.Client
|
|
|
|
bucket string
|
2020-08-24 00:44:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize initializes the AWS S3 storage driver
|
|
|
|
func (driver *S3Driver) Initialize() error {
|
2021-04-15 21:15:42 +03:00
|
|
|
client, err := minio.New(config.Current.S3.Endpoint, &minio.Options{
|
|
|
|
Creds: credentials.NewStaticV4(config.Current.S3.AccessKeyID, config.Current.S3.SecretAccessKey, config.Current.S3.SecretToken),
|
|
|
|
Secure: config.Current.S3.Secure,
|
|
|
|
Region: config.Current.S3.Region,
|
2020-08-24 00:44:47 +03:00
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-08-24 20:18:05 +03:00
|
|
|
driver.client = client
|
2021-04-15 21:15:42 +03:00
|
|
|
driver.bucket = config.Current.S3.Bucket
|
2020-08-24 00:44:47 +03:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-08-24 19:08:27 +03:00
|
|
|
// Terminate terminates the AWS S3 storage driver (does nothing, because the AWS S3 storage driver does not need any termination)
|
2020-08-24 00:44:47 +03:00
|
|
|
func (driver *S3Driver) Terminate() error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-08-26 22:59:22 +03:00
|
|
|
// ListIDs returns a list of all existing paste IDs
|
|
|
|
func (driver *S3Driver) ListIDs() ([]string, error) {
|
|
|
|
// Define the IDs slice
|
|
|
|
var ids []string
|
|
|
|
|
|
|
|
// Fill the IDs slice
|
|
|
|
channel := driver.client.ListObjects(context.Background(), driver.bucket, minio.ListObjectsOptions{})
|
|
|
|
for object := range channel {
|
|
|
|
if object.Err != nil {
|
|
|
|
return nil, object.Err
|
|
|
|
}
|
|
|
|
ids = append(ids, strings.TrimSuffix(object.Key, ".json"))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return the IDs slice
|
|
|
|
return ids, nil
|
|
|
|
}
|
|
|
|
|
2020-08-24 00:44:47 +03:00
|
|
|
// Get loads a paste
|
2021-04-15 21:15:42 +03:00
|
|
|
func (driver *S3Driver) Get(id string) (*shared.Paste, error) {
|
2020-08-24 00:44:47 +03:00
|
|
|
// Read the object
|
2020-08-24 21:22:53 +03:00
|
|
|
object, err := driver.client.GetObject(context.Background(), driver.bucket, id+".json", minio.GetObjectOptions{})
|
2020-08-24 00:44:47 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
data, err := ioutil.ReadAll(object)
|
|
|
|
if err != nil {
|
2020-09-02 20:13:49 +03:00
|
|
|
if minio.ToErrorResponse(err).Code == "NoSuchKey" {
|
|
|
|
return nil, nil
|
|
|
|
}
|
2020-08-24 00:44:47 +03:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unmarshal the object into a paste
|
2021-04-15 21:15:42 +03:00
|
|
|
paste := new(shared.Paste)
|
2020-08-24 00:44:47 +03:00
|
|
|
err = json.Unmarshal(data, &paste)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return paste, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save saves a paste
|
2021-04-15 21:15:42 +03:00
|
|
|
func (driver *S3Driver) Save(paste *shared.Paste) error {
|
2020-08-24 00:44:47 +03:00
|
|
|
// Marshal the paste
|
|
|
|
jsonBytes, err := json.Marshal(paste)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Put the object
|
|
|
|
reader := bytes.NewReader(jsonBytes)
|
2020-08-24 21:22:53 +03:00
|
|
|
_, err = driver.client.PutObject(context.Background(), driver.bucket, paste.ID+".json", reader, reader.Size(), minio.PutObjectOptions{
|
2020-08-24 00:44:47 +03:00
|
|
|
ContentType: "application/json",
|
|
|
|
})
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete deletes a paste
|
2020-08-24 21:22:53 +03:00
|
|
|
func (driver *S3Driver) Delete(id string) error {
|
|
|
|
return driver.client.RemoveObject(context.Background(), driver.bucket, id+".json", minio.RemoveObjectOptions{})
|
2020-08-24 00:44:47 +03:00
|
|
|
}
|
2020-09-19 02:56:50 +03:00
|
|
|
|
|
|
|
// Cleanup cleans up the expired pastes
|
|
|
|
func (driver *S3Driver) Cleanup() (int, error) {
|
|
|
|
// Retrieve all paste IDs
|
|
|
|
ids, err := driver.ListIDs()
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Define the amount of deleted items
|
|
|
|
deleted := 0
|
|
|
|
|
|
|
|
// Loop through all pastes
|
|
|
|
for _, id := range ids {
|
|
|
|
// Retrieve the paste object
|
|
|
|
paste, err := driver.Get(id)
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete the paste if it is expired
|
2021-04-15 21:15:42 +03:00
|
|
|
lifetime := config.Current.AutoDelete.Lifetime
|
2021-07-30 22:51:33 +03:00
|
|
|
if paste.Created+int64(lifetime.Seconds()) < time.Now().Unix() {
|
2020-09-19 02:56:50 +03:00
|
|
|
err = driver.Delete(id)
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
deleted++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return deleted, nil
|
|
|
|
}
|