You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 09:02:49