mirror of
https://github.com/gmemstr/sliproad.git
synced 2024-09-19 16:11:11 +01:00
Simplify file serving from local or remote.
Prior, we would decide how to serve a file based on whether it was local or remote at a router level. This moves everything to an io.Copy call in the router with the Provider returning an io.Reader.
This commit is contained in:
parent
8127aaa6a8
commit
54fe5f9c5c
|
@ -7,7 +7,9 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
@ -142,7 +144,7 @@ func (bp *BackblazeProvider) FilePath(path string) string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func (bp *BackblazeProvider) RemoteFile(path string, w io.Writer) {
|
||||
func (bp *BackblazeProvider) SendFile(path string, w io.Writer) (stream io.Reader, contenttype string, err error) {
|
||||
client := &http.Client{}
|
||||
// Get bucket name >:(
|
||||
bucketIdPayload := fmt.Sprintf(`{"accountId": "%s", "bucketId": "%s"}`, bp.Name, bp.Bucket)
|
||||
|
@ -150,20 +152,17 @@ func (bp *BackblazeProvider) RemoteFile(path string, w io.Writer) {
|
|||
req, err := http.NewRequest("POST", bp.Location + "/b2api/v2/b2_list_buckets",
|
||||
bytes.NewBuffer([]byte(bucketIdPayload)))
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
return nil, contenttype, err
|
||||
}
|
||||
req.Header.Add("Authorization", bp.Authentication)
|
||||
|
||||
res, err := client.Do(req)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
return nil, contenttype, err
|
||||
}
|
||||
bucketData, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
return nil, contenttype, err
|
||||
}
|
||||
|
||||
var data BackblazeBucketInfoPayload
|
||||
|
@ -175,22 +174,23 @@ func (bp *BackblazeProvider) RemoteFile(path string, w io.Writer) {
|
|||
url,
|
||||
bytes.NewBuffer([]byte("")))
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
return nil, contenttype, err
|
||||
}
|
||||
req.Header.Add("Authorization", bp.Authentication)
|
||||
file, err := client.Do(req)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
return nil, contenttype, err
|
||||
}
|
||||
|
||||
_, err = io.Copy(w, file.Body)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
contenttype = mime.TypeByExtension(filepath.Ext(path))
|
||||
if contenttype == "" {
|
||||
var buf [512]byte
|
||||
n, _ := io.ReadFull(file.Body, buf[:])
|
||||
contenttype = http.DetectContentType(buf[:n])
|
||||
}
|
||||
|
||||
return file.Body, contenttype, err
|
||||
}
|
||||
|
||||
func (bp *BackblazeProvider) SaveFile(file io.Reader, filename string, path string) bool {
|
||||
|
|
|
@ -4,7 +4,10 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
@ -42,13 +45,22 @@ func (dp *DiskProvider) GetDirectory(path string) Directory {
|
|||
}
|
||||
}
|
||||
|
||||
func (dp *DiskProvider) FilePath(path string) string {
|
||||
func (dp *DiskProvider) SendFile(path string, writer io.Writer) (stream io.Reader, contenttype string, err error) {
|
||||
rp := strings.Join([]string{dp.Location,path}, "/")
|
||||
return rp
|
||||
f, err := os.Open(rp)
|
||||
if err != nil {
|
||||
return stream, contenttype, err
|
||||
}
|
||||
|
||||
func (dp *DiskProvider) RemoteFile(path string, writer io.Writer) {
|
||||
return
|
||||
contenttype = mime.TypeByExtension(filepath.Ext(rp))
|
||||
|
||||
if contenttype == "" {
|
||||
var buf [512]byte
|
||||
n, _ := io.ReadFull(f, buf[:])
|
||||
contenttype = http.DetectContentType(buf[:n])
|
||||
}
|
||||
|
||||
return f, contenttype, nil
|
||||
}
|
||||
|
||||
func (dp *DiskProvider) SaveFile(file io.Reader, filename string, path string) bool {
|
||||
|
|
|
@ -39,7 +39,7 @@ type FileProviderInterface interface {
|
|||
Setup(args map[string]string) (ok bool)
|
||||
GetDirectory(path string) (directory Directory)
|
||||
FilePath(path string) (realpath string)
|
||||
RemoteFile(path string, writer io.Writer)
|
||||
SendFile(path string, writer io.Writer) (stream io.Reader, contenttype string, err error)
|
||||
SaveFile(file io.Reader, filename string, path string) (ok bool)
|
||||
ObjectInfo(path string) (exists bool, isDir bool, location string)
|
||||
CreateDirectory(path string) (ok bool)
|
||||
|
@ -64,7 +64,7 @@ func (f FileProvider) FilePath(path string) string {
|
|||
}
|
||||
|
||||
// RemoteFile will bypass http.ServeContent() and instead write directly to the response.
|
||||
func (f FileProvider) RemoteFile(path string, writer io.Writer) {
|
||||
func (f FileProvider) SendFile(path string, writer io.Writer) (stream io.Reader, contenttype string, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -3,14 +3,14 @@ package router
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gmemstr/nas/files"
|
||||
"github.com/gorilla/mux"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gmemstr/nas/files"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
func handleProvider() handler {
|
||||
|
@ -29,7 +29,7 @@ func handleProvider() handler {
|
|||
StatusCode: http.StatusInternalServerError,
|
||||
}
|
||||
}
|
||||
ok, isDir, location := provider.ObjectInfo(filename)
|
||||
ok, isDir, _ := provider.ObjectInfo(filename)
|
||||
if !ok {
|
||||
return &httpError{
|
||||
Message: fmt.Sprintf("error locating file %s\n", filename),
|
||||
|
@ -49,27 +49,25 @@ func handleProvider() handler {
|
|||
}
|
||||
w.Write(data)
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
stream, contenttype, err := provider.SendFile(filename, w)
|
||||
|
||||
// If the file is local, attempt to use http.ServeContent for correct headers.
|
||||
if location == files.FileIsLocal {
|
||||
rp := provider.FilePath(filename)
|
||||
if rp != "" {
|
||||
f, err := os.Open(rp)
|
||||
if err != nil {
|
||||
return &httpError{
|
||||
Message: fmt.Sprintf("error opening file %s\n", rp),
|
||||
StatusCode: http.StatusInternalServerError,
|
||||
Message: fmt.Sprintf("error finding file %s\n", vars["file"]),
|
||||
StatusCode: http.StatusNotFound,
|
||||
}
|
||||
}
|
||||
http.ServeContent(w, r, filename, time.Time{}, f)
|
||||
w.Header().Set("Content-Type", contenttype)
|
||||
_, err = io.Copy(w, stream)
|
||||
if err != nil {
|
||||
return &httpError{
|
||||
Message: fmt.Sprintf("unable to write %s\n", vars["file"]),
|
||||
StatusCode: http.StatusBadGateway,
|
||||
}
|
||||
}
|
||||
// If the file is remote, then delegate the writing to the response to the provider.
|
||||
// This isn't a great workaround, but avoids caching the whole file in mem or on disk.
|
||||
if location == files.FileIsRemote {
|
||||
provider.RemoteFile(filename, w)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue