# DBux
[![Build Status](](
[![Coverage Status](](

DBux provides bindings for [D-Bus]( IPC
protocol for the [Elixir]( programming language.

## Project aims

DBux's aim is to provide low-level GenServer-like pattern to handle interaction
with D-Bus daemon.

It is not going to provide high-level proxy that will magically map
objects/interfaces exported over D-Bus to data structures used in your application.
In my opinion it's a task for an another abstraction layer (read: another project
built on top of DBux).

At the beginning it's going to provide only functionality needed to act as
a client. Acting as a server may be added later.

## Versioning

Project follows [Semantic Versioning](

## Status

Project in production use in at least one big app :) However, some things are
still not implemented:

* Marshalling variants that contain container types
* Handling message timeouts
* Handling introspection calls and other generic D-Bus methods
* Other transports than TCP
* Other authentication methods than anonymous

# Installation

Add dependency to your `mix.exs`:

defp deps do
  [{:dbux, "~> 1.0.0"}]

# Sample Usage

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"
  <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 name="Bazify">
        <arg name="bar" type="(iiu)" direction="in"/>
        <arg name="bar" type="v" direction="out"/>
      <method name="Mogrify">
        <arg name="bar" type="(iiav)" direction="in"/>
      <signal name="Changed">
        <arg name="new_value" type="b"/>
      <property name="Bar" type="y" access="readwrite"/>
    <node name="child_of_sample_object"/>
    <node name="another_child_of_sample_object"/>

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

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

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

  def handle_up(state) do"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}

  def handle_down(state) do
    {:backoff, 1000, state}

  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}

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

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

  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}

  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}

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

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


And of the accompanying process that can control the connection:

defmodule MyApp.Core do
  def do_the_stuff do
    {:ok, connection} = MyApp.Bus.start_link("")

# Authors

Marcin Lewandowski <>

# Debugging

If you encounter bugs, you may want to compile (not run, compile) the code with
`DBUX_DEBUG` environment variable set to any value.

# Contributing

You are welcome to open pull requests. Tests are mandatory.

# Credits

Project is heavily inspired by [Connection](

# License