263 lines
6.3 KiB
Go
263 lines
6.3 KiB
Go
package server
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"net/http"
|
||
"sort"
|
||
"strings"
|
||
|
||
handler "git.pyer.club/kingecg/gohttpd/hander"
|
||
"git.pyer.club/kingecg/gohttpd/model"
|
||
"git.pyer.club/kingecg/gologger"
|
||
logger "git.pyer.club/kingecg/gologger"
|
||
)
|
||
|
||
type RequestCtxKey string
|
||
|
||
type Route struct {
|
||
Method string
|
||
Path string
|
||
Handler http.Handler
|
||
matcher *UrlParamMatcher
|
||
middles *MiddlewareLink
|
||
}
|
||
|
||
func (route *Route) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||
if route.middles.Len() > 0 && !route.middles.ServeHTTP(w, r) {
|
||
return
|
||
}
|
||
route.Handler.ServeHTTP(w, r)
|
||
}
|
||
|
||
func (route *Route) Match(r *http.Request) bool {
|
||
l := gologger.GetLogger("Route")
|
||
l.Debug(fmt.Sprintf("match route: %s %s", r.Method, r.URL.Path))
|
||
if route.Method != "" && route.Method != r.Method {
|
||
l.Debug("method not match")
|
||
return false
|
||
}
|
||
|
||
if route.matcher != nil && route.matcher.Reg != 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
|
||
}
|
||
l.Debug("Not match matcher reg")
|
||
return false
|
||
}
|
||
if route.Path == "" {
|
||
return true
|
||
}
|
||
return strings.HasPrefix(r.URL.Path, route.Path)
|
||
}
|
||
|
||
func (route *Route) Add(m Middleware) {
|
||
route.middles.Add(m)
|
||
}
|
||
|
||
// NewRoute 返回一个新的Route实例
|
||
// 参数:
|
||
// - method: 请求方法
|
||
// - path: 请求路径
|
||
// - handleFn: http.Handler处理函数
|
||
// 返回值:
|
||
// - *Route: 一个指向Route的指针
|
||
func NewRoute(method string, path string, handleFn http.Handler) *Route {
|
||
ret := &Route{
|
||
Method: method,
|
||
Path: path,
|
||
middles: NewMiddlewareLink(),
|
||
}
|
||
p := ParseUrl(path)
|
||
// 使用handleFn构建handler
|
||
ret.Handler = handleFn
|
||
ret.matcher = &p
|
||
return ret
|
||
}
|
||
|
||
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 *MiddlewareLink
|
||
}
|
||
|
||
func (mux *RestMux) Use(m Middleware) {
|
||
mux.middlewares.Add(m)
|
||
}
|
||
func (mux *RestMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||
|
||
c := r.Context()
|
||
data := map[string]interface{}{}
|
||
cn := context.WithValue(c, RequestCtxKey("data"), data)
|
||
newRequest := r.WithContext(cn)
|
||
if mux.middlewares.Len() > 0 && !mux.middlewares.ServeHTTP(w, newRequest) {
|
||
return
|
||
}
|
||
|
||
// 根据r 从routes中找到匹配的路由
|
||
for _, route := range mux.routes {
|
||
if route.Match(newRequest) {
|
||
route.ServeHTTP(w, newRequest)
|
||
return
|
||
}
|
||
}
|
||
|
||
http.NotFound(w, r)
|
||
}
|
||
|
||
func (mux *RestMux) HandleFunc(method string, path string, f func(http.ResponseWriter, *http.Request)) *Route {
|
||
r := NewRoute(method, path, http.HandlerFunc(f))
|
||
mux.routes = append(mux.routes, r)
|
||
sort.Sort(mux.routes)
|
||
return r
|
||
}
|
||
|
||
func (mux *RestMux) Get(path string, f func(http.ResponseWriter, *http.Request)) *Route {
|
||
return mux.HandleFunc("GET", path, f)
|
||
}
|
||
|
||
func (mux *RestMux) Post(path string, f func(http.ResponseWriter, *http.Request)) *Route {
|
||
return mux.HandleFunc("POST", path, f)
|
||
}
|
||
|
||
func (mux *RestMux) Put(path string, f func(http.ResponseWriter, *http.Request)) *Route {
|
||
return mux.HandleFunc("PUT", path, f)
|
||
}
|
||
func (mux *RestMux) Delete(path string, f func(http.ResponseWriter, *http.Request)) *Route {
|
||
return mux.HandleFunc("DELETE", path, f)
|
||
}
|
||
func (mux *RestMux) Patch(path string, f func(http.ResponseWriter, *http.Request)) *Route {
|
||
return mux.HandleFunc("PATCH", path, f)
|
||
}
|
||
func (mux *RestMux) Head(path string, f func(http.ResponseWriter, *http.Request)) *Route {
|
||
return mux.HandleFunc("HEAD", path, f)
|
||
}
|
||
|
||
func (mux *RestMux) Option(path string, f func(http.ResponseWriter, *http.Request)) *Route {
|
||
return mux.HandleFunc("OPTION", path, f)
|
||
}
|
||
|
||
func (mux *RestMux) HandleMux(nmux *RestMux) *Route {
|
||
p := nmux.Path
|
||
if !strings.HasSuffix(p, "/") {
|
||
p = p + "/"
|
||
}
|
||
r := NewRoute("", p, nmux)
|
||
mux.routes = append(mux.routes, r)
|
||
sort.Sort(mux.routes)
|
||
return r
|
||
}
|
||
|
||
func NewRestMux(path string) *RestMux {
|
||
ret := &RestMux{
|
||
Path: path,
|
||
routes: Routes{},
|
||
middlewares: NewMiddlewareLink(),
|
||
}
|
||
return ret
|
||
}
|
||
|
||
type ServerMux struct {
|
||
http.Handler
|
||
directiveHandlers *MiddlewareLink
|
||
handlers map[string]http.Handler
|
||
paths []string
|
||
}
|
||
|
||
func (s *ServerMux) Handle(pattern string, handler http.Handler) {
|
||
if s.handlers == nil {
|
||
s.handlers = make(map[string]http.Handler)
|
||
}
|
||
s.handlers[pattern] = handler
|
||
s.paths = append(s.paths, pattern)
|
||
// 自定义比较函数排序s.paths
|
||
sort.Slice(s.paths, func(i, j int) bool {
|
||
return len(s.paths[i]) > len(s.paths[j]) || s.paths[i] > s.paths[j]
|
||
})
|
||
}
|
||
|
||
func (s *ServerMux) AddDirective(directiveStr string) {
|
||
//TODO: 根据字符串内容生成一个中间件链,等directive实现再来补充逻辑
|
||
strs := strings.Split(directiveStr, " ")
|
||
directiveName := strs[0]
|
||
params := strs[1:]
|
||
directive, ok := DirectiveMap[directiveName]
|
||
if ok {
|
||
s.directiveHandlers.Add(directive(params...))
|
||
}
|
||
}
|
||
|
||
func (s *ServerMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||
for _, p := range s.paths {
|
||
if strings.HasPrefix(r.URL.Path, p) {
|
||
s.directiveHandlers.ServeHTTP(w, r)
|
||
s.handlers[p].ServeHTTP(w, r)
|
||
return
|
||
}
|
||
}
|
||
http.NotFound(w, r)
|
||
}
|
||
|
||
func NewServeMux(c *model.HttpServerConfig) *ServerMux {
|
||
l := logger.GetLogger("ServerMux")
|
||
l.Debug("NewServeMux")
|
||
s := &ServerMux{
|
||
directiveHandlers: NewMiddlewareLink(),
|
||
handlers: make(map[string]http.Handler),
|
||
paths: []string{},
|
||
}
|
||
|
||
for _, directive := range c.Directives {
|
||
s.AddDirective(string(directive))
|
||
}
|
||
for _, httpPath := range c.Paths {
|
||
if httpPath.Root != "" {
|
||
fileHandler := handler.NewFileHandler(handler.FileHandler{
|
||
Root: httpPath.Root,
|
||
Default: httpPath.Default,
|
||
})
|
||
s.Handle(httpPath.Path, fileHandler)
|
||
} else if len(httpPath.Upstreams) != 0 {
|
||
proxyHandler := handler.NewProxyHandler(&httpPath)
|
||
s.Handle(httpPath.Path, proxyHandler)
|
||
} else {
|
||
l.Error("Not supportted server path type :", httpPath.Path)
|
||
}
|
||
}
|
||
return s
|
||
}
|