Pierre-Olivier Mercier
ecda17fc7d
All checks were successful
continuous-integration/drone/push Build is passing
273 lines
6.1 KiB
Go
273 lines
6.1 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"flag"
|
|
"fmt"
|
|
"image"
|
|
"image/jpeg"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"path"
|
|
|
|
"github.com/aws/aws-sdk-go/aws"
|
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
|
"github.com/aws/aws-sdk-go/aws/session"
|
|
"github.com/aws/aws-sdk-go/service/s3"
|
|
"github.com/aws/aws-sdk-go/service/s3/s3manager"
|
|
)
|
|
|
|
var (
|
|
s3_endpoint string
|
|
s3_region = "us"
|
|
s3_bucket string
|
|
s3_access_key string
|
|
s3_secret_key string
|
|
s3_path_style bool
|
|
)
|
|
|
|
func init() {
|
|
existing_backends = append(existing_backends, "s3")
|
|
|
|
if endpoint, ok := os.LookupEnv("S3_ENDPOINT"); ok {
|
|
backend = "s3"
|
|
s3_endpoint = endpoint
|
|
}
|
|
if region, ok := os.LookupEnv("S3_REGION"); ok {
|
|
backend = "s3"
|
|
s3_region = region
|
|
}
|
|
s3_bucket, _ = os.LookupEnv("S3_BUCKET")
|
|
s3_access_key, _ = os.LookupEnv("S3_ACCESS_KEY")
|
|
s3_secret_key, _ = os.LookupEnv("S3_SECRET_KEY")
|
|
if path_style, ok := os.LookupEnv("S3_PATH_STYLE"); ok {
|
|
s3_path_style = path_style == "1" || path_style == "ON" || path_style == "on" || path_style == "TRUE" || path_style == "true" || path_style == "yes" || path_style == "YES"
|
|
}
|
|
|
|
flag.StringVar(&s3_endpoint, "s3-endpoint", s3_endpoint, "When using S3 backend, endpoint to use")
|
|
flag.StringVar(&s3_region, "s3-region", s3_region, "When using S3 backend, region to use")
|
|
flag.StringVar(&s3_bucket, "s3-bucket", s3_bucket, "When using S3 backend, bucket to use")
|
|
flag.StringVar(&s3_access_key, "s3-access-key", s3_access_key, "When using S3 backend, Access Key")
|
|
flag.StringVar(&s3_secret_key, "s3-secret-key", s3_secret_key, "When using S3 backend, Secret Key")
|
|
flag.BoolVar(&s3_path_style, "s3-path-style", s3_path_style, "When using S3 backend, force path style (when using minio)")
|
|
}
|
|
|
|
type S3FileBackend struct {
|
|
Endpoint string
|
|
Region string
|
|
Bucket string
|
|
AccessKey string
|
|
SecretKey string
|
|
PathStyle bool
|
|
BaseDir string
|
|
}
|
|
|
|
func (l *S3FileBackend) getPath(box, name string) string {
|
|
if l.BaseDir == "" {
|
|
return path.Join(box, name+".jpg")
|
|
} else {
|
|
return path.Join(l.BaseDir, box, name+".jpg")
|
|
}
|
|
}
|
|
|
|
func (l *S3FileBackend) newSession() (*session.Session, error) {
|
|
return session.NewSession(&aws.Config{
|
|
Credentials: credentials.NewStaticCredentials(l.AccessKey, l.SecretKey, ""),
|
|
Endpoint: &l.Endpoint,
|
|
Region: &l.Region,
|
|
S3ForcePathStyle: &l.PathStyle,
|
|
})
|
|
}
|
|
|
|
func (l *S3FileBackend) DeletePicture(box, name string) error {
|
|
s, err := l.newSession()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
log.Println(l.getPath(box, name))
|
|
|
|
input := &s3.DeleteObjectsInput{
|
|
Bucket: aws.String(l.Bucket),
|
|
Delete: &s3.Delete{
|
|
Objects: []*s3.ObjectIdentifier{
|
|
{
|
|
Key: aws.String(l.getPath(box, name)),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
_, err = s3.New(s).DeleteObjects(input)
|
|
return err
|
|
}
|
|
|
|
func (l *S3FileBackend) ServeFile() http.Handler {
|
|
return l
|
|
}
|
|
|
|
func (l *S3FileBackend) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
s, err := l.newSession()
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
result, err := s3.New(s).GetObject(&s3.GetObjectInput{
|
|
Bucket: aws.String(l.Bucket),
|
|
Key: aws.String(r.URL.Path),
|
|
})
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
io.Copy(w, result.Body)
|
|
}
|
|
|
|
func (l *S3FileBackend) createPictureInfo(local_path, name string, file *s3.Object) *Picture {
|
|
return &Picture{
|
|
local_path, // Path
|
|
name, // Basename
|
|
name[:len(name)-len(path.Ext(name))], // Sanitized filename
|
|
*file.LastModified, // UploadTime
|
|
}
|
|
}
|
|
|
|
func (l *S3FileBackend) GetPicture(box, name string, w io.Writer) error {
|
|
s, err := l.newSession()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
s3_path := l.getPath(box, name)
|
|
|
|
input := &s3.GetObjectInput{
|
|
Bucket: aws.String(l.Bucket),
|
|
Key: aws.String(s3_path),
|
|
}
|
|
|
|
result, err := s3.New(s).GetObject(input)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = io.Copy(w, result.Body)
|
|
|
|
return err
|
|
}
|
|
|
|
func (l *S3FileBackend) GetPictureInfo(box, name string) (*Picture, error) {
|
|
s, err := l.newSession()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
input := &s3.ListObjectsInput{
|
|
Bucket: aws.String(l.Bucket),
|
|
Prefix: aws.String(l.getPath(box, name)),
|
|
}
|
|
|
|
result, err := s3.New(s).ListObjects(input)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var pictures []*Picture
|
|
for _, file := range result.Contents {
|
|
pictures = append(pictures, l.createPictureInfo(*file.Key, path.Base(*file.Key), file))
|
|
break
|
|
}
|
|
|
|
if len(pictures) == 0 {
|
|
return nil, fmt.Errorf("Object not found")
|
|
}
|
|
|
|
return pictures[0], nil
|
|
}
|
|
|
|
func (l *S3FileBackend) ListPictures(box string) ([]*Picture, error) {
|
|
s, err := l.newSession()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
input := &s3.ListObjectsInput{
|
|
Bucket: aws.String(l.Bucket),
|
|
}
|
|
|
|
if l.BaseDir == "" {
|
|
input.Prefix = aws.String(box)
|
|
} else {
|
|
input.Prefix = aws.String(path.Join(l.BaseDir, box))
|
|
}
|
|
|
|
result, err := s3.New(s).ListObjects(input)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
pictures := make([]*Picture, 0)
|
|
for _, file := range result.Contents {
|
|
pictures = append(pictures, l.createPictureInfo(path.Join(box, *file.Key), path.Base(*file.Key), file))
|
|
}
|
|
|
|
return pictures, nil
|
|
}
|
|
|
|
func (l *S3FileBackend) MovePicture(box_from, box_to, name string) error {
|
|
s, err := l.newSession()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
log.Println(l.getPath(box_from, name), l.getPath(box_to, name))
|
|
|
|
_, err = s3.New(s).CopyObject(&s3.CopyObjectInput{
|
|
Bucket: aws.String(l.Bucket),
|
|
CopySource: aws.String(path.Join("", l.Bucket, l.getPath(box_from, name))),
|
|
Key: aws.String(l.getPath(box_to, name)),
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
log.Println(l.getPath(box_from, name))
|
|
|
|
input := &s3.DeleteObjectsInput{
|
|
Bucket: aws.String(l.Bucket),
|
|
Delete: &s3.Delete{
|
|
Objects: []*s3.ObjectIdentifier{
|
|
{
|
|
Key: aws.String(l.getPath(box_from, name)),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
_, err = s3.New(s).DeleteObjects(input)
|
|
return err
|
|
}
|
|
|
|
func (l *S3FileBackend) PutPicture(box, name string, img *image.Image) error {
|
|
s, err := l.newSession()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
bbuf := new(bytes.Buffer)
|
|
err = jpeg.Encode(bbuf, *img, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = s3manager.NewUploader(s).Upload(&s3manager.UploadInput{
|
|
Bucket: aws.String(l.Bucket),
|
|
ACL: aws.String("public-read"),
|
|
Key: aws.String(l.getPath(box, name)),
|
|
Body: bbuf,
|
|
})
|
|
|
|
return err
|
|
}
|