Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM golang:alpine as builder
FROM golang:1.23-alpine AS builder

WORKDIR /build
COPY go.mod go.sum ./
Expand Down
38 changes: 23 additions & 15 deletions client.go
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
package main

import (
"cmp"
"context"
"errors"
"fmt"
"io"
"log/slog"
"net/url"
"os"
"slices"
"strconv"
"time"

"github.com/charmbracelet/bubbles/table"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/gorilla/websocket"
"github.com/vmihailenco/msgpack/v5"

"github.com/abennett/ttt/pkg"
)
Expand Down Expand Up @@ -59,6 +58,7 @@ func connectLoop(wsUrl string) (*websocket.Conn, error) {
slog.Debug("redirecting", "location", wsUrl)
continue
}
defer resp.Body.Close()
return conn, nil
}

Expand Down Expand Up @@ -136,7 +136,7 @@ func errorCmd(err error) tea.Cmd {
}
}

func (c client) Init() tea.Cmd {
func (c *client) Init() tea.Cmd {
slog.Debug("running Init")
conn, err := connectLoop(c.endpoint)
if err != nil {
Expand All @@ -146,9 +146,13 @@ func (c client) Init() tea.Cmd {
req := pkg.RollRequest{
User: c.user,
}
err = conn.WriteJSON(req)
b, err := msgpack.Marshal(req)
if err != nil {
return errorCmd(fmt.Errorf("unable to write json: %w", err))
return errorCmd(fmt.Errorf("failed to marshal: %w", err))
}
err = conn.WriteMessage(websocket.BinaryMessage, b)
if err != nil {
return errorCmd(fmt.Errorf("unable to write server: %w", err))
}

go waitClose(conn, c.done)
Expand All @@ -166,11 +170,10 @@ func resultsToRows(rrs []pkg.RollResult) []table.Row {
}

func (c *client) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
slog.Debug("updating model", "msg", msg)
switch msg := msg.(type) {
case []pkg.RollResult:
slog.Debug("roll result")
c.table.SetHeight(len(msg))
c.table.SetHeight(len(msg) + 1)
c.table.SetRows(resultsToRows(msg))
return c, c.readUpdate()
case tea.KeyMsg:
Expand All @@ -183,20 +186,22 @@ func (c *client) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
slog.Error("exiting for error", "error", msg)
c.err = msg
return c, tea.Quit
default:
slog.Debug("unsupported message", "msg", msg)
}
slog.Debug("no update")
return c, nil
}

func (c client) View() string {
func (c *client) View() string {
slog.Debug("rerendering view")
if c.err != nil {
return fmt.Sprintln(c.err)
}
return baseStyle.Render(c.table.View()) + "\n"
}

func (c client) readUpdate() tea.Cmd {
func (c *client) readUpdate() tea.Cmd {
slog.Debug("reading update")
return func() tea.Msg {
slog.Debug("reading from channel")
Expand All @@ -223,27 +228,30 @@ func updateLoop(conn *websocket.Conn, updates chan<- []pkg.RollResult) {
slog.Debug("running update loop")
var currentVersion int
for {
var room pkg.Room
err := conn.ReadJSON(&room)
_, b, err := conn.ReadMessage()
if err != nil {
slog.Error(err.Error())
return
}
slog.Debug("message recieved", "version", room.Version)
var room pkg.RoomState
err = msgpack.Unmarshal(b, &room)
if err != nil {
slog.Error("failed parsing room", "error", err)
return
}
slog.Debug("message recieved", "room", room)
if currentVersion == room.Version {
slog.Debug("version hasn't changed, continuing")
continue
}

slog.Debug("new version")
rolls := make([]pkg.RollResult, len(room.Rolls))
var idx int
for _, rr := range room.Rolls {
rolls[idx] = rr
idx++
}
slices.SortFunc(rolls, func(a, b pkg.RollResult) int {
return cmp.Compare(b.Result, a.Result)
})
slog.Debug("pushing rolls on channel")
updates <- rolls
currentVersion = room.Version
Expand Down
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/abennett/ttt

go 1.21.0
go 1.22

require (
github.com/charmbracelet/bubbles v0.20.0
Expand All @@ -9,6 +9,7 @@ require (
github.com/go-chi/chi/v5 v5.2.0
github.com/gorilla/websocket v1.5.3
github.com/peterbourgon/ff/v3 v3.4.0
github.com/vmihailenco/msgpack/v5 v5.4.1
)

require (
Expand All @@ -24,6 +25,7 @@ require (
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/muesli/termenv v0.15.2 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/text v0.21.0 // indirect
Expand Down
12 changes: 12 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b h1:MnAM
github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
github.com/go-chi/chi/v5 v5.2.0 h1:Aj1EtB0qR2Rdo2dG4O94RIU35w2lvQSj6BRA4+qwFL0=
Expand All @@ -36,9 +38,17 @@ github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
github.com/peterbourgon/ff/v3 v3.4.0 h1:QBvM/rizZM1cB0p0lGMdmR7HxZeI/ZrBWB4DqLkMUBc=
github.com/peterbourgon/ff/v3 v3.4.0/go.mod h1:zjJVUhx+twciwfDl0zBcFzl4dW8axCRyXE/eKY9RztQ=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
Expand All @@ -47,3 +57,5 @@ golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
68 changes: 68 additions & 0 deletions pkg/dice.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package pkg

import (
"errors"
"fmt"
"math"
"math/rand/v2"
"regexp"
"strconv"
"strings"
)

var diceRegex = regexp.MustCompile(`(\d+)d(\d+)(\+\d+|\-\d+)?`)

type DiceRoll struct {
Count int
DiceSides int
Modifier int
}

func ParseDiceRoll(diceRoll string) (DiceRoll, error) {
// <int>d<int>[+|-<int>]
// (\d+)d(\d+)???
var d DiceRoll
matches := diceRegex.FindStringSubmatch(diceRoll)
if len(matches) < 3 {
return d, errors.New("string does not match expression")
}
parsed := make([]int, 3)
for idx, s := range matches[1:] {
if s == "" {
parsed[idx] = 0
continue
}
v, err := strconv.Atoi(s)
if err != nil {
return d, err
}
parsed[idx] = v
}
return DiceRoll{
Count: parsed[0],
DiceSides: parsed[1],
Modifier: parsed[2],
}, nil
}

func (dr DiceRoll) String() string {
var builder strings.Builder
base := fmt.Sprintf("%dd%d", dr.Count, dr.DiceSides)
builder.WriteString(base)
if dr.Modifier > 0 {
builder.WriteString("+" + strconv.Itoa(dr.Modifier))
}
if dr.Modifier < 0 {
absolute := int(math.Abs(float64(dr.Modifier)))
builder.WriteString("-" + strconv.Itoa(absolute))
}
return builder.String()
}

func (dr DiceRoll) Roll() int {
var result int
for x := 0; x < dr.Count; x++ {
result += rand.IntN(dr.DiceSides) + 1
}
return result + dr.Modifier
}
Loading
Loading