add chat example
Showing
7 changed files
with
290 additions
and
123 deletions
example/chat/chat.go
deleted
100644 → 0
| 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/conf/app.conf
0 → 100644
example/chat/controllers/default.go
0 → 100644
example/chat/controllers/ws.go
0 → 100644
| 1 | package controllers | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "github.com/astaxie/beego" | ||
| 5 | "github.com/garyburd/go-websocket/websocket" | ||
| 6 | "io/ioutil" | ||
| 7 | "math/rand" | ||
| 8 | "net/http" | ||
| 9 | "time" | ||
| 10 | ) | ||
| 11 | |||
| 12 | const ( | ||
| 13 | // Time allowed to write a message to the client. | ||
| 14 | writeWait = 10 * time.Second | ||
| 15 | |||
| 16 | // Time allowed to read the next message from the client. | ||
| 17 | readWait = 60 * time.Second | ||
| 18 | |||
| 19 | // Send pings to client with this period. Must be less than readWait. | ||
| 20 | pingPeriod = (readWait * 9) / 10 | ||
| 21 | |||
| 22 | // Maximum message size allowed from client. | ||
| 23 | maxMessageSize = 512 | ||
| 24 | ) | ||
| 25 | |||
| 26 | func init() { | ||
| 27 | rand.Seed(time.Now().UTC().UnixNano()) | ||
| 28 | go h.run() | ||
| 29 | } | ||
| 30 | |||
| 31 | // connection is an middleman between the websocket connection and the hub. | ||
| 32 | type connection struct { | ||
| 33 | username string | ||
| 34 | |||
| 35 | // The websocket connection. | ||
| 36 | ws *websocket.Conn | ||
| 37 | |||
| 38 | // Buffered channel of outbound messages. | ||
| 39 | send chan []byte | ||
| 40 | } | ||
| 41 | |||
| 42 | // readPump pumps messages from the websocket connection to the hub. | ||
| 43 | func (c *connection) readPump() { | ||
| 44 | defer func() { | ||
| 45 | h.unregister <- c | ||
| 46 | c.ws.Close() | ||
| 47 | }() | ||
| 48 | c.ws.SetReadLimit(maxMessageSize) | ||
| 49 | c.ws.SetReadDeadline(time.Now().Add(readWait)) | ||
| 50 | for { | ||
| 51 | op, r, err := c.ws.NextReader() | ||
| 52 | if err != nil { | ||
| 53 | break | ||
| 54 | } | ||
| 55 | switch op { | ||
| 56 | case websocket.OpPong: | ||
| 57 | c.ws.SetReadDeadline(time.Now().Add(readWait)) | ||
| 58 | case websocket.OpText: | ||
| 59 | message, err := ioutil.ReadAll(r) | ||
| 60 | if err != nil { | ||
| 61 | break | ||
| 62 | } | ||
| 63 | h.broadcast <- []byte(c.username + "_" + time.Now().Format("15:04:05") + ":" + string(message)) | ||
| 64 | } | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | // write writes a message with the given opCode and payload. | ||
| 69 | func (c *connection) write(opCode int, payload []byte) error { | ||
| 70 | c.ws.SetWriteDeadline(time.Now().Add(writeWait)) | ||
| 71 | return c.ws.WriteMessage(opCode, payload) | ||
| 72 | } | ||
| 73 | |||
| 74 | // writePump pumps messages from the hub to the websocket connection. | ||
| 75 | func (c *connection) writePump() { | ||
| 76 | ticker := time.NewTicker(pingPeriod) | ||
| 77 | defer func() { | ||
| 78 | ticker.Stop() | ||
| 79 | c.ws.Close() | ||
| 80 | }() | ||
| 81 | for { | ||
| 82 | select { | ||
| 83 | case message, ok := <-c.send: | ||
| 84 | if !ok { | ||
| 85 | c.write(websocket.OpClose, []byte{}) | ||
| 86 | return | ||
| 87 | } | ||
| 88 | if err := c.write(websocket.OpText, message); err != nil { | ||
| 89 | return | ||
| 90 | } | ||
| 91 | case <-ticker.C: | ||
| 92 | if err := c.write(websocket.OpPing, []byte{}); err != nil { | ||
| 93 | return | ||
| 94 | } | ||
| 95 | } | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | type hub struct { | ||
| 100 | // Registered connections. | ||
| 101 | connections map[*connection]bool | ||
| 102 | |||
| 103 | // Inbound messages from the connections. | ||
| 104 | broadcast chan []byte | ||
| 105 | |||
| 106 | // Register requests from the connections. | ||
| 107 | register chan *connection | ||
| 108 | |||
| 109 | // Unregister requests from connections. | ||
| 110 | unregister chan *connection | ||
| 111 | } | ||
| 112 | |||
| 113 | var h = &hub{ | ||
| 114 | broadcast: make(chan []byte, maxMessageSize), | ||
| 115 | register: make(chan *connection, 1), | ||
| 116 | unregister: make(chan *connection, 1), | ||
| 117 | connections: make(map[*connection]bool), | ||
| 118 | } | ||
| 119 | |||
| 120 | func (h *hub) run() { | ||
| 121 | for { | ||
| 122 | select { | ||
| 123 | case c := <-h.register: | ||
| 124 | h.connections[c] = true | ||
| 125 | case c := <-h.unregister: | ||
| 126 | delete(h.connections, c) | ||
| 127 | close(c.send) | ||
| 128 | case m := <-h.broadcast: | ||
| 129 | for c := range h.connections { | ||
| 130 | select { | ||
| 131 | case c.send <- m: | ||
| 132 | default: | ||
| 133 | close(c.send) | ||
| 134 | delete(h.connections, c) | ||
| 135 | } | ||
| 136 | } | ||
| 137 | } | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 141 | type WSController struct { | ||
| 142 | beego.Controller | ||
| 143 | } | ||
| 144 | |||
| 145 | func (this *WSController) Get() { | ||
| 146 | ws, err := websocket.Upgrade(this.Ctx.ResponseWriter, this.Ctx.Request.Header, nil, 1024, 1024) | ||
| 147 | if _, ok := err.(websocket.HandshakeError); ok { | ||
| 148 | http.Error(this.Ctx.ResponseWriter, "Not a websocket handshake", 400) | ||
| 149 | return | ||
| 150 | } else if err != nil { | ||
| 151 | return | ||
| 152 | } | ||
| 153 | c := &connection{send: make(chan []byte, 256), ws: ws, username: randomString(10)} | ||
| 154 | h.register <- c | ||
| 155 | go c.writePump() | ||
| 156 | c.readPump() | ||
| 157 | } | ||
| 158 | |||
| 159 | func randomString(l int) string { | ||
| 160 | bytes := make([]byte, l) | ||
| 161 | for i := 0; i < l; i++ { | ||
| 162 | bytes[i] = byte(randInt(65, 90)) | ||
| 163 | } | ||
| 164 | return string(bytes) | ||
| 165 | } | ||
| 166 | |||
| 167 | func randInt(min int, max int) int { | ||
| 168 | return min + rand.Intn(max-min) | ||
| 169 | } |
example/chat/main.go
0 → 100644
example/chat/views/index.html
deleted
100644 → 0
| 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 |
example/chat/views/index.tpl
0 → 100644
| 1 | <!DOCTYPE html> | ||
| 2 | <html lang="en"> | ||
| 3 | <head> | ||
| 4 | <title>Chat Example</title> | ||
| 5 | <script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script> | ||
| 6 | <script type="text/javascript"> | ||
| 7 | $(function() { | ||
| 8 | |||
| 9 | var conn; | ||
| 10 | var msg = $("#msg"); | ||
| 11 | var log = $("#log"); | ||
| 12 | |||
| 13 | function appendLog(msg) { | ||
| 14 | var d = log[0] | ||
| 15 | var doScroll = d.scrollTop == d.scrollHeight - d.clientHeight; | ||
| 16 | msg.appendTo(log) | ||
| 17 | if (doScroll) { | ||
| 18 | d.scrollTop = d.scrollHeight - d.clientHeight; | ||
| 19 | } | ||
| 20 | } | ||
| 21 | |||
| 22 | $("#form").submit(function() { | ||
| 23 | if (!conn) { | ||
| 24 | return false; | ||
| 25 | } | ||
| 26 | if (!msg.val()) { | ||
| 27 | return false; | ||
| 28 | } | ||
| 29 | conn.send(msg.val()); | ||
| 30 | msg.val(""); | ||
| 31 | return false | ||
| 32 | }); | ||
| 33 | |||
| 34 | if (window["WebSocket"]) { | ||
| 35 | conn = new WebSocket("ws://{{.host}}/ws"); | ||
| 36 | conn.onclose = function(evt) { | ||
| 37 | appendLog($("<div><b>Connection closed.</b></div>")) | ||
| 38 | } | ||
| 39 | conn.onmessage = function(evt) { | ||
| 40 | appendLog($("<div/>").text(evt.data)) | ||
| 41 | } | ||
| 42 | } else { | ||
| 43 | appendLog($("<div><b>Your browser does not support WebSockets.</b></div>")) | ||
| 44 | } | ||
| 45 | }); | ||
| 46 | </script> | ||
| 47 | <style type="text/css"> | ||
| 48 | html { | ||
| 49 | overflow: hidden; | ||
| 50 | } | ||
| 51 | |||
| 52 | body { | ||
| 53 | overflow: hidden; | ||
| 54 | padding: 0; | ||
| 55 | margin: 0; | ||
| 56 | width: 100%; | ||
| 57 | height: 100%; | ||
| 58 | background: gray; | ||
| 59 | } | ||
| 60 | |||
| 61 | #log { | ||
| 62 | background: white; | ||
| 63 | margin: 0; | ||
| 64 | padding: 0.5em 0.5em 0.5em 0.5em; | ||
| 65 | position: absolute; | ||
| 66 | top: 0.5em; | ||
| 67 | left: 0.5em; | ||
| 68 | right: 0.5em; | ||
| 69 | bottom: 3em; | ||
| 70 | overflow: auto; | ||
| 71 | } | ||
| 72 | |||
| 73 | #form { | ||
| 74 | padding: 0 0.5em 0 0.5em; | ||
| 75 | margin: 0; | ||
| 76 | position: absolute; | ||
| 77 | bottom: 1em; | ||
| 78 | left: 0px; | ||
| 79 | width: 100%; | ||
| 80 | overflow: hidden; | ||
| 81 | } | ||
| 82 | |||
| 83 | </style> | ||
| 84 | </head> | ||
| 85 | <body> | ||
| 86 | <div id="log"></div> | ||
| 87 | <form id="form"> | ||
| 88 | <input type="submit" value="Send" /> | ||
| 89 | <input type="text" id="msg" size="64"/> | ||
| 90 | </form> | ||
| 91 | </body> | ||
| 92 | </html> | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
-
Please register or sign in to post a comment