After installing Go and setting up your GOPATH
go get golang.org/x/net/websocket
# Add your personnal ip as 192.168.*.* or your domain as www.example.com
go run main.go -addr=0.0.0.0:3000
Open your favorite browser : http://localhost:3000
After installing Go and setting up your GOPATH
go get golang.org/x/net/websocket
# Add your personnal ip as 192.168.*.* or your domain as www.example.com
go run main.go -addr=0.0.0.0:3000
Open your favorite browser : http://localhost:3000
<!DOCTYPE html> | |
<html lang="en" dir="ltr"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>Websocket</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" /> | |
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous" /> | |
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous" /> | |
<style> | |
#messages { | |
height: 120px; | |
overflow: scroll; | |
padding: 20px; | |
} | |
#messages div { | |
margin-bottom: 4px; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="container"> | |
<h1>Websocket</h1> | |
<div class="col"> | |
<div class="form-group"> | |
<input type="text" id="username" class="form-control" placeholder="Username" /> | |
</div> | |
<div class="form-group"> | |
<textarea id="text" class="form-control" placeholder="Write a message and press enter..."></textarea> | |
</div> | |
</div> | |
<div> | |
<h3>Messages:</h3> | |
<div id="messages" class="pre-scrollable well"></div> | |
</div> | |
</div> | |
<script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script> | |
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script> | |
<script type="text/javascript"> | |
$(document).ready(function () { | |
var ws = new WebSocket('ws://' + location.host + '/echo'); | |
var username = ''; | |
ws.onopen = function () { | |
console.log('Connected'); | |
}; | |
ws.onclose = function () { | |
alert('Disconnected'); | |
} | |
ws.onmessage = function (e) { | |
console.log(e.data); | |
var m = JSON.parse(e.data); | |
var div = document.createElement('div'); | |
var strg = document.createElement('strong'); | |
strg.appendChild(document.createTextNode(m.username + ': ')); | |
div.appendChild(strg); | |
div.appendChild(document.createTextNode(m.text)); | |
$(div).hide().appendTo('#messages').fadeIn(300); | |
}; | |
ws.onerror = function (e) { | |
console.debug(e.data); | |
}; | |
$(document).on('keypress', '#text', function (e) { | |
if (e.keyCode == 13) { | |
e.preventDefault(); | |
if (username === '') { | |
username = $('#username').val(); | |
} | |
var text = $(this); | |
var msg = { | |
username: username, | |
text: text.val() | |
}; | |
if (text.val() !== '') { | |
ws.send(JSON.stringify(msg)); | |
text.val(''); | |
} | |
} | |
}); | |
}); | |
setInterval(animateScroll($('#messages')), 3000); | |
function animateScroll(elem) { | |
return function () { | |
elem.animate({ | |
scrollTop: elem[0].scrollHeight | |
}, 1000); | |
} | |
} | |
</script> | |
</body> | |
</html> |
// Copyright 2017 The Nanoninja Authors. All rights reserved. | |
package main | |
import ( | |
"flag" | |
"html/template" | |
"io" | |
"log" | |
"net/http" | |
"golang.org/x/net/websocket" | |
) | |
var ( | |
addr = flag.String("addr", "0.0.0.0:3000", "host:port") | |
chat = NewChat() | |
) | |
func main() { | |
flag.Parse() | |
go chat.Run() | |
http.HandleFunc("/", indexHandler) | |
http.HandleFunc("/echo", webSocketHandler) | |
if err := http.ListenAndServe(*addr, nil); err != nil { | |
panic(err.Error()) | |
} | |
} | |
func indexHandler(w http.ResponseWriter, r *http.Request) { | |
t, err := template.ParseFiles("index.html") | |
if err != nil { | |
http.Error(w, err.Error(), http.StatusInternalServerError) | |
} | |
err = t.Execute(w, nil) | |
} | |
type User struct { | |
Name string | |
Addr string | |
Output chan Message | |
} | |
type Message struct { | |
Username string `json:"username"` | |
Text string `json:"text"` | |
} | |
type Chat struct { | |
Users map[string]User | |
Join chan User | |
Leave chan User | |
Input chan Message | |
} | |
func NewChat() *Chat { | |
return &Chat{ | |
Users: make(map[string]User), | |
Join: make(chan User), | |
Leave: make(chan User), | |
Input: make(chan Message), | |
} | |
} | |
func (c *Chat) Run() { | |
for { | |
select { | |
case user := <-c.Join: | |
c.Users[user.Name] = user | |
case user := <-c.Leave: | |
delete(c.Users, user.Name) | |
case msg := <-c.Input: | |
for _, user := range c.Users { | |
user.Output <- msg | |
} | |
} | |
} | |
} | |
func webSocketServer(ws *websocket.Conn) { | |
defer ws.Close() | |
user := User{ | |
Output: make(chan Message), | |
Addr: ws.Request().RemoteAddr, | |
} | |
defer func() { | |
chat.Leave <- user | |
}() | |
go func() { | |
for { | |
m := Message{} | |
if err := websocket.JSON.Receive(ws, &m); err != nil { | |
if err == io.EOF { | |
log.Printf("%s has disconnected", user.Name) | |
chat.Leave <- user | |
break | |
} | |
} | |
user.Name = m.Username | |
chat.Join <- user | |
m.Text = textLimit(255)(m.Text) | |
chat.Input <- m | |
addr := chat.Users[m.Username].Addr | |
log.Printf("[%s] %s: %s\n", addr, m.Username, m.Text) | |
} | |
}() | |
for msg := range user.Output { | |
if err := websocket.JSON.Send(ws, msg); err != nil { | |
log.Println(err) | |
break | |
} | |
} | |
} | |
func webSocketHandler(w http.ResponseWriter, r *http.Request) { | |
s := websocket.Server{Handler: websocket.Handler(webSocketServer)} | |
s.ServeHTTP(w, r) | |
} | |
type filter func(s string) string | |
func textLimit(length int) filter { | |
return func(s string) string { | |
if len(s) > length { | |
return s[:length] | |
} | |
return s | |
} | |
} |