Current section
Files
Jump to
Current section
Files
lib/docker_api/request.ex
defmodule DockerAPI.Request do
@moduledoc false
@default_headers [
{"Accept", "application/json"},
{"Content-Type", "application/json"}
]
def get(client, path, headers \\ @default_headers), do: request(client, :get, path, "", headers)
def delete(client, path, headers \\ @default_headers), do: request(client, :delete, path, "", headers)
def post(client, path, body \\ "{}", headers \\ @default_headers), do: request(client, :post, path, body, headers)
def request(client, method, path, body \\ "", headers \\ @default_headers, options \\ []) do
url = client.server<>"/v1.19"<>path
options = Keyword.merge(options, [
hackney: [ssl_options: client.ssl_options]
])
{:ok, raw_reply} = HTTPoison.request(method, url, body, headers, options)
raw_reply |> body_parser
end
def stream_request(client, method, path, body \\ "", headers \\ @default_headers, options \\ []) do
url = client.server<>"/v1.19"<>path
task = Task.async(fn ->
options = Keyword.merge(options, [
hackney: [ssl_options: client.ssl_options],
recv_timeout: 60_000,
stream_to: self
])
{:ok, %HTTPoison.AsyncResponse{}} = HTTPoison.request(method, url, body, headers, options)
stream_loop(nil, [])
end)
case Task.await(task, :infinity) do
{:ok, data} -> data
{:error, reason} -> raise DockerAPI.RequestError, message: reason
end
end
defp stream_loop(status, acc) do
receive do
%HTTPoison.AsyncStatus{code: new_status} -> stream_loop(new_status, acc)
%HTTPoison.AsyncHeaders{} -> stream_loop(status, acc)
%HTTPoison.AsyncChunk{chunk: chunk} -> stream_loop(status, [Poison.decode!(chunk)|acc])
%HTTPoison.AsyncEnd{} -> {:ok, Enum.reverse(acc)}
%HTTPoison.Error{reason: reason} -> {:error, reason}
after 30_000 -> {:error, "Request timed out"}
end
end
defp body_parser(%{body: "", status: status_code}) when status_code < 400, do: :ok
defp body_parser(%{body: body, status: status_code}) when status_code >= 400 do
raise DockerAPI.RequestError, message: body
end
defp body_parser(%{headers: headers, body: body}) do
if {"Content-Type", "application/json"} in headers do
Poison.decode!(body)
else
nil
end
end
end