Files
knet/src/boxes/boxes.go
JurajKubrican a393b03d98 drop sqlite
2025-08-04 15:22:34 +02:00

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
}