119 lines
3.0 KiB
Elixir
119 lines
3.0 KiB
Elixir
defmodule MessageServer.Router do
|
|
use Plug.Router
|
|
require Logger
|
|
|
|
alias MessageServer.{
|
|
MessageRequest,
|
|
RemoteHandler,
|
|
MessageHandler
|
|
}
|
|
|
|
plug(:match)
|
|
|
|
plug(:debug_content_type)
|
|
|
|
plug(Plug.Parsers,
|
|
parsers: [:urlencoded, :multipart, :json],
|
|
json_decoder: Jason,
|
|
pass: ["application/octet-stream"]
|
|
)
|
|
|
|
plug(:dispatch)
|
|
|
|
def json_request?(conn) do
|
|
conn.request_path != "/api/remote/messages"
|
|
end
|
|
|
|
post "/api/messages" do
|
|
with {:ok, message} <- validate_message_request(conn.body_params),
|
|
:ok <- MessageHandler.handle_message(message) do
|
|
conn
|
|
|> put_resp_content_type("application/json")
|
|
|> send_resp(200, Jason.encode!(%{status: "success"}))
|
|
else
|
|
{:error, reason} ->
|
|
Logger.warning("Message handling failed: #{inspect(reason)}")
|
|
|
|
conn
|
|
|> put_resp_content_type("application/json")
|
|
|> send_resp(400, Jason.encode!(%{error: reason}))
|
|
end
|
|
end
|
|
|
|
post "/api/remote/messages" do
|
|
case handle_etf_body(conn) do
|
|
{:ok, payload} ->
|
|
payload
|
|
|> RemoteHandler.handle_remote_message()
|
|
|> case do
|
|
:ok ->
|
|
conn
|
|
|> put_resp_content_type("application/json")
|
|
|> send_resp(200, Jason.encode!(%{status: "success"}))
|
|
|
|
{:error, reason} ->
|
|
Logger.warning("Remote message handling failed: #{inspect(reason)}")
|
|
|
|
conn
|
|
|> put_resp_content_type("application/json")
|
|
|> send_resp(400, Jason.encode!(%{error: reason}))
|
|
end
|
|
|
|
{:error, reason} ->
|
|
conn
|
|
|> put_resp_content_type("application/json")
|
|
|> send_resp(400, Jason.encode!(%{error: reason, message: "Invalid request body"}))
|
|
end
|
|
end
|
|
|
|
match _ do
|
|
send_resp(conn, 404, "Not found")
|
|
end
|
|
|
|
defp debug_content_type(conn, _opts) do
|
|
conn
|
|
|> Plug.Conn.get_req_header("content-type")
|
|
|> IO.inspect(label: "Received Content-Type")
|
|
|
|
conn
|
|
end
|
|
|
|
defp handle_etf_body(conn) do
|
|
with {:ok, body, _conn} <- Plug.Conn.read_body(conn),
|
|
{:ok, decoded} <- decode_etf(body) do
|
|
{:ok, decoded}
|
|
else
|
|
{:error, reason} -> {:error, "Failed to read body: #{reason}"}
|
|
{:more, _partial, _conn} -> {:error, "Body too large"}
|
|
end
|
|
end
|
|
|
|
@spec decode_etf(binary()) :: {:ok, map()} | {:error, String.t()}
|
|
defp decode_etf(binary_body) do
|
|
try do
|
|
payload = :erlang.binary_to_term(binary_body, [:safe])
|
|
{:ok, payload}
|
|
rescue
|
|
error -> {:error, "Deserialization failed: #{inspect(error)}"}
|
|
end
|
|
end
|
|
|
|
@spec validate_message_request(map()) :: {:ok, map()} | {:error, String.t()}
|
|
defp validate_message_request(params) do
|
|
required_fields = ["from", "to", "message"]
|
|
|
|
case Enum.all?(required_fields, &Map.has_key?(params, &1)) do
|
|
true ->
|
|
{:ok,
|
|
%MessageRequest{
|
|
from: params["from"],
|
|
to: params["to"],
|
|
message: params["message"]
|
|
}}
|
|
|
|
false ->
|
|
{:error, "Missing required fields: from, to, message"}
|
|
end
|
|
end
|
|
end
|