diff options
author | href <href@random.sh> | 2021-09-01 10:30:18 +0200 |
---|---|---|
committer | href <href@random.sh> | 2021-09-01 10:30:18 +0200 |
commit | 75687711f35355bc30e4829439384aab28fcac6d (patch) | |
tree | 8f3256f472893c39720a684d390e890a152f7303 /lib/lsg_irc/tell_plugin.ex | |
parent | link: post_* callbacks; html & pdftitle. (diff) |
Commit all the changes that hasn't been committed + updates.
Diffstat (limited to 'lib/lsg_irc/tell_plugin.ex')
-rw-r--r-- | lib/lsg_irc/tell_plugin.ex | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/lib/lsg_irc/tell_plugin.ex b/lib/lsg_irc/tell_plugin.ex new file mode 100644 index 0000000..a683b43 --- /dev/null +++ b/lib/lsg_irc/tell_plugin.ex @@ -0,0 +1,93 @@ +defmodule LSG.IRC.TellPlugin do + use GenServer + + @moduledoc """ + # Tell + + * **!tell `<nick>` `<message>`**: tell `message` to `nick` when they reconnect. + """ + + def irc_doc, do: @moduledoc + def start_link() do + GenServer.start_link(__MODULE__, [], name: __MODULE__) + end + + def dets do + (LSG.data_path() <> "/tell.dets") |> String.to_charlist() + end + + def init([]) do + regopts = [plugin: __MODULE__] + {:ok, _} = Registry.register(IRC.PubSub, "account", regopts) + {:ok, _} = Registry.register(IRC.PubSub, "trigger:tell", regopts) + {:ok, dets} = :dets.open_file(dets(), [type: :bag]) + {:ok, %{dets: dets}} + end + + def handle_info({:irc, :trigger, "tell", m = %IRC.Message{trigger: %IRC.Trigger{type: :bang, args: [nick_target | message]}}}, state) do + target = IRC.Account.find_always_by_nick(m.network, m.channel, nick_target) + message = Enum.join(message, " ") + with \ + {:target, %IRC.Account{} = target} <- {:target, target}, + {:same, false} <- {:same, target.id == m.account.id}, + target_user = IRC.UserTrack.find_by_account(m.network, target), + target_nick = if(target_user, do: target_user.nick, else: target.name), + present? = if(target_user, do: Map.has_key?(target_user.last_active, m.channel)), + {:absent, true, _} <- {:absent, !present?, target_nick}, + {:message, message} <- {:message, message} + do + obj = { {m.network, m.channel, target.id}, m.account.id, message, NaiveDateTime.utc_now()} + :dets.insert(state.dets, obj) + m.replyfun.("will tell to #{target_nick}") + else + {:same, _} -> m.replyfun.("are you so stupid that you need a bot to tell yourself things ?") + {:target, _} -> m.replyfun.("#{nick_target} unknown") + {:absent, _, nick} -> m.replyfun.("#{nick} is here, tell yourself!") + {:message, _} -> m.replyfun.("can't tell without a message") + end + {:noreply, state} + end + + def handle_info({:account, network, channel, nick, account_id}, state) do + messages = :dets.lookup(state.dets, {network, channel, account_id}) + if messages != [] do + strs = Enum.map(messages, fn({_, from, message, at}) -> + account = IRC.Account.get(from) + user = IRC.UserTrack.find_by_account(network, account) + fromnick = if user, do: user.nick, else: account.name + "#{nick}: <#{fromnick}> #{message}" + end) + Enum.each(strs, fn(s) -> IRC.Connection.broadcast_message(network, channel, s) end) + :dets.delete(state.dets, {network, channel, account_id}) + end + {:noreply, state} + end + + def handle_info({:account_change, old_id, new_id}, state) do + #:ets.fun2ms(fn({ {_net, _chan, target_id}, from_id, _, _} = obj) when (target_id == old_id) or (from_id == old_id) -> obj end) + spec = [{{{:"$1", :"$2", :"$3"}, :"$4", :_, :_}, [{:orelse, {:==, :"$3", {:const, old_id}}, {:==, :"$4", {:const, old_id}}}], [:"$_"]}] + Util.Util.ets_mutate_select_each(:dets, state.dets, spec, fn(table, obj) -> + case obj do + { {net, chan, ^old_id}, from_id, message, at } = obj -> + :dets.delete(obj) + :dets.insert(table, {{net, chan, new_id}, from_id, message, at}) + {key, ^old_id, message, at} = obj -> + :dets.delete(table, obj) + :dets.insert(table, {key, new_id, message, at}) + _ -> :ok + end + end) + {:noreply, state} + end + + + def handle_info(info, state) do + {:noreply, state} + end + + def terminate(_, state) do + :dets.close(state.dets) + :ok + end + +end |