eventenvelope.go raw
1 // Package eventenvelope is a codec for the event Submission request EVENT envelope
2 // (client) and event Result (to a REQ) from a relay.
3 package eventenvelope
4
5 import (
6 "io"
7
8 "next.orly.dev/pkg/nostr/encoders/envelopes"
9 "next.orly.dev/pkg/nostr/encoders/event"
10 "next.orly.dev/pkg/nostr/encoders/text"
11 "next.orly.dev/pkg/nostr/interfaces/codec"
12 "next.orly.dev/pkg/nostr/utils/constraints"
13 "next.orly.dev/pkg/nostr/utils/units"
14 "next.orly.dev/pkg/lol/chk"
15 "next.orly.dev/pkg/lol/errorf"
16 )
17
18 // L is the label associated with this type of codec.Envelope.
19 const L = "EVENT"
20
21 type I interface{ Id() []byte }
22
23 // Submission is a request from a client for a realy to store an event.
24 type Submission struct {
25 *event.E
26 }
27
28 var _ codec.Envelope = (*Submission)(nil)
29
30 // NewSubmission creates an empty new eventenvelope.Submission.
31 func NewSubmission() *Submission { return &Submission{E: &event.E{}} }
32
33 // NewSubmissionWith creates a new eventenvelope.Submission with a provided event.E.
34 func NewSubmissionWith(ev *event.E) *Submission { return &Submission{E: ev} }
35
36 // Label returns the label of a event eventenvelope.Submission envelope.
37 func (en *Submission) Label() string { return L }
38
39 func (en *Submission) Id() []byte { return en.E.ID }
40
41 // Write the Submission to a provided io.Writer.
42 func (en *Submission) Write(w io.Writer) (err error) {
43 _, err = w.Write(en.Marshal(nil))
44 return
45 }
46
47 // Marshal an event Submission envelope in minified JSON, appending to a
48 // provided destination slice.
49 func (en *Submission) Marshal(dst []byte) (b []byte) {
50 var err error
51 // if the destination capacity is not large enough, allocate a new
52 // destination slice.
53 if en.EstimateSize() >= cap(dst) {
54 dst = make([]byte, 0, en.EstimateSize()+units.Kb)
55 }
56 b = dst
57 b = envelopes.Marshal(
58 b, L,
59 func(bst []byte) (o []byte) {
60 o = bst
61 o = en.E.Marshal(o)
62 return
63 },
64 )
65 _ = err
66 return
67 }
68
69 // Unmarshal an event eventenvelope.Submission from minified JSON, returning the
70 // remainder after the end of the envelope.
71 func (en *Submission) Unmarshal(b []byte) (r []byte, err error) {
72 r = b
73 en.E = event.New()
74 if r, err = en.E.Unmarshal(r); chk.T(err) {
75 return
76 }
77 // after parsing the event object, r points just after the event JSON
78 // now skip to the end of the envelope (consume comma/closing bracket etc.)
79 if r, err = envelopes.SkipToTheEnd(r); chk.E(err) {
80 return
81 }
82 return
83 }
84
85 // ParseSubmission reads an event envelope Submission from minified JSON into a newly
86 // allocated eventenvelope.Submission.
87 func ParseSubmission(b []byte) (t *Submission, rem []byte, err error) {
88 t = NewSubmission()
89 if rem, err = t.Unmarshal(b); chk.E(err) {
90 return
91 }
92 return
93 }
94
95 // Result is an event matching a filter associated with a subscription.
96 type Result struct {
97 Subscription []byte
98 Event *event.E
99 }
100
101 var _ codec.Envelope = (*Result)(nil)
102
103 // NewResult creates a new empty eventenvelope.Result.
104 func NewResult() *Result { return &Result{} }
105
106 // NewResultWith creates a new eventenvelope.Result with a provided
107 // subscription.Id string and event.E.
108 func NewResultWith[V constraints.Bytes](s V, ev *event.E) (
109 res *Result, err error,
110 ) {
111 if len(s) < 0 || len(s) > 64 {
112 err = errorf.E("subscription id must be length > 0 and <= 64")
113 return
114 }
115 return &Result{[]byte(s), ev}, nil
116 }
117
118 func (en *Result) Id() []byte { return en.Event.ID }
119
120 // Label returns the label of a event eventenvelope.Result envelope.
121 func (en *Result) Label() string { return L }
122
123 // Write the eventenvelope.Result to a provided io.Writer.
124 func (en *Result) Write(w io.Writer) (err error) {
125 _, err = w.Write(en.Marshal(nil))
126 return
127 }
128
129 // Marshal an eventenvelope.Result envelope in minified JSON, appending to a
130 // provided destination slice.
131 func (en *Result) Marshal(dst []byte) (b []byte) {
132 // if the destination capacity is not large enough, allocate a new
133 // destination slice.
134 if en.Event.EstimateSize() >= cap(dst) {
135 dst = make([]byte, 0, en.Event.EstimateSize()+units.Kb)
136 }
137 b = dst
138 var err error
139 b = envelopes.Marshal(
140 b, L,
141 func(bst []byte) (o []byte) {
142 o = bst
143 o = append(o, '"')
144 o = append(o, en.Subscription...)
145 o = append(o, '"')
146 o = append(o, ',')
147 o = en.Event.Marshal(o)
148 return
149 },
150 )
151 _ = err
152 return
153 }
154
155 // Unmarshal an event Result envelope from minified JSON, returning the
156 // remainder after the end of the envelope.
157 func (en *Result) Unmarshal(b []byte) (r []byte, err error) {
158 r = b
159 if en.Subscription, r, err = text.UnmarshalQuoted(r); chk.E(err) {
160 return
161 }
162 en.Event = event.New()
163 if r, err = en.Event.Unmarshal(r); err != nil {
164 return
165 }
166 if r, err = envelopes.SkipToTheEnd(r); chk.E(err) {
167 return
168 }
169 return
170 }
171
172 // ParseResult allocates a new eventenvelope.Result and unmarshalls an EVENT
173 // envelope into it.
174 func ParseResult(b []byte) (t *Result, rem []byte, err error) {
175 t = NewResult()
176 if rem, err = t.Unmarshal(b); err != nil {
177 return
178 }
179 return
180 }
181