summaryrefslogtreecommitdiff
path: root/lib/polyjuice/client
diff options
context:
space:
mode:
authorHubert Chathi <hubert@uhoreg.ca>2020-11-02 22:04:22 -0500
committerHubert Chathi <hubert@uhoreg.ca>2020-11-02 22:04:22 -0500
commit04644972f45511f8372ab0cfa3e76c6c14d760b8 (patch)
tree066105ae0c2ef22a91a6559f1483f71cb3da51d8 /lib/polyjuice/client
parentallow compressed server responses (diff)
add support for proxies, SSL options, and following redirects
Diffstat (limited to 'lib/polyjuice/client')
-rw-r--r--lib/polyjuice/client/sync.ex87
1 files changed, 63 insertions, 24 deletions
diff --git a/lib/polyjuice/client/sync.ex b/lib/polyjuice/client/sync.ex
index 4671260..c315e90 100644
--- a/lib/polyjuice/client/sync.ex
+++ b/lib/polyjuice/client/sync.ex
@@ -21,16 +21,17 @@ defmodule Polyjuice.Client.Sync do
@doc """
Start a sync task.
"""
- @enforce_keys [:id, :homeserver_url, :uri, :storage]
+ @enforce_keys [:id, :homeserver_url, :storage, :hackney_connect, :hackney_request]
defstruct [
:handler,
:conn_ref,
:id,
:pid,
:homeserver_url,
- :uri,
:storage,
:since,
+ :hackney_connect,
+ :hackney_request,
query_params: "",
backoff: nil,
set_filter: nil,
@@ -47,8 +48,12 @@ defmodule Polyjuice.Client.Sync do
homeserver_url,
id,
pid,
+ hackney_opts,
%{storage: storage, handler: handler, test: test} = opts
) do
+ homeserver_url =
+ if is_binary(homeserver_url), do: URI.parse(homeserver_url), else: homeserver_url
+
# Figure out how to handle the filter (if any): can we pass it in straight
# to the query, or do we need to get its ID. And if we get its ID, do we
# already have it, or do we need to send it to the server?
@@ -83,35 +88,73 @@ defmodule Polyjuice.Client.Sync do
|> Enum.concat()
|> URI.encode_query()
- uri = URI.merge(homeserver_url, @sync_path)
-
Registry.register(Polyjuice.Client, {id, :sync}, nil)
+ {hackney_connect, hackney_request} = get_hackney_functions(opts, hackney_opts, homeserver_url)
+
connect(%__MODULE__{
handler: handler,
id: id,
pid: pid,
homeserver_url: homeserver_url,
- uri: uri,
query_params: query_params,
storage: storage,
since: Polyjuice.Client.Storage.get_sync_token(storage),
+ hackney_connect: hackney_connect,
+ hackney_request: hackney_request,
set_filter: set_filter,
test: test
})
end
+ defp get_hackney_functions(opts, hackney_opts, uri) do
+ hackney_transport =
+ case uri.scheme do
+ "http" -> :hackney_tcp
+ "https" -> :hackney_ssl
+ end
+
+ hackney_opts = [recv_timeout: @sync_timeout + @buffer_timeout] ++ hackney_opts
+
+ hackney_connect =
+ if Map.has_key?(opts, :proxy) do
+ # we only get one request per connection when using a proxy, so don't
+ # bother trying to maintain an open connection. We'll just make single
+ # requests.
+ fn -> {:ok, nil} end
+ else
+ fn ->
+ :hackney.connect(hackney_transport, uri.host, uri.port, hackney_opts)
+ end
+ end
+
+ hackney_request =
+ if Map.has_key?(opts, :proxy) do
+ fn method, path, headers, body, state ->
+ url = URI.merge(state.homeserver_url, path) |> to_string()
+ :hackney.request(method, url, headers, body, hackney_opts)
+ end
+ else
+ fn method, path, headers, body, state ->
+ uri = URI.merge(state.homeserver_url, path)
+ abs_path = if uri.query, do: "#{uri.path}?#{uri.query}", else: uri.path
+
+ :hackney.send_request(
+ state.conn_ref,
+ {method, abs_path, [{"Host", state.homeserver_url.host} | headers], body}
+ )
+ end
+ end
+
+ {hackney_connect, hackney_request}
+ end
+
defp calc_backoff(backoff), do: if(backoff, do: min(backoff * 2, 30), else: 1)
defp connect(state) do
if state.backoff, do: :timer.sleep(state.backoff * 1000)
- uri = state.uri
- options = [recv_timeout: @sync_timeout + @buffer_timeout]
-
- case %URI{scheme: uri.scheme, host: uri.host, port: uri.port}
- |> URI.to_string()
- |> :hackney.connect(options) do
+ case state.hackney_connect.() do
{:ok, conn_ref} ->
Logger.info("Connected to sync")
Polyjuice.Client.Handler.handle(state.handler, :sync_connected)
@@ -125,7 +168,7 @@ defmodule Polyjuice.Client.Sync do
# FIXME: what errors do we need to handle differently?
{:error, err} ->
backoff = calc_backoff(state.backoff)
- Logger.error("Sync error: #{err}; retrying in #{backoff} seconds.")
+ Logger.error("Sync connection error: #{err}; retrying in #{backoff} seconds.")
connect(%{state | backoff: backoff})
end
end
@@ -139,12 +182,6 @@ defmodule Polyjuice.Client.Sync do
%{access_token: access_token, user_id: user_id} = GenServer.call(state.pid, :get_state)
- path =
- URI.merge(
- state.homeserver_url,
- "#{Polyjuice.Client.Endpoint.HttpSpec.prefix_r0()}/user/#{e.(user_id)}/filter"
- ).path
-
headers = [
{"Accept", "application/json"},
{"Accept-Encoding", "gzip, deflate"},
@@ -152,10 +189,12 @@ defmodule Polyjuice.Client.Sync do
{"Authorization", "Bearer #{access_token}"}
]
- case :hackney.send_request(
- state.conn_ref,
- {if(state.test, do: :put, else: :post), path, headers,
- Jason.encode_to_iodata!(state.set_filter)}
+ case state.hackney_request.(
+ if(state.test, do: :put, else: :post),
+ "#{Polyjuice.Client.Endpoint.HttpSpec.prefix_r0()}/user/#{e.(user_id)}/filter",
+ headers,
+ Jason.encode_to_iodata!(state.set_filter),
+ state
) do
{:ok, status_code, resp_headers, client_ref} ->
case status_code do
@@ -254,12 +293,12 @@ defmodule Polyjuice.Client.Sync do
]
path =
- state.uri.path <>
+ @sync_path <>
"?" <>
state.query_params <>
if state.since, do: "&since=" <> URI.encode_www_form(state.since), else: ""
- case :hackney.send_request(state.conn_ref, {:get, path, headers, ""}) do
+ case state.hackney_request.(:get, path, headers, "", state) do
{:ok, status_code, resp_headers, client_ref} ->
case status_code do
200 ->