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