defmodule OhMyExOhIrcd.IRC.Message do
@moduledoc """
Parses and renders RFC 1459 / 2812-ish IRC lines.
:prefix COMMAND param1 param2 :trailing with spaces
Tags (IRCv3) are not handled here.
"""
@type t :: %__MODULE__{
prefix: nil | String.t(),
command: String.t(),
params: [String.t()]
}
defstruct prefix: nil, command: "", params: []
@doc "Parse a single line (no CRLF) into a Message struct."
@spec parse(String.t()) :: {:ok, t()} | {:error, :empty}
def parse(line) when is_binary(line) do
case String.trim(line) do
"" -> {:error, :empty}
trimmed -> {:ok, do_parse(trimmed)}
end
end
defp do_parse(":" <> rest) do
[prefix, rest2] = String.split(rest, " ", parts: 2)
%__MODULE__{} = parsed = do_parse(rest2)
%{parsed | prefix: prefix}
end
defp do_parse(rest) do
{command, params} =
case String.split(rest, " ", parts: 2) do
[cmd] -> {cmd, []}
[cmd, params_str] -> {cmd, parse_params(params_str)}
end
%__MODULE__{command: String.upcase(command), params: params}
end
defp parse_params(""), do: []
defp parse_params(":" <> trailing), do: [trailing]
defp parse_params(str) do
case String.split(str, " ", parts: 2) do
[param] -> [param]
[param, rest] -> [param | parse_params(rest)]
end
end
@doc "Render a Message struct to a wire line, *without* CRLF."
@spec encode(t()) :: iodata()
def encode(%__MODULE__{prefix: prefix, command: cmd, params: params}) do
[prefix_part(prefix), cmd, params_part(params)]
end
@doc "Render a Message struct to a wire line, *with* CRLF, ready to send."
@spec to_iodata(t()) :: iodata()
def to_iodata(msg), do: [encode(msg), "\r\n"]
defp prefix_part(nil), do: ""
defp prefix_part(p), do: [":", p, " "]
defp params_part([]), do: ""
defp params_part(params) do
{leading, [last]} = Enum.split(params, length(params) - 1)
leading_part = Enum.map(leading, &[" ", &1])
last_part = [" ", maybe_colon(last)]
[leading_part, last_part]
end
defp maybe_colon(""), do: ":"
defp maybe_colon(":" <> _ = p), do: [":", p]
defp maybe_colon(p) do
if String.contains?(p, " "), do: [":", p], else: p
end
@doc "Convenience: build a Message struct."
def build(command, params, prefix \\ nil) do
%__MODULE__{prefix: prefix, command: command, params: params}
end
end
neiam
/oh-my-ex-oh-ircd
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
Log in to mark this repository.
2.4 KiB · text
History
4b6fe3b