diff options
author | Hubert Chathi <hubert@uhoreg.ca> | 2020-11-02 22:04:22 -0500 |
---|---|---|
committer | Hubert Chathi <hubert@uhoreg.ca> | 2020-11-02 22:04:22 -0500 |
commit | 04644972f45511f8372ab0cfa3e76c6c14d760b8 (patch) | |
tree | 066105ae0c2ef22a91a6559f1483f71cb3da51d8 /lib/polyjuice/client | |
parent | allow 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.ex | 87 |
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 -> |