lib/nostr/client/subscriptions/profile_subscription.ex

defmodule Nostr.Client.Subscriptions.ProfileSubscription do
  @moduledoc """
  A process creating and managing a live subscription to a user's profile
  on a bunch of relays
  """

  use GenServer

  alias Nostr.RelaySocket
  alias Nostr.Event.Types.{MetadataEvent, EndOfStoredEvents}

  def start_link([relay_pids, pubkey, subscriber]) do
    GenServer.start_link(__MODULE__, %{
      relay_pids: relay_pids,
      pubkey: pubkey,
      subscriber: subscriber
    })
  end

  @impl true
  def init(%{relay_pids: relay_pids, pubkey: pubkey} = state) do
    subscriptions =
      relay_pids
      |> Enum.map(fn relay_pid ->
        RelaySocket.subscribe_profile(relay_pid, pubkey)
      end)

    {
      :ok,
      state
      |> set_profile_subscriptions(subscriptions)
      |> Map.put(:found, false)
    }
  end

  @impl true
  def handle_info(
        {_relay_url, %Nostr.Event.Types.EndOfStoredEvents{}},
        %{found: false, pubkey: pubkey, subscriber: subscriber} = state
      ) do
    empty_event = MetadataEvent.create_empty_event(pubkey)

    send(subscriber, empty_event)

    {:noreply, state}
  end

  @impl true
  def handle_info({_relay_url, %EndOfStoredEvents{}}, %{found: true} = state) do
    ## nothing to do, we're done here

    {:noreply, state}
  end

  @impl true
  def handle_info(
        {_relay_url, %MetadataEvent{} = event},
        %{subscriber: subscriber} = state
      ) do
    send(subscriber, event)

    {
      :noreply,
      %{state | found: true}
    }
  end

  defp set_profile_subscriptions(state, subscriptions) do
    Map.put(state, :subscriptions, subscriptions)
  end
end