Current section
Files
Jump to
Current section
Files
lib/messanger.ex
defmodule Mouth.Messanger do
@moduledoc """
"""
@cannot_call_directly_error """
cannot call Mouth.Messanger directly. Instead implement your own Messanger module
with: use Mouth.Messanger, otp_app: :my_app
"""
require Logger
defmacro __using__(opts) do
quote bind_quoted: [opts: opts] do
@spec deliver(Mouth.Message.t) :: Mouth.Message.t
def deliver(message) do
config = build_config()
Mouth.Messanger.deliver(config.adapter, message, config)
end
def status(id) do
config = build_config()
Mouth.Messanger.status(config.adapter, id, config)
end
otp_app = Keyword.fetch!(opts, :otp_app)
defp build_config, do: Mouth.Messanger.build_config(__MODULE__, unquote(otp_app))
end
end
@doc false
def deliver(_message) do
raise @cannot_call_directly_error
end
def status(_) do
raise @cannot_call_directly_error
end
@doc false
def deliver(adapter, message, config) do
message = validate_and_normalize(message, adapter)
result =
if message.to == [] do
debug_unsent(message)
{:error, "Empty recipient"}
else
debug_sent(message, adapter)
adapter.deliver(message, config)
end
result
end
@doc false
def status(adapter, id, config) do
adapter.status(id, config)
end
defp debug_sent(message, adapter) do
Logger.debug """
Sending message with #{inspect adapter}:
#{inspect message, limit: :infinity}
"""
end
defp debug_unsent(message) do
Logger.debug """
Message was not sent because recipient is empty.
Full message - #{inspect message, limit: :infinity}
"""
end
defp validate_and_normalize(message, adapter) do
validate(message, adapter)
end
defp validate(message, _adapter) do
validate_recipients(message)
end
defp validate_recipients(%Mouth.Message{} = message) do
if Enum.all?(
Enum.map([:to], &Map.get(message, &1)),
&nil_recipient?/1
) do
raise Mouth.NilRecipientsError, message
else
message
end
end
defp nil_recipient?(nil), do: true
defp nil_recipient?([]), do: false
defp nil_recipient?([_] = recipients) do
Enum.all?(recipients, &nil_recipient?/1)
end
defp nil_recipient?(_), do: false
def build_config(messanger, otp_app) do
otp_app
|> Application.fetch_env!(messanger)
|> Map.new
|> handle_adapter_config
end
defp handle_adapter_config(base_config = %{adapter: adapter}) do
adapter.handle_config(base_config)
end
end