all doc comments for envelopes
This commit is contained in:
@@ -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")
|
||||
)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)]
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user