Repository navigation
Folders and files
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Repository files navigation
<!-- Copyright © 2025 - 2026 Chee Bin HOH. All rights reserved. --> # Dmn: Distributed Messaging & Synchronization Dmn is a C++ library for distributed messaging and data synchronization. It provides building blocks for networking, message exchange, concurrency control, and conflict resolution, with an emphasis on delegation and integration into existing applications. On Linux, Dmn also provides `dmn-bluetooth-cosmic`, an optional Rust/libcosmic desktop app for COSMIC with the same workflow (see [COSMIC Bluetooth application](#cosmic-bluetooth-application)), and `dmn-bluetooth-gtk`, an optional GTK 4/libadwaita desktop app for browsing BlueZ devices and explicitly managing Bluetooth connections and ANCS notification monitoring. It is a separate frontend from the `dmn-bluez-cli` discovery tool and `dmn-bluetooth-cli` ANCS monitor. ## Documentation Generated documentation: <https://cheebinhoh.github.io/Dmn/> ## Build, test, and install The default Linux CI workflow uses the Dockerfile to build and test the complete configuration: DMesg messaging, Kafka, all three Bluetooth applications, and their registered tests. A plain CMake configure remains lean: each app option defaults to `OFF`, while enabling an app automatically enables its required ANCS, BlueZ, and D-Bus libraries. CMake fetches missing third-party dependencies when `DMN_ALLOW_DEPENDENCY_FETCH=ON`. ### 1. Complete Linux build and test On Ubuntu 24.04, install the native build and test prerequisites: ```bash sudo apt-get update sudo apt-get install build-essential cmake git pkg-config libicu-dev \ libdbus-1-dev dbus-daemon libgtk-4-dev libadwaita-1-dev \ desktop-file-utils appstream valgrind openjdk-17-jre-headless curl tar \ unzip automake autoconf libtool ``` Configure and build all supported software features. This enables the two Bluetooth CLIs, GTK desktop app, the COSMIC C library, Kafka integration tests, Valgrind test variants, and fault-injection tests; physical-device tests remain opt-in. The optional application flags are the only flags needed to select the apps: their ANCS, BlueZ, and D-Bus dependencies are enabled automatically. ```bash cmake -S . -B build-all -DCMAKE_BUILD_TYPE=Debug \ -DDMN_BUILD_TESTS=ON \ -DDMN_ALLOW_DEPENDENCY_FETCH=ON \ -DBUILD_KAFKA_TEST=ON \ -DENABLE_APP_BLUEZ_DISCOVERY_CLI=ON \ -DENABLE_APP_BLUETOOTH_CLI=ON \ -DENABLE_APP_BLUETOOTH_GTK=ON \ -DENABLE_APP_BLUETOOTH_COSMIC=ON \ -DENABLE_VALGRIND=ON \ -DENABLE_FAULT_INJECTION=ON cmake --build build-all --parallel 2 ./build-all/scripts/run-bookstrap-dmn.sh ctest --test-dir build-all --output-on-failure ./build-all/scripts/run-bookstrap-dmn.sh stop ``` CTest runs every test registered by this configuration, including the GTK headless smoke/metadata tests and the COSMIC engine/C ABI test (the Rust app itself is built by Cargo; see [COSMIC Bluetooth application](#cosmic-bluetooth-application)). Kafka tests need Java and a first-run download; the helper starts a local broker and creates the required topic. The GUI is compiled and tested without opening a desktop window. To build and run the same full Linux configuration in the project's Docker image, see [Docker](#docker). The default Linux CI workflow builds and tests this image. ### 2. Minimal GTK app build and runtime install For the GTK Bluetooth app without Dmn's DMesg/DMesgNet messaging stack (and therefore without Protobuf, librdkafka, or Kafka), install only its required Ubuntu development packages: ```bash sudo apt-get install build-essential cmake git pkg-config libicu-dev \ libdbus-1-dev libgtk-4-dev libadwaita-1-dev ``` Configure with just the GTK app enabled. This minimal app-only build disables tests and dependency fetching; GTK automatically enables its ANCS, BlueZ, and D-Bus libraries. Set the final install prefix at configure time because the desktop launcher and D-Bus activation service contain prefix-dependent paths. ```bash cmake -S . -B build-gtk-app \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX="$HOME/.local" \ -DENABLE_APP_BLUETOOTH_GTK=ON \ -DENABLE_DMN_DMESGNET=OFF \ -DDMN_BUILD_TESTS=OFF \ -DDMN_ALLOW_DEPENDENCY_FETCH=OFF cmake --build build-gtk-app --target dmn-bluetooth-gtk --parallel 2 cmake --install build-gtk-app --component Runtime "$HOME/.local/bin/dmn-bluetooth-gtk" # Hardware-free review: fake devices, no BlueZ, saved devices untouched "$HOME/.local/bin/dmn-bluetooth-gtk" --demo ``` `Runtime` installs the executable and desktop assets. `Development` installs the reusable headers, static libraries, and developer tools; an unqualified `cmake --install build-gtk-app` installs both components. ### 3. Developer build and install For the core library and regular unit tests without optional Bluetooth apps: ```bash cmake -S . -B build-dev -DCMAKE_BUILD_TYPE=Debug \ -DCMAKE_INSTALL_PREFIX="$HOME/.local" cmake --build build-dev --parallel 2 ctest --test-dir build-dev -L dmn --output-on-failure cmake --install build-dev --component Development ``` To run every test registered in this developer configuration, use `ctest --test-dir build-dev --output-on-failure`. Optional applications and test groups are selected at configure time; see [Build options](#build-options). ## Optional build and test configurations The developer workflow runs the regular unit tests. To run every test registered in that build, use: ```bash ctest --test-dir build-dev --output-on-failure ``` The optional configurations below add features or test groups. Use a separate build directory when trying a different set of CMake options. ### Valgrind tests Install Valgrind (on Ubuntu, `sudo apt-get install valgrind`) and enable its test variants at configure time: ```bash cmake -S . -B build-valgrind -DCMAKE_BUILD_TYPE=Debug \ -DENABLE_VALGRIND=ON cmake --build build-valgrind --parallel 2 ctest --test-dir build-valgrind -L 'dmn|valgrind' --output-on-failure ``` This runs regular tests plus their Valgrind variants. The `valgrind` variants are registered only when `ENABLE_VALGRIND=ON`. They cover the library tests that do not link GUI code (including the ANCS, D-Bus and BlueZ GATT suites when enabled); GTK/COSMIC tests and `dmn-test-bluez-device-list` (too slow under Valgrind) are excluded. ### Kafka integration tests Kafka tests are optional and require a broker available at `localhost:9092`. Either start a broker and create the `timer_counter` topic yourself, or enable `BUILD_KAFKA_TEST=ON` and use the staged project helper. For example, with Kafka's command-line tools: ```bash kafka-topics.sh --create --topic timer_counter --bootstrap-server localhost:9092 ``` Then configure, build, and run the Kafka tests: ```bash cmake -S . -B build-kafka -DCMAKE_BUILD_TYPE=Debug \ -DBUILD_KAFKA_TEST=ON cmake --build build-kafka --parallel 2 ./build-kafka/scripts/run-bookstrap-dmn.sh ctest --test-dir build-kafka -L kafka --output-on-failure ./build-kafka/scripts/run-bookstrap-dmn.sh stop ``` The helper downloads and verifies the pinned Kafka distribution when needed; it requires Java and network access on first use. The Docker entrypoint starts Kafka and creates this topic automatically. ### D-Bus extension The optional D-Bus extension provides byte-oriented input/output adapters that send and receive D-Bus signals, plus a typed generic client for method calls, properties, and signal subscriptions. The signal adapters can carry serialized DMesg messages through `Dmn_DMesgNet` or other application payloads using a configured signal routing tuple. The extension is intended for inter-process communication on one host and does not provide cross-host transport. The core `dmn` library does not depend on D-Bus; the extension is built separately as `dmn-dbus` and is disabled by default. `Dmn_DMesgDbus` is the DMesg-specific composition facade for applications that do not need to construct the underlying D-Bus endpoints directly; advanced callers can continue to inject `Dmn_DbusInput` and `Dmn_DbusOutput` into `Dmn_DMesgNet`. When an application links `dmn-dbus`, the target defines `DMN_ENABLE_DBUS`, so `dmn.hpp` also includes the D-Bus configuration, endpoint, and facade headers. Generic clients include `dmn-dbus-client.hpp` and `dmn-dbus-value.hpp` directly; BlueZ clients include `dmn-bluez-client.hpp`. Without the optional target and its compile definitions, the umbrella header does not include the optional D-Bus API. The `dmn-fault-injection.hpp` header is included by `dmn.hpp` only when `ENABLE_FAULT_INJECTION=ON` defines `FIU_ENABLE`; its CMake target-source registration is gated by the same option. On Ubuntu, install the libdbus development files, pkg-config, and daemon used by the private-bus unit test: ```bash sudo apt-get install libdbus-1-dev pkg-config dbus-daemon ``` Enable the extension and run its test (registered under the regular `dmn` CTest label): ```bash cmake -S . -B build-dbus -DCMAKE_BUILD_TYPE=Debug -DENABLE_DBUS=ON cmake --build build-dbus --parallel 2 ctest --test-dir build-dbus -R '^dmn-test-dbus-(io|facade)$' \ --output-on-failure ``` ### BlueZ discovery CLI On Linux, the optional `dmn-bluez-cli` program prints BlueZ's known adapter/device inventory and can explicitly start a scan on one powered adapter. It depends on the Dmn D-Bus extension, but not on GATT or ANCS. Install the D-Bus development package and daemon as above, then configure and build both optional Bluetooth CLIs: ```bash cmake -S . -B build-cli -DCMAKE_BUILD_TYPE=Debug \ -DENABLE_APP_BLUEZ_DISCOVERY_CLI=ON -DENABLE_APP_BLUETOOTH_CLI=ON \ -DENABLE_APP_BLUETOOTH_GTK=OFF \ -DCMAKE_INSTALL_PREFIX="$HOME/.local" cmake --build build-cli --target dmn-bluez-cli dmn-bluetooth-cli \ dmn-test-bluez-device-list --parallel 2 cmake --install build-cli --component Runtime ``` This CLI-only configuration enables both command-line programs and disables the GTK app. `Runtime` is project-wide: it installs runtime files for every application enabled in the configured build. Add `-DENABLE_APP_BLUETOOTH_GTK=ON` to include the GTK app too. To install Dmn's reusable headers and libraries as well, install the `Development` component; an unqualified install includes both components. Add the configured local prefix to `PATH` and view the manual pages with: ```bash export PATH="$HOME/.local/bin:$PATH" man -M "$HOME/.local/share/man" dmn-bluez-cli man -M "$HOME/.local/share/man" dmn-bluetooth-cli ``` Print the current known-device inventory as CSV without starting discovery: ```bash ./build-cli/src/app/dmn-bluez-cli ``` The CSV includes the adapter address and path needed to select a scan target. Start an explicit scan with either selector; if exactly one powered adapter exists, `--adapter` may be omitted: ```bash ./build-cli/src/app/dmn-bluez-cli --discovery \ --adapter 'B8:F7:75:BF:F3:C3' ``` The CLI prints initial known devices, then live add/change/remove rows until Ctrl-C or SIGTERM. It stops only the discovery session it started. It does not pair, connect, change trust, or power an adapter. Scanning requires a working BlueZ system service and local system-bus policy that permits the discovery calls; the CLI does not fall back to the session bus. For argument syntax, run `./build-cli/src/app/dmn-bluez-cli --help`. The private-bus integration coverage can be run with: ```bash ctest --test-dir build-cli -R '^dmn-test-bluez-device-list$' \ --output-on-failure ``` ### Shared Bluetooth engine `dmn-bluetooth-cli`, `dmn-bluetooth-gtk` and `dmn-bluetooth-cosmic` all drive the same GUI-independent engine (`dmn::gui::Dmn_Engine`, static library `dmn-bluetooth-engine`, sources in `src/app/engine` and `include/app/engine`). It has no GTK or GLib dependency and is built automatically whenever any of `ENABLE_APP_BLUETOOTH_CLI`, `ENABLE_APP_BLUETOOTH_GTK` or `ENABLE_APP_BLUETOOTH_COSMIC` is on, so each app can be built on its own or together with the others. The engine has two backends: the BlueZ backend (real hardware over BlueZ/ANCS) and a demo backend (synthetic phones, no hardware, used by `--demo`). Only the GTK and COSMIC apps need GLib, through `dmn-bluetooth-gui-core`; the CLI does not. See the header comment in `include/app/engine/dmn-engine.hpp` for the architecture. ### Bluetooth ANCS monitor CLI The optional `dmn-bluetooth-cli` command pairs/connects one selected device as needed and monitors its ANCS notifications through the shared engine: ```bash ./build-cli/src/app/dmn-bluetooth-cli monitor "iPhone Genghis" ``` See `man dmn-bluetooth-cli` for its options, output, failure handling, and recovery guidance. This CLI requires a working BlueZ system service and does not provide a graphical interface. ### GTK Bluetooth application On Linux desktops, the optional `dmn-bluetooth-gtk` app provides a graphical interface for browsing BlueZ devices, saving a device selection, connecting and disconnecting, and explicitly starting or stopping ANCS monitoring. The GTK application and CLI are separate frontends to the same shared engine; enabling the GTK build does not build or replace the CLI. Optional desktop alerts use GNotification. All Bluetooth behavior comes from the shared engine that the CLI and COSMIC app also use; the GTK code only renders it. The window has a left device panel (search, **Selected only**, sorting, and the "Previous selected devices" and "Nearby devices" groups) and a notifications panel. Run `dmn-bluetooth-gtk --demo` to try it with fake devices and no Bluetooth hardware; demo mode never touches saved devices. The app never connects automatically. **Start monitoring** is an explicit choice saved per device, so the app can restore that intent on later launches. It starts the monitor only after the device is saved, paired, and BlueZ confirms it is connected; if disconnected, it waits for you to connect it. **Stop monitoring** clears the saved intent. Disconnecting or exiting stops the live monitor but preserves the intent, so monitoring can resume after reconnection or relaunch. The newest-first event feed contains only notifications received while the app process is running; it is not a persistent notification archive or a desktop notification-history reader. Search and device, event-kind, and category filters compose; each notification has a Details button. A sidebar toggle at the left edge of the header bar opens and closes the device panel; its visibility and the Selected only setting are remembered across launches. The app scans for its whole lifetime, so there are no Scan buttons. The feed is capped at 1,000 in-memory events, with older-event eviction reported in the interface. Hovering over notification text shows its full value wrapped to the available feed width. The GTK app requires a running BlueZ system service and a graphical desktop session. GTK 4 4.14 or newer and libadwaita 1.5 or newer are required. Follow the [minimal GTK app build](#2-minimal-gtk-app-build-and-runtime-install) above to build and install this app. The GTK option enables the required ANCS, BlueZ, and D-Bus libraries but remains off in default builds. For the implemented UI, remaining features, and current design details, see the [GTK application specification](docs/specs/dmn-bluetooth-gtk-app-spec.md) and its [UI storyboard](docs/specs/dmn-bluetooth-gtk-ui-storyboard.md). ### COSMIC Bluetooth application `dmn-bluetooth-cosmic` is a native COSMIC (Rust, libcosmic) frontend with the same workflow as the GTK app: browse BlueZ devices, save a selection, connect, disconnect, and explicitly start or stop ANCS monitoring. It reuses Dmn's C++ BlueZ/ANCS/D-Bus code through a C library (`dmn-bluetooth-cabi`) and a JSON-protocol engine; the UI contains no Bluetooth logic. Settings are stored in `$XDG_CONFIG_HOME/dmn-bluetooth-cosmic/settings.json`. The device panel can be hidden with the toggle in the header bar. The list has two groups: "Previous selected devices" (saved selection) and "Nearby devices" (nearby or unselected); a device changes group only when its selection is saved or discarded. The device list and notification feed scroll independently. The app scans for devices for as long as it runs and the list updates as results arrive, so there are no Scan or Refresh buttons. The toolbar has a search box (half the device panel wide, always visible), the Selected only checkbox, and the Save and Discard buttons; the header-bar menu has the Desktop alerts checkbox (on by default) and About; the search box filters both groups by any part of a device (name, address, status). Notification titles and messages can be highlighted and copied (right-click Copy / Select All), and hovering a notification shows its full text. Cargo is the build entry point. Its build script (`dmn-build.rs`) runs CMake with `-DENABLE_APP_BLUETOOTH_COSMIC=ON`, so no manual CMake step is needed: ```bash sudo apt install build-essential cmake pkg-config libdbus-1-dev \ libfontconfig-dev libfreetype-dev libexpat1-dev libwayland-dev \ libxkbcommon-dev curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh cd src/app/gui/cosmic cargo build --release --locked cargo test --workspace --locked # no Bluetooth hardware needed cargo fmt --all --check ./target/release/dmn-bluetooth-cosmic --demo # fake devices, no BlueZ ``` The binary loads `libdmn-bluetooth-cabi.so` through an rpath emitted by the build script; when copying the binary elsewhere, copy the library next to it and set the rpath to `$ORIGIN` (for example with `patchelf`). Desktop entry, AppStream metadata, and icons are in `src/app/gui/cosmic/data/`. Optional environment variables: `DMN_SOURCE_DIR`, `DMN_CMAKE_GENERATOR`, and `DMN_CMAKE_ARGS`. Running CMake directly with `-DENABLE_APP_BLUETOOTH_COSMIC=ON` builds only the C library and its tests (`ctest -L dmn-gui`); the option is off by default and the default build never requires Rust. The Docker image builds and tests the app; pass `--build-arg ENABLE_APP_BLUETOOTH_COSMIC=OFF` to skip it. See the [COSMIC specification](docs/specs/dmn-bluetooth-cosmic-spec.md). ### Fault-injection tests Fault-injection support is optional and disabled by default. Enabling it links libfiu into the fault-injection build. CMake uses an installed libfiu package found through pkg-config when available; otherwise it fetches and builds libfiu 1.2 and its `fiu-run` launcher. ```bash cmake -S . -B build-fi -DCMAKE_BUILD_TYPE=Debug \ -DENABLE_FAULT_INJECTION=ON cmake --build build-fi --target fault-injection-tests --parallel 2 ctest --test-dir build-fi -L fault-injection --output-on-failure ``` Fault-injection tests are GoogleTest executables invoked by CTest through `fiu-run`. They use the separate `fault-injection` label and are not included in the regular `dmn` test group. To run one test by name: ```bash ctest --test-dir build-fi -R '^dmn-test-fi-timer-thread-start-failure$' \ --output-on-failure ``` The recurring-reschedule failure test can be run individually with: ```bash ctest --test-dir build-fi -R '^dmn-test-fi-timer-reschedule-failure$' \ --output-on-failure ``` ### Docker From the repository root, build the image: ```bash docker build -t dmn . ``` Start it interactively with its normal entrypoint: ```bash docker run -it --rm dmn ``` The image installs GTK 4/libadwaita development packages and the Rust toolchain, enables all three applications plus Kafka, Valgrind, and fault-injection tests, and builds all configured targets. On startup, the entrypoint bootstraps Kafka and runs the regular, CLI, GTK, COSMIC (`cargo test`), Kafka, Valgrind, and fault-injection tests. These tests do not launch a graphical window; showing the app itself requires forwarding a host graphical session. If tests pass, the container opens a Bash prompt; if they fail, it exits. The run command removes the container on exit because it uses `--rm`. The default Linux CI workflow builds and runs this Docker image. To enter a shell immediately without starting Kafka or running tests, bypass the entrypoint: ```bash docker run -it --rm --entrypoint /bin/bash dmn ``` The Docker build leaves assertions enabled. To build with Docker Buildx and load the image into the local Docker engine: ```bash docker buildx build -t dmn:latest --load . ``` Remove the image when it is no longer needed: ```bash docker rmi dmn ``` ### Build options | Option | Default | Purpose | | --- | --- | --- | | `BUILD_NDEBUG` | `OFF` | Define `NDEBUG` for the build. | | `BUILD_KAFKA_TEST` | `OFF` | Build the additional Kafka integration tests when `ENABLE_DMN_DMESGNET` is also `ON`; otherwise they are skipped with a CMake status message. | | `ENABLE_DMN_DMESGNET` | `ON` | Build the Protobuf-based DMesg/DMesgNet messaging stack and its Kafka transport; requires Protobuf and librdkafka. Set `OFF` for applications that do not use DMesg messaging, such as the GTK Bluetooth app. DMesg, DMesgNet, and Kafka tests are registered only when this option is `ON`; other tests remain available. | | `ENABLE_DBUS` | `OFF` | Build the optional D-Bus signal I/O extension and generic D-Bus client. Requires libdbus development files and pkg-config; private-bus tests require `dbus-daemon`. | | `ENABLE_BLUEZ` | `OFF` | Build the Linux BlueZ library; automatically enables its `ENABLE_DBUS` dependency. | | `ENABLE_ANCS` | `OFF` | Build the backend-neutral ANCS protocol library. | | `ENABLE_APP_BLUEZ_DISCOVERY_CLI` | `OFF` | Build and install `dmn-bluez-cli`; automatically enables `ENABLE_BLUEZ` and `ENABLE_DBUS`. | | `ENABLE_APP_BLUETOOTH_CLI` | `OFF` | Build and install `dmn-bluetooth-cli`; automatically enables `ENABLE_ANCS`, `ENABLE_BLUEZ`, and `ENABLE_DBUS`. | | `ENABLE_APP_BLUETOOTH_GTK` | `OFF` | Build and install the Linux GTK 4/libadwaita `dmn-bluetooth-gtk` desktop app; automatically enables `ENABLE_ANCS`, `ENABLE_BLUEZ`, and `ENABLE_DBUS`. Requires GTK 4 4.14+, libadwaita 1.5+, and GLib schema tools. | | `ENABLE_APP_BLUETOOTH_COSMIC` | `OFF` | Build the `dmn-bluetooth-cabi` C library and tests used by the Rust COSMIC app; automatically enables `ENABLE_ANCS`, `ENABLE_BLUEZ`, and `ENABLE_DBUS`. Normally driven by Cargo, not set by hand. | | `ENABLE_ANCS_HARDWARE_TESTS` | `OFF` | Register the opt-in physical-iPhone test; requires `ENABLE_APP_BLUETOOTH_CLI=ON`. | | `ENABLE_VALGRIND` | `OFF` | Register Valgrind test variants; requires Valgrind. | | `ENABLE_FAULT_INJECTION` | `OFF` | Build libfiu support and register tests run through `fiu-run`. | The options are cached in the build directory. Reconfigure that directory with the desired options before building. The `dmn` CTest label selects the regular unit tests; `kafka`, `fault-injection`, and `valgrind` select their respective optional test groups. `ENABLE_DMN_DMESGNET` controls the complete DMesg messaging layer: local `Dmn_DMesg`, `Dmn_DMesgNet`, the Kafka adapter and examples, and the DMesgNet-over-D-Bus facade. When enabled, CMake discovers or fetches both Protobuf and librdkafka according to `DMN_ALLOW_DEPENDENCY_FETCH`. Generic D-Bus I/O, BlueZ, and the GTK Bluetooth app are independent of this layer. For a GTK-only Flatpak build, explicitly pass `-DENABLE_DMN_DMESGNET=OFF` in the module's `config-opts`: this option defaults to `ON`, and disabling dependency fetching alone does not disable the feature or remove its Protobuf/librdkafka requirements. When `DMN_BUILD_TESTS=ON`, the DMesg/DMesgNet/Kafka-specific tests are added only if `ENABLE_DMN_DMESGNET=ON`; other tests can run with the messaging stack disabled. The minimal GTK application-only build above disables this stack, so it does not discover or fetch Protobuf or librdkafka. For the full Linux configuration, use the [complete build and test](#1-complete-linux-build-and-test) instructions. BlueZ tests use a private bus and do not require a physical adapter; physical-iPhone tests remain opt-in.