DBus
的文档中有这个例子,
ping :: MethodCall -> IO Reply
ping _ = ReplyReturn []
sayHello :: String -> IO String
sayHello name = return ("Hello " ++ name ++ "!")
export client "/hello_world"
defaultInterface { interfaceName = "com.example.HelloWorld"
, interfaceMethods =
[ method "com.example.HelloWorld" "Ping" ping
, autoMethod "com.example.HelloWorld" "Hello" sayHello
]
}
但是,该示例在几个方面似乎有点过时:
method
(有相关的Method
、makeMethod
、autoMethod
);ping
也有一个过时的签名,也许它应该返回 DBusR Reply
而不是 IO Reply
;autoMethod
给出了 3 个参数,但应该给出 2 个参数,只需删除 "Hello"
就可以进行类型检查,但是...我读过 AutoMethod
的文档,但我不太明白.但最重要的是这个例子不完整。我该如何使用它?
export
的文档为
处导出给定的Interface
ObjectPath
让我觉得我所要做的就是将片段的最后一部分(对
export
的调用)放入 main :: IO ()
函数中,然后使用 _ <- getChar
或 return ()
之前的其他内容使其保持活动状态,但是我仍然不知道如何...调用这些函数 sayHello
和 ping
。看着这个答案我有点觉得我应该使用dbus-send
,但是无论我如何根据上面的代码片段编译Haskell废话,如果我运行
dbus-send --session --print-reply --dest="com.example.HelloWorld" /hello_world com.example.HelloWorld.Ping
我明白了
Error org.freedesktop.DBus.Error.ServiceUnknown: The name is not activatable
根据我目前的知识,这可能是因为我应该做一些与 Haskell 无关的设置,以及因为我写了 Haskell 废话。
无论如何,这是我设法编译的一些代码,但实际上并没有做任何事情:
{-# LANGUAGE OverloadedStrings #-}
import DBus
import DBus.Client
ping :: MethodCall -> IO Reply
ping _ = return (ReplyReturn [])
sayHello :: String -> IO String
sayHello name = return ("Hello " ++ name ++ "!")
main :: IO ()
main = do
client <- connectSession
export client "/hello_world"
defaultInterface { interfaceName = "com.example.HelloWorld"
, interfaceMethods =
[
autoMethod "com.example.HelloWorld" sayHello
]
}
_ <- getLine
return ()
错误消息谈论的是总线名称,基本上是总线上每个服务(甚至每个客户端)的“地址”。最重要的是,这意味着所请求的
--dest=
姓名当前不存在在公交车上。
(除此之外,该错误消息还意味着 dbus-daemon 不知道如何按需启动您的服务,但您可以安全地忽略它 - “激活”只是自动启动机制,当您'重新手动启动您的服务。)
总线名称不是通过配置设置的(仅用于自动启动);每次启动并连接到总线时,服务都会使用特殊的总线调用“认领”它们。您的流程需要调用
requestName
(docs) 才能实现这一点。
接口名称不是——接口只是您自己的代码用来分组或区分方法的东西,而服务名称(又名总线名称,又名唯一名称)是整个过程的实际“D-Bus 地址” 。对于简单的 1 对象、1 接口服务,它们很可能是相同的,但如果您浏览
d-spy
,您会看到许多示例,其中一个服务使许多对象可用,并且具有多个接口,所有这些都在单个总线名称。
理想情况下,应该在设置并导出初始对象之后声明总线名称,以防止对服务的调用失败并出现“没有此类对象”或类似的情况,因为它碰巧到达得太早了。