From 88998577933d7ae9efed9ef5b28ab7e30832cea4 Mon Sep 17 00:00:00 2001 From: Fenny <08jadez@gmail.com> Date: Mon, 30 Dec 2019 13:33:50 +0100 Subject: [PATCH] Update router.go --- router.go | 296 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 293 insertions(+), 3 deletions(-) diff --git a/router.go b/router.go index f6a1dfa2..e9512fb8 100644 --- a/router.go +++ b/router.go @@ -176,12 +176,10 @@ func (r *Fiber) register(method string, args ...interface{}) { // If its a simple wildcard ( aka match anything ) if path == "" || path == "*" || path == "/*" { r.routes = append(r.routes, &route{method, path, true, nil, nil, handler}) - fmt.Println(r.routes[0]) return } // Get params from path params := getParams(path) - fmt.Println(params) // If path has no params, we dont need regex if len(params) == 0 { r.routes = append(r.routes, &route{method, path, false, nil, nil, handler}) @@ -228,7 +226,299 @@ func (r *Fiber) handler(fctx *fasthttp.RequestCtx) { continue } // Skip route if regex does not match - fmt.Println("We did regex -,-") + if route.regex == nil || !route.regex.MatchString(path) { + continue + } + // If we have parameters, lets find the matches + if route.params != nil && len(route.params) > 0 { + matches := route.regex.FindAllStringSubmatch(path, -1) + // If we have matches, add params and values to context + if len(matches) > 0 && len(matches[0]) > 1 { + ctx.params = &route.params + ctx.values = matches[0][1:len(matches[0])] + } + } + // Execute handler with context + route.handler(ctx) + // if next is not set, leave loop and release ctx + if !ctx.next { + break + } + // set next to false for next iteration + ctx.next = false + } + // release context back into sync pool + releaseCtx(ctx) +} + +// Listen : +func (r *Fiber) Listen(port int) { + // Disable server header if server name is not given + if r.Settings.Name != "" { + r.Settings.NoDefaultServerHeader = false + } + server := &fasthttp.Server{ + // Express custom handler + Handler: r.handler, + // Server settings + Name: r.Settings.Name, + Concurrency: r.Settings.Concurrency, + DisableKeepalive: r.Settings.DisableKeepAlive, + ReadBufferSize: r.Settings.ReadBufferSize, + WriteBufferSize: r.Settings.WriteBufferSize, + WriteTimeout: r.Settings.WriteTimeout, + IdleTimeout: r.Settings.IdleTimeout, + MaxConnsPerIP: r.Settings.MaxConnsPerIP, + MaxRequestsPerConn: r.Settings.MaxRequestsPerConn, + TCPKeepalive: r.Settings.TCPKeepalive, + TCPKeepalivePeriod: r.Settings.TCPKeepalivePeriod, + MaxRequestBodySize: r.Settings.MaxRequestBodySize, + ReduceMemoryUsage: r.Settings.ReduceMemoryUsage, + GetOnly: r.Settings.GetOnly, + DisableHeaderNamesNormalizing: r.Settings.DisableHeaderNamesNormalizing, + SleepWhenConcurrencyLimitsExceeded: r.Settings.SleepWhenConcurrencyLimitsExceeded, + NoDefaultServerHeader: r.Settings.NoDefaultServerHeader, + NoDefaultContentType: r.Settings.NoDefaultContentType, + KeepHijackedConns: r.Settings.KeepHijackedConns, + } + if r.Settings.TLSEnable { + if err := server.ListenAndServeTLS(fmt.Sprintf(":%v", port), r.Settings.CertFile, r.Settings.CertKey); err != nil { + panic(err) + } + return + } + if err := server.ListenAndServe(fmt.Sprintf(":%v", port)); err != nil { + panic(err) + } +} +package fiber + +import ( + "fmt" + "regexp" + "time" + + "github.com/valyala/fasthttp" +) + +type route struct { + method string + path string + anyPath bool + regex *regexp.Regexp + params []string + handler func(*Context) +} + +// Settings : +type Settings struct { + TLSEnable bool + CertKey string + CertFile string + Name string + Concurrency int + DisableKeepAlive bool + ReadBufferSize int + WriteBufferSize int + WriteTimeout time.Duration + IdleTimeout time.Duration + MaxConnsPerIP int + MaxRequestsPerConn int + TCPKeepalive bool + TCPKeepalivePeriod time.Duration + MaxRequestBodySize int + ReduceMemoryUsage bool + GetOnly bool + DisableHeaderNamesNormalizing bool + SleepWhenConcurrencyLimitsExceeded time.Duration + NoDefaultServerHeader bool + NoDefaultContentType bool + KeepHijackedConns bool +} + +// Fiber : +type Fiber struct { + routes []*route + methods []string + Settings *Settings +} + +// New : +func New() *Fiber { + return &Fiber{ + methods: []string{"GET", "PUT", "POST", "DELETE", "HEAD", "PATCH", "OPTIONS", "TRACE", "CONNECT"}, + Settings: &Settings{ + TLSEnable: false, + CertKey: "", + CertFile: "", + Name: "", + Concurrency: 256 * 1024, + DisableKeepAlive: false, + ReadBufferSize: 4096, + WriteBufferSize: 4096, + WriteTimeout: 0, + IdleTimeout: 0, + MaxConnsPerIP: 0, + MaxRequestsPerConn: 0, + TCPKeepalive: false, + TCPKeepalivePeriod: 0, + MaxRequestBodySize: 4 * 1024 * 1024, + ReduceMemoryUsage: false, + GetOnly: false, + DisableHeaderNamesNormalizing: false, + SleepWhenConcurrencyLimitsExceeded: 0, + NoDefaultServerHeader: true, + NoDefaultContentType: false, + KeepHijackedConns: false, + }, + } +} + +// Get : +func (r *Fiber) Get(args ...interface{}) { + r.register("GET", args...) +} + +// Put : +func (r *Fiber) Put(args ...interface{}) { + r.register("PUT", args...) +} + +// Post : +func (r *Fiber) Post(args ...interface{}) { + r.register("POST", args...) +} + +// Delete : +func (r *Fiber) Delete(args ...interface{}) { + r.register("DELETE", args...) +} + +// Head : +func (r *Fiber) Head(args ...interface{}) { + r.register("HEAD", args...) +} + +// Patch : +func (r *Fiber) Patch(args ...interface{}) { + r.register("PATCH", args...) +} + +// Options : +func (r *Fiber) Options(args ...interface{}) { + r.register("OPTIONS", args...) +} + +// Trace : +func (r *Fiber) Trace(args ...interface{}) { + r.register("TRACE", args...) +} + +// Connect : +func (r *Fiber) Connect(args ...interface{}) { + r.register("CONNECT", args...) +} + +// All : +func (r *Fiber) All(args ...interface{}) { + r.register("*", args...) + // for _, method := range r.methods { + // r.register(method, args...) + // } +} + +// Use : +func (r *Fiber) Use(args ...interface{}) { + r.register("*", args...) + // for _, method := range r.methods { + // r.register(method, args...) + // } +} + +// register : +func (r *Fiber) register(method string, args ...interface{}) { + // Pre-set variables for interface assertion + var ok bool + var path string + var handler func(*Context) + // Register only handler: app.Get(handler) + if len(args) == 1 { + // Convert interface to func(*Context) + handler, ok = args[0].(func(*Context)) + if !ok { + panic("Invalid handler must be func(*express.Context)") + } + } + // Register path and handler: app.Get(path, handler) + if len(args) == 2 { + // Convert interface to path string + path, ok = args[0].(string) + if !ok { + panic("Invalid path") + } + // Panic if first char does not begins with / or * + if path[0] != '/' && path[0] != '*' { + panic("Invalid path, must begin with slash '/' or wildcard '*'") + } + // Convert interface to func(*Context) + handler, ok = args[1].(func(*Context)) + if !ok { + panic("Invalid handler, must be func(*express.Context)") + } + } + // If its a simple wildcard ( aka match anything ) + if path == "" || path == "*" || path == "/*" { + r.routes = append(r.routes, &route{method, path, true, nil, nil, handler}) + return + } + // Get params from path + params := getParams(path) + // If path has no params, we dont need regex + if len(params) == 0 { + r.routes = append(r.routes, &route{method, path, false, nil, nil, handler}) + return + } + + // Compile regix from path + regex, err := getRegex(path) + if err != nil { + panic("Invalid url pattern: " + path) + } + r.routes = append(r.routes, &route{method, path, false, regex, params, handler}) +} + +// handler : +func (r *Fiber) handler(fctx *fasthttp.RequestCtx) { + // get custom context from sync pool + ctx := acquireCtx(fctx) + // get path and method from main context + path := ctx.Path() + method := ctx.Method() + // loop trough routes + for _, route := range r.routes { + // Skip route if method is not allowed + if route.method != "*" && route.method != method { + continue + } + // First check if we match a static path or wildcard + if route.anyPath || (route.path == path && route.params == nil) { + // If * always set the path to the wildcard parameter + if route.anyPath { + ctx.params = &[]string{"*"} + ctx.values = []string{path} + } + // Execute handler with context + route.handler(ctx) + // if next is not set, leave loop and release ctx + if !ctx.next { + break + } + // set next to false for next iteration + ctx.next = false + // continue to go to the next route + continue + } + // Skip route if regex does not match if route.regex == nil || !route.regex.MatchString(path) { continue }