out/cmd/server/ws.go

153 lines
3.4 KiB
Go

package main
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"slices"
"strconv"
"strings"
"github.com/coder/websocket"
)
func isWS(r *http.Request) bool {
return r.URL.Path == "/ws" || strings.HasPrefix(r.URL.Path, "/ws/")
}
func (s *S) serveWS(w http.ResponseWriter, r *http.Request) error {
ctx, can := context.WithCancel(r.Context())
defer can()
c, err := websocket.Accept(w, r, nil)
if err != nil {
return err
}
defer c.CloseNow()
ugs, err := NewUserGameServer(ctx, s.Session(ctx), s.games)
if err != nil {
return err
}
go ugs.Listen(ctx, can, func(ctx context.Context) ([]byte, error) {
_, b, err := c.Read(ctx)
return b, err
})
for ugs.More(ctx) == nil {
gameState, err := ugs.State(ctx)
if err != nil {
return err
}
msg := map[string]any{
"help": strings.Join([]string{
"CARD ASSASSINS (Mobile Ed.)",
"",
"1. Get any target to say any of his or her kill words.",
"2. Click the word to collect points.",
"3. Review new kill words.",
"",
"The game ends when everyone has been assassinated.",
}, "<br>"),
}
if gameState.Started {
msg["page"] = "B"
if gameState.Completed.IsZero() {
msg["event"] = "A"
items := []map[string]any{}
for k, v := range gameState.Players {
if k == s.Session(ctx).ID {
continue
}
name, err := s.games.UserName(ctx, k)
if err != nil {
return err
}
tags := []map[string]any{}
if self := gameState.Players[s.Session(ctx).ID]; self.KillWords.Assignee == k {
for _, private := range v.KillWords.Assignment.Private {
tags = append(tags, map[string]any{
"k": private.Word,
"v": private.Points,
})
}
}
for _, public := range v.KillWords.Assignment.Public {
tags = append(tags, map[string]any{
"k": public.Word,
"v": public.Points,
})
}
if self := gameState.Players[s.Session(ctx).ID]; !slices.ContainsFunc(self.Kills, func(a Kill) bool {
return a.Victim == k
}) {
tags = append(tags, map[string]any{
"k": self.KillWords.Global.Word,
"v": self.KillWords.Global.Points,
})
}
items = append(items, map[string]any{
"name": name,
"title": strconv.Itoa(v.Points()),
"tags": tags,
})
}
slices.SortFunc(items, func(a, b map[string]any) int {
an, _ := strconv.Atoi(fmt.Sprint(a["title"]))
bn, _ := strconv.Atoi(fmt.Sprint(b["title"]))
return an - bn
})
return io.EOF
} else {
msg["event"] = "B"
items := []map[string]any{}
for k, v := range gameState.Players {
name, err := s.games.UserName(ctx, k)
if err != nil {
return err
}
tags := []map[string]any{}
for _, kill := range v.Kills {
tags = append(tags, map[string]any{
"k": kill.KillWord.Word,
"v": kill.Victim,
})
}
items = append(items, map[string]any{
"name": name,
"title": fmt.Sprint(v.Points()),
"tags": tags,
})
}
msg["items"] = items
}
} else {
msg["page"] = "A"
items := []map[string]any{}
for k := range gameState.Players {
name, err := s.games.UserName(ctx, k)
if err != nil {
return err
}
items = append(items, map[string]any{"name": name})
}
msg["items"] = items
}
msgB, _ := json.Marshal(msg)
if err := c.Write(ctx, 1, msgB); err != nil {
return err
}
}
return ctx.Err()
}