From fccd0d02849f4a800fe878cb43f239f3d5e28636 Mon Sep 17 00:00:00 2001 From: href Date: Thu, 2 Sep 2021 05:57:21 +0200 Subject: telegram: plumb room --- lib/irc/connection.ex | 32 ++++++++++++++++------------ lib/lsg/telegram.ex | 19 +++++++++++++++++ lib/lsg/telegram_room.ex | 55 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 14 deletions(-) create mode 100644 lib/lsg/telegram_room.ex (limited to 'lib') diff --git a/lib/irc/connection.ex b/lib/irc/connection.ex index fee84c3..e856114 100644 --- a/lib/irc/connection.ex +++ b/lib/irc/connection.ex @@ -239,7 +239,7 @@ defmodule IRC.Connection do end def handle_cast({:privmsg, channel, line}, state) do - irc_reply(state.client, {channel, nil}, line) + irc_reply(state, {channel, nil}, line) {:noreply, state} end @@ -273,20 +273,20 @@ defmodule IRC.Connection do # Received something in a channel def handle_info({:received, text, sender, chan}, state) do - reply_fun = fn(text) -> irc_reply(state.client, {chan, sender}, text) end + reply_fun = fn(text) -> irc_reply(state, {chan, sender}, text) end account = IRC.Account.lookup(sender) message = %IRC.Message{text: text, network: network(state), account: account, sender: sender, channel: chan, replyfun: reply_fun, trigger: extract_trigger(text)} message = case IRC.UserTrack.messaged(message) do :ok -> message {:ok, message} -> message end - publish(message, ["message:#{chan}"]) + publish(message, ["message:#{chan}", "#{message.network}/#{chan}:message"]) {:noreply, state} end # Received a private message def handle_info({:received, text, sender}, state) do - reply_fun = fn(text) -> irc_reply(state.client, {sender.nick, sender}, text) end + reply_fun = fn(text) -> irc_reply(state, {sender.nick, sender}, text) end account = IRC.Account.lookup(sender) message = %IRC.Message{text: text, network: network(state), account: account, sender: sender, replyfun: reply_fun, trigger: extract_trigger(text)} message = case IRC.UserTrack.messaged(message) do @@ -302,14 +302,14 @@ defmodule IRC.Connection do if net == state.conn.network do user = IRC.UserTrack.find_by_account(net, account) if user do - irc_reply(state.client, {user.nick, nil}, message) + irc_reply(state, {user.nick, nil}, message) end end {:noreply, state} end def handle_info({:broadcast, net, chan, message}, state) do if net == state.conn.network && Enum.member?(state.conn.channels, chan) do - irc_reply(state.client, {chan, nil}, message) + irc_reply(state, {chan, nil}, message) end {:noreply, state} end @@ -382,7 +382,7 @@ defmodule IRC.Connection do end def publish(m = %IRC.Message{trigger: t = %IRC.Trigger{trigger: trigger}}, keys) do - dispatch(["triggers", "trigger:"<>trigger], {:irc, :trigger, trigger, m}) + dispatch(["triggers", "#{m.network}/#{m.channel}:triggers", "trigger:"<>trigger], {:irc, :trigger, trigger, m}) end def dispatch(keys, content, sub \\ IRC.PubSub) @@ -419,32 +419,36 @@ defmodule IRC.Connection do # irc_reply(ExIRC.Client pid, {channel or nick, ExIRC.Sender}, binary | replies # replies :: {:kick, reason} | {:kick, nick, reason} | {:mode, mode, nick} - defp irc_reply(client, {target, _}, text) when is_binary(text) or is_list(text) do + defp irc_reply(%{client: client, network: network}, {target, _}, text) when is_binary(text) or is_list(text) do lines = IRC.splitlong(text) |> Enum.map(fn(x) -> if(is_list(x), do: x, else: String.split(x, "\n")) end) |> List.flatten() for line <- lines do ExIRC.Client.msg(client, :privmsg, target, line) end + case :global.whereis_name({LSG.TelegramRoom, network, target}) do + pid when is_pid(pid) -> send(pid, {:raw, text}) + _ -> :ok + end end - defp irc_reply(client, {target, %{nick: nick}}, {:kick, reason}) do + defp irc_reply(%{client: client}, {target, %{nick: nick}}, {:kick, reason}) do ExIRC.Client.kick(client, target, nick, reason) end - defp irc_reply(client, {target, _}, {:kick, nick, reason}) do + defp irc_reply(%{client: client}, {target, _}, {:kick, nick, reason}) do ExIRC.Client.kick(client, target, nick, reason) end - defp irc_reply(client, {target, %{nick: nick}}, {:mode, mode}) do - ExIRC.Client.mode(client, target, mode, nick) + defp irc_reply(%{client: client}, {target, %{nick: nick}}, {:mode, mode}) do + ExIRC.Client.mode(%{client: client}, target, mode, nick) end - defp irc_reply(client, target, {:mode, mode, nick}) do + defp irc_reply(%{client: client}, target, {:mode, mode, nick}) do ExIRC.Client.mode(client, target, mode, nick) end - defp irc_reply(client, target, {:channel_mode, mode}) do + defp irc_reply(%{client: client}, target, {:channel_mode, mode}) do ExIRC.Client.mode(client, target, mode) end diff --git a/lib/lsg/telegram.ex b/lib/lsg/telegram.ex index d393a2c..e5790da 100644 --- a/lib/lsg/telegram.ex +++ b/lib/lsg/telegram.ex @@ -14,6 +14,10 @@ defmodule LSG.Telegram do end @impl Telegram.ChatBot + def init(chat_id) when chat_id < 0 do + {:ok, state} = LSG.TelegramRoom.init(chat_id) + {:ok, %{room_state: state}} + end def init(chat_id) do Logger.info("Telegram session starting: #{chat_id}") account = IRC.Account.find_meta_account("telegram-id", chat_id) @@ -22,6 +26,11 @@ defmodule LSG.Telegram do end @impl Telegram.ChatBot + def handle_update(update, token, %{room_state: room_state}) do + {:ok, room_state} = LSG.TelegramRoom.handle_update(update, token, room_state) + {:ok, %{room_state: room_state}} + end + def handle_update(%{"message" => m = %{"chat" => %{"type" => "private"}, "text" => text = "/start"<>_}}, _token, state) do text = "*Welcome to beautte!*\n\nQuery the bot on IRC and say \"enable-telegram\" to continue." send_message(m["chat"]["id"], text) @@ -168,6 +177,16 @@ defmodule LSG.Telegram do {:ok, state} end + @impl Telegram.ChatBot + def handle_info(info, %{room_state: room_state}) do + {:ok, room_state} = LSG.TelegramRoom.handle_info(info, room_state) + {:ok, %{room_state: room_state}} + end + + def handle_info(_info, state) do + {:ok, state} + end + defp as_irc_message(id, text, account) do reply_fun = fn(text) -> send_message(id, text) end trigger_text = cond do diff --git a/lib/lsg/telegram_room.ex b/lib/lsg/telegram_room.ex new file mode 100644 index 0000000..8c228e1 --- /dev/null +++ b/lib/lsg/telegram_room.ex @@ -0,0 +1,55 @@ +defmodule LSG.TelegramRoom do + require Logger + @behaviour Telegram.ChatBot + alias Telegram.Api + + @impl Telegram.ChatBot + def init(id) do + token = Keyword.get(Application.get_env(:lsg, :telegram, []), :key) + {:ok, chat} = Api.request(token, "getChat", chat_id: id) + Logger.debug("Starting ChatBot for room #{id} \"#{chat["title"]}\"") + [net, chan] = String.split(chat["title"], "/", parts: 2) + case IRC.Connection.get_network(net, chan) do + %IRC.Connection{} -> + :global.register_name({__MODULE__, net, chan}, self()) + {:ok, _} = Registry.register(IRC.PubSub, "#{net}/#{chan}:message", plugin: __MODULE__) + {:ok, _} = Registry.register(IRC.PubSub, "#{net}/#{chan}:triggers", plugin: __MODULE__) + err -> + Logger.warn("Did not found telegram match for #{id} \"#{chat["title"]}\"") + end + {:ok, %{id: id, net: net, chan: chan}} + end + + def handle_update(%{"message" => %{"from" => %{"id" => user_id}, "text" => text}}, _token, state) do + account = IRC.Account.find_meta_account("telegram-id", user_id) + user = IRC.UserTrack.find_by_account(state.net, account) + nick = if(user, do: user.nick, else: account.name) + prefix = "<#{nick}> " + IRC.Connection.broadcast_message(state.net, state.chan, "#{prefix}#{text}") + {:ok, state} + end + + def handle_update(update, token, state) do + {:ok, state} + end + + def handle_info({:irc, _, %IRC.Message{sender: %{nick: nick}, text: text}}, state) do + LSG.Telegram.send_message(state.id, "<#{nick}> #{text}") + {:ok, state} + end + + def handle_info({:raw, lines}, state) when is_list(lines) do + formatted = for l <- lines, into: <<>>, do: l <> "\n" + LSG.Telegram.send_message(state.id, formatted) + {:ok, state} + end + + def handle_info({:raw, line}, state) do + handle_info({:raw, [line]}, state) + end + + def handle_info(info, state) do + {:ok, state} + end + +end -- cgit v1.2.3