support websocket #20
add example chat
Showing
4 changed files
with
220 additions
and
1 deletions
| ... | @@ -207,6 +207,11 @@ func Router(path string, c ControllerInterface) *App { | ... | @@ -207,6 +207,11 @@ func Router(path string, c ControllerInterface) *App { |
| 207 | return BeeApp | 207 | return BeeApp |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | func RouterHandler(path string, c http.Handler) *App { | ||
| 211 | BeeApp.Handlers.AddHandler(path, c) | ||
| 212 | return BeeApp | ||
| 213 | } | ||
| 214 | |||
| 210 | func Filter(filter http.HandlerFunc) *App { | 215 | func Filter(filter http.HandlerFunc) *App { |
| 211 | BeeApp.Filter(filter) | 216 | BeeApp.Filter(filter) |
| 212 | return BeeApp | 217 | return BeeApp | ... | ... |
example/chat/chat.go
0 → 100644
| 1 | package main | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "fmt" | ||
| 5 | "github.com/astaxie/beego" | ||
| 6 | "github.com/fzzy/sockjs-go/sockjs" | ||
| 7 | "strings" | ||
| 8 | ) | ||
| 9 | |||
| 10 | var users *sockjs.SessionPool = sockjs.NewSessionPool() | ||
| 11 | |||
| 12 | func chatHandler(s sockjs.Session) { | ||
| 13 | users.Add(s) | ||
| 14 | defer users.Remove(s) | ||
| 15 | |||
| 16 | for { | ||
| 17 | m := s.Receive() | ||
| 18 | if m == nil { | ||
| 19 | break | ||
| 20 | } | ||
| 21 | fullAddr := s.Info().RemoteAddr | ||
| 22 | addr := fullAddr[:strings.LastIndex(fullAddr, ":")] | ||
| 23 | m = []byte(fmt.Sprintf("%s: %s", addr, m)) | ||
| 24 | users.Broadcast(m) | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | type MainController struct { | ||
| 29 | beego.Controller | ||
| 30 | } | ||
| 31 | |||
| 32 | func (m *MainController) Get() { | ||
| 33 | m.TplNames = "index.html" | ||
| 34 | } | ||
| 35 | |||
| 36 | func main() { | ||
| 37 | conf := sockjs.NewConfig() | ||
| 38 | sockjshandler := sockjs.NewHandler("/chat", chatHandler, conf) | ||
| 39 | beego.Router("/", &MainController{}) | ||
| 40 | beego.RouterHandler("/chat/:info(.*)", sockjshandler) | ||
| 41 | beego.Run() | ||
| 42 | } |
example/chat/views/index.html
0 → 100644
| 1 | <!DOCTYPE html> | ||
| 2 | <html> | ||
| 3 | <head> | ||
| 4 | <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> | ||
| 5 | <script src="http://cdn.sockjs.org/sockjs-0.3.4.min.js"></script> | ||
| 6 | <script> | ||
| 7 | $(function() { | ||
| 8 | var conn = null; | ||
| 9 | |||
| 10 | function log(msg) { | ||
| 11 | var control = $('#log'); | ||
| 12 | control.html(control.html() + msg + '<br/>'); | ||
| 13 | control.scrollTop(control.scrollTop() + 1000); | ||
| 14 | } | ||
| 15 | |||
| 16 | function disconnect() { | ||
| 17 | if (conn != null) { | ||
| 18 | log('Disconnecting...'); | ||
| 19 | |||
| 20 | conn.close(); | ||
| 21 | conn = null; | ||
| 22 | |||
| 23 | updateUi(); | ||
| 24 | } | ||
| 25 | } | ||
| 26 | |||
| 27 | function updateUi() { | ||
| 28 | if (conn == null || conn.readyState != SockJS.OPEN) { | ||
| 29 | $('#status').text('disconnected'); | ||
| 30 | $('#connect').text('Connect'); | ||
| 31 | } else { | ||
| 32 | $('#status').text('connected (' + conn.protocol + ')'); | ||
| 33 | $('#connect').text('Disconnect'); | ||
| 34 | } | ||
| 35 | } | ||
| 36 | |||
| 37 | $('form').submit(function() { | ||
| 38 | var text = $('#message').val(); | ||
| 39 | conn.send(text); | ||
| 40 | $('#message').val('').focus(); | ||
| 41 | return false; | ||
| 42 | }); | ||
| 43 | |||
| 44 | conn = new SockJS('http://' + window.location.host + '/chat'); | ||
| 45 | log('Connecting...'); | ||
| 46 | |||
| 47 | conn.onopen = function() { | ||
| 48 | log('Connected.'); | ||
| 49 | updateUi(); | ||
| 50 | }; | ||
| 51 | |||
| 52 | conn.onmessage = function(e) { | ||
| 53 | log(e.data); | ||
| 54 | }; | ||
| 55 | |||
| 56 | conn.onclose = function() { | ||
| 57 | log('Disconnected.'); | ||
| 58 | conn = null; | ||
| 59 | updateUi(); | ||
| 60 | }; | ||
| 61 | |||
| 62 | $('#message').val('').focus(); | ||
| 63 | }); | ||
| 64 | </script> | ||
| 65 | <title>Sockjs-go chat</title> | ||
| 66 | </head> | ||
| 67 | <body> | ||
| 68 | <h1>Sockjs-go chat</h1> | ||
| 69 | |||
| 70 | <div> | ||
| 71 | Status: <span id="status">disconnected</span> | ||
| 72 | </div> | ||
| 73 | <div id="log" style="width: 60em; height: 20em; overflow:auto; border: 1px solid black"> | ||
| 74 | </div> | ||
| 75 | <form id="chatform"> | ||
| 76 | <label for="message">Message:</label> | ||
| 77 | <input id="message" type="text" /> | ||
| 78 | <input type="submit" value="Send" /> | ||
| 79 | </form> | ||
| 80 | </body> | ||
| 81 | </html> | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| ... | @@ -16,14 +16,22 @@ type controllerInfo struct { | ... | @@ -16,14 +16,22 @@ type controllerInfo struct { |
| 16 | controllerType reflect.Type | 16 | controllerType reflect.Type |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | type userHandler struct { | ||
| 20 | pattern string | ||
| 21 | regex *regexp.Regexp | ||
| 22 | params map[int]string | ||
| 23 | h http.Handler | ||
| 24 | } | ||
| 25 | |||
| 19 | type ControllerRegistor struct { | 26 | type ControllerRegistor struct { |
| 20 | routers []*controllerInfo | 27 | routers []*controllerInfo |
| 21 | fixrouters []*controllerInfo | 28 | fixrouters []*controllerInfo |
| 22 | filters []http.HandlerFunc | 29 | filters []http.HandlerFunc |
| 30 | userHandlers map[string]*userHandler | ||
| 23 | } | 31 | } |
| 24 | 32 | ||
| 25 | func NewControllerRegistor() *ControllerRegistor { | 33 | func NewControllerRegistor() *ControllerRegistor { |
| 26 | return &ControllerRegistor{routers: make([]*controllerInfo, 0)} | 34 | return &ControllerRegistor{routers: make([]*controllerInfo, 0), userHandlers: make(map[string]*userHandler)} |
| 27 | } | 35 | } |
| 28 | 36 | ||
| 29 | func (p *ControllerRegistor) Add(pattern string, c ControllerInterface) { | 37 | func (p *ControllerRegistor) Add(pattern string, c ControllerInterface) { |
| ... | @@ -77,6 +85,52 @@ func (p *ControllerRegistor) Add(pattern string, c ControllerInterface) { | ... | @@ -77,6 +85,52 @@ func (p *ControllerRegistor) Add(pattern string, c ControllerInterface) { |
| 77 | 85 | ||
| 78 | } | 86 | } |
| 79 | 87 | ||
| 88 | func (p *ControllerRegistor) AddHandler(pattern string, c http.Handler) { | ||
| 89 | parts := strings.Split(pattern, "/") | ||
| 90 | |||
| 91 | j := 0 | ||
| 92 | params := make(map[int]string) | ||
| 93 | for i, part := range parts { | ||
| 94 | if strings.HasPrefix(part, ":") { | ||
| 95 | expr := "([^/]+)" | ||
| 96 | //a user may choose to override the defult expression | ||
| 97 | // similar to expressjs: ‘/user/:id([0-9]+)’ | ||
| 98 | if index := strings.Index(part, "("); index != -1 { | ||
| 99 | expr = part[index:] | ||
| 100 | part = part[:index] | ||
| 101 | } | ||
| 102 | params[j] = part | ||
| 103 | parts[i] = expr | ||
| 104 | j++ | ||
| 105 | } | ||
| 106 | } | ||
| 107 | if j == 0 { | ||
| 108 | //now create the Route | ||
| 109 | uh := &userHandler{} | ||
| 110 | uh.pattern = pattern | ||
| 111 | uh.h = c | ||
| 112 | p.userHandlers[pattern] = uh | ||
| 113 | } else { // add regexp routers | ||
| 114 | //recreate the url pattern, with parameters replaced | ||
| 115 | //by regular expressions. then compile the regex | ||
| 116 | pattern = strings.Join(parts, "/") | ||
| 117 | regex, regexErr := regexp.Compile(pattern) | ||
| 118 | if regexErr != nil { | ||
| 119 | //TODO add error handling here to avoid panic | ||
| 120 | panic(regexErr) | ||
| 121 | return | ||
| 122 | } | ||
| 123 | |||
| 124 | //now create the Route | ||
| 125 | uh := &userHandler{} | ||
| 126 | uh.regex = regex | ||
| 127 | uh.params = params | ||
| 128 | uh.pattern = pattern | ||
| 129 | uh.h = c | ||
| 130 | p.userHandlers[pattern] = uh | ||
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 80 | // Filter adds the middleware filter. | 134 | // Filter adds the middleware filter. |
| 81 | func (p *ControllerRegistor) Filter(filter http.HandlerFunc) { | 135 | func (p *ControllerRegistor) Filter(filter http.HandlerFunc) { |
| 82 | p.filters = append(p.filters, filter) | 136 | p.filters = append(p.filters, filter) |
| ... | @@ -143,6 +197,43 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) | ... | @@ -143,6 +197,43 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) |
| 143 | 197 | ||
| 144 | requestPath := r.URL.Path | 198 | requestPath := r.URL.Path |
| 145 | 199 | ||
| 200 | //user defined Handler | ||
| 201 | for pattern, c := range p.userHandlers { | ||
| 202 | if c.regex == nil && pattern == requestPath { | ||
| 203 | c.h.ServeHTTP(rw, r) | ||
| 204 | return | ||
| 205 | } else if c.regex == nil { | ||
| 206 | continue | ||
| 207 | } | ||
| 208 | |||
| 209 | //check if Route pattern matches url | ||
| 210 | if !c.regex.MatchString(requestPath) { | ||
| 211 | continue | ||
| 212 | } | ||
| 213 | |||
| 214 | //get submatches (params) | ||
| 215 | matches := c.regex.FindStringSubmatch(requestPath) | ||
| 216 | |||
| 217 | //double check that the Route matches the URL pattern. | ||
| 218 | if len(matches[0]) != len(requestPath) { | ||
| 219 | continue | ||
| 220 | } | ||
| 221 | |||
| 222 | if len(c.params) > 0 { | ||
| 223 | //add url parameters to the query param map | ||
| 224 | values := r.URL.Query() | ||
| 225 | for i, match := range matches[1:] { | ||
| 226 | values.Add(c.params[i], match) | ||
| 227 | params[c.params[i]] = match | ||
| 228 | } | ||
| 229 | //reassemble query params and add to RawQuery | ||
| 230 | r.URL.RawQuery = url.Values(values).Encode() + "&" + r.URL.RawQuery | ||
| 231 | //r.URL.RawQuery = url.Values(values).Encode() | ||
| 232 | } | ||
| 233 | c.h.ServeHTTP(rw, r) | ||
| 234 | return | ||
| 235 | } | ||
| 236 | |||
| 146 | //first find path from the fixrouters to Improve Performance | 237 | //first find path from the fixrouters to Improve Performance |
| 147 | for _, route := range p.fixrouters { | 238 | for _, route := range p.fixrouters { |
| 148 | n := len(requestPath) | 239 | n := len(requestPath) | ... | ... |
-
Please register or sign in to post a comment