6
1
mirror of https://git.mills.io/saltyim/saltyim.git synced 2024-06-16 03:48:24 +00:00
prologic-saltyim/internal/router.go
2022-03-31 21:19:45 +00:00

162 lines
4.5 KiB
Go

package internal
import (
"io/fs"
"net/http"
"github.com/julienschmidt/httprouter"
)
// Middleware ...
type Middleware func(httprouter.Handle) httprouter.Handle
// Router ...
type Router struct {
httprouter.Router
path string
middlewares []Middleware
}
// NewRouter ...
func NewRouter() *Router {
return &Router{
Router: httprouter.Router{
RedirectTrailingSlash: true,
RedirectFixedPath: true,
HandleMethodNotAllowed: false,
HandleOPTIONS: true,
GlobalOPTIONS: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers", "*")
w.Header().Set("Access-Control-Expose-Headers", "*")
w.Header().Set("Accept-Encoding", "br, gzip, deflate")
w.Header().Set("X-Salty-Accept-Encoding", "br, gzip, deflate")
}),
},
}
}
func (r *Router) joinPath(path string) string {
if (r.path + path)[0] != '/' {
panic("path should start with '/' in path '" + path + "'.")
}
return r.path + path
}
// Group returns new *Router with given path and middlewares.
// It should be used for handles which have same path prefix or common middlewares.
func (r *Router) Group(path string, m ...Middleware) *Router {
if path[len(path)-1] == '/' {
path = path[:len(path)-1]
}
return &Router{
Router: r.Router,
middlewares: append(m, r.middlewares...),
path: r.joinPath(path),
}
}
// Use appends new middleware to current Router.
func (r *Router) Use(m ...Middleware) *Router {
r.middlewares = append(m, r.middlewares...)
return r
}
// Handle registers a new request handle combined with middlewares.
func (r *Router) Handle(method, path string, handle httprouter.Handle) {
for _, v := range r.middlewares {
handle = v(handle)
}
r.Router.Handle(method, r.joinPath(path), handle)
}
// GET is a shortcut for Router.Handle("GET", path, handle)
func (r *Router) GET(path string, handle httprouter.Handle) {
r.Handle("GET", path, handle)
}
// HEAD is a shortcut for Router.Handle("HEAD", path, handle)
func (r *Router) HEAD(path string, handle httprouter.Handle) {
r.Handle("HEAD", path, handle)
}
// OPTIONS is a shortcut for Router.Handle("OPTIONS", path, handle)
func (r *Router) OPTIONS(path string, handle httprouter.Handle) {
r.Handle("OPTIONS", path, handle)
}
// POST is a shortcut for Router.Handle("POST", path, handle)
func (r *Router) POST(path string, handle httprouter.Handle) {
r.Handle("POST", path, handle)
}
// PUT is a shortcut for Router.Handle("PUT", path, handle)
func (r *Router) PUT(path string, handle httprouter.Handle) {
r.Handle("PUT", path, handle)
}
// PATCH is a shortcut for Router.Handle("PATCH", path, handle)
func (r *Router) PATCH(path string, handle httprouter.Handle) {
r.Handle("PATCH", path, handle)
}
// DELETE is a shortcut for Router.Handle("DELETE", path, handle)
func (r *Router) DELETE(path string, handle httprouter.Handle) {
r.Handle("DELETE", path, handle)
}
// Handler is an adapter for http.Handler.
func (r *Router) Handler(method, path string, handler http.Handler) {
handle := func(w http.ResponseWriter, req *http.Request, _ httprouter.Params) {
handler.ServeHTTP(w, req)
}
r.Handle(method, path, handle)
}
// HandlerFunc is an adapter for http.HandlerFunc.
func (r *Router) HandlerFunc(method, path string, handler http.HandlerFunc) {
r.Handler(method, path, handler)
}
// Static serves files from given root directory.
func (r *Router) Static(path, root string) {
if len(path) < 10 || path[len(path)-10:] != "/*filepath" {
panic("path should end with '/*filepath' in path '" + path + "'.")
}
base := r.joinPath(path[:len(path)-9])
fileServer := http.StripPrefix(base, http.FileServer(http.Dir(root)))
r.Handler("GET", path, fileServer)
}
// File serves the named file.
func (r *Router) File(path, name string) {
r.HandlerFunc("GET", path, func(w http.ResponseWriter, req *http.Request) {
http.ServeFile(w, req, name)
})
}
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
r.Router.ServeHTTP(w, req)
}
// ServeFilesWithCacheControl ...
func (r *Router) ServeFilesWithCacheControl(path string, root fs.FS) {
if len(path) < 10 || path[len(path)-10:] != "/*filepath" {
panic("path must end with /*filepath in path '" + path + "'")
}
fileServer := http.FileServer(http.FS(root))
r.GET(path, func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
w.Header().Set("Vary", "Accept-Encoding")
w.Header().Set("Cache-Control", "public, max-age=7776000")
req.URL.Path = ps.ByName("filepath")
fileServer.ServeHTTP(w, req)
})
}