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でやってみますか。