View Source GenNostr behaviour (GenNostr v0.1.0)

A low level websocket client that implements the Nostr protocol.

It works like a GenServer.

architecture

Architecture

The GenNostr process spawn a PrimarySupervisor with a ConnectionRegistry and a ConnectionSupervisor (DynamicSupervisor) that supervises connections. The ConnectionRegistry store the url as key to avoid connections to same relay.

The GenNostr process is the client and the websocket processes are then connections. The client send commands to connections. The connections emit events that can to be generated by the commands or by websocket messages and sends back the response to client through handlers.

Link to this section Summary

Callbacks

Invoked when a gen_nostr connection receives a AUTH message (NIP-42).

Invoked when a GenNostr process receives a GenServer call.

Invoked when a GenNostr process receives a GenServer cast.

Invoked when a connection has been established to a relay.

Invoked when a GenNostr process receives a message.

Invoked when a gen_nostr connection is disconected from relay.

Invoked when a gen_nostr connection receives a EOSE message (NIP-15).

Invoked when a gen_nostr connection has a error and can trigger a handle_disconnect/3 if the error close the connection.

Invoked when a gen_nostr connection receives a EVENT message (NIP-01).

Invoked when a GenNostr process receives a message.

Invoked when a gen_nostr connection receives a NOTICE message (NIP-01).

Invoked when a gen_nostr connection receives a OK message (NIP-20).

Invoked when the gen_nostr process starts.

Invoked when a GenNostr process is terminated.

Functions

Crate a new connection to relay.

Send a broadcast message to connected relays.

Relay url list of all current connections.

Tries to reconnect after a disconnection.

Finishes the connection and removes the relay.

Send a message to the specified url or relay.

Starts a GenNostr client process.

Link to this section Callbacks

Link to this callback

handle_auth(auth_msg, relay, state)

View Source (optional)
@callback handle_auth(auth_msg :: term(), relay :: GenNostr.Relay.t(), state :: term()) ::
  {:ok, new_state} | {:stop, new_state} | {:stop, reason :: term(), new_state}
when new_state: term()

Invoked when a gen_nostr connection receives a AUTH message (NIP-42).

Link to this callback

handle_call(request, from, state)

View Source (optional)
@callback handle_call(
  request :: term(),
  from :: GenServer.from(),
  state :: term()
) ::
  {:reply, reply, new_state}
  | {:reply, reply, new_state, timeout() | :hibernate | {:continue, term()}}
  | {:noreply, new_state}
  | {:noreply, new_state, timeout() | :hibernate | {:continue, term()}}
  | {:stop, reason, new_state}
  | {:stop, reason, reply, new_state}
when new_state: term(), reply: term(), reason: term()

Invoked when a GenNostr process receives a GenServer call.

Behaves the same as GenServer.handle_call/3

Link to this callback

handle_cast(request, state)

View Source (optional)
@callback handle_cast(request :: term(), state :: term()) ::
  {:noreply, new_state}
  | {:noreply, new_state, timeout() | :hibernate | {:continue, term()}}
  | {:stop, reason :: term(), new_state}
when new_state: term()

Invoked when a GenNostr process receives a GenServer cast.

Behaves the same as GenServer.handle_cast/2

Link to this callback

handle_connect(relay, state)

View Source (optional)
@callback handle_connect(relay :: GenNostr.Relay.t(), state :: term()) ::
  {:ok, new_state} | {:stop, reason :: term(), new_state}
when new_state: term()

Invoked when a connection has been established to a relay.

Link to this callback

handle_continue(continue_arg, state)

View Source (optional)
@callback handle_continue(continue_arg, state :: term()) ::
  {:noreply, new_state}
  | {:noreply, new_state, timeout() | :hibernate | {:continue, continue_arg}}
  | {:stop, reason :: term(), new_state}
when new_state: term(), continue_arg: term()

Invoked when a GenNostr process receives a message.

Behaves the same as GenServer.handle_continue/2

Link to this callback

handle_disconnect(reason, relay, state)

View Source (optional)
@callback handle_disconnect(
  reason :: term(),
  relay :: GenNostr.Relay.t(),
  state :: term()
) ::
  {:ok, new_state} | {:stop, stop_reason :: term(), new_state}
when new_state: term()

Invoked when a gen_nostr connection is disconected from relay.

Link to this callback

handle_eose(eose_msg, relay, state)

View Source (optional)
@callback handle_eose(eose_msg :: term(), relay :: GenNostr.Relay.t(), state :: term()) ::
  {:ok, new_state} | {:stop, new_state} | {:stop, reason :: term(), new_state}
when new_state: term()

Invoked when a gen_nostr connection receives a EOSE message (NIP-15).

Link to this callback

handle_error(reason, relay, state)

View Source (optional)
@callback handle_error(reason :: term(), relay :: GenNostr.Relay.t(), state :: term()) ::
  {:ok, new_state} | {:stop, stop_reason :: term(), new_state}
when new_state: term()

Invoked when a gen_nostr connection has a error and can trigger a handle_disconnect/3 if the error close the connection.

Link to this callback

handle_event(event_msg, relay, state)

View Source (optional)
@callback handle_event(event_msg :: term(), relay :: GenNostr.Relay.t(), state :: term()) ::
  {:ok, new_state} | {:stop, new_state} | {:stop, reason :: term(), new_state}
when new_state: term()

Invoked when a gen_nostr connection receives a EVENT message (NIP-01).

Link to this callback

handle_info(msg, state)

View Source (optional)
@callback handle_info(msg :: :timeout | term(), state :: term()) ::
  {:noreply, new_state}
  | {:noreply, new_state, timeout() | :hibernate | {:continue, term()}}
  | {:stop, reason :: term(), new_state}
when new_state: term()

Invoked when a GenNostr process receives a message.

Behaves the same as GenServer.handle_info/2

Link to this callback

handle_notice(notice_msg, relay, state)

View Source (optional)
@callback handle_notice(
  notice_msg :: term(),
  relay :: GenNostr.Relay.t(),
  state :: term()
) ::
  {:ok, new_state} | {:stop, new_state} | {:stop, reason :: term(), new_state}
when new_state: GenNostr.Relay.t()

Invoked when a gen_nostr connection receives a NOTICE message (NIP-01).

Link to this callback

handle_ok(ok_msg, relay, state)

View Source (optional)
@callback handle_ok(ok_msg :: term(), relay :: GenNostr.Relay.t(), state :: term()) ::
  {:ok, new_state} | {:stop, new_state} | {:stop, reason :: term(), new_state}
when new_state: term()

Invoked when a gen_nostr connection receives a OK message (NIP-20).

Link to this callback

init(init_arg)

View Source (optional)
@callback init(init_arg :: term()) ::
  {:ok, state}
  | {:ok, state, timeout() | :hibernate | {:continue, continue_arg :: term()}}
  | :ignore
  | {:stop, reason :: any()}
when state: term()

Invoked when the gen_nostr process starts.

Behaves the same as GenServer.init/1

@impl GenNostr
def init(args) do
  relays = Keyword.get(args, :relays, [])
  options = Keyword.get(args, :options, [])

  Enum.each(relays, &GenNostr.add_relay(&1, options))

  {:ok, %{}}
end
Link to this callback

terminate(reason, state)

View Source (optional)
@callback terminate(reason, state :: term()) :: term()
when reason: :normal | :shutdown | {:shutdown, term()} | term()

Invoked when a GenNostr process is terminated.

Note that this callback is not always invoked as the process shuts down. See GenServer.terminate/2 for more information.

Link to this section Functions

Crate a new connection to relay.

options

Options

  • :mint - keyword list of specific options of elixir mint, default to [protocols: [:http1]]

  • :reconnect - timeouts list in msec used by reconnect/1, default to [500, 1_000, 5_000, 10_000, 30_000]

  • :tasks - keyword list of recurring timeout tasks in msec, default to [garbage_collector: 60 * 60 * 1000]

examples

Examples

# using a url and default options
GenNostr.add_relay("wss://relay.com/")

# using the Relay struct and default options
GenNostr.Relay.new(url: "wss://relay.com/")
|> GenNostr.add_relay()
Link to this function

add_relay(url, options \\ [])

View Source
@spec add_relay(
  String.t() | GenNostr.Relay.t(),
  keyword()
) :: term()
Link to this function

broadcast_message(message)

View Source
@spec broadcast_message(String.t()) :: any()

Send a broadcast message to connected relays.

@spec list_relays() :: [String.t()]

Relay url list of all current connections.

@spec reconnect(GenNostr.Relay.t()) :: term()

Tries to reconnect after a disconnection.

This function must be used within handle_disconnect/3.

examples

Examples

@impl GenNostr
def handle_disconnect(reason, relay, state) do
  Logger.info("Disconnected from relay")

  # don't reconnect if the :remove_relay is the reason
  case reason do
    :remove_relay -> Logger.info("Don't reconnect")
    _ -> GenNostr.reconnect(relay)
  end

  {:ok, state}
end
@spec remove_relay(String.t() | GenNostr.Relay.t()) :: term()

Finishes the connection and removes the relay.

This function invokes handle_disconnect/3 and receive a reason of :remove_relay

examples

Examples

# using a url and default options
GenNostr.remove_relay("wss://relay.com/")

# using the Relay struct and default options
GenNostr.Relay.new(url: "wss://relay.com/")
|> GenNostr.remove_relay()
Link to this function

send_message(message, relay)

View Source
@spec send_message(String.t(), String.t() | GenNostr.Relay.t()) :: any()

Send a message to the specified url or relay.

Link to this function

start_link(module, args, options \\ [])

View Source
@spec start_link(module(), term(), GenServer.options()) :: GenServer.on_start()

Starts a GenNostr client process.

This function return a GenServer.start_link/3

examples

Examples

defmodule NostrClient do
  use GenNostr

  def start_link(args) do
    GenNostr.start_link(__MODULE__, args, name: __MODULE__)
  end
end