Amarula.Protocol.USync (amarula v0.1.0)

View Source

USync (user sync) query builder and result parser.

Port of Baileys' WAUSync (src/WAUSync/). A USync query bundles one or more protocols (devices, contact, status, lid, ...) and a list of users to look up, then is serialized into a single iq get with xmlns="usync".

This module is pure: it builds the request Node and parses the response Node. The socket layer is responsible for sending the IQ and correlating the reply (see Amarula.Connection's tracked-IQ machinery).

Usage

USync.new()
|> USync.with_context("message")
|> USync.with_protocol(:devices)
|> USync.with_protocol(:lid)
|> USync.with_user(%{id: "1234@s.whatsapp.net"})
|> USync.build_iq()

Parse the result of the matching iq reply with parse_result/2:

USync.parse_result(query, reply_node)
#=> %{list: [%{"devices" => ..., id: "1234@s.whatsapp.net"}], side_list: []}

Summary

Functions

Build the iq request node for this query.

Start a new, empty USync query.

Parse a USync iq reply for the given query.

Set the query context (default "interactive").

Set the query mode (default "query").

Append a protocol to the query. Order is preserved to match the request element order Baileys produces.

Append a user to look up.

Types

protocol()

@type protocol() ::
  :devices
  | :contact
  | :status
  | :disappearing_mode
  | :bot_profile
  | :lid
  | :username

result()

@type result() :: %{list: [result_entry()], side_list: [result_entry()]}

result_entry()

@type result_entry() :: %{:id => String.t(), optional(String.t()) => any()}

t()

@type t() :: %Amarula.Protocol.USync{
  context: String.t(),
  mode: String.t(),
  protocols: [protocol()],
  users: [user()]
}

user()

@type user() :: %{
  optional(:id) => String.t(),
  optional(:lid) => String.t(),
  optional(:phone) => String.t(),
  optional(:username) => String.t(),
  optional(:username_key) => String.t(),
  optional(:type) => String.t(),
  optional(:persona_id) => String.t()
}

Functions

build_iq(query, sid \\ nil)

@spec build_iq(t(), String.t() | nil) ::
  {:ok, Amarula.Protocol.Binary.Node.t()} | {:error, :no_protocols}

Build the iq request node for this query.

Mirrors Baileys' executeUSyncQuery. The caller supplies the sid (Baileys uses a fresh message tag); id is left unset so the socket layer can stamp the correlation id when it sends the IQ.

Returns {:error, :no_protocols} if no protocol was added.

new()

@spec new() :: t()

Start a new, empty USync query.

parse_result(query, reply)

@spec parse_result(t(), Amarula.Protocol.Binary.Node.t() | nil) :: result() | nil

Parse a USync iq reply for the given query.

Returns %{list: [...], side_list: [...]} where each list entry is a map of protocol_name => parsed_value plus an :id key (the user's jid). Returns nil if the reply is not a type="result" IQ.

Side-list parsing is not yet implemented (matches the Baileys TODO).

with_context(q, context)

@spec with_context(t(), String.t()) :: t()

Set the query context (default "interactive").

with_mode(q, mode)

@spec with_mode(t(), String.t()) :: t()

Set the query mode (default "query").

with_protocol(q, protocol)

@spec with_protocol(t(), protocol()) :: t()

Append a protocol to the query. Order is preserved to match the request element order Baileys produces.

with_user(q, user)

@spec with_user(t(), user()) :: t()

Append a user to look up.