summaryrefslogblamecommitdiff
path: root/lib/lsg/telegram_room.ex
blob: f7e42c6b8754d07461226c7d39130b9057171308 (plain) (tree)
1
2
3
4
5




                             













                                                                                                   







                                                                        
                                                                                               
                                                                                               
                                                                                              


                                                                                  
                                         




                                                                                                      
                                                      
                                                                   


                












                                                                                                                                                     



                                            



                                                  





                                                                                                 


                
                                 
                                            


                

















































                                                                                                                        
   
defmodule LSG.TelegramRoom do
  require Logger
  @behaviour Telegram.ChatBot
  alias Telegram.Api

  def dets() do
    (LSG.data_path() <> "/telegram-rooms.dets") |> String.to_charlist()
  end

  def setup() do
    {:ok, _} = :dets.open_file(dets(), [])
    :ok
  end

  def after_start() do
    rooms = :dets.foldl(fn({id, _, _}, acc) -> [id | acc] end, [], dets())
    for id <- rooms, do: Telegram.Bot.ChatBot.Chat.Session.Supervisor.start_child(LSG.Telegram, id)
  end

  @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{} ->
        {:ok, _} = Registry.register(IRC.PubSub, "#{net}/#{chan}:messages", plugin: __MODULE__)
        {:ok, _} = Registry.register(IRC.PubSub, "#{net}/#{chan}:triggers", plugin: __MODULE__)
        {:ok, _} = Registry.register(IRC.PubSub, "#{net}/#{chan}:outputs", plugin: __MODULE__)
      err ->
        Logger.warn("Did not found telegram match for #{id} \"#{chat["title"]}\"")
    end
    :dets.insert(dets(), {id, net, chan})
    {: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)
    connection = IRC.Connection.get_network(state.net)
    IRC.send_message_as(account, state.net, state.chan, text, true)
    {:ok, state}
  end

  def handle_update(data = %{"message" => %{"from" => %{"id" => user_id}, "location" => %{"latitude" => lat, "longitude" => lon}}}, _token, state) do
    account = IRC.Account.find_meta_account("telegram-id", user_id)
    connection = IRC.Connection.get_network(state.net)
    IRC.send_message_as(account, state.net, state.chan, "@ #{lat}, #{lon}", true)
    {:ok, state}
  end

  for type <- ~w(photo voice video document animation) do
    def handle_update(data = %{"message" => %{unquote(type) => _}}, token, state) do
      upload(unquote(type), data, token, state)
    end
  end

  def handle_update(update, token, state) do
    {:ok, state}
  end

  def handle_info({:irc, _, _, message}, state) do
    handle_info({:irc, nil, message}, state)
  end

  def handle_info({:irc, _, message = %IRC.Message{sender: %{nick: nick}, text: text}}, state) do
    if Map.get(message.meta, :from) == self() do
    else
      body = if Map.get(message.meta, :self), do: text, else: "<#{nick}> #{text}"
      LSG.Telegram.send_message(state.id, body)
    end
    {:ok, state}
  end

  def handle_info(info, state) do
    Logger.info("UNhandled #{inspect info}")
    {:ok, state}
  end

  defp upload(_type, %{"message" => m = %{"chat" => %{"id" => chat_id}, "from" => %{"id" => user_id}}}, token, state) do
    account = IRC.Account.find_meta_account("telegram-id", user_id)
    if account do
      {content, type} = cond do
        m["photo"] -> {m["photo"], "photo"}
        m["voice"] -> {m["voice"], "voice message"}
        m["video"] -> {m["video"], "video"}
        m["document"] -> {m["document"], "file"}
        m["animation"] -> {m["animation"], "gif"}
      end

      file = if is_list(content) && Enum.count(content) > 1 do
        Enum.sort_by(content, fn(p) -> p["file_size"] end, &>=/2)
        |> List.first()
      else
        content
      end

      file_id = file["file_id"]
      file_unique_id = file["file_unique_id"]
      text = if(m["caption"], do: m["caption"] <> " ", else: "")

      spawn(fn() ->
        with \
          {:ok, file} <- Telegram.Api.request(token, "getFile", file_id: file_id),
          path = "https://api.telegram.org/file/bot#{token}/#{file["file_path"]}",
          {:ok, %HTTPoison.Response{status_code: 200, body: body}} <- HTTPoison.get(path),
          <<smol_body::binary-size(20), _::binary>> = body,
          {:ok, magic} <- GenMagic.Pool.perform(LSG.GenMagic, {:bytes, smol_body}),
          bucket = Application.get_env(:lsg, :s3, []) |> Keyword.get(:bucket),
          ext = Path.extname(file["file_path"]),
          s3path = "#{account.id}/#{file_unique_id}#{ext}",
          s3req = ExAws.S3.put_object(bucket, s3path, body, acl: :public_read, content_type: magic.mime_type),
          {:ok, _} <- ExAws.request(s3req)
        do
          path = LSGWeb.Router.Helpers.url(LSGWeb.Endpoint) <> "/files/#{s3path}"
          txt = "#{type}: #{text}#{path}"
          connection = IRC.Connection.get_network(state.net)
          IRC.send_message_as(account, state.net, state.chan, txt, true)
        else
          error ->
            Telegram.Api.request(token, "sendMessage", chat_id: chat_id, text: "File upload failed, sorry.")
            Logger.error("Failed upload from Telegram: #{inspect error}")
        end
      end)

      {:ok, state}
    end
  end

end