使用godbus实现DBus通知服务器时Notify方法无法识别
问题:godbus开发DBus通知服务器无法调用接口方法
我正在尝试使用godbus开发一个DBus通知服务器,遵循freedesktop通知规范实现,同时参考了godbus仓库中的_example/server.go示例代码。
服务器代码
package main import ( "fmt" "os" "github.com/godbus/dbus/v5" "github.com/godbus/dbus/v5/introspect" ) const xml = ` <node> <interface name="org.freedesktop.Notifications"> <method name="Notify"> <arg direction="in" type="s"/> <arg direction="in" type="u"/> <arg direction="in" type="s"/> <arg direction="in" type="s"/> <arg direction="in" type="s"/> <arg direction="in" type="as"/> <arg direction="in" type="a{sv}"/> <arg direction="in" type="i"/> <arg direction="out" type="u"/> </method> <method name="GetCapabilities"> <arg direction="out" type="as"/> </method> <method name="GetServerInformation"> <arg direction="out" type="s"/> <arg direction="out" type="s"/> <arg direction="out" type="s"/> <arg direction="out" type="s"/> </method> <method name="CloseNotification"> <arg direction="in" type="u"/> </method> <signal name="NotificationClosed"> <arg type="u" name="id"/> <arg type="u" name="reason"/> </signal> </interface>` + introspect.IntrospectDataString + `</node> ` type NotificationServer struct { } func (s *NotificationServer) Notify(appName string, replacesID uint32, appIcon string, summary string, body string, actions []string, hints map[string]dbus.Variant, expireTimeout int32) (uint32, *dbus.Error) { fmt.Printf("New notification: %s\n", body) return 0, nil } func (s *NotificationServer) GetCapabilities() ([]string, *dbus.Error) { return []string{"action-icons", "actions", "body", "body-hyperlinks", "body-images", "body-markup", "icon-multi", "icon-static", "persistence", "sound"}, nil } func (s *NotificationServer) GetServerInformation() (string, string, string, string, *dbus.Error) { return "antarctica", "antarctica.com", "1.0", "1.2", nil } func (s *NotificationServer) CloseNotification(id uint32) *dbus.Error { s.NotificationClosed(id, 0) return nil } func (s *NotificationServer) NotificationClosed(id, reason uint32) { } func main() { conn, err := dbus.ConnectSessionBus() if err != nil { panic(err) } defer conn.Close() reply, err := conn.RequestName("com.antarctica.notification", dbus.NameFlagDoNotQueue) if err != nil { panic(err) } if reply != dbus.RequestNameReplyPrimaryOwner { fmt.Fprintln(os.Stderr, "name already taken") os.Exit(1) } server := NotificationServer{} err = conn.Export(server,"/org/freedesktop/Notifications","org.freedesktop.Notifications") if err != nil { panic(err) } conn.Export(introspect.Introspectable(xml), "/org/freedesktop/Notifications", "org.freedesktop.DBus.Introspectable") fmt.Println("Listening on com.antarctica.notification / /com/antarctica/notification ...") select {} }
当前问题
客户端可以正常获取到introspect XML:
$ gdbus introspect --session --dest com.antarctica.notification --object-path /org/freedesktop/Notifications --xml > returns xml
但无法调用我在服务器代码中实现的org.freedesktop.Notifications接口方法,例如调用Notify时会报错:
$ dbus-send --session --print-reply=literal --dest=com.antarctica.notification /org/freedesktop/Notifications org.freedesktop.Notifications.Notify > Error org.freedesktop.DBus.Error.UnknownMethod: Unknown / invalid method 'Notify'
在qdbusviewer中执行任何方法时,也提示“Unable to find method x on path /org/freedesktop/Notifications in interface org.freedesktop.Notifications”。
已尝试的操作
- 确认DBus服务正在运行
- 确认我的服务器程序正在运行
- 重启DBus服务及电脑
- 怀疑NotificationServer实例未被正确导出,但不清楚原因
解决方案
问题核心是导出对象时传递的是值而非指针。godbus要求导出的对象必须是指针类型,才能匹配你代码中定义的*NotificationServer类型方法接收者。
1. 修复对象导出逻辑
修改main函数中的导出代码:
// 原代码 server := NotificationServer{} err = conn.Export(server,"/org/freedesktop/Notifications","org.freedesktop.Notifications") // 修改为 server := &NotificationServer{} err = conn.Export(server,"/org/freedesktop/Notifications","org.freedesktop.Notifications")
2. 修复信号发送逻辑
当前的NotificationClosed只是普通函数,无法向DBus总线发送信号,需要通过DBus连接发送信号:
// 修改NotificationServer结构体,添加DBus连接字段 type NotificationServer struct { conn *dbus.Conn } // 修改CloseNotification方法 func (s *NotificationServer) CloseNotification(id uint32) *dbus.Error { err := s.conn.Emit( "/org/freedesktop/Notifications", "org.freedesktop.Notifications.NotificationClosed", id, 0, ) if err != nil { return dbus.NewError("org.freedesktop.DBus.Error.Failed", []interface{}{err.Error()}) } return nil } // main中初始化时传递DBus连接 server := &NotificationServer{conn: conn}
修改完成后,接口方法即可正常调用,信号也能正确发送。
内容的提问来源于stack exchange,提问作者Schrodinger's Neko
相关产品推荐
相关产品推荐

