loqui v0.4.2 Loqui.Client

A high performance client for the Loqui protocol

This client exposes five public functions, start_link, request, push, ping and close. In loqui parlance, request is a synchronous call and push is asynchrounous. Be careful with push calls, as they can overwhelm the remote server.

Codecs and Compressors

A codec changes data structures into iodata and a compressor applies a compression algorithm to iodata. They’re applied thusly:

term
|> Codec.encode()
|> Compressor.compress()

When connecting, a Loqui client and server negotiate which compressors and codecs they should use to communicate.

The Loqui client comes with several preinstalled codecs and compressors. They are:

Codecs

Compressors

The dependencies for the JSON and Msgpack codecs are not automatically resolved. If you wish to use one of them, you need to update your app’s mix.exs.

# in your mix.exs
{:jiffy, "~> 0.14.11"}, # adding this line downloads jiffy and enables the Json codec
{:msgpax, "~> 2.0"}, # adding this line downloads msgpax and enables the Msgpack codec

If Loqui can detect the presence of the modules, then the codecs will be enabled.

Defining your own

If you need to define your own codec or compressor, you’ll need to implement a module and then tell the client about it. In order to define one, implement the behaviour:

defmodule Useless do
  @behaviour Loqui.Protocol.Codec

  def name(), do: "useless"
  def encode(term), do: "1"
  def decode(binary), do: 1
end

Then you need to tell the client to use your codec.

{:ok, client} = Loqui.Client.start_link("localhost", 1234, "/_rpc", loqui_opts: [codecs: [Useless]])

During negotiation, codecs and compressors defined by the user take precedence over the defaults, so if the server supports the Useless codec, it will be the one selected. If not, the precedence is: Erlpack, Msgpack, Json. You can override this ordering by re-specifying the default compressors:

alias Loqui.Protocol.Codecs.{Erlpack, Json, Msgpack}
# Starts a Loqui client on port 4450 favoring the Json codec, then the Msgpack codec, then the Erlpack codec.
{:ok, json_client} = Loqui.Client.start_link("localhost", 4450, "/_rpc", loqui_opts: [codecs: [Json, Msgpack, Erlpack]])

Summary

Functions

Closes the connection

Synchronously pings the server

Makes an asynchronous request to the server

Makes a synchronous request to the server

Creates a connection to a Loqui server

Types

loqui_opt()
loqui_opt ::
  {:codecs, [Loqui.Protocol.Codec.t]} |
  {:compressors, [Loqui.Protocol.Compressor.t]}
loqui_opts()
loqui_opts() :: [loqui_opt]
opts()
opts() :: [loqui_opts: loqui_opts, tcp_opts: tcp_opts]
sequence()
sequence() :: 1..4294967295
tcp_opt()
tcp_opt ::
  {:recv_timeout, pos_integer} |
  {:send_timeout, pos_integer}
tcp_opts()
tcp_opts() :: [tcp_opt]

Functions

close(conn, timeout \\ 5000)
close(pid, pos_integer) :: :ok | {:error, term}

Closes the connection.

ping(conn, timeout \\ 5000)
ping(pid, pos_integer) :: :ok | {:error, term}

Synchronously pings the server.

push(conn, payload)
push(pid, term) :: :ok

Makes an asynchronous request to the server.

push sends a request to the server, but doesn’t wait for a reply before returning. This is good for one-off messages, but it’s it’s important to be cognizant that you don’t overwhelm the server with requests, as there’s no backpressure.

request(conn, payload, timeout \\ 5000)
request(pid, term, pos_integer) ::
  {:ok, term} |
  {:error, term}

Makes a synchronous request to the server.

Sends the payload to the server and awaits a response.

start_link(host, port, loqui_path, options)
start_link(String.t, pos_integer, String.t, opts) ::
  {:ok, pid} |
  {:error, term}

Creates a connection to a Loqui server.