github.com/vugu/vugu@v0.3.6-0.20240430171613-3f6f402e014b/devutil/mux.go (about) 1 package devutil 2 3 import ( 4 "net/http" 5 "path" 6 ) 7 8 /* 9 10 Example use: 11 wc := devutil.NewWasmCompiler().SetDir(".") 12 mux := devutil.NewMux() 13 //mux.Exact("/", devutil.DefaultIndex) 14 mux.Match(devutil.NoFileExt, devutil.DefaultIndex) 15 //mux.Match(devutil.NoFileExt, devutil.StaticFilePath("index.html")) 16 mux.Exact("/main.wasm", devutil.MainWasmHandler(wc)) 17 mux.Exact("/wasm_exec.js", devutil.WasmExecJSHandler(wc)) 18 mux.Default(devutil.NewFileServer().SetDir(".")) 19 20 */ 21 22 // RequestMatcher describes something that can say yes/no if a request matches. 23 // We use it here to mean "should this path be followed in order to answer this request". 24 type RequestMatcher interface { 25 RequestMatch(r *http.Request) bool 26 } 27 28 // RequestMatcherFunc implements RequestMatcher as a function. 29 type RequestMatcherFunc func(r *http.Request) bool 30 31 // NoFileExt is a RequestMatcher that will return true for all paths which do not have a file extension. 32 var NoFileExt = RequestMatcherFunc(func(r *http.Request) bool { 33 return path.Ext(path.Clean("/"+r.URL.Path)) == "" 34 }) 35 36 // RequestMatch implements RequestMatcher. 37 func (f RequestMatcherFunc) RequestMatch(r *http.Request) bool { return f(r) } 38 39 // Mux is simple HTTP request multiplexer that has more generally useful behavior for Vugu development than http.ServeMux. 40 // Routes are considered in the order they are added. 41 type Mux struct { 42 routeList []muxRoute 43 defaultHandler http.Handler 44 } 45 46 type muxRoute struct { 47 rm RequestMatcher 48 h http.Handler 49 } 50 51 // NewMux returns a new Mux. 52 func NewMux() *Mux { 53 return &Mux{} 54 } 55 56 // Exact adds an exact route match. If path.Clean("/"+r.URL.Path)==name then h is called to handle the request. 57 func (m *Mux) Exact(name string, h http.Handler) *Mux { 58 m.Match(RequestMatcherFunc(func(r *http.Request) bool { 59 return path.Clean("/"+r.URL.Path) == name 60 }), h) 61 return m 62 } 63 64 // Match adds a route that is used if the provided RequestMatcher returns true. 65 func (m *Mux) Match(rm RequestMatcher, h http.Handler) *Mux { 66 m.routeList = append(m.routeList, muxRoute{rm: rm, h: h}) 67 return m 68 } 69 70 // Default sets the defualt handler to be called if no other matches were found. 71 func (m *Mux) Default(h http.Handler) *Mux { 72 m.defaultHandler = h 73 return m 74 } 75 76 // ServeHTTP implements http.Handler. 77 func (m *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request) { 78 79 for _, rt := range m.routeList { 80 if rt.rm.RequestMatch(r) { 81 rt.h.ServeHTTP(w, r) 82 return 83 } 84 } 85 86 if m.defaultHandler != nil { 87 m.defaultHandler.ServeHTTP(w, r) 88 return 89 } 90 91 http.NotFound(w, r) 92 }