Implement Setup() function for providers, cleanup

Implemented a much-needed Setup() function for providers to implement,
which (as demonstrated in the backblaze provider) allows for
authentication in advance of needing to make calls to remote locations.
This could also be used to create a directory or perform some other
sanity check required for the provider to work. So far, haven't noticed
any performance impacts from this approach, besides not needing to auth
each time we make a request.
This commit is contained in:
Gabriel Simmer 2020-03-21 00:31:24 +00:00
parent 7450d229f4
commit 49dba732d3
No known key found for this signature in database
GPG key ID: 33BA4D83B160A0A9
6 changed files with 77 additions and 42 deletions

View file

@ -45,37 +45,42 @@ type BackblazeBucketInfoPayload struct {
} }
// Call Backblaze API endpoint to authorize and gather facts. // Call Backblaze API endpoint to authorize and gather facts.
func (bp *BackblazeProvider) Authorize(appKeyId string, appKey string) error { func (bp *BackblazeProvider) Setup(args map[string]string) bool {
applicationKeyId := args["applicationKeyId"]
applicationKey := args["applicationKey"]
client := &http.Client{} client := &http.Client{}
req, err := http.NewRequest("GET", req, err := http.NewRequest("GET",
"https://api.backblazeb2.com/b2api/v2/b2_authorize_account", "https://api.backblazeb2.com/b2api/v2/b2_authorize_account",
nil) nil)
if err != nil { if err != nil {
return err return false
} }
req.SetBasicAuth(appKeyId, appKey) req.SetBasicAuth(applicationKeyId, applicationKey)
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
return err return false
} }
defer resp.Body.Close() defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body) body, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return err return false
} }
var data BackblazeAuthPayload var data BackblazeAuthPayload
err = json.Unmarshal(body, &data) err = json.Unmarshal(body, &data)
if err != nil { if err != nil {
return err return false
} }
bp.Authentication = data.AuthToken bp.Authentication = data.AuthToken
bp.Location = data.ApiUrl bp.Location = data.ApiUrl
bp.Name = data.AccountId bp.Name = data.AccountId
bp.DownloadLocation = data.DownloadUrl bp.DownloadLocation = data.DownloadUrl
return nil return true
} }
func (bp *BackblazeProvider) GetDirectory(path string) Directory { func (bp *BackblazeProvider) GetDirectory(path string) Directory {
@ -131,10 +136,22 @@ func (bp *BackblazeProvider) ViewFile(path string, w io.Writer) {
req, err := http.NewRequest("POST", bp.Location + "/b2api/v2/b2_list_buckets", req, err := http.NewRequest("POST", bp.Location + "/b2api/v2/b2_list_buckets",
bytes.NewBuffer([]byte(bucketIdPayload))) bytes.NewBuffer([]byte(bucketIdPayload)))
if err != nil {
fmt.Println(err.Error())
return
}
req.Header.Add("Authorization", bp.Authentication) req.Header.Add("Authorization", bp.Authentication)
res, err := client.Do(req) res, err := client.Do(req)
if err != nil {
fmt.Println(err.Error())
return
}
bucketData, err := ioutil.ReadAll(res.Body) bucketData, err := ioutil.ReadAll(res.Body)
if err != nil {
fmt.Println(err.Error())
return
}
var data BackblazeBucketInfoPayload var data BackblazeBucketInfoPayload
json.Unmarshal(bucketData, &data) json.Unmarshal(bucketData, &data)
@ -169,4 +186,8 @@ func (bp *BackblazeProvider) SaveFile(contents []byte, path string) bool {
func (bp *BackblazeProvider) DetermineType(path string) string { func (bp *BackblazeProvider) DetermineType(path string) string {
return "file" return "file"
}
func (bp *BackblazeProvider) GetProviderConfig() FileProvider {
return ProviderConfig[bp.Name]
} }

View file

@ -11,6 +11,10 @@ type DiskProvider struct{
FileProvider FileProvider
} }
func (dp *DiskProvider) Setup(args map[string]string) bool {
return true
}
func (dp *DiskProvider) GetDirectory(path string) Directory { func (dp *DiskProvider) GetDirectory(path string) Directory {
rp := strings.Join([]string{dp.Location,path}, "/") rp := strings.Join([]string{dp.Location,path}, "/")
fileDir, err := ioutil.ReadDir(rp) fileDir, err := ioutil.ReadDir(rp)

View file

@ -1,7 +1,6 @@
package files package files
import ( import (
"fmt"
"io" "io"
) )
@ -24,44 +23,24 @@ type FileInfo struct {
Extension string Extension string
} }
var Providers map[string]FileProvider
type FileContents struct { type FileContents struct {
Content []byte Content []byte
IsUrl bool IsUrl bool
} }
type FileProviderInterface interface { type FileProviderInterface interface {
Setup(args map[string]string) bool
GetDirectory(path string) Directory GetDirectory(path string) Directory
ViewFile(path string, w io.Writer) ViewFile(path string, w io.Writer)
SaveFile(contents []byte, path string) bool SaveFile(contents []byte, path string) bool
DetermineType(path string) string DetermineType(path string) string
} }
func TranslateProvider(codename string, i *FileProviderInterface) { /** DO NOT USE THESE DEFAULTS **/
provider := Providers[codename] func (f FileProvider) Setup(args map[string]string) bool {
if codename == "disk" { return false
*i = &DiskProvider{provider,}
return
}
/*
* @TODO: It would be ideal if the authorization with Backblaze was done before
* actually needing to use it, ideally during the startup step.
*/
if codename == "backblaze" {
bbProv := &BackblazeProvider{provider, provider.Config["bucket"], ""}
err := bbProv.Authorize(provider.Config["appKeyId"], provider.Config["appId"])
if err != nil {
fmt.Println(err.Error())
}
*i = bbProv
return
}
*i = FileProvider{}
} }
/** DO NOT USE THESE DEFAULTS **/
func (f FileProvider) GetDirectory(path string) Directory { func (f FileProvider) GetDirectory(path string) Directory {
return Directory{} return Directory{}
} }
@ -77,3 +56,4 @@ func (f FileProvider) SaveFile(contents []byte, path string) bool {
func (f FileProvider) DetermineType(path string) string { func (f FileProvider) DetermineType(path string) string {
return "" return ""
} }

36
files/fileutils.go Normal file
View file

@ -0,0 +1,36 @@
package files
import "fmt"
var ProviderConfig map[string]FileProvider
var Providers map[string]*FileProviderInterface
func TranslateProvider(codename string, i *FileProviderInterface) {
provider := ProviderConfig[codename]
if codename == "disk" {
*i = &DiskProvider{provider,}
return
}
if codename == "backblaze" {
bbProv := &BackblazeProvider{provider, provider.Config["bucket"], ""}
*i = bbProv
return
}
*i = FileProvider{}
}
func SetupProviders() {
Providers = make(map[string]*FileProviderInterface)
for name, provider := range ProviderConfig {
var i FileProviderInterface
TranslateProvider(name, &i)
success := i.Setup(provider.Config)
if !success {
fmt.Printf("%s failed to initialize\n", name)
} else {
Providers[name] = &i
fmt.Printf("%s initialized successfully\n", name)
}
}
}

View file

@ -14,8 +14,7 @@ func HandleProvider() common.Handler {
vars := mux.Vars(r) vars := mux.Vars(r)
if r.Method == "GET" { if r.Method == "GET" {
providerCodename := vars["provider"] providerCodename := vars["provider"]
var provider files.FileProviderInterface provider := *files.Providers[providerCodename]
files.TranslateProvider(providerCodename, &provider)
fileList := provider.GetDirectory("") fileList := provider.GetDirectory("")
if vars["file"] != "" { if vars["file"] != "" {

View file

@ -1,9 +1,3 @@
/* webserver.go
*
* This is the webserver handler for Pogo, and handles
* all incoming connections, including authentication.
*/
package main package main
import ( import (
@ -34,10 +28,11 @@ func main() {
if err != nil { if err != nil {
panic(err) panic(err)
} }
err = yaml.Unmarshal(file, &files.Providers) err = yaml.Unmarshal(file, &files.ProviderConfig)
if err != nil { if err != nil {
panic(err) panic(err)
} }
files.SetupProviders()
r := router.Init() r := router.Init()
fmt.Println("Your NAS instance is live on port :3000") fmt.Println("Your NAS instance is live on port :3000")