如何将映射字符串到结构的字典传递给带有busctl的d-bus方法?
Posted
技术标签:
【中文标题】如何将映射字符串到结构的字典传递给带有busctl的d-bus方法?【英文标题】:How to pass a dictionary that maps strings to structures to a d-bus method with busctl? 【发布时间】:2021-09-24 09:47:12 【问题描述】:我有一个 D-Bus 方法,它接收将字符串映射到结构的字典作为输入:
<method name="myMethod">
<arg name="input_dict" type="as(ss)" direction="in"/>
...
</method>
我尝试使用 busctl 调用此类方法,但没有成功。到目前为止,我已经尝试使用以下参数:
busctl call $SERVICE $OBJECT $INTERFACE myMethod "as(ss)" 1 "str1" \( "str2" "str3" \)
busctl call $SERVICE $OBJECT $INTERFACE myMethod "as(ss)" 1 str1 str2 str3
busctl call $SERVICE $OBJECT $INTERFACE myMethod "as(ss)" str1 str2 str3
busctl call $SERVICE $OBJECT $INTERFACE myMethod "as(ss)" 1 str1 '(ss)' str2 str3
busctl call $SERVICE $OBJECT $INTERFACE myMethod "as(ss)" 1 str1 \(ss\) str2 str3
busctl call $SERVICE $OBJECT $INTERFACE myMethod "as(ss)" 1 str1 "ss" str2 str3
busctl call $SERVICE $OBJECT $INTERFACE myMethod "as(ss)" 1 str1 \"ss\" str2 str3
busctl call $SERVICE $OBJECT $INTERFACE myMethod "as(ss)" 1 str1 \(str2 str3\)
busctl call $SERVICE $OBJECT $INTERFACE myMethod "as(ss)" 1 str1 \(ss\) \(str2 str3\)
根据调用的不同,我会遇到不同的错误:
No such method 'WakeUp' in interface 'com.verisure.cuxscored.DECT' at object path '/com/verisure/cuxscored/dect' (signature 'as(ss)')
Too many parameters for signature.
因此,我的问题是:如何在使用 busctl 时将参数传递给 myMethod?
编辑
感谢 ukBaz 的回答,我得到了一个见解。我也有一个 getter 方法,我之前调用过,我得到的结果与 ukBaz 的有点不同:
<method name="myGetMethod">
<arg name="output_dict" type="as(ss)" direction="out"/>
...
</method>
运行 busctl 命令它给了我这个:
a(s(ss)) 1 "str1" "str2" "str3"
注意与预期解决方案的区别(a(s(ss))
代替 as(ss)
,括号代替大括号)。如果我做对了,那么输出应该被解释为一个结构数组,其中包含一个字符串,另一个结构包含两个字符串。
我不太确定为什么结果会有所不同,但我已经克服了这个问题,直接使用 getter 的输出作为其他方法的输入:
busctl call $SERVICE $OBJECT $INTERFACE myMethod `busctl call $SERVICE $OBJECT $INTERFACE myGetMethod`
同样,如果我“按原样”使用 myGetMethod 的输出,该方法也有效:
busctl call $SERVICE $OBJECT $INTERFACE myMethod "a(s(ss))" 1 "str1" "str2" "str3"
所以剩下的唯一问题就是为什么 D-bus 方法返回一个结构数组,即使它被声明为返回一个字典。
编辑 2
如果我运行 dbusctl introspect,这就是我得到的结果:
NAME TYPE SIGNATURE RESULT/VALUE FLAGS
$INTERFACE interface - - -
.myGetMethod method - as(ss) -
.myMethod method as(ss) - -
...
作为一个问题,我也尝试过使用 D-Feet,但没有更好的结果。我调用了一个返回 as(ss) 类型值的方法,D-Feet 返回以下结构:
[('str1', ('str2', 'str3'))]
如果我随后使用相同的结构在 D-Feet 上调用 myMethod,我得到一个 DBus.Error.UnknownMethod:
No '
"such method 'myMethod' in interface '$INTERFACE' at object "
"path '$OBJECT' (signature 'as(ss)') (19)")
但是,如果我使用参数、大括号等,我会收到不同的错误消息,但我无法让该方法正常工作。那么,在使用 D-Feet 时,将这种参数传递给 myMethod 的适当方式是什么?
【问题讨论】:
您的更新使方法看起来存在实现问题,或者库如何猜测类型。如果不了解有关服务实施的更多信息,可能很难提供帮助。您能否对busctl
进行自省,看看 getter 和 setter 方法的签名是什么?
我已将内省的结果添加到主要问题中。
【参考方案1】:
我为自己创建了一个带有该签名的 DBus 服务来测试:
from gi.repository import GLib
from pydbus import SessionBus
loop = GLib.MainLoop()
class MyDBUSService(object):
"""
<node>
<interface name='net.lew21.pydbus.ClientServerExample'>
<method name='Hello'>
<arg type='as(ss)' name='response' direction='in'/>
</method>
<method name='Echo'>
<arg type='as(ss)' name='response' direction='out'/>
</method>
<method name='Quit'/>
</interface>
</node>
"""
def Hello(self, data):
"""Prints the data sent to it"""
for my_key in data:
print(f'key: my_key - Value: data[my_key]')
def Echo(self):
"""Sends a known string back"""
return "str1" : ("str2", "str3")
def Quit(self):
"""removes this object from the DBUS connection and exits"""
loop.quit()
bus = SessionBus()
bus.publish("net.lew21.pydbus.ClientServerExample", MyDBUSService())
loop.run()
busctl
自省中给出的:
$ busctl --user introspect net.lew21.pydbus.ClientServerExample /net/lew21/pydbus/ClientServerExample net.lew21.pydbus.ClientServerExample
NAME TYPE SIGNATURE RESULT/VALUE FLAGS
.Echo method - as(ss) -
.Hello method as(ss) - -
.Quit method - - -
Echo
的结果输出为:
$ busctl --user call net.lew21.pydbus.ClientServerExample /net/lew21/pydbus/ClientServerExample net.lew21.pydbus.ClientServerExample Echo
as(ss) 1 "str1" "str2" "str3"
我使用该输出来训练如何将值放入:
$ busctl --user call net.lew21.pydbus.ClientServerExample /net/lew21/pydbus/ClientServerExample net.lew21.pydbus.ClientServerExample Hello "as(ss)" 1 str str2 str3
我的 Python 脚本给出了正确的输出:
$ python3 dbus_service_struct.py
key: str - Value: ('str2', 'str3')
所以我不知道为什么你的第二次尝试没有成功
为了完整起见,下面是一个在字典中发送两个值的示例:
$ busctl --user call net.lew21.pydbus.ClientServerExample /net/lew21/pydbus/ClientServerExample net.lew21.pydbus.ClientServerExample Hello 'as(ss)' 2 "key1" "value1:1" "value1:2" "key2" "value2:1" "value2:1"
$ python3 dbus_service_struct.py
key: key1 - Value: ('value1:1', 'value1:2')
key: key2 - Value: ('value2:1', 'value2:1')
【讨论】:
以上是关于如何将映射字符串到结构的字典传递给带有busctl的d-bus方法?的主要内容,如果未能解决你的问题,请参考以下文章
为啥threading.thread将空字典传递给python中的函数线程
iOS Swift 如何从 UIWebView 将 JSON 字符串和数组或字典传递给 Javascript?
SWIG (Java):如何将带有回调函数的结构从 Android 应用程序传递给 C++?