Last active
August 29, 2015 14:10
-
-
Save dadamssg/30f47974fc62ce8cb6f2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="UTF-8"> | |
<title>Chat</title> | |
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css"> | |
<script src="https://code.jquery.com/jquery-2.1.1.min.js"></script> | |
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script> | |
<script> | |
$(function() { | |
var $chatName = $("#chat-name-input"); | |
var $memberName = $("#member-name-input"); | |
var $input = $("#msg-input"); | |
var $button = $("#msg-button"); | |
var $ul = $("#messages"); | |
var appendMsg = function (msg) { | |
$ul.append("<li>" + msg + "</li>"); | |
} | |
$("#chat-name-button").click(function () { | |
var roomName = $chatName.val(); | |
var memberName = $memberName.val(); | |
var conn = new WebSocket("ws://192.168.56.109:8089/ws?room=" + roomName + "&name=" + memberName); | |
conn.onclose = function(e) { | |
appendMsg("Disconnected from '" + roomName + "'"); | |
}; | |
conn.onopen = function(e) { | |
appendMsg("Connected to '" + roomName + "' as '" + memberName + "'"); | |
}; | |
conn.onmessage = function(e){ | |
appendMsg(e.data); | |
}; | |
$button.click(function () { | |
conn.send($input.val()); | |
$input.val(''); | |
return false; | |
}); | |
$chatName.val(''); | |
$memberName.val(''); | |
return false; | |
}); | |
}); | |
</script> | |
</head> | |
<body> | |
<div class="row"> | |
<div class="col-md-4"> | |
<h3>Join</h3> | |
<form class="form-inline" role="form"> | |
<div class="form-group"> | |
<input type="text" class="form-control" id="chat-name-input" placeholder="Chat room"> | |
<input type="text" class="form-control" id="member-name-input" placeholder="Nick"> | |
</div> | |
<button type="submit" class="btn btn-primary" id="chat-name-button">Join</button> | |
</form> | |
</div> | |
<div class="col-md-4"> | |
<h3>Chat</h3> | |
<div> | |
<ul id="messages"> | |
</ul> | |
</div> | |
<form class="form-inline" role="form"> | |
<div class="form-group"> | |
<input type="text" class="form-control" id="msg-input" placeholder="Message"> | |
</div> | |
<button type="submit" class="btn btn-primary" id="msg-button">Send</button> | |
</form> | |
</div> | |
<div class="col-md-4"></div> | |
</div> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"flag" | |
"fmt" | |
"log" | |
"net/http" | |
"github.com/gorilla/websocket" | |
) | |
type user struct { | |
name string | |
send chan []byte | |
conn *websocket.Conn | |
} | |
func (u *user) reader(broadcast chan []byte) { | |
for { | |
_, msg, err := u.conn.ReadMessage() | |
if err != nil { | |
break | |
} | |
log.Printf("'%s' wrote message: '%s'.", u.name, string(msg)) | |
broadcast <- msg | |
} | |
} | |
func (u *user) writer() { | |
for msg := range u.send { | |
log.Printf("'%s' is being sent message: '%s'.", u.name, string(msg)) | |
err := u.conn.WriteMessage(websocket.TextMessage, msg) | |
if err != nil { | |
break | |
} | |
} | |
} | |
type chatRoom struct { | |
name string | |
broadcast chan []byte | |
register chan *user | |
unregister chan *user | |
members map[*user]bool | |
} | |
func (room *chatRoom) open() { | |
for { | |
select { | |
case u := <-room.register: | |
room.members[u] = true | |
log.Printf("'%s' connected to '%s'.", u.name, room.name) | |
case u := <-room.unregister: | |
if _, ok := room.members[u]; ok { | |
delete(room.members, u) | |
close(u.send) | |
log.Printf("'%s' disconnected from '%s'.", u.name, room.name) | |
} | |
case msg := <-room.broadcast: | |
for u := range room.members { | |
select { | |
case u.send <- msg: | |
default: | |
delete(room.members, u) | |
close(u.send) | |
} | |
} | |
} | |
} | |
} | |
type roomFinder struct { | |
name string | |
finder chan *chatRoom | |
} | |
type chatHouse struct { | |
rooms map[*chatRoom]bool | |
finder chan *roomFinder | |
destroy chan *chatRoom | |
} | |
func (house *chatHouse) open() { | |
for { | |
select { | |
case f := <-house.finder: | |
name := f.name | |
var room *chatRoom | |
for r := range house.rooms { | |
if r.name == name { | |
log.Printf("'%s' room found.", name) | |
room = r | |
} | |
} | |
if room == nil { | |
room = &chatRoom{ | |
name: name, | |
broadcast: make(chan []byte), | |
register: make(chan *user), | |
unregister: make(chan *user), | |
members: make(map[*user]bool), | |
} | |
go room.open() | |
house.rooms[room] = true | |
log.Printf("'%s' room created.", name) | |
} | |
f.finder <- room | |
case room := <-house.destroy: | |
if _, ok := house.rooms[room]; ok { | |
close(room.broadcast) | |
close(room.register) | |
close(room.unregister) | |
delete(house.rooms, room) | |
} | |
} | |
} | |
} | |
func getWsHandler(upgrader *websocket.Upgrader, house *chatHouse) http.HandlerFunc { | |
return func(w http.ResponseWriter, r *http.Request) { | |
roomName := string(r.URL.Query()["room"][0]) | |
memberName := string(r.URL.Query()["name"][0]) | |
conn, err := upgrader.Upgrade(w, r, nil) | |
if err != nil { | |
return | |
} | |
defer func() { conn.Close() }() | |
u := &user{ | |
name: memberName, | |
send: make(chan []byte, 256), | |
conn: conn, | |
} | |
finderChan := make(chan *chatRoom) | |
finder := &roomFinder{name: roomName, finder: finderChan} | |
house.finder <- finder | |
room := <-finderChan | |
close(finderChan) | |
room.register <- u | |
defer func() { room.unregister <- u }() | |
go u.writer() | |
u.reader(room.broadcast) | |
} | |
} | |
func main() { | |
port := flag.Int("port", 8089, "port to serve on") | |
dir := flag.String("directory", "web/", "directory of web files") | |
flag.Parse() | |
upgrader := &websocket.Upgrader{ReadBufferSize: 1024, WriteBufferSize: 1024} | |
house := &chatHouse{ | |
rooms: make(map[*chatRoom]bool), | |
finder: make(chan *roomFinder), | |
destroy: make(chan *chatRoom), | |
} | |
go house.open() | |
fs := http.Dir(*dir) | |
fileHandler := http.FileServer(fs) | |
http.Handle("/", fileHandler) | |
http.Handle("/ws", getWsHandler(upgrader, house)) | |
log.Printf("Running on port %d\n", *port) | |
addr := fmt.Sprintf(":%d", *port) | |
err := http.ListenAndServe(addr, nil) | |
fmt.Println(err.Error()) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment