summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/irc/admin_handler.ex2
-rw-r--r--lib/irc/puppet_connection.ex226
2 files changed, 162 insertions, 66 deletions
diff --git a/lib/irc/admin_handler.ex b/lib/irc/admin_handler.ex
index cb953db..39556fe 100644
--- a/lib/irc/admin_handler.ex
+++ b/lib/irc/admin_handler.ex
@@ -13,7 +13,7 @@ defmodule Nola.Irc.AdminHandler do
end
def init([client]) do
- ExIRC.Client.add_handler client, self
+ ExIRC.Client.add_handler client, self()
{:ok, _} = Registry.register(Nola.PubSub, "op", [])
{:ok, client}
end
diff --git a/lib/irc/puppet_connection.ex b/lib/irc/puppet_connection.ex
index 1c093ca..890b976 100644
--- a/lib/irc/puppet_connection.ex
+++ b/lib/irc/puppet_connection.ex
@@ -1,9 +1,9 @@
defmodule Nola.Irc.PuppetConnection do
require Logger
@min_backoff :timer.seconds(5)
- @max_backoff :timer.seconds(2*60)
+ @max_backoff :timer.seconds(2 * 60)
@max_idle :timer.hours(12)
- @env Mix.env
+ @env Mix.env()
defmodule Supervisor do
use DynamicSupervisor
@@ -13,7 +13,12 @@ defmodule Nola.Irc.PuppetConnection do
end
def start_child(%Nola.Account{id: account_id}, %Nola.Irc.Connection{id: connection_id}) do
- spec = %{id: {account_id, connection_id}, start: {Nola.Irc.PuppetConnection, :start_link, [account_id, connection_id]}, restart: :transient}
+ spec = %{
+ id: {account_id, connection_id},
+ start: {Nola.Irc.PuppetConnection, :start_link, [account_id, connection_id]},
+ restart: :transient
+ }
+
DynamicSupervisor.start_child(__MODULE__, spec)
end
@@ -27,29 +32,48 @@ defmodule Nola.Irc.PuppetConnection do
end
end
- def whereis(account = %Nola.Account{id: account_id}, connection = %Nola.Irc.Connection{id: connection_id}) do
+ def whereis(
+ account = %Nola.Account{id: account_id},
+ connection = %Nola.Irc.Connection{id: connection_id}
+ ) do
{:global, name} = name(account_id, connection_id)
+
case :global.whereis_name(name) do
:undefined -> nil
pid -> pid
end
end
- def send_message(account = %Nola.Account{id: account_id}, connection = %Nola.Irc.Connection{id: connection_id}, channel, text, meta) do
+ def send_message(
+ account = %Nola.Account{id: account_id},
+ connection = %Nola.Irc.Connection{id: connection_id},
+ channel,
+ text,
+ meta
+ ) do
GenServer.cast(name(account_id, connection_id), {:send_message, self(), channel, text, meta})
end
- def start_and_send_message(account = %Nola.Account{id: account_id}, connection = %Nola.Irc.Connection{id: connection_id}, channel, text, meta) do
+ def start_and_send_message(
+ account = %Nola.Account{id: account_id},
+ connection = %Nola.Irc.Connection{id: connection_id},
+ channel,
+ text,
+ meta
+ ) do
{:global, name} = name(account_id, connection_id)
pid = whereis(account, connection)
- pid = if !pid do
+
+ pid =
+ if !pid do
case Nola.Irc.PuppetConnection.Supervisor.start_child(account, connection) do
{:ok, pid} -> pid
{:error, {:already_started, pid}} -> pid
end
- else
- pid
- end
+ else
+ pid
+ end
+
GenServer.cast(pid, {:send_message, self(), channel, text, meta})
end
@@ -58,7 +82,9 @@ defmodule Nola.Irc.PuppetConnection do
end
def start_link(account_id, connection_id) do
- GenServer.start_link(__MODULE__, [account_id, connection_id], name: name(account_id, connection_id))
+ GenServer.start_link(__MODULE__, [account_id, connection_id],
+ name: name(account_id, connection_id)
+ )
end
def name(account_id, connection_id) do
@@ -69,40 +95,61 @@ defmodule Nola.Irc.PuppetConnection do
account = %Nola.Account{} = Nola.Account.get(account_id)
connection = %Nola.Irc.Connection{} = Nola.Irc.Connection.lookup(connection_id)
Logger.metadata(puppet_conn: account.id <> "@" <> connection.id)
- backoff = :backoff.init(@min_backoff, @max_backoff)
- |> :backoff.type(:jitter)
- idle = :erlang.send_after(@max_idle, self, :idle)
- {:ok, %{client: nil, backoff: backoff, idle: idle, connected: false, buffer: [], channels: [], connection_id: connection_id, account_id: account_id, connected_server: nil, connected_port: nil, network: connection.network}, {:continue, :connect}}
+
+ backoff =
+ :backoff.init(@min_backoff, @max_backoff)
+ |> :backoff.type(:jitter)
+
+ idle = :erlang.send_after(@max_idle, self(), :idle)
+
+ {:ok,
+ %{
+ client: nil,
+ backoff: backoff,
+ idle: idle,
+ connected: false,
+ buffer: [],
+ channels: [],
+ connection_id: connection_id,
+ account_id: account_id,
+ connected_server: nil,
+ connected_port: nil,
+ network: connection.network
+ }, {:continue, :connect}}
end
def handle_continue(:connect, state) do
- #ipv6 = if @env == :prod do
+ # ipv6 = if @env == :prod do
# subnet = Nola.Subnet.assign(state.account_id)
# Nola.Account.put_meta(Nola.Account.get(state.account_id), "subnet", subnet)
# ip = Pfx.host(subnet, 1)
# {:ok, ipv6} = :inet_parse.ipv6_address(to_charlist(ip))
# System.cmd("add-ip6", [ip])
# ipv6
- #end
+ # end
conn = Nola.Irc.Connection.lookup(state.connection_id)
- client_opts = []
- |> Keyword.put(:network, conn.network)
- client = if state.client && Process.alive?(state.client) do
- Logger.info("Reconnecting client")
- state.client
- else
- Logger.info("Connecting")
- {:ok, client} = ExIRC.Client.start_link(debug: false)
- ExIRC.Client.add_handler(client, self())
- client
- end
+
+ client_opts =
+ []
+ |> Keyword.put(:network, conn.network)
+
+ client =
+ if state.client && Process.alive?(state.client) do
+ Logger.info("Reconnecting client")
+ state.client
+ else
+ Logger.info("Connecting")
+ {:ok, client} = ExIRC.Client.start_link(debug: false)
+ ExIRC.Client.add_handler(client, self())
+ client
+ end
base_opts = [
{:nodelay, true}
]
- #{ip, opts} = case {ipv6, :inet_res.resolve(to_charlist(conn.host), :in, :aaaa)} do
+ # {ip, opts} = case {ipv6, :inet_res.resolve(to_charlist(conn.host), :in, :aaaa)} do
# {ipv6, {:ok, {:dns_rec, _dns_header, _query, rrs = [{:dns_rr, _, _, _, _, _, _, _, _, _} | _], _, _}}} ->
# ip = rrs
# |> Enum.map(fn({:dns_rr, _, :aaaa, :in, _, _, ipv6, _, _, _}) -> ipv6 end)
@@ -115,8 +162,8 @@ defmodule Nola.Irc.PuppetConnection do
# ]
# {ip, opts}
# _ ->
- {ip, opts} = {to_charlist(conn.host), []}
- #end
+ {ip, opts} = {to_charlist(conn.host), []}
+ # end
conn_fun = if conn.tls, do: :connect_ssl!, else: :connect!
apply(ExIRC.Client, conn_fun, [client, ip, conn.port, base_opts ++ opts])
@@ -125,46 +172,76 @@ defmodule Nola.Irc.PuppetConnection do
end
def handle_continue(:connected, state) do
- state = Enum.reduce(Enum.reverse(state.buffer), state, fn(b, state) ->
- {:noreply, state} = handle_cast(b, state)
- state
- end)
+ state =
+ Enum.reduce(Enum.reverse(state.buffer), state, fn b, state ->
+ {:noreply, state} = handle_cast(b, state)
+ state
+ end)
+
{:noreply, %{state | buffer: []}}
end
- def handle_cast(cast = {:send_message, _pid, _channel, _text, _meta}, state = %{connected: false, buffer: buffer}) do
+ def handle_cast(
+ cast = {:send_message, _pid, _channel, _text, _meta},
+ state = %{connected: false, buffer: buffer}
+ ) do
{:noreply, %{state | buffer: [cast | buffer]}}
end
def handle_cast({:send_message, pid, channel, text, pub_meta}, state = %{connected: true}) do
- channels = if !Enum.member?(state.channels, channel) do
- ExIRC.Client.join(state.client, channel)
- [channel | state.channels]
- else
- state.channels
- end
+ channels =
+ if !Enum.member?(state.channels, channel) do
+ ExIRC.Client.join(state.client, channel)
+ [channel | state.channels]
+ else
+ state.channels
+ end
+
ExIRC.Client.msg(state.client, :privmsg, channel, text)
meta = %{puppet: true, from: pid, origin: Keyword.get(pub_meta, :origin, __MODULE__)}
account = Nola.Account.get(state.account_id)
nick = make_nick(state)
- sender = %ExIRC.SenderInfo{network: state.network, nick: suffix_nick(nick), user: nick, host: "puppet."}
- reply_fun = fn(text) ->
+
+ sender = %ExIRC.SenderInfo{
+ network: state.network,
+ nick: suffix_nick(nick),
+ user: nick,
+ host: "puppet."
+ }
+
+ reply_fun = fn text ->
Nola.Irc.Connection.broadcast_message(state.network, channel, text, pub_meta)
end
- message = %Nola.Message{id: FlakeId.get(), at: NaiveDateTime.utc_now(), text: text, network: state.network, account: account, sender: sender, channel: channel, replyfun: reply_fun, trigger: Nola.Irc.Connection.extract_trigger(text), meta: meta}
- message = case Nola.UserTrack.messaged(message) do
- :ok -> message
- {:ok, message} -> message
- end
+
+ message = %Nola.Message{
+ id: FlakeId.get(),
+ at: NaiveDateTime.utc_now(),
+ text: text,
+ network: state.network,
+ account: account,
+ sender: sender,
+ channel: channel,
+ replyfun: reply_fun,
+ trigger: Nola.Irc.Connection.extract_trigger(text),
+ meta: meta
+ }
+
+ message =
+ case Nola.UserTrack.messaged(message) do
+ :ok -> message
+ {:ok, message} -> message
+ end
+
Nola.Irc.Connection.publish(message, ["#{message.network}/#{channel}:messages"])
- idle = if length(state.buffer) == 0 do
- :erlang.cancel_timer(state.idle)
- :erlang.send_after(@max_idle, self(), :idle)
- else
- state.idle
- end
+ idle =
+ if length(state.buffer) == 0 do
+ :erlang.cancel_timer(state.idle)
+ :erlang.send_after(@max_idle, self(), :idle)
+ else
+ state.idle
+ end
{:noreply, %{state | idle: idle, channels: channels}}
end
@@ -177,7 +254,7 @@ defmodule Nola.Irc.PuppetConnection do
def handle_info(:disconnected, state) do
{delay, backoff} = :backoff.fail(state.backoff)
- Logger.info("#{inspect(self())} Disconnected -- reconnecting in #{inspect delay}ms")
+ Logger.info("#{inspect(self())} Disconnected -- reconnecting in #{inspect(delay)}ms")
Process.send_after(self(), :connect, delay)
{:noreply, %{state | connected: false, backoff: backoff}}
end
@@ -188,10 +265,18 @@ defmodule Nola.Irc.PuppetConnection do
# Connection successful
def handle_info({:connected, server, port}, state) do
- Logger.info("#{inspect(self())} Connected to #{inspect(server)}:#{port} #{inspect state}")
+ Logger.info("#{inspect(self())} Connected to #{inspect(server)}:#{port} #{inspect(state)}")
{_, backoff} = :backoff.succeed(state.backoff)
base_nick = make_nick(state)
- ExIRC.Client.logon(state.client, "", suffix_nick(base_nick), base_nick, "#{base_nick}'s puppet")
+
+ ExIRC.Client.logon(
+ state.client,
+ "",
+ suffix_nick(base_nick),
+ base_nick,
+ "#{base_nick}'s puppet"
+ )
+
{:noreply, %{state | backoff: backoff, connected_server: server, connected_port: port}}
end
@@ -199,8 +284,17 @@ defmodule Nola.Irc.PuppetConnection do
def handle_info(:logged_in, state) do
Logger.info("#{inspect(self())} Logged in")
{_, backoff} = :backoff.succeed(state.backoff)
+
# Create an UserTrack entry for the client so it's authenticated to the right account_id already.
- Nola.UserTrack.connected(state.network, suffix_nick(make_nick(state)), make_nick(state), "puppet.", state.account_id, %{puppet: true})
+ Nola.UserTrack.connected(
+ state.network,
+ suffix_nick(make_nick(state)),
+ make_nick(state),
+ "puppet.",
+ state.account_id,
+ %{puppet: true}
+ )
+
{:noreply, %{state | backoff: backoff}}
end
@@ -222,19 +316,21 @@ defmodule Nola.Irc.PuppetConnection do
account = Nola.Account.get(state.account_id)
user = Nola.UserTrack.find_by_account(state.network, account)
base_nick = if(user, do: user.nick, else: account.name)
- clean_nick = case String.split(base_nick, ":", parts: 2) do
- ["@"<>nick, _] -> nick
- [nick] -> nick
- end
+
+ clean_nick =
+ case String.split(base_nick, ":", parts: 2) do
+ ["@" <> nick, _] -> nick
+ [nick] -> nick
+ end
+
clean_nick
|> :unicode.characters_to_nfd_binary()
|> String.replace(~r/[^a-z0-9]/, "")
end
- if Mix.env == :dev do
+ if Mix.env() == :dev do
def suffix_nick(nick), do: "#{nick}[d]"
else
def suffix_nick(nick), do: "#{nick}[p]"
end
-
end