189 lines
3.4 KiB
Go
189 lines
3.4 KiB
Go
package main
|
|
|
|
import (
|
|
"github.com/gorilla/websocket"
|
|
"log"
|
|
"net/http"
|
|
"sync"
|
|
)
|
|
|
|
type Client struct {
|
|
ip int
|
|
socket *websocket.Conn
|
|
channel chan string
|
|
}
|
|
|
|
func (c *Client) run() {
|
|
log.Println("starting ", c.ip)
|
|
var message SocketMessage
|
|
for {
|
|
select {
|
|
case <-c.channel:
|
|
log.Println("stopping ", c.ip)
|
|
return
|
|
default:
|
|
c.read(&message)
|
|
logger <- message
|
|
broadcast <- Package{
|
|
sender: c.ip,
|
|
message: message,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
func (c *Client) read(msg *SocketMessage) {
|
|
err := c.socket.ReadJSON(&msg)
|
|
if err != nil {
|
|
log.Println(c, err)
|
|
clients.remove(*c)
|
|
}
|
|
log.Println("read", msg, "from", c.ip)
|
|
}
|
|
func (c *Client) write(msg SocketMessage) {
|
|
err := c.socket.WriteJSON(msg)
|
|
if err != nil {
|
|
log.Println(c, err)
|
|
clients.remove(*c)
|
|
}
|
|
log.Println("wrote", msg, "to", c.ip)
|
|
}
|
|
|
|
type Clients struct {
|
|
list map[int]*Client
|
|
mux sync.Mutex
|
|
}
|
|
|
|
func (c *Clients) run() {
|
|
log.Println("starting broadcaster")
|
|
read := func() (message SocketMessage, ip int) {
|
|
packet, ok := <-broadcast
|
|
if !ok {
|
|
log.Println("stopping broadcaster")
|
|
return
|
|
}
|
|
return packet.message, packet.sender
|
|
}
|
|
for {
|
|
msg, sender := read()
|
|
for ip, client := range clients.list {
|
|
if sender == ip {
|
|
continue
|
|
}
|
|
client.write(msg)
|
|
}
|
|
}
|
|
}
|
|
func (c *Clients) add(client Client) {
|
|
c.mux.Lock()
|
|
defer c.mux.Unlock()
|
|
c.list[client.ip] = &client
|
|
log.Println("saved", client.ip)
|
|
go client.run()
|
|
}
|
|
func (c *Clients) remove(client Client) {
|
|
c.mux.Lock()
|
|
defer c.mux.Unlock()
|
|
_, ok := <-client.channel
|
|
if ok {
|
|
close(client.channel)
|
|
}
|
|
delete(c.list, client.ip)
|
|
log.Println("removed", c.ip)
|
|
}
|
|
|
|
type History struct {
|
|
log []SocketMessage
|
|
mux sync.Mutex
|
|
channel chan string
|
|
}
|
|
|
|
func (h *History) run() {
|
|
log.Println("starting logger")
|
|
for {
|
|
message, ok := <-logger
|
|
if !ok {
|
|
log.Println("stopping logger")
|
|
return
|
|
}
|
|
h.push(message)
|
|
}
|
|
}
|
|
func (h *History) push(message SocketMessage) {
|
|
h.mux.Lock()
|
|
defer h.mux.Unlock()
|
|
h.log = append(h.log, message)
|
|
log.Println("logged ", message)
|
|
}
|
|
func (h *History) replay(client Client) {
|
|
h.mux.Lock()
|
|
defer h.mux.Unlock()
|
|
for _, message := range h.log {
|
|
client.write(message)
|
|
}
|
|
log.Println("replayed history for", client.ip)
|
|
}
|
|
|
|
type Package struct {
|
|
sender int
|
|
message SocketMessage
|
|
}
|
|
|
|
type SocketMessage struct {
|
|
Tag string `json:"tag"`
|
|
X int `json:"x"`
|
|
Y int `json:"y"`
|
|
}
|
|
|
|
var upgrader = websocket.Upgrader{
|
|
ReadBufferSize: 1024,
|
|
WriteBufferSize: 1024,
|
|
CheckOrigin: func(r *http.Request) bool {
|
|
return true
|
|
},
|
|
}
|
|
|
|
func init() {
|
|
log.SetPrefix("")
|
|
log.SetFlags(0)
|
|
}
|
|
|
|
var broadcast = make(chan Package, 10)
|
|
var logger = make(chan SocketMessage, 10)
|
|
var count = 0
|
|
|
|
var clients = &Clients{list: make(map[int]*Client)}
|
|
var history = &History{log: make([]SocketMessage, 0)}
|
|
|
|
func main() {
|
|
history.push(SocketMessage{
|
|
Tag: "p",
|
|
X: 1,
|
|
Y: 2,
|
|
})
|
|
http.HandleFunc("/connect", func(w http.ResponseWriter, r *http.Request) {
|
|
log.Println("connect", count)
|
|
socket, werr := upgrader.Upgrade(w, r, nil)
|
|
if werr != nil {
|
|
log.Println(werr)
|
|
return
|
|
}
|
|
ip := count
|
|
count++
|
|
|
|
client := Client{
|
|
ip: ip,
|
|
socket: socket,
|
|
channel: make(chan string)}
|
|
history.replay(client)
|
|
clients.add(client)
|
|
})
|
|
go history.run()
|
|
go clients.run()
|
|
log.Fatal(http.ListenAndServe("localhost:8080", nil))
|
|
close(logger)
|
|
close(broadcast)
|
|
for _, client := range clients.list {
|
|
close(client.channel)
|
|
}
|
|
}
|