DBus ことはじめ

お仕事でプロセス間通信を行う際にDBusを使いました。
とても便利だったので、他の人も使ってほしいですね。
簡単に始めれるようにサンプルプログラムも一緒に残しておきます。

# DBusの基礎
DBusを理解するにあたって、この[PDF](https://bootlin.com/pub/conferences/2016/meetup/dbus/josserand-dbus-meetup.pdf)は、読みやすかったです。
公式のページは小難しく感じますね。とりあえず、URLを載せておきます。
https://dbus.freedesktop.org/doc/dbus-specification.html
https://dbus.freedesktop.org/doc/dbus-tutorial.html

PDFから抜粋して、覚えることを列挙します。

## 覚えること
### その1
- System bus
    - On desktop, a single bus for all users
    - Dedicated to system services
    - is about low-level events such as connection to a network, USB devices, etc
    - On embedded Linux system, this bus is often the only D-Bus type
- Session bus
    - On instance per user session
    - Provide desktop services to user applications

システムバスは、システムに1つのバスが存在し、すべてのユーザがアクセスできて、システム稼働に利用しているみたいですね。
セッションバスは、ユーザごとにバスが存在し、そのユーザのみが利用するみたいですね。

### その2
- Service
    - An application can expose its servcies to all D-Bus users by registering to a bus instance
    - A `service` is a collection of `objects` providing a specific set of features
    - When an application opens a connection to a bus instance, it is assigned a unique name (ie `:1.40`)
    - Can request a more human-readable service name: the **well-known name** (ie `org.ofono`)
- Object
    - Are attached to one service
    - Can be dynamically created or removed
    - Are uniquely identified by an **object path** (ie `/` or `/net/conman/technology/cellular`)
    - Implement one or several interfaces
- Interface
    - Can be compared to a "namespace" in Java
    - Has a unique name resembling Java interface names, using dots (ie `org.ofono.manager`)
    - Contains members: `properties`, `methods` and `signals`

![image.png](https://qiita-image-store.s3.amazonaws.com/0/82600/623b1fa9-92b4-860e-24d2-6dec4ace4ba7.png)

DBusは、 `Service・Object・Interface` を用いてエンドポイントまでのURIを特定します。

まずは、`qdbusviewer` を用いて、既存を参照してみましょう。

```
# 僕の環境
$ cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux buster/sid" 
$ sudo apt install qtbase qdbusviewer
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/82600/b92501f2-4f4b-b98d-d2ba-e47ce1217adb.png)

画像では、以下のように解釈できます。

| section | address |
|---|---|
|service | org.freedesktop.systemd1 |
|object | org/feredesktop/systemd1 |
|interface | org.freedesktop.DBus.Peer |

serviceおよびinterfaceは「.」で区切り
objectは「/」で区切ります。
また、慣習的(?)に、ドメイン名はリバースします。(freedesktop.org → org.freedesktop)

### その3
- Properties (今回使用していないので省きます)
    - Directly accessible fields
    - Can be read / written
    - Can be of different types defined by the D-Bus specification: (割愛)
    - Very convenient standard interface: `org.freedesktop.DBus.Properties`
    - Types are represented by characters: (割愛)
- Methods
    - allow remote procedure calls from one process to another
    - Can be passed one or several parameters
    - Can return values / objects
    - Look like any method you could know from other languages
- Signals
    - Messages / notifications
    - Unidirectional
    - Sent to every clients that are listening to it
    - A client will subscribe to signals to get notifications
- Policy (今回使用していないので省きます)

Client -> Server に対しては Methods を使って呼び出します。
逆に、 Server -> Client に対しては Signals を使って呼び出します。
ただ、Signalは、非同期で Observerパターンのように subscribe しているclient達に対して通知します。

注意として、Methodは同期処理なので重い処理はせず、signalで返しましょう。
(というのを見ましたが、出典元は忘れました...)

その昔、DBusは、同期呼び出しと非同期呼び出しがあって、それぞれMethodとSignalというふうに認識していましたが
全然違いました。

# Python3のDBusライブラリの使い方 例
この章では、 [dbus-python v1.2.8](https://pypi.org/project/dbus-python/)を使用して、ServerとClientを作成し、
MethodおよびSignalを飛ばすコードを残します。
そもそも何故コードを残しているか？というとAPIの使い方が分かりにくかったです。Python力足りないせいですかね。

コードは、gistを置いています。
https://gist.github.com/yuu/c25e95eef7d6ff3fe9f80b14c6b06911

## server side
`@dbus.service.method` と `@dbus.service.signal` でデコレートするだけです。

`method`は、listener登録になり、clientからコール可能になります。
`signal`は、publish登録になり、clientはsubscribe可能になり、関数orメソッド呼び出しを行うことで送信します。

## client side
`method`は、`bus.get_object(service, obj)` 時に、proxyオブジェクトを生成し、メソッドも自動生成されます。
`signal`は、`bus.add_signal_receiver(..)` で handler を登録します。

# まとめ
- 特別な理由がないなら、socketよりDBusを使いませんか
- デコレータまじ便利 (だけど 疲れて説明が適当すぎ)
- お仕事ではServer側をC++で実装して頂いており、XMLから[dbusxx-xml2cpp](http://manpages.ubuntu.com/manpages/bionic/man1/dbusxx-xml2cpp.1.html)でソースコードを生成しています。  
  XMLから生成するのでPythonと違ってズレることがないのはいいですね。