1diff --git a/cmd/server/main.go b/cmd/server/main.go
2index 385c54f554a135737ec038c895fb6f32db917e2a..39987e5834e607f801155dab453d6ca7cffc8b0f 100644
3--- a/cmd/server/main.go
4+++ b/cmd/server/main.go
5@@ -4,13 +4,13 @@ import (
6 "context"
7 "encoding/hex"
8 "errors"
9+ "net/http"
10 "os"
11 "os/signal"
12
13- "github.com/fasthttp/router"
14+ "github.com/gorilla/mux"
15 "github.com/sirupsen/logrus"
16 flag "github.com/spf13/pflag"
17- "github.com/valyala/fasthttp"
18 "gorm.io/driver/mysql"
19 "gorm.io/driver/postgres"
20 "gorm.io/driver/sqlite"
21@@ -71,8 +71,8 @@ if err != nil {
22 panic("failed to decode key database: " + err.Error())
23 }
24
25- r := router.New()
26- r.GET("/static/{filepath:*}", ext.FileServer(static.Static))
27+ r := mux.NewRouter()
28+ r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.FS(static.Static))))
29
30 // repository
31 var (
32@@ -122,7 +122,7 @@ )
33
34 // worker
35 var (
36- serverWorker = worker.NewServerWorker(&fasthttp.Server{Handler: r.Handler, NoDefaultContentType: true})
37+ serverWorker = worker.NewServerWorker(&http.Server{Handler: r, Addr: "0.0.0.0:8080"})
38 fileWorker = worker.NewWorkerFromChanProcessor[string](
39 fileScanner,
40 scheduler,
41diff --git a/go.mod b/go.mod
42index 8b4538dd8cc256279703e1f2a210d72e4aed034d..91dd7fa6fe880f5bcc4c8e787ec6d438b695edab 100644
43--- a/go.mod
44+++ b/go.mod
45@@ -4,12 +4,11 @@ go 1.19
46
47 require (
48 github.com/barasher/go-exiftool v1.10.0
49- github.com/fasthttp/router v1.4.19
50 github.com/google/go-cmp v0.5.9
51+ github.com/gorilla/mux v1.8.0
52 github.com/h2non/bimg v1.1.9
53 github.com/sirupsen/logrus v1.9.2
54 github.com/spf13/pflag v1.0.5
55- github.com/valyala/fasthttp v1.47.0
56 github.com/valyala/quicktemplate v1.7.0
57 golang.org/x/crypto v0.8.0
58 gorm.io/driver/mysql v1.5.1
59@@ -20,16 +19,13 @@ gorm.io/gorm v1.25.1
60 )
61
62 require (
63- github.com/andybalholm/brotli v1.0.5 // indirect
64 github.com/go-sql-driver/mysql v1.7.1 // indirect
65 github.com/jackc/pgpassfile v1.0.0 // indirect
66 github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
67 github.com/jackc/pgx/v5 v5.3.1 // indirect
68 github.com/jinzhu/inflection v1.0.0 // indirect
69 github.com/jinzhu/now v1.1.5 // indirect
70- github.com/klauspost/compress v1.16.5 // indirect
71 github.com/mattn/go-sqlite3 v1.14.16 // indirect
72- github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect
73 github.com/valyala/bytebufferpool v1.0.0 // indirect
74 golang.org/x/mod v0.10.0 // indirect
75 golang.org/x/sys v0.8.0 // indirect
76diff --git a/go.sum b/go.sum
77index c0456bcef960c20fd37c2cb31634cc5a5b5e1c35..03ce51a72b270cd86a03b06252ae5e751efefc18 100644
78--- a/go.sum
79+++ b/go.sum
80@@ -1,14 +1,10 @@
81 github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
82 github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
83-github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
84-github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
85 github.com/barasher/go-exiftool v1.10.0 h1:f5JY5jc42M7tzR6tbL9508S2IXdIcG9QyieEXNMpIhs=
86 github.com/barasher/go-exiftool v1.10.0/go.mod h1:F9s/a3uHSM8YniVfwF+sbQUtP8Gmh9nyzigNF+8vsWo=
87 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
88 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
89 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
90-github.com/fasthttp/router v1.4.19 h1:RLE539IU/S4kfb4MP56zgP0TIBU9kEg0ID9GpWO0vqk=
91-github.com/fasthttp/router v1.4.19/go.mod h1:+Fh3YOd8x1+he6ZS+d2iUDBH9MGGZ1xQFUor0DE9rKE=
92 github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
93 github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
94 github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
95@@ -18,6 +14,8 @@ github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
96 github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
97 github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
98 github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
99+github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
100+github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
101 github.com/h2non/bimg v1.1.9 h1:WH20Nxko9l/HFm4kZCA3Phbgu2cbHvYzxwxn9YROEGg=
102 github.com/h2non/bimg v1.1.9/go.mod h1:R3+UiYwkK4rQl6KVFTOFJHitgLbZXBZNFh2cv3AEbp8=
103 github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
104@@ -33,16 +31,12 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
105 github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
106 github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
107 github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
108-github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI=
109-github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
110 github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
111 github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
112 github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
113 github.com/microsoft/go-mssqldb v0.17.0 h1:Fto83dMZPnYv1Zwx5vHHxpNraeEaUlQ/hhHLgZiaenE=
114 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
115 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
116-github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk=
117-github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g=
118 github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y=
119 github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
120 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
121@@ -54,8 +48,6 @@ github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
122 github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
123 github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
124 github.com/valyala/fasthttp v1.30.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus=
125-github.com/valyala/fasthttp v1.47.0 h1:y7moDoxYzMooFpT5aHgNgVOQDrS3qlkfiP9mDtGGK9c=
126-github.com/valyala/fasthttp v1.47.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA=
127 github.com/valyala/quicktemplate v1.7.0 h1:LUPTJmlVcb46OOUY3IeD9DojFpAVbsG+5WFTcjMJzCM=
128 github.com/valyala/quicktemplate v1.7.0/go.mod h1:sqKJnoaOF88V07vkO+9FL8fb9uZg/VPSJnLYn+LmLk8=
129 github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
130diff --git a/pkg/ext/fileserver.go b/pkg/ext/fileserver.go
131deleted file mode 100644
132index 87c1ae8f2d507f8c1d69832d741e24a2c76daeca..0000000000000000000000000000000000000000
133--- a/pkg/ext/fileserver.go
134+++ /dev/null
135@@ -1,33 +0,0 @@
136-package ext
137-
138-import (
139- "io/fs"
140- "mime"
141- "path/filepath"
142-
143- "github.com/valyala/fasthttp"
144-)
145-
146-type FileSystem interface {
147- Open(name string) (fs.File, error)
148-}
149-
150-// This is a VERY simple file server. It does not take a lot into consideration
151-// and it should only be used to return small predictable files, like in the
152-// static folder.
153-func FileServer(rootFS FileSystem) fasthttp.RequestHandler {
154- return func(ctx *fasthttp.RequestCtx) {
155- path := ctx.UserValue("filepath").(string)
156-
157- f, err := rootFS.Open(path)
158- if err != nil {
159- InternalServerError(ctx, err)
160- return
161- }
162- defer f.Close()
163-
164- m := mime.TypeByExtension(filepath.Ext(path))
165- ctx.SetContentType(m)
166- ctx.SetBodyStream(f, -1)
167- }
168-}
169diff --git a/pkg/ext/middleware.go b/pkg/ext/middleware.go
170index bcc6c5feb3fa1e30f54afc64d96dfc2c6ad5ca2d..fe2d185be75a28df5f686dabb664b237f85d56ae 100644
171--- a/pkg/ext/middleware.go
172+++ b/pkg/ext/middleware.go
173@@ -1,22 +1,22 @@
174 package ext
175
176 import (
177+ "context"
178 "encoding/base64"
179+ "errors"
180+ "net/http"
181 "time"
182
183 "github.com/sirupsen/logrus"
184- "github.com/valyala/fasthttp"
185
186 "git.sr.ht/~gabrielgio/img/pkg/database/repository"
187 "git.sr.ht/~gabrielgio/img/pkg/service"
188 )
189
190-func HTML(next fasthttp.RequestHandler) fasthttp.RequestHandler {
191- return func(ctx *fasthttp.RequestCtx) {
192- if len(ctx.Request.Header.ContentType()) > 0 {
193- ctx.Response.Header.SetContentType("text/html")
194- }
195- next(ctx)
196+func HTML(next http.HandlerFunc) http.HandlerFunc {
197+ return func(w http.ResponseWriter, r *http.Request) {
198+ w.Header().Set("Content-Type", "text/html")
199+ next(w, r)
200 }
201 }
202
203@@ -30,17 +30,15 @@ entry: log,
204 }
205 }
206
207-func (l *LogMiddleware) HTTP(next fasthttp.RequestHandler) fasthttp.RequestHandler {
208- return func(ctx *fasthttp.RequestCtx) {
209+func (l *LogMiddleware) HTTP(next http.HandlerFunc) http.HandlerFunc {
210+ return func(w http.ResponseWriter, r *http.Request) {
211 start := time.Now()
212- next(ctx)
213+ next(w, r)
214 elapsed := time.Since(start)
215 l.entry.
216 WithField("time", elapsed).
217- WithField("code", ctx.Response.StatusCode()).
218- WithField("path", string(ctx.Path())).
219- WithField("bytes", len(ctx.Response.Body())).
220- Info(string(ctx.Request.Header.Method()))
221+ WithField("path", r.URL.Path).
222+ Info(r.Method)
223 }
224 }
225
226@@ -56,23 +54,23 @@ entry: log.WithField("context", "auth"),
227 }
228 }
229
230-func (a *AuthMiddleware) LoggedIn(next fasthttp.RequestHandler) fasthttp.RequestHandler {
231- return func(ctx *fasthttp.RequestCtx) {
232- path := string(ctx.Path())
233+func (a *AuthMiddleware) LoggedIn(next http.HandlerFunc) http.HandlerFunc {
234+ return func(w http.ResponseWriter, r *http.Request) {
235+ path := string(r.URL.Path)
236 if path == "/login" || path == "/initial" {
237- next(ctx)
238+ next(w, r)
239 return
240 }
241
242 redirectLogin := "/login?redirect=" + path
243- authBase64 := ctx.Request.Header.Cookie("auth")
244- if authBase64 == nil {
245+ authBase64, err := r.Cookie("auth")
246+ if errors.Is(err, http.ErrNoCookie) {
247 a.entry.Info("No auth provided")
248- ctx.Redirect(redirectLogin, 307)
249+ http.Redirect(w, r, redirectLogin, http.StatusTemporaryRedirect)
250 return
251 }
252
253- auth, err := base64.StdEncoding.DecodeString(string(authBase64))
254+ auth, err := base64.StdEncoding.DecodeString(authBase64.Value)
255 if err != nil {
256 a.entry.Error(err)
257 return
258@@ -81,20 +79,20 @@
259 token, err := service.ReadToken(auth, a.key)
260 if err != nil {
261 a.entry.Error(err)
262- ctx.Redirect(redirectLogin, 307)
263+ http.Redirect(w, r, redirectLogin, http.StatusTemporaryRedirect)
264 return
265 }
266- ctx.SetUserValue("token", token)
267+ r = r.WithContext(context.WithValue(r.Context(), "token", token))
268 a.entry.
269 WithField("userID", token.UserID).
270 WithField("username", token.Username).
271 Info("user recognized")
272- next(ctx)
273+ next(w, r)
274 }
275 }
276
277-func GetTokenFromCtx(ctx *fasthttp.RequestCtx) *service.Token {
278- tokenValue := ctx.UserValue("token")
279+func GetTokenFromCtx(w http.ResponseWriter, r *http.Request) *service.Token {
280+ tokenValue := r.Context().Value("token")
281 if token, ok := tokenValue.(*service.Token); ok {
282 return token
283 }
284@@ -111,31 +109,31 @@ userRepository: userRepository,
285 }
286 }
287
288-func (i *InitialSetupMiddleware) Check(next fasthttp.RequestHandler) fasthttp.RequestHandler {
289- return func(ctx *fasthttp.RequestCtx) {
290+func (i *InitialSetupMiddleware) Check(next http.HandlerFunc) http.HandlerFunc {
291+ return func(w http.ResponseWriter, r *http.Request) {
292 // if user has been set to context it is logged in already
293- _, ok := ctx.UserValue("token").(*service.Token)
294- if ok {
295- next(ctx)
296+ token := GetTokenFromCtx(w, r)
297+ if token == nil {
298+ next(w, r)
299 return
300 }
301
302- path := string(ctx.Path())
303+ path := r.URL.Path
304 if path == "/initial" {
305- next(ctx)
306+ next(w, r)
307 return
308 }
309
310- exists, err := i.userRepository.Any(ctx)
311+ exists, err := i.userRepository.Any(r.Context())
312 if err != nil {
313- InternalServerError(ctx, err)
314+ InternalServerError(w, err)
315 return
316 }
317
318 if exists {
319- next(ctx)
320+ next(w, r)
321 return
322 }
323- ctx.Redirect("/initial", 307)
324+ http.Redirect(w, r, "/initial", http.StatusTemporaryRedirect)
325 }
326 }
327diff --git a/pkg/ext/responses.go b/pkg/ext/responses.go
328index dbad5b20204f2c8f3d665bf9a7cd7094bdddf328..ba58dd5d54d2a7d27a5a3a0c241240d3ec747614 100644
329--- a/pkg/ext/responses.go
330+++ b/pkg/ext/responses.go
331@@ -1,39 +1,21 @@
332 package ext
333
334 import (
335- "bytes"
336 "fmt"
337-
338- "github.com/valyala/fasthttp"
339+ "net/http"
340
341 "git.sr.ht/~gabrielgio/img/templates"
342 )
343
344-var (
345- ContentTypeHTML = []byte("text/html")
346-)
347-
348-func NotFoundHTML(ctx *fasthttp.RequestCtx) {
349- templates.WritePageTemplate(ctx, &templates.ErrorPage{
350+func NotFound(w http.ResponseWriter, r *http.Request) {
351+ templates.WritePageTemplate(w, &templates.ErrorPage{
352 Err: "Not Found",
353 })
354 }
355
356-func NotFound(ctx *fasthttp.RequestCtx) {
357- ctx.Response.SetStatusCode(404)
358- ct := ctx.Response.Header.ContentType()
359- if bytes.Equal(ct, ContentTypeHTML) {
360- NotFoundHTML(ctx)
361- }
362-}
363-
364-func InternalServerError(ctx *fasthttp.RequestCtx, err error) {
365- ctx.Response.SetStatusCode(500)
366- templates.WritePageTemplate(ctx, &templates.ErrorPage{
367+func InternalServerError(w http.ResponseWriter, err error) {
368+ w.WriteHeader(http.StatusInternalServerError)
369+ templates.WritePageTemplate(w, &templates.ErrorPage{
370 Err: fmt.Sprintf("Internal Server Error:\n%s", err.Error()),
371 })
372 }
373-
374-func NoContent(ctx *fasthttp.RequestCtx) {
375- ctx.Response.SetStatusCode(204)
376-}
377diff --git a/pkg/ext/router.go b/pkg/ext/router.go
378index 74f0a95f468cb3a484bdfa17a27e6085c35729a8..8b9a31090bef2036a018bb43cae4e6e81fd6ad0a 100644
379--- a/pkg/ext/router.go
380+++ b/pkg/ext/router.go
381@@ -1,51 +1,52 @@
382 package ext
383
384 import (
385- "github.com/fasthttp/router"
386- "github.com/valyala/fasthttp"
387+ "net/http"
388+
389+ "github.com/gorilla/mux"
390 )
391
392 type (
393 Router struct {
394 middlewares []Middleware
395- fastRouter *router.Router
396+ router *mux.Router
397 }
398- Middleware func(next fasthttp.RequestHandler) fasthttp.RequestHandler
399- ErrorRequestHandler func(ctx *fasthttp.RequestCtx) error
400+ Middleware func(next http.HandlerFunc) http.HandlerFunc
401+ ErrorRequestHandler func(w http.ResponseWriter, r *http.Request) error
402 )
403
404-func NewRouter(nestedRouter *router.Router) *Router {
405+func NewRouter(nestedRouter *mux.Router) *Router {
406 return &Router{
407- fastRouter: nestedRouter,
408+ router: nestedRouter,
409 }
410 }
411
412-func (self *Router) AddMiddleware(middleware Middleware) {
413- self.middlewares = append(self.middlewares, middleware)
414+func (r *Router) AddMiddleware(middleware Middleware) {
415+ r.middlewares = append(r.middlewares, middleware)
416 }
417
418-func wrapError(next ErrorRequestHandler) fasthttp.RequestHandler {
419- return func(ctx *fasthttp.RequestCtx) {
420- if err := next(ctx); err != nil {
421- ctx.Response.SetStatusCode(500)
422- InternalServerError(ctx, err)
423+func wrapError(next ErrorRequestHandler) http.HandlerFunc {
424+ return func(w http.ResponseWriter, r *http.Request) {
425+ if err := next(w, r); err != nil {
426+ w.WriteHeader(http.StatusInternalServerError)
427+ InternalServerError(w, err)
428 }
429 }
430 }
431
432-func (self *Router) run(next ErrorRequestHandler) fasthttp.RequestHandler {
433- return func(ctx *fasthttp.RequestCtx) {
434+func (r *Router) run(next ErrorRequestHandler) http.HandlerFunc {
435+ return func(w http.ResponseWriter, re *http.Request) {
436 req := wrapError(next)
437- for _, r := range self.middlewares {
438+ for _, r := range r.middlewares {
439 req = r(req)
440 }
441- req(ctx)
442+ req(w, re)
443 }
444 }
445
446-func (self *Router) GET(path string, handler ErrorRequestHandler) {
447- self.fastRouter.GET(path, self.run(handler))
448+func (r *Router) GET(path string, handler ErrorRequestHandler) {
449+ r.router.HandleFunc(path, r.run(handler)).Methods("GET")
450 }
451-func (self *Router) POST(path string, handler ErrorRequestHandler) {
452- self.fastRouter.POST(path, self.run(handler))
453+func (r *Router) POST(path string, handler ErrorRequestHandler) {
454+ r.router.HandleFunc(path, r.run(handler)).Methods("POSt")
455 }
456diff --git a/pkg/view/auth.go b/pkg/view/auth.go
457index 631cfb30815cde5ec8694a09073da6a597b8e0a4..2a4b95e77f23249aaa99b9c644ae39e6926029db 100644
458--- a/pkg/view/auth.go
459+++ b/pkg/view/auth.go
460@@ -2,8 +2,7 @@ package view
461
462 import (
463 "encoding/base64"
464-
465- "github.com/valyala/fasthttp"
466+ "net/http"
467
468 "git.sr.ht/~gabrielgio/img/pkg/ext"
469 "git.sr.ht/~gabrielgio/img/pkg/service"
470@@ -20,71 +19,77 @@ userController: userController,
471 }
472 }
473
474-func (v *AuthView) LoginView(ctx *fasthttp.RequestCtx) error {
475- templates.WritePageTemplate(ctx, &templates.LoginPage{})
476+func (v *AuthView) LoginView(w http.ResponseWriter, r *http.Request) error {
477+ templates.WritePageTemplate(w, &templates.LoginPage{})
478 return nil
479 }
480
481-func (v *AuthView) Logout(ctx *fasthttp.RequestCtx) error {
482- cook := fasthttp.Cookie{}
483- cook.SetKey("auth")
484- cook.SetValue("")
485- cook.SetMaxAge(-1)
486- cook.SetHTTPOnly(true)
487- cook.SetSameSite(fasthttp.CookieSameSiteDefaultMode)
488- ctx.Response.Header.SetCookie(&cook)
489+func (v *AuthView) Logout(w http.ResponseWriter, r *http.Request) error {
490+ cook := http.Cookie{
491+ Name: "auth",
492+ Value: "",
493+ MaxAge: -1,
494+ HttpOnly: true,
495+ SameSite: http.SameSiteDefaultMode,
496+ }
497+ http.SetCookie(w, &cook)
498
499- ctx.Redirect("/", 307)
500+ http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
501 return nil
502 }
503
504-func (v *AuthView) Login(ctx *fasthttp.RequestCtx) error {
505- username := ctx.FormValue("username")
506- password := ctx.FormValue("password")
507+func (v *AuthView) Login(w http.ResponseWriter, r *http.Request) error {
508+ var (
509+ username = []byte(r.FormValue("username"))
510+ password = []byte(r.FormValue("password"))
511+ )
512
513- auth, err := v.userController.Login(ctx, username, password)
514+ auth, err := v.userController.Login(r.Context(), username, password)
515 if err != nil {
516 return err
517 }
518
519 base64Auth := base64.StdEncoding.EncodeToString(auth)
520
521- cook := fasthttp.Cookie{}
522- cook.SetKey("auth")
523- cook.SetValue(base64Auth)
524- cook.SetHTTPOnly(true)
525- cook.SetSameSite(fasthttp.CookieSameSiteDefaultMode)
526- ctx.Response.Header.SetCookie(&cook)
527+ cook := http.Cookie{
528+ Name: "auth",
529+ Value: base64Auth,
530+ HttpOnly: true,
531+ SameSite: http.SameSiteDefaultMode,
532+ }
533+ http.SetCookie(w, &cook)
534
535- redirect := string(ctx.FormValue("redirect"))
536+ redirect := r.FormValue("redirect")
537 if redirect == "" {
538- ctx.Redirect("/", 307)
539+ http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
540 } else {
541- ctx.Redirect(redirect, 307)
542+ http.Redirect(w, r, redirect, http.StatusTemporaryRedirect)
543 }
544 return nil
545 }
546
547-func Index(ctx *fasthttp.RequestCtx) {
548- ctx.Redirect("/login", 307)
549+func Index(w http.ResponseWriter, r *http.Request) {
550+ http.Redirect(w, r, "/login", http.StatusTemporaryRedirect)
551 }
552
553-func (v *AuthView) InitialRegisterView(ctx *fasthttp.RequestCtx) error {
554- templates.WritePageTemplate(ctx, &templates.RegisterPage{})
555+func (v *AuthView) InitialRegisterView(w http.ResponseWriter, r *http.Request) error {
556+ templates.WritePageTemplate(w, &templates.RegisterPage{})
557 return nil
558 }
559
560-func (v *AuthView) InitialRegister(ctx *fasthttp.RequestCtx) error {
561- username := ctx.FormValue("username")
562- password := ctx.FormValue("password")
563- path := ctx.FormValue("path")
564+func (v *AuthView) InitialRegister(w http.ResponseWriter, r *http.Request) error {
565+ var (
566+ username = []byte(r.FormValue("username"))
567+ password = []byte(r.FormValue("password"))
568+ path = []byte(r.FormValue("path"))
569+ )
570
571- err := v.userController.InitialRegister(ctx, username, password, path)
572+ err := v.userController.InitialRegister(r.Context(), username, password, path)
573 if err != nil {
574 return err
575 }
576
577- ctx.Redirect("/login", 307)
578+ http.Redirect(w, r, "/login", http.StatusTemporaryRedirect)
579 return nil
580 }
581
582diff --git a/pkg/view/filesystem.go b/pkg/view/filesystem.go
583index 6a011171eef0c61a0385600ec638b4dcc18f672c..d49ad4ff02e0b62f151c8570ed4598b73d504cde 100644
584--- a/pkg/view/filesystem.go
585+++ b/pkg/view/filesystem.go
586@@ -1,7 +1,7 @@
587 package view
588
589 import (
590- "github.com/valyala/fasthttp"
591+ "net/http"
592
593 "git.sr.ht/~gabrielgio/img/pkg/database/repository"
594 "git.sr.ht/~gabrielgio/img/pkg/ext"
595@@ -31,21 +31,23 @@ settings: settingsRepository,
596 }
597 }
598
599-func (self *FileSystemView) Index(ctx *fasthttp.RequestCtx) error {
600- pathValue := string(ctx.FormValue("path"))
601- token := ext.GetTokenFromCtx(ctx)
602+func (self *FileSystemView) Index(w http.ResponseWriter, r *http.Request) error {
603+ var (
604+ pathValue = r.FormValue("path")
605+ token = ext.GetTokenFromCtx(w, r)
606+ )
607
608- page, err := self.fsService.GetPage(ctx, token.UserID, pathValue)
609+ page, err := self.fsService.GetPage(r.Context(), token.UserID, pathValue)
610 if err != nil {
611 return err
612 }
613
614- settings, err := self.settings.Load(ctx)
615+ settings, err := self.settings.Load(r.Context())
616 if err != nil {
617 return err
618 }
619
620- templates.WritePageTemplate(ctx, &templates.FilePage{
621+ templates.WritePageTemplate(w, &templates.FilePage{
622 Page: page,
623 ShowMode: settings.ShowMode,
624 ShowOwner: settings.ShowOwner,
625diff --git a/pkg/view/media.go b/pkg/view/media.go
626index 6e34fd6c4505d418f9a57c57f20d9156866a9b2f..c7d84ec9e8346627ef2b13fab1bc7e0ec949a2d5 100644
627--- a/pkg/view/media.go
628+++ b/pkg/view/media.go
629@@ -1,9 +1,8 @@
630 package view
631
632 import (
633+ "net/http"
634 "strconv"
635-
636- "github.com/valyala/fasthttp"
637
638 "git.sr.ht/~gabrielgio/img/pkg/database/repository"
639 "git.sr.ht/~gabrielgio/img/pkg/ext"
640@@ -18,12 +17,12 @@ settingsRepository repository.SettingsRepository
641 }
642 )
643
644-func getPagination(ctx *fasthttp.RequestCtx) *repository.Pagination {
645+func getPagination(w http.ResponseWriter, r *http.Request) *repository.Pagination {
646 var (
647 size int
648 page int
649- sizeStr = string(ctx.FormValue("size"))
650- pageStr = string(ctx.FormValue("page"))
651+ sizeStr = r.FormValue("size")
652+ pageStr = r.FormValue("page")
653 )
654
655 if sizeStr == "" {
656@@ -60,22 +59,22 @@ settingsRepository: settingsRepository,
657 }
658 }
659
660-func (self *MediaView) Index(ctx *fasthttp.RequestCtx) error {
661- p := getPagination(ctx)
662- token := ext.GetTokenFromCtx(ctx)
663+func (self *MediaView) Index(w http.ResponseWriter, r *http.Request) error {
664+ p := getPagination(w, r)
665+ token := ext.GetTokenFromCtx(w, r)
666
667- userPath, err := self.userRepository.GetPathFromUserID(ctx, token.UserID)
668+ userPath, err := self.userRepository.GetPathFromUserID(r.Context(), token.UserID)
669 if err != nil {
670 return err
671 }
672
673 p.Path = userPath
674- medias, err := self.mediaRepository.List(ctx, p)
675+ medias, err := self.mediaRepository.List(r.Context(), p)
676 if err != nil {
677 return err
678 }
679
680- settings, err := self.settingsRepository.Load(ctx)
681+ settings, err := self.settingsRepository.Load(r.Context())
682 if err != nil {
683 return err
684 }
685@@ -89,43 +88,43 @@ },
686 Settings: settings,
687 }
688
689- templates.WritePageTemplate(ctx, page)
690+ templates.WritePageTemplate(w, page)
691
692 return nil
693 }
694
695-func (self *MediaView) GetImage(ctx *fasthttp.RequestCtx) error {
696- pathHash := string(ctx.FormValue("path_hash"))
697+func (self *MediaView) GetImage(w http.ResponseWriter, r *http.Request) error {
698+ pathHash := r.FormValue("path_hash")
699
700- media, err := self.mediaRepository.Get(ctx, pathHash)
701+ media, err := self.mediaRepository.Get(r.Context(), pathHash)
702 if err != nil {
703 return err
704 }
705
706- ctx.Response.Header.SetContentType(media.MIMEType)
707- fasthttp.ServeFileUncompressed(ctx, media.Path)
708+ w.Header().Set("Content-Type", media.MIMEType)
709+ http.ServeFile(w, r, media.Path)
710 return nil
711 }
712
713-func (self *MediaView) GetThumbnail(ctx *fasthttp.RequestCtx) error {
714- pathHash := string(ctx.FormValue("path_hash"))
715+func (self *MediaView) GetThumbnail(w http.ResponseWriter, r *http.Request) error {
716+ pathHash := r.FormValue("path_hash")
717
718- path, err := self.mediaRepository.GetThumbnailPath(ctx, pathHash)
719+ path, err := self.mediaRepository.GetThumbnailPath(r.Context(), pathHash)
720 if err != nil {
721- ctx.Redirect("/media/image?path_hash="+pathHash, 307)
722+ http.Redirect(w, r, "/media/image?path_hash="+pathHash, http.StatusTemporaryRedirect)
723 // nolint: nilerr
724 return nil
725 }
726
727- ctx.Request.Header.SetContentType("image/jpeg")
728- fasthttp.ServeFileUncompressed(ctx, path)
729+ w.Header().Set("Content-Type", "image/jpeg")
730+ http.ServeFile(w, r, path)
731 return nil
732 }
733
734 func (self *MediaView) SetMyselfIn(r *ext.Router) {
735- r.GET("/media", self.Index)
736- r.POST("/media", self.Index)
737+ r.GET("/media/", self.Index)
738+ r.POST("/media/", self.Index)
739
740- r.GET("/media/image", self.GetImage)
741- r.GET("/media/thumbnail", self.GetThumbnail)
742+ r.GET("/media/image/", self.GetImage)
743+ r.GET("/media/thumbnail/", self.GetThumbnail)
744 }
745diff --git a/pkg/view/settings.go b/pkg/view/settings.go
746index 5131362e2ba129a8791a42a73ce732e91322f5c2..bf2dca6d27190c1ada6765d2ee61588edb8e85f0 100644
747--- a/pkg/view/settings.go
748+++ b/pkg/view/settings.go
749@@ -1,9 +1,8 @@
750 package view
751
752 import (
753+ "net/http"
754 "strconv"
755-
756- "github.com/valyala/fasthttp"
757
758 "git.sr.ht/~gabrielgio/img/pkg/database/repository"
759 "git.sr.ht/~gabrielgio/img/pkg/ext"
760@@ -29,18 +28,18 @@ userController: userController,
761 }
762 }
763
764-func (self *SettingsView) Index(ctx *fasthttp.RequestCtx) error {
765- s, err := self.settingsRepository.Load(ctx)
766+func (self *SettingsView) Index(w http.ResponseWriter, r *http.Request) error {
767+ s, err := self.settingsRepository.Load(r.Context())
768 if err != nil {
769 return err
770 }
771
772- users, err := self.userController.List(ctx)
773+ users, err := self.userController.List(r.Context())
774 if err != nil {
775 return err
776 }
777
778- templates.WritePageTemplate(ctx, &templates.SettingsPage{
779+ templates.WritePageTemplate(w, &templates.SettingsPage{
780 Settings: s,
781 Users: users,
782 })
783@@ -48,22 +47,22 @@
784 return nil
785 }
786
787-func (self *SettingsView) User(ctx *fasthttp.RequestCtx) error {
788- id := string(ctx.FormValue("userId"))
789+func (self *SettingsView) User(w http.ResponseWriter, r *http.Request) error {
790+ id := r.FormValue("userId")
791 idValue, err := ParseUint(id)
792 if err != nil {
793 return err
794 }
795
796 if idValue == nil {
797- templates.WritePageTemplate(ctx, &templates.UserPage{})
798+ templates.WritePageTemplate(w, &templates.UserPage{})
799 } else {
800- user, err := self.userController.Get(ctx, *idValue)
801+ user, err := self.userController.Get(r.Context(), *idValue)
802 if err != nil {
803 return err
804 }
805
806- templates.WritePageTemplate(ctx, &templates.UserPage{
807+ templates.WritePageTemplate(w, &templates.UserPage{
808 ID: idValue,
809 Username: user.Username,
810 Path: user.Path,
811@@ -74,13 +73,13 @@
812 return nil
813 }
814
815-func (self *SettingsView) UpsertUser(ctx *fasthttp.RequestCtx) error {
816+func (self *SettingsView) UpsertUser(w http.ResponseWriter, r *http.Request) error {
817 var (
818- username = string(ctx.FormValue("username"))
819- password = ctx.FormValue("password")
820- path = string(ctx.FormValue("path"))
821- isAdmin = string(ctx.FormValue("isAdmin")) == "on"
822- id = string(ctx.FormValue("userId"))
823+ username = r.FormValue("username")
824+ password = []byte(r.FormValue("password"))
825+ path = r.FormValue("path")
826+ isAdmin = r.FormValue("isAdmin") == "on"
827+ id = r.FormValue("userId")
828 )
829
830 idValue, err := ParseUint(id)
831@@ -88,18 +87,18 @@ if err != nil {
832 return err
833 }
834
835- err = self.userController.Upsert(ctx, idValue, username, "", password, isAdmin, path)
836+ err = self.userController.Upsert(r.Context(), idValue, username, "", password, isAdmin, path)
837 if err != nil {
838 return err
839 }
840
841- ctx.Redirect("/settings", 307)
842+ http.Redirect(w, r, "/settings", http.StatusTemporaryRedirect)
843 return nil
844 }
845
846-func (self *SettingsView) Delete(ctx *fasthttp.RequestCtx) error {
847+func (self *SettingsView) Delete(w http.ResponseWriter, r *http.Request) error {
848 var (
849- id = string(ctx.FormValue("userId"))
850+ id = r.FormValue("userId")
851 )
852
853 idValue, err := ParseUint(id)
854@@ -108,24 +107,24 @@ return err
855 }
856
857 if idValue != nil {
858- err = self.userController.Delete(ctx, *idValue)
859+ err = self.userController.Delete(r.Context(), *idValue)
860 if err != nil {
861 return err
862 }
863 }
864
865- ctx.Redirect("/settings", 307)
866+ http.Redirect(w, r, "/settings", http.StatusTemporaryRedirect)
867 return nil
868 }
869
870-func (self *SettingsView) Save(ctx *fasthttp.RequestCtx) error {
871+func (self *SettingsView) Save(w http.ResponseWriter, r *http.Request) error {
872 var (
873- showMode = string(ctx.FormValue("showMode")) == "on"
874- showOwner = string(ctx.FormValue("showOwner")) == "on"
875- preloadVideoMetadata = string(ctx.FormValue("preloadVideoMetadata")) == "on"
876+ showMode = r.FormValue("showMode") == "on"
877+ showOwner = r.FormValue("showOwner") == "on"
878+ preloadVideoMetadata = r.FormValue("preloadVideoMetadata") == "on"
879 )
880
881- err := self.settingsRepository.Save(ctx, &repository.Settings{
882+ err := self.settingsRepository.Save(r.Context(), &repository.Settings{
883 ShowMode: showMode,
884 ShowOwner: showOwner,
885 PreloadVideoMetadata: preloadVideoMetadata,
886@@ -134,7 +133,7 @@ if err != nil {
887 return err
888 }
889
890- return self.Index(ctx)
891+ return self.Index(w, r)
892 }
893
894 func (self *SettingsView) SetMyselfIn(r *ext.Router) {
895diff --git a/pkg/worker/httpserver.go b/pkg/worker/httpserver.go
896index 181cf73f4d173437b0b37312b1a4999ad4221324..dc8f255f1953dfec7011e4611dd54ddfb3d22cfa 100644
897--- a/pkg/worker/httpserver.go
898+++ b/pkg/worker/httpserver.go
899@@ -2,29 +2,24 @@ package worker
900
901 import (
902 "context"
903-
904- "github.com/valyala/fasthttp"
905+ "net/http"
906 )
907
908 type ServerWorker struct {
909- server *fasthttp.Server
910+ server *http.Server
911 }
912
913 func (self *ServerWorker) Start(ctx context.Context) error {
914 go func() {
915 // nolint: errcheck
916- self.server.ListenAndServe("0.0.0.0:8080")
917+ self.server.ListenAndServe()
918 }()
919
920 <-ctx.Done()
921- return self.Shutdown()
922+ return self.server.Shutdown(ctx)
923 }
924
925-func (self *ServerWorker) Shutdown() error {
926- return self.server.Shutdown()
927-}
928-
929-func NewServerWorker(server *fasthttp.Server) *ServerWorker {
930+func NewServerWorker(server *http.Server) *ServerWorker {
931 return &ServerWorker{
932 server: server,
933 }
934diff --git a/templates/media.qtpl b/templates/media.qtpl
935index 621789945412ff643221945ab5ea59d590722f66..ae58e6181411735d7552404a7f6c5c443cb0dcae 100644
936--- a/templates/media.qtpl
937+++ b/templates/media.qtpl
938@@ -22,19 +22,19 @@ <div class="columns is-multiline">
939 {% for _, media := range p.Medias %}
940 <div class="card-image">
941 {% if media.IsVideo() %}
942- <video class="image is-fit" controls muted="true" poster="/media/thumbnail?path_hash={%s media.PathHash %}" preload="{%s p.PreloadAttr() %}">
943- <source src="/media/image?path_hash={%s media.PathHash %}" type="{%s media.MIMEType %}">
944+ <video class="image is-fit" controls muted="true" poster="/media/thumbnail/?path_hash={%s media.PathHash %}" preload="{%s p.PreloadAttr() %}">
945+ <source src="/media/image/?path_hash={%s media.PathHash %}" type="{%s media.MIMEType %}">
946 </video>
947 {% else %}
948 <figure class="image is-fit">
949- <img src="/media/thumbnail?path_hash={%s media.PathHash %}">
950+ <img src="/media/thumbnail/?path_hash={%s media.PathHash %}">
951 </figure>
952 {% endif %}
953 </div>
954 {% endfor %}
955 </div>
956 <div class="row">
957- <a href="/media?page={%d p.Next.Page %}" class="button is-pulled-right">next</a>
958+ <a href="/media/?page={%d p.Next.Page %}" class="button is-pulled-right">next</a>
959 </div>
960 {% endfunc %}
961