diff --git a/lib/chat/application.ex b/lib/chat/application.ex index f524d72..28301a4 100644 --- a/lib/chat/application.ex +++ b/lib/chat/application.ex @@ -4,6 +4,7 @@ defmodule Chat.Application do @moduledoc false use Application + require Logger @impl true def start(_type, _args) do @@ -13,9 +14,17 @@ defmodule Chat.Application do # Start the PubSub system {Phoenix.PubSub, name: Chat.PubSub}, # Start the Endpoint (http/https) - ChatWeb.Endpoint + ChatWeb.Endpoint, # Start a worker by calling: Chat.Worker.start_link(arg) # {Chat.Worker, arg} + # Start the message handler + Chat.Floof, + + # Start the relay + {Task, fn -> + Floof.Distributor.register(self()) + relay_loop() + end} ] # See https://hexdocs.pm/elixir/Supervisor.html @@ -31,4 +40,20 @@ defmodule Chat.Application do ChatWeb.Endpoint.config_change(changed, removed) :ok end + + defp relay_loop do + receive do + {:fwdxfer, {_, {:XferBlob, source, _, _, _, xfinner}}} -> + {:ok, dcdi} = :FloofProtocol.decode(:XferInner, xfinner) + {:XferInner, topic, attrs, _, data} = dcdi + if topic == [{:RelativeDistinguishedName, {0, 9, 2342, 19200300, 100, 1, 14}, "Chat"}] do + [{:RelativeDistinguishedName, {0, 9, 2342, 19200300, 100, 1, 4}, name}] = attrs + {:ok, source_encd} = :FloofProtocol.encode(:RDNSequence, source) + source_encd = Base.url_encode64(source_encd) + ChatWeb.Endpoint.broadcast!("room:lobby", "shout", %{name: source_encd <> " :: " <> name, message: data}) + end + x -> Logger.error("unable to handle message #{inspect(x)}") + end + relay_loop() + end end diff --git a/lib/chat/floof.ex b/lib/chat/floof.ex new file mode 100644 index 0000000..456d677 --- /dev/null +++ b/lib/chat/floof.ex @@ -0,0 +1,37 @@ +defmodule Chat.Floof do + use Agent + require Logger + + defstruct secret: "", source: [] + + def start_link do + Agent.start_link(fn -> + secret_file = Application.fetch_env!(:chat, :secret_file) + source = Application.fetch_env!(:chat, :source) + {:ok, secret} = File.read(secret_file) + %Chat.Floof{secret: secret, source: source} + end, name: __MODULE__) + end + + def setup do + # generate and save a keypair + kp = :enacl.sign_keypair() + secret_file = Application.fetch_env!(:chat, :secret_file) + source = Application.fetch_env!(:chat, :source) + :ok = File.write(secret_file, kp.secret) + {:ok, pkname} = :FloofProtocol.encode(:RDNSequence, source) + pubkey_config = Application.fetch_env!(:floof, :pubkey_config) + :ok = File.write(pubkey_config.keydb <> "/" <> Base.url_encode64(pkname), kp.public) + end + + def send_message(name, data) do + msg_topic = [{:RelativeDistinguishedName, {0, 9, 2342, 19200300, 100, 1, 14}, "Chat"}] + msg_attrs = [{:RelativeDistinguishedName, {0, 9, 2342, 19200300, 100, 1, 4}, name}] + msg_inner = Floof.Message.pack_inner(msg_topic, msg_attrs, :info, data) + Agent.cast(__MODULE__, fn state -> + msg_outer = Floof.Message.build_outer(state.source, 255, [], state.secret, msg_inner) + Floof.Message.emit(msg_outer) + state + end) + end +end diff --git a/lib/chat_web/channels/room_channel.ex b/lib/chat_web/channels/room_channel.ex index 99dfc7b..d562fa7 100644 --- a/lib/chat_web/channels/room_channel.ex +++ b/lib/chat_web/channels/room_channel.ex @@ -21,6 +21,7 @@ defmodule ChatWeb.RoomChannel do # broadcast to everyone in the current topic (room:lobby). @impl true def handle_in("shout", payload, socket) do + Chat.Floof.send_message(payload.name, payload.message) broadcast(socket, "shout", payload) {:noreply, socket} end diff --git a/mix.exs b/mix.exs index 2e37073..5b71b3c 100644 --- a/mix.exs +++ b/mix.exs @@ -46,7 +46,8 @@ defmodule Chat.MixProject do {:gettext, "~> 0.18"}, {:jason, "~> 1.2"}, {:plug_cowboy, "~> 2.5"}, - {:floof, git: "https://git.exozy.me/zseri/floof.git"} + {:floof, git: "https://git.exozy.me/zseri/floof.git"}, + {:enacl, "~> 1.0.0"} ] end