161 lines
3.1 KiB
Go
161 lines
3.1 KiB
Go
package boxes
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/labstack/echo/v4"
|
|
"github.com/labstack/gommon/log"
|
|
"golang.org/x/net/websocket"
|
|
)
|
|
|
|
var (
|
|
wsConnections = make(map[*websocket.Conn]bool)
|
|
wsMutex sync.Mutex
|
|
)
|
|
|
|
type Box struct {
|
|
Id int
|
|
Value bool
|
|
}
|
|
|
|
func deserializeBox(msg string) (Box, error) {
|
|
parts := strings.Split(msg, ":")
|
|
index, err := strconv.Atoi(parts[1])
|
|
if err != nil {
|
|
return Box{}, err
|
|
}
|
|
checked := parts[2] == "+"
|
|
return Box{index, checked}, nil
|
|
}
|
|
|
|
func (box Box) serialize() string {
|
|
message := "b:" + strconv.Itoa(box.Id)
|
|
if box.Value {
|
|
message += ":+"
|
|
} else {
|
|
message += ":-"
|
|
}
|
|
return message + "\n"
|
|
}
|
|
|
|
func handleWsError(err error, conn *websocket.Conn) {
|
|
if err != nil {
|
|
log.Errorf("Failed to handle websocket: %v", err)
|
|
conn.Close()
|
|
wsMutex.Lock()
|
|
defer wsMutex.Unlock()
|
|
delete(wsConnections, conn)
|
|
}
|
|
}
|
|
|
|
func broadcastMessage(message string) {
|
|
wsMutex.Lock()
|
|
defer wsMutex.Unlock()
|
|
for conn := range wsConnections {
|
|
err := websocket.Message.Send(conn, message)
|
|
handleWsError(err, conn)
|
|
|
|
}
|
|
}
|
|
|
|
func randomizeBoxes(count int) []Box {
|
|
boxes := make([]Box, count)
|
|
for i := 0; i < count; i++ {
|
|
index := random.Int() % 1000
|
|
box := getBox(index)
|
|
box.Value = !box.Value
|
|
box.persist()
|
|
boxes[i] = box
|
|
}
|
|
return boxes
|
|
|
|
}
|
|
|
|
func handleMessage(msg string, ws *websocket.Conn) error {
|
|
if msg == "gol" {
|
|
matrix := make(map[string]Box)
|
|
boxes := GetBoxes()
|
|
index := 0
|
|
for i := 0; i < 32; i++ {
|
|
for j := 0; j < 32; j++ {
|
|
matrix[fmt.Sprintf("%d-%d", i, j)] = boxes[index]
|
|
index++
|
|
}
|
|
}
|
|
nextGen := make([]Box, 0)
|
|
for id, item := range matrix {
|
|
nextItem := shouldBeAlive(matrix, id)
|
|
if nextItem.Value != item.Value {
|
|
nextGen = append(nextGen, shouldBeAlive(matrix, id))
|
|
}
|
|
|
|
}
|
|
|
|
nextMessage := ""
|
|
for _, item := range nextGen {
|
|
item.persist()
|
|
nextMessage += item.serialize()
|
|
}
|
|
broadcastMessage(nextMessage)
|
|
|
|
} else if strings.Contains(msg, "r:") {
|
|
count, err := strconv.Atoi(strings.Split(msg, ":")[1])
|
|
if err != nil {
|
|
log.Errorf("Failed to parse randomize count: %v", err)
|
|
}
|
|
boxes := randomizeBoxes(count)
|
|
message := ""
|
|
for _, box := range boxes {
|
|
message += box.serialize()
|
|
}
|
|
|
|
broadcastMessage(message)
|
|
|
|
} else if strings.Contains(msg, "b:") {
|
|
box, err := deserializeBox(msg)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
broadcastMessage(msg)
|
|
box.persist()
|
|
} else if strings.Contains(msg, "ping") {
|
|
len := len(wsConnections)
|
|
websocket.Message.Send(ws, "pong-"+strconv.Itoa(len))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func InitWs(c echo.Context) error {
|
|
websocket.Handler(func(ws *websocket.Conn) {
|
|
wsMutex.Lock()
|
|
wsConnections[ws] = true
|
|
wsMutex.Unlock()
|
|
|
|
boxes := GetBoxes()
|
|
msg := ""
|
|
for _, box := range boxes {
|
|
msg += box.serialize()
|
|
}
|
|
|
|
err := websocket.Message.Send(ws, msg)
|
|
handleWsError(err, ws)
|
|
|
|
for {
|
|
var msg string
|
|
err := websocket.Message.Receive(ws, &msg)
|
|
handleWsError(err, ws)
|
|
if err != nil {
|
|
break
|
|
}
|
|
handleMessage(msg, ws)
|
|
log.Infof("Received message: %s", msg)
|
|
}
|
|
}).ServeHTTP(c.Response(), c.Request())
|
|
|
|
return nil
|
|
}
|