Golang中如何使用godbus进行内省
Golang中如何使用godbus进行内省 大家好,
我又回来研究DBus了,但由于缺乏现实世界中的示例,我遇到了一些麻烦。
当我让自省功能工作时,我只能让一个方法正常工作(如果你加载另一个方法,它会覆盖第一个。请参考 _examples 下的 server.go)。另一方面,我可以让所有方法都正常工作,但自省功能却不行。
以下是我目前的代码…
type server struct {
id int
}
var dbmethods []introspect.Method
// Foo : 测试导出
func (server) Foo() (string, *dbus.Error) {
return "Bar!", nil
}
// Ping : 测试
func (server) Ping() (string, *dbus.Error) {
return "Pong!", nil
}
func (dbo dbusobj) registerServerMethods() error {
// 注册与服务器关联的所有方法。
var methods []reflect.Method
serverType := reflect.TypeOf(server{})
for i := 0; i < serverType.NumMethod(); i++ {
servmethod := serverType.Method(i)
methods = append(methods, servmethod)
fmt.Println("Server Method:", servmethod.Name)
fmt.Println("Server Method:", servmethod)
methNames[servmethod.Name] = strings.ToLower(servmethod.Name)
err := dbo.Conn.ExportWithMap(server{}, methNames, dbo.Path, dbo.Iface)
if err != nil {
return err
}
// 尝试自省。
// node := &introspect.Node{}
// node.Name = dbo.Iface
// iface := &introspect.Interface{}
// iface.Name = dbo.Iface
// dbmethods = append(dbmethods, introspect.Methods(servmethod)[0])
// iface.Methods = dbmethods
// node.Interfaces = append(node.Interfaces, *iface)
// dbusXMLinsp := introspect.NewIntrospectable(node)
// fmt.Println("Method debug ...") // 调试
// printXML(fmt.Sprint(dbusXMLinsp)) // 调试
// err = dbo.Conn.Export(dbusXMLinsp, dbo.Path, "org.freedesktop.DBus.Introspectable")
// if err != nil {
// return err
// }
}
return nil
}
注释掉的部分是我正在尝试使其工作的部分。有什么建议吗?
更多关于Golang中如何使用godbus进行内省的实战教程也可以访问 https://www.itying.com/category-94-b0.html
有人吗?我不想硬编码内省(就像我上次做的那样)。
更多关于Golang中如何使用godbus进行内省的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
你好 Eric,
感谢你的回复。查看这些变更,它们似乎与第183号问题有关(这是我提交并随后关闭的)。在创建系统总线的私有实例(用于测试)时,我给 Southworth 先生带来了一些困扰。
问题在于,示例中使用了两种完全不同的技术来注册方法(绑定到服务器结构体)和注册内省(绑定到一个类型化的字符串,该字符串必须是你函数名的小写形式)。即使是当前的维护者(Southworth 先生)也承认他不在 godbus 中使用内省功能。我研究了他的做法,但那太针对他的应用程序了,无法成为一个有效的示例。
在Golang中使用godbus进行内省时,关键是要正确构建introspect.Node结构并一次性导出所有方法。你的代码问题在于循环内多次导出同一个对象,导致方法被覆盖。以下是修正后的示例:
package main
import (
"fmt"
"github.com/godbus/dbus/v5"
"github.com/godbus/dbus/v5/introspect"
)
type server struct{}
func (server) Foo() (string, *dbus.Error) {
return "Bar!", nil
}
func (server) Ping() (string, *dbus.Error) {
return "Pong!", nil
}
func main() {
conn, err := dbus.SessionBus()
if err != nil {
panic(err)
}
defer conn.Close()
s := server{}
path := dbus.ObjectPath("/com/example/Test")
iface := "com.example.Test"
// 导出所有方法
err = conn.Export(s, path, iface)
if err != nil {
panic(err)
}
// 构建内省数据
node := &introspect.Node{
Name: string(path),
Interfaces: []introspect.Interface{
{
Name: iface,
Methods: introspect.Methods(s),
},
introspect.IntrospectData,
},
}
// 导出内省接口
err = conn.Export(introspect.NewIntrospectable(node), path,
"org.freedesktop.DBus.Introspectable")
if err != nil {
panic(err)
}
// 请求名称
reply, err := conn.RequestName("com.example.Test",
dbus.NameFlagDoNotQueue)
if err != nil {
panic(err)
}
if reply != dbus.RequestNameReplyPrimaryOwner {
panic("名称已被占用")
}
fmt.Println("服务已启动,等待调用...")
select{}
}
使用introspect.Methods()函数自动从服务器对象提取方法信息。通过dbus命令行工具验证:
# 查看内省数据
dbus-send --session --dest=com.example.Test \
--type=method_call --print-reply \
/com/example/Test \
org.freedesktop.DBus.Introspectable.Introspect
# 测试Foo方法
dbus-send --session --dest=com.example.Test \
--type=method_call --print-reply \
/com/example/Test \
com.example.Test.Foo
# 测试Ping方法
dbus-send --session --dest=com.example.Test \
--type=method_call --print-reply \
/com/example/Test \
com.example.Test.Ping
对于带参数的方法,需要正确定义方法签名:
func (server) Add(x, y int32) (int32, *dbus.Error) {
return x + y, nil
}
func (server) Greet(name string) (string, *dbus.Error) {
return "Hello " + name, nil
}
introspect.Methods()会自动处理参数和返回类型。确保所有导出方法都遵循(返回值, *dbus.Error)的签名格式。

