Как мне использовать интерфейс Emacs DBUS?

Я посмотрел пакет dbus, и кажется, что все функции встроены в исходный код C и для них нет документации.

Как я могу использовать dbus-call-method функционировать?

4 ответа

Решение

Гугл в помощь... Перейдите по ссылке для примера, это не мой код, поэтому я не буду помещать его здесь.

http://emacs-fu.blogspot.com/2009/01/using-d-bus-example.html

У меня была та же проблема, и я нашел статью emacs-fu, которая появляется, когда поискать в Google немного слишком просто для моих нужд.

В частности, я хотел экспортировать свои собственные методы elisp через dbus, и у меня были проблемы с пониманием терминологии dbus и ее применения к интерфейсу emacs dbus.

Первое, что нужно проверить, документация по emacs, Ch f dbus-register-method

dbus-register-method is a built-in function in `C source code'.

(dbus-register-method BUS SERVICE PATH INTERFACE METHOD HANDLER)

Register for method METHOD on the D-Bus BUS.

BUS is either the symbol `:system' or the symbol `:session'.

SERVICE is the D-Bus service name of the D-Bus object METHOD is
registered for.  It must be a known name.

PATH is the D-Bus object path SERVICE is registered.  INTERFACE is the
interface offered by SERVICE.  It must provide METHOD.  HANDLER is a
Lisp function to be called when a method call is received.  It must
accept the input arguments of METHOD.  The return value of HANDLER is
used for composing the returning D-Bus message.

BUS будет просто:session или:system (где вы, вероятно, почти всегда хотите использовать:session как настольное приложение, я полагаю).

SERVICE - это уникальное имя приложения на шине, например, адрес или доменное имя. Dbus.el определяет dbus-service-emacs как "org.gnu.Emacs".

PATH предназначен для различных типов функциональных возможностей приложений, как SERVICE для различных приложений. Например, определенный модуль emacs может предоставлять функциональность в /ModuleName PATH в org.gnu.Emacs SERVICE.

ИНТЕРФЕЙС как интерфейс в программировании. Это спецификация, которая сообщает другим клиентам dbus, как взаимодействовать с объектами, которые выставляет ваше приложение. Он содержит, например, сигнатуры типов для ваших методов. Таким образом, у вас может быть интерфейс, который говорит что-то вроде: в службе org.gnu.Emacs в пути / ModuleName вы найдете метод с именем helloworld, который будет принимать нулевые аргументы и возвращать строку.

Трудно было понять: как определить интерфейс для моего метода?

Обыскивая dbus.el, вы обнаружите, что dbus-interface-introspectable (среди прочего) определено, что просто содержит строку "org.freedesktop.DBus.Introspectable", которая называет стандартный интерфейс, который просто предоставляет один метод:

org.freedesktop.DBus.Introspectable.Introspect (out STRING xml_data)

(ссылка на спецификацию http://dbus.freedesktop.org/doc/dbus-specification.html)

И это метод, который вызывается клиентами, чтобы выяснить, какие приложения выставляются на dbus. Таким образом, мы можем использовать этот метод, чтобы посмотреть, как другие приложения рекламируют свои вещи на dbus, а затем мы можем реализовать наш собственный метод Introspect, просто имитирующий то, что делают другие, и все будет хорошо.

Однако обратите внимание, что в спецификации сказано, что приложения могут реализовывать интроспективный интерфейс, они не обязаны это делать. На самом деле вы можете позвонить dbus-register-method просто отлично с пустой строкой в ​​качестве интерфейса (кажется, все будет делать). Вы сможете вызвать свой метод. Однако я всегда получал ошибки NoReply и проблемы с приложениями, зависшими в ожидании ответа от dbus, который исчез, когда я понял, как сделать свои вещи интроспективными. Поэтому я предполагаю, что Introspect() ожидается довольно часто.

Итак, давайте сделаем это:

(defun say-world ()
  ;; you need to map between dbus and emacs datatypes, that's what :string is for
  ;; if you're returning just one value that should work automatically, otherwise
  ;; you're expected to put your return values in a list like I am doing here
  (list :string "world"))

(dbus-register-method
  :session
  "org.test.emacs"
  "/helloworld"
  "org.test.emacs"
  "hello"
  'say-world)

Это то, что мы хотим реализовать и, следовательно, хотим определить интерфейс (с именем "org.test.emacs"). Вы можете использовать его просто так и попытаться вызвать метод hello с помощью qdbus org.test.emacs /helloworld org.test.emacs.hello, Он должен работать, у меня он работает только после 20 секунд ожидания (приложение зависает), но работает.

Теперь давайте сделаем это самоанализом:

(defun dbus-test-slash-introspect ()
  "<node name='/'>
  <interface name='org.freedesktop.DBus.Introspectable'>
  <method name='Introspect'>
  <arg name='xml_data' type='s' direction='out'/>
  </method>
  </interface>
  <node name='helloworld'>
  </node>
  </node>")

(dbus-register-method
  :session
  "org.test.emacs"
  "/"
  dbus-interface-introspectable
  "Introspect"
  'dbus-test-slash-introspect)

(defun dbus-test-slash-helloworld-introspect ()
  "<node name='/helloworld'>
  <interface name='org.freedesktop.DBus.Introspectable'>
  <method name='Introspect'>
  <arg name='xml_data' type='s' direction='out'/>
  </method>
  </interface>
  <interface name='org.test.emacs'>
  <method name='hello'>
  <arg name='' direction='out' type='s' />
  </method>
  </interface>
  </node>")

(dbus-register-method
  :session
  "org.test.emacs"
  "/helloworld"
  dbus-interface-introspectable
  "Introspect"
  'dbus-test-slash-helloworld-introspect)

Вот и мы. Мы просто определяем два метода Introspect (по одному для каждого уровня иерархии нашего пути) и возвращаем некоторый рукописный xml, сообщающий другим приложениям о пути / helloworld и методе hello внутри него. Обратите внимание, что dbus-test-slash-helloworld-introspect содержит <interface name="org.test.emacs">...</interface> у него есть сигнатура типа для нашего метода, то есть, насколько мне известно, определение интерфейса, который мы использовали при регистрации нашего метода в dbus.

Оцените все это и покопайтесь в qdbus:

~> qdbus org.test.emacs
/
/helloworld

~> qdbus org.test.emacs /
method QString org.freedesktop.DBus.Introspectable.Introspect()

~> qdbus org.test.emacs /helloworld
method QString org.freedesktop.DBus.Introspectable.Introspect()
method QString org.test.emacs.helloworld()

~> qdbus org.test.emacs /helloworld org.test.emacs.hello
world

Ура, работает как положено, без зависаний или ошибок NoReply.

И последнее, вы можете попробовать протестировать свой метод следующим образом:

(dbus-call-method :session "org.test.emacs" "/helloworld" "org.test.emacs" "hello" :timeout 1000)

и найти, что это просто таймауты и удивляться, почему Это потому, что если вы зарегистрируетесь и вызовете метод из одного и того же экземпляра emacs, то emacs будет ждать ответа. Не происходит никаких необычных потоков, вы всегда получите NoReply ответ в этой ситуации.

Если вам нужно вызвать и зарегистрировать метод в том же экземпляре emacs, вы можете использовать dbus-call-method-asynchronously вот так:

(defun handle-hello (hello)
  (print hello))

(dbus-call-method-asynchronously :session "org.test.emacs" "/helloworld" "org.test.emacs" "hello" 'handle-hello)

Вот безопасный способ проверить возможности dbus:

(defun dbus-capable ()
  "Check if dbus is available"
  (unwind-protect
      (let (retval)
        (condition-case ex
            (setq retval (dbus-ping :session "org.freedesktop.Notifications"))
          ('error
           (message (format "Error: %s - No dbus" ex))))
        retval)))

И вот способ отправить уведомление dbus:

(defun mbug-desktop-notification (summary body timeout icon)
  "call notification-daemon method METHOD with ARGS over dbus"
  (if (dbus-capable)
      (dbus-call-method
       :session                                 ; Session (not system) bus
       "org.freedesktop.Notifications"          ; Service name
       "/org/freedesktop/Notifications"         ; Service path
       "org.freedesktop.Notifications" "Notify" ; Method
       "emacs"
       0
       icon
       summary
       body
       '(:array)
       '(:array :signature "{sv}")
       ':int32 timeout)
    (message "Oh well, you're still notified")))

Или просто оцените следующее в Emacs:

(info "(dbus)")
Другие вопросы по тегам