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

3 回复

有人吗?我不想硬编码内省(就像我上次做的那样)。

更多关于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)的签名格式。

回到顶部