diff --git a/.gitignore b/.gitignore index 3e69d51..1e7ce82 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ erl_crash.dump *.ez /rel/ +/.elixir_ls/ diff --git a/README.md b/README.md index 9708033..2e77be7 100644 --- a/README.md +++ b/README.md @@ -67,14 +67,14 @@ log you into matrix.org and you can play around with your bot. The package can be installed as: - 1. Add bender to your list of dependencies in `mix.exs`: +1. Add bender to your list of dependencies in `mix.exs`: - def deps do - [{:bender, git: "https://github.com/DylanGriffith/bender.git"}] - end + def deps do + [{:bender, git: "https://github.com/DylanGriffith/bender.git"}] + end - 2. Ensure bender is started before your application: +2. Ensure bender is started before your application: - def application do - [applications: [:bender]] - end + def application do + [applications: [:bender]] + end diff --git a/config/config.exs b/config/config.exs index a8ad5f1..9850935 100644 --- a/config/config.exs +++ b/config/config.exs @@ -13,9 +13,12 @@ use Mix.Config config :bender, command_prefix: "bender", matrix_home_server: "matrix.org", + matrix_home_server_protocol: "https", + matrix_home_server_port: "443", matrix_user: "bender", matrix_password: "bender", commands: [Bender.Commands.Echo, Bender.Commands.Ping], + event_reactions: [], room_names: ["#bender:matrix.org"] # diff --git a/lib/bender.ex b/lib/bender.ex index de66727..861fa1f 100644 --- a/lib/bender.ex +++ b/lib/bender.ex @@ -1,23 +1,33 @@ defmodule Bender do use Application - # See http://elixir-lang.org/docs/stable/elixir/Application.html - # for more information on OTP Applications def start(_type, _args) do import Supervisor.Spec, warn: false home_server = Application.get_env(:bender, :matrix_home_server) + home_server_protocol = Application.get_env(:bender, :matrix_home_server_protocol, "https") + home_server_port = Application.get_env(:bender, :matrix_home_server_port, "443") user = Application.get_env(:bender, :matrix_user) password = Application.get_env(:bender, :matrix_password) room_names = Application.get_env(:bender, :room_names) commands = Application.get_env(:bender, :commands) + event_reactions = Application.get_env(:bender, :event_reactions) children = [ - worker(Bender.Bot, [%Matrix.Config{home_server: home_server, user: user, password: password}, room_names, commands]), + worker(Bender.Bot, [ + %Matrix.Config{ + home_server: home_server, + user: user, + password: password, + home_server_protocol: home_server_protocol, + home_server_port: home_server_port + }, + room_names, + commands, + event_reactions + ]) ] - # See http://elixir-lang.org/docs/stable/elixir/Supervisor.html - # for other strategies and supported options opts = [strategy: :one_for_one, name: Bender.Supervisor] Supervisor.start_link(children, opts) end diff --git a/lib/bender/bot.ex b/lib/bender/bot.ex index 316921d..324b51a 100644 --- a/lib/bender/bot.ex +++ b/lib/bender/bot.ex @@ -1,66 +1,117 @@ defmodule Bender.Bot do use GenServer - def start_link(config = %Matrix.Config{}, room_names, commands) do - GenServer.start_link(__MODULE__, [config, room_names, commands], name: __MODULE__) + require Logger + + def start_link(config = %Matrix.Config{}, room_names, commands, event_reactions) do + config |> IO.inspect() + + GenServer.start_link(__MODULE__, [config, room_names, commands, event_reactions], + name: __MODULE__ + ) + |> IO.inspect() end - def init([config = %Matrix.Config{}, room_names, commands]) do - event_manager = setup_event_manager(commands) + def init([config = %Matrix.Config{}, room_names, commands, event_reactions]) do + event_manager = setup_event_manager(commands, event_reactions) # Login - session = Matrix.Client.login!(config) + session = Matrix.Client.login!(config) |> IO.inspect() + + Logger.debug(fn -> "Login Result (Session): #{inspect(session, pretty: true)}" end) # Join Rooms - rooms = Enum.map room_names, fn(room_name) -> - Matrix.Client.join!(session, room_name) - end + rooms = + Enum.map(room_names, fn room_name -> + Matrix.Client.join!(session, room_name) + end) + + Logger.debug(fn -> "Rooms: #{inspect(rooms, pretty: true)}" end) # Trigger first poll for events - GenServer.cast(self, :poll_matrix) - {:ok, %{session: session, rooms: rooms, event_manager: event_manager, from: nil, commands: commands}} + GenServer.cast(self(), :poll_matrix) + + {:ok, + %{ + session: session, + rooms: rooms, + event_manager: event_manager, + from: nil, + commands: commands, + event_reactions: event_reactions + }} end - def handle_cast(:poll_matrix, state = %{session: session = %Matrix.Session{}, event_manager: event_manager, from: from}) do + # this call primarily exists to allow an optional eval command to modify the + # bot during runtime + def handle_call({:set_state, new_state}, _from, state), + do: {:reply, {state, new_state}, new_state} + def handle_call(:get_state, _from, state), do: {:reply, state, state} + + def handle_cast( + :poll_matrix, + state = %{session: session = %Matrix.Session{}, event_manager: event_manager, from: from} + ) do # Get latest events events = Matrix.Client.events!(session, from) - state = Dict.put state, :from, events.endd + state = Map.put(state, :from, events.endd) + + Logger.debug(fn -> "Matrix Events: #{inspect(events, pretty: true)}" end) + + # Dispatch events + Enum.each(events.events, fn event -> + GenEvent.notify( + event_manager, + {:matrix_event, {session, event}} + ) + end) # Extract commands - command_events = (events.events - |> Enum.reject(fn (e) -> e.user && e.user.user_id == session.user_id end) - |> Enum.filter(fn (e) -> e.type == "m.room.message" end) - |> Enum.filter(fn (e) -> e.content.msg_type == "m.text" end) - |> Enum.map(fn (e) -> {Bender.Parser.try_parse(e.content.body), e} end) - |> Enum.filter(fn ({c, _e}) -> !is_nil(c) end)) + command_events = + events.events + |> Enum.reject(fn e -> e.user && e.user.user_id == session.user_id end) + |> Enum.filter(fn e -> e.type == "m.room.message" end) + |> Enum.filter(fn e -> e.content.msg_type == "m.text" end) + |> Enum.map(fn e -> {Bender.Parser.try_parse(e.content.body), e} end) + |> Enum.filter(fn {c, _e} -> !is_nil(c) end) # Dispatch commands - Enum.each command_events, fn ({command, event}) -> - GenEvent.notify(event_manager, {command, %{session: session, room: event.room, author: event.user}}) - end + Enum.each(command_events, fn {command, event} -> + GenEvent.notify( + event_manager, + {command, %{session: session, room: event.room, author: event.user}} + ) + end) # Poll again for events - GenServer.cast(self, :poll_matrix) + GenServer.cast(self(), :poll_matrix) {:noreply, state} end - def handle_info({:gen_event_EXIT, _, _}, state = %{commands: commands}) do - state = Dict.put(state, :event_manager, setup_event_manager(commands)) + def handle_info( + {:gen_event_EXIT, _, _}, + state = %{commands: commands, event_reactions: event_reactions} + ) do + state = Map.put(state, :event_manager, setup_event_manager(commands, event_reactions)) {:noreply, state} end - def setup_event_manager(commands) do + def setup_event_manager(commands, event_reactions) do # Start the GenEvent manager - {:ok, event_manager} = GenEvent.start_link + {:ok, event_manager} = GenEvent.start_link() Process.monitor(event_manager) - Enum.each commands, fn(c) -> - :ok = GenEvent.add_mon_handler(event_manager, c, self) - end + Enum.each(commands, fn c -> + :ok = GenEvent.add_mon_handler(event_manager, c, self()) + end) + + Enum.each(event_reactions, fn er -> + :ok = GenEvent.add_mon_handler(event_manager, er, self()) + end) event_manager end diff --git a/lib/bender/command.ex b/lib/bender/command.ex index bac4050..2d93911 100644 --- a/lib/bender/command.ex +++ b/lib/bender/command.ex @@ -12,13 +12,15 @@ defmodule Bender.Command do defmacro __before_compile__(_env) do quote do - - if Module.get_attribute(__MODULE__, :usage) && Module.get_attribute(__MODULE__, :short_description) do + if Module.get_attribute(__MODULE__, :usage) && + Module.get_attribute(__MODULE__, :short_description) do def handle_event({{:command, "help", ""}, meta}, parent) do message = get_help_message(@usage, @short_description) + if message do respond(message, meta) end + {:ok, parent} end end diff --git a/lib/bender/event_reaction.ex b/lib/bender/event_reaction.ex new file mode 100644 index 0000000..caa256b --- /dev/null +++ b/lib/bender/event_reaction.ex @@ -0,0 +1,24 @@ +defmodule Bender.EventReaction do + defmacro __using__(_opts) do + quote do + @before_compile unquote(__MODULE__) + use GenEvent + + def respond(message, {session, %{room: room}}) do + Matrix.Client.post!(session, room, message) + end + end + end + + defmacro __before_compile__(_env) do + quote do + def handle_event(_, parent) do + {:ok, parent} + end + + def get_help_message(description) do + "#{inspect(__MODULE__)}: #{description}" + end + end + end +end diff --git a/lib/bender/parser.ex b/lib/bender/parser.ex index d7e08d3..3586471 100644 --- a/lib/bender/parser.ex +++ b/lib/bender/parser.ex @@ -1,6 +1,19 @@ defmodule Bender.Parser do + require Logger + def try_parse(message, command_prefix \\ Application.get_env(:bender, :command_prefix)) do - match = Regex.named_captures(~r/^\s*@?#{command_prefix}:?\s+(?[\w-]+)\s*(?.*)/i, message) + match = + Regex.named_captures( + ~r/^#{command_prefix}:?\s*(?[\w-]+)\s*(?.*)/sim, + message + ) + + Logger.debug(fn -> + "Bender.Parser.try_parse() - Event ({msg, regex_match}): #{ + inspect({message, match}, pretty: true) + }" + end) + if match && match["command"] do {:command, match["command"], match["message"]} else diff --git a/lib/matrix/client.ex b/lib/matrix/client.ex index d884aa7..f16cef7 100644 --- a/lib/matrix/client.ex +++ b/lib/matrix/client.ex @@ -1,33 +1,103 @@ defmodule Matrix.Client do - def login!(%Matrix.Config{home_server: home_server, user: user, password: password}) do + defp base_url( + %Matrix.Config{home_server_protocol: protocol, home_server: host, home_server_port: port} = + config + ) do + "#{protocol}://#{host}:#{port}/_matrix" + end + + defp base_url(%Matrix.Session{} = session) do + "#{session.home_server}/_matrix" + end + + def login!( + %Matrix.Config{ + home_server: home_server, + user: user, + password: password, + home_server_protocol: home_server_protocol, + home_server_port: home_server_port + } = config + ) do data = %{user: user, password: password, type: "m.login.password"} - response = HTTPoison.post!("https://#{home_server}/_matrix/client/api/v1/login", Poison.encode!(data), [], timeout: 10_000) - Poison.decode!(response.body, as: Matrix.Session) + + response = + HTTPoison.post!( + "#{base_url(config)}/client/api/v1/login", + Poison.encode!(data), + [], + timeout: 10_000 + ) + + Poison.decode!(response.body, as: %Matrix.Session{}) + |> IO.inspect() + |> Map.put(:home_server, "#{home_server_protocol}://#{home_server}:#{home_server_port}") + end + + def leave!(session, room_name) do + room_response = + HTTPoison.post!( + "#{session}/client/api/v1/leave/#{room_name}?access_token=#{session.access_token}", + "", + [], + timeout: 10_000 + ) end def join!(session, room_name) do - room_response = HTTPoison.post!("https://#{session.home_server}/_matrix/client/api/v1/join/#{room_name}?access_token=#{session.access_token}", "", [], timeout: 10_000) - Poison.decode!(room_response.body, as: Matrix.Room) + room_response = + HTTPoison.post!( + "#{base_url(session)}/client/api/v1/join/#{room_name}?access_token=#{session.access_token}", + "", + [], + timeout: 10_000 + ) + + Poison.decode!(room_response.body, as: %Matrix.Room{}) end def events!(session, from \\ nil) do params = [timeout: 30000, access_token: session.access_token] - if from do - params = Dict.put params, :from, from - end + params = + if from do + Keyword.put(params, :from, from) + else + params + end - response = HTTPoison.get!("https://#{session.home_server}/_matrix/client/api/v1/events", ["Accept": "application/json"], params: params, recv_timeout: 40000, timeout: 10_000) + response = + HTTPoison.get!( + "#{base_url(session)}/client/api/v1/events", + [Accept: "application/json"], + params: params, + recv_timeout: 40000, + timeout: 10_000 + ) - data = Poison.decode!(response.body) - Matrix.ResponseConstructer.events(data) + response.body + |> Poison.decode!() + |> Matrix.ResponseConstructor.events() end - def post!(session = %Matrix.Session{}, room = %Matrix.Room{}, message, msg_type \\ "m.text", event_type \\ "m.room.message") do - data = %{msgtype: msg_type, body: message} + def post!( + session = %Matrix.Session{}, + room = %Matrix.Room{}, + message, + msg_type \\ "m.text", + event_type \\ "m.room.message", + extra_fields \\ %{} + ) do + data = Map.merge(%{msgtype: msg_type, body: message}, extra_fields) - response = HTTPoison.post!("https://#{session.home_server}/_matrix/client/api/v1/rooms/#{room.room_id}/send/#{event_type}?access_token=#{session.access_token}", Poison.encode!(data)) + response = + HTTPoison.post!( + "#{base_url(session)}/client/api/v1/rooms/#{room.room_id}/send/#{event_type}?access_token=#{ + session.access_token + }", + Poison.encode!(data) + ) - Poison.decode!(response.body, as: Matrix.EventId) + Poison.decode!(response.body, as: %Matrix.EventId{}) end end diff --git a/lib/matrix/config.ex b/lib/matrix/config.ex index 4cd65ec..01d0779 100644 --- a/lib/matrix/config.ex +++ b/lib/matrix/config.ex @@ -1,3 +1,3 @@ defmodule Matrix.Config do - defstruct [:home_server, :user, :password] + defstruct [:home_server, :user, :password, :home_server_protocol, :home_server_port] end diff --git a/lib/matrix/content.ex b/lib/matrix/content.ex index 2873404..35c2a52 100644 --- a/lib/matrix/content.ex +++ b/lib/matrix/content.ex @@ -1,3 +1,3 @@ defmodule Matrix.Content do - defstruct [:users, :body, :msg_type] + defstruct [:users, :body, :msg_type, :original_response] end diff --git a/lib/matrix/event.ex b/lib/matrix/event.ex index 889b0eb..37895e7 100644 --- a/lib/matrix/event.ex +++ b/lib/matrix/event.ex @@ -1,3 +1,3 @@ defmodule Matrix.Event do - defstruct [:event_id, :age, :user, :room, :type, :content, :origin_server_ts] + defstruct [:event_id, :age, :user, :room, :type, :content, :origin_server_ts, :original_response] end diff --git a/lib/matrix/response_contstructer.ex b/lib/matrix/response_contstructor.ex similarity index 75% rename from lib/matrix/response_contstructer.ex rename to lib/matrix/response_contstructor.ex index 781aca7..a080354 100644 --- a/lib/matrix/response_contstructer.ex +++ b/lib/matrix/response_contstructor.ex @@ -1,4 +1,4 @@ -defmodule Matrix.ResponseConstructer do +defmodule Matrix.ResponseConstructor do def events(response) do %Matrix.Events{ events: response["chunk"] |> Enum.map(&event/1), @@ -16,24 +16,29 @@ defmodule Matrix.ResponseConstructer do type: response["type"], origin_server_ts: response["origin_server_ts"], user: user(response["user_id"]), + original_response: response } end def content("m.typing", response) do %Matrix.Content{ - users: Enum.map(response["user_ids"] , &user/1) + users: Enum.map(response["user_ids"], &user/1), + original_response: response } end def content("m.room.message", response) do %Matrix.Content{ body: response["body"], - msg_type: response["msgtype"] + msg_type: response["msgtype"], + original_response: response } end def content(_type, response) do - %Matrix.Content{} + %Matrix.Content{ + original_response: response + } end def user(nil) do diff --git a/mix.exs b/mix.exs index b7b97fd..0fa55fa 100644 --- a/mix.exs +++ b/mix.exs @@ -2,44 +2,33 @@ defmodule Bender.Mixfile do use Mix.Project def project do - [app: :bender, - version: "0.0.1", - elixir: "~> 1.1", - build_embedded: Mix.env == :prod, - start_permanent: Mix.env == :prod, - deps: deps] + [ + app: :bender, + version: "0.5.1", + elixir: "~> 1.1", + build_embedded: Mix.env() == :prod, + start_permanent: Mix.env() == :prod, + deps: deps() + ] end - # Configuration for the OTP application - # - # Type "mix help compile.app" for more information def application do - [applications: [:logger, :httpoison, :poison], - mod: {Bender, []}] + [applications: [:logger, :httpoison, :poison], mod: {Bender, []}] end - # Dependencies can be Hex packages: - # - # {:mydep, "~> 0.3.0"} - # - # Or git/path repositories: - # - # {:mydep, git: "https://github.com/elixir-lang/mydep.git", tag: "0.1.0"} - # - # Type "mix help deps" for more examples and options defp deps do [ - {:httpoison, "~> 0.7"}, - {:poison, "~> 1.5"}, - {:exrm, "~> 0.19"}, + {:httpoison, "~> 1.0"}, + {:poison, "~> 4.0"} ] end defp package do - [# These are the default files included in the package - files: ["lib", "priv", "mix.exs", "README.md", "LICENSE.txt",], - maintainers: ["Dylan Griffith"], - licenses: ["MIT"], - links: %{"GitHub" => "https://github.com/DylanGriffith/bender"}] + [ + files: ["lib", "priv", "mix.exs", "README.md", "LICENSE.txt"], + maintainers: ["Dylan Griffith"], + licenses: ["MIT"], + links: %{"GitHub" => "https://github.com/DylanGriffith/bender"} + ] end end diff --git a/mix.lock b/mix.lock index 66a65c9..c2fc96b 100644 --- a/mix.lock +++ b/mix.lock @@ -1,13 +1,21 @@ -%{"bbmustache": {:hex, :bbmustache, "1.0.3"}, +%{ + "bbmustache": {:hex, :bbmustache, "1.0.3"}, + "certifi": {:hex, :certifi, "2.6.1", "dbab8e5e155a0763eea978c913ca280a6b544bfa115633fa20249c3d396d9493", [:rebar3], [], "hexpm", "524c97b4991b3849dd5c17a631223896272c6b0af446778ba4675a1dff53bb7e"}, "conform": {:hex, :conform, "0.17.0"}, "erlware_commons": {:hex, :erlware_commons, "0.15.0"}, "exrm": {:hex, :exrm, "0.19.9"}, "getopt": {:hex, :getopt, "0.8.2"}, - "hackney": {:hex, :hackney, "1.3.2"}, - "httpoison": {:hex, :httpoison, "0.7.4"}, - "idna": {:hex, :idna, "1.0.2"}, + "hackney": {:hex, :hackney, "1.17.4", "99da4674592504d3fb0cfef0db84c3ba02b4508bae2dff8c0108baa0d6e0977c", [:rebar3], [{:certifi, "~>2.6.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "de16ff4996556c8548d512f4dbe22dd58a587bf3332e7fd362430a7ef3986b16"}, + "httpoison": {:hex, :httpoison, "1.8.0", "6b85dea15820b7804ef607ff78406ab449dd78bed923a49c7160e1886e987a3d", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "28089eaa98cf90c66265b6b5ad87c59a3729bea2e74e9d08f9b51eb9729b3c3a"}, + "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, + "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, + "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, "neotoma": {:hex, :neotoma, "1.7.3"}, - "poison": {:hex, :poison, "1.5.0"}, + "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"}, + "poison": {:hex, :poison, "4.0.1", "bcb755a16fac91cad79bfe9fc3585bb07b9331e50cfe3420a24bcc2d735709ae", [:mix], [], "hexpm", "ba8836feea4b394bb718a161fc59a288fe0109b5006d6bdf97b6badfcf6f0f25"}, "providers": {:hex, :providers, "1.4.1"}, "relx": {:hex, :relx, "3.5.0"}, - "ssl_verify_hostname": {:hex, :ssl_verify_hostname, "1.0.5"}} + "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"}, + "ssl_verify_hostname": {:hex, :ssl_verify_hostname, "1.0.5"}, + "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, +} diff --git a/test/bender/parser_test.exs b/test/bender/parser_test.exs index a02a7c7..8132ff1 100644 --- a/test/bender/parser_test.exs +++ b/test/bender/parser_test.exs @@ -5,12 +5,14 @@ defmodule Bender.ParserTest do assert Bender.Parser.try_parse("bender echo hello world") == {:command, "echo", "hello world"} end - test "#try_parse supports using @bender" do - assert Bender.Parser.try_parse("@bender echo hello world") == {:command, "echo", "hello world"} + test "#try_parse does not work unless the command prefix starts the string" do + assert Bender.Parser.try_parse("@bender echo hello world") == + nil end test "#try_parse supports using bender:" do - assert Bender.Parser.try_parse("bender: echo hello world") == {:command, "echo", "hello world"} + assert Bender.Parser.try_parse("bender: echo hello world") == + {:command, "echo", "hello world"} end test "#try_parse supports using uppercase" do @@ -18,11 +20,13 @@ defmodule Bender.ParserTest do end test "#try_parse supports commands with hyphens" do - assert Bender.Parser.try_parse("Bender foo-bar hello world") == {:command, "foo-bar", "hello world"} + assert Bender.Parser.try_parse("Bender foo-bar hello world") == + {:command, "foo-bar", "hello world"} end test "#try_parse supports custom command_prefix" do - assert Bender.Parser.try_parse("foobar echo hello world", "foobar") == {:command, "echo", "hello world"} + assert Bender.Parser.try_parse("foobar echo hello world", "foobar") == + {:command, "echo", "hello world"} end test "#try_parse supports empty message after command" do diff --git a/test/matrix/response_constructer_test.exs b/test/matrix/response_constructor_test.exs similarity index 67% rename from test/matrix/response_constructer_test.exs rename to test/matrix/response_constructor_test.exs index c265f29..0909cfa 100644 --- a/test/matrix/response_constructer_test.exs +++ b/test/matrix/response_constructor_test.exs @@ -1,4 +1,4 @@ -defmodule Matrix.ResponseConstructerTest do +defmodule Matrix.ResponseConstructorTest do use ExUnit.Case, async: true test "#events: transforms typing events in Matrix.Events" do @@ -17,16 +17,22 @@ defmodule Matrix.ResponseConstructerTest do output = %Matrix.Events{ events: [ %Matrix.Event{ - content: %Matrix.Content{users: [%Matrix.User{user_id: "@bob:matrix.org"}]}, + content: %Matrix.Content{ + users: [ + %Matrix.User{user_id: "@bob:matrix.org"} + ], + original_response: input |> Map.get("chunk") |> Enum.at(0) |> Map.get("content") + }, + original_response: input["chunk"] |> Enum.at(0), room: %Matrix.Room{room_id: "!abc123:matrix.org"}, type: "m.typing" - }, + } ], endd: "s12345", start: "s12344" } - assert Matrix.ResponseConstructer.events(input) == output + assert Matrix.ResponseConstructor.events(input) == output end test "transforms message events in Matrix.Events" do @@ -36,7 +42,7 @@ defmodule Matrix.ResponseConstructerTest do "age" => 136, "content" => %{"body" => "bender echo hello", "msgtype" => "m.text"}, "event_id" => "$1446024043133ABC:matrix.org", - "origin_server_ts" => 1446024043133, + "origin_server_ts" => 1_446_024_043_133, "room_id" => "!abc123:matrix.org", "type" => "m.room.message", "user_id" => "@bob:matrix.org" @@ -51,20 +57,22 @@ defmodule Matrix.ResponseConstructerTest do %Matrix.Event{ event_id: "$1446024043133ABC:matrix.org", age: 136, + original_response: input |> Map.get("chunk") |> Enum.at(0), content: %Matrix.Content{ body: "bender echo hello", + original_response: input |> Map.get("chunk") |> Enum.at(0) |> Map.get("content"), msg_type: "m.text" }, - origin_server_ts: 1446024043133, + origin_server_ts: 1_446_024_043_133, room: %Matrix.Room{room_id: "!abc123:matrix.org"}, type: "m.room.message", user: %Matrix.User{user_id: "@bob:matrix.org"} - }, + } ], endd: "s12345", start: "s12344" } - assert Matrix.ResponseConstructer.events(input) == output + assert Matrix.ResponseConstructor.events(input) == output end end