This repository has been archived by the owner on Nov 19, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
router.go
123 lines (91 loc) · 2.69 KB
/
router.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
// SPDX-FileCopyrightText: 2023 Iván Szkiba
//
// SPDX-License-Identifier: MIT
package muxpress
import (
"net/http"
"strings"
"github.com/dop251/goja"
"github.com/julienschmidt/httprouter"
"github.com/spf13/afero"
)
type middleware func(req *goja.Object, res *goja.Object, next goja.Callable)
type middlewareChain []middleware
func (chain middlewareChain) callOne(req *goja.Object, res *goja.Object, mware middleware) bool {
nextCalled := false
mware(req, res, func(this goja.Value, args ...goja.Value) (goja.Value, error) {
nextCalled = true
return goja.Undefined(), nil
})
return nextCalled
}
func (chain middlewareChain) call(req *goja.Object, res *goja.Object, cascade ...middleware) {
all := make([]middleware, len(chain)+len(cascade))
copy(all, chain)
copy(all[len(chain):], cascade)
for _, mware := range all {
if !chain.callOne(req, res, mware) {
break
}
}
}
type router struct {
*httprouter.Router
runner RunnerFunc
middlewares middlewareChain
filesystem afero.Fs
}
func newRouter(runner RunnerFunc, filesystem afero.Fs) *router {
return &router{
Router: httprouter.New(),
runner: runner,
filesystem: filesystem,
middlewares: make(middlewareChain, 0),
}
}
func (r *router) use(middlewares ...middleware) {
r.middlewares = append(r.middlewares, middlewares...)
}
func (r *router) runSync(fn func() error) {
done := make(chan struct{}, 1)
r.runner(func() error {
err := fn()
done <- struct{}{}
return err
})
<-done
}
func (r *router) handle(runtime *goja.Runtime, response http.ResponseWriter, request *http.Request, middlewares ...middleware) {
r.runSync(func() error {
req := wrapRequest(runtime, request)
res := wrapResponseWriter(runtime, response)
r.middlewares.call(req, res, middlewares...)
return nil
})
}
func (r *router) handleMethod(runtime *goja.Runtime, method string, path string, middlewares ...middleware) {
r.Router.HandlerFunc(method, path, func(response http.ResponseWriter, request *http.Request) {
r.handle(runtime, response, request, middlewares...)
})
}
func (r *router) fixpath(path string) string {
if strings.HasSuffix(path, "/*filepath") {
return path
}
if !strings.HasSuffix(path, "/") {
path += "/"
}
return path + "*filepath"
}
func (r *router) static(path string, docroot string) {
fs := afero.NewHttpFs(afero.NewBasePathFs(r.filesystem, docroot))
fileserver := http.FileServer(fs)
r.Router.HandlerFunc(http.MethodGet, r.fixpath(path), func(response http.ResponseWriter, request *http.Request) {
params := httprouter.ParamsFromContext(request.Context())
request.URL.Path = params.ByName("filepath")
r.runSync(func() error {
fileserver.ServeHTTP(response, request)
return nil
})
})
}