godbus

How can I receive a dbus message properly?


I wrote the following golang program as main.go to learn dbus in Go :

package main

import (
    "fmt"
    "github.com/godbus/dbus/v5"
    "time"
)

// Listener function to listen for D-Bus signals
func runListener() {
    // Create a new D-Bus connection for the listener
    conn, err := dbus.SessionBus()
    if err != nil {
        fmt.Println("Listener: Failed to connect to session bus:", err)
        return
    }
    defer conn.Close()

    // Request a unique name for the listener
    busName := "org.example.Listener"
    if _, reqErr := conn.RequestName(busName, dbus.NameFlagDoNotQueue); reqErr != nil {
        fmt.Println("Listener: Failed to request name:", reqErr)
        return
    }
    fmt.Println("Listener: Listening for messages on", busName)

    // Add a match rule for the specific signal
    err = conn.AddMatchSignal(
        dbus.WithMatchInterface("org.example.ListenerInterface"), // Match interface
        dbus.WithMatchMember("Message"),                          // Match signal member
    )
    if err != nil {
        fmt.Println("Listener: Failed to add match rule:", err)
        return
    }

    // Create a channel to receive signals
    c := make(chan *dbus.Signal, 10)
    conn.Signal(c)

    // Listen for messages
    fmt.Println("Listener: Waiting for D-Bus messages...")
    for signal := range c {
        fmt.Printf("Listener: Received message: %v\n", signal.Body)
    }
}

// Sender function to send a D-Bus signal
func runSender() {
    // Wait briefly to ensure the listener is ready
    time.Sleep(2 * time.Second)

    // Create a new D-Bus connection for the sender
    conn, err := dbus.SessionBus()
    if err != nil {
        fmt.Println("Sender: Failed to connect to session bus:", err)
        return
    }
    defer conn.Close()

    // Define the signal details
    objectPath := dbus.ObjectPath("/org/example/Listener") // Convert string to ObjectPath
    interfaceName := "org.example.ListenerInterface"
    signalName := interfaceName + ".Message"

    // Emit the signal
    fmt.Println("Sender: Sending message to listener...")
    err = conn.Emit(objectPath, signalName, "Hello from the sender!")
    if err != nil {
        fmt.Println("Sender: Failed to send message:", err)
        return
    }

    fmt.Println("Sender: Message sent successfully!")
}

func main() {
    // Run the listener and sender as separate goroutines
    go runListener()
    go runSender()

    // Prevent the program from exiting immediately
    select {}
}

The problem I am having is that the program successfully outputs:

Listener: Listening for messages on org.example.Listener Listener:
Waiting for D-Bus messages... Sender: Sending message to listener...
Sender: Message sent successfully!

But notice that there is no "Listener: Received message" output...

I have also tried to do this using two separate main.go files in two separate project directories (Listener, Sender), but I was unable to properly configure GoLand to run both main.go files at the same time, as I got an error from GoLand: package dbus_messenger is not in std (/usr/lib/golang/src/dbus_messenger) .


Solution

  • Just change your code to use ConnectSessionBus.

    conn, err := dbus.ConnectSessionBus()
    

    SessionBus uses a shared connection, which may interfere with message reception.

    ConnectSessionBus will create separate connections to the Listener and the Sender.

    SessionBus returns a shared connection to the session bus, connecting to it if not already done.

    With this change, your code works correctly.

    go run main.go 
    Listener: Listening for messages on org.example.Listener
    Listener: Waiting for D-Bus messages...
    Sender: Sending message to listener...
    Sender: Message sent successfully!
    Listener: Received message: [Hello from the sender!]
    

    It also works using dbus-send

    dbus-send --session \
      --dest=org.example.Listener \
      --type=signal \
      /org/example/Listener \
      org.example.ListenerInterface.Message \
      string:"Hello from dbus-send!"
    

    Wich produces:

    ...
    Listener: Received message: [Hello from dbus-send!]