@@ -2,6 +2,7 @@ package internal
22
33import (
44 "fmt"
5+ "github.com/bmizerany/pat"
56 "github.com/docopt/docopt-go"
67 "github.com/jackhftang/tusc/internal/util"
78 "github.com/tus/tusd"
@@ -24,10 +25,12 @@ Usage:
2425 tusc (server|s) --help
2526
2627Options:
27- -h --host HOST Host to bind HTTP server to [default: 0.0.0.0]
28+ -u --url URL Url of HTTP server [default: http://localhost:1080]
29+ -b --bind ADDR Address to bind HTTP server to [default: 0.0.0.0]
2830 -p --port PORT Port to bind HTTP server to [default: 1080]
2931 -d --dir PATH Directory to store uploads in [default: ./data]
30- --base-path PATH Basepath of the HTTP server [default: /files/]
32+ --listing-endpoint PATH Http path for flies listing [default: /]
33+ --files-endpoint PATH Http path for files [default: /files/]
3134 --unix-sock PATH If set will listen to a UNIX socket at this location instead of a TCP socket
3235 --max-size SIZE Maximum size of a single upload in bytes [default: 0]
3336 --store-size BYTE Size of space allowed for storage [default: 0]
@@ -36,16 +39,17 @@ Options:
3639`
3740
3841type ServerConf struct {
39- httpHost string
40- httpPort string
41- httpSock string
42- maxSize int64
43- uploadDir string
44- storeSize int64
45- listingEndpoint string
46- uploadEndpoint string
47- timeout int64
48- isBehindProxy bool
42+ Url string `docopt:"--url"`
43+ BindAddr string `docopt:"--bind"`
44+ Port string `docopt:"--port"`
45+ HttpSock string `docopt:"--unix-sock"`
46+ MaxSize int64 `docopt:"--max-size"`
47+ UploadDir string `docopt:"--dir"`
48+ StoreSize int64 `docopt:"--store-size"`
49+ ListingEndpoint string `docopt:"--listing-endpoint"`
50+ FilesEndpoint string `docopt:"--files-endpoint"`
51+ Timeout int64 `docopt:"--timeout"`
52+ IsBehindProxy bool `docopt:"--behind-proxy"`
4953}
5054
5155var stdout = log .New (os .Stdout , "[tusd] " , log .Ldate | log .Ltime )
@@ -58,61 +62,62 @@ func logEv(logOutput *log.Logger, eventName string, details ...string) {
5862func Server () {
5963 var conf ServerConf
6064 arguments , _ := docopt .ParseDoc (serverUsage )
61- conf .httpHost , _ = arguments .String ("--host" )
62- conf .httpPort , _ = arguments .String ("--port" )
63- conf .httpSock , _ = arguments .String ("--unix-sock" )
64- conf .maxSize = util .GetInt64 (arguments , "--max-size" )
65- conf .uploadDir , _ = arguments .String ("--dir" )
66- conf .storeSize = util .GetInt64 (arguments , "--store-size" )
67- conf .listingEndpoint = "/"
68- conf .uploadEndpoint , _ = arguments .String ("--base-path" )
69- conf .timeout = util .GetInt64 (arguments , "--timeout" )
70- conf .isBehindProxy , _ = arguments .Bool ("--behind-proxy" )
65+ //arguments.Bind(&conf) // todo: bug
66+ conf .Url , _ = arguments .String ("--url" )
67+ conf .BindAddr , _ = arguments .String ("--bind" )
68+ conf .Port , _ = arguments .String ("--port" )
69+ conf .HttpSock , _ = arguments .String ("--unix-sock" )
70+ conf .MaxSize = util .GetInt64 (arguments , "--max-size" )
71+ conf .UploadDir , _ = arguments .String ("--dir" )
72+ conf .StoreSize = util .GetInt64 (arguments , "--store-size" )
73+ conf .ListingEndpoint , _ = arguments .String ("--listing-endpoint" )
74+ conf .FilesEndpoint , _ = arguments .String ("--files-endpoint" )
75+ conf .Timeout = util .GetInt64 (arguments , "--timeout" )
76+ conf .IsBehindProxy , _ = arguments .Bool ("--behind-proxy" )
77+ fmt .Println (conf )
7178
7279 storeCompoesr := tusd .NewStoreComposer ()
7380
74- stdout .Printf ("Using '%s' as directory storage.\n " , conf .uploadDir )
75- if err := os .MkdirAll (conf .uploadDir , os .FileMode (0774 )); err != nil {
81+ stdout .Printf ("Using '%s' as directory storage.\n " , conf .UploadDir )
82+ if err := os .MkdirAll (conf .UploadDir , os .FileMode (0774 )); err != nil {
7683 stderr .Fatalf ("Unable to ensure directory exists: %s" , err )
7784 }
78- store := filestore .New (conf .uploadDir )
85+ store := filestore .New (conf .UploadDir )
7986 store .UseIn (storeCompoesr )
8087
81- if conf .storeSize > 0 {
82- limitedstore .New (conf .storeSize , storeCompoesr .Core , storeCompoesr .Terminater ).UseIn (storeCompoesr )
83- stdout .Printf ("Using %.2fMB as storage size.\n " , float64 (conf .storeSize )/ 1024 / 1024 )
88+ if conf .StoreSize > 0 {
89+ limitedstore .New (conf .StoreSize , storeCompoesr .Core , storeCompoesr .Terminater ).UseIn (storeCompoesr )
90+ stdout .Printf ("Using %.2fMB as storage size.\n " , float64 (conf .StoreSize )/ 1024 / 1024 )
8491
8592 // We need to ensure that a single upload can fit into the storage size
86- if conf .maxSize > conf .storeSize || conf .maxSize == 0 {
87- conf .maxSize = conf .storeSize
93+ if conf .MaxSize > conf .StoreSize || conf .MaxSize == 0 {
94+ conf .MaxSize = conf .StoreSize
8895 }
8996 }
9097
91- stdout .Printf ("Using %.2fMB as maximum size.\n " , float64 (conf .maxSize )/ 1024 / 1024 )
92-
93- // Serve
98+ stdout .Printf ("Using %.2fMB as maximum size.\n " , float64 (conf .MaxSize )/ 1024 / 1024 )
9499
95100 // Address
96101 address := ""
97- if conf .httpSock != "" {
98- address = conf .httpSock
102+ if conf .HttpSock != "" {
103+ address = conf .HttpSock
99104 stdout .Printf ("Using %s as socket to listen.\n " , address )
100105 } else {
101- address = conf .httpHost + ":" + conf .httpPort
106+ address = conf .BindAddr + ":" + conf .Port
102107 stdout .Printf ("Using %s as address to listen.\n " , address )
103108 }
104109
105110 // Base path
106- stdout .Printf ("Using %s as the base path.\n " , conf .uploadEndpoint )
111+ stdout .Printf ("Using %s as the base path.\n " , conf .FilesEndpoint )
107112
108113 // show capabilities
109114 stdout .Printf (storeCompoesr .Capabilities ())
110115
111116 // tus handler
112117 handler , err := tusd .NewHandler (tusd.Config {
113- MaxSize : conf .maxSize ,
114- BasePath : conf .uploadEndpoint ,
115- RespectForwardedHeaders : conf .isBehindProxy ,
118+ MaxSize : conf .MaxSize ,
119+ BasePath : conf .FilesEndpoint ,
120+ RespectForwardedHeaders : conf .IsBehindProxy ,
116121 StoreComposer : storeCompoesr ,
117122 NotifyCompleteUploads : false ,
118123 NotifyTerminatedUploads : false ,
@@ -123,31 +128,34 @@ func Server() {
123128 stderr .Fatalf ("Unable to create handler: %s" , err )
124129 }
125130
126- http .Handle (conf .uploadEndpoint , http .StripPrefix (conf .uploadEndpoint , handler ))
127- if conf .listingEndpoint != conf .uploadEndpoint {
128- http .Handle (conf .listingEndpoint , http .StripPrefix (conf .listingEndpoint , homepage (store )))
131+ if conf .ListingEndpoint != conf .FilesEndpoint {
132+ mux := pat .New ()
133+ mux .Get ("/" , listingHandler (conf , store ))
134+ http .Handle (conf .ListingEndpoint , mux )
129135 }
136+ http .Handle (conf .FilesEndpoint , http .StripPrefix (conf .FilesEndpoint , handler ))
137+
130138
131139 var listener net.Listener
132- timeoutDuration := time .Duration (conf .timeout ) * time .Millisecond
140+ timeoutDuration := time .Duration (conf .Timeout ) * time .Millisecond
133141
134- if conf .httpSock != "" {
142+ if conf .HttpSock != "" {
135143 if listener , err = util .NewUnixListener (address , timeoutDuration , timeoutDuration ); err != nil {
136144 stderr .Fatalf ("Unable to create listener: %s" , err )
137145 }
138- stdout .Printf ("You can now upload files to: http://%s%s" , address , conf .uploadEndpoint )
139146 } else {
140147 if listener , err = util .NewListener (address , timeoutDuration , timeoutDuration ); err != nil {
141148 stderr .Fatalf ("Unable to create listener: %s" , err )
142149 }
150+ stdout .Printf ("You can now upload files to: http://%s%s" , address , conf .FilesEndpoint )
143151 }
144152
145153 if err = http .Serve (listener , nil ); err != nil {
146154 stderr .Fatalf ("Unable to serve: %s" , err )
147155 }
148156}
149157
150- func homepage ( store filestore.FileStore ) http.HandlerFunc {
158+ func listingHandler ( conf ServerConf , store filestore.FileStore ) http.HandlerFunc {
151159 t , err := template .New ("foo" ).Parse (`{{define "listing"}}<html><head><title>File Listing</title><style>
152160* {
153161 font-family: monospace;
178186 padding: 0;
179187}
180188</style></head><body><ul>
181- {{ range . }}<li><a href="http://127.0.0.1:1080/files/ {{ .ID }}">{{ index .MetaData "filename" }}</a></li>{{ end }}
189+ {{ range .Infos }}<li><a href="{{ $.Conf.Url }}{{ $.Conf.FilesEndpoint }} {{ .ID }}">{{ index .MetaData "filename" }}</a></li>{{ end }}
182190 </ul>
183191 </body>
184192</html>{{end}}` )
189197 return http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
190198 var err error
191199 var fileInfos []os.FileInfo
200+
201+ // todo: here read once, calling GetInfo read another once
192202 if fileInfos , err = ioutil .ReadDir (store .Path ); err != nil {
193203 http .Error (w , "" , 500 )
194204 return
@@ -217,7 +227,11 @@ li {
217227 sort .Slice (infos , func (i , j int ) bool {
218228 return infos [i ].MetaData ["filename" ] < infos [j ].MetaData ["filename" ]
219229 })
220- if err = t .ExecuteTemplate (w , "listing" , infos ); err != nil {
230+ data := struct {
231+ Infos []tusd.FileInfo
232+ Conf ServerConf
233+ }{infos , conf ,}
234+ if err = t .ExecuteTemplate (w , "listing" , data ); err != nil {
221235 //stderr.Fatalf("Unable to render template: %s", err)
222236 http .Error (w , "" , 500 )
223237 return
0 commit comments