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)
.
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!]