swift-dbus

0.8.0

Swift wrapper for D-Bus on Linux (Swift 6.2)
tdelhaise/swift-dbus

What's New

2025-11-09T11:27:03Z

Highlights

  • Typed return decoding via DBusReturnDecodable + DBusTuple helpers
  • Property cache + DBusPropertyConvertible typed getters/setters
  • Typed signal streaming via proxy.signals(NameOwnerChangedSignal.self) and README examples
  • CI fixes: ensure workflows remain green after reruns

swift-dbus

CI (Linux)

Squelette SPM minimal pour un binding Swift de D-Bus sous Linux. Cible : Ubuntu 24.04.3 + Swift 6.2 (installé via Swiftly).

Pré-requis (Ubuntu 24.04.3)

# Swift via Swiftly (https://swiftlang.github.io/swiftly/)
# Assurez-vous d'avoir Swift 6.2 actif dans votre shell.
swift --version

# Headers/SDK D-Bus
sudo apt update
sudo apt install -y libdbus-1-dev

Construction

git clone <votre-repo-ou-ce-dossier> swift-dbus
cd swift-dbus

# Construire la librairie et l'exécutable d'exemple
swift build

# Lancer l'exemple
swift run swift-dbus-examples

Vous devriez voir la version de libdbus ainsi qu'un indicateur de disponibilité.

Tests & Qualité

  • bash scripts/test.sh – lance swift test dans un dbus-run-session dédié (utile sur CI/sandbox).
  • bash scripts/format.sh – applique swift-format puis swiftlint --fix && lint --strict.

Les tests d’intégration ouvrent un vrai bus session temporaire, requièrent donc libdbus-1 et dbus-run-session.

Structure

  • Package.swift – Dépendance système vers libdbus-1 via un target .systemLibrary (CDbus).
  • Sources/CDbus – Module système SPM avec module.modulemap pointant vers shim.h qui inclut <dbus/dbus.h>.
  • Sources/SwiftDBus – API Swift de plus haut niveau (placeholder à étendre).
  • Sources/swift-dbus-examples – Petit binaire de démonstration.
  • Tests/SwiftDBusTests – Tests unitaires minimalistes.

Aperçu API

Connexion & appels bus

let connection = try DBusConnection(bus: .session)

_ = try connection.requestName("org.example.App")
let id = try connection.getBusId()
let machineId = try connection.getMachineId()
let names = try connection.listNames()
let owner = try connection.getNameOwner("org.freedesktop.DBus")
try connection.pingPeer()

Appels multi-arguments & retour typé

let proxy = DBusProxy(
    connection: connection,
    destination: "org.freedesktop.DBus",
    path: "/org/freedesktop/DBus",
    interface: "org.freedesktop.DBus"
)

let status: UInt32 = try proxy.callExpectingSingle(
    "RequestName",
    typedArguments: DBusArguments("org.example.App", UInt32(0))
)

struct ListNamesResponse: DBusReturnDecodable {
    let names: [String]

    init(from decoder: inout DBusDecoder) throws {
        names = try decoder.next([String].self)
    }
}

let namesResult: ListNamesResponse = try proxy.callExpecting(
    "ListNames",
    as: ListNamesResponse.self
)
print("Bus exposes \(namesResult.names.count) names")

// Helper DBusArguments(...) construit la liste d'arguments (ici String + UInt32)

Pour les méthodes qui renvoient plusieurs valeurs, utilisez les helper DBusTuple2 / DBusTuple3 ou faites conformer votre propre struct à DBusReturnDecodable.

Écouter un signal typé

let rule = DBusMatchRule.signal(
    interface: "org.freedesktop.DBus",
    member: "NameOwnerChanged",
    arg0: "org.example.App"
)

for await signal in try connection.signals(matching: rule) {
    print("Signal from \(signal.sender ?? "-"): \(signal.args)")
}

L’API signals(matching:) inscrit automatiquement la règle côté bus (AddMatch) et la retire (RemoveMatch) à la fin du flux.

Proxy haut niveau (WIP M4)

let proxy = DBusProxy(
    connection: connection,
    destination: "org.freedesktop.DBus",
    path: "/org/freedesktop/DBus",
    interface: "org.freedesktop.DBus"
)

let busId = try proxy.callExpectingFirstString("GetId")

for await change in try proxy.signals(member: "NameOwnerChanged", arg0: "org.example.App") {
    print("Change: \(change.args)")
}

Propriétés via org.freedesktop.DBus.Properties

let features: [String] = try proxy.getProperty("Features")
let all = try proxy.getAllProperties()
print(all["Features"] ?? .unsupported(0))

let cache = DBusPropertyCache()
let cachedFeatures: [String] = try proxy.getProperty("Features", cache: cache)
let refreshedFeatures: [String] = try proxy.getProperty(
    "Features",
    cache: cache,
    refreshCache: true
)
print("Cached features \(cachedFeatures), live value \(refreshedFeatures)")

Signaux typés via proxy

struct NameOwnerChangedSignal: DBusSignalPayload {
    static let member = "NameOwnerChanged"

    let name: String
    let oldOwner: String
    let newOwner: String

    init(from decoder: inout DBusDecoder) throws {
        name = try decoder.next()
        oldOwner = try decoder.next()
        newOwner = try decoder.next()
    }
}

let typedStream = try proxy.signals(NameOwnerChangedSignal.self, arg0: "org.example.App")

for await signal in typedStream {
    print("\(signal.name) moved from \(signal.oldOwner) -> \(signal.newOwner)")
}

CI (Ubuntu)

Un workflow GitHub Actions est fourni pour builder et tester sur ubuntu-24.04 avec Swift 6.2.

🧭 Roadmap

Le projet swift-dbus vise à offrir une couverture complète et moderne de l’API D-Bus en Swift (6.2+), pour Linux.

La feuille de route détaillant les différentes étapes (wrappers bas niveau, API Swift, proxies, export d’objets, génération de code, etc.) est disponible ici :

👉 Consulter la ROADMAP →

Tu y trouveras la progression prévue, les milestones et les futurs objectifs de compatibilité et d’outillage.

Description

  • Swift Tools 6.0.0
View More Packages from this Author

Dependencies

  • None
Last updated: Sun Apr 12 2026 10:11:41 GMT-0900 (Hawaii-Aleutian Daylight Time)