ws

package
v0.8.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 18, 2025 License: Unlicense Imports: 46 Imported by: 0

Documentation

Overview

Package ws provides both relay and client websocket implementations, including a pool for fanning out to multiple relays and managing subscriptions.

Package ws implements nostr websockets with their authentication state.

Index

Constants

View Source
const MAX_LOCKS = 50

Variables

This section is empty.

Functions

func WithPenaltyBox added in v0.5.0

func WithPenaltyBox() withPenaltyBoxOpt

WithPenaltyBox just sets the penalty box mechanism so relays that fail to connect or that disconnect will be ignored for a while and we won't attempt to connect again.

func WithRelayOptions added in v0.5.0

func WithRelayOptions(ropts ...RelayOption) withRelayOptionsOpt

WithRelayOptions sets options that will be used on every relay instance created by this pool.

Types

type Client

type Client struct {
	URL string

	Connection    *Connection
	Subscriptions *xsync.MapOf[string, *Subscription]

	ConnectionError error

	// custom things that aren't often used
	//
	AssumeValid bool // this will skip verifying signatures for events received from this relay
	// contains filtered or unexported fields
}

Client represents a connection to a Nostr relay.

func NewRelay

func NewRelay(ctx context.Context, url string, opts ...RelayOption) *Client

NewRelay returns a new relay. It takes a context that, when canceled, will close the relay connection.

func RelayConnect

func RelayConnect(ctx context.Context, url string, opts ...RelayOption) (
	*Client, error,
)

RelayConnect returns a relay object connected to url.

The given subscription is only used during the connection phase. Once successfully connected, cancelling ctx has no effect.

The ongoing relay connection uses a background context. To close the connection, call r.Close(). If you need fine grained long-term connection contexts, use NewRelay() instead.

func (*Client) Auth

func (r *Client) Auth(
	ctx context.Context, sign signer.I,
) (err error)

Auth sends an "AUTH" command client->relay as in NIP-42 and waits for an OK response.

You don't have to build the AUTH event yourself, this function takes a function to which the event that must be signed will be passed, so it's only necessary to sign that.

func (*Client) Close

func (r *Client) Close() error

Close closes the relay connection.

func (*Client) Connect

func (r *Client) Connect(ctx context.Context) error

Connect tries to establish a websocket connection to r.URL. If the context expires before the connection is complete, an error is returned. Once successfully connected, context expiration has no effect: call r.Close to close the connection.

The given context here is only used during the connection phase. The long-living relay connection will be based on the context given to NewRelay().

func (*Client) ConnectWithTLS

func (r *Client) ConnectWithTLS(
	ctx context.Context, tlsConfig *tls.Config,
) error

ConnectWithTLS is like Connect(), but takes a special tls.Config if you need that.

func (*Client) Context

func (r *Client) Context() context.Context

Context retrieves the context that is associated with this relay connection. It will be closed when the relay is disconnected.

func (*Client) IsConnected

func (r *Client) IsConnected() bool

IsConnected returns true if the connection to this relay seems to be active.

func (*Client) PrepareSubscription

func (r *Client) PrepareSubscription(
	ctx context.Context, ff *filters.T, opts ...SubscriptionOption,
) (sub *Subscription)

PrepareSubscription creates a subscription, but doesn't fire it.

Remember to cancel subscriptions, either by calling `.Unsub()` on them or ensuring their `context.Context` will be canceled at some point. Failure to do that will result in a huge number of halted goroutines being created.

func (*Client) Publish

func (r *Client) Publish(ctx context.Context, event *event.E) error

Publish sends an "EVENT" command to the relay r as in NIP-01 and waits for an OK response.

func (*Client) QueryEvents added in v0.5.0

func (r *Client) QueryEvents(ctx context.Context, f *filter.F) (
	evc event.C, err error,
)

QueryEvents subscribes to events matching the given filter and returns a channel of events.

In most cases it's better to use SimplePool instead of this method.

func (*Client) QuerySync

func (r *Client) QuerySync(ctx context.Context, ff *filter.F) (
	[]*event.E, error,
)

QuerySync subscribes to events matching the given filter and returns a slice of events. This method blocks until all events are received or the context is canceled.

In most cases it's better to use SimplePool instead of this method.

func (*Client) String

func (r *Client) String() string

String just returns the relay URL.

func (*Client) Subscribe

func (r *Client) Subscribe(
	ctx context.Context, ff *filters.T, opts ...SubscriptionOption,
) (*Subscription, error)

Subscribe sends a "REQ" command to the relay r as in NIP-01. Events are returned through the channel sub.Events. The subscription is closed when context ctx is cancelled ("CLOSE" in NIP-01).

Remember to cancel subscriptions, either by calling `.Unsub()` on them or ensuring their `context.Context` will be canceled at some point. Failure to do that will result in a huge number of halted goroutines being created.

func (*Client) Write

func (r *Client) Write(msg []byte) <-chan error

Write queues an arbitrary message to be sent to the relay.

type Connection

type Connection struct {
	// contains filtered or unexported fields
}

Connection represents a websocket connection to a Nostr relay.

func NewConnection

func NewConnection(
	ctx context.T, url string, reqHeader http.Header,
	tlsConfig *tls.Config,
) (c *Connection, err error)

NewConnection creates a new websocket connection to a Nostr relay.

func (*Connection) Close

func (c *Connection) Close() error

Close closes the websocket connection.

func (*Connection) Ping added in v0.5.0

func (c *Connection) Ping(ctx context.T) error

Ping sends a ping message to the websocket connection.

func (*Connection) ReadMessage

func (c *Connection) ReadMessage(
	ctx context.T, buf io.Writer,
) (err error)

ReadMessage reads arbitrary bytes from the websocket connection into the provided buffer.

func (*Connection) WriteMessage

func (c *Connection) WriteMessage(
	ctx context.T, data []byte,
) (err error)

WriteMessage writes arbitrary bytes to the websocket connection.

type DirectedFilter added in v0.5.0

type DirectedFilter struct {
	Filter *filter.F
	Relay  string
}

DirectedFilter combines a Filter with a specific relay URL.

type Listener

type Listener struct {
	Conn    *websocket.Conn
	Request *http.Request
	// contains filtered or unexported fields
}

Listener is a websocket implementation for a relay listener.

func NewListener

func NewListener(
	conn *websocket.Conn, req *http.Request, authRequired bool,
) (ws *Listener)

NewListener creates a new Listener for listening for inbound connections for a relay.

func (*Listener) AuthRequested

func (ws *Listener) AuthRequested() (read bool)

AuthRequested returns whether the Listener has asked for auth from the client.

func (*Listener) AuthedPubkey

func (ws *Listener) AuthedPubkey() []byte

func (*Listener) Challenge

func (ws *Listener) Challenge() []byte

func (*Listener) Close

func (ws *Listener) Close() (err error)

Close the Listener connection from the Listener side.

func (*Listener) GetPendingEvent added in v0.2.18

func (ws *Listener) GetPendingEvent() (ev *event.E)

func (*Listener) IsAuthed

func (ws *Listener) IsAuthed() bool

func (*Listener) RealRemote

func (ws *Listener) RealRemote() string

RealRemote returns the stored remote address of the client.

func (*Listener) Req

func (ws *Listener) Req() *http.Request

Req returns the http.Request associated with the client connection to the Listener.

func (*Listener) RequestAuth

func (ws *Listener) RequestAuth()

RequestAuth stores when auth has been required from a client.

func (*Listener) SetAuthedPubkey

func (ws *Listener) SetAuthedPubkey(b []byte)

func (*Listener) SetChallenge

func (ws *Listener) SetChallenge(b []byte)

func (*Listener) SetPendingEvent added in v0.2.18

func (ws *Listener) SetPendingEvent(ev *event.E)

func (*Listener) Write

func (ws *Listener) Write(p []byte) (n int, err error)

Write a message to send to a client.

func (*Listener) WriteJSON

func (ws *Listener) WriteJSON(any interface{}) error

WriteJSON encodes whatever into JSON and sends it to the client.

func (*Listener) WriteMessage

func (ws *Listener) WriteMessage(t int, b []byte) error

WriteMessage is a wrapper around the websocket WriteMessage, which includes a websocket message type identifier.

type PoolOption

type PoolOption interface {
	ApplyPoolOption(*SimplePool)
}

PoolOption is an interface for options that can be applied to a SimplePool.

type PublishResult added in v0.5.0

type PublishResult struct {
	Error    error
	RelayURL string
	Relay    *Client
}

PublishResult represents the result of publishing an event to a relay.

type RelayEvent added in v0.5.0

type RelayEvent struct {
	*event.E
	Relay *Client
}

RelayEvent represents an event received from a specific relay.

func (RelayEvent) String added in v0.5.0

func (ie RelayEvent) String() string

type RelayOption

type RelayOption interface {
	ApplyRelayOption(*Client)
}

RelayOption is the type of the argument passed when instantiating relay connections.

type ReplaceableKey added in v0.5.0

type ReplaceableKey struct {
	PubKey string
	D      string
}

type SimplePool added in v0.8.1

type SimplePool struct {
	Relays  *xsync.MapOf[string, *Client]
	Context context.T
	// contains filtered or unexported fields
}

SimplePool manages connections to multiple relays, ensures they are reopened when necessary and not duplicated.

func NewSimplePool added in v0.8.1

func NewSimplePool(ctx context.T, opts ...PoolOption) *SimplePool

NewSimplePool creates a new SimplePool with the given context and options.

func (*SimplePool) BatchedSubManyEose added in v0.8.1

func (pool *SimplePool) BatchedSubManyEose(
	ctx context.T,
	dfs []DirectedFilter,
	opts ...SubscriptionOption,
) chan RelayEvent

BatchedSubManyEose performs batched subscriptions to multiple relays with different filters.

func (*SimplePool) Close added in v0.8.1

func (pool *SimplePool) Close(reason string)

Close closes the pool with the given reason.

func (*SimplePool) EnsureRelay added in v0.8.1

func (pool *SimplePool) EnsureRelay(url string) (*Client, error)

EnsureRelay ensures that a relay connection exists and is active. If the relay is not connected, it attempts to connect.

func (*SimplePool) FetchMany added in v0.8.1

func (pool *SimplePool) FetchMany(
	ctx context.T,
	urls []string,
	filter *filter.F,
	opts ...SubscriptionOption,
) chan RelayEvent

FetchMany opens a subscription, much like SubscribeMany, but it ends as soon as all Relays return an EOSE message.

func (*SimplePool) FetchManyReplaceable added in v0.8.1

func (pool *SimplePool) FetchManyReplaceable(
	ctx context.T,
	urls []string,
	filter *filter.F,
	opts ...SubscriptionOption,
) *xsync.MapOf[ReplaceableKey, *event.E]

FetchManyReplaceable is like FetchMany, but deduplicates replaceable and addressable events and returns only the latest for each "d" tag.

func (*SimplePool) PublishMany added in v0.8.1

func (pool *SimplePool) PublishMany(
	ctx context.T, urls []string, evt *event.E,
) chan PublishResult

PublishMany publishes an event to multiple relays and returns a channel of results emitted as they're received.

func (*SimplePool) QuerySingle added in v0.8.1

func (pool *SimplePool) QuerySingle(
	ctx context.T,
	urls []string,
	filter *filter.F,
	opts ...SubscriptionOption,
) *RelayEvent

QuerySingle returns the first event returned by the first relay, cancels everything else.

func (*SimplePool) SubMany deprecated added in v0.8.1

func (pool *SimplePool) SubMany(
	ctx context.T,
	urls []string,
	filters *filters.T,
	opts ...SubscriptionOption,
) chan RelayEvent

Deprecated: SubMany is deprecated: use SubscribeMany instead.

func (*SimplePool) SubManyEose deprecated added in v0.8.1

func (pool *SimplePool) SubManyEose(
	ctx context.T,
	urls []string,
	filters *filters.T,
	opts ...SubscriptionOption,
) chan RelayEvent

Deprecated: SubManyEose is deprecated: use FetchMany instead.

func (*SimplePool) SubscribeMany added in v0.8.1

func (pool *SimplePool) SubscribeMany(
	ctx context.T,
	urls []string,
	filter *filter.F,
	opts ...SubscriptionOption,
) chan RelayEvent

SubscribeMany opens a subscription with the given filter to multiple relays the subscriptions ends when the context is canceled or when all relays return a CLOSED.

func (*SimplePool) SubscribeManyNotifyEOSE added in v0.8.1

func (pool *SimplePool) SubscribeManyNotifyEOSE(
	ctx context.T,
	urls []string,
	filter *filter.F,
	eoseChan chan struct{},
	opts ...SubscriptionOption,
) chan RelayEvent

SubscribeManyNotifyEOSE is like SubscribeMany, but takes a channel that is closed when all subscriptions have received an EOSE

type Subscription

type Subscription struct {
	Client  *Client
	Filters *filters.T

	// the Events channel emits all EVENTs that come in a Subscription
	// will be closed when the subscription ends
	Events chan *event.E

	// the EndOfStoredEvents channel gets closed when an EOSE comes for that subscription
	EndOfStoredEvents chan struct{}

	// the ClosedReason channel emits the reason when a CLOSED message is received
	ClosedReason chan string

	// Context will be .Done() when the subscription ends
	Context context.Context
	// contains filtered or unexported fields
}

Subscription represents a subscription to a relay.

func (*Subscription) Close

func (sub *Subscription) Close()

Close just sends a CLOSE message. You probably want Unsub() instead.

func (*Subscription) Fire

func (sub *Subscription) Fire() (err error)

Fire sends the "REQ" command to the relay.

func (*Subscription) GetID

func (sub *Subscription) GetID() string

GetID returns the subscription ID.

func (*Subscription) Sub

func (sub *Subscription) Sub(_ context.Context, ff *filters.T)

Sub sets sub.Filters and then calls sub.Fire(ctx). The subscription will be closed if the context expires.

func (*Subscription) Unsub

func (sub *Subscription) Unsub()

Unsub closes the subscription, sending "CLOSE" to relay as in NIP-01. Unsub() also closes the channel sub.Events and makes a new one.

type SubscriptionOption

type SubscriptionOption interface {
	IsSubscriptionOption()
}

SubscriptionOption is the type of the argument passed when instantiating relay connections. Some examples are WithLabel.

type WithAuthHandler

type WithAuthHandler struct {
	signer.I
}

WithAuthHandler must be a function that signs the auth event when called. it will be called whenever any relay in the pool returns a `CLOSED` message with the "auth-required:" prefix, only once for each relay

func (*WithAuthHandler) ApplyPoolOption

func (h *WithAuthHandler) ApplyPoolOption(pool *SimplePool)

type WithAuthMiddleware added in v0.8.1

type WithAuthMiddleware func(RelayEvent) error

type WithAuthorKindQueryMiddleware added in v0.5.0

type WithAuthorKindQueryMiddleware func(
	relay string, pubkey []byte, kind *kind.T,
)

WithAuthorKindQueryMiddleware is a function that will be called with every combination of relay+pubkey+kind queried in a .SubMany*() call -- when applicable (i.e. when the query contains a pubkey and a kind).

func (WithAuthorKindQueryMiddleware) ApplyPoolOption added in v0.5.0

func (h WithAuthorKindQueryMiddleware) ApplyPoolOption(pool *SimplePool)

type WithCheckDuplicate added in v0.8.1

type WithCheckDuplicate func(id, relay string) bool

WithCheckDuplicate sets checkDuplicate on the subscription

func (WithCheckDuplicate) IsSubscriptionOption added in v0.8.1

func (_ WithCheckDuplicate) IsSubscriptionOption()

type WithCheckDuplicateReplaceable added in v0.8.1

type WithCheckDuplicateReplaceable func(rk ReplaceableKey, ts *timestamp.T) bool

WithCheckDuplicateReplaceable sets checkDuplicateReplaceable on the subscription

func (WithCheckDuplicateReplaceable) IsSubscriptionOption added in v0.8.1

func (_ WithCheckDuplicateReplaceable) IsSubscriptionOption()

type WithCustomHandler added in v0.5.0

type WithCustomHandler func(data string)

WithCustomHandler must be a function that handles any relay message that couldn't be parsed as a standard envelope.

func (WithCustomHandler) ApplyRelayOption added in v0.5.0

func (ch WithCustomHandler) ApplyRelayOption(r *Client)

type WithDuplicateMiddleware added in v0.5.0

type WithDuplicateMiddleware func(relay string, id string)

WithDuplicateMiddleware is a function that will be called with all duplicate ids received.

func (WithDuplicateMiddleware) ApplyPoolOption added in v0.5.0

func (h WithDuplicateMiddleware) ApplyPoolOption(pool *SimplePool)

type WithEventMiddleware

type WithEventMiddleware func(RelayEvent)

WithEventMiddleware is a function that will be called with all events received.

func (WithEventMiddleware) ApplyPoolOption

func (h WithEventMiddleware) ApplyPoolOption(pool *SimplePool)

type WithLabel

type WithLabel string

WithLabel puts a label on the subscription (it is prepended to the automatic id) that is sent to relays.

func (WithLabel) IsSubscriptionOption

func (_ WithLabel) IsSubscriptionOption()

type WithRequestHeader added in v0.5.0

type WithRequestHeader http.Header

WithRequestHeader sets the HTTP request header of the websocket preflight request.

func (WithRequestHeader) ApplyRelayOption added in v0.5.0

func (ch WithRequestHeader) ApplyRelayOption(r *Client)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL