Squashed commit of the following:

commit d6ba86b7c300122af52e5be71b5fade4bb88d77c
Author: Marius <maerious@gmail.com>
Date:   Wed Jul 19 17:44:56 2017 +0200

    Add documentation for post-create

commit 1d1605f98036e6cfd7e2695cf2e4f8510a220326
Author: Marius <maerious@gmail.com>
Date:   Wed Jul 19 13:21:01 2017 +0200

    Remove duplicated log for created uploads

commit 1f5c6d22bb62e1251297db9b10f78f6db363759d
Author: Marius <maerious@gmail.com>
Date:   Wed Jul 19 13:08:11 2017 +0200

    Rename UploadsCreated to CreatedUploads to match other names

commit 5c67ea7548548986c4bce79b7eea311a02a4c541
Author: Marius <maerious@gmail.com>
Date:   Wed Jul 19 13:07:14 2017 +0200

    Remove unused variable from hook script

commit e21d7f5824ce533d80d74e75835ddc33de2184fb
Merge: 028ba57 447aa9c
Author: Marius <maerious@gmail.com>
Date:   Wed Jul 19 12:47:52 2017 +0200

    Merge branch 'f-post-create-hook' of https://github.com/flaneurtv/tusd into flaneurtv-f-post-create-hook

commit 447aa9c485
Author: Markus Kienast <mark@rickkiste.at>
Date:   Thu Jul 13 15:57:07 2017 +0200

    added post-create hook

    added test for handler.UploadCreated

    go fmt .
This commit is contained in:
Marius 2017-07-19 17:45:16 +02:00
parent 028ba57206
commit a51f5994bb
7 changed files with 44 additions and 2 deletions

8
.hooks/post-create Executable file
View File

@ -0,0 +1,8 @@
#!/bin/bash
id="$TUS_ID"
offset="$TUS_OFFSET"
size="$TUS_SIZE"
echo "Upload created with ID ${id} and size ${size}"
cat /dev/stdin | jq .

View File

@ -22,6 +22,7 @@ const (
HookPostFinish HookType = "post-finish" HookPostFinish HookType = "post-finish"
HookPostTerminate HookType = "post-terminate" HookPostTerminate HookType = "post-terminate"
HookPostReceive HookType = "post-receive" HookPostReceive HookType = "post-receive"
HookPostCreate HookType = "post-create"
HookPreCreate HookType = "pre-create" HookPreCreate HookType = "pre-create"
) )
@ -52,6 +53,8 @@ func SetupPostHooks(handler *tusd.Handler) {
invokeHook(HookPostTerminate, info) invokeHook(HookPostTerminate, info)
case info := <-handler.UploadProgress: case info := <-handler.UploadProgress:
invokeHook(HookPostReceive, info) invokeHook(HookPostReceive, info)
case info := <-handler.CreatedUploads:
invokeHook(HookPostCreate, info)
} }
} }
}() }()

View File

@ -18,6 +18,7 @@ func Serve() {
NotifyCompleteUploads: true, NotifyCompleteUploads: true,
NotifyTerminatedUploads: true, NotifyTerminatedUploads: true,
NotifyUploadProgress: true, NotifyUploadProgress: true,
NotifyCreatedUploads: true,
}) })
if err != nil { if err != nil {
stderr.Fatalf("Unable to create handler: %s", err) stderr.Fatalf("Unable to create handler: %s", err)

View File

@ -34,6 +34,9 @@ type Config struct {
// NotifyUploadProgress indicates whether sending notifications about // NotifyUploadProgress indicates whether sending notifications about
// the upload progress using the UploadProgress channel should be enabled. // the upload progress using the UploadProgress channel should be enabled.
NotifyUploadProgress bool NotifyUploadProgress bool
// NotifyCreatedUploads indicates whether sending notifications about
// the upload having been created using the CreatedUploads channel should be enabled.
NotifyCreatedUploads bool
// Logger is the logger to use internally, mostly for printing requests. // Logger is the logger to use internally, mostly for printing requests.
Logger *log.Logger Logger *log.Logger
// Respect the X-Forwarded-Host, X-Forwarded-Proto and Forwarded headers // Respect the X-Forwarded-Host, X-Forwarded-Proto and Forwarded headers

View File

@ -19,6 +19,10 @@ On the other hand, there are a few *blocking* hooks, such as caused by the `pre-
This event will be triggered before an upload is created, allowing you to run certain routines. For example, validating that specific metadata values are set, or verifying that a corresponding entity belonging to the upload (e.g. a user) exists. Because this event will result in a blocking hook, you can determine whether the upload should be created or rejected using the exit code. An exit code of `0` will allow the upload to be created and continued as usual. A non-zero exit code will reject an upload creation request, making it a good place for authentication and authorization. Please be aware, that during this stage the upload ID will be an empty string as the entity has not been created and therefore this piece of information is not yet available. This event will be triggered before an upload is created, allowing you to run certain routines. For example, validating that specific metadata values are set, or verifying that a corresponding entity belonging to the upload (e.g. a user) exists. Because this event will result in a blocking hook, you can determine whether the upload should be created or rejected using the exit code. An exit code of `0` will allow the upload to be created and continued as usual. A non-zero exit code will reject an upload creation request, making it a good place for authentication and authorization. Please be aware, that during this stage the upload ID will be an empty string as the entity has not been created and therefore this piece of information is not yet available.
### post-create
This event will be triggered after an upload is created, allowing you to run certain routines. For example, notifying other parts of your system that a new upload has to be handled. At this point the upload may have received some data already since the invocation of these hooks may be delayed by a short duration.
### post-finish ### post-finish
This event will be triggered after an upload is fully finished, meaning that all chunks have been transfered and saved in the storage. After this point, no further modifications, except possible deletion, can be made to the upload entity and it may be desirable to use the file for further processing or notify other applications of the completions of this upload. This event will be triggered after an upload is fully finished, meaning that all chunks have been transfered and saved in the storage. After this point, no further modifications, except possible deletion, can be made to the upload entity and it may be desirable to use the file for further processing or notify other applications of the completions of this upload.

View File

@ -7,6 +7,7 @@ import (
"testing" "testing"
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
. "github.com/tus/tusd" . "github.com/tus/tusd"
) )
@ -24,8 +25,12 @@ func TestPost(t *testing.T) {
handler, _ := NewHandler(Config{ handler, _ := NewHandler(Config{
DataStore: store, DataStore: store,
BasePath: "https://buy.art/files/", BasePath: "https://buy.art/files/",
NotifyCreatedUploads: true,
}) })
c := make(chan FileInfo, 1)
handler.CreatedUploads = c
(&httpTest{ (&httpTest{
Method: "POST", Method: "POST",
ReqHeader: map[string]string{ ReqHeader: map[string]string{
@ -39,6 +44,12 @@ func TestPost(t *testing.T) {
"Location": "https://buy.art/files/foo", "Location": "https://buy.art/files/foo",
}, },
}).Run(handler, t) }).Run(handler, t)
info := <-c
a := assert.New(t)
a.Equal("foo", info.ID)
a.Equal(int64(300), info.Size)
}) })
SubTest(t, "CreateExceedingMaxSizeFail", func(t *testing.T, store *MockFullDataStore) { SubTest(t, "CreateExceedingMaxSizeFail", func(t *testing.T, store *MockFullDataStore) {

View File

@ -94,6 +94,12 @@ type UnroutedHandler struct {
// happen if the NotifyUploadProgress field is set to true in the Config // happen if the NotifyUploadProgress field is set to true in the Config
// structure. // structure.
UploadProgress chan FileInfo UploadProgress chan FileInfo
// CreatedUploads is used to send notifications about the uploads having been
// created. It triggers post creation and therefore has all the FileInfo incl.
// the ID available already. It facilitates the post-create hook. Sending to
// this channel will only happen if the NotifyCreatedUploads field is set to
// true in the Config structure.
CreatedUploads chan FileInfo
// Metrics provides numbers of the usage for this handler. // Metrics provides numbers of the usage for this handler.
Metrics Metrics Metrics Metrics
} }
@ -124,6 +130,7 @@ func NewUnroutedHandler(config Config) (*UnroutedHandler, error) {
CompleteUploads: make(chan FileInfo), CompleteUploads: make(chan FileInfo),
TerminatedUploads: make(chan FileInfo), TerminatedUploads: make(chan FileInfo),
UploadProgress: make(chan FileInfo), UploadProgress: make(chan FileInfo),
CreatedUploads: make(chan FileInfo),
logger: config.Logger, logger: config.Logger,
extensions: extensions, extensions: extensions,
Metrics: newMetrics(), Metrics: newMetrics(),
@ -284,6 +291,11 @@ func (handler *UnroutedHandler) PostFile(w http.ResponseWriter, r *http.Request)
go handler.Metrics.incUploadsCreated() go handler.Metrics.incUploadsCreated()
handler.log("UploadCreated", "id", id, "size", i64toa(size), "url", url) handler.log("UploadCreated", "id", id, "size", i64toa(size), "url", url)
if handler.config.NotifyCreatedUploads {
info.ID = id
handler.CreatedUploads <- info
}
if isFinal { if isFinal {
if err := handler.composer.Concater.ConcatUploads(id, partialUploads); err != nil { if err := handler.composer.Concater.ConcatUploads(id, partialUploads); err != nil {
handler.sendError(w, r, err) handler.sendError(w, r, err)