Cleanup work

This commit is contained in:
Maciej 2026-03-01 11:35:32 +02:00
parent eb6631dd8b
commit f0cf03141b
Signed by: maciej
GPG key ID: 28243AF437E32F99
11 changed files with 59 additions and 9 deletions

View file

@ -1,4 +1,18 @@
defmodule BirdyChat.Dispatcher do
@moduledoc """
Main dispatcher of messages - decides to either write them to local file system or send them via
HTTP to peers.
It originally started as a websocket connection between servers, but then I decided to rip
it out and replace with simple HTTP request-response for the following reasons:
1. HTTP guarantees immediate feedback (request succeeds or not), making the addition of caching
or retries easy.
2. HTTP requests have well-know semantic so I can i.e use HTTP statuses for error signals
instead of inventing my own error language.
"""
@spec dispatch(Ecto.Changeset.t()) :: :ok | {:error, String.t()}
def dispatch(%Ecto.Changeset{changes: changes} = changeset) do
case changes do
%{routing: :local} -> BirdyChat.MessageWriter.write(changeset.changes)
@ -6,13 +20,13 @@ defmodule BirdyChat.Dispatcher do
end
end
def send_to_remote(%{server: server, to: to} = message) do
{_name, base_url} =
defp send_to_remote(%{server: server, from: from} = message) do
{name, base_url} =
BirdyChat.Identity.peers()
|> Enum.find(fn {name, _url} -> name == server end)
api_url = base_url <> "/api/internal"
token = Phoenix.Token.sign(BirdyChatWeb.Endpoint, "serverAuth", to)
token = Phoenix.Token.sign(BirdyChatWeb.Endpoint, "serverAuth", from)
{_request, result} =
Req.new(url: api_url, retry: false, method: :post)
@ -24,6 +38,12 @@ defmodule BirdyChat.Dispatcher do
# Handle more when you encounter errors
case result do
%Req.Response{status: 201} -> :ok
# This should never happen under normal circumstances so I am commenting this out but maybe
# needs a second look.
# %Req.Response{status: 403} -> {:error, "Unauthorised"}
# Peer is down.
%Req.TransportError{reason: :econnrefused} -> {:error, "peer #{name} is unreachable"}
end
end

View file

@ -55,6 +55,12 @@ defmodule BirdyChat.Identity do
peers: %{"test2" => "http://localhost:4001"},
mode: :test
}
{identity, peers} ->
peers = parse_peers(peers)
identity = parse_identity(identity)
%__MODULE__{identity: identity, peers: peers, mode: :connected}
end
end
end

View file

@ -1,5 +1,7 @@
defmodule BirdyChat.MessageWriter do
@moduledoc false
@moduledoc """
Simple file writer that stores messages in priv folder of Elixir application/release.
"""
@spec write(%{to: String.t(), from: String.t(), message: String.t()}) :: :ok
def write(message) do

View file

@ -10,10 +10,10 @@ defmodule BirdyChatWeb.Api.Messages.Controller do
|> put_status(:created)
|> render(:create, message: changeset.changes)
:error ->
{:error, error} ->
conn
|> put_status(:unprocessable_entity)
|> render(:error, changeset: changeset)
|> render(:error, message: error)
end
{:error, changeset} ->

View file

@ -3,6 +3,10 @@ defmodule BirdyChatWeb.Api.Messages.JSON do
message
end
def render("error.json", %{message: message}) do
%{errors: %{"general" => Gettext.dgettext(BirdyChatWeb.Gettext, "errors", message, [])}}
end
def render("error.json", %{changeset: changeset}) do
errors = Ecto.Changeset.traverse_errors(changeset, &get_error/1)
%{errors: errors}