1
0
Fork 0
mirror of https://github.com/Luzifer/share.git synced 2024-12-20 18:41:17 +00:00

Add HTTP server mode

Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
Knut Ahlers 2017-12-29 23:35:57 +01:00
parent 8ac15adf54
commit d0b62062a3
Signed by: luzifer
GPG key ID: DC2729FDD34BE99E
3 changed files with 167 additions and 86 deletions

32
http.go Normal file
View file

@ -0,0 +1,32 @@
package main
import (
"net/http"
log "github.com/sirupsen/logrus"
)
func doListen() error {
http.HandleFunc("/post", simpleFilePost)
return http.ListenAndServe(cfg.Listen, nil)
}
func simpleFilePost(res http.ResponseWriter, r *http.Request) {
f, fh, err := r.FormFile("file")
if err != nil {
log.WithError(err).Error("Unable to retrieve file from request")
http.Error(res, "Could not retrieve your file", http.StatusBadRequest)
return
}
url, err := executeUpload(fh.Filename, f, true)
if err != nil {
log.WithError(err).Error("Uploading file from HTTP request failed")
http.Error(res, "Failed to upload file. For details see the log.", http.StatusInternalServerError)
return
}
res.Header().Set("Content-Type", "text/plain")
res.WriteHeader(http.StatusOK)
res.Write([]byte(url))
}

119
main.go
View file

@ -4,20 +4,11 @@ package main
import ( import (
"bytes" "bytes"
"crypto/sha1" "errors"
"fmt" "fmt"
"io"
"io/ioutil"
"mime"
"os" "os"
"path"
"strings"
"text/template"
"github.com/Luzifer/rconfig" "github.com/Luzifer/rconfig"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@ -27,6 +18,7 @@ var (
BasePath string `flag:"base-path" default:"file/{{ printf \"%.2s\" .Hash }}/{{.Hash}}" description:"Path to upload the file to"` BasePath string `flag:"base-path" default:"file/{{ printf \"%.2s\" .Hash }}/{{.Hash}}" description:"Path to upload the file to"`
Bootstrap bool `flag:"bootstrap" default:"false" description:"Upload frontend files into bucket"` Bootstrap bool `flag:"bootstrap" default:"false" description:"Upload frontend files into bucket"`
Bucket string `flag:"bucket" default:"" description:"S3 bucket to upload files to" validate:"nonzero"` Bucket string `flag:"bucket" default:"" description:"S3 bucket to upload files to" validate:"nonzero"`
Listen string `flag:"listen" default:"" description:"Enable HTTP server if set to IP/Port (e.g. ':3000')"`
VersionAndExit bool `flag:"version" default:"false" description:"Prints current version and exits"` VersionAndExit bool `flag:"version" default:"false" description:"Prints current version and exits"`
}{} }{}
@ -45,96 +37,57 @@ func init() {
} }
func main() { func main() {
if cfg.Bootstrap { switch {
for _, asset := range []string{"index.html", "app.js"} {
if _, err := executeUpload(asset, asset, bytes.NewReader(MustAsset("frontend/"+asset))); err != nil { case cfg.Bootstrap:
log.WithError(err).Fatalf("Unable to upload bootstrap asset %q", asset) if err := doBootstrap(); err != nil {
log.WithError(err).Fatal("Bootstrap failed")
} }
} log.Info("Bucket bootstrap finished: Frontend uploaded")
log.Info("Bucket bootstrap finished: Frontend uploaded.")
return case cfg.Listen != "":
if err := doListen(); err != nil {
log.WithError(err).Fatal("HTTP server ended unclean")
} }
default:
if err := doCLIUpload(); err != nil {
log.WithError(err).Fatal("Upload failed")
}
}
}
func doCLIUpload() error {
if len(rconfig.Args()) == 1 { if len(rconfig.Args()) == 1 {
log.Fatalf("Usage: share <file to upload>") return errors.New("Missing argument: File to upload")
} }
if cfg.BaseURL == "" { if cfg.BaseURL == "" {
log.Error("No BaseURL configured, output will be no complete URL") log.Warn("No BaseURL configured, output will be no complete URL")
} }
inFile := rconfig.Args()[1] inFileName := rconfig.Args()[1]
inFileHandle, err := os.Open(inFile) inFileHandle, err := os.Open(inFileName)
if err != nil { if err != nil {
log.WithError(err).Fatal("Unable to open source file") return fmt.Errorf("Unable to open source file: %s", err)
} }
upFile, err := calculateUploadFilename(inFile) defer inFileHandle.Close()
url, err := executeUpload(inFileName, inFileHandle, true)
if err != nil { if err != nil {
log.WithError(err).Fatal("Unable to calculate upload filename") return fmt.Errorf("Unable to upload file: %s", err)
} }
url, err := executeUpload(inFile, upFile, inFileHandle)
if err != nil {
log.WithError(err).Fatal("Failed to upload file")
}
fmt.Println(url) fmt.Println(url)
return nil
} }
func calculateUploadFilename(inFile string) (string, error) { func doBootstrap() error {
upFile := path.Join( for _, asset := range []string{"index.html", "app.js"} {
cfg.BasePath, if _, err := executeUpload(asset, bytes.NewReader(MustAsset("frontend/"+asset)), false); err != nil {
strings.Replace(path.Base(inFile), " ", "_", -1), return fmt.Errorf("Unable to upload bootstrap asset %q: %s", asset, err)
)
fileHash, err := hashFile(inFile)
if err != nil {
return "", err
} }
return executeTemplate(upFile, map[string]interface{}{
"Hash": fileHash,
})
} }
return nil
func executeUpload(inFile, upFile string, inFileHandle io.ReadSeeker) (string, error) {
mimeType := mime.TypeByExtension(path.Ext(inFile))
if mimeType == "" {
mimeType = "application/octet-stream"
}
log.Debugf("Uploading %q to %q with type %q", inFile, upFile, mimeType)
sess := session.Must(session.NewSession())
svc := s3.New(sess)
if _, err := svc.PutObject(&s3.PutObjectInput{
Body: inFileHandle,
Bucket: aws.String(cfg.Bucket),
ContentType: aws.String(mimeType),
Key: aws.String(upFile),
}); err != nil {
return "", err
}
return fmt.Sprintf("%s%s", cfg.BaseURL, upFile), nil
}
func hashFile(inFile string) (string, error) {
data, err := ioutil.ReadFile(inFile)
if err != nil {
return "", err
}
sum1 := sha1.Sum(data)
return fmt.Sprintf("%x", sum1), nil
}
func executeTemplate(tplStr string, vars map[string]interface{}) (string, error) {
tpl, err := template.New("basepath").Parse(tplStr)
if err != nil {
return "", err
}
buf := new(bytes.Buffer)
err = tpl.Execute(buf, vars)
return buf.String(), err
} }

96
upload.go Normal file
View file

@ -0,0 +1,96 @@
package main
import (
"bytes"
"crypto/sha1"
"fmt"
"html/template"
"io"
"io/ioutil"
"mime"
"path"
"strings"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
log "github.com/sirupsen/logrus"
)
func executeUpload(inFileName string, inFileHandle io.ReadSeeker, useCalculatedFilename bool) (string, error) {
var (
upFile = inFileName
err error
)
if useCalculatedFilename {
if upFile, err = calculateUploadFilename(inFileName, inFileHandle); err != nil {
return "", fmt.Errorf("Unable to calculate upload filename: %s", err)
}
}
mimeType := mime.TypeByExtension(path.Ext(upFile))
if mimeType == "" {
mimeType = "application/octet-stream"
}
log.Debugf("Uploading file to %q with type %q", upFile, mimeType)
sess := session.Must(session.NewSession())
svc := s3.New(sess)
if _, err := inFileHandle.Seek(0, io.SeekStart); err != nil {
return "", err
}
if _, err := svc.PutObject(&s3.PutObjectInput{
Body: inFileHandle,
Bucket: aws.String(cfg.Bucket),
ContentType: aws.String(mimeType),
Key: aws.String(upFile),
}); err != nil {
return "", err
}
return fmt.Sprintf("%s%s", cfg.BaseURL, upFile), nil
}
func calculateUploadFilename(inFile string, inFileHandle io.ReadSeeker) (string, error) {
upFile := path.Join(
cfg.BasePath,
strings.Replace(path.Base(inFile), " ", "_", -1),
)
fileHash, err := hashFile(inFileHandle)
if err != nil {
return "", err
}
return executeTemplate(upFile, map[string]interface{}{
"Hash": fileHash,
})
}
func hashFile(inFileHandle io.ReadSeeker) (string, error) {
if _, err := inFileHandle.Seek(0, io.SeekStart); err != nil {
return "", err
}
data, err := ioutil.ReadAll(inFileHandle)
if err != nil {
return "", err
}
sum1 := sha1.Sum(data)
return fmt.Sprintf("%x", sum1), nil
}
func executeTemplate(tplStr string, vars map[string]interface{}) (string, error) {
tpl, err := template.New("basepath").Parse(tplStr)
if err != nil {
return "", err
}
buf := new(bytes.Buffer)
err = tpl.Execute(buf, vars)
return buf.String(), err
}