mirror of
https://github.com/gmemstr/sliproad.git
synced 2024-09-20 00:21:15 +01:00
8db4a35994
Implemented a few new functions to handle the differences between local and remote files - local files will be served (best it can be) with ServeContent(), while remote files will be passed through from the response body directly to the response writer. This isn't a very elegant solution right now, but hoping to refactor this approach and simplify the decision logic. However, serving files from local disks is much better, including improvements to video files and generally better handling of metadata. Also some small tweaks to the frontned to align things a little nicer.
274 lines
6.1 KiB
Go
274 lines
6.1 KiB
Go
package files
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/sha1"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
type BackblazeProvider struct {
|
|
FileProvider
|
|
Bucket string
|
|
DownloadLocation string
|
|
}
|
|
|
|
type BackblazeAuthPayload struct {
|
|
AccountId string `json:"accountId"`
|
|
AuthToken string `json:"authorizationToken"`
|
|
ApiUrl string `json:"apiUrl"`
|
|
DownloadUrl string `json:"downloadUrl"`
|
|
}
|
|
|
|
type BackblazeFile struct {
|
|
Action string `json:"action"`
|
|
Size int64 `json:"contentLength"`
|
|
Type string `json:"contentType"`
|
|
FileName string `json:"fileName"`
|
|
Timestamp int64 `json:"uploadTimestamp"`
|
|
}
|
|
|
|
type BackblazeFilePayload struct {
|
|
Files []BackblazeFile `json:"files"`
|
|
}
|
|
|
|
type BackblazeBucketInfo struct {
|
|
BucketId string `json:"bucketId"`
|
|
BucketName string `json:"bucketName"`
|
|
}
|
|
|
|
type BackblazeBucketInfoPayload struct {
|
|
Buckets []BackblazeBucketInfo `json:"buckets"`
|
|
}
|
|
|
|
type BackblazeUploadInfo struct {
|
|
UploadUrl string `json:"uploadUrl"`
|
|
AuthToken string `json:"authorizationToken"`
|
|
}
|
|
|
|
// Call Backblaze API endpoint to authorize and gather facts.
|
|
func (bp *BackblazeProvider) Setup(args map[string]string) bool {
|
|
applicationKeyId := args["applicationKeyId"]
|
|
applicationKey := args["applicationKey"]
|
|
|
|
client := &http.Client{}
|
|
req, err := http.NewRequest("GET",
|
|
"https://api.backblazeb2.com/b2api/v2/b2_authorize_account",
|
|
nil)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
req.SetBasicAuth(applicationKeyId, applicationKey)
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
defer resp.Body.Close()
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
var data BackblazeAuthPayload
|
|
|
|
err = json.Unmarshal(body, &data)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
bp.Authentication = data.AuthToken
|
|
bp.Location = data.ApiUrl
|
|
bp.Name = data.AccountId
|
|
bp.DownloadLocation = data.DownloadUrl
|
|
|
|
return true
|
|
}
|
|
|
|
func (bp *BackblazeProvider) GetDirectory(path string) Directory {
|
|
client := &http.Client{}
|
|
|
|
requestBody := fmt.Sprintf(`{"bucketId": "%s"}`, bp.Bucket)
|
|
|
|
req, err := http.NewRequest("POST",
|
|
bp.Location + "/b2api/v2/b2_list_file_names",
|
|
bytes.NewBuffer([]byte(requestBody)))
|
|
if err != nil {
|
|
fmt.Println(err.Error())
|
|
return Directory{}
|
|
}
|
|
req.Header.Add("Authorization", bp.Authentication)
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
fmt.Println(err.Error())
|
|
return Directory{}
|
|
}
|
|
defer resp.Body.Close()
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
if err != nil {
|
|
fmt.Println(err.Error())
|
|
return Directory{}
|
|
}
|
|
|
|
var data BackblazeFilePayload
|
|
err = json.Unmarshal(body, &data)
|
|
if err != nil {
|
|
fmt.Println(err.Error())
|
|
return Directory{}
|
|
}
|
|
finalDir := Directory{
|
|
Path: bp.Bucket,
|
|
}
|
|
for _, v := range data.Files {
|
|
file := FileInfo{
|
|
IsDirectory: v.Action == "folder",
|
|
Name: v.FileName,
|
|
}
|
|
if v.Action != "folder" {
|
|
split := strings.Split(v.FileName, ".")
|
|
file.Extension = split[len(split) - 1]
|
|
}
|
|
finalDir.Files = append(finalDir.Files, file)
|
|
}
|
|
|
|
return finalDir
|
|
}
|
|
|
|
func (bp *BackblazeProvider) ViewFile(path string) string {
|
|
return ""
|
|
}
|
|
|
|
func (bp *BackblazeProvider) RemoteFile(path string, w io.Writer) {
|
|
client := &http.Client{}
|
|
// Get bucket name >:(
|
|
bucketIdPayload := fmt.Sprintf(`{"accountId": "%s", "bucketId": "%s"}`, bp.Name, bp.Bucket)
|
|
|
|
req, err := http.NewRequest("POST", bp.Location + "/b2api/v2/b2_list_buckets",
|
|
bytes.NewBuffer([]byte(bucketIdPayload)))
|
|
if err != nil {
|
|
fmt.Println(err.Error())
|
|
return
|
|
}
|
|
req.Header.Add("Authorization", bp.Authentication)
|
|
|
|
res, err := client.Do(req)
|
|
if err != nil {
|
|
fmt.Println(err.Error())
|
|
return
|
|
}
|
|
bucketData, err := ioutil.ReadAll(res.Body)
|
|
if err != nil {
|
|
fmt.Println(err.Error())
|
|
return
|
|
}
|
|
|
|
var data BackblazeBucketInfoPayload
|
|
json.Unmarshal(bucketData, &data)
|
|
ourBucket := data.Buckets[0].BucketName
|
|
// Get file and write over to client.
|
|
url := strings.Join([]string{bp.DownloadLocation,"file",ourBucket,path}, "/")
|
|
req, err = http.NewRequest("GET",
|
|
url,
|
|
bytes.NewBuffer([]byte("")))
|
|
if err != nil {
|
|
fmt.Println(err.Error())
|
|
return
|
|
}
|
|
req.Header.Add("Authorization", bp.Authentication)
|
|
file, err := client.Do(req)
|
|
|
|
if err != nil {
|
|
fmt.Println(err.Error())
|
|
return
|
|
}
|
|
|
|
_, err = io.Copy(w, file.Body)
|
|
if err != nil {
|
|
fmt.Println(err.Error())
|
|
return
|
|
}
|
|
}
|
|
|
|
func (bp *BackblazeProvider) SaveFile(file io.Reader, filename string, path string) bool {
|
|
client := &http.Client{}
|
|
bucketIdPayload := fmt.Sprintf(`{"bucketId": "%s"}`, bp.Bucket)
|
|
|
|
req, err := http.NewRequest("POST", bp.Location + "/b2api/v2/b2_get_upload_url",
|
|
bytes.NewBuffer([]byte(bucketIdPayload)))
|
|
if err != nil {
|
|
fmt.Println(err.Error())
|
|
return false
|
|
}
|
|
req.Header.Add("Authorization", bp.Authentication)
|
|
|
|
res, err := client.Do(req)
|
|
if err != nil {
|
|
fmt.Println(err.Error())
|
|
return false
|
|
}
|
|
bucketData, err := ioutil.ReadAll(res.Body)
|
|
if err != nil {
|
|
fmt.Println(err.Error())
|
|
return false
|
|
}
|
|
|
|
var data BackblazeUploadInfo
|
|
err = json.Unmarshal(bucketData, &data)
|
|
if err != nil {
|
|
fmt.Println(err.Error())
|
|
return false
|
|
}
|
|
|
|
req, err = http.NewRequest("POST",
|
|
data.UploadUrl,
|
|
file,
|
|
)
|
|
if err != nil {
|
|
fmt.Println(err.Error())
|
|
return false
|
|
}
|
|
// Read the content
|
|
var bodyBytes []byte
|
|
if req.Body != nil {
|
|
bodyBytes, _ = ioutil.ReadAll(req.Body)
|
|
}
|
|
req.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
|
|
|
|
// Calculate SHA1 and add required headers.
|
|
fileSha := sha1.New()
|
|
fileSha.Write(bodyBytes)
|
|
|
|
req.Header.Add("Authorization", data.AuthToken)
|
|
req.Header.Add("X-Bz-File-Name", filename)
|
|
req.Header.Add("Content-Type", "b2/x-auto")
|
|
req.Header.Add("X-Bz-Content-Sha1", fmt.Sprintf("%x", fileSha.Sum(nil)))
|
|
req.ContentLength = int64(len(bodyBytes))
|
|
|
|
res, err = client.Do(req)
|
|
if err != nil {
|
|
fmt.Println(err.Error())
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func (bp *BackblazeProvider) ObjectInfo(path string) (string, string) {
|
|
// B2 is really a "flat" filesystem, with directories being virtual.
|
|
// Therefore, we can assume everything is a file ;)
|
|
return "file", "remote"
|
|
}
|
|
|
|
func (bp *BackblazeProvider) CreateDirectory(path string) bool {
|
|
// See above comment about virtual directories.
|
|
return false
|
|
}
|
|
|
|
func (bp *BackblazeProvider) Delete(path string) bool {
|
|
// TODO
|
|
return false
|
|
} |