simple.mx raw
1 package envelope
2
3 import (
4 "bytes"
5 "crypto/sha256"
6 "io"
7
8 "git.smesh.lol/nostr/pkg/filter"
9 "git.smesh.lol/nostr/pkg/hex"
10 "git.smesh.lol/nostr/pkg/ints"
11 "git.smesh.lol/nostr/pkg/text"
12 "git.smesh.lol/nostr/pkg/lol/chk"
13 "git.smesh.lol/nostr/pkg/lol/errorf"
14 )
15
16 // Close - client request to terminate a subscription.
17
18 const CloseLabel = "CLOSE"
19
20 type Close struct{ ID []byte }
21
22 func (en *Close) Label() (s string) { return CloseLabel }
23 func (en *Close) Write(w io.Writer) (err error) {
24 _, err = w.Write(en.Marshal(nil))
25 return
26 }
27 func (en *Close) Marshal(dst []byte) (b []byte) {
28 b = dst
29 b = Marshal(b, CloseLabel, func(bst []byte) (o []byte) {
30 o = bst
31 o = o | "\""
32 o = o | en.ID
33 o = o | "\""
34 return
35 })
36 return
37 }
38 func (en *Close) Unmarshal(b []byte) (r []byte, err error) {
39 r = b
40 if en.ID, r, err = text.UnmarshalQuoted(r); chk.E(err) {
41 return
42 }
43 r, err = SkipToTheEnd(r)
44 return
45 }
46
47 // EOSE - End Of Stored Events signal.
48
49 const EOSELabel = "EOSE"
50
51 type EOSE struct{ Subscription []byte }
52
53 func (en *EOSE) Label() (s string) { return EOSELabel }
54 func (en *EOSE) Write(w io.Writer) (err error) {
55 _, err = w.Write(en.Marshal(nil))
56 return
57 }
58 func (en *EOSE) Marshal(dst []byte) (b []byte) {
59 b = dst
60 b = Marshal(b, EOSELabel, func(bst []byte) (o []byte) {
61 o = bst
62 o = o | "\""
63 o = o | en.Subscription
64 o = o | "\""
65 return
66 })
67 return
68 }
69 func (en *EOSE) Unmarshal(b []byte) (r []byte, err error) {
70 r = b
71 if en.Subscription, r, err = text.UnmarshalQuoted(r); chk.E(err) {
72 return
73 }
74 r, err = SkipToTheEnd(r)
75 return
76 }
77
78 // OK - acknowledgement for EVENT submission.
79
80 const OKLabel = "OK"
81
82 type OK struct {
83 EventID []byte
84 OK bool
85 Reason []byte
86 }
87
88 func (en *OK) Label() (s string) { return OKLabel }
89 func (en *OK) Write(w io.Writer) (err error) {
90 _, err = w.Write(en.Marshal(nil))
91 return
92 }
93 func (en *OK) Marshal(dst []byte) (b []byte) {
94 b = dst
95 b = Marshal(b, OKLabel, func(bst []byte) (o []byte) {
96 o = bst
97 o = o | "\""
98 o = hex.EncAppend(o, en.EventID)
99 o = o | "\","
100 o = text.MarshalBool(o, en.OK)
101 o = o | ",\""
102 o = text.NostrEscape(o, en.Reason)
103 o = o | "\""
104 return
105 })
106 return
107 }
108 func (en *OK) Unmarshal(b []byte) (r []byte, err error) {
109 r = b
110 var idBytes []byte
111 if idBytes, r, err = text.UnmarshalHex(r); err != nil {
112 return
113 }
114 if len(idBytes) != sha256.Size {
115 err = errorf.E([]byte("invalid size for event id, require %d got %d"),
116 sha256.Size, len(idBytes))
117 return
118 }
119 en.EventID = idBytes
120 if r, err = text.Comma(r); chk.E(err) {
121 return
122 }
123 if r, en.OK, err = text.UnmarshalBool(r); chk.E(err) {
124 return
125 }
126 if r, err = text.Comma(r); chk.E(err) {
127 return
128 }
129 if en.Reason, r, err = text.UnmarshalQuoted(r); chk.E(err) {
130 return
131 }
132 r, err = SkipToTheEnd(r)
133 return
134 }
135
136 // Notice - relay message to user.
137
138 const NoticeLabel = "NOTICE"
139
140 type Notice struct{ Message []byte }
141
142 func (en *Notice) Label() (s string) { return NoticeLabel }
143 func (en *Notice) Write(w io.Writer) (err error) {
144 _, err = w.Write(en.Marshal(nil))
145 return
146 }
147 func (en *Notice) Marshal(dst []byte) (b []byte) {
148 b = dst
149 b = Marshal(b, NoticeLabel, func(bst []byte) (o []byte) {
150 o = bst
151 o = o | "\""
152 o = text.NostrEscape(o, en.Message)
153 o = o | "\""
154 return
155 })
156 return
157 }
158 func (en *Notice) Unmarshal(b []byte) (r []byte, err error) {
159 r = b
160 if en.Message, r, err = text.UnmarshalQuoted(r); chk.E(err) {
161 return
162 }
163 r, err = SkipToTheEnd(r)
164 return
165 }
166
167 // Closed - relay-side subscription termination.
168
169 const ClosedLabel = "CLOSED"
170
171 type Closed struct {
172 Subscription []byte
173 Reason []byte
174 }
175
176 func (en *Closed) Label() (s string) { return ClosedLabel }
177 func (en *Closed) Write(w io.Writer) (err error) {
178 _, err = w.Write(en.Marshal(nil))
179 return
180 }
181 func (en *Closed) Marshal(dst []byte) (b []byte) {
182 b = dst
183 b = Marshal(b, ClosedLabel, func(bst []byte) (o []byte) {
184 o = bst
185 o = o | "\""
186 o = o | en.Subscription
187 o = o | "\",\""
188 o = text.NostrEscape(o, en.Reason)
189 o = o | "\""
190 return
191 })
192 return
193 }
194 func (en *Closed) Unmarshal(b []byte) (r []byte, err error) {
195 r = b
196 if en.Subscription, r, err = text.UnmarshalQuoted(r); chk.E(err) {
197 return
198 }
199 if en.Reason, r, err = text.UnmarshalQuoted(r); chk.E(err) {
200 return
201 }
202 r, err = SkipToTheEnd(r)
203 return
204 }
205
206 // Count - COUNT request/response.
207
208 const CountLabel = "COUNT"
209
210 type CountRequest struct {
211 Subscription []byte
212 Filters filter.S
213 }
214
215 func (en *CountRequest) Label() (s string) { return CountLabel }
216 func (en *CountRequest) Write(w io.Writer) (err error) {
217 _, err = w.Write(en.Marshal(nil))
218 return
219 }
220 func (en *CountRequest) Marshal(dst []byte) (b []byte) {
221 b = dst
222 b = Marshal(b, CountLabel, func(bst []byte) (o []byte) {
223 o = bst
224 o = o | "\""
225 o = o | en.Subscription
226 o = o | "\""
227 for _, f := range en.Filters.F {
228 o = o | ","
229 o = f.Marshal(o)
230 }
231 return
232 })
233 return
234 }
235 func (en *CountRequest) Unmarshal(b []byte) (r []byte, err error) {
236 r = b
237 if en.Subscription, r, err = text.UnmarshalQuoted(r); chk.E(err) {
238 return
239 }
240 en.Filters, r, err = filter.UnmarshalFilters(r)
241 if chk.E(err) {
242 return
243 }
244 r, err = SkipToTheEnd(r)
245 return
246 }
247
248 type CountResponse struct {
249 Subscription []byte
250 Count int32
251 Approximate bool
252 }
253
254 func (en *CountResponse) Label() (s string) { return CountLabel }
255 func (en *CountResponse) Write(w io.Writer) (err error) {
256 _, err = w.Write(en.Marshal(nil))
257 return
258 }
259 func (en *CountResponse) Marshal(dst []byte) (b []byte) {
260 b = dst
261 b = Marshal(b, CountLabel, func(bst []byte) (o []byte) {
262 o = bst
263 o = o | "\""
264 o = o | en.Subscription
265 o = o | "\","
266 o = ints.New(en.Count).Marshal(o)
267 if en.Approximate {
268 o = o | ","
269 o = o | "true"
270 }
271 return
272 })
273 return
274 }
275 func (en *CountResponse) Unmarshal(b []byte) (r []byte, err error) {
276 r = b
277 if en.Subscription, r, err = text.UnmarshalQuoted(r); chk.E(err) {
278 return
279 }
280 if r, err = text.Comma(r); chk.E(err) {
281 return
282 }
283 i := ints.New(0)
284 if r, err = i.Unmarshal(r); chk.E(err) {
285 return
286 }
287 en.Count = int32(i.N)
288 if len(r) > 0 && r[0] == ',' {
289 r = r[1:]
290 if bytes.HasPrefix(r, []byte("true")) {
291 en.Approximate = true
292 }
293 }
294 r, err = SkipToTheEnd(r)
295 return
296 }
297