all doc comments for envelopes

This commit is contained in:
2025-03-30 08:25:32 -01:06
parent bfbe357756
commit 93e09b1592
14 changed files with 279 additions and 73 deletions

View File

@@ -32,7 +32,9 @@ var (
// include relay hints to find the event, and the author's npub.
NeventHRP = []byte("nevent")
// NentityHRP is the Human Readable Prefix (HRP) for a nostr is a generic nostr entity, which may include relay hints to find the event, and the author's npub.
// NentityHRP is the Human Readable Prefix (HRP) for a nostr is a generic nostr
// entity, which may include relay hints to find the event, and the author's
// npub.
NentityHRP = []byte("naddr")
)

View File

@@ -11,6 +11,7 @@ import (
"realy.lol/text"
)
// L is the label associated with this type of codec.Envelope.
const L = "AUTH"
// Challenge is the relay-sent message containing a relay-chosen random string
@@ -41,8 +42,8 @@ func (en *Challenge) Write(w io.Writer) (err error) {
return
}
// Marshal a Challenge to minified JSON. Note that this ensures correct string
// escaping on the challenge field.
// Marshal a Challenge to minified JSON, appending to a provided destination
// slice. Note that this ensures correct string escaping on the challenge field.
func (en *Challenge) Marshal(dst []byte) (b []byte) {
b = dst
var err error
@@ -58,8 +59,9 @@ func (en *Challenge) Marshal(dst []byte) (b []byte) {
return
}
// Unmarshal a Challenge from minified JSON. Note that this ensures the
// challenge string was correctly escaped by NIP-01 escaping rules.
// Unmarshal a Challenge from minified JSON, returning the remainder after the
// end of the envelope. Note that this ensures the challenge string was
// correctly escaped by NIP-01 escaping rules.
func (en *Challenge) Unmarshal(b []byte) (r []byte, err error) {
r = b
if en.Challenge, r, err = text.UnmarshalQuoted(r); chk.E(err) {
@@ -109,8 +111,8 @@ func (en *Response) Write(w io.Writer) (err error) {
return
}
// Marshal a Response to minified JSON. Note that this ensures correct string
// escaping on the challenge field.
// Marshal a Response to minified JSON, appending to a provided destination
// slice. Note that this ensures correct string escaping on the challenge field.
func (en *Response) Marshal(dst []byte) (b []byte) {
var err error
if en == nil {
@@ -127,8 +129,9 @@ func (en *Response) Marshal(dst []byte) (b []byte) {
return
}
// Unmarshal a Response from minified JSON. Note that this ensures the
// challenge string was correctly escaped by NIP-01 escaping rules.
// Unmarshal a Response from minified JSON, returning the remainder after the en
// of the envelope. Note that this ensures the challenge string was correctly
// escaped by NIP-01 escaping rules.
func (en *Response) Unmarshal(b []byte) (r []byte, err error) {
r = b
// literally just unmarshal the event

View File

@@ -12,8 +12,12 @@ import (
"realy.lol/text"
)
// L is the label associated with this type of codec.Envelope.
const L = "CLOSED"
// T is a CLOSED envelope, which is a signal that a subscription has been
// stopped on the relay side for some reason. Primarily this is for auth and can
// be for other things like rate limiting.
type T struct {
Subscription *subscription.Id
Reason []byte
@@ -21,11 +25,21 @@ type T struct {
var _ codec.Envelope = (*T)(nil)
func New() *T { return &T{Subscription: subscription.NewStd()} }
func NewFrom(id *subscription.Id, msg []byte) *T { return &T{Subscription: id, Reason: msg} }
func (en *T) Label() string { return L }
func (en *T) ReasonString() string { return string(en.Reason) }
// New creates an empty new T.
func New() *T {
return &T{Subscription: subscription.NewStd()}
}
// NewFrom creates a new T populated with subscription Id and Reason.
func NewFrom(id *subscription.Id, msg []byte) *T { return &T{Subscription: id, Reason: msg} }
// Label returns the label of a CLOSED envelope.
func (en *T) Label() string { return L }
// ReasonString returns the Reason in the form of a string.
func (en *T) ReasonString() string { return string(en.Reason) }
// Write the CLOSED T to a provided io.Writer.
func (en *T) Write(w io.Writer) (err error) {
var b []byte
b = en.Marshal(b)
@@ -33,6 +47,9 @@ func (en *T) Write(w io.Writer) (err error) {
return
}
// Marshal a CLOSED T envelope in minified JSON, appending to a provided
// destination slice. Note that this ensures correct string escaping on the
// Reason field.
func (en *T) Marshal(dst []byte) (b []byte) {
b = dst
b = envelopes.Marshal(b, L,
@@ -48,6 +65,9 @@ func (en *T) Marshal(dst []byte) (b []byte) {
return
}
// Unmarshal a CLOSED T from minified JSON, returning the remainder after the end
// of the envelope. Note that this ensures the Reason string is correctly
// unescaped by NIP-01 escaping rules.
func (en *T) Unmarshal(b []byte) (r []byte, err error) {
r = b
if en.Subscription, err = subscription.NewId([]byte{0}); chk.E(err) {
@@ -65,6 +85,7 @@ func (en *T) Unmarshal(b []byte) (r []byte, err error) {
return
}
// Parse reads a CLOSED T from minified JSON into a newly allocated T.
func Parse(b []byte) (t *T, rem []byte, err error) {
t = New()
if rem, err = t.Unmarshal(b); chk.E(err) {

View File

@@ -10,22 +10,34 @@ import (
"realy.lol/subscription"
)
// L is the label associated with this type of codec.Envelope.
const L = "CLOSE"
// T is a CLOSE envelope, which is a signal from client to relay to stop a
// specified subscription.
type T struct {
ID *subscription.Id
}
var _ codec.Envelope = (*T)(nil)
func New() *T { return &T{ID: subscription.NewStd()} }
// New creates an empty new standard formatted T.
func New() *T { return &T{ID: subscription.NewStd()} }
// NewFrom creates a new T populated with subscription Id.
func NewFrom(id *subscription.Id) *T { return &T{ID: id} }
func (en *T) Label() string { return L }
// Label returns the label of a CLOSE envelope.
func (en *T) Label() string { return L }
// Write the CLOSE T to a provided io.Writer.
func (en *T) Write(w io.Writer) (err error) {
_, err = w.Write(en.Marshal(nil))
return
}
// Marshal a CLOSE T envelope in minified JSON, appending to a provided
// destination slice.
func (en *T) Marshal(dst []byte) (b []byte) {
b = dst
b = envelopes.Marshal(b, L,
@@ -37,6 +49,8 @@ func (en *T) Marshal(dst []byte) (b []byte) {
return
}
// Unmarshal a CLOSE T from minified JSON, returning the remainder after the end
// of the envelope.
func (en *T) Unmarshal(b []byte) (r []byte, err error) {
r = b
if en.ID, err = subscription.NewId([]byte{0}); chk.E(err) {
@@ -51,6 +65,7 @@ func (en *T) Unmarshal(b []byte) (r []byte, err error) {
return
}
// Parse reads a CLOSE T in minified JSON into a newly allocated T.
func Parse(b []byte) (t *T, rem []byte, err error) {
t = New()
if rem, err = t.Unmarshal(b); chk.E(err) {

View File

@@ -14,8 +14,13 @@ import (
"realy.lol/text"
)
// L is the label associated with this type of codec.Envelope.
const L = "COUNT"
// Request is a COUNT envelope sent by a client to request a count of results.
// This is a stupid idea because it costs as much processing as fetching the
// events, but doesn't provide the means to actually get them (the HTTP API
// /filter does this by returning the actual event Ids).
type Request struct {
Subscription *subscription.Id
Filters *filters.T
@@ -23,15 +28,23 @@ type Request struct {
var _ codec.Envelope = (*Request)(nil)
// New creates a new Request with a standard style subscription.Id and empty filter.
func New() *Request {
return &Request{Subscription: subscription.NewStd(),
Filters: filters.New()}
}
// NewRequest creates a new Request with a provided subscription.Id and
// filter.T.
func NewRequest(id *subscription.Id, filters *filters.T) *Request {
return &Request{Subscription: id,
Filters: filters}
}
// Label returns the label of a CLOSED envelope.
func (en *Request) Label() string { return L }
// Write the Request to a provided io.Writer.
func (en *Request) Write(w io.Writer) (err error) {
var b []byte
b = en.Marshal(b)
@@ -39,6 +52,8 @@ func (en *Request) Write(w io.Writer) (err error) {
return
}
// Marshal a Request appended to the provided destination slice as minified
// JSON.
func (en *Request) Marshal(dst []byte) (b []byte) {
var err error
b = dst
@@ -54,6 +69,8 @@ func (en *Request) Marshal(dst []byte) (b []byte) {
return
}
// Unmarshal a Request from minified JSON, returning the remainder after the end
// of the envelope.
func (en *Request) Unmarshal(b []byte) (r []byte, err error) {
r = b
if en.Subscription, err = subscription.NewId([]byte{0}); chk.E(err) {
@@ -72,6 +89,7 @@ func (en *Request) Unmarshal(b []byte) (r []byte, err error) {
return
}
// ParseRequest reads a Request in minified JSON into a newly allocated Request.
func ParseRequest(b []byte) (t *Request, rem []byte, err error) {
t = New()
if rem, err = t.Unmarshal(b); chk.E(err) {
@@ -80,6 +98,8 @@ func ParseRequest(b []byte) (t *Request, rem []byte, err error) {
return
}
// Response is a COUNT Response returning a count and approximate flag
// associated with the REQ subscription.Id.
type Response struct {
ID *subscription.Id
Count int
@@ -88,8 +108,16 @@ type Response struct {
var _ codec.Envelope = (*Response)(nil)
// NewResponse creates a new empty COUNT Response with a standard formatted
// subscription.Id.
func NewResponse() *Response { return &Response{ID: subscription.NewStd()} }
func NewResponseFrom[V string | []byte](s V, cnt int, approx ...bool) (res *Response, err error) {
// NewResponseFrom creates a new response with provided string for the
// subscription.Id, a count and optional variadic approximate flag, which is
// otherwise false and does not get rendered into the JSON.
func NewResponseFrom[V string | []byte](s V, cnt int,
approx ...bool) (res *Response, err error) {
var a bool
if len(approx) > 0 {
a = approx[0]
@@ -100,12 +128,18 @@ func NewResponseFrom[V string | []byte](s V, cnt int, approx ...bool) (res *Resp
}
return &Response{subscription.MustNew(s), cnt, a}, nil
}
// Label returns the COUNT label associated with a Response.
func (en *Response) Label() string { return L }
// Write a Response to a provided io.Writer as minified JSON.
func (en *Response) Write(w io.Writer) (err error) {
_, err = w.Write(en.Marshal(nil))
return
}
// Marshal a COUNT Response envelope in minified JSON, appending to a provided
// destination slice.
func (en *Response) Marshal(dst []byte) (b []byte) {
var err error
b = dst
@@ -126,6 +160,8 @@ func (en *Response) Marshal(dst []byte) (b []byte) {
return
}
// Unmarshal a COUNT Response from minified JSON, returning the remainder after
// the end of the envelope.
func (en *Response) Unmarshal(b []byte) (r []byte, err error) {
r = b
var inID, inCount bool
@@ -185,6 +221,8 @@ func (en *Response) Unmarshal(b []byte) (r []byte, err error) {
return
}
// Parse reads a Count Response in minified JSON into a newly allocated
// Response.
func Parse(b []byte) (t *Response, rem []byte, err error) {
t = NewResponse()
if rem, err = t.Unmarshal(b); chk.E(err) {

View File

@@ -12,23 +12,38 @@ import (
"realy.lol/subscription"
)
// L is the label associated with this type of codec.Envelope.
const L = "EOSE"
// T is an EOSE envelope, that signals the end of events that are stored and the
// beginning of a subscription. This is necessitated by the confusing
// multiplexing of websockets for multiple requests, and an ugly merging of two
// distinct API calls, filter and subscribe.
type T struct {
Subscription *subscription.Id
}
var _ codec.Envelope = (*T)(nil)
func New() *T { return &T{Subscription: subscription.NewStd()} }
func NewFrom(id *subscription.Id) *T { return &T{Subscription: id} }
func (en *T) Label() string { return L }
// New creates a new EOSE T with a standard form subscription.Id.
func New() *T {
return &T{Subscription: subscription.NewStd()}
}
// NewFrom creates a new EOSE T using a provided subscription.Id.
func NewFrom(id *subscription.Id) *T { return &T{Subscription: id} }
// Label returns the label of a EOSE envelope.
func (en *T) Label() string { return L }
// Write the EOSE T to a provided io.Writer.
func (en *T) Write(w io.Writer) (err error) {
_, err = w.Write(en.Marshal(nil))
return
}
// Marshal a EOSE T envelope in minified JSON, appending to a provided
// destination slice.
func (en *T) Marshal(dst []byte) (b []byte) {
var err error
b = dst
@@ -43,6 +58,8 @@ func (en *T) Marshal(dst []byte) (b []byte) {
return
}
// Unmarshal a EOSE T from minified JSON, returning the remainder after the
// end of the envelope.
func (en *T) Unmarshal(b []byte) (r []byte, err error) {
r = b
if en.Subscription, err = subscription.NewId([]byte{0}); chk.E(err) {
@@ -57,6 +74,7 @@ func (en *T) Unmarshal(b []byte) (r []byte, err error) {
return
}
// Parse reads a EOSE T in minified JSON into a newly allocated T.
func Parse(b []byte) (t *T, rem []byte, err error) {
t = New()
if rem, err = t.Unmarshal(b); chk.E(err) {

View File

@@ -11,6 +11,7 @@ import (
"realy.lol/subscription"
)
// L is the label associated with this type of codec.Envelope.
const L = "EVENT"
// Submission is a request from a client for a realy to store an event.
@@ -20,15 +21,23 @@ type Submission struct {
var _ codec.Envelope = (*Submission)(nil)
func NewSubmission() *Submission { return &Submission{T: &event.T{}} }
func NewSubmissionWith(ev *event.T) *Submission { return &Submission{T: ev} }
func (en *Submission) Label() string { return L }
// NewSubmission creates an empty new Submission.
func NewSubmission() *Submission { return &Submission{T: &event.T{}} }
// NewSubmissionWith creates a new Submission with a provided event.T.
func NewSubmissionWith(ev *event.T) *Submission { return &Submission{T: ev} }
// Label returns the label of a event Submission envelope.
func (en *Submission) Label() string { return L }
// Write the Submission to a provided io.Writer.
func (en *Submission) Write(w io.Writer) (err error) {
_, err = w.Write(en.Marshal(nil))
return
}
// Marshal a event Submission T envelope in minified JSON, appending to a provided
// destination slice.
func (en *Submission) Marshal(dst []byte) (b []byte) {
var err error
b = dst
@@ -42,6 +51,8 @@ func (en *Submission) Marshal(dst []byte) (b []byte) {
return
}
// Unmarshal an event Submission from minified JSON, returning the remainder
// after the end of the envelope.
func (en *Submission) Unmarshal(b []byte) (r []byte, err error) {
r = b
en.T = event.New()
@@ -55,6 +66,8 @@ func (en *Submission) Unmarshal(b []byte) (r []byte, err error) {
return
}
// ParseSubmission reads an event Submission from minified JSON into a newly
// allocated Submission.
func ParseSubmission(b []byte) (t *Submission, rem []byte, err error) {
t = NewSubmission()
if rem, err = t.Unmarshal(b); chk.E(err) {
@@ -71,7 +84,11 @@ type Result struct {
var _ codec.Envelope = (*Result)(nil)
// NewResult creates a new empty event Result.
func NewResult() *Result { return &Result{} }
// NewResultWith creates a new Result with a provided subscription.Id string and
// event.T.
func NewResultWith[V string | []byte](s V, ev *event.T) (res *Result, err error) {
if len(s) < 0 || len(s) > 64 {
err = errorf.E("subscription id must be length > 0 and <= 64")
@@ -79,13 +96,18 @@ func NewResultWith[V string | []byte](s V, ev *event.T) (res *Result, err error)
}
return &Result{subscription.MustNew(s), ev}, nil
}
// Label returns the label of a event Result envelope.
func (en *Result) Label() string { return L }
// Write the event Result T to a provided io.Writer.
func (en *Result) Write(w io.Writer) (err error) {
_, err = w.Write(en.Marshal(nil))
return
}
// Marshal a event Result envelope in minified JSON, appending to a provided
// destination slice.
func (en *Result) Marshal(dst []byte) (b []byte) {
var err error
b = dst
@@ -101,6 +123,8 @@ func (en *Result) Marshal(dst []byte) (b []byte) {
return
}
// Unmarshal a event Result from minified JSON, returning the remainder after
// the end of the envelope.
func (en *Result) Unmarshal(b []byte) (r []byte, err error) {
r = b
if en.Subscription, err = subscription.NewId([]byte{0}); chk.E(err) {

View File

@@ -1,5 +1,10 @@
package envelopes
// Identify handles determining what kind of codec.Envelope is, by the Label,
// the first step in identifying the structure of the message. This first step
// is not sufficient because the same labels are used on several codec.Envelope
// types in the nostr specification. The rest of the context is in whether this
// is a client or a relay receiving it.
func Identify(b []byte) (t string, rem []byte, err error) {
var openBrackets, openQuotes, afterQuotes bool
var label []byte

View File

@@ -7,16 +7,36 @@ import (
)
const (
Duplicate = "duplicate"
Pow = "pow"
Blocked = "blocked"
// Duplicate is a machine readable prefix for OK envelopes indicating that the
// submitted event is already in the relay,s event store.
Duplicate = "duplicate"
// Pow is a machine readable prefix for OK envelopes indicating that the
// eventid.T lacks sufficient zeros at the front.
Pow = "pow"
// Blocked is a machine readable prefix for OK envelopes indicating the event
// submission or REQ has been rejected.
Blocked = "blocked"
// RateLimited is a machine readable prefix for CLOSED and OK envelopes
// indicating the relay is now slowing down processing of requests from the
// client.
RateLimited = "rate-limited"
Invalid = "invalid"
Error = "error"
// Invalid is a machine readable prefix for OK envelopes indicating
// that the submitted event or other request is not correctly formatted, and may
// mean a signature does not verify.
Invalid = "invalid"
// Error is a machine readable prefix for CLOSED and OK envelopes indicating
// there was some kind of error in processing the request.
Error = "error"
)
// Examples are some examples of the use of the prefixes above with appropriate
// human-readable suffixes.
var Examples = [][]byte{
[]byte(""),
[]byte("pow: difficulty 25>=24"),
[]byte("duplicate: already have this event"),
[]byte("blocked: you are banned from posting here"),
@@ -28,6 +48,7 @@ var Examples = [][]byte{
[]byte("error: could not connect to the database"),
}
// RandomMessage generates a random message out of the above list of Examples.
func RandomMessage() []byte {
return Examples[frand.Intn(len(Examples)-1)]
}

View File

@@ -11,23 +11,36 @@ import (
"realy.lol/text"
)
// L is the label associated with this type of codec.Envelope.
const L = "NOTICE"
// T is a NOTICE envelope, intended to convey information to the user about the
// state of the relay connection. This thing is rarely displayed on clients
// except sometimes in event logs.
type T struct {
Message []byte
}
var _ codec.Envelope = (*T)(nil)
func New() *T { return &T{} }
func NewFrom[V string | []byte](msg V) *T { return &T{Message: []byte(msg)} }
func (en *T) Label() string { return L }
// New creates a new empty NOTICE T.
func New() *T { return &T{} }
// NewFrom creates a new NOTICE T with a provided message.
func NewFrom[V string | []byte](msg V) *T { return &T{Message: []byte(msg)} }
// Label returns the label of a NOTICE envelope.
func (en *T) Label() string { return L }
// Write the NOTICE T to a provided io.Writer.
func (en *T) Write(w io.Writer) (err error) {
_, err = w.Write(en.Marshal(nil))
return
}
// Marshal a NOTICE T envelope in minified JSON, appending to a provided
// destination slice. Note that this ensures correct string escaping on the
// Reason field.
func (en *T) Marshal(dst []byte) (b []byte) {
var err error
_ = err
@@ -43,6 +56,9 @@ func (en *T) Marshal(dst []byte) (b []byte) {
return
}
// Unmarshal a NOTICE T from minified JSON, returning the remainder after the
// end of the envelope. Note that this ensures the Reason string is correctly
// unescaped by NIP-01 escaping rules.
func (en *T) Unmarshal(b []byte) (r []byte, err error) {
r = b
if en.Message, r, err = text.UnmarshalQuoted(r); chk.E(err) {
@@ -54,6 +70,7 @@ func (en *T) Unmarshal(b []byte) (r []byte, err error) {
return
}
// Parse reads a NOTICE T in minified JSON into a newly allocated T.
func Parse(b []byte) (t *T, rem []byte, err error) {
t = New()
if rem, err = t.Unmarshal(b); chk.E(err) {

View File

@@ -13,10 +13,11 @@ import (
"realy.lol/text"
)
const (
L = "OK"
)
// L is the label associated with this type of codec.Envelope.
const L = "OK"
// T is an OK envelope, used to signal acceptance or rejection, with a reason,
// to an eventenvelope.Submission.
type T struct {
EventID *eventid.T
OK bool
@@ -25,11 +26,15 @@ type T struct {
var _ codec.Envelope = (*T)(nil)
// New creates a new empty OK T.
func New() *T { return &T{} }
func NewFrom[V string | []byte](eid V, ok bool, msg ...[]byte) *T {
// NewFrom creates a new OK T with a string for the subscription.Id and the
// Reason.
func NewFrom[V string | []byte](eid V, ok bool, msg ...V) *T {
var m []byte
if len(msg) > 0 {
m = msg[0]
m = []byte(msg[0])
}
if len(eid) != sha256.Size {
log.W.F("event ID unexpected length, expect %d got %d",
@@ -37,14 +42,22 @@ func NewFrom[V string | []byte](eid V, ok bool, msg ...[]byte) *T {
}
return &T{EventID: eventid.NewWith(eid), OK: ok, Reason: m}
}
func (en *T) Label() string { return L }
// Label returns the label of an OK envelope.
func (en *T) Label() string { return L }
// ReasonString returns the Reason in the form of a string.
func (en *T) ReasonString() string { return string(en.Reason) }
// Write the OK T to a provided io.Writer.
func (en *T) Write(w io.Writer) (err error) {
_, err = w.Write(en.Marshal(nil))
return
}
// Marshal a CLOSED T envelope in minified JSON, appending to a provided
// destination slice. Note that this ensures correct string escaping on the
// subscription.Id and Reason fields.
func (en *T) Marshal(dst []byte) (b []byte) {
var err error
_ = err
@@ -66,6 +79,9 @@ func (en *T) Marshal(dst []byte) (b []byte) {
return
}
// Unmarshal a CLOSED T from minified JSON, returning the remainder after the
// end of the envelope. Note that this ensures the Reason and subscription.Id
// strings are correctly unescaped by NIP-01 escaping rules.
func (en *T) Unmarshal(b []byte) (r []byte, err error) {
r = b
var idHex []byte
@@ -95,6 +111,7 @@ func (en *T) Unmarshal(b []byte) (r []byte, err error) {
return
}
// Parse reads a OK T in minified JSON into a newly allocated T.
func Parse(b []byte) (t *T, rem []byte, err error) {
t = New()
if rem, err = t.Unmarshal(b); chk.E(err) {

View File

@@ -4,8 +4,14 @@ import (
"io"
)
// Marshaler is a function signature the same as the codec.JSON Marshal but
// without the requirement of there being a full implementation or declared
// receiver variable of this interface. Used here to encapsulate one or more
// other data structures into an envelope.
type Marshaler func(dst []byte) (b []byte)
// Marshal is a parser for dynamic typed arrays like nosttr codec.Envelope
// types.
func Marshal(dst []byte, label string, m Marshaler) (b []byte) {
b = dst
b = append(b, '[', '"')
@@ -16,6 +22,8 @@ func Marshal(dst []byte, label string, m Marshaler) (b []byte) {
return
}
// SkipToTheEnd scans forward after all fields in an envelope have been read to
// find the closing bracket.
func SkipToTheEnd(dst []byte) (rem []byte, err error) {
if len(dst) == 0 {
return

View File

@@ -12,8 +12,13 @@ import (
"realy.lol/text"
)
// L is the label associated with this type of codec.Envelope.
const L = "REQ"
// T is a filter/subscription request envelope that can contain multiple
// filters. These prompt the relay to search its event store and return all
// events and if the limit is unset or large enough, it will continue to return
// newly received events after it returns an eoseenvelope.T.
type T struct {
Subscription *subscription.Id
Filters *filters.T
@@ -21,21 +26,30 @@ type T struct {
var _ codec.Envelope = (*T)(nil)
// New creates a new REQ T with a standard subscription.Id and empty filters.T.
func New() *T {
return &T{Subscription: subscription.NewStd(),
Filters: filters.New()}
}
// NewFrom creates a new REQ T with a provided subscription.Id and filters.T.
func NewFrom(id *subscription.Id, filters *filters.T) *T {
return &T{Subscription: id,
Filters: filters}
}
// Label returns the label of a REQ envelope.
func (en *T) Label() string { return L }
// Write the REQ T to a provided io.Writer.
func (en *T) Write(w io.Writer) (err error) {
_, err = w.Write(en.Marshal(nil))
return
}
// Marshal a REQ T envelope in minified JSON, appending to a provided
// destination slice. Note that this ensures correct string escaping on the
// subscription.Id field.
func (en *T) Marshal(dst []byte) (b []byte) {
var err error
_ = err
@@ -53,6 +67,9 @@ func (en *T) Marshal(dst []byte) (b []byte) {
return
}
// Unmarshal a REQ T from minified JSON, returning the remainder after the end
// of the envelope. Note that this ensures the subscription.Id string is
// correctly unescaped by NIP-01 escaping rules.
func (en *T) Unmarshal(b []byte) (r []byte, err error) {
r = b
if en.Subscription, err = subscription.NewId([]byte{0}); chk.E(err) {
@@ -74,6 +91,7 @@ func (en *T) Unmarshal(b []byte) (r []byte, err error) {
return
}
// Parse reads a REQ T from minified JSON into a newly allocated T.
func (en *T) Parse(b []byte) (t *T, rem []byte, err error) {
t = New()
if rem, err = t.Unmarshal(b); chk.E(err) {

View File

@@ -4,7 +4,6 @@ import (
"fmt"
"sync/atomic"
"testing"
"time"
"realy.lol/context"
"realy.lol/filter"
@@ -17,41 +16,41 @@ import (
const RELAY = "wss://mleku.realy.lol"
// test if we can fetch a couple of random events
func TestSubscribeBasic(t *testing.T) {
rl := mustRelayConnect(RELAY)
defer rl.Close()
var lim uint = 2
sub, err := rl.Subscribe(context.Bg(),
filters.New(&filter.T{Kinds: kinds.New(kind.TextNote), Limit: &lim}))
if err != nil {
t.Fatalf("subscription failed: %v", err)
return
}
timeout := time.After(5 * time.Second)
n := 0
for {
select {
case event := <-sub.Events:
if event == nil {
t.Fatalf("event is nil: %v", event)
}
n++
case <-sub.EndOfStoredEvents:
goto end
case <-rl.Context().Done():
t.Errorf("connection closed: %v", rl.Context().Err())
goto end
case <-timeout:
t.Errorf("timeout")
goto end
}
}
end:
if n != 2 {
t.Fatalf("expected 2 events, got %d", n)
}
}
// // test if we can fetch a couple of random events
// func TestSubscribeBasic(t *testing.T) {
// rl := mustRelayConnect(RELAY)
// defer rl.Close()
// var lim uint = 2
// sub, err := rl.Subscribe(context.Bg(),
// filters.New(&filter.T{Kinds: kinds.New(kind.TextNote), Limit: &lim}))
// if err != nil {
// t.Fatalf("subscription failed: %v", err)
// return
// }
// timeout := time.After(5 * time.Second)
// n := 0
// for {
// select {
// case event := <-sub.Events:
// if event == nil {
// t.Fatalf("event is nil: %v", event)
// }
// n++
// case <-sub.EndOfStoredEvents:
// goto end
// case <-rl.Context().Done():
// t.Errorf("connection closed: %v", rl.Context().Err())
// goto end
// case <-timeout:
// t.Errorf("timeout")
// goto end
// }
// }
// end:
// if n != 2 {
// t.Fatalf("expected 2 events, got %d", n)
// }
// }
// test if we can do multiple nested subscriptions
func TestNestedSubscriptions(t *testing.T) {