2021-05-28 22:43:30 +01:00
|
|
|
package files
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io"
|
2021-05-29 10:48:32 +01:00
|
|
|
"mime"
|
|
|
|
"net/http"
|
2021-05-29 19:37:45 +01:00
|
|
|
"path/filepath"
|
2021-05-29 10:48:32 +01:00
|
|
|
|
2021-05-28 22:43:30 +01:00
|
|
|
// I _really_ don't want to deal with AWS API stuff by hand.
|
|
|
|
"github.com/aws/aws-sdk-go/aws"
|
2021-05-29 19:37:45 +01:00
|
|
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
2021-05-28 22:43:30 +01:00
|
|
|
"github.com/aws/aws-sdk-go/aws/session"
|
|
|
|
"github.com/aws/aws-sdk-go/service/s3"
|
2021-05-29 19:53:03 +01:00
|
|
|
"github.com/aws/aws-sdk-go/service/s3/s3manager"
|
2021-05-28 22:43:30 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
var svc s3.S3
|
2021-05-29 19:53:03 +01:00
|
|
|
var sess session.Session
|
2021-05-28 22:43:30 +01:00
|
|
|
|
|
|
|
type S3Provider struct {
|
|
|
|
FileProvider
|
2021-05-29 19:37:45 +01:00
|
|
|
Region string
|
|
|
|
Bucket string
|
|
|
|
Endpoint string
|
|
|
|
KeyID string
|
|
|
|
KeySecret string
|
2021-05-28 22:43:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Setup runs when the application starts up, and allows for things like authentication.
|
|
|
|
func (s *S3Provider) Setup(args map[string]string) bool {
|
2021-05-29 19:37:45 +01:00
|
|
|
config := &aws.Config{Region: aws.String(s.Region)}
|
|
|
|
if s.KeyID != "" && s.KeySecret != "" {
|
|
|
|
config = &aws.Config{
|
|
|
|
Region: aws.String(s.Region),
|
|
|
|
Credentials: credentials.NewStaticCredentials(s.KeyID, s.KeySecret, ""),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if s.Endpoint != "" {
|
|
|
|
config.Endpoint = &s.Endpoint
|
|
|
|
}
|
2021-05-29 19:53:03 +01:00
|
|
|
ss, err := session.NewSession(config)
|
|
|
|
sess = *ss
|
2021-05-28 22:43:30 +01:00
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
2021-05-29 19:53:03 +01:00
|
|
|
svc = *s3.New(&sess)
|
2021-05-28 22:43:30 +01:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetDirectory fetches a directory's contents.
|
|
|
|
func (s *S3Provider) GetDirectory(path string) Directory {
|
|
|
|
resp, err := svc.ListObjectsV2(&s3.ListObjectsV2Input{Bucket: aws.String(s.Bucket)})
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
2021-05-29 19:37:45 +01:00
|
|
|
return Directory{}
|
2021-05-28 22:43:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
dir := Directory{}
|
|
|
|
for _, item := range resp.Contents {
|
2021-05-29 10:48:32 +01:00
|
|
|
ik := *item.Key
|
|
|
|
// Why is this here? AWS returns a complete list of files, including
|
|
|
|
// files within subdirectories (prefixed with the dir name). So we can
|
|
|
|
// ignore directories altogether -- I would prefer to display them but
|
|
|
|
// not sure what the best method of distinguishing them in ObjectInfo()
|
|
|
|
// would be.
|
|
|
|
if ik[len(ik)-1:] == "/" {
|
|
|
|
continue
|
|
|
|
}
|
2021-05-28 22:43:30 +01:00
|
|
|
file := FileInfo{
|
|
|
|
IsDirectory: false,
|
2021-05-29 19:37:45 +01:00
|
|
|
Name: *item.Key,
|
2021-05-28 22:43:30 +01:00
|
|
|
}
|
|
|
|
dir.Files = append(dir.Files, file)
|
|
|
|
}
|
|
|
|
|
|
|
|
return dir
|
|
|
|
}
|
|
|
|
|
2021-05-29 10:48:32 +01:00
|
|
|
func (s *S3Provider) SendFile(path string) (stream io.Reader, contenttype string, err error) {
|
|
|
|
req, err := svc.GetObject(&s3.GetObjectInput{
|
|
|
|
Bucket: &s.Bucket,
|
2021-05-29 19:37:45 +01:00
|
|
|
Key: &path,
|
2021-05-29 10:48:32 +01:00
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return stream, contenttype, err
|
|
|
|
}
|
|
|
|
|
|
|
|
contenttype = mime.TypeByExtension(filepath.Ext(path))
|
|
|
|
if contenttype == "" {
|
|
|
|
var buf [512]byte
|
|
|
|
n, _ := io.ReadFull(req.Body, buf[:])
|
|
|
|
contenttype = http.DetectContentType(buf[:n])
|
|
|
|
}
|
|
|
|
|
|
|
|
return req.Body, contenttype, err
|
2021-05-28 22:43:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *S3Provider) SaveFile(file io.Reader, filename string, path string) bool {
|
2021-05-29 19:53:03 +01:00
|
|
|
uploader := s3manager.NewUploader(&sess)
|
|
|
|
_, err := uploader.Upload(&s3manager.UploadInput{
|
2021-05-29 19:57:49 +01:00
|
|
|
Bucket: &s.Bucket,
|
|
|
|
Key: &filename,
|
|
|
|
Body: file,
|
2021-05-29 19:53:03 +01:00
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
2021-05-28 22:43:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *S3Provider) ObjectInfo(path string) (bool, bool, string) {
|
2021-05-29 10:48:32 +01:00
|
|
|
if path == "" {
|
|
|
|
return true, true, ""
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err := svc.GetObject(&s3.GetObjectInput{
|
|
|
|
Bucket: &s.Bucket,
|
2021-05-29 19:37:45 +01:00
|
|
|
Key: &path,
|
2021-05-29 10:48:32 +01:00
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
return false, false, ""
|
|
|
|
}
|
|
|
|
|
|
|
|
return true, false, ""
|
2021-05-28 22:43:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// CreateDirectory will create a directory on services that support it.
|
|
|
|
func (s *S3Provider) CreateDirectory(path string) bool {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete simply deletes a file. This is expected to be a destructive action by default.
|
|
|
|
func (s *S3Provider) Delete(path string) bool {
|
2021-05-29 19:57:49 +01:00
|
|
|
_, err := svc.DeleteObject(&s3.DeleteObjectInput{Bucket: aws.String(s.Bucket), Key: aws.String(path)})
|
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
err = svc.WaitUntilObjectNotExists(&s3.HeadObjectInput{
|
|
|
|
Bucket: aws.String(s.Bucket),
|
|
|
|
Key: aws.String(path),
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
2021-05-28 22:43:30 +01:00
|
|
|
}
|