Implement SendFile() and ObjectInfo() for S3.

Also removed a now useless parameter for file providers, which used to
be for writing directly to the HTTP response.
This commit is contained in:
Gabriel Simmer 2021-05-29 10:48:32 +01:00
parent 22e1df4bc7
commit 550e722a53
5 changed files with 50 additions and 8 deletions

View file

@ -140,7 +140,7 @@ func (bp *BackblazeProvider) GetDirectory(path string) Directory {
return finalDir return finalDir
} }
func (bp *BackblazeProvider) SendFile(path string, w io.Writer) (stream io.Reader, contenttype string, err error) { func (bp *BackblazeProvider) SendFile(path string) (stream io.Reader, contenttype string, err error) {
client := &http.Client{} client := &http.Client{}
// Get bucket name >:( // Get bucket name >:(
bucketIdPayload := fmt.Sprintf(`{"accountId": "%s", "bucketId": "%s"}`, bp.Name, bp.Bucket) bucketIdPayload := fmt.Sprintf(`{"accountId": "%s", "bucketId": "%s"}`, bp.Name, bp.Bucket)

View file

@ -45,7 +45,7 @@ func (dp *DiskProvider) GetDirectory(path string) Directory {
} }
} }
func (dp *DiskProvider) SendFile(path string, writer io.Writer) (stream io.Reader, contenttype string, err error) { func (dp *DiskProvider) SendFile(path string) (stream io.Reader, contenttype string, err error) {
rp := strings.Join([]string{dp.Location,path}, "/") rp := strings.Join([]string{dp.Location,path}, "/")
f, err := os.Open(rp) f, err := os.Open(rp)
if err != nil { if err != nil {

View file

@ -38,7 +38,7 @@ type FileInfo struct {
type FileProviderInterface interface { type FileProviderInterface interface {
Setup(args map[string]string) (ok bool) Setup(args map[string]string) (ok bool)
GetDirectory(path string) (directory Directory) GetDirectory(path string) (directory Directory)
SendFile(path string, writer io.Writer) (stream io.Reader, contenttype string, err error) SendFile(path string) (stream io.Reader, contenttype string, err error)
SaveFile(file io.Reader, filename string, path string) (ok bool) SaveFile(file io.Reader, filename string, path string) (ok bool)
ObjectInfo(path string) (exists bool, isDir bool, location string) ObjectInfo(path string) (exists bool, isDir bool, location string)
CreateDirectory(path string) (ok bool) CreateDirectory(path string) (ok bool)
@ -58,7 +58,7 @@ func (f FileProvider) GetDirectory(path string) Directory {
} }
// RemoteFile will bypass http.ServeContent() and instead write directly to the response. // RemoteFile will bypass http.ServeContent() and instead write directly to the response.
func (f FileProvider) SendFile(path string, writer io.Writer) (stream io.Reader, contenttype string, err error) { func (f FileProvider) SendFile(path string) (stream io.Reader, contenttype string, err error) {
return return
} }

View file

@ -3,6 +3,10 @@ package files
import ( import (
"fmt" "fmt"
"io" "io"
"mime"
"path/filepath"
"net/http"
// I _really_ don't want to deal with AWS API stuff by hand. // I _really_ don't want to deal with AWS API stuff by hand.
"github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/aws/session"
@ -10,6 +14,7 @@ import (
) )
var svc s3.S3 var svc s3.S3
var sess *session.Session
type S3Provider struct { type S3Provider struct {
FileProvider FileProvider
@ -40,6 +45,15 @@ func (s *S3Provider) GetDirectory(path string) Directory {
dir := Directory{} dir := Directory{}
for _, item := range resp.Contents { for _, item := range resp.Contents {
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
}
file := FileInfo{ file := FileInfo{
IsDirectory: false, IsDirectory: false,
Name: *item.Key, Name: *item.Key,
@ -51,8 +65,23 @@ func (s *S3Provider) GetDirectory(path string) Directory {
} }
// RemoteFile will bypass http.ServeContent() and instead write directly to the response. // RemoteFile will bypass http.ServeContent() and instead write directly to the response.
func (s *S3Provider) SendFile(path string, writer io.Writer) (stream io.Reader, contenttype string, err error) { func (s *S3Provider) SendFile(path string) (stream io.Reader, contenttype string, err error) {
return req, err := svc.GetObject(&s3.GetObjectInput{
Bucket: &s.Bucket,
Key: &path,
})
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
} }
// SaveFile will save a file with the contents of the io.Reader at the path specified. // SaveFile will save a file with the contents of the io.Reader at the path specified.
@ -64,9 +93,22 @@ func (s *S3Provider) SaveFile(file io.Reader, filename string, path string) bool
// Should return whether the path exists, if the path is a directory, and if it lives on disk. // Should return whether the path exists, if the path is a directory, and if it lives on disk.
// (see constants defined: `FILE_IS_REMOTE` and `FILE_IS_LOCAL`) // (see constants defined: `FILE_IS_REMOTE` and `FILE_IS_LOCAL`)
func (s *S3Provider) ObjectInfo(path string) (bool, bool, string) { func (s *S3Provider) ObjectInfo(path string) (bool, bool, string) {
if path == "" {
return true, true, "" return true, true, ""
} }
_, err := svc.GetObject(&s3.GetObjectInput{
Bucket: &s.Bucket,
Key: &path,
})
if err != nil {
fmt.Println(err)
return false, false, ""
}
return true, false, ""
}
// CreateDirectory will create a directory on services that support it. // CreateDirectory will create a directory on services that support it.
func (s *S3Provider) CreateDirectory(path string) bool { func (s *S3Provider) CreateDirectory(path string) bool {
return false return false

View file

@ -50,7 +50,7 @@ func handleProvider() handler {
w.Write(data) w.Write(data)
return nil return nil
} else { } else {
stream, contenttype, err := provider.SendFile(filename, w) stream, contenttype, err := provider.SendFile(filename)
if err != nil { if err != nil {
return &httpError{ return &httpError{