drawserver/backend/server.go
2020-10-24 01:17:39 +01:00

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)
}
}