dbux v1.0.1 DBux.PeerConnection behaviour

This module handles connection to the another D-Bus peer.

At the moment it handles only connections to the buses.

It basically allows to establish a connection and then send and receive messages. Its interface is intentionally quite low-level. You probably won’t be able to use it properly without understanding how D-Bus protocol works.

An example DBux.PeerConnection process:

defmodule MyApp.Bus do
  require Logger
  use DBux.PeerConnection

  @request_name_message_id :request_name
  @add_match_message_id    :add_match

  @introspection """
  <!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
   "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
  <node name="/com/example/sample_object">
    <interface name="com.example.SampleInterface">
      <method name="Frobate">
        <arg name="foo" type="i" direction="in"/>
        <arg name="bar" type="s" direction="out"/>
        <arg name="baz" type="a{us}" direction="out"/>
        <annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
      </method>
      <method name="Bazify">
        <arg name="bar" type="(iiu)" direction="in"/>
        <arg name="bar" type="v" direction="out"/>
      </method>
      <method name="Mogrify">
        <arg name="bar" type="(iiav)" direction="in"/>
      </method>
      <signal name="Changed">
        <arg name="new_value" type="b"/>
      </signal>
      <property name="Bar" type="y" access="readwrite"/>
    </interface>
    <node name="child_of_sample_object"/>
    <node name="another_child_of_sample_object"/>
  </node>
  """

  def start_link(hostname, options \ []) do
    DBux.PeerConnection.start_link(__MODULE__, hostname, options)
  end

  def init(hostname) do
    initial_state = %{hostname: hostname}

    {:ok, "tcp:host=" <> hostname <> ",port=8888", [:anonymous], initial_state}
  end

  def handle_up(state) do
    Logger.info("Up")

    {:send, [
      DBux.Message.build_signal("/", "org.example.dbux.MyApp", "Connected", []),
      {@add_match_message_id,    DBux.MessageTemplate.add_match(:signal, nil, "org.example.dbux.OtherIface")},
      {@request_name_message_id, DBux.MessageTemplate.request_name("org.example.dbux.MyApp", 0x4)}
    ], state}
  end

  def handle_down(state) do
    Logger.warn("Down")
    {:backoff, 1000, state}
  end

  def handle_method_call(serial, sender, "/", "Introspect", "org.freedesktop.DBus.Introspectable", _body, _flags, state) do
    Logger.debug("Got Introspect call")

    {:send, [
      DBux.Message.build_method_return(serial, sender, [%DBux.Value{type: :string, value: @introspection}])
    ], state}
  end

  def handle_method_return(_serial, _sender, _reply_serial, _body, @request_name_message_id, state) do
    Logger.info("Name acquired")
    {:noreply, state}
  end

  def handle_method_return(_serial, _sender, _reply_serial, _body, @add_match_message_id, state) do
    Logger.info("Match added")
    {:noreply, state}
  end

  def handle_error(_serial, _sender, _reply_serial, error_name, _body, @request_name_message_id, state) do
    Logger.warn("Failed to acquire name: " <> error_name)
    {:noreply, state}
  end

  def handle_error(_serial, _sender, _reply_serial, error_name, _body, @add_match_message_id, state) do
    Logger.warn("Failed to add match: " <> error_name)
    {:noreply, state}
  end

  def handle_signal(_serial, _sender, _path, _member, "org.example.dbux.OtherIface", _body, state) do
    Logger.info("Got signal from OtherIface")
    {:noreply, state}
  end

  def handle_signal(_serial, _sender, _path, _member, _member, _body, state) do
    Logger.info("Got other signal")
    {:noreply, state}
  end
end

Summary

Functions

Sends a synchronous call to the PeerConnection process and waits for a reply. See Connection.call/2 for more information

Sends a synchronous request to the PeerConnection process and waits for a reply. See Connection.call/3 for more information

Sends a asynchronous request to the PeerConnection process. See Connection.cast/2 for more information

Sends a reply to a request sent by call/3. See Connection.reply/2 for more information

Sends DBux.Message with attributes appropriate for error

Sends DBux.Message

Sends DBux.Message with attributes appropriate for method call

Sends DBux.Message with attributes appropriate for method return

Sends DBux.Message with attributes appropriate for signal

Connects to the bus run by a D-Bus daemon or other pper using given transport and authentication methods

Callbacks

Called when we receive a call

Called when connection is lost

Called when connection is ready

Called when PeerConnection process is first started. start_link/1 will block until it returns

Types

message_queue ::
  [] |
  [%DBux.Message{body: term, destination: term, error_name: term, flags: term, interface: term, member: term, message_type: term, path: term, reply_serial: term, sender: term, serial: term, signature: term, unix_fds: term} | {message_queue_id, %DBux.Message{body: term, destination: term, error_name: term, flags: term, interface: term, member: term, message_type: term, path: term, reply_serial: term, sender: term, serial: term, signature: term, unix_fds: term}}]
message_queue_id :: String.t | atom | number

Functions

call(conn, req)

Sends a synchronous call to the PeerConnection process and waits for a reply. See Connection.call/2 for more information.

call(conn, req, timeout)

Sends a synchronous request to the PeerConnection process and waits for a reply. See Connection.call/3 for more information.

cast(conn, req)

Sends a asynchronous request to the PeerConnection process. See Connection.cast/2 for more information.

reply(from, response)

Sends a reply to a request sent by call/3. See Connection.reply/2 for more information.

send_error(bus, reply_serial, error_name, body \\ [])

Specs

Sends DBux.Message with attributes appropriate for error.

Returns {:ok, serial} on success.

Returns {:error, reason} otherwise. Please note that error does not mean error reply over D-Bus, but internal application error.

It is a synchronous call.

send_message(bus, message)

Specs

send_message(GenServer.server, %DBux.Message{body: term, destination: term, error_name: term, flags: term, interface: term, member: term, message_type: term, path: term, reply_serial: term, sender: term, serial: term, signature: term, unix_fds: term}) ::
  {:ok, DBux.Serial.t} |
  {:error, any}

Sends DBux.Message.

Returns {:ok, serial} on success.

Returns {:error, reason} otherwise. Please note that error does not mean error reply over D-Bus, but internal application error.

It is a synchronous call.

send_method_call(bus, path, interface, member, body \\ [], destination \\ nil)

Sends DBux.Message with attributes appropriate for method call.

Returns {:ok, serial} on success.

Returns {:error, reason} otherwise. Please note that error does not mean error reply over D-Bus, but internal application error.

It is a synchronous call.

send_method_return(bus, reply_serial, body \\ [])

Specs

send_method_return(GenServer.server, DBux.Serial.t, DBux.Value.list_of_values) ::
  {:ok, DBux.Serial.t} |
  {:error, any}

Sends DBux.Message with attributes appropriate for method return.

Returns {:ok, serial} on success.

Returns {:error, reason} otherwise. Please note that error does not mean error reply over D-Bus, but internal application error.

It is a synchronous call.

send_signal(bus, path, interface, member, body \\ [])

Specs

Sends DBux.Message with attributes appropriate for signal.

Returns {:ok, serial} on success.

Returns {:error, reason} otherwise. Please note that error does not mean error reply over D-Bus, but internal application error.

It is a synchronous call.

start_link(mod, mod_options \\ nil, proc_options \\ [])

Specs

start_link(module, any, list) :: GenServer.on_start

Connects to the bus run by a D-Bus daemon or other pper using given transport and authentication methods.

mod is a module that will become a process, similarily how it happens in GenServer.

mod_options are options that will be passed to init/1.

proc_options are options that will be passed to underlying GenServer.start_link call, so they can contain global process name etc.

It returns the same return value as GenServer.start_link.

Callbacks

handle_call(any, arg1, any)

Specs

handle_call(any, GenServer.server, any) ::
  {:reply, any, any} |
  {:noreply, any} |
  {:stop, any, any}

Called when we receive a call.

Returning {:noreply, state} will cause to update state with state.

Returning {:reply, value, state} will cause to update state with state and return value to the caller .

Returning {:stop, reason, state} will cause to terminate the process.

handle_down(any)

Specs

handle_down(any) ::
  {:connect, any} |
  {:backoff, timeout, any} |
  {:noconnect, any} |
  {:stop, any, any}

Called when connection is lost.

Returning {:connect, state} will cause to try to reconnect immediately.

Returning {:backoff, timeout, state} will cause to try to reconnect after timeout milliseconds.

Returning {:noconnect, state} will cause to update state with state and do nothing.

Returning {:stop, info, state} will cause to terminate the process.

handle_error(arg0, arg1, arg2, arg3, arg4, message_queue_id, any)

Specs

Called when we receive an error.

Returning {:noreply, state} will cause to update state with state.

handle_method_call(arg0, arg1, arg2, arg3, arg4, arg5, number, any)

Specs

handle_method_call(DBux.Serial.t, String.t, String.t, String.t, String.t, DBux.Value.list_of_values, number, any) ::
  {:noreply, any} |
  {:send, message_queue}

Called when we receive a method call.

Returning {:noreply, state} will cause to update state with state.

Returning {:send, list_of_messages, state} will cause to update state with state and send messages passed as the second element of the tuple. The list can just contain DBux.Message structs or {identifier, %DBux.Message{}} tuples, where identifier is an arbitrary identifier that will allow later to match response with the message.

handle_method_return(arg0, arg1, arg2, arg3, message_queue_id, any)

Specs

handle_method_return(DBux.Serial.t, String.t, DBux.Serial.t, DBux.Value.list_of_values, message_queue_id, any) ::
  {:noreply, any} |
  {:send, message_queue}

Called when we receive a method return.

Returning {:noreply, state} will cause to update state with state.

Returning {:send, list_of_messages, state} will cause to update state with state and send messages passed as the second element of the tuple. The list can just contain DBux.Message structs or {identifier, %DBux.Message{}} tuples, where identifier is an arbitrary identifier that will allow later to match response with the message.

handle_signal(arg0, arg1, arg2, arg3, arg4, arg5, any)

Specs

handle_signal(DBux.Serial.t, String.t, String.t, String.t, String.t, DBux.Value.list_of_values, any) ::
  {:noreply, any} |
  {:send, message_queue}

Called when we receive a signal.

Returning {:noreply, state} will cause to update state with state.

handle_up(any)

Specs

handle_up(any) ::
  {:noreply, any} |
  {:send, message_queue}

Called when connection is ready.

Returning {:noreply, state} will cause to update state with state.

Returning {:send, list_of_messages, state} will cause to update state with state and send messages passed as the second element of the tuple. The list can just contain DBux.Message structs or {identifier, %DBux.Message{}} tuples, where identifier is an arbitrary identifier that will allow later to match response with the message.

init(any)

Specs

init(any) :: {:ok, String.t, [any], any}

Called when PeerConnection process is first started. start_link/1 will block until it returns.

The first argument will be the same as mod_options passed to start_link/3.

Returning {:ok, address, auth_mechanisms, state} will cause start_link/5 to return {:ok, pid} and the process to enter its loop with state state