A Swift 6 D-Bus protocol implementation with SwiftNIO and modern Swift concurrency support.
DBUS is a Swift package that provides a pure Swift implementation of the D-Bus protocol built on SwiftNIO. D-Bus is a message bus system used for interprocess communication on Linux systems. This library enables Swift applications to communicate with system services and other applications using modern Swift concurrency features.
- Pure Swift Implementation: No C library dependencies, built entirely on SwiftNIO
 - Modern Swift 6 API: Full async/await support with Swift concurrency
 - Complete D-Bus Protocol: Message parsing, authentication, and type system
 - Type-Safe Interface: Swift types mapped to D-Bus types with compile-time safety
 - SwiftNIO Foundation: High-performance networking with proper resource management
 - Authentication Support: ANONYMOUS and EXTERNAL authentication methods
 - Comprehensive Testing: Full test coverage with real-world scenarios
 - Well Documented: DocC comments and extensive usage examples
 
- Swift 6.0 or later
 
DBUS is designed specifically for Linux environments where D-Bus is natively available. D-Bus is a core component of Linux desktop environments and is not natively supported on other platforms.
For development and testing on non-Linux platforms, a Docker environment is provided:
# Run tests in Docker
./run-tests-in-docker.shThis will build a Docker container with all necessary dependencies and run the test suite in a Linux environment.
Add the following to your Package.swift file:
dependencies: [
    .package(url: "https://github.com/edgeengineer/dbus.git", from: "0.1.0")
]Then add the dependency to your target:
.target(
    name: "YourTarget",
    dependencies: ["DBUS"]),import DBUS
try await DBusClient.withConnection(
    to: SocketAddress(unixDomainSocketPath: "/var/run/dbus/system_bus_socket"),
    auth: .external(userID: getuid())
) { connection in
    // You've got a DBUS connection!
}try await DBusClient.withConnection(
    to: SocketAddress(unixDomainSocketPath: "/var/run/dbus/system_bus_socket"),
    auth: .external(userID: getuid())
) { connection in
    // Send a method call and get reply
    let reply = try await connection.send(DBusRequest.createMethodCall(
        destination: "org.freedesktop.DBus",
        path: "/org/freedesktop/DBus", 
        interface: "org.freedesktop.DBus",
        method: "ListNames"
    ))
    
    // Handle the reply
    if let reply = reply {
        print("Received reply: \(reply)")
    }
}try await DBusClient.withConnection(
    to: SocketAddress(unixDomainSocketPath: "/var/run/dbus/session_bus_socket"),
    auth: .external(userID: getuid())
) { connection in
    // Create and send a signal
    let signal = DBusRequest.createSignal(
        path: "/org/example/Path",
        interface: "org.example.Interface", 
        name: "ExampleSignal"
    )
    try await connection.send(signal)
}// D-Bus types are represented as DBusValue
let stringValue = DBusValue.string("Hello")
let intValue = DBusValue.uint32(42)
let arrayValue = DBusValue.array([stringValue, intValue])
// Create requests with typed arguments
let request = DBusRequest.createMethodCall(
    destination: "org.freedesktop.DBus",
    path: "/org/freedesktop/DBus",
    interface: "org.freedesktop.DBus", 
    method: "GetConnectionUnixProcessID",
    body: [DBusValue.string("org.freedesktop.DBus")]
)try await DBusClient.withConnection(
    to: SocketAddress(unixDomainSocketPath: "/var/run/dbus/system_bus_socket"),
    auth: .external(userID: "0") // root user
) { connection in
    // Send request
    let reply = try await connection.send(DBusRequest.createMethodCall(
        destination: "org.freedesktop.DBus",
        path: "/org/freedesktop/DBus",
        interface: "org.freedesktop.DBus",
        method: "Hello"
    ))
    guard 
        let helloReply = reply,
        case .methodReturn = helloReply.messageType
    else {
        print("No reply from Hello method call")
        return
    }
    print("Received reply from Hello method call \(helloReply)")
}DBUS logs to swift-log to help with debugging and understanding internal operations. You can provide your own logger implementation or use the standard adapters. We'll log to .debug and .trace levels in compliant with established standards.
DBUS maps D-Bus types to Swift types as follows:
| D-Bus Type | Signature | Swift Type | 
|---|---|---|
| Byte | y | UInt8 | 
| Boolean | b | Bool | 
| Int16 | n | Int16 | 
| UInt16 | q | UInt16 | 
| Int32 | i | Int32 | 
| UInt32 | u | UInt32 | 
| Int64 | x | Int64 | 
| UInt64 | t | UInt64 | 
| Double | d | Double | 
| String | s | String | 
| Object Path | o | String | 
| Signature | g | String | 
| Array | a | [DBusValue] | 
| Variant | v | DBusVariant | 
While DBUS provides a solid foundation for D-Bus communication, some features are not yet implemented:
- Signal Subscription: No built-in signal filtering and callback registration
 - Service Registration: Cannot expose Swift objects as D-Bus services
 - Introspection Support: No XML parsing or automatic proxy generation
 - Connection Pooling: Limited to single-use connections
 - Standard Interfaces: No built-in support for 
org.freedesktop.DBus.Properties,org.freedesktop.DBus.Introspectable, etc. - Bus Name Management: No automatic name reservation or ownership monitoring
 - Property Interface: Basic property access only, no caching or change notifications
 - High-Level API: Currently requires low-level message construction
 
- Empty arrays default to byte array type signature regardless of intended type
 - Complex nested dictionary structures may have parsing edge cases
 - Message serial number overflow not handled
 - Authentication handler has potential race conditions
 
Future releases may include:
- Higher-level convenience APIs
 - Signal subscription and routing
 - Service registration capabilities
 - Introspection and proxy generation
 - Connection management improvements
 
DBUS includes comprehensive tests using Swift Testing. The tests are designed to run on Linux and include real-world scenarios with NetworkManager integration.
swift testThis project is available under the Apache License 2.0. See the LICENSE file for more info.