diff --git a/beego.go b/beego.go index 3286cf40..f8f89ac7 100644 --- a/beego.go +++ b/beego.go @@ -207,6 +207,11 @@ func Router(path string, c ControllerInterface) *App { return BeeApp } +func RouterHandler(path string, c http.Handler) *App { + BeeApp.Handlers.AddHandler(path, c) + return BeeApp +} + func Filter(filter http.HandlerFunc) *App { BeeApp.Filter(filter) return BeeApp diff --git a/example/chat/chat.go b/example/chat/chat.go new file mode 100644 index 00000000..09005753 --- /dev/null +++ b/example/chat/chat.go @@ -0,0 +1,42 @@ +package main + +import ( + "fmt" + "github.com/astaxie/beego" + "github.com/fzzy/sockjs-go/sockjs" + "strings" +) + +var users *sockjs.SessionPool = sockjs.NewSessionPool() + +func chatHandler(s sockjs.Session) { + users.Add(s) + defer users.Remove(s) + + for { + m := s.Receive() + if m == nil { + break + } + fullAddr := s.Info().RemoteAddr + addr := fullAddr[:strings.LastIndex(fullAddr, ":")] + m = []byte(fmt.Sprintf("%s: %s", addr, m)) + users.Broadcast(m) + } +} + +type MainController struct { + beego.Controller +} + +func (m *MainController) Get() { + m.TplNames = "index.html" +} + +func main() { + conf := sockjs.NewConfig() + sockjshandler := sockjs.NewHandler("/chat", chatHandler, conf) + beego.Router("/", &MainController{}) + beego.RouterHandler("/chat/:info(.*)", sockjshandler) + beego.Run() +} diff --git a/example/chat/views/index.html b/example/chat/views/index.html new file mode 100644 index 00000000..12e5616b --- /dev/null +++ b/example/chat/views/index.html @@ -0,0 +1,81 @@ + + + + + + + Sockjs-go chat + + +

Sockjs-go chat

+ +
+ Status: disconnected +
+
+
+
+ + + +
+ + \ No newline at end of file diff --git a/router.go b/router.go index 3a1dd2a8..4e7b6c17 100644 --- a/router.go +++ b/router.go @@ -16,14 +16,22 @@ type controllerInfo struct { controllerType reflect.Type } +type userHandler struct { + pattern string + regex *regexp.Regexp + params map[int]string + h http.Handler +} + type ControllerRegistor struct { - routers []*controllerInfo - fixrouters []*controllerInfo - filters []http.HandlerFunc + routers []*controllerInfo + fixrouters []*controllerInfo + filters []http.HandlerFunc + userHandlers map[string]*userHandler } func NewControllerRegistor() *ControllerRegistor { - return &ControllerRegistor{routers: make([]*controllerInfo, 0)} + return &ControllerRegistor{routers: make([]*controllerInfo, 0), userHandlers: make(map[string]*userHandler)} } func (p *ControllerRegistor) Add(pattern string, c ControllerInterface) { @@ -77,6 +85,52 @@ func (p *ControllerRegistor) Add(pattern string, c ControllerInterface) { } +func (p *ControllerRegistor) AddHandler(pattern string, c http.Handler) { + parts := strings.Split(pattern, "/") + + j := 0 + params := make(map[int]string) + for i, part := range parts { + if strings.HasPrefix(part, ":") { + expr := "([^/]+)" + //a user may choose to override the defult expression + // similar to expressjs: ‘/user/:id([0-9]+)’ + if index := strings.Index(part, "("); index != -1 { + expr = part[index:] + part = part[:index] + } + params[j] = part + parts[i] = expr + j++ + } + } + if j == 0 { + //now create the Route + uh := &userHandler{} + uh.pattern = pattern + uh.h = c + p.userHandlers[pattern] = uh + } else { // add regexp routers + //recreate the url pattern, with parameters replaced + //by regular expressions. then compile the regex + pattern = strings.Join(parts, "/") + regex, regexErr := regexp.Compile(pattern) + if regexErr != nil { + //TODO add error handling here to avoid panic + panic(regexErr) + return + } + + //now create the Route + uh := &userHandler{} + uh.regex = regex + uh.params = params + uh.pattern = pattern + uh.h = c + p.userHandlers[pattern] = uh + } +} + // Filter adds the middleware filter. func (p *ControllerRegistor) Filter(filter http.HandlerFunc) { p.filters = append(p.filters, filter) @@ -143,6 +197,43 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) requestPath := r.URL.Path + //user defined Handler + for pattern, c := range p.userHandlers { + if c.regex == nil && pattern == requestPath { + c.h.ServeHTTP(rw, r) + return + } else if c.regex == nil { + continue + } + + //check if Route pattern matches url + if !c.regex.MatchString(requestPath) { + continue + } + + //get submatches (params) + matches := c.regex.FindStringSubmatch(requestPath) + + //double check that the Route matches the URL pattern. + if len(matches[0]) != len(requestPath) { + continue + } + + if len(c.params) > 0 { + //add url parameters to the query param map + values := r.URL.Query() + for i, match := range matches[1:] { + values.Add(c.params[i], match) + params[c.params[i]] = match + } + //reassemble query params and add to RawQuery + r.URL.RawQuery = url.Values(values).Encode() + "&" + r.URL.RawQuery + //r.URL.RawQuery = url.Values(values).Encode() + } + c.h.ServeHTTP(rw, r) + return + } + //first find path from the fixrouters to Improve Performance for _, route := range p.fixrouters { n := len(requestPath)