diff options
Diffstat (limited to 'lib/lsg_matrix/matrix.ex')
-rw-r--r-- | lib/lsg_matrix/matrix.ex | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/lib/lsg_matrix/matrix.ex b/lib/lsg_matrix/matrix.ex new file mode 100644 index 0000000..bea6d8b --- /dev/null +++ b/lib/lsg_matrix/matrix.ex @@ -0,0 +1,158 @@ +defmodule LSG.Matrix do + require Logger + alias Polyjuice.Client + + @behaviour MatrixAppService.Adapter.Room + @behaviour MatrixAppService.Adapter.Transaction + @behaviour MatrixAppService.Adapter.User + + def dets(part) do + (LSG.data_path() <> "/matrix-#{to_string(part)}.dets") |> String.to_charlist() + end + + def setup() do + {:ok, _} = :dets.open_file(dets(:rooms), []) + {:ok, _} = :dets.open_file(dets(:room_aliases), []) + {:ok, _} = :dets.open_file(dets(:users), []) + :ok + end + + def myself?("@_dev:random.sh"), do: true + def myself?("@_dev."<>_), do: true + def myself?(_), do: false + + + def get_or_create_matrix_user(id) do + if mxid = lookup_user(id) do + mxid + else + opts = [ + type: "m.login.application_service", + inhibit_login: true, + device_id: "APP_SERVICE", + initial_device_display_name: "Application Service", + username: "_dev.#{id}" + ] + Logger.debug("Registering user for #{id}") + {:ok, %{"user_id" => mxid}} = Polyjuice.Client.LowLevel.register(client(), opts) + :dets.insert(dets(:users), {id, mxid}) + end + end + + def lookup_user(id) do + case :dets.lookup(dets(:users), id) do + [{_, matrix_id}] -> matrix_id + _ -> nil + end + end + + def user_name("@"<>name) do + [username, _] = String.split(name, ":", parts: 2) + username + end + + def application_childs() do + import Supervisor.Spec + [ + supervisor(LSG.Matrix.Room.Supervisor, [], [name: IRC.PuppetConnection.Supervisor]), + ] + end + + def after_start() do + rooms = :dets.foldl(fn({id, _, _, _}, acc) -> [id | acc] end, [], dets(:rooms)) + for room <- rooms, do: LSG.Matrix.Room.start(room) + end + + def lookup_room(room) do + case :dets.lookup(dets(:rooms), room) do + [{_, network, channel, opts}] -> {:ok, Map.merge(opts, %{network: network, channel: channel})} + _ -> {:error, :no_such_room} + end + end + + def lookup_room_alias(room_alias) do + case :dets.lookup(dets(:room_aliases), room_alias) do + [{_, room_id}] -> {:ok, room_id} + _ -> {:error, :no_such_room_alias} + end + end + + def lookup_or_create_room(room_alias) do + case lookup_room_alias(room_alias) do + {:ok, room_id} -> {:ok, room_id} + {:error, :no_such_room_alias} -> create_room(room_alias) + end + end + + def create_room(room_alias) do + Logger.debug("Matrix: creating room #{inspect room_alias}") + localpart = localpart(room_alias) + with {:ok, network, channel} <- extract_network_channel_from_localpart(localpart), + %IRC.Connection{} <- IRC.Connection.get_network(network, channel), + room = [visibility: :public, room_alias_name: localpart, name: "#{network}/#{channel}"], + {:ok, %{"room_id" => room_id}} <- Client.Room.create_room(client(), room) do + Logger.info("Matrix: created room #{room_alias} #{room_id}") + :dets.insert(dets(:rooms), {room_id, network, channel, %{}}) + :dets.insert(dets(:room_aliases), {room_alias, room_id}) + {:ok, room_id} + else + nil -> {:error, :no_such_network_channel} + error -> error + end + end + + def localpart(room_alias) do + [<<"#", localpart :: binary>>, _] = String.split(room_alias, ":", parts: 2) + localpart + end + + def extract_network_channel_from_localpart(localpart) do + s = localpart + |> String.replace("dev.", "") + |> String.split("_", parts: 2) + + case s do + [network, channel] -> {:ok, network, channel} + _ -> {:error, :invalid_localpart} + end + end + + @impl MatrixAppService.Adapter.Room + def query_alias(room_alias) do + case lookup_or_create_room(room_alias) do + {:ok, room_id} -> + LSG.Matrix.Room.start(room_id) + :ok + error -> error + end + end + + @impl MatrixAppService.Adapter.Transaction + def new_event(event = %MatrixAppService.Event{}) do + Logger.debug("New matrix event: #{inspect event}") + if room_id = event.room_id, do: LSG.Matrix.Room.start_and_send_matrix_event(room_id, event) + :noop + end + + @impl MatrixAppService.Adapter.User + def query_user(user_id) do + Logger.warn("Matrix lookup user: #{inspect user_id}") + :error + end + + def client(opts \\ []) do + base_url = Application.get_env(:matrix_app_service, :base_url) + access_token = Application.get_env(:matrix_app_service, :access_token) + default_opts = [ + access_token: access_token, + device_id: "APP_SERVICE", + application_service: true, + user_id: nil + ] + opts = Keyword.merge(default_opts, opts) + + Polyjuice.Client.LowLevel.create(base_url, opts) + end + + +end |