defmodule NostrApp.Server do @moduledoc """ The server part of the NostrApp, which is an example of an app """ use GenServer require Logger alias NostrApp.Subscribe alias Nostr.Client alias Nostr.Event.Types.MetadataEvent alias Nostr.Models.{Profile} alias Nostr.Keys.{PrivateKey, PublicKey} @impl true def init(%{relays: relays, private_key: private_key} = args) do with {:ok, binary_private_key} <- PrivateKey.to_binary(private_key), {:ok, public_key} <- PublicKey.from_private_key(binary_private_key), {:ok, supervisor_pid} <- Nostr.Client.start_link() do connect_to_relays(relays) { :ok, %{args | private_key: binary_private_key} |> Map.put(:supervisor_pid, supervisor_pid) |> Map.put(:public_key, public_key) } else {:error, message} -> {:stop, message} :already_present -> :ok :ignore -> {:stop, :ignore} other -> {:stop, other} end end @impl true def handle_cast({:send_note, note}, %{private_key: private_key} = socket) do Client.send_note(note, private_key) {:noreply, socket} end @impl true def handle_cast({:react, note_id}, %{private_key: private_key} = socket) do case Client.react(note_id, private_key) do {:ok, _} -> Logger.info("successfully sent a reaction") {:error, message} -> Logger.error(message) end {:noreply, socket} end @impl true def handle_cast({:contacts}, %{public_key: public_key} = socket) do Subscribe.to_contacts(public_key) {:noreply, socket} end @impl true def handle_cast({:contacts, pubkey}, socket) do Client.subscribe_contacts(pubkey) {:noreply, socket} end @impl true def handle_cast({:follow, contact_pubkey}, %{private_key: private_key} = socket) do case Client.follow(contact_pubkey, private_key) do {:ok, _} -> Logger.info("successfully followed #{contact_pubkey}") {:error, message} -> Logger.error(message) end {:noreply, socket} end @impl true def handle_cast({:unfollow, contact_pubkey}, %{private_key: private_key} = socket) do case Client.unfollow(contact_pubkey, private_key) do {:ok, _} -> Logger.info("successfully unfollowed #{contact_pubkey}") {:error, message} -> Logger.error(message) end {:noreply, socket} end @impl true def handle_cast({:encrypted_direct_messages}, %{private_key: private_key} = socket) do Subscribe.to_encrypted_direct_messages(private_key) {:noreply, socket} end @impl true def handle_cast({:encrypted_direct_messages, private_key}, socket) do Client.encrypted_direct_messages(private_key) {:noreply, socket} end @impl true def handle_cast( {:send_encrypted_direct_messages, pubkey, message}, %{private_key: private_key} = socket ) do case Client.send_encrypted_direct_messages(pubkey, message, private_key) do :ok -> Logger.info("successfully sent an encrypted direct message") {:error, message} -> Logger.error(message) end {:noreply, socket} end @impl true def handle_cast({:profile, nil}, %{public_key: public_key} = socket) do Subscribe.to_profile(public_key) {:noreply, socket} end @impl true def handle_cast({:profile, public_key}, socket) do Subscribe.to_profile(public_key) {:noreply, socket} end @impl true def handle_cast({:update_profile, %Profile{} = profile}, %{private_key: private_key} = socket) do Client.update_profile(profile, private_key) {:noreply, socket} end @impl true def handle_cast({:note, note_id}, socket) do Subscribe.to_note(note_id) {:noreply, socket} end @impl true def handle_cast({:notes}, %{public_key: public_key} = socket) do Subscribe.to_notes([public_key]) {:noreply, socket} end @impl true def handle_cast({:notes, pubkeys}, socket) do Subscribe.to_notes(pubkeys) {:noreply, socket} end @impl true def handle_cast({:delete, event_ids, note}, %{private_key: private_key} = socket) do case Client.delete_events(event_ids, note, private_key) do {:ok, _} -> Logger.info("successfully deleted #{event_ids}") {:error, message} -> Logger.error(message) end {:noreply, socket} end @impl true def handle_cast({:deletions}, %{public_key: public_key} = socket) do Subscribe.to_deletions([public_key]) {:noreply, socket} end @impl true def handle_cast({:deletions, pubkeys}, socket) do Subscribe.to_deletions(pubkeys) {:noreply, socket} end @impl true def handle_cast({:repost, note_id}, %{private_key: private_key} = socket) do case Client.repost(note_id, private_key) do {:ok, _} -> Logger.info("successfully reposted #{note_id}") {:error, message} -> Logger.error(message) end {:noreply, socket} end @impl true def handle_cast({:reposts}, %{public_key: public_key} = socket) do Subscribe.to_reposts([public_key]) {:noreply, socket} end @impl true def handle_cast({:reposts, pubkeys}, socket) do Subscribe.to_reposts(pubkeys) {:noreply, socket} end @impl true def handle_cast({:reactions}, %{public_key: public_key} = socket) do Subscribe.to_reactions([public_key]) {:noreply, socket} end @impl true def handle_cast({:reactions, pubkeys}, socket) do Subscribe.to_reactions(pubkeys) {:noreply, socket} end @impl true def handle_cast({:timeline}, %{public_key: public_key} = socket) do Client.subscribe_timeline(public_key) {:noreply, socket} end @impl true def handle_cast({:timeline, pubkey}, socket) do Client.subscribe_timeline(pubkey) {:noreply, socket} end @impl true def handle_info({:connection, _relay_url, :error, _message} = message, socket) do # credo:disable-for-next-line IO.inspect(message) {:noreply, socket} end @impl true def handle_info({relay, %MetadataEvent{} = event}, socket) do Logger.info("From #{relay}, got a profile: #{inspect(event)}") {:noreply, socket} end @impl true def handle_info({relay, event}, socket) do # credo:disable-for-next-line IO.puts("from #{relay}") # credo:disable-for-next-line IO.inspect(event) {:noreply, socket} end @impl true def handle_info(event, socket) do # credo:disable-for-next-line IO.inspect(event) {:noreply, socket} end defp connect_to_relays(relays) do for relay <- relays do Client.add_relay(relay) end end end