Skip to content

Instantly share code, notes, and snippets.

@elimisteve
Created February 8, 2012 17:02
Show Gist options
  • Save elimisteve/1771068 to your computer and use it in GitHub Desktop.
Save elimisteve/1771068 to your computer and use it in GitHub Desktop.
Go WebSocket Example
package main
import (
"websocket"
)
type connection struct {
// The websocket connection.
ws *websocket.Conn
// Buffered channel of outbound messages.
send chan string
}
func (c *connection) reader() {
for {
var message string
err := websocket.Message.Receive(c.ws, &message)
if err != nil {
break
}
h.broadcast <- message
}
c.ws.Close()
}
func (c *connection) writer() {
for message := range c.send {
err := websocket.Message.Send(c.ws, message)
if err != nil {
break
}
}
c.ws.Close()
}
func wsHandler(ws *websocket.Conn) {
c := &connection{send: make(chan string, 256), ws: ws}
h.register <- c
defer func() { h.unregister <- c }()
go c.writer()
c.reader()
}
<html>
<head>
<title>Chat Example</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
var conn;
var msg = $("#msg");
var log = $("#log");
function appendLog(msg) {
var d = log[0]
var doScroll = d.scrollTop == d.scrollHeight - d.clientHeight;
msg.appendTo(log)
if (doScroll) {
d.scrollTop = d.scrollHeight - d.clientHeight;
}
}
$("#form").submit(function() {
if (!conn) {
return false;
}
if (!msg.val()) {
return false;
}
conn.send(msg.val());
msg.val("");
return false
});
if (window["WebSocket"]) {
conn = new WebSocket("ws://{{$}}/ws");
conn.onclose = function(evt) {
appendLog($("<div><b>Connection closed.</b></div>"))
}
conn.onmessage = function(evt) {
appendLog($("<div/>").text(evt.data))
}
} else {
appendLog($("<div><b>Your browser does not support WebSockets.</b></div>"))
}
});
</script>
<style type="text/css">
html {
overflow: hidden;
}
body {
overflow: hidden;
padding: 0;
margin: 0;
width: 100%;
height: 100%;
background: gray;
}
#log {
background: white;
margin: 0;
padding: 0.5em 0.5em 0.5em 0.5em;
position: absolute;
top: 0.5em;
left: 0.5em;
right: 0.5em;
bottom: 3em;
overflow: auto;
}
#form {
padding: 0 0.5em 0 0.5em;
margin: 0;
position: absolute;
bottom: 1em;
left: 0px;
width: 100%;
overflow: hidden;
}
</style>
</head>
<body>
<div id="log"></div>
<form id="form">
<input type="submit" value="Send" />
<input type="text" id="msg" size="64"/>
</form>
</body>
</html>
package main
type hub struct {
// Registered connections.
connections map[*connection]bool
// Inbound messages from the connections.
broadcast chan string
// Register requests from the connections.
register chan *connection
// Unregister requests from connections.
unregister chan *connection
}
var h = hub{
broadcast: make(chan string),
register: make(chan *connection),
unregister: make(chan *connection),
connections: make(map[*connection]bool),
}
func (h *hub) run() {
for {
select {
case c := <-h.register:
h.connections[c] = true
case c := <-h.unregister:
delete(h.connections, c)
close(c.send)
case m := <-h.broadcast:
for c := range h.connections {
select {
case c.send <- m:
default:
delete(h.connections, c)
close(c.send)
go c.ws.Close()
}
}
}
}
}
package main
import (
"flag"
"log"
"net/http"
"text/template"
"websocket"
)
var addr = flag.String("addr", ":8080", "http service address")
var homeTempl = template.Must(template.ParseFiles("home.html"))
func homeHandler(c http.ResponseWriter, req *http.Request) {
homeTempl.Execute(c, req.Host)
}
func main() {
flag.Parse()
go h.run()
http.HandleFunc("/", homeHandler)
http.Handle("/ws", websocket.Handler(wsHandler))
if err := http.ListenAndServe(*addr, nil); err != nil {
log.Fatal("ListenAndServe:", err)
}
}
run: clean example
./example
include $(GOROOT)/src/Make.inc
TARG=example
GOFILES=\
main.go\
hub.go\
conn.go
include $(GOROOT)/src/Make.cmd
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment