-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
131 lines (116 loc) · 4.34 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package main
import (
"fmt"
"log"
"path/filepath"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
"github.com/tus/tusd/pkg/gcsstore"
tusd "github.com/tus/tusd/pkg/handler"
"github.com/tus/tusd/pkg/memorylocker"
)
func FileUploadHandler() *tusd.UnroutedHandler {
//GCS bucket is for storing uploaded files
bucket := "your-gcs-bucket-name"
/*
It is a json file, that contains the credentials which allows to perform actions
for a specific resource in our GCP project. While creating service account, we should assign
a set of roles and permissions to the service account that allows to do specific actions.
In our case, this service account should have the permission to read, write and modify objects in GCS bucket.
*/
serviceAccountKeyFilePath, err := filepath.Abs("./serviceAccountKey.json")
if err != nil {
log.Fatal("Unable to load serviceAccountKey.json file:: ", err.Error())
}
//initialize GCS service
gcs_service, err := gcsstore.NewGCSService(serviceAccountKeyFilePath)
if err != nil {
log.Fatal("Unable to create GCS service:: ", err.Error())
}
//StoreComposer represents a composable data store. It consists of the core data store and optional extensions.
composer := tusd.NewStoreComposer()
/*
Memorylocker provides an in-memory locking mechanism.
When multiple processes are attempting to access an upload, whether it be by reading or writing,
a synchronization mechanism is required to prevent data corruption, especially to ensure correct offset
values and the proper order of chunks inside a single upload.
MemoryLocker persists locks using memory and therefore allowing a simple and cheap mechanism.
Locks will only exist as long as this object is kept in reference and will be erased if the program exits.
*/
locker := memorylocker.New()
locker.UseIn(composer) //Add memory locker extension to the store composer
/*
GCSStore is a storage backend that uses the GCSAPI interface in order to store uploads on GCS.
Uploads will be represented by two files in GCS; the data file will be stored as an extensionless
object uid and the JSON info file will stored as uid.info.
*/
store := gcsstore.New(bucket, gcs_service)
store.ObjectPrefix = "tus-files" //specify the destination folder in GCS bucket where the files are to be uploaded
store.UseIn(composer) // Add gcs store extension to the composer
//create a handler for handling fileupload operations.
handler, err := tusd.NewUnroutedHandler(tusd.Config{
BasePath: "/tus-files/", //this defines a base path for fileupload endpoint.
StoreComposer: composer,
NotifyCompleteUploads: true,
})
if err != nil {
log.Fatal("Unable to create tus handler:: ", err.Error())
}
//go routine to check for upload complete and notify once it is completed.
go func() {
for {
event := <-handler.CompleteUploads
fmt.Printf("\nSuccessfully uploaded a file with an id: %v", event.Upload.ID)
}
}()
return handler
}
func main() {
router := gin.Default()
router.Use(cors.New(cors.Config{
AllowOrigins: []string{"http://localhost:3000"},
AllowMethods: []string{"PUT", "PATCH", "GET", "POST", "OPTIONS", "DELETE"},
//these headers are tus specific headers that should be allowed and exposed for CORS while uploading file.
AllowHeaders: []string{
"Access-Control-Allow-Origin",
"Access-Control-Allow-Headers",
"X-HTTP-Method-Override",
"Upload-Length",
"Upload-Offset",
"Tus-Resumable",
"Upload-Metadata",
"Upload-Defer-Length",
"Upload-Concat",
"User-Agent",
"Referrer",
"Origin",
"Content-Type",
"Content-Length",
"Content-Range",
"Accept-Encoding",
"Accept",
"Cache-Control",
"X-Agent-User",
"X-Requested-With",
},
ExposeHeaders: []string{
"Upload-Offset",
"Location",
"Tus-Version",
"Tus-Resumable",
"Tus-Max-Size",
"Tus-Extension",
"Upload-Metadata",
"Upload-Defer-Length",
"Upload-Concat",
"Upload-Offset",
"Upload-Length",
},
}))
//these endpoints handle the fileupload requests.
router.POST("tus-files/", gin.WrapF(FileUploadHandler().PostFile))
router.HEAD("tus-files/:id", gin.WrapF(FileUploadHandler().HeadFile))
router.PATCH("tus-files/:id", gin.WrapF(FileUploadHandler().PatchFile))
router.GET("tus-files/:id", gin.WrapF(FileUploadHandler().GetFile))
router.Run(":8080") // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}