3ad639e7 by astaxie

support websocket #20

add example chat
1 parent 25736968
...@@ -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
......
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 }
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)
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!