192 lines
4.2 KiB
Go
192 lines
4.2 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
type RequestCtxKey string
|
|
|
|
type Route struct {
|
|
Method string
|
|
Path string
|
|
Handle http.HandlerFunc
|
|
Handler http.Handler
|
|
matcher *UrlParamMatcher
|
|
}
|
|
|
|
func (route *Route) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
if route.Handler != nil {
|
|
route.Handler.ServeHTTP(w, r)
|
|
} else {
|
|
route.Handle(w, r)
|
|
}
|
|
}
|
|
|
|
func (route *Route) Match(r *http.Request) bool {
|
|
if route.Method != "" && route.Method != r.Method {
|
|
return false
|
|
}
|
|
|
|
if route.matcher != nil {
|
|
params, matched := MatchUrlParam(r.URL.Path, route.matcher)
|
|
if matched {
|
|
ctx := r.Context()
|
|
data := ctx.Value(RequestCtxKey("data")).(map[string]interface{})
|
|
for _, p := range route.matcher.Params {
|
|
data[p] = params[p]
|
|
}
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
if route.Path == "" {
|
|
return true
|
|
}
|
|
return strings.HasPrefix(r.URL.Path, route.Path)
|
|
}
|
|
|
|
type Routes []*Route
|
|
|
|
func (rs Routes) Less(i, j int) bool {
|
|
iPaths := strings.Split(rs[i].Path, "/")
|
|
jPaths := strings.Split(rs[j].Path, "/")
|
|
if len(iPaths) > len(jPaths) {
|
|
return true
|
|
}
|
|
if len(iPaths) < len(jPaths) {
|
|
return false
|
|
}
|
|
for k := 0; k < len(iPaths); k++ {
|
|
if iPaths[k] != jPaths[k] {
|
|
return iPaths[k] < jPaths[k]
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (rs Routes) Len() int {
|
|
return len(rs)
|
|
}
|
|
|
|
func (rs Routes) Swap(i, j int) {
|
|
rs[i], rs[j] = rs[j], rs[i]
|
|
}
|
|
|
|
// 可以嵌套的Rest http server mux
|
|
type RestMux struct {
|
|
Path string
|
|
routes Routes
|
|
middlewares []Middleware
|
|
}
|
|
|
|
func (mux *RestMux) Use(m Middleware) {
|
|
mux.middlewares = append(mux.middlewares, m)
|
|
}
|
|
func (mux *RestMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
canContinue := false
|
|
c := r.Context()
|
|
data := map[string]interface{}{}
|
|
cn := context.WithValue(c, RequestCtxKey("data"), data)
|
|
newRequest := r.WithContext(cn)
|
|
if len(mux.middlewares) > 0 {
|
|
for _, m := range mux.middlewares {
|
|
canContinue = false
|
|
m(w, newRequest, func() { canContinue = true })
|
|
if !canContinue {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// _, has := lo.Find(mux.rmuxPaths, func(s string) bool {
|
|
// return strings.HasPrefix(newRequest.URL.Path, s)
|
|
// })
|
|
// if has {
|
|
// mux.imux.ServeHTTP(w, newRequest)
|
|
// return
|
|
// }
|
|
|
|
// 根据r 从routes中找到匹配的路由
|
|
for _, route := range mux.routes {
|
|
if route.Match(newRequest) {
|
|
route.ServeHTTP(w, newRequest)
|
|
return
|
|
}
|
|
}
|
|
// newRequest.URL.Path = "/" + strings.ToLower(newRequest.Method) + newRequest.URL.Path
|
|
// newRequest.RequestURI = "/" + strings.ToLower(newRequest.Method) + newRequest.RequestURI
|
|
// h, _ := mux.imux.Handler(newRequest)
|
|
|
|
// h.ServeHTTP(w, newRequest)
|
|
http.NotFound(w, r)
|
|
}
|
|
|
|
func (mux *RestMux) HandleFunc(method string, path string, f func(http.ResponseWriter, *http.Request)) {
|
|
r := &Route{
|
|
Method: method,
|
|
Path: path,
|
|
Handle: f,
|
|
Handler: nil,
|
|
}
|
|
*r.matcher = ParseUrl(path)
|
|
mux.routes = append(mux.routes, r)
|
|
sort.Sort(mux.routes)
|
|
}
|
|
|
|
func (mux *RestMux) Get(path string, f func(http.ResponseWriter, *http.Request)) {
|
|
mux.HandleFunc("GET", path, f)
|
|
}
|
|
|
|
func (mux *RestMux) Post(path string, f func(http.ResponseWriter, *http.Request)) {
|
|
mux.HandleFunc("POST", path, f)
|
|
}
|
|
|
|
func (mux *RestMux) Put(path string, f func(http.ResponseWriter, *http.Request)) {
|
|
mux.HandleFunc("PUT", path, f)
|
|
}
|
|
func (mux *RestMux) Delete(path string, f func(http.ResponseWriter, *http.Request)) {
|
|
mux.HandleFunc("DELETE", path, f)
|
|
}
|
|
func (mux *RestMux) Patch(path string, f func(http.ResponseWriter, *http.Request)) {
|
|
mux.HandleFunc("PATCH", path, f)
|
|
}
|
|
func (mux *RestMux) Head(path string, f func(http.ResponseWriter, *http.Request)) {
|
|
mux.HandleFunc("HEAD", path, f)
|
|
}
|
|
|
|
func (mux *RestMux) Option(path string, f func(http.ResponseWriter, *http.Request)) {
|
|
mux.HandleFunc("OPTION", path, f)
|
|
}
|
|
|
|
func (mux *RestMux) HandleMux(nmux *RestMux) {
|
|
p := nmux.Path
|
|
if !strings.HasSuffix(p, "/") {
|
|
p = p + "/"
|
|
}
|
|
// mux.imux.Handle(p, http.StripPrefix(nmux.Path, nmux))
|
|
// mux.rmuxPaths = append(mux.rmuxPaths, nmux.Path)
|
|
r := &Route{
|
|
Method: "",
|
|
Path: p,
|
|
Handle: nil,
|
|
Handler: nmux,
|
|
}
|
|
r.matcher = &UrlParamMatcher{
|
|
Params: []string{},
|
|
Reg: nil,
|
|
}
|
|
sort.Sort(mux.routes)
|
|
}
|
|
|
|
func NewRestMux(path string) *RestMux {
|
|
ret := &RestMux{
|
|
Path: path,
|
|
routes: Routes{},
|
|
middlewares: []Middleware{},
|
|
}
|
|
return ret
|
|
}
|