binary.mx raw
1 package event
2
3 import (
4 "bytes"
5 "io"
6
7 "crypto/secp256k1"
8 "git.smesh.lol/nostr/pkg/tag"
9 "git.smesh.lol/nostr/pkg/varint"
10 "git.smesh.lol/nostr/pkg/lol/chk"
11 )
12
13 func (ev *E) MarshalBinary(w io.Writer) {
14 _, _ = w.Write(ev.ID)
15 _, _ = w.Write(ev.Pubkey)
16 varint.Encode(w, uint64(ev.CreatedAt))
17 varint.Encode(w, uint64(ev.Kind))
18 if ev.Tags == nil {
19 varint.Encode(w, 0)
20 } else {
21 varint.Encode(w, uint64(ev.Tags.Len()))
22 for _, x := range ev.Tags.T {
23 varint.Encode(w, uint64(x.Len()))
24 for _, y := range x.T {
25 varint.Encode(w, uint64(len(y)))
26 _, _ = w.Write(y)
27 }
28 }
29 }
30 varint.Encode(w, uint64(len(ev.Content)))
31 _, _ = w.Write(ev.Content)
32 _, _ = w.Write(ev.Sig)
33 }
34
35 func (ev *E) MarshalBinaryToBytes(dst []byte) (out []byte) {
36 var buf *bytes.Buffer
37 if dst == nil {
38 size := 32 + 32 + 10 + 10 + 64
39 if ev.Tags != nil {
40 for _, t := range ev.Tags.T {
41 size += 10
42 for _, elem := range t.T {
43 size += 10 + len(elem)
44 }
45 }
46 }
47 size += 10 + len(ev.Content)
48 b := []byte{:0:size}
49 buf = bytes.NewBuffer(b)
50 } else {
51 buf = bytes.NewBuffer(dst[:0])
52 }
53 ev.MarshalBinary(buf)
54 return buf.Bytes()
55 }
56
57 // readFull reads exactly len(buf) bytes. io.Reader.Read may return a short
58 // count with a nil error, so a truncated frame used to decode into a
59 // zero-padded field and look like a valid event; io.ReadFull turns that into
60 // ErrUnexpectedEOF.
61 func readFull(r io.Reader, buf []byte) (err error) {
62 if _, err = io.ReadFull(r, buf); chk.E(err) {
63 return
64 }
65 return
66 }
67
68 func (ev *E) UnmarshalBinary(r io.Reader) (err error) {
69 ev.ID = []byte{:32}
70 if err = readFull(r, ev.ID); chk.E(err) {
71 return
72 }
73 ev.Pubkey = []byte{:32}
74 if err = readFull(r, ev.Pubkey); chk.E(err) {
75 return
76 }
77 var ca uint64
78 if ca, err = varint.Decode(r); chk.E(err) {
79 return
80 }
81 ev.CreatedAt = int64(ca)
82 var k uint64
83 if k, err = varint.Decode(r); chk.E(err) {
84 return
85 }
86 ev.Kind = uint16(k)
87 var nTags uint64
88 if nTags, err = varint.Decode(r); chk.E(err) {
89 return
90 }
91 // Declared outside the loops: a declaration in the body of a self-mutating
92 // method allocates in the sovereign arena on every iteration.
93 var nField uint64
94 var t *tag.T
95 var lenField uint64
96 var field []byte
97 if nTags == 0 {
98 ev.Tags = nil
99 } else {
100 ev.Tags = tag.NewSWithCap(int32(nTags))
101 for range nTags {
102 if nField, err = varint.Decode(r); chk.E(err) {
103 return
104 }
105 t = tag.NewWithCap(int32(nField))
106 for range nField {
107 if lenField, err = varint.Decode(r); chk.E(err) {
108 return
109 }
110 field = []byte{:lenField}
111 if err = readFull(r, field); chk.E(err) {
112 return
113 }
114 t.T = push(t.T, field)
115 }
116 ev.Tags.T = push(ev.Tags.T, t)
117 }
118 }
119 var cLen uint64
120 if cLen, err = varint.Decode(r); chk.E(err) {
121 return
122 }
123 ev.Content = []byte{:cLen}
124 if err = readFull(r, ev.Content); chk.E(err) {
125 return
126 }
127 ev.Sig = []byte{:secp256k1.SignatureSize}
128 if err = readFull(r, ev.Sig); chk.E(err) {
129 return
130 }
131 return
132 }
133