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:
parent
8ac15adf54
commit
d0b62062a3
3 changed files with 167 additions and 86 deletions
32
http.go
Normal file
32
http.go
Normal 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))
|
||||||
|
}
|
125
main.go
125
main.go
|
@ -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 {
|
|
||||||
log.WithError(err).Fatalf("Unable to upload bootstrap asset %q", asset)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.Info("Bucket bootstrap finished: Frontend uploaded.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
|
case cfg.Bootstrap:
|
||||||
|
if err := doBootstrap(); err != nil {
|
||||||
|
log.WithError(err).Fatal("Bootstrap failed")
|
||||||
|
}
|
||||||
|
log.Info("Bucket bootstrap finished: Frontend uploaded")
|
||||||
|
|
||||||
|
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 nil
|
||||||
return executeTemplate(upFile, map[string]interface{}{
|
|
||||||
"Hash": fileHash,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
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
96
upload.go
Normal 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
|
||||||
|
}
|
Loading…
Reference in a new issue