# Copyright 2019 Hubert Chathi # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. defmodule Polyjuice.Client.Endpoint do @moduledoc false defmodule HttpSpec do @typedoc """ The description of how to handle the endpoint. - `method` is the HTTP verb - `headers` is a list of the HTTP headers - `url` is the URL to call - `body` is the HTTP body (if any) - `transform` is a function to transform the result (status code, headers, content) to a return value - `auth_required` indicates whether the end point requires authentication """ @type t :: %__MODULE__{ method: atom, headers: [{String.t(), String.t()}], url: String.t(), body: String.t(), auth_required: true | false } @enforce_keys [:method, :headers, :url] defstruct [ :method, :headers, :url, body: "", auth_required: true ] end defprotocol Proto do @moduledoc """ Matrix client endpoint. """ @doc """ Generate the spec for calling the endpoint via HTTP. """ @spec http_spec( endpoint_args :: __MODULE__.t(), base_url :: String.t() ) :: Polyjuice.Client.Endpoint.HttpSpec.t() def http_spec(endpoint_args, base_url) @doc """ Transform the HTTP result into a return value. """ @spec transform_http_result( endpoint_args :: __MODULE__.t(), status_code :: integer(), headers :: [{String.t(), String.t()}, ...], body :: String.t() ) :: any def transform_http_result(endpoint_args, status_code, headers, body) end defprotocol BodyParser do @fallback_to_any true @spec parse(endpoint_args :: __MODULE__.t(), body :: any) :: {:ok, any} | any def parse(endpoint_args, body) end defimpl BodyParser, for: Any do def parse(_endpoint_args, body), do: {:ok, body} end @spec parse_response( endpoint_args :: map, status_code :: integer(), headers :: [{String.t(), String.t()}, ...], body :: String.t() ) :: {:ok, any} | any def parse_response(%{} = endpoint_args, status_code, headers, body) when is_integer(status_code) and is_list(headers) and is_binary(body) do # FIXME: check if content type is "application/json" with {:ok, json} <- Poison.decode(body) do case status_code do 200 -> Polyjuice.Client.Endpoint.BodyParser.parse(endpoint_args, json) _ -> {:error, status_code, json} end else _ -> {:error, if(status_code == 200, do: 500, else: status_code), %{"errcode" => "CA_UHOREG_POLYJUICE_BAD_RESPONSE", "body" => body}} end end end