summaryrefslogtreecommitdiff
path: root/lib/irc
diff options
context:
space:
mode:
authorJordan Bracco <href@random.sh>2022-12-20 03:03:58 +0000
committerJordan Bracco <href@random.sh>2022-12-20 19:29:41 +0100
commit1d9916bc01e121b53dee4eb11b7cae958fc2f9d8 (patch)
treeca5a9522f4d28088f7d2346865ffe84e97c32352 /lib/irc
parentRename IRC.Membership to Nola.Membership, refs T77 (diff)
Rename IRC.UserTrack to Nola.UserTrack, refs T77
Diffstat (limited to 'lib/irc')
-rw-r--r--lib/irc/connection.ex32
-rw-r--r--lib/irc/irc.ex2
-rw-r--r--lib/irc/puppet_connection.ex6
-rw-r--r--lib/irc/user_track.ex329
4 files changed, 20 insertions, 349 deletions
diff --git a/lib/irc/connection.ex b/lib/irc/connection.ex
index 49f5774..9bb09ed 100644
--- a/lib/irc/connection.ex
+++ b/lib/irc/connection.ex
@@ -264,7 +264,7 @@ defmodule IRC.Connection do
# ISUP
def handle_info({:isup, network}, state) when is_binary(network) do
- IRC.UserTrack.clear_network(state.network)
+ Nola.UserTrack.clear_network(state.network)
if network != state.network do
Logger.warn("Possibly misconfigured network: #{network} != #{state.network}")
end
@@ -279,11 +279,11 @@ defmodule IRC.Connection do
# Received something in a channel
def handle_info({:received, text, sender, chan}, state) do
- user = if user = IRC.UserTrack.find_by_nick(state.network, sender.nick) do
+ user = if user = Nola.UserTrack.find_by_nick(state.network, sender.nick) do
user
else
Logger.error("Could not lookup user for message: #{inspect {state.network, chan, sender.nick}}")
- user = IRC.UserTrack.joined(chan, sender, [])
+ user = Nola.UserTrack.joined(chan, sender, [])
ExIRC.Client.who(state.client, chan) # Rewho everything in case of need ? We shouldn't not know that user..
user
end
@@ -297,7 +297,7 @@ defmodule IRC.Connection do
message = %IRC.Message{id: FlakeId.get(), transport: :irc, at: NaiveDateTime.utc_now(), text: text, network: state.network,
account: account, sender: sender, channel: chan, replyfun: reply_fun,
trigger: extract_trigger(text)}
- message = case IRC.UserTrack.messaged(message) do
+ message = case Nola.UserTrack.messaged(message) do
:ok -> message
{:ok, message} -> message
end
@@ -313,7 +313,7 @@ defmodule IRC.Connection do
account = Nola.Account.lookup(sender)
message = %IRC.Message{id: FlakeId.get(), transport: :irc, text: text, network: state.network, at: NaiveDateTime.utc_now(),
account: account, sender: sender, replyfun: reply_fun, trigger: extract_trigger(text)}
- message = case IRC.UserTrack.messaged(message) do
+ message = case Nola.UserTrack.messaged(message) do
:ok -> message
{:ok, message} -> message
end
@@ -324,7 +324,7 @@ defmodule IRC.Connection do
## -- Broadcast
def handle_info({:broadcast, net, account = %Nola.Account{}, message}, state) do
if net == state.conn.network do
- user = IRC.UserTrack.find_by_account(net, account)
+ user = Nola.UserTrack.find_by_account(net, account)
if user do
irc_reply(state, {user.nick, nil}, message)
end
@@ -349,7 +349,7 @@ defmodule IRC.Connection do
accounts = Enum.map(whos, fn(who = %ExIRC.Who{nick: nick, operator?: operator}) ->
priv = if operator, do: [:operator], else: []
# Don't touch -- on WHO the bot joined, not the users.
- IRC.UserTrack.joined(channel, who, priv, false)
+ Nola.UserTrack.joined(channel, who, priv, false)
account = Nola.Account.lookup(who)
if account do
{:account, who.network, channel, who.nick, account.id}
@@ -361,12 +361,12 @@ defmodule IRC.Connection do
end
def handle_info({:quit, reason, sender}, state) do
- IRC.UserTrack.quitted(sender, reason)
+ Nola.UserTrack.quitted(sender, reason)
{:noreply, state}
end
def handle_info({:joined, channel, sender}, state) do
- IRC.UserTrack.joined(channel, sender, [])
+ Nola.UserTrack.joined(channel, sender, [])
account = Nola.Account.lookup(sender)
if account do
dispatch("account", {:account, sender.network, channel, sender.nick, account.id})
@@ -375,12 +375,12 @@ defmodule IRC.Connection do
end
def handle_info({:kicked, nick, _by, channel, _reason}, state) do
- IRC.UserTrack.parted(state.network, channel, nick)
+ Nola.UserTrack.parted(state.network, channel, nick)
{:noreply, state}
end
def handle_info({:parted, channel, %ExIRC.SenderInfo{nick: nick}}, state) do
- IRC.UserTrack.parted(state.network, channel, nick)
+ Nola.UserTrack.parted(state.network, channel, nick)
{:noreply, state}
end
@@ -390,7 +390,7 @@ defmodule IRC.Connection do
end
def handle_info({:nick_changed, old_nick, new_nick}, state) do
- IRC.UserTrack.renamed(state.network, old_nick, new_nick)
+ Nola.UserTrack.renamed(state.network, old_nick, new_nick)
{:noreply, state}
end
@@ -490,22 +490,22 @@ defmodule IRC.Connection do
end
defp track_mode(network, channel, nick, "+o") do
- IRC.UserTrack.change_privileges(network, channel, nick, {[:operator], []})
+ Nola.UserTrack.change_privileges(network, channel, nick, {[:operator], []})
:ok
end
defp track_mode(network, channel, nick, "-o") do
- IRC.UserTrack.change_privileges(network, channel, nick, {[], [:operator]})
+ Nola.UserTrack.change_privileges(network, channel, nick, {[], [:operator]})
:ok
end
defp track_mode(network, channel, nick, "+v") do
- IRC.UserTrack.change_privileges(network, channel, nick, {[:voice], []})
+ Nola.UserTrack.change_privileges(network, channel, nick, {[:voice], []})
:ok
end
defp track_mode(network, channel, nick, "-v") do
- IRC.UserTrack.change_privileges(network, channel, nick, {[], [:voice]})
+ Nola.UserTrack.change_privileges(network, channel, nick, {[], [:voice]})
:ok
end
diff --git a/lib/irc/irc.ex b/lib/irc/irc.ex
index 7cd9dc8..93525e4 100644
--- a/lib/irc/irc.ex
+++ b/lib/irc/irc.ex
@@ -25,7 +25,7 @@ defmodule IRC do
if connection && (force_puppet || IRC.PuppetConnection.whereis(account, connection)) do
IRC.PuppetConnection.start_and_send_message(account, connection, channel, text)
else
- user = IRC.UserTrack.find_by_account(network, account)
+ user = Nola.UserTrack.find_by_account(network, account)
nick = if(user, do: user.nick, else: account.name)
IRC.Connection.broadcast_message(network, channel, "<#{nick}> #{text}")
end
diff --git a/lib/irc/puppet_connection.ex b/lib/irc/puppet_connection.ex
index fd0a98e..75a06f3 100644
--- a/lib/irc/puppet_connection.ex
+++ b/lib/irc/puppet_connection.ex
@@ -153,7 +153,7 @@ defmodule IRC.PuppetConnection do
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
+ message = case Nola.UserTrack.messaged(message) do
:ok -> message
{:ok, message} -> message
end
@@ -200,7 +200,7 @@ defmodule IRC.PuppetConnection 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})
+ Nola.UserTrack.connected(state.network, suffix_nick(make_nick(state)), make_nick(state), "puppet.", state.account_id, %{puppet: true})
{:noreply, %{state | backoff: backoff}}
end
@@ -220,7 +220,7 @@ defmodule IRC.PuppetConnection do
def make_nick(state) do
account = Nola.Account.get(state.account_id)
- user = IRC.UserTrack.find_by_account(state.network, account)
+ 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
diff --git a/lib/irc/user_track.ex b/lib/irc/user_track.ex
deleted file mode 100644
index 56a319f..0000000
--- a/lib/irc/user_track.ex
+++ /dev/null
@@ -1,329 +0,0 @@
-defmodule IRC.UserTrack do
- @moduledoc """
- User Track DB & Utilities
- """
-
- @ets IRC.UserTrack.Storage
- # {uuid, network, nick, nicks, privilege_map}
- # Privilege map:
- # %{"#channel" => [:operator, :voice]
- defmodule Storage do
-
- def delete(id) do
- op(fn(ets) -> :ets.delete(ets, id) end)
- end
-
- def insert(tuple) do
- op(fn(ets) -> :ets.insert(ets, tuple) end)
- end
-
- def clear_network(network) do
- op(fn(ets) ->
- spec = [
- {{:_, :"$1", :_, :_, :_, :_, :_, :_, :_, :_, :_, :_},
- [
- {:==, :"$1", {:const, network}}
- ], [:"$_"]}
- ]
- :ets.match_delete(ets, spec)
- end)
- end
-
- def op(fun) do
- GenServer.call(__MODULE__, {:op, fun})
- end
-
- def start_link do
- GenServer.start_link(__MODULE__, [], [name: __MODULE__])
- end
-
- def init([]) do
- ets = :ets.new(__MODULE__, [:set, :named_table, :protected, {:read_concurrency, true}])
- {:ok, ets}
- end
-
- def handle_call({:op, fun}, _from, ets) do
- returned = try do
- {:ok, fun.(ets)}
- rescue
- rescued -> {:error, rescued}
- catch
- rescued -> {:error, rescued}
- end
- {:reply, returned, ets}
- end
-
- def terminate(_reason, ets) do
- :ok
- end
- end
-
- defmodule Id, do: use EntropyString
-
- defmodule User do
- defstruct [:id, :account, :network, :nick, {:nicks, []}, :username, :host, :realname, {:privileges, %{}}, {:last_active, %{}}, {:options, %{}}]
-
- def to_tuple(u = %__MODULE__{}) do
- {u.id || IRC.UserTrack.Id.large_id, u.network, u.account, String.downcase(u.nick), u.nick, u.nicks || [], u.username, u.host, u.realname, u.privileges, u.last_active, u.options}
- end
-
- #tuple size: 11
- def from_tuple({id, network, account, _downcased_nick, nick, nicks, username, host, realname, privs, last_active, opts}) do
- struct = %__MODULE__{id: id, account: account, network: network, nick: nick, nicks: nicks, username: username, host: host, realname: realname, privileges: privs, last_active: last_active, options: opts}
- end
- end
-
- def find_by_account(%Nola.Account{id: id}) do
- #iex(15)> :ets.fun2ms(fn(obj = {_, net, acct, _, _, _, _, _, _}) when net == network and acct == account -> obj end)
- spec = [
- {{:_, :_, :"$2", :_, :_, :_, :_, :_, :_, :_, :_, :_},
- [
- {:==, :"$2", {:const, id}}
- ], [:"$_"]}
- ]
- results = :ets.select(@ets, spec)
- |> Enum.filter(& &1)
- for obj <- results, do: User.from_tuple(obj)
- end
-
- def find_by_account(network, nil) do
- nil
- end
-
- def find_by_account(network, %Nola.Account{id: id}) do
- #iex(15)> :ets.fun2ms(fn(obj = {_, net, acct, _, _, _, _, _, _}) when net == network and acct == account -> obj end)
- spec = [
- {{:_, :"$1", :"$2", :_, :_, :_, :_, :_, :_, :_, :_, :_},
- [
- {:andalso, {:==, :"$1", {:const, network}},
- {:==, :"$2", {:const, id}}}
- ], [:"$_"]}
- ]
- case :ets.select(@ets, spec) do
- results = [_r | _] ->
- result = results
- |> Enum.reject(fn({_, net, _, _, _, _, _, _, _, _, actives, opts}) -> network != "matrix" && net == "matrix" end)
- |> Enum.reject(fn({_, net, _, _, _, _, _, _, _, _, actives, opts}) -> network != "telegram" && net == "telegram" end)
- |> Enum.reject(fn({_, _, _, _, _, _, _, _, _, _, actives, opts}) -> network not in ["matrix", "telegram"] && Map.get(opts, :puppet) end)
- |> Enum.sort_by(fn({_, _, _, _, _, _, _, _, _, _, actives, _}) ->
- Map.get(actives, nil)
- end, {:desc, NaiveDateTime})
- |> List.first
-
- if result, do: User.from_tuple(result)
- _ -> nil
- end
- end
-
- def clear_network(network) do
- Storage.clear_network(network)
- end
-
-
- def merge_account(old_id, new_id) do
- #iex(15)> :ets.fun2ms(fn(obj = {_, net, acct, _, _, _, _, _, _}) when net == network and acct == account -> obj end)
- spec = [
- {{:_, :_, :"$1", :_, :_, :_, :_, :_, :_, :_, :_, :_},
- [
- {:==, :"$1", {:const, old_id}}
- ], [:"$_"]}
- ]
- Enum.each(:ets.select(@ets, spec), fn({id, net, _, downcased_nick, nick, nicks, username, host, realname, privs, active, opts}) ->
- Storage.op(fn(ets) ->
- :ets.insert(@ets, {id, net, new_id, downcased_nick, nick, nicks, username, host, realname, privs, active, opts})
- end)
- end)
- end
-
- def find_by_nick(%ExIRC.Who{network: network, nick: nick}) do
- find_by_nick(network, nick)
- end
-
-
- def find_by_nick(%ExIRC.SenderInfo{network: network, nick: nick}) do
- find_by_nick(network, nick)
- end
-
- def find_by_nick(network, nick) do
- case :ets.match(@ets, {:"$1", network, :_, String.downcase(nick), :_, :_, :_, :_, :_, :_, :_, :_}) do
- [[id] | _] -> lookup(id)
- _ ->
- nil
- end
- end
-
- def to_list, do: :ets.tab2list(@ets)
-
- def lookup(id) do
- case :ets.lookup(@ets, id) do
- [] -> nil
- [tuple] -> User.from_tuple(tuple)
- end
- end
-
- def operator?(network, channel, nick) do
- if user = find_by_nick(network, nick) do
- privs = Map.get(user.privileges, channel, [])
- Enum.member?(privs, :admin) || Enum.member?(privs, :operator)
- else
- false
- end
- end
-
- def channel(network, channel) do
- Enum.filter(to_list(), fn({_, network, _, _, _, _, _, _, _, channels, _, _}) ->
- Map.get(channels, channel)
- end)
- end
-
- # TODO
- def connected(network, nick, user, host, account_id, opts \\ %{}) do
- if account = Nola.Account.get(account_id) do
- user = if user = find_by_nick(network, nick) do
- user
- else
- user = %User{id: IRC.UserTrack.Id.large_id, account: account_id, network: network, nick: nick, username: user, host: host, privileges: %{}, options: opts}
- Storage.op(fn(ets) ->
- :ets.insert(ets, User.to_tuple(user))
- end)
- user
- end
-
- IRC.Connection.publish_event(network, %{type: :connect, user_id: user.id, account_id: user.account})
- :ok
- else
- :error
- end
- end
-
- def joined(c, s), do: joined(c,s,[])
-
- def joined(channel, sender=%{nick: nick, user: uname, host: host}, privileges, touch \\ true) do
- privileges = if IRC.admin?(sender) do
- privileges ++ [:admin]
- else privileges end
- user = if user = find_by_nick(sender.network, nick) do
- %User{user | username: uname, host: host, privileges: Map.put(user.privileges || %{}, channel, privileges)}
- else
- user = %User{id: IRC.UserTrack.Id.large_id, network: sender.network, nick: nick, username: uname, host: host, privileges: %{channel => privileges}}
-
- account = Nola.Account.lookup(user).id
- user = %User{user | account: account}
- end
- user = touch_struct(user, channel)
-
- if touch && user.account do
- Nola.Membership.touch(user.account, sender.network, channel)
- end
-
- Storage.op(fn(ets) ->
- :ets.insert(ets, User.to_tuple(user))
- end)
-
- IRC.Connection.publish_event({sender.network, channel}, %{type: :join, user_id: user.id, account_id: user.account})
-
- user
- end
-
- #def joined(network, channel, nick, privileges) do
- # user = if user = find_by_nick(network, nick) do
- # %User{user | privileges: Map.put(user.privileges, channel, privileges)}
- # else
- # %User{nick: nick, privileges: %{channel => privileges}}
- # end
- #
- # Storage.op(fn(ets) ->
- # :ets.insert(ets, User.to_tuple(user))
- # end)
- #end
-
- def messaged(%IRC.Message{network: network, account: account, channel: chan, sender: %{nick: nick}} = m) do
- {user, account} = if user = find_by_nick(network, nick) do
- {touch_struct(user, chan), account || Nola.Account.lookup(user)}
- else
- user = %User{network: network, nick: nick, privileges: %{}}
- account = Nola.Account.lookup(user)
- {%User{user | account: account.id}, account}
- end
- Storage.insert(User.to_tuple(user))
- if chan, do: Nola.Membership.touch(account, network, chan)
- if !m.account do
- {:ok, %IRC.Message{m | account: account}}
- else
- :ok
- end
- end
-
- def renamed(network, old_nick, new_nick) do
- if user = find_by_nick(network, old_nick) do
- old_account = Nola.Account.lookup(user)
- user = %User{user | nick: new_nick, nicks: [old_nick|user.nicks]}
- account = Nola.Account.lookup(user, false) || old_account
- user = %User{user | nick: new_nick, account: account.id, nicks: [old_nick|user.nicks]}
- Storage.insert(User.to_tuple(user))
- channels = for {channel, _} <- user.privileges, do: channel
- IRC.Connection.publish_event(network, %{type: :nick, user_id: user.id, account_id: account.id, nick: new_nick, old_nick: old_nick})
- end
- end
-
- def change_privileges(network, channel, nick, {add, remove}) do
- if user = find_by_nick(network, nick) do
- privs = Map.get(user.privileges, channel)
-
- privs = Enum.reduce(add, privs, fn(priv, acc) -> [priv|acc] end)
- privs = Enum.reduce(remove, privs, fn(priv, acc) -> List.delete(acc, priv) end)
-
- user = %User{user | privileges: Map.put(user.privileges, channel, privs)}
- Storage.insert(User.to_tuple(user))
- IRC.Connection.publish_event({network, channel}, %{type: :privileges, user_id: user.id, account_id: user.account, added: add, removed: remove})
- end
- end
-
- # XXX: Reason
- def parted(channel, %{network: network, nick: nick}) do
- parted(network, channel, nick)
- end
-
- def parted(network, channel, nick) do
- if user = find_by_nick(network, nick) do
- if user.account do
- Nola.Membership.touch(user.account, network, channel)
- end
-
- privs = Map.delete(user.privileges, channel)
- lasts = Map.delete(user.last_active, channel)
- if Enum.count(privs) > 0 do
- user = %User{user | privileges: privs}
- Storage.insert(User.to_tuple(user))
- IRC.Connection.publish_event({network, channel}, %{type: :part, user_id: user.id, account_id: user.account, reason: nil})
- else
- IRC.Connection.publish_event(network, %{type: :quit, user_id: user.id, account_id: user.account, reason: "Left all known channels"})
- Storage.delete(user.id)
- end
- end
- end
-
- def quitted(sender, reason) do
- if user = find_by_nick(sender.network, sender.nick) do
- if user.account do
- for {channel, _} <- user.privileges do
- Nola.Membership.touch(user.account, sender.network, channel)
- end
- IRC.Connection.publish_event(sender.network, %{type: :quit, user_id: user.id, account_id: user.account, reason: reason})
- end
- Storage.delete(user.id)
- end
- end
-
- defp touch_struct(user = %User{last_active: last_active}, channel) do
- now = NaiveDateTime.utc_now()
- last_active = last_active
- |> Map.put(channel, now)
- |> Map.put(nil, now)
- %User{user | last_active: last_active}
- end
-
- defp userchans(%{privileges: privileges}) do
- for({chan, _} <- privileges, do: chan)
- end
-end