-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
137 additions
and
126 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,51 @@ | ||
package sweetygo | ||
|
||
import ( | ||
"net/http" | ||
"net/url" | ||
) | ||
|
||
// Context provide a HTTP context for SweetyGo. | ||
type Context struct { | ||
sg *SweetyGo | ||
Req *http.Request | ||
Resp *responseWriter | ||
handlers []HandlerFunc | ||
} | ||
|
||
// NewContext . | ||
func NewContext(s *SweetyGo) *Context { | ||
c := &Context{} | ||
c.sg = s | ||
c.handlers = make([]HandlerFunc, len(s.middlewares)+1) | ||
copy(c.handlers, s.middlewares) | ||
return c | ||
} | ||
|
||
// Init the context gotten from sync pool. | ||
func (c *Context) Init(w http.ResponseWriter, r *http.Request) { | ||
c.Resp = &responseWriter{w, 0} | ||
c.Req = r | ||
c.handlers = c.handlers[:len(c.sg.middlewares)] | ||
} | ||
|
||
// Next execute next middleware or router. | ||
func (c *Context) Next() { | ||
n := len(c.handlers) | ||
switch { | ||
case n > 1: | ||
c.handlers[0](c) | ||
c.handlers = c.handlers[1:] | ||
c.Next() | ||
case n == 1: | ||
c.handlers[0](c) | ||
default: | ||
return | ||
} | ||
} | ||
|
||
// Params returns route params | ||
func (c *Context) Params() url.Values { | ||
c.Req.ParseForm() | ||
return c.Req.Form | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,119 +1,69 @@ | ||
package sweetygo | ||
|
||
import ( | ||
"fmt" | ||
"net/http" | ||
"strings" | ||
) | ||
|
||
// Router is based on Radix Tree | ||
// rootHandler is for runMiddleware | ||
type Router struct { | ||
tree *Trie | ||
rootHandler HandlerFunc | ||
middlewares []HandlerFunc | ||
// NotFoundHandler . | ||
func NotFoundHandler(c *Context) { | ||
http.NotFound(c.Resp, c.Req) | ||
} | ||
|
||
// New Router | ||
func New(root HandlerFunc) *Router { | ||
tree := Trie{ | ||
component: "/", | ||
methods: make(map[string]HandlerFunc), | ||
} | ||
return &Router{tree: &tree, | ||
middlewares: make([]HandlerFunc, 0), | ||
rootHandler: root} | ||
} | ||
|
||
// USE middlewares for router | ||
func (r *Router) USE(middleware ...HandlerFunc) { | ||
r.middlewares = append(r.middlewares, middleware...) | ||
} | ||
|
||
func runMiddleware(w http.ResponseWriter, req *http.Request, middleware Middleware) { | ||
middleware.ServeHTTP(w, req) | ||
} | ||
|
||
// build a middleware list | ||
func mwareList(middleware []HandlerFunc, handler HandlerFunc) Middleware { | ||
var next Middleware | ||
|
||
if len(middleware) == 0 { | ||
return finalHandler(handler) | ||
} else if len(middleware) > 1 { | ||
next = mwareList(middleware[1:], handler) | ||
} else { | ||
next = finalHandler(handler) | ||
} | ||
|
||
return Middleware{middleware[0], &next} | ||
} | ||
func (s *SweetyGo) ServeHTTP(w http.ResponseWriter, r *http.Request) { | ||
c := s.pool.Get().(*Context) | ||
c.Init(w, r) | ||
|
||
func finalHandler(handler HandlerFunc) Middleware { | ||
return Middleware{ | ||
HandlerFunc(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { | ||
handler(w, r, next) | ||
}), | ||
&Middleware{}} | ||
} | ||
|
||
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { | ||
req.ParseForm() | ||
params := req.Form | ||
|
||
node := r.tree.Search(strings.Split(req.URL.Path, "/")[1:], params) | ||
if node != nil && node.methods[req.Method] != nil { | ||
runMiddleware(w, req, mwareList(r.middlewares, node.methods[req.Method])) | ||
node := s.tree.Search(strings.Split(r.URL.Path, "/")[1:], c.Params()) | ||
if node != nil && node.methods[r.Method] != nil { | ||
c.handlers = append(c.handlers, node.methods[r.Method]) | ||
} else { | ||
runMiddleware(w, req, mwareList(r.middlewares, r.rootHandler)) | ||
c.handlers = append(c.handlers, s.notFoundHandler) | ||
} | ||
} | ||
|
||
// RunServer at the given addr | ||
func (r *Router) RunServer(addr string) { | ||
fmt.Printf("*SweetyGo* -- Listen on %s\n", addr) | ||
http.ListenAndServe(addr, r) | ||
c.Next() | ||
s.pool.Put(c) | ||
} | ||
|
||
// Handle register custom METHOD request HandlerFunc | ||
func (r *Router) Handle(method, path string, handler HandlerFunc) { | ||
func (s *SweetyGo) Handle(method, path string, handler HandlerFunc) { | ||
if len(path) < 1 || path[0] != '/' { | ||
panic("Path should be like '/sweety/go'") | ||
} | ||
r.tree.Insert(method, path, handler) | ||
s.tree.Insert(method, path, handler) | ||
} | ||
|
||
// GET register GET request handler | ||
func (r *Router) GET(path string, handler HandlerFunc) { | ||
r.Handle("GET", path, handler) | ||
func (s *SweetyGo) GET(path string, handler HandlerFunc) { | ||
s.Handle("GET", path, handler) | ||
} | ||
|
||
// HEAD register HEAD request handler | ||
func (r *Router) HEAD(path string, handler HandlerFunc) { | ||
r.Handle("HEAD", path, handler) | ||
func (s *SweetyGo) HEAD(path string, handler HandlerFunc) { | ||
s.Handle("HEAD", path, handler) | ||
} | ||
|
||
// OPTIONS register OPTIONS request handler | ||
func (r *Router) OPTIONS(path string, handler HandlerFunc) { | ||
r.Handle("OPTIONS", path, handler) | ||
func (s *SweetyGo) OPTIONS(path string, handler HandlerFunc) { | ||
s.Handle("OPTIONS", path, handler) | ||
} | ||
|
||
// POST register POST request handler | ||
func (r *Router) POST(path string, handler HandlerFunc) { | ||
r.Handle("POST", path, handler) | ||
func (s *SweetyGo) POST(path string, handler HandlerFunc) { | ||
s.Handle("POST", path, handler) | ||
} | ||
|
||
// PUT register PUT request handler | ||
func (r *Router) PUT(path string, handler HandlerFunc) { | ||
r.Handle("PUT", path, handler) | ||
func (s *SweetyGo) PUT(path string, handler HandlerFunc) { | ||
s.Handle("PUT", path, handler) | ||
} | ||
|
||
// PATCH register PATCH request HandlerFunc | ||
func (r *Router) PATCH(path string, handler HandlerFunc) { | ||
r.Handle("PATCH", path, handler) | ||
func (s *SweetyGo) PATCH(path string, handler HandlerFunc) { | ||
s.Handle("PATCH", path, handler) | ||
} | ||
|
||
// DELETE register DELETE request handler | ||
func (r *Router) DELETE(path string, handler HandlerFunc) { | ||
r.Handle("DELETE", path, handler) | ||
func (s *SweetyGo) DELETE(path string, handler HandlerFunc) { | ||
s.Handle("DELETE", path, handler) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,50 @@ | ||
package sweetygo | ||
|
||
import "net/http" | ||
import ( | ||
"fmt" | ||
"net/http" | ||
"sync" | ||
) | ||
|
||
type Handler interface { | ||
ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) | ||
} | ||
// HandlerFunc context handler func | ||
type HandlerFunc func(*Context) | ||
|
||
// Middleware handler | ||
type Middleware interface{} | ||
|
||
type HandlerFunc func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) | ||
// SweetyGo is Suuuuuuuuper Sweetie! | ||
type SweetyGo struct { | ||
tree *Trie | ||
pool sync.Pool | ||
notFoundHandler HandlerFunc | ||
middlewares []HandlerFunc | ||
} | ||
|
||
type Middleware struct { | ||
handler Handler | ||
next *Middleware | ||
// New SweetyGo App | ||
func New() *SweetyGo { | ||
tree := &Trie{ | ||
component: "/", | ||
methods: make(map[string]HandlerFunc), | ||
} | ||
s := &SweetyGo{tree: tree, | ||
notFoundHandler: NotFoundHandler, | ||
middlewares: make([]HandlerFunc, 0), | ||
} | ||
s.pool = sync.Pool{ | ||
New: func() interface{} { | ||
return NewContext(s) | ||
}, | ||
} | ||
return s | ||
} | ||
|
||
func (h HandlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { | ||
h(w, r, next) | ||
// USE middlewares for SweetyGo | ||
func (s *SweetyGo) USE(middleware ...HandlerFunc) { | ||
s.middlewares = append(s.middlewares, middleware...) | ||
} | ||
|
||
func (m Middleware) ServeHTTP(w http.ResponseWriter, r *http.Request) { | ||
m.handler.ServeHTTP(w, r, m.next.ServeHTTP) | ||
// RunServer at the given addr | ||
func (s *SweetyGo) RunServer(addr string) { | ||
fmt.Printf("*SweetyGo* -- Listen on %s\n", addr) | ||
http.ListenAndServe(addr, s) | ||
} |