lib/nostr_basics/client_message/decoder.ex

defmodule NostrBasics.ClientMessage.Decoder do
  @moduledoc """
  Converts Jason encoded structures into NostrBasics elixir structures
  """

  alias NostrBasics.{Event, Filter, CloseRequest}

  @doc """
  Converts Jason encoded structures into NostrBasics elixir structures

  ## Examples
      iex> [
      ...>   "EVENT",
      ...>   %{
      ...>     "content" => "gm nostr",
      ...>     "created_at" => 1675881420,
      ...>     "id" => "c899ed67ac6c736648f1809cf17d187ba2599a7fb2ab85359e19a78cd627a6b9",
      ...>     "kind" => 1,
      ...>     "pubkey" => "5ab9f2efb1fda6bc32696f6f3fd715e156346175b93b6382099d23627693c3f2",
      ...>     "sig" => "4868c4307638289cd2c3c56aa53eb6ff89372a3ff3b8d744e347889f06bb01e78e0a9704301ea226581e08210984212e275d98fc1d7704406fc4149fb345b19d",
      ...>     "tags" => []
      ...>   }
      ...> ]
      ...> |> NostrBasics.ClientMessage.Decoder.decode()
      {
        :event,
        %NostrBasics.Event{
          id: "c899ed67ac6c736648f1809cf17d187ba2599a7fb2ab85359e19a78cd627a6b9",
          pubkey: <<0x5ab9f2efb1fda6bc32696f6f3fd715e156346175b93b6382099d23627693c3f2::256>>,
          created_at: ~U[2023-02-08 18:37:00Z],
          kind: 1,
          tags: [],
          content: "gm nostr",
          sig: <<0x4868c4307638289cd2c3c56aa53eb6ff89372a3ff3b8d744e347889f06bb01e78e0a9704301ea226581e08210984212e275d98fc1d7704406fc4149fb345b19d::512>>
        }
      }

      iex> [
      ...>   "REQ",
      ...>   "7c4924a0d6d3a88917744ea7616618f9",
      ...>   %{
      ...>     "authors" => ["5ab9f2efb1fda6bc32696f6f3fd715e156346175b93b6382099d23627693c3f2"],
      ...>     "kinds" => [1],
      ...>     "limit" => 10
      ...>   }
      ...> ]
      ...> |> NostrBasics.ClientMessage.Decoder.decode()
      {
        :req,
        [
          %NostrBasics.Filter{
            subscription_id: "7c4924a0d6d3a88917744ea7616618f9",
            since: nil,
            until: nil,
            limit: 10,
            ids: [],
            authors: [<<0x5ab9f2efb1fda6bc32696f6f3fd715e156346175b93b6382099d23627693c3f2::256>>],
            kinds: [1],
            e: [],
            p: []
          }
        ]
      }

      iex> ["CLOSE", "7c4924a0d6d3a88917744ea7616618f9"]
      ...> |> NostrBasics.ClientMessage.Decoder.decode()
      {
        :close,
        %NostrBasics.CloseRequest{
          subscription_id: "7c4924a0d6d3a88917744ea7616618f9"
        }
      }

      iex> ~s(["WHAT", "something new"])
      ...> |> NostrBasics.ClientMessage.Decoder.decode()
      {:unknown, "Unknown nostr message type"}
  """
  @spec decode(list()) ::
          {:event, Event.t()}
          | {:req, list(Filter.t())}
          | {:close, CloseRequest.t()}
          | {:unknown, String.t()}
  def decode(["EVENT", encoded_event]) do
    {:event, Event.decode(encoded_event)}
  end

  def decode(["REQ" | [subscription_id | requests]]) do
    {:req, Enum.map(requests, &Filter.decode(&1, subscription_id))}
  end

  def decode(["CLOSE", subscription_id]) do
    {:close, %CloseRequest{subscription_id: subscription_id}}
  end

  def decode(_unknown_message) do
    {:unknown, "Unknown nostr message type"}
  end
end