-
-
Save toannd96/b74098fa7e76e298dad7dedccc85f2c9 to your computer and use it in GitHub Desktop.
Golang Multipart upload to S3 over HTTP using tusd
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bytes" | |
"errors" | |
"fmt" | |
"io" | |
"log" | |
"mime/multipart" | |
"net/http" | |
"os" | |
"path/filepath" | |
"regexp" | |
"strconv" | |
) | |
/* | |
Demonstration of using the tusd as a client to send file uploads | |
with just multiparts being written to the server (acting as a proxy between client and s3) | |
*/ | |
func main() { | |
SendPostRequest("http://localhost:8080/files/upload/", "test.txt", "txt") | |
} | |
func SendPostRequest(url string, filename string, filetype string) (string, error) { | |
file, err := os.Open(filename) | |
if err != nil { | |
log.Fatal(err) | |
} | |
defer file.Close() | |
body := &bytes.Buffer{} | |
writer := multipart.NewWriter(body) | |
part, err := writer.CreateFormFile(filetype, filepath.Base(file.Name())) | |
if err != nil { | |
log.Fatal(err) | |
} | |
io.Copy(part, file) | |
writer.Close() | |
request, err := http.NewRequest("POST", url, body) | |
if err != nil { | |
log.Fatal(err) | |
} | |
fileStats, err := file.Stat() | |
if err != nil { | |
// Could not obtain stat, handle error | |
} | |
fileSize := strconv.FormatInt(fileStats.Size(), 10) | |
request.Header.Add("Tus-Resumable", "1.0.0") | |
request.Header.Add("Upload-Offset", "0") | |
request.Header.Add("Content-Length", fileSize) | |
request.Header.Add("Upload-Length", fileSize) | |
request.Header.Add("Content-Type", writer.FormDataContentType()) | |
client := &http.Client{} | |
response, err := client.Do(request) | |
if err != nil { | |
log.Fatal(err) | |
} | |
defer response.Body.Close() | |
if response.StatusCode != 201 { | |
fmt.Println("There was an error with the request ", response.StatusCode) | |
} else { | |
r := regexp.MustCompile(`files\/upload\/(.*?)\+`) | |
subStrings := r.FindStringSubmatch(response.Header["Location"][0]) | |
// [0] is the full string | |
storedFileName := subStrings[1] | |
fmt.Println("stored File Name "+storedFileName, " status code: ", response.StatusCode) | |
return storedFileName, nil | |
} | |
return "", errors.New("The file upload failed") | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"log" | |
"net/http" | |
"os" | |
"regexp" | |
"github.com/aws/aws-sdk-go/aws" | |
"github.com/aws/aws-sdk-go/aws/credentials" | |
"github.com/aws/aws-sdk-go/aws/session" | |
"github.com/aws/aws-sdk-go/service/s3" | |
"github.com/tus/tusd" | |
"github.com/tus/tusd/filestore" | |
"github.com/tus/tusd/s3store" | |
) | |
/* | |
Demonstration of using the tusd as a server to accept file uploads direct to s3 | |
with just multiparts being written to the server (acting as a proxy between client and s3) | |
*/ | |
func main() { | |
fStore := filestore.FileStore{ | |
Path: "./uploads", | |
} | |
S3_ACCESS_KEY := os.Getenv("S3_ACCESS_KEY") | |
S3_SECRET_KEY := os.Getenv("S3_SECRET_KEY") | |
s3Config := &aws.Config{ | |
Region: aws.String("eu-west-2"), | |
Credentials: credentials.NewStaticCredentials(S3_ACCESS_KEY, S3_SECRET_KEY, ""), | |
} | |
s3Locker := s3store.New("app.bucket", s3.New(session.Must(session.NewSession()), s3Config)) | |
composer := tusd.NewStoreComposer() | |
fStore.UseIn(composer) | |
s3Locker = s3Locker | |
handler, err := tusd.NewHandler(tusd.Config{ | |
BasePath: "/files/upload/", | |
StoreComposer: composer, | |
NotifyCompleteUploads: true, | |
NotifyTerminatedUploads: true, | |
NotifyUploadProgress: true, | |
NotifyCreatedUploads: true, | |
}) | |
if err != nil { | |
panic(fmt.Errorf("Unable to create handler: %s", err)) | |
} | |
http.Handle("/files/upload/", http.StripPrefix("/files/upload/", handler)) | |
err = http.ListenAndServe(":8080", nil) | |
if err != nil { | |
panic(fmt.Errorf("Unable to listen: %s", err)) | |
} | |
} | |
func setupPostHooks(handler *tusd.Handler) { | |
go func() { | |
select { | |
case info := <-handler.CompleteUploads: | |
log.Println("upload complete:", info) | |
case info := <-handler.TerminatedUploads: | |
log.Println("upload terminated:", info) | |
case info := <-handler.UploadProgress: | |
log.Println("upload progress:", info) | |
case info := <-handler.CreatedUploads: | |
log.Println("create upload:", info) | |
processStoredFile(info) | |
} | |
}() | |
} | |
func processStoredFile(info tusd.FileInfo) { | |
fmt.Printf("info %+v\r\n", info) | |
r := regexp.MustCompile(`^(.*?)\+`) | |
subStrings := r.FindStringSubmatch(info.ID) | |
storedFileName := subStrings[1] | |
fmt.Println("stored File Name " + storedFileName) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment