summaryrefslogtreecommitdiff
path: root/lib/irc/puppet_connection.ex
diff options
context:
space:
mode:
Diffstat (limited to 'lib/irc/puppet_connection.ex')
-rw-r--r--lib/irc/puppet_connection.ex238
1 files changed, 0 insertions, 238 deletions
diff --git a/lib/irc/puppet_connection.ex b/lib/irc/puppet_connection.ex
deleted file mode 100644
index 91a26b3..0000000
--- a/lib/irc/puppet_connection.ex
+++ /dev/null
@@ -1,238 +0,0 @@
-defmodule IRC.PuppetConnection do
- require Logger
- @min_backoff :timer.seconds(5)
- @max_backoff :timer.seconds(2*60)
- @max_idle :timer.hours(12)
- @env Mix.env
-
- defmodule Supervisor do
- use DynamicSupervisor
-
- def start_link() do
- DynamicSupervisor.start_link(__MODULE__, [], name: __MODULE__)
- end
-
- def start_child(%IRC.Account{id: account_id}, %IRC.Connection{id: connection_id}) do
- spec = %{id: {account_id, connection_id}, start: {IRC.PuppetConnection, :start_link, [account_id, connection_id]}, restart: :transient}
- DynamicSupervisor.start_child(__MODULE__, spec)
- end
-
- @impl true
- def init(_init_arg) do
- DynamicSupervisor.init(
- strategy: :one_for_one,
- max_restarts: 10,
- max_seconds: 1
- )
- end
- end
-
- def whereis(account = %IRC.Account{id: account_id}, connection = %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 = %IRC.Account{id: account_id}, connection = %IRC.Connection{id: connection_id}, channel, text) do
- GenServer.cast(name(account_id, connection_id), {:send_message, self(), channel, text})
- end
-
- def start_and_send_message(account = %IRC.Account{id: account_id}, connection = %IRC.Connection{id: connection_id}, channel, text) do
- {:global, name} = name(account_id, connection_id)
- pid = whereis(account, connection)
- pid = if !pid do
- case IRC.PuppetConnection.Supervisor.start_child(account, connection) do
- {:ok, pid} -> pid
- {:error, {:already_started, pid}} -> pid
- end
- else
- pid
- end
- GenServer.cast(pid, {:send_message, self(), channel, text})
- end
-
- def start(account = %IRC.Account{}, connection = %IRC.Connection{}) do
- IRC.PuppetConnection.Supervisor.start_child(account, connection)
- end
-
- def start_link(account_id, connection_id) do
- GenServer.start_link(__MODULE__, [account_id, connection_id], name: name(account_id, connection_id))
- end
-
- def name(account_id, connection_id) do
- {:global, {PuppetConnection, account_id, connection_id}}
- end
-
- def init([account_id, connection_id]) do
- account = %IRC.Account{} = IRC.Account.get(account_id)
- connection = %IRC.Connection{} = 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}}
- end
-
- def handle_continue(:connect, state) do
- #ipv6 = if @env == :prod do
- # subnet = Nola.Subnet.assign(state.account_id)
- # IRC.Account.put_meta(IRC.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
-
- conn = 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
-
- base_opts = [
- {:nodelay, true}
- ]
-
- #{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)
- # |> Enum.shuffle()
- # |> List.first()
-
- # opts = [
- # :inet6,
- # {:ifaddr, ipv6}
- # ]
- # {ip, opts}
- # _ ->
- {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])
-
- {:noreply, %{state | client: client}}
- 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)
- {:noreply, %{state | buffer: []}}
- end
-
- def handle_cast(cast = {:send_message, _pid, _channel, _text}, state = %{connected: false, buffer: buffer}) do
- {:noreply, %{state | buffer: [cast | buffer]}}
- end
-
- def handle_cast({:send_message, pid, channel, text}, 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
- ExIRC.Client.msg(state.client, :privmsg, channel, text)
-
- meta = %{puppet: true, from: pid}
- account = IRC.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) ->
- IRC.Connection.broadcast_message(state.network, channel, text)
- end
- message = %IRC.Message{id: FlakeId.get(), at: NaiveDateTime.utc_now(), text: text, network: state.network, account: account, sender: sender, channel: channel, replyfun: reply_fun, trigger: IRC.Connection.extract_trigger(text), meta: meta}
- message = case IRC.UserTrack.messaged(message) do
- :ok -> message
- {:ok, message} -> message
- end
- 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
-
- {:noreply, %{state | idle: idle, channels: channels}}
- end
-
- def handle_info(:idle, state) do
- ExIRC.Client.quit(state.client, "Puppet was idle for too long")
- ExIRC.Client.stop!(state.client)
- {:stop, :normal, state}
- end
-
- def handle_info(:disconnected, state) do
- {delay, backoff} = :backoff.fail(state.backoff)
- Logger.info("#{inspect(self())} Disconnected -- reconnecting in #{inspect delay}ms")
- Process.send_after(self(), :connect, delay)
- {:noreply, %{state | connected: false, backoff: backoff}}
- end
-
- def handle_info(:connect, state) do
- {:noreply, state, {:continue, :connect}}
- end
-
- # Connection successful
- def handle_info({:connected, server, port}, state) do
- 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")
- {:noreply, %{state | backoff: backoff, connected_server: server, connected_port: port}}
- end
-
- # Logon successful
- 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.
- IRC.UserTrack.connected(state.network, suffix_nick(make_nick(state)), make_nick(state), "puppet.", state.account_id, %{puppet: true})
- {:noreply, %{state | backoff: backoff}}
- end
-
- # ISUP
- def handle_info({:isup, network}, state) do
- {:noreply, %{state | network: network, connected: true}, {:continue, :connected}}
- end
-
- # Been kicked
- def handle_info({:kicked, _sender, chan, _reason}, state) do
- {:noreply, %{state | channels: state.channels -- [chan]}}
- end
-
- def handle_info(_info, state) do
- {:noreply, state}
- end
-
- def make_nick(state) do
- account = IRC.Account.get(state.account_id)
- user = IRC.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
- end
-
- if Mix.env == :dev do
- def suffix_nick(nick), do: "#{nick}[d]"
- else
- def suffix_nick(nick), do: "#{nick}[p]"
- end
-
-end