Skip to content

Instantly share code, notes, and snippets.

@andrewytliu
Created June 16, 2013 14:46
Show Gist options
  • Save andrewytliu/5792278 to your computer and use it in GitHub Desktop.
Save andrewytliu/5792278 to your computer and use it in GitHub Desktop.
Websocket chatroom in Go
<html>
<head>
<title>HashGreen</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
var conn, msg = $("#msg"), log = $("#log");
$("#form").submit(function() {
if (!conn) return false;
if (!msg.val()) return false;
conn.send(msg.val());
msg.val("");
return false;
});
conn = new WebSocket("ws://{{$}}/ws");
conn.onclose = function(e) {
log.append($("<div><b>Connection closed.</b></div>"));
}
conn.onmessage = function(e) {
log.append($("<div/>").text(e.data));
}
});
</script>
<style type="text/css">
html {
overflow: hidden;
}
body {
overflow: hidden;
padding: 0;
margin: 0;
width: 100%;
height: 100%;
background: #252525;
font-family: 'Lato', sans-serif;
}
#log {
border-radius: 20px;
background: #FFF;
margin: 5em;
padding: 0.5em;
overflow: auto;
}
#form {
padding: 5px;
margin-left: 5em;
margin-right: 5em;
overflow: hidden;
}
</style>
</head>
<body>
<div id="log"></div>
<form id="form">
<input type="text" id="msg" size="50" />
<input type="submit" value="Send!" />
</form>
</body>
</html>
package main
import (
"code.google.com/p/go.net/websocket"
"log"
"net/http"
"text/template"
)
type Connection struct {
ws *websocket.Conn
send chan string
}
func (c *Connection) ReadLoop() {
for {
var m string
err := websocket.Message.Receive(c.ws, &m)
if err != nil {
log.Println("Read conn:", err)
break
}
pool.broadcast <- m
}
c.ws.Close()
}
func (c *Connection) WriteLoop() {
for m := range c.send {
err := websocket.Message.Send(c.ws, m)
if err != nil {
log.Println("Write conn:", err)
break
}
}
c.ws.Close()
}
func NewConnection(ws *websocket.Conn) {
c := &Connection{send: make(chan string, 256), ws: ws}
pool.connect <- c
defer func() { pool.disconnect <- c }()
go c.WriteLoop()
c.ReadLoop()
}
type Pool struct {
connections map[*Connection]bool
broadcast chan string
connect chan *Connection
disconnect chan *Connection
}
func (p *Pool) Run() {
for {
select {
case c := <-p.connect:
p.connections[c] = true
log.Println("New connection in:", c.ws.LocalAddr())
case c := <-p.disconnect:
delete(p.connections, c)
log.Println("Disconnected:", c.ws.LocalAddr())
case m := <-p.broadcast:
log.Println("Broadcasting:", m)
for c := range p.connections {
select {
case c.send <- m:
default:
delete(p.connections, c)
close(c.send)
go c.ws.Close()
}
}
}
}
}
var pool = Pool{
connections: make(map[*Connection]bool),
broadcast: make(chan string),
connect: make(chan *Connection),
disconnect: make(chan *Connection),
}
var tmpl = template.Must(template.ParseFiles("home.html"))
func main() {
go pool.Run()
http.HandleFunc("/", func(res http.ResponseWriter, req *http.Request) {
tmpl.Execute(res, req.Host)
})
http.Handle("/ws", websocket.Handler(NewConnection))
log.Println("Starting the server...")
if err := http.ListenAndServe(":3000", nil); err != nil {
log.Fatal("Serve: ", err)
}
log.Println("Server started")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment