summaryrefslogtreecommitdiff
path: root/lib/lsg/telegram_room.ex
blob: 1eeec8fdd78febdf7e7d6408ed12e93dd97ebb23 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
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}:messages", 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)
    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, _, %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

  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