summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHubert Chathi <hubert@uhoreg.ca>2020-08-29 22:28:04 -0400
committerHubert Chathi <hubert@uhoreg.ca>2020-08-29 22:43:12 -0400
commit126ff42d912dfea9e251e2b98bdcf8f295b8707e (patch)
tree5820307fc63e643e36b9534686c3585d5ad3b346
parentadd module for handling .well-known (diff)
make Polyjuice.Client.start_link return {:ok, pid}, like a normal start_link
add a function that returns a client struct from the pid, and add a stop function to Polyjuice.Client.stop
-rw-r--r--lib/mix/tasks/polyjuice/login.ex6
-rw-r--r--lib/mix/tasks/polyjuice/logout.ex6
-rw-r--r--lib/polyjuice/client.ex91
-rw-r--r--lib/polyjuice/client/low_level.ex5
-rw-r--r--test/polyjuice/client/media_test.exs6
-rw-r--r--test/polyjuice/client/room_test.exs2
-rw-r--r--test/polyjuice/client/sync_test.exs26
-rw-r--r--test/polyjuice/client_test.exs124
-rw-r--r--test/support/dummy_client.ex22
9 files changed, 170 insertions, 118 deletions
diff --git a/lib/mix/tasks/polyjuice/login.ex b/lib/mix/tasks/polyjuice/login.ex
index 3ae1234..f485ed5 100644
--- a/lib/mix/tasks/polyjuice/login.ex
+++ b/lib/mix/tasks/polyjuice/login.ex
@@ -51,16 +51,18 @@ defmodule Mix.Tasks.Polyjuice.Login do
nil
end
- client =
+ {:ok, client_pid} =
Polyjuice.Client.start_link(
url,
storage: storage,
sync: false
)
+ client = Polyjuice.Client.get_client(client_pid)
+
ret = Polyjuice.Client.log_in_with_password(client, user_id, password)
- Polyjuice.Client.stop(client)
+ Polyjuice.Client.API.stop(client)
if storage, do: Polyjuice.Client.Storage.close(storage)
diff --git a/lib/mix/tasks/polyjuice/logout.ex b/lib/mix/tasks/polyjuice/logout.ex
index 9ac65a3..71f0e4d 100644
--- a/lib/mix/tasks/polyjuice/logout.ex
+++ b/lib/mix/tasks/polyjuice/logout.ex
@@ -54,7 +54,7 @@ defmodule Mix.Tasks.Polyjuice.Logout do
nil
end
- client =
+ {:ok, client_pid} =
Polyjuice.Client.start_link(
url,
access_token: opts[:access_token],
@@ -62,9 +62,11 @@ defmodule Mix.Tasks.Polyjuice.Logout do
sync: false
)
+ client = Polyjuice.Client.get_client(client_pid)
+
ret = Polyjuice.Client.log_out(client)
- Polyjuice.Client.stop(client)
+ Polyjuice.Client.API.stop(client)
if storage, do: Polyjuice.Client.Storage.close(storage)
diff --git a/lib/polyjuice/client.ex b/lib/polyjuice/client.ex
index 9f4aa8f..3f1668c 100644
--- a/lib/polyjuice/client.ex
+++ b/lib/polyjuice/client.ex
@@ -16,10 +16,7 @@ defmodule Polyjuice.Client do
@moduledoc """
Matrix client functions.
- To start a client, use `start_link/2`, and to stop it, use
- `stop/3`.
-
- The struct in this module, or any struct that implements the
+ The client created by this module, or any client that implements the
`Polyjuice.Client.API` protocol, can be used to connect to a Matrix server
using the functions from submodules.
@@ -31,7 +28,23 @@ defmodule Polyjuice.Client do
The client defined in this module should work for most cases. If you want
more control, you can use `Polyjuice.Client.LowLevel` instead.
+ To start a client with this module, create a process using `start_link/2`,
+ and then call `get_client/1` to get a struct that can be used with the above
+ modules. To stop the client, use `Polyjuice.Client.API.stop/3`.
+
"""
+
+ @doc """
+ Returns a specification to start the client.
+
+ `arg` must be a list, where the first element is the base URL for the
+ homeserver, and the remainder of the list is options, as would be given to
+ `start_link/2`. For example:
+
+ Polyjuice.Client.child_spec(["http://localhost:8008", sync: false])
+
+ """
+ use Supervisor
require Logger
@typedoc """
@@ -81,14 +94,29 @@ defmodule Polyjuice.Client do
will not start if there is no `storage` or `handler` provided.
- `sync_filter`: the filter to use for the sync. Defaults to no filter.
"""
- @spec start_link(base_url :: String.t(), opts :: Keyword.t()) :: t()
- def start_link(base_url, opts \\ []) when is_binary(base_url) and is_list(opts) do
+ @spec start_link(base_url :: String.t(), opts :: Keyword.t()) :: {:ok, pid}
+ def start_link(base_url, opts) when is_binary(base_url) and is_list(opts) do
base_url =
if(String.ends_with?(base_url, "/"), do: base_url, else: base_url <> "/")
|> URI.parse()
client_id = Agent.get_and_update(Polyjuice.Client.ID, &{&1, &1 + 1})
+ Supervisor.start_link(
+ __MODULE__,
+ [client_id, base_url, opts],
+ name: process_name(client_id, :supervisor)
+ )
+ end
+
+ def start_link(base_url) when is_binary(base_url), do: start_link(base_url, [])
+
+ def start_link([base_url | opts]) when is_binary(base_url) and is_list(opts) do
+ start_link(base_url, opts)
+ end
+
+ @impl Supervisor
+ def init([client_id, base_url, opts]) do
sync = Keyword.get(opts, :sync, true)
storage = Keyword.get(opts, :storage)
handler = Keyword.get(opts, :handler)
@@ -153,7 +181,16 @@ defmodule Polyjuice.Client do
%{
access_token: access_token,
user_id: user_id,
- device_id: device_id
+ device_id: device_id,
+ client: %__MODULE__{
+ base_url: base_url,
+ id: client_id,
+ storage: storage,
+ handler: handler,
+ sync: sync,
+ opts: opts,
+ test: Keyword.get(opts, :test, false)
+ }
}
end,
[name: process_name(client_id, :state)]
@@ -165,29 +202,19 @@ defmodule Polyjuice.Client do
)
]
- {:ok, _pid} =
- Supervisor.start_link(children,
- strategy: :rest_for_one,
- name: process_name(client_id, :supervisor)
- )
-
- %__MODULE__{
- base_url: base_url,
- id: client_id,
- storage: storage,
- handler: handler,
- sync: sync,
- opts: opts,
- test: Keyword.get(opts, :test, false)
- }
+ Supervisor.init(children, strategy: :rest_for_one)
end
@doc """
- Stop a client.
+ Get a struct that implements `Polyjuice.Client.API` from the pid given by
+ `start_link`.
"""
- @spec stop(Polyjuice.Client.t(), reason :: term, timeout()) :: :ok
- def stop(%__MODULE__{id: id}, reason \\ :normal, timeout \\ :infinity) do
- Supervisor.stop(process_name(id, :supervisor), reason, timeout)
+ def get_client(pid) do
+ agent_pid =
+ Supervisor.which_children(pid)
+ |> Enum.find_value(fn {id, pid, _, _} -> if id == Polyjuice.Client, do: pid end)
+
+ Agent.get(agent_pid, &Map.fetch!(&1, :client))
end
@doc false
@@ -244,6 +271,12 @@ defmodule Polyjuice.Client do
"""
@spec transaction_id(client_api :: Polyjuice.Client.API.t()) :: String.t()
def transaction_id(client_api)
+
+ @doc """
+ Stop the client.
+ """
+ @spec stop(Polyjuice.Client.t(), reason :: term, timeout()) :: :ok
+ def stop(client_api, reason \\ :normal, timeout \\ :infinity)
end
defimpl Polyjuice.Client.API do
@@ -369,6 +402,10 @@ defmodule Polyjuice.Client do
def transaction_id(_) do
"#{Node.self()}_#{:erlang.system_time(:millisecond)}_#{:erlang.unique_integer()}"
end
+
+ def stop(%{id: id}, reason \\ :normal, timeout \\ :infinity) do
+ Supervisor.stop(Polyjuice.Client.process_name(id, :supervisor), reason, timeout)
+ end
end
@doc false
@@ -518,7 +555,7 @@ defmodule Polyjuice.Client do
)
end
- if client.sync do
+ if client.sync && client.handler do
# make sure we don't already have a sync process running
kill_sync(client.id)
diff --git a/lib/polyjuice/client/low_level.ex b/lib/polyjuice/client/low_level.ex
index 918805e..f41cf8c 100644
--- a/lib/polyjuice/client/low_level.ex
+++ b/lib/polyjuice/client/low_level.ex
@@ -109,6 +109,11 @@ defmodule Polyjuice.Client.LowLevel do
def transaction_id(_) do
"#{Node.self()}_#{:erlang.system_time(:millisecond)}_#{:erlang.unique_integer()}"
end
+
+ def stop(_, _, _) do
+ # don't need to do anything to stop it
+ :ok
+ end
end
@doc """
diff --git a/test/polyjuice/client/media_test.exs b/test/polyjuice/client/media_test.exs
index 4c545ac..abe7b83 100644
--- a/test/polyjuice/client/media_test.exs
+++ b/test/polyjuice/client/media_test.exs
@@ -86,7 +86,7 @@ defmodule Polyjuice.Client.MediaTest do
port = :httpd.info(httpd_pid) |> Keyword.fetch!(:port)
- client =
+ {:ok, client_pid} =
Polyjuice.Client.start_link(
"http://127.0.0.1:#{port}/Elixir.Polyjuice.Client.MediaTest.Httpd",
access_token: "an_access_token",
@@ -95,6 +95,8 @@ defmodule Polyjuice.Client.MediaTest do
test: true
)
+ client = Polyjuice.Client.get_client(client_pid)
+
{:ok, url} = Polyjuice.Client.Media.upload(client, {:file, "mix.exs"})
assert url == "mxc://example.org/abcdefg"
@@ -106,7 +108,7 @@ defmodule Polyjuice.Client.MediaTest do
assert content_type == "text/plain"
assert Enum.join(body) == "foo"
- Polyjuice.Client.stop(client)
+ Polyjuice.Client.API.stop(client)
:inets.stop(:httpd, httpd_pid)
after
diff --git a/test/polyjuice/client/room_test.exs b/test/polyjuice/client/room_test.exs
index 97180b0..6c631e0 100644
--- a/test/polyjuice/client/room_test.exs
+++ b/test/polyjuice/client/room_test.exs
@@ -332,7 +332,7 @@ defmodule Polyjuice.Client.RoomTest do
}
]
- DummyClient.MultiReq.destroy(client)
+ Polyjuice.Client.API.stop(client)
end
end
end
diff --git a/test/polyjuice/client/sync_test.exs b/test/polyjuice/client/sync_test.exs
index ae86fa4..e1085d6 100644
--- a/test/polyjuice/client/sync_test.exs
+++ b/test/polyjuice/client/sync_test.exs
@@ -196,7 +196,7 @@ defmodule Polyjuice.Client.SyncTest do
end
end
- defp handle_login(session_id, _env, {_, input}) do
+ defp handle_login(session_id, _env, _input) do
:mod_esi.deliver(
session_id,
'Content-Type: application/json\r\n\r\n{"user_id":"@alice:example.org","access_token":"an_access_token","device_id":"foo"}'
@@ -235,7 +235,7 @@ defmodule Polyjuice.Client.SyncTest do
port = :httpd.info(httpd_pid) |> Keyword.fetch!(:port)
- client =
+ {:ok, client_pid} =
Polyjuice.Client.start_link(
"http://127.0.0.1:#{port}/Elixir.Polyjuice.Client.SyncTest.Httpd",
access_token: "an_access_token",
@@ -246,6 +246,8 @@ defmodule Polyjuice.Client.SyncTest do
test: true
)
+ client = Polyjuice.Client.get_client(client_pid)
+
assert_receive({:polyjuice_client, :sync_connected})
assert_receive(
@@ -329,7 +331,7 @@ defmodule Polyjuice.Client.SyncTest do
1000
)
- Polyjuice.Client.stop(client)
+ Polyjuice.Client.API.stop(client)
:inets.stop(:httpd, httpd_pid)
after
@@ -362,7 +364,7 @@ defmodule Polyjuice.Client.SyncTest do
port = :httpd.info(httpd_pid) |> Keyword.fetch!(:port)
- client =
+ {:ok, client_pid} =
Polyjuice.Client.start_link(
"http://127.0.0.1:#{port}/Elixir.Polyjuice.Client.SyncTest.Httpd",
handler: self(),
@@ -371,6 +373,8 @@ defmodule Polyjuice.Client.SyncTest do
test: true
)
+ client = Polyjuice.Client.get_client(client_pid)
+
{:ok, _} = Polyjuice.Client.log_in_with_password(client, "@alice:example.org", "password")
assert_receive({:polyjuice_client, :sync_connected})
@@ -384,7 +388,7 @@ defmodule Polyjuice.Client.SyncTest do
|> Supervisor.which_children()
|> Enum.find(fn {id, _, _, _} -> id == Polyjuice.Client.Sync end) == nil
- Polyjuice.Client.stop(client)
+ Polyjuice.Client.API.stop(client)
:inets.stop(:httpd, httpd_pid)
after
@@ -417,7 +421,7 @@ defmodule Polyjuice.Client.SyncTest do
port = :httpd.info(httpd_pid) |> Keyword.fetch!(:port)
- client =
+ {:ok, client_pid} =
Polyjuice.Client.start_link(
"http://127.0.0.1:#{port}/Elixir.Polyjuice.ClientTest.Httpd.LoggedOut",
access_token: "an_access_token",
@@ -428,6 +432,8 @@ defmodule Polyjuice.Client.SyncTest do
test: true
)
+ client = Polyjuice.Client.get_client(client_pid)
+
assert_receive({:polyjuice_client, :logged_out, {false}})
# make sure the sync has time to stop
@@ -438,7 +444,7 @@ defmodule Polyjuice.Client.SyncTest do
|> Enum.find_value(fn {id, pid, _, _} -> if id == Polyjuice.Client.Sync, do: pid end) ==
:undefined
- Polyjuice.Client.stop(client)
+ Polyjuice.Client.API.stop(client)
:inets.stop(:httpd, httpd_pid)
after
@@ -471,7 +477,7 @@ defmodule Polyjuice.Client.SyncTest do
port = :httpd.info(httpd_pid) |> Keyword.fetch!(:port)
- client =
+ {:ok, client_pid} =
Polyjuice.Client.start_link(
"http://127.0.0.1:#{port}/Elixir.Polyjuice.ClientTest.Httpd.LoggedOut",
access_token: "an_access_token",
@@ -481,6 +487,8 @@ defmodule Polyjuice.Client.SyncTest do
test: true
)
+ client = Polyjuice.Client.get_client(client_pid)
+
assert_receive({:polyjuice_client, :logged_out, {false}})
# make sure the sync has time to stop
@@ -491,7 +499,7 @@ defmodule Polyjuice.Client.SyncTest do
|> Enum.find_value(fn {id, pid, _, _} -> if id == Polyjuice.Client.Sync, do: pid end) ==
:undefined
- Polyjuice.Client.stop(client)
+ Polyjuice.Client.API.stop(client)
:inets.stop(:httpd, httpd_pid)
after
diff --git a/test/polyjuice/client_test.exs b/test/polyjuice/client_test.exs
index d11239c..d9f95a8 100644
--- a/test/polyjuice/client_test.exs
+++ b/test/polyjuice/client_test.exs
@@ -150,7 +150,7 @@ defmodule Polyjuice.ClientTest do
port = :httpd.info(httpd_pid) |> Keyword.fetch!(:port)
- client =
+ {:ok, client_pid} =
Polyjuice.Client.start_link(
"http://127.0.0.1:#{port}/Elixir.Polyjuice.ClientTest.Httpd/",
access_token: "an_access_token",
@@ -159,6 +159,8 @@ defmodule Polyjuice.ClientTest do
test: true
)
+ client = Polyjuice.Client.get_client(client_pid)
+
# binary body
assert Polyjuice.Client.API.call(
client,
@@ -187,7 +189,7 @@ defmodule Polyjuice.ClientTest do
}
) == {:ok, %{"foo" => "bar"}}
- Polyjuice.Client.stop(client)
+ Polyjuice.Client.API.stop(client)
:inets.stop(:httpd, httpd_pid)
after
@@ -219,7 +221,7 @@ defmodule Polyjuice.ClientTest do
port = :httpd.info(httpd_pid) |> Keyword.fetch!(:port)
- client =
+ {:ok, client_pid} =
Polyjuice.Client.start_link(
"http://127.0.0.1:#{port}/Elixir.Polyjuice.ClientTest.Httpd/",
access_token: nil,
@@ -229,18 +231,18 @@ defmodule Polyjuice.ClientTest do
test: true
)
+ client = Polyjuice.Client.get_client(client_pid)
+
Polyjuice.Client.log_in_with_password(client, "@alice:example.org", "password")
assert Agent.get(
Polyjuice.Client.process_name(client.id, :state),
- fn %{
- access_token: access_token,
- user_id: user_id,
- device_id: device_id
- } ->
- {access_token, user_id, device_id}
- end
- ) == {"m.id.user_login", "@alice:example.org", "foo"}
+ &Map.take(&1, [:access_token, :user_id, :device_id])
+ ) == %{
+ access_token: "m.id.user_login",
+ user_id: "@alice:example.org",
+ device_id: "foo"
+ }
assert_receive({:polyjuice_client, :logged_in, {"@alice:example.org", "foo", _}})
@@ -264,11 +266,7 @@ defmodule Polyjuice.ClientTest do
assert Agent.get(
Polyjuice.Client.process_name(client.id, :state),
- fn %{
- access_token: access_token
- } ->
- access_token
- end
+ &Map.fetch!(&1, :access_token)
) == nil
Polyjuice.Client.log_in_with_password(
@@ -281,14 +279,12 @@ defmodule Polyjuice.ClientTest do
assert Agent.get(
Polyjuice.Client.process_name(client.id, :state),
- fn %{
- access_token: access_token,
- user_id: user_id,
- device_id: device_id
- } ->
- {access_token, user_id, device_id}
- end
- ) == {"m.id.thirdparty_login", "@alice:example.org", "foo"}
+ &Map.take(&1, [:access_token, :user_id, :device_id])
+ ) == %{
+ access_token: "m.id.thirdparty_login",
+ user_id: "@alice:example.org",
+ device_id: "foo"
+ }
Polyjuice.Client.log_in_with_password(
client,
@@ -300,14 +296,12 @@ defmodule Polyjuice.ClientTest do
assert Agent.get(
Polyjuice.Client.process_name(client.id, :state),
- fn %{
- access_token: access_token,
- user_id: user_id,
- device_id: device_id
- } ->
- {access_token, user_id, device_id}
- end
- ) == {"m.id.phone_login", "@alice:example.org", "foo"}
+ &Map.take(&1, [:access_token, :user_id, :device_id])
+ ) == %{
+ access_token: "m.id.phone_login",
+ user_id: "@alice:example.org",
+ device_id: "foo"
+ }
Polyjuice.Client.log_in_with_password(
client,
@@ -321,16 +315,14 @@ defmodule Polyjuice.ClientTest do
assert Agent.get(
Polyjuice.Client.process_name(client.id, :state),
- fn %{
- access_token: access_token,
- user_id: user_id,
- device_id: device_id
- } ->
- {access_token, user_id, device_id}
- end
- ) == {"ca.uhoreg.foo_login", "@alice:example.org", "foo"}
+ &Map.take(&1, [:access_token, :user_id, :device_id])
+ ) == %{
+ access_token: "ca.uhoreg.foo_login",
+ user_id: "@alice:example.org",
+ device_id: "foo"
+ }
- Polyjuice.Client.stop(client)
+ Polyjuice.Client.API.stop(client)
:inets.stop(:httpd, httpd_pid)
after
@@ -344,7 +336,7 @@ defmodule Polyjuice.ClientTest do
# if we start a client and specify the access token, user ID, and device
# ID, then those values get stored
- client =
+ {:ok, client_pid} =
Polyjuice.Client.start_link(
"http://127.0.0.1:8008/",
access_token: "an_access_token",
@@ -355,16 +347,16 @@ defmodule Polyjuice.ClientTest do
test: true
)
+ client = Polyjuice.Client.get_client(client_pid)
+
assert Agent.get(
Polyjuice.Client.process_name(client.id, :state),
- fn %{
- access_token: access_token,
- user_id: user_id,
- device_id: device_id
- } ->
- {access_token, user_id, device_id}
- end
- ) == {"an_access_token", "@alice:example.org", "a_device"}
+ &Map.take(&1, [:access_token, :user_id, :device_id])
+ ) == %{
+ access_token: "an_access_token",
+ user_id: "@alice:example.org",
+ device_id: "a_device"
+ }
assert Polyjuice.Client.Storage.kv_get(storage, "ca.uhoreg.polyjuice", "access_token") ==
"an_access_token"
@@ -375,12 +367,12 @@ defmodule Polyjuice.ClientTest do
assert Polyjuice.Client.Storage.kv_get(storage, "ca.uhoreg.polyjuice", "device_id") ==
"a_device"
- Polyjuice.Client.stop(client)
+ Polyjuice.Client.API.stop(client)
# if we start a client and don't specify them, but they're stored, use the
# stored values
- client2 =
+ {:ok, client2_pid} =
Polyjuice.Client.start_link(
"http://127.0.0.1:8008/",
sync: false,
@@ -388,16 +380,16 @@ defmodule Polyjuice.ClientTest do
test: true
)
+ client2 = Polyjuice.Client.get_client(client2_pid)
+
assert Agent.get(
Polyjuice.Client.process_name(client2.id, :state),
- fn %{
- access_token: access_token,
- user_id: user_id,
- device_id: device_id
- } ->
- {access_token, user_id, device_id}
- end
- ) == {"an_access_token", "@alice:example.org", "a_device"}
+ &Map.take(&1, [:access_token, :user_id, :device_id])
+ ) == %{
+ access_token: "an_access_token",
+ user_id: "@alice:example.org",
+ device_id: "a_device"
+ }
end
test "invalidates token if server says we're logged out" do
@@ -424,7 +416,7 @@ defmodule Polyjuice.ClientTest do
port = :httpd.info(httpd_pid) |> Keyword.fetch!(:port)
- client =
+ {:ok, client_pid} =
Polyjuice.Client.start_link(
"http://127.0.0.1:#{port}/Elixir.Polyjuice.ClientTest.Httpd.LoggedOut",
access_token: "some_token",
@@ -435,21 +427,19 @@ defmodule Polyjuice.ClientTest do
test: true
)
+ client = Polyjuice.Client.get_client(client_pid)
+
Polyjuice.Client.Room.send_event(client, "!a_room:example.org", "m.room.message", %{})
assert Agent.get(
Polyjuice.Client.process_name(client.id, :state),
- fn %{
- access_token: access_token
- } ->
- access_token
- end
+ &Map.fetch!(&1, :access_token)
) == nil
assert Polyjuice.Client.Storage.kv_get(storage, "ca.uhoreg.polyjuice", "access_token") ==
nil
- Polyjuice.Client.stop(client)
+ Polyjuice.Client.API.stop(client)
:inets.stop(:httpd, httpd_pid)
after
diff --git a/test/support/dummy_client.ex b/test/support/dummy_client.ex
index 7c1556e..bc0d202 100644
--- a/test/support/dummy_client.ex
+++ b/test/support/dummy_client.ex
@@ -32,6 +32,11 @@ defmodule DummyClient do
end
def transaction_id(_), do: "txn_id"
+
+ def stop(_, _, _) do
+ # don't need to do anything to stop it
+ :ok
+ end
end
defmodule MultiReq do
@@ -47,14 +52,6 @@ defmodule DummyClient do
}
end
- def destroy(%{pid: pid}) do
- # make sure we weren't expecting any more requests
- remaining = Agent.get(pid, & &1)
- assert remaining == []
-
- Process.exit(pid, :kill)
- end
-
defimpl Polyjuice.Client.API do
def call(%{pid: pid}, endpoint) do
{request, result} =
@@ -78,6 +75,15 @@ defmodule DummyClient do
end
def transaction_id(_), do: "txn_id"
+
+ def stop(%{pid: pid}, _, _) do
+ # make sure we weren't expecting any more requests
+ remaining = Agent.get(pid, & &1)
+ assert remaining == []
+
+ Process.exit(pid, :kill)
+ :ok
+ end
end
end
end