envelope.mx raw
1 // Package envelope provides marshal/unmarshal for all nostr protocol envelope types.
2 package envelope
3
4 import (
5 "io"
6 )
7
8 // Identify extracts the label from a nostr envelope JSON array.
9 func Identify(b []byte) (t string, rem []byte, err error) {
10 var openBrackets, openQuotes, afterQuotes bool
11 var label []byte
12 rem = b
13 for ; len(rem) > 0; rem = rem[1:] {
14 if !openBrackets && rem[0] == '[' {
15 openBrackets = true
16 } else if openBrackets {
17 if !openQuotes && rem[0] == '"' {
18 openQuotes = true
19 } else if afterQuotes {
20 if rem[0] == ',' {
21 rem = rem[1:]
22 return
23 }
24 } else if openQuotes {
25 for i := range rem {
26 if rem[i] == '"' {
27 label = rem[:i]
28 rem = rem[i:]
29 t = string(label)
30 afterQuotes = true
31 break
32 }
33 }
34 }
35 }
36 }
37 return
38 }
39
40 // Marshaller is a function signature for marshalling envelope content.
41 type Marshaller func(dst []byte) (b []byte)
42
43 // Marshal wraps content in a JSON array envelope with the given label.
44 func Marshal(dst []byte, label string, m Marshaller) (b []byte) {
45 b = dst
46 b = append(b, '[', '"')
47 b = append(b, label...)
48 b = append(b, '"', ',')
49 b = m(b)
50 b = append(b, ']')
51 return
52 }
53
54 // SkipToTheEnd scans forward to the closing bracket of an envelope.
55 func SkipToTheEnd(dst []byte) (rem []byte, err error) {
56 if len(dst) == 0 {
57 return
58 }
59 rem = dst
60 for ; len(rem) > 0; rem = rem[1:] {
61 if rem[0] == ']' {
62 rem = rem[:0]
63 return
64 }
65 }
66 err = io.EOF
67 return
68 }
69