From dbd4d54b4d47a407bcd961c825dc189fe2dc0c6b Mon Sep 17 00:00:00 2001 From: Marius Date: Mon, 22 Feb 2016 12:53:15 +0100 Subject: [PATCH 1/5] Add postfinish hook --- .hooks/postfinish | 4 ++++ cmd/tusd/main.go | 49 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100755 .hooks/postfinish diff --git a/.hooks/postfinish b/.hooks/postfinish new file mode 100755 index 0000000..843e10d --- /dev/null +++ b/.hooks/postfinish @@ -0,0 +1,4 @@ +#!/bin/bash + +echo "Upload finished" +printenv diff --git a/cmd/tusd/main.go b/cmd/tusd/main.go index d5a1d6d..e71b5a1 100644 --- a/cmd/tusd/main.go +++ b/cmd/tusd/main.go @@ -7,6 +7,10 @@ import ( "net" "net/http" "os" + "os/exec" + "path/filepath" + "strconv" + "strings" "time" "github.com/tus/tusd" @@ -32,11 +36,14 @@ var storeSize int64 var basepath string var timeout int64 var s3Bucket string +var hooksDir string var version bool var stdout = log.New(os.Stdout, "[tusd] ", 0) var stderr = log.New(os.Stderr, "[tusd] ", 0) +var hookInstalled bool + func init() { flag.StringVar(&httpHost, "host", "0.0.0.0", "Host to bind HTTP server to") flag.StringVar(&httpPort, "port", "1080", "Port to bind HTTP server to") @@ -46,9 +53,17 @@ func init() { flag.StringVar(&basepath, "base-path", "/files/", "Basepath of the HTTP server") flag.Int64Var(&timeout, "timeout", 30*1000, "Read timeout for connections in milliseconds") flag.StringVar(&s3Bucket, "s3-bucket", "", "Use AWS S3 with this bucket as storage backend (requires the AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and AWS_REGION environment variables to be set)") + flag.StringVar(&hooksDir, "hooks-dir", "", "") flag.BoolVar(&version, "version", false, "Print tusd version information") flag.Parse() + + if hooksDir != "" { + hooksDir, _ = filepath.Abs(hooksDir) + hookInstalled = true + + stdout.Printf("Using '%s' for hooks", hooksDir) + } } func main() { @@ -104,7 +119,7 @@ func main() { for { select { case info := <-handler.CompleteUploads: - stdout.Printf("Upload %s (%d bytes) finished\n", info.ID, info.Size) + invokeHook(info) } } }() @@ -122,6 +137,38 @@ func main() { } } +func invokeHook(info tusd.FileInfo) { + stdout.Printf("Upload %s (%d bytes) finished\n", info.ID, info.Size) + + if !hookInstalled { + return + } + + stdout.Println("Invoking hooks…") + + cmd := exec.Command(hooksDir + "/postfinish") + env := os.Environ() + env = append(env, "TUS_ID="+info.ID) + env = append(env, "TUS_SIZE="+strconv.FormatInt(info.Size, 10)) + + for k, v := range info.MetaData { + k = strings.ToUpper(k) + env = append(env, "TUS_METADATA_"+k+"="+v) + } + + cmd.Env = env + cmd.Dir = hooksDir + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + go func() { + err := cmd.Run() + if err != nil { + stderr.Printf("Error running postfinish hook for %s: %s", info.ID, err) + } + }() +} + // Listener wraps a net.Listener, and gives a place to store the timeout // parameters. On Accept, it will wrap the net.Conn with our own Conn for us. // Original implementation taken from https://gist.github.com/jbardin/9663312 From a949cb6b8155189079ee75f5953ef0eba72b5cae Mon Sep 17 00:00:00 2001 From: Marius Date: Mon, 22 Feb 2016 13:58:05 +0100 Subject: [PATCH 2/5] Set proper offset for complete notifications --- unrouted_handler.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unrouted_handler.go b/unrouted_handler.go index a44a1fe..38fb6b1 100644 --- a/unrouted_handler.go +++ b/unrouted_handler.go @@ -415,7 +415,7 @@ func (handler *UnroutedHandler) PatchFile(w http.ResponseWriter, r *http.Request // ... send the info out to the channel if handler.config.NotifyCompleteUploads { - info.Size = newOffset + info.Offset = newOffset handler.CompleteUploads <- info } } From 0070379a916549fc6d1a4b44b21da3c4fd37bc61 Mon Sep 17 00:00:00 2001 From: Marius Date: Mon, 22 Feb 2016 13:59:28 +0100 Subject: [PATCH 3/5] Pass info object as JSON blob to hook --- .hooks/postfinish | 4 ++-- cmd/tusd/main.go | 12 ++++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.hooks/postfinish b/.hooks/postfinish index 843e10d..03c059a 100755 --- a/.hooks/postfinish +++ b/.hooks/postfinish @@ -1,4 +1,4 @@ #!/bin/bash -echo "Upload finished" -printenv +echo "Upload $TUS_ID ($TUS_SIZE bytes) finished" +cat /dev/stdin | jq . diff --git a/cmd/tusd/main.go b/cmd/tusd/main.go index e71b5a1..a4fd4aa 100644 --- a/cmd/tusd/main.go +++ b/cmd/tusd/main.go @@ -1,6 +1,8 @@ package main import ( + "bytes" + "encoding/json" "flag" "fmt" "log" @@ -10,7 +12,6 @@ import ( "os/exec" "path/filepath" "strconv" - "strings" "time" "github.com/tus/tusd" @@ -151,11 +152,14 @@ func invokeHook(info tusd.FileInfo) { env = append(env, "TUS_ID="+info.ID) env = append(env, "TUS_SIZE="+strconv.FormatInt(info.Size, 10)) - for k, v := range info.MetaData { - k = strings.ToUpper(k) - env = append(env, "TUS_METADATA_"+k+"="+v) + jsonInfo, err := json.Marshal(info) + if err != nil { + stderr.Printf("Error encoding JSON for hook: %s", err) } + reader := bytes.NewReader(jsonInfo) + cmd.Stdin = reader + cmd.Env = env cmd.Dir = hooksDir cmd.Stdout = os.Stdout From d5d0452c36d74139490f17246dd33791216679a9 Mon Sep 17 00:00:00 2001 From: Marius Date: Mon, 22 Feb 2016 14:04:14 +0100 Subject: [PATCH 4/5] Rename postfinish hook to post-finish --- .hooks/{postfinish => post-finish} | 0 cmd/tusd/main.go | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename .hooks/{postfinish => post-finish} (100%) diff --git a/.hooks/postfinish b/.hooks/post-finish similarity index 100% rename from .hooks/postfinish rename to .hooks/post-finish diff --git a/cmd/tusd/main.go b/cmd/tusd/main.go index a4fd4aa..21d75f2 100644 --- a/cmd/tusd/main.go +++ b/cmd/tusd/main.go @@ -147,7 +147,7 @@ func invokeHook(info tusd.FileInfo) { stdout.Println("Invoking hooks…") - cmd := exec.Command(hooksDir + "/postfinish") + cmd := exec.Command(hooksDir + "/post-finish") env := os.Environ() env = append(env, "TUS_ID="+info.ID) env = append(env, "TUS_SIZE="+strconv.FormatInt(info.Size, 10)) From c542a657ff245f64fa3aab4604e33f9579cfe833 Mon Sep 17 00:00:00 2001 From: Marius Date: Mon, 22 Feb 2016 14:08:24 +0100 Subject: [PATCH 5/5] Exclude .hooks direcory from tests --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4236ace..13f0727 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,7 @@ matrix: - go: tip install: -- export PACKAGES=$(find ./ -maxdepth 1 -type d -not \( -name ".git" -or -name "cmd" -or -name "vendor" -or -name "data" \)) +- export PACKAGES=$(find ./ -maxdepth 1 -type d -not \( -name ".git" -or -name "cmd" -or -name "vendor" -or -name "data" -or -name ".hooks" \)) - rsync -r ./vendor/ $GOPATH/src script: