From f0c03493fea61763b547584876f30ac97fdeb75b Mon Sep 17 00:00:00 2001 From: Daniel Flanagan Date: Fri, 12 Oct 2018 13:39:04 -0500 Subject: [PATCH 01/18] Update deps, fix broken things --- lib/bender.ex | 10 ++--- lib/bender/bot.ex | 61 ++++++++++++++++---------- lib/bender/parser.ex | 7 ++- lib/matrix/client.ex | 66 +++++++++++++++++++++++------ lib/matrix/response_contstructer.ex | 4 +- mix.exs | 45 ++++++++------------ mix.lock | 20 ++++++--- 7 files changed, 135 insertions(+), 78 deletions(-) diff --git a/lib/bender.ex b/lib/bender.ex index de66727..568df61 100644 --- a/lib/bender.ex +++ b/lib/bender.ex @@ -1,8 +1,6 @@ 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 @@ -13,11 +11,13 @@ defmodule Bender do commands = Application.get_env(:bender, :commands) 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}, + room_names, + commands + ]) ] - # 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..bd5a754 100644 --- a/lib/bender/bot.ex +++ b/lib/bender/bot.ex @@ -12,55 +12,70 @@ defmodule Bender.Bot do session = Matrix.Client.login!(config) # 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) # 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 + }} end - def handle_cast(:poll_matrix, state = %{session: session = %Matrix.Session{}, event_manager: event_manager, from: from}) do - + 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) # 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)) + state = Map.put(state, :event_manager, setup_event_manager(commands)) {:noreply, state} end def setup_event_manager(commands) 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) event_manager end diff --git a/lib/bender/parser.ex b/lib/bender/parser.ex index d7e08d3..4cdc94f 100644 --- a/lib/bender/parser.ex +++ b/lib/bender/parser.ex @@ -1,6 +1,11 @@ defmodule Bender.Parser do 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/^\s*@?#{command_prefix}:?\s*(?[\w-]+)\s*(?.*)/i, + message + ) + 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..6eff624 100644 --- a/lib/matrix/client.ex +++ b/lib/matrix/client.ex @@ -1,33 +1,73 @@ defmodule Matrix.Client do def login!(%Matrix.Config{home_server: home_server, user: user, password: password}) 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!( + "https://#{home_server}/_matrix/client/api/v1/login", + Poison.encode!(data), + [], + timeout: 10_000 + ) + + Poison.decode!(response.body, as: %Matrix.Session{}) 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!( + "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{}) 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!( + "https://#{session.home_server}/_matrix/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.ResponseConstructer.events() end - def post!(session = %Matrix.Session{}, room = %Matrix.Room{}, message, msg_type \\ "m.text", event_type \\ "m.room.message") do + 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} - 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!( + "https://#{session.home_server}/_matrix/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/response_contstructer.ex b/lib/matrix/response_contstructer.ex index 781aca7..6a517bb 100644 --- a/lib/matrix/response_contstructer.ex +++ b/lib/matrix/response_contstructer.ex @@ -15,13 +15,13 @@ defmodule Matrix.ResponseConstructer do room: room(response["room_id"]), type: response["type"], origin_server_ts: response["origin_server_ts"], - user: user(response["user_id"]), + user: user(response["user_id"]) } 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) } end diff --git a/mix.exs b/mix.exs index b7b97fd..c4bf5e8 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.0.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..7f73490 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.4.2", "75424ff0f3baaccfd34b1214184b6ef616d89e420b258bb0a5ea7d7bc628f7f0", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"}, "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.14.3", "b5f6f5dcc4f1fba340762738759209e21914516df6be440d85772542d4a5e412", [:rebar3], [{:certifi, "2.4.2", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.4", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"}, + "httpoison": {:hex, :httpoison, "1.3.1", "7ac607311f5f706b44e8b3fab736d0737f2f62a31910ccd9afe7227b43edb7f0", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, + "idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"}, + "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"}, + "mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [:rebar3], [], "hexpm"}, "neotoma": {:hex, :neotoma, "1.7.3"}, - "poison": {:hex, :poison, "1.5.0"}, + "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"}, + "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"}, "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.4", "f0eafff810d2041e93f915ef59899c923f4568f4585904d010387ed74988e77b", [:make, :mix, :rebar3], [], "hexpm"}, + "ssl_verify_hostname": {:hex, :ssl_verify_hostname, "1.0.5"}, + "unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm"}, +} From cb2b064e017a7f2731824d62f4d3753380d4bb88 Mon Sep 17 00:00:00 2001 From: Daniel Flanagan Date: Fri, 12 Oct 2018 14:48:32 -0500 Subject: [PATCH 02/18] v0.0.2 --- mix.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.exs b/mix.exs index c4bf5e8..543b2ce 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule Bender.Mixfile do def project do [ app: :bender, - version: "0.0.1", + version: "0.0.2", elixir: "~> 1.1", build_embedded: Mix.env() == :prod, start_permanent: Mix.env() == :prod, From d03d4541e5ca342081b66695ad040fab7e2e097a Mon Sep 17 00:00:00 2001 From: Daniel Flanagan Date: Fri, 12 Oct 2018 16:42:30 -0500 Subject: [PATCH 03/18] Add event listener for any matrix event --- config/config.exs | 1 + lib/bender.ex | 4 +++- lib/bender/bot.ex | 41 ++++++++++++++++++++++++++++-------- lib/bender/command.ex | 6 ++++-- lib/bender/event_reaction.ex | 24 +++++++++++++++++++++ lib/matrix/client.ex | 12 +++++++++++ mix.exs | 2 +- 7 files changed, 77 insertions(+), 13 deletions(-) create mode 100644 lib/bender/event_reaction.ex diff --git a/config/config.exs b/config/config.exs index a8ad5f1..fef3524 100644 --- a/config/config.exs +++ b/config/config.exs @@ -16,6 +16,7 @@ config :bender, matrix_user: "bender", matrix_password: "bender", commands: [Bender.Commands.Echo, Bender.Commands.Ping], + event_reactions: [Bender.EventReactions.AutoJoinRoomInvites], room_names: ["#bender:matrix.org"] # diff --git a/lib/bender.ex b/lib/bender.ex index 568df61..08d48a4 100644 --- a/lib/bender.ex +++ b/lib/bender.ex @@ -9,12 +9,14 @@ defmodule Bender do 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 + commands, + event_reactions ]) ] diff --git a/lib/bender/bot.ex b/lib/bender/bot.ex index bd5a754..5c9699f 100644 --- a/lib/bender/bot.ex +++ b/lib/bender/bot.ex @@ -1,21 +1,26 @@ 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__) + def start_link(config = %Matrix.Config{}, room_names, commands, event_reactions) do + GenServer.start_link(__MODULE__, [config, room_names, commands, event_reactions], + name: __MODULE__ + ) 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() # Join Rooms rooms = Enum.map(room_names, fn room_name -> Matrix.Client.join!(session, room_name) end) + |> IO.inspect() # Trigger first poll for events GenServer.cast(self(), :poll_matrix) @@ -26,7 +31,8 @@ defmodule Bender.Bot do rooms: rooms, event_manager: event_manager, from: nil, - commands: commands + commands: commands, + event_reactions: event_reactions }} end @@ -39,6 +45,16 @@ defmodule Bender.Bot do state = Map.put(state, :from, events.endd) + # Dispatch events + events |> IO.inspect() + + Enum.each(events.events, fn event -> + GenEvent.notify( + event_manager, + {:matrix_event, {session, event}} + ) + end) + # Extract commands command_events = events.events @@ -62,12 +78,15 @@ defmodule Bender.Bot do {:noreply, state} end - def handle_info({:gen_event_EXIT, _, _}, state = %{commands: commands}) do - state = Map.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() @@ -77,6 +96,10 @@ defmodule Bender.Bot do :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 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/matrix/client.ex b/lib/matrix/client.ex index 6eff624..abe8844 100644 --- a/lib/matrix/client.ex +++ b/lib/matrix/client.ex @@ -13,6 +13,18 @@ defmodule Matrix.Client do Poison.decode!(response.body, as: %Matrix.Session{}) end + def leave!(session, room_name) do + room_response = + HTTPoison.post!( + "https://#{session.home_server}/_matrix/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!( diff --git a/mix.exs b/mix.exs index 543b2ce..676f09b 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule Bender.Mixfile do def project do [ app: :bender, - version: "0.0.2", + version: "0.0.3", elixir: "~> 1.1", build_embedded: Mix.env() == :prod, start_permanent: Mix.env() == :prod, From 922afc580ef6d0b0c96869da16248b7e4a56a332 Mon Sep 17 00:00:00 2001 From: Daniel Flanagan Date: Mon, 15 Oct 2018 16:04:50 -0500 Subject: [PATCH 04/18] Add extra fields option for post! --- lib/matrix/client.ex | 5 +++-- mix.exs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/matrix/client.ex b/lib/matrix/client.ex index abe8844..32b0481 100644 --- a/lib/matrix/client.ex +++ b/lib/matrix/client.ex @@ -68,9 +68,10 @@ defmodule Matrix.Client do room = %Matrix.Room{}, message, msg_type \\ "m.text", - event_type \\ "m.room.message" + event_type \\ "m.room.message", + extra_fields \\ %{} ) do - data = %{msgtype: msg_type, body: message} + data = Map.merge(%{msgtype: msg_type, body: message}, extra_fields) response = HTTPoison.post!( diff --git a/mix.exs b/mix.exs index 676f09b..6ef3c08 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule Bender.Mixfile do def project do [ app: :bender, - version: "0.0.3", + version: "0.0.4", elixir: "~> 1.1", build_embedded: Mix.env() == :prod, start_permanent: Mix.env() == :prod, From 8510586a10658614a7b0c932e1f0a31c3daa4879 Mon Sep 17 00:00:00 2001 From: Daniel Flanagan Date: Mon, 15 Oct 2018 16:31:55 -0500 Subject: [PATCH 05/18] Add get_state call --- lib/bender/bot.ex | 2 ++ mix.exs | 2 +- mix.lock | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/bender/bot.ex b/lib/bender/bot.ex index 5c9699f..c26def0 100644 --- a/lib/bender/bot.ex +++ b/lib/bender/bot.ex @@ -36,6 +36,8 @@ defmodule Bender.Bot do }} end + 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} diff --git a/mix.exs b/mix.exs index 6ef3c08..9fe1c1f 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule Bender.Mixfile do def project do [ app: :bender, - version: "0.0.4", + version: "0.0.5", elixir: "~> 1.1", build_embedded: Mix.env() == :prod, start_permanent: Mix.env() == :prod, diff --git a/mix.lock b/mix.lock index 7f73490..5942cd3 100644 --- a/mix.lock +++ b/mix.lock @@ -12,7 +12,7 @@ "mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [:rebar3], [], "hexpm"}, "neotoma": {:hex, :neotoma, "1.7.3"}, "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"}, - "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"}, + "poison": {:hex, :poison, "4.0.1", "bcb755a16fac91cad79bfe9fc3585bb07b9331e50cfe3420a24bcc2d735709ae", [:mix], [], "hexpm"}, "providers": {:hex, :providers, "1.4.1"}, "relx": {:hex, :relx, "3.5.0"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.4", "f0eafff810d2041e93f915ef59899c923f4568f4585904d010387ed74988e77b", [:make, :mix, :rebar3], [], "hexpm"}, From 1f398832c994648035eb68d3c8d6f3e777b54622 Mon Sep 17 00:00:00 2001 From: Daniel Flanagan Date: Wed, 17 Oct 2018 16:13:53 -0500 Subject: [PATCH 06/18] Add state mutator - highly deadly to bots --- lib/bender/bot.ex | 3 +++ mix.exs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/bender/bot.ex b/lib/bender/bot.ex index c26def0..179a07f 100644 --- a/lib/bender/bot.ex +++ b/lib/bender/bot.ex @@ -36,6 +36,9 @@ defmodule Bender.Bot do }} end + 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( diff --git a/mix.exs b/mix.exs index 9fe1c1f..55ea88d 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule Bender.Mixfile do def project do [ app: :bender, - version: "0.0.5", + version: "0.0.6", elixir: "~> 1.1", build_embedded: Mix.env() == :prod, start_permanent: Mix.env() == :prod, From 4e67138952f4fd081d331a4533df2084d766ae12 Mon Sep 17 00:00:00 2001 From: Daniel Flanagan Date: Wed, 17 Oct 2018 17:07:28 -0500 Subject: [PATCH 07/18] Multiline commands --- lib/bender/parser.ex | 3 ++- mix.exs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/bender/parser.ex b/lib/bender/parser.ex index 4cdc94f..7e7f136 100644 --- a/lib/bender/parser.ex +++ b/lib/bender/parser.ex @@ -2,9 +2,10 @@ defmodule Bender.Parser do 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, + ~r/\s*@?#{command_prefix}:?\s*(?[\w-]+)\s*(?.*)/sim, message ) + |> IO.inspect() if match && match["command"] do {:command, match["command"], match["message"]} diff --git a/mix.exs b/mix.exs index 55ea88d..c025917 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule Bender.Mixfile do def project do [ app: :bender, - version: "0.0.6", + version: "0.0.7", elixir: "~> 1.1", build_embedded: Mix.env() == :prod, start_permanent: Mix.env() == :prod, From b4ecffb6e5516d501f54e87f2356c9b56c2183c6 Mon Sep 17 00:00:00 2001 From: Daniel Flanagan Date: Thu, 18 Oct 2018 09:58:37 -0500 Subject: [PATCH 08/18] Remove bad IO.inspect calls and use proper logging --- lib/bender/bot.ex | 17 +++++++++++------ lib/bender/parser.ex | 7 ++++++- mix.exs | 2 +- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/lib/bender/bot.ex b/lib/bender/bot.ex index 179a07f..ee4f75a 100644 --- a/lib/bender/bot.ex +++ b/lib/bender/bot.ex @@ -1,6 +1,8 @@ defmodule Bender.Bot do use GenServer + require Logger + def start_link(config = %Matrix.Config{}, room_names, commands, event_reactions) do GenServer.start_link(__MODULE__, [config, room_names, commands, event_reactions], name: __MODULE__ @@ -11,16 +13,17 @@ defmodule Bender.Bot do event_manager = setup_event_manager(commands, event_reactions) # Login - session = - Matrix.Client.login!(config) - |> IO.inspect() + session = Matrix.Client.login!(config) + + Logger.debug(fn -> "Login Result (Session): #{inspect(session)}" end) # Join Rooms rooms = Enum.map(room_names, fn room_name -> Matrix.Client.join!(session, room_name) end) - |> IO.inspect() + + Logger.debug(fn -> "Rooms: #{inspect(rooms)}" end) # Trigger first poll for events GenServer.cast(self(), :poll_matrix) @@ -36,6 +39,8 @@ defmodule Bender.Bot do }} end + # 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} @@ -50,9 +55,9 @@ defmodule Bender.Bot do state = Map.put(state, :from, events.endd) - # Dispatch events - events |> IO.inspect() + Logger.debug(fn -> "Matrix Events: #{inspect(session)}" end) + # Dispatch events Enum.each(events.events, fn event -> GenEvent.notify( event_manager, diff --git a/lib/bender/parser.ex b/lib/bender/parser.ex index 7e7f136..c314f40 100644 --- a/lib/bender/parser.ex +++ b/lib/bender/parser.ex @@ -1,11 +1,16 @@ 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*(?.*)/sim, message ) - |> IO.inspect() + + Logger.debug(fn -> + "Bender.Parser.try_parse() - Event ({msg, regex_match}): #{inspect({message, match})}" + end) if match && match["command"] do {:command, match["command"], match["message"]} diff --git a/mix.exs b/mix.exs index c025917..9815934 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule Bender.Mixfile do def project do [ app: :bender, - version: "0.0.7", + version: "0.0.8", elixir: "~> 1.1", build_embedded: Mix.env() == :prod, start_permanent: Mix.env() == :prod, From 90a1e25fff3a0d002cb4fec15ec6a6eaa7492187 Mon Sep 17 00:00:00 2001 From: Daniel Flanagan Date: Thu, 18 Oct 2018 14:18:08 -0500 Subject: [PATCH 09/18] Fix bad logging call --- lib/bender/bot.ex | 2 +- mix.exs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/bender/bot.ex b/lib/bender/bot.ex index ee4f75a..143ab6b 100644 --- a/lib/bender/bot.ex +++ b/lib/bender/bot.ex @@ -55,7 +55,7 @@ defmodule Bender.Bot do state = Map.put(state, :from, events.endd) - Logger.debug(fn -> "Matrix Events: #{inspect(session)}" end) + Logger.debug(fn -> "Matrix Events: #{inspect(events)}" end) # Dispatch events Enum.each(events.events, fn event -> diff --git a/mix.exs b/mix.exs index 9815934..ae5fe61 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule Bender.Mixfile do def project do [ app: :bender, - version: "0.0.8", + version: "0.1.0", elixir: "~> 1.1", build_embedded: Mix.env() == :prod, start_permanent: Mix.env() == :prod, From fe734743eed4d2dfc8c5cd96d918ffe4fb4b7405 Mon Sep 17 00:00:00 2001 From: Daniel Flanagan Date: Thu, 18 Oct 2018 14:27:44 -0500 Subject: [PATCH 10/18] Add original response reference to matrix event, fix typo in module name --- lib/bender/bot.ex | 6 +++--- lib/bender/parser.ex | 2 +- lib/matrix/client.ex | 2 +- lib/matrix/content.ex | 2 +- lib/matrix/event.ex | 2 +- ...e_contstructer.ex => response_contstructor.ex} | 15 ++++++++++----- mix.exs | 2 +- ...ter_test.exs => response_constructor_test.exs} | 14 +++++++------- 8 files changed, 25 insertions(+), 20 deletions(-) rename lib/matrix/{response_contstructer.ex => response_contstructor.ex} (72%) rename test/matrix/{response_constructer_test.exs => response_constructor_test.exs} (84%) diff --git a/lib/bender/bot.ex b/lib/bender/bot.ex index 143ab6b..c0c2052 100644 --- a/lib/bender/bot.ex +++ b/lib/bender/bot.ex @@ -15,7 +15,7 @@ defmodule Bender.Bot do # Login session = Matrix.Client.login!(config) - Logger.debug(fn -> "Login Result (Session): #{inspect(session)}" end) + Logger.debug(fn -> "Login Result (Session): #{inspect(session, pretty: true)}" end) # Join Rooms rooms = @@ -23,7 +23,7 @@ defmodule Bender.Bot do Matrix.Client.join!(session, room_name) end) - Logger.debug(fn -> "Rooms: #{inspect(rooms)}" end) + Logger.debug(fn -> "Rooms: #{inspect(rooms, pretty: true)}" end) # Trigger first poll for events GenServer.cast(self(), :poll_matrix) @@ -55,7 +55,7 @@ defmodule Bender.Bot do state = Map.put(state, :from, events.endd) - Logger.debug(fn -> "Matrix Events: #{inspect(events)}" end) + Logger.debug(fn -> "Matrix Events: #{inspect(events, pretty: true)}" end) # Dispatch events Enum.each(events.events, fn event -> diff --git a/lib/bender/parser.ex b/lib/bender/parser.ex index c314f40..4d7f1fc 100644 --- a/lib/bender/parser.ex +++ b/lib/bender/parser.ex @@ -9,7 +9,7 @@ defmodule Bender.Parser do ) Logger.debug(fn -> - "Bender.Parser.try_parse() - Event ({msg, regex_match}): #{inspect({message, match})}" + "Bender.Parser.try_parse() - Event ({msg, regex_match}): #{inspect({message, match}, pretty: true)}" end) if match && match["command"] do diff --git a/lib/matrix/client.ex b/lib/matrix/client.ex index 32b0481..d8c2d3f 100644 --- a/lib/matrix/client.ex +++ b/lib/matrix/client.ex @@ -60,7 +60,7 @@ defmodule Matrix.Client do response.body |> Poison.decode!() - |> Matrix.ResponseConstructer.events() + |> Matrix.ResponseConstructor.events() end def post!( 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 72% rename from lib/matrix/response_contstructer.ex rename to lib/matrix/response_contstructor.ex index 6a517bb..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), @@ -15,25 +15,30 @@ defmodule Matrix.ResponseConstructer do room: room(response["room_id"]), type: response["type"], origin_server_ts: response["origin_server_ts"], - user: user(response["user_id"]) + 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 ae5fe61..ed331b5 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule Bender.Mixfile do def project do [ app: :bender, - version: "0.1.0", + version: "0.2.0", elixir: "~> 1.1", build_embedded: Mix.env() == :prod, start_permanent: Mix.env() == :prod, diff --git a/test/matrix/response_constructer_test.exs b/test/matrix/response_constructor_test.exs similarity index 84% rename from test/matrix/response_constructer_test.exs rename to test/matrix/response_constructor_test.exs index c265f29..05bfb38 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 @@ -20,13 +20,13 @@ defmodule Matrix.ResponseConstructerTest do content: %Matrix.Content{users: [%Matrix.User{user_id: "@bob:matrix.org"}]}, 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 +36,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" @@ -55,16 +55,16 @@ defmodule Matrix.ResponseConstructerTest do body: "bender echo hello", 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 From 2aed2d4231a8b358172eb4bf436082bd9e672eaf Mon Sep 17 00:00:00 2001 From: Daniel Flanagan Date: Mon, 6 May 2019 12:36:07 -0500 Subject: [PATCH 11/18] Only parse commands where the command prefix begins a line --- lib/bender/parser.ex | 6 ++++-- mix.exs | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/bender/parser.ex b/lib/bender/parser.ex index 4d7f1fc..3586471 100644 --- a/lib/bender/parser.ex +++ b/lib/bender/parser.ex @@ -4,12 +4,14 @@ defmodule Bender.Parser do def try_parse(message, command_prefix \\ Application.get_env(:bender, :command_prefix)) do match = Regex.named_captures( - ~r/\s*@?#{command_prefix}:?\s*(?[\w-]+)\s*(?.*)/sim, + ~r/^#{command_prefix}:?\s*(?[\w-]+)\s*(?.*)/sim, message ) Logger.debug(fn -> - "Bender.Parser.try_parse() - Event ({msg, regex_match}): #{inspect({message, match}, pretty: true)}" + "Bender.Parser.try_parse() - Event ({msg, regex_match}): #{ + inspect({message, match}, pretty: true) + }" end) if match && match["command"] do diff --git a/mix.exs b/mix.exs index ed331b5..83dfe03 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule Bender.Mixfile do def project do [ app: :bender, - version: "0.2.0", + version: "0.3.0", elixir: "~> 1.1", build_embedded: Mix.env() == :prod, start_permanent: Mix.env() == :prod, From 7fafe02672899d87baaca073d57befa46f3fb4f8 Mon Sep 17 00:00:00 2001 From: Daniel Flanagan Date: Thu, 9 May 2019 15:43:38 -0500 Subject: [PATCH 12/18] Allow configuring the matrix's home server protocol --- config/config.exs | 1 + lib/bender.ex | 8 +++++++- lib/matrix/client.ex | 29 +++++++++++++++++------------ lib/matrix/config.ex | 2 +- mix.exs | 2 +- 5 files changed, 27 insertions(+), 15 deletions(-) diff --git a/config/config.exs b/config/config.exs index fef3524..c0a35d9 100644 --- a/config/config.exs +++ b/config/config.exs @@ -13,6 +13,7 @@ use Mix.Config config :bender, command_prefix: "bender", matrix_home_server: "matrix.org", + matrix_home_server_protocol: "https", matrix_user: "bender", matrix_password: "bender", commands: [Bender.Commands.Echo, Bender.Commands.Ping], diff --git a/lib/bender.ex b/lib/bender.ex index 08d48a4..9ff20ab 100644 --- a/lib/bender.ex +++ b/lib/bender.ex @@ -5,6 +5,7 @@ defmodule Bender 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") user = Application.get_env(:bender, :matrix_user) password = Application.get_env(:bender, :matrix_password) room_names = Application.get_env(:bender, :room_names) @@ -13,7 +14,12 @@ defmodule Bender do children = [ worker(Bender.Bot, [ - %Matrix.Config{home_server: home_server, user: user, password: password}, + %Matrix.Config{ + home_server: home_server, + user: user, + password: password, + home_server_protocol: home_server_protocol + }, room_names, commands, event_reactions diff --git a/lib/matrix/client.ex b/lib/matrix/client.ex index d8c2d3f..10d6727 100644 --- a/lib/matrix/client.ex +++ b/lib/matrix/client.ex @@ -1,10 +1,15 @@ defmodule Matrix.Client do - def login!(%Matrix.Config{home_server: home_server, user: user, password: password}) do + def login!(%Matrix.Config{ + home_server: home_server, + user: user, + password: password, + home_server_protocol: home_server_protocol + }) do data = %{user: user, password: password, type: "m.login.password"} response = HTTPoison.post!( - "https://#{home_server}/_matrix/client/api/v1/login", + "#{home_server_protocol}://#{home_server}/_matrix/client/api/v1/login", Poison.encode!(data), [], timeout: 10_000 @@ -16,9 +21,9 @@ defmodule Matrix.Client do def leave!(session, room_name) do room_response = HTTPoison.post!( - "https://#{session.home_server}/_matrix/client/api/v1/leave/#{room_name}?access_token=#{ - session.access_token - }", + "#{session.home_server_protocol}://#{session.home_server}/_matrix/client/api/v1/leave/#{ + room_name + }?access_token=#{session.access_token}", "", [], timeout: 10_000 @@ -28,9 +33,9 @@ defmodule Matrix.Client do 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 - }", + "#{session.home_server_protocol}://#{session.home_server}/_matrix/client/api/v1/join/#{ + room_name + }?access_token=#{session.access_token}", "", [], timeout: 10_000 @@ -51,7 +56,7 @@ defmodule Matrix.Client do response = HTTPoison.get!( - "https://#{session.home_server}/_matrix/client/api/v1/events", + "#{session.home_server_protocol}://#{session.home_server}/_matrix/client/api/v1/events", [Accept: "application/json"], params: params, recv_timeout: 40000, @@ -75,9 +80,9 @@ defmodule Matrix.Client do response = HTTPoison.post!( - "https://#{session.home_server}/_matrix/client/api/v1/rooms/#{room.room_id}/send/#{ - event_type - }?access_token=#{session.access_token}", + "#{session.home_server_protocol}://#{session.home_server}/_matrix/client/api/v1/rooms/#{ + room.room_id + }/send/#{event_type}?access_token=#{session.access_token}", Poison.encode!(data) ) diff --git a/lib/matrix/config.ex b/lib/matrix/config.ex index 4cd65ec..3b2f49c 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] end diff --git a/mix.exs b/mix.exs index 83dfe03..d11dd7d 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule Bender.Mixfile do def project do [ app: :bender, - version: "0.3.0", + version: "0.4.0", elixir: "~> 1.1", build_embedded: Mix.env() == :prod, start_permanent: Mix.env() == :prod, From 91e35e846833592733ba9d5513d9ff37d4d330fc Mon Sep 17 00:00:00 2001 From: Daniel Flanagan Date: Thu, 9 May 2019 15:53:06 -0500 Subject: [PATCH 13/18] Add port specification --- config/config.exs | 1 + lib/bender.ex | 2 ++ lib/matrix/client.ex | 17 +++++++++++------ mix.exs | 2 +- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/config/config.exs b/config/config.exs index c0a35d9..50de494 100644 --- a/config/config.exs +++ b/config/config.exs @@ -14,6 +14,7 @@ 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], diff --git a/lib/bender.ex b/lib/bender.ex index 9ff20ab..c3a7093 100644 --- a/lib/bender.ex +++ b/lib/bender.ex @@ -6,6 +6,7 @@ defmodule Bender do 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) @@ -19,6 +20,7 @@ defmodule Bender do user: user, password: password, home_server_protocol: home_server_protocol + home_server_port: home_server_port }, room_names, commands, diff --git a/lib/matrix/client.ex b/lib/matrix/client.ex index 10d6727..180ea20 100644 --- a/lib/matrix/client.ex +++ b/lib/matrix/client.ex @@ -1,15 +1,20 @@ defmodule Matrix.Client do + defp base_url(%Matrix.Config{} = config) do + "#{config.home_server_protocol}://#{config.home_server}:#{config.port}/_matrix" + end + def login!(%Matrix.Config{ home_server: home_server, user: user, password: password, home_server_protocol: home_server_protocol - }) do + home_server_port: home_server_port + } = config) do data = %{user: user, password: password, type: "m.login.password"} response = HTTPoison.post!( - "#{home_server_protocol}://#{home_server}/_matrix/client/api/v1/login", + "#{base_url(config)}/client/api/v1/login", Poison.encode!(data), [], timeout: 10_000 @@ -21,7 +26,7 @@ defmodule Matrix.Client do def leave!(session, room_name) do room_response = HTTPoison.post!( - "#{session.home_server_protocol}://#{session.home_server}/_matrix/client/api/v1/leave/#{ + "#{base_url(config)}/client/api/v1/leave/#{ room_name }?access_token=#{session.access_token}", "", @@ -33,7 +38,7 @@ defmodule Matrix.Client do def join!(session, room_name) do room_response = HTTPoison.post!( - "#{session.home_server_protocol}://#{session.home_server}/_matrix/client/api/v1/join/#{ + "#{base_url(config)}/client/api/v1/join/#{ room_name }?access_token=#{session.access_token}", "", @@ -56,7 +61,7 @@ defmodule Matrix.Client do response = HTTPoison.get!( - "#{session.home_server_protocol}://#{session.home_server}/_matrix/client/api/v1/events", + "#{base_url(config)}/client/api/v1/events", [Accept: "application/json"], params: params, recv_timeout: 40000, @@ -80,7 +85,7 @@ defmodule Matrix.Client do response = HTTPoison.post!( - "#{session.home_server_protocol}://#{session.home_server}/_matrix/client/api/v1/rooms/#{ + "#{base_url(config)}/client/api/v1/rooms/#{ room.room_id }/send/#{event_type}?access_token=#{session.access_token}", Poison.encode!(data) diff --git a/mix.exs b/mix.exs index d11dd7d..e3dc323 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule Bender.Mixfile do def project do [ app: :bender, - version: "0.4.0", + version: "0.5.0", elixir: "~> 1.1", build_embedded: Mix.env() == :prod, start_permanent: Mix.env() == :prod, From 9838fca83cfed589e87fe1f23a08e9b46b404b81 Mon Sep 17 00:00:00 2001 From: Daniel Flanagan Date: Thu, 9 May 2019 16:21:04 -0500 Subject: [PATCH 14/18] Fix tests while we're breaking everything --- config/config.exs | 2 +- lib/bender.ex | 2 +- lib/bender/bot.ex | 5 ++- lib/matrix/client.ex | 45 +++++++++++++---------- lib/matrix/config.ex | 2 +- lib/matrix/session.ex | 2 +- test/bender/parser_test.exs | 14 ++++--- test/matrix/response_constructor_test.exs | 10 ++++- 8 files changed, 51 insertions(+), 31 deletions(-) diff --git a/config/config.exs b/config/config.exs index 50de494..9850935 100644 --- a/config/config.exs +++ b/config/config.exs @@ -18,7 +18,7 @@ config :bender, matrix_user: "bender", matrix_password: "bender", commands: [Bender.Commands.Echo, Bender.Commands.Ping], - event_reactions: [Bender.EventReactions.AutoJoinRoomInvites], + event_reactions: [], room_names: ["#bender:matrix.org"] # diff --git a/lib/bender.ex b/lib/bender.ex index c3a7093..861fa1f 100644 --- a/lib/bender.ex +++ b/lib/bender.ex @@ -19,7 +19,7 @@ defmodule Bender do home_server: home_server, user: user, password: password, - home_server_protocol: home_server_protocol + home_server_protocol: home_server_protocol, home_server_port: home_server_port }, room_names, diff --git a/lib/bender/bot.ex b/lib/bender/bot.ex index c0c2052..324b51a 100644 --- a/lib/bender/bot.ex +++ b/lib/bender/bot.ex @@ -4,16 +4,19 @@ defmodule Bender.Bot do 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, 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) diff --git a/lib/matrix/client.ex b/lib/matrix/client.ex index 180ea20..45e7610 100644 --- a/lib/matrix/client.ex +++ b/lib/matrix/client.ex @@ -1,15 +1,24 @@ defmodule Matrix.Client do - defp base_url(%Matrix.Config{} = config) do - "#{config.home_server_protocol}://#{config.home_server}:#{config.port}/_matrix" + defp base_url( + %Matrix.Config{home_server_protocol: protocol, home_server: host, home_server_port: port} = + config + ) do + "#{protocol}://#{host}:#{port}/_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 + defp base_url(%Matrix.Session{} = session) do + "https://#{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 = @@ -20,15 +29,13 @@ defmodule Matrix.Client do timeout: 10_000 ) - Poison.decode!(response.body, as: %Matrix.Session{}) + Poison.decode!(response.body, as: %Matrix.Session{}) |> IO.inspect() end def leave!(session, room_name) do room_response = HTTPoison.post!( - "#{base_url(config)}/client/api/v1/leave/#{ - room_name - }?access_token=#{session.access_token}", + "#{session}/client/api/v1/leave/#{room_name}?access_token=#{session.access_token}", "", [], timeout: 10_000 @@ -38,9 +45,7 @@ defmodule Matrix.Client do def join!(session, room_name) do room_response = HTTPoison.post!( - "#{base_url(config)}/client/api/v1/join/#{ - room_name - }?access_token=#{session.access_token}", + "#{base_url(session)}/client/api/v1/join/#{room_name}?access_token=#{session.access_token}", "", [], timeout: 10_000 @@ -61,7 +66,7 @@ defmodule Matrix.Client do response = HTTPoison.get!( - "#{base_url(config)}/client/api/v1/events", + "#{base_url(session)}/client/api/v1/events", [Accept: "application/json"], params: params, recv_timeout: 40000, @@ -85,9 +90,9 @@ defmodule Matrix.Client do response = HTTPoison.post!( - "#{base_url(config)}/client/api/v1/rooms/#{ - room.room_id - }/send/#{event_type}?access_token=#{session.access_token}", + "#{base_url(session)}/client/api/v1/rooms/#{room.room_id}/send/#{event_type}?access_token=#{ + session.access_token + }", Poison.encode!(data) ) diff --git a/lib/matrix/config.ex b/lib/matrix/config.ex index 3b2f49c..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, :home_server_protocol] + defstruct [:home_server, :user, :password, :home_server_protocol, :home_server_port] end diff --git a/lib/matrix/session.ex b/lib/matrix/session.ex index b03165b..5273162 100644 --- a/lib/matrix/session.ex +++ b/lib/matrix/session.ex @@ -1,4 +1,4 @@ defmodule Matrix.Session do @derive [Poison.Encoder] - defstruct [:access_token, :home_server, :user_id] + defstruct [:access_token, :home_server, :user_id, :home_server_protocol, :home_server_port] end 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_constructor_test.exs b/test/matrix/response_constructor_test.exs index 05bfb38..0909cfa 100644 --- a/test/matrix/response_constructor_test.exs +++ b/test/matrix/response_constructor_test.exs @@ -17,7 +17,13 @@ defmodule Matrix.ResponseConstructorTest 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" } @@ -51,8 +57,10 @@ defmodule Matrix.ResponseConstructorTest 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: 1_446_024_043_133, From 0864247d46e30ed04e8d0875e00396399fa32f9b Mon Sep 17 00:00:00 2001 From: Daniel Flanagan Date: Thu, 9 May 2019 17:08:01 -0500 Subject: [PATCH 15/18] Fix session not using the configuration --- lib/matrix/client.ex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/matrix/client.ex b/lib/matrix/client.ex index 45e7610..57b74f4 100644 --- a/lib/matrix/client.ex +++ b/lib/matrix/client.ex @@ -29,7 +29,9 @@ defmodule Matrix.Client do timeout: 10_000 ) - Poison.decode!(response.body, as: %Matrix.Session{}) |> IO.inspect() + 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 From e68688674cac951c0464b91c881ec9ffc203a886 Mon Sep 17 00:00:00 2001 From: Daniel Flanagan Date: Thu, 9 May 2019 17:10:48 -0500 Subject: [PATCH 16/18] Fix for realsies --- lib/matrix/client.ex | 8 ++++---- lib/matrix/session.ex | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/matrix/client.ex b/lib/matrix/client.ex index 57b74f4..f16cef7 100644 --- a/lib/matrix/client.ex +++ b/lib/matrix/client.ex @@ -7,7 +7,7 @@ defmodule Matrix.Client do end defp base_url(%Matrix.Session{} = session) do - "https://#{session.home_server}/_matrix" + "#{session.home_server}/_matrix" end def login!( @@ -29,9 +29,9 @@ defmodule Matrix.Client do timeout: 10_000 ) - Poison.decode!(response.body, as: %Matrix.Session{}) - |> IO.inspect() - |> Map.put(:home_server, "#{home_server_protocol}://#{home_server}:#{home_server_port}" + 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 diff --git a/lib/matrix/session.ex b/lib/matrix/session.ex index 5273162..b03165b 100644 --- a/lib/matrix/session.ex +++ b/lib/matrix/session.ex @@ -1,4 +1,4 @@ defmodule Matrix.Session do @derive [Poison.Encoder] - defstruct [:access_token, :home_server, :user_id, :home_server_protocol, :home_server_port] + defstruct [:access_token, :home_server, :user_id] end From aafc1e54496e558927b4ee763a6ac533bd8e7767 Mon Sep 17 00:00:00 2001 From: Daniel Flanagan Date: Wed, 22 May 2019 00:22:02 -0500 Subject: [PATCH 17/18] Fix readme and ignore elixir language server files --- .gitignore | 1 + README.md | 16 ++++++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) 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 From 1033f2e2a2bb3b45a6782342e070e5e593212c2c Mon Sep 17 00:00:00 2001 From: Daniel Flanagan Date: Wed, 28 Jul 2021 15:10:44 -0500 Subject: [PATCH 18/18] Update dependencies to work with newer Elixir versions --- mix.exs | 2 +- mix.lock | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/mix.exs b/mix.exs index e3dc323..0fa55fa 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule Bender.Mixfile do def project do [ app: :bender, - version: "0.5.0", + version: "0.5.1", elixir: "~> 1.1", build_embedded: Mix.env() == :prod, start_permanent: Mix.env() == :prod, diff --git a/mix.lock b/mix.lock index 5942cd3..c2fc96b 100644 --- a/mix.lock +++ b/mix.lock @@ -1,21 +1,21 @@ %{ "bbmustache": {:hex, :bbmustache, "1.0.3"}, - "certifi": {:hex, :certifi, "2.4.2", "75424ff0f3baaccfd34b1214184b6ef616d89e420b258bb0a5ea7d7bc628f7f0", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"}, + "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.14.3", "b5f6f5dcc4f1fba340762738759209e21914516df6be440d85772542d4a5e412", [:rebar3], [{:certifi, "2.4.2", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.4", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"}, - "httpoison": {:hex, :httpoison, "1.3.1", "7ac607311f5f706b44e8b3fab736d0737f2f62a31910ccd9afe7227b43edb7f0", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, - "idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"}, - "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"}, - "mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [:rebar3], [], "hexpm"}, + "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"}, - "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"}, - "poison": {:hex, :poison, "4.0.1", "bcb755a16fac91cad79bfe9fc3585bb07b9331e50cfe3420a24bcc2d735709ae", [:mix], [], "hexpm"}, + "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_fun": {:hex, :ssl_verify_fun, "1.1.4", "f0eafff810d2041e93f915ef59899c923f4568f4585904d010387ed74988e77b", [:make, :mix, :rebar3], [], "hexpm"}, + "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.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm"}, + "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, }