json.gno
2.64 Kb · 108 lines
1package connect4_v2
2
3import (
4 "strconv"
5 "strings"
6 "time"
7)
8
9// GameJSON returns {"now":<unix>,"game":<game>|null}. It is a read-only
10// accessor for clients querying over vm/qeval; now is the block time.
11func GameJSON(id int) string {
12 var b strings.Builder
13 writeNow(&b)
14 b.WriteString(`,"game":`)
15 if g := get(id); g != nil {
16 writeGame(&b, g)
17 } else {
18 b.WriteString("null")
19 }
20 b.WriteString("}")
21 return b.String()
22}
23
24// ActiveJSON returns {"now":<unix>,"games":[...]}: Open and Playing games in
25// id order, skipping offset and returning at most limit (clamped to 1-100).
26func ActiveJSON(offset, limit int) string {
27 if offset < 0 {
28 offset = 0
29 }
30 if limit < 1 {
31 limit = 1
32 }
33 if limit > 100 {
34 limit = 100
35 }
36 var b strings.Builder
37 writeNow(&b)
38 b.WriteString(`,"games":[`)
39 n := 0
40 active.IterateByOffset(offset, limit, func(_ string, v any) bool {
41 if n > 0 {
42 b.WriteString(",")
43 }
44 writeGame(&b, v.(*Game))
45 n++
46 return false
47 })
48 b.WriteString("]}")
49 return b.String()
50}
51
52func writeNow(b *strings.Builder) {
53 b.WriteString(`{"now":`)
54 b.WriteString(strconv.FormatInt(time.Now().Unix(), 10))
55}
56
57// writeGame emits one game. Every stored string is validated on write
58// (addresses by IsValid, the commitment as hex), so Quote is defence in depth.
59func writeGame(b *strings.Builder, g *Game) {
60 turnPlayer := ""
61 deadline := int64(0)
62 if g.Status == Playing {
63 deadline = g.deadline().Unix()
64 if g.Turn != 0 {
65 turnPlayer = g.player(g.Turn).String()
66 }
67 }
68 b.WriteString(`{"id":`)
69 b.WriteString(strconv.Itoa(g.ID))
70 writeStr(b, "creator", g.Creator.String())
71 writeStr(b, "opponent", g.Opponent.String())
72 writeStr(b, "acceptor", g.Acceptor.String())
73 writeNum(b, "stake", g.Stake)
74 writeNum(b, "fee", g.Fee)
75 writeNum(b, "expiresAt", g.ExpiresAt.Unix())
76 writeStr(b, "commitment", g.Commitment)
77 b.WriteString(`,"board":"`)
78 for c := 0; c < cols; c++ {
79 for r := 0; r < rows; r++ {
80 b.WriteByte('0' + g.Board[c][r])
81 }
82 }
83 b.WriteString(`"`)
84 writeNum(b, "turn", int64(g.Turn))
85 writeStr(b, "turnPlayer", turnPlayer)
86 writeNum(b, "moves", int64(g.Moves))
87 writeNum(b, "lastCol", int64(g.LastCol))
88 writeNum(b, "lastRow", int64(g.LastRow))
89 writeNum(b, "deadline", deadline)
90 writeStr(b, "status", g.Status.String())
91 writeStr(b, "winner", g.Winner.String())
92 b.WriteString("}")
93}
94
95// writeStr and writeNum append `,"k":v`; the caller writes the first field.
96func writeStr(b *strings.Builder, k, v string) {
97 b.WriteString(`,"`)
98 b.WriteString(k)
99 b.WriteString(`":`)
100 b.WriteString(strconv.Quote(v))
101}
102
103func writeNum(b *strings.Builder, k string, v int64) {
104 b.WriteString(`,"`)
105 b.WriteString(k)
106 b.WriteString(`":`)
107 b.WriteString(strconv.FormatInt(v, 10))
108}