state.go raw
1 package main
2
3 import (
4 "common/helpers"
5 "common/jsbridge/subtle"
6 "common/jsbridge/sw"
7 )
8
9 // Shared state not yet assigned to a specific domain.
10 var (
11 dmSubIDs map[string]bool
12 dmRelayURLs []string
13 cryptoCBs map[int]func(string, string)
14 nextCryptoID int
15 )
16
17 func initSharedState() {
18 dmSubIDs = make(map[string]bool)
19 cryptoCBs = make(map[int]func(string, string))
20 }
21
22 // --- Shared utilities ---
23
24 func sendToClient(clientID, msg string) {
25 sw.GetClientByID(clientID, func(c sw.Client, ok bool) {
26 if ok {
27 sw.PostMessageJSON(c, msg)
28 }
29 })
30 }
31
32 func broadcastToClients(msg string) {
33 sw.MatchClients(func(c sw.Client) {
34 sw.PostMessageJSON(c, msg)
35 })
36 }
37
38 func jstr(s string) string { return helpers.JsonString(s) }
39
40 func hexTo32(s string) [32]byte {
41 out, _ := helpers.HexDecode32(s)
42 return out
43 }
44
45 func random32() [32]byte {
46 var b [32]byte
47 subtle.RandomBytes(b[:])
48 return b
49 }
50
51 // mw is a JSON array message walker for parsing client messages.
52 type mw struct {
53 s string
54 i int
55 }
56
57 func newMW(s string) mw {
58 w := mw{s: s}
59 for w.i < len(s) && s[w.i] != '[' {
60 w.i++
61 }
62 if w.i < len(s) {
63 w.i++
64 }
65 return w
66 }
67
68 func (w *mw) sep() {
69 for w.i < len(w.s) {
70 c := w.s[w.i]
71 if c != ' ' && c != '\n' && c != '\r' && c != '\t' && c != ',' {
72 break
73 }
74 w.i++
75 }
76 }
77
78 func (w *mw) str() string {
79 w.sep()
80 if w.i >= len(w.s) || w.s[w.i] != '"' {
81 return ""
82 }
83 w.i++
84 start := w.i
85 for w.i < len(w.s) && w.s[w.i] != '"' {
86 if w.s[w.i] == '\\' {
87 w.i++
88 }
89 w.i++
90 }
91 if w.i >= len(w.s) {
92 return ""
93 }
94 result := w.s[start:w.i]
95 w.i++
96 return result
97 }
98
99 func (w *mw) num() int64 {
100 w.sep()
101 neg := false
102 if w.i < len(w.s) && w.s[w.i] == '-' {
103 neg = true
104 w.i++
105 }
106 var n int64
107 for w.i < len(w.s) && w.s[w.i] >= '0' && w.s[w.i] <= '9' {
108 n = n*10 + int64(w.s[w.i]-'0')
109 w.i++
110 }
111 if neg {
112 n = -n
113 }
114 return n
115 }
116
117 func (w *mw) raw() string {
118 w.sep()
119 start := w.i
120 w.i = skipval(w.s, w.i)
121 if w.i < 0 {
122 w.i = len(w.s)
123 return ""
124 }
125 return w.s[start:w.i]
126 }
127
128 func (w *mw) strs() []string {
129 w.sep()
130 if w.i >= len(w.s) || w.s[w.i] != '[' {
131 return nil
132 }
133 w.i++
134 var out []string
135 for {
136 w.sep()
137 if w.i >= len(w.s) {
138 return out
139 }
140 if w.s[w.i] == ']' {
141 w.i++
142 return out
143 }
144 if w.s[w.i] != '"' {
145 return out
146 }
147 w.i++
148 start := w.i
149 for w.i < len(w.s) && w.s[w.i] != '"' {
150 if w.s[w.i] == '\\' {
151 w.i++
152 }
153 w.i++
154 }
155 if w.i < len(w.s) {
156 out = append(out, w.s[start:w.i])
157 w.i++
158 }
159 }
160 }
161
162 func skipval(s string, i int) int {
163 if i >= len(s) {
164 return -1
165 }
166 switch s[i] {
167 case '"':
168 i++
169 for i < len(s) {
170 if s[i] == '\\' {
171 i += 2
172 continue
173 }
174 if s[i] == '"' {
175 return i + 1
176 }
177 i++
178 }
179 return -1
180 case '{':
181 return skipBrack(s, i, '{', '}')
182 case '[':
183 return skipBrack(s, i, '[', ']')
184 case 't':
185 if i+4 <= len(s) {
186 return i + 4
187 }
188 return -1
189 case 'f':
190 if i+5 <= len(s) {
191 return i + 5
192 }
193 return -1
194 case 'n':
195 if i+4 <= len(s) {
196 return i + 4
197 }
198 return -1
199 default:
200 for i < len(s) && s[i] != ',' && s[i] != '}' && s[i] != ']' && s[i] != ' ' && s[i] != '\n' {
201 i++
202 }
203 return i
204 }
205 }
206
207 func skipBrack(s string, i int, open, close byte) int {
208 depth := 1
209 i++
210 inStr := false
211 for i < len(s) && depth > 0 {
212 if inStr {
213 if s[i] == '\\' {
214 i++
215 } else if s[i] == '"' {
216 inStr = false
217 }
218 } else {
219 switch s[i] {
220 case '"':
221 inStr = true
222 case open:
223 depth++
224 case close:
225 depth--
226 }
227 }
228 i++
229 }
230 if depth != 0 {
231 return -1
232 }
233 return i
234 }
235