defmodule Kadabra do @moduledoc """ HTTP/2 client for Elixir. """ alias Kadabra.{Connection} @doc ~S""" Opens a new connection. ## Examples iex> {:ok, pid} = Kadabra.open('http2.golang.org', :https) iex> is_pid(pid) true """ @spec open(charlist, :https, Keyword.t) :: {:ok, pid} | {:error, term} def open(uri, scheme, opts \\ []) do port = Keyword.get(opts, :port, 443) reconnect = Keyword.get(opts, :reconnect, true) nopts = opts |> List.keydelete(:port, 0) |> List.keydelete(:reconnect, 0) start_opts = [scheme: scheme, ssl: nopts, port: port, reconnect: reconnect] case Connection.start_link(uri, self(), start_opts) do {:ok, pid} -> {:ok, pid} {:error, reason} -> {:error, reason} end end @doc ~S""" Closes an existing connection. ## Examples iex> {:ok, pid} = Kadabra.open('http2.golang.org', :https) iex> Kadabra.close(pid) iex> receive do ...> {:closed, ^pid} -> "connection closed!" ...> end "connection closed!" """ @spec close(pid) :: :ok def close(pid), do: GenServer.cast(pid, {:send, :goaway}) @doc ~S""" Pings an existing connection. ## Examples iex> {:ok, pid} = Kadabra.open('http2.golang.org', :https) iex> Kadabra.ping(pid) iex> receive do ...> {:pong, ^pid} -> "got pong!" ...> end "got pong!" """ def ping(pid), do: GenServer.cast(pid, {:send, :ping}) @doc ~S""" Makes a request with given headers. ## Examples iex> {:ok, pid} = Kadabra.open('http2.golang.org', :https) iex> path = "/reqinfo" # Route echoes PUT body in uppercase iex> headers = [ ...> {":method", "GET"}, ...> {":path", path}, ...> ] iex> Kadabra.request(pid, headers) iex> response = receive do ...> {:end_stream, %Kadabra.Stream.Response{} = response} -> response ...> after 5_000 -> :timed_out ...> end iex> {response.id, response.status} {1, 200} """ def request(pid, headers) do GenServer.cast(pid, {:send, :headers, headers}) end @doc ~S""" Makes a request with given headers and body. ## Examples iex> {:ok, pid} = Kadabra.open('http2.golang.org', :https) iex> path = "/ECHO" # Route echoes PUT body in uppercase iex> body = "sample echo request" iex> headers = [ ...> {":method", "PUT"}, ...> {":path", path}, ...> ] iex> Kadabra.request(pid, headers, body) iex> response = receive do ...> {:end_stream, %Kadabra.Stream.Response{} = response} -> response ...> after 5_000 -> :timed_out ...> end iex> {response.id, response.status, response.body} {1, 200, "SAMPLE ECHO REQUEST"} """ def request(pid, headers, body) do GenServer.cast(pid, {:send, :headers, headers, body}) end @doc ~S""" Makes a GET request. ## Examples iex> {:ok, pid} = Kadabra.open('http2.golang.org', :https) iex> Kadabra.get(pid, "/reqinfo") :ok iex> response = receive do ...> {:end_stream, response} -> response ...> end iex> {response.id, response.status} {1, 200} """ def get(pid, path) do headers = [ {":method", "GET"}, {":path", path}, ] request(pid, headers) end @doc ~S""" Makes a POST request. """ def post(pid, path, payload) do headers = [ {":method", "POST"}, {":path", path}, ] request(pid, headers, payload) end @doc ~S""" Makes a PUT request. ## Examples iex> {:ok, pid} = Kadabra.open('http2.golang.org', :https) iex> Kadabra.put(pid, "/crc32", "test") :ok iex> stream = receive do ...> {:end_stream, stream} -> stream ...> end iex> stream.status 200 iex> stream.body "bytes=4, CRC32=d87f7e0c" """ def put(pid, path, payload) do headers = [ {":method", "PUT"}, {":path", path}, ] request(pid, headers, payload) end end