examplesのgit: https://github.com/revel/examples
$ git clone https://github.com/revel/examples.git
$ revel run github.com/revel/examples/chat
templateのjs
var socket = new WebSocket('ws://'+window.location.host+'/websocket/room/socket?user={{.user}}') // Display a message var display = function(event) { $('#thread').append(tmpl('message_tmpl', {event: event})); $('#thread').scrollTo('max') } // Message received on the socket socket.onmessage = function(event) { display(JSON.parse(event.data)) } $('#send').click(function(e) { var message = $('#message').val() $('#message').val('') socket.send(JSON.stringify(message)) }); $('#message').keypress(function(e) { if(e.charCode == 13 || e.keyCode == 13) { $('#send').click() e.preventDefault() } })
route
GET /websocket/room WebSocket.Room WS /websocket/room/socket WebSocket.RoomSocket
top
<form action="{{url "Application.EnterDemo"}}"> {{if .flash.error}} <p class="error"> {{.flash.error}} </p> {{end}} <p> <label for="nick">Choose a nick name</label> <input type="text" name="user" id="user"> </p> <p> <label for="nick">Demonstration</label> <select name="demo"> <option></option> <option value="refresh">Ajax, active refresh</option> <option value="longpolling">Ajax, long polling</option> <option value="websocket">WebSocket</option> </select> </p> <p> <label></label> <input type="submit" id="enter" value="Enter the chat room"> </p> </form>
controller
func (c Application) EnterDemo(user, demo string) revel.Result { c.Validation.Required(user) c.Validation.Required(demo) if c.Validation.HasErrors() { c.Flash.Error("Please choose a nick name and the demonstration type.") return c.Redirect(Application.Index) } switch demo { case "refresh": return c.Redirect("/refresh?user=%s", user) case "longpolling": return c.Redirect("/longpolling/room?user=%s", user) case "websocket": return c.Redirect("/websocket/room?user=%s", user) } return nil }
controller
package controllers import ( "github.com/revel/revel" "github.com/revel/examples/chat/app/chatroom" ) type WebSocket struct { *revel.Controller } func (c WebSocket) Room(user string) revel.Result { return c.Render(user) } func (c WebSocket) RoomSocket(user string, ws revel.ServerWebSocket) revel.Result { // Make sure the websocket is valid. if ws == nil { return nil } // Join the room. subscription := chatroom.Subscribe() defer subscription.Cancel() chatroom.Join(user) defer chatroom.Leave(user) // Send down the archive. for _, event := range subscription.Archive { if ws.MessageSendJSON(&event) != nil { // They disconnected return nil } } // In order to select between websocket messages and subscription events, we // need to stuff websocket events into a channel. newMessages := make(chan string) go func() { var msg string for { err := ws.MessageReceiveJSON(&msg) if err != nil { close(newMessages) return } newMessages <- msg } }() // Now listen for new events from either the websocket or the chatroom. for { select { case event := <-subscription.New: if ws.MessageSendJSON(&event) != nil { // They disconnected. return nil } case msg, ok := <-newMessages: // If the channel is closed, they disconnected. if !ok { return nil } // Otherwise, say something. chatroom.Say(user, msg) } } return nil }
なるほど、なんとなく構成要素は分かったので、revelでやってみますか。