golang dbus 服务器示例

golang dbus server example

Golang dbus module has provided the following example但是不清楚服务端是如何接收消息和响应的。推荐一个 ping/pong 示例:

package main

import (
    "fmt"
    "os"

    "github.com/godbus/dbus"
    "github.com/godbus/dbus/introspect"
)

const intro = `
<node>
    <interface name="com.github.guelfey.Demo">
        <method name="Foo">
            <arg direction="out" type="s"/>
        </method>
    </interface>` + introspect.IntrospectDataString + `</node> `

type foo string

func (f foo) Foo() (string, *dbus.Error) {
    fmt.Println(f)
    return string(f), nil
}

func main() {
    conn, err := dbus.ConnectSessionBus()
    if err != nil {
        panic(err)
    }
    defer conn.Close()

    f := foo("Bar!")
    conn.Export(f, "/com/github/guelfey/Demo", "com.github.guelfey.Demo")
    conn.Export(introspect.Introspectable(intro), "/com/github/guelfey/Demo",
        "org.freedesktop.DBus.Introspectable")

    reply, err := conn.RequestName("com.github.guelfey.Demo",
        dbus.NameFlagDoNotQueue)
    if err != nil {
        panic(err)
    }
    if reply != dbus.RequestNameReplyPrimaryOwner {
        fmt.Fprintln(os.Stderr, "name already taken")
        os.Exit(1)
    }
    fmt.Println("Listening on com.github.guelfey.Demo / /com/github/guelfey/Demo ...")
    select {}
}

(这只是我阅读程序和文档的印象。自己测试一下是否准确)

https://pkg.go.dev/github.com/godbus/dbus#Conn.Export

func (conn *Conn) Export(v interface{}, path ObjectPath, iface string) error

If a method call on the given path and interface is received, an exported method with the same name is called with v as the receiver if the parameters match and the last return value is of type *Error. If this *Error is not nil, it is sent back to the caller as an error. Otherwise, a method reply is sent with the other return values as its body.

程序将 foo 类型的 f 传递给 conn.Export

foo 具有与描述的模式相匹配的方法:

func (f foo) Foo() (string, *dbus.Error)

响应是此函数的 return 值,不包括最终错误,即 string(f)。 ("Bar!" 在这种情况下)。

最后的空select语句select {}是我从未见过的巧妙技巧。它只是一个永远阻塞的语句。您可以在 this question 中阅读更多相关信息。它在这里只是用来阻止 main goroutine 终止。在 Go 中,当 main goroutine 完成时,整个过程将立即结束。

鉴于这个空 select 是一个“聪明的把戏”,最好附上一条简单的评论解释:

// Blocks forever
select {}

这个例子之所以让人迷惑,大概是因为这个Export方法比较神奇吧。它接受一个命名模糊的空接口值,并根据一些可能使用反射的内部过程来确定如何处理它。除非您阅读该函数的文档,否则很难猜测它会做什么。