Как прочитать вывод dbus-monitor?

20

Я играю с dbus-monitor, чтобы попытаться понять, как dbus работает в среде Ubuntu. У меня есть несколько вопросов по этому поводу:

  1. Не могли бы вы дать мне знать, как правильно читать следующее? Я понимаю большую идею, но не детали.

    signal sender=:1.1948 -> dest=(null destination) serial=1829990 path=/org/ayatana/menu/DA00003; interface=org.ayatana.dbusmenu; member=ItemPropertyUpdated
    int32 23
    string "enabled"
    variant boolean true
    method call sender=:1.6 -> dest=org.freedesktop.Notifications serial=1399 path=/org/freedesktop/Notifications; interface=org.freedesktop.Notifications;
    member=GetCapabilities
    

    Я понимаю, что первый - это сигнал, а второй - метод. Означает ли пункт назначения, что может быть определенный приемник / слот для сигнала? Какой член ? И соответствуют ли пункты списка сигналу аргументы, передаваемые в сигнале? Что такое отправитель и сериалы ?

  2. Я заметил кое-что о связи между регулировкой громкости и уведомлениями. Из того, что я прочитал с выхода dbus-monitor

    method call sender=:1.6 -> dest=org.freedesktop.Notifications serial=1400 path=/org/freedesktop/Notifications; interface=org.freedesktop.Notifications; member=Notify
    string "gnome-settings-daemon"
    uint32 0
    string "notification-audio-volume-medium"
    string " "
    string ""
    array [
    ]
    array [
    dict entry(
    string "value"
    variant int32 38
    )
    dict entry(
    string "x-canonical-private-synchronous"
    variant string "volume"
    )
    ]
    int32 -1
    

    Кажется, что уведомление вызывается его методом. Я просто не очень понимаю, почему это так работает. На мой взгляд, было бы более разумно, если бы существовал сигнал "Notification-Audio-Volume-Medium", в то время как уведомление будет прослушивать этот сигнал и реагировать соответствующим образом. Если бы отправка / получение было бы общедоступным, а не частным, разве это не позволило бы повысить гибкость и эффективность? Например, если был публичный сигнал для «уведомления-аудио-объем-носитель» тогда несколько приложений могли бы прослушивать этот сигнал (что позволило бы появиться конкурирующим приложениям для уведомлений), и разработчики просто должны были бы заботиться об отправке сигналов, тогда как сбор и обработка сигнала были бы делом уведомляющего приложения (или любого другого программа, которая нуждается в этих сигналах).

  3. Я просто новичок в Dbus и хочу узнать больше, поскольку я работаю с Dbus на Python, главным образом над разработкой некоторых апплетов. Я видел учебник по dbus-python, и он учит, как прослушивать все сигналы (не указывая ни интерфейс, ни путь и т. Д.). Но как отслеживать методы при их вызове, как это делает dbus-monitor?

Если у вас есть терпение, чтобы научить, как это работает, милости просим.

Вениамин
источник

Ответы:

24

D-Bus введение

  • D-Bus предоставляет средства для связи между службами . Сервисы могут быть анонимными (идентифицируются исключительно по адресу шины, например: 1.6), а сервисы могут получать общеизвестные имена , такие как org.freedesktop.Notificationsили org.freedesktop.NetworkManager. Отправитель и получатель, которые вы видите в журналах, являются службами. «Нулевой пункт назначения» означает трансляцию: доставка на все услуги.

  • Служба может экспортировать один или несколько объектов в шину. Объектам задаются пути к объектам , например /org/freedesktop/NetworkManager/ActiveConnection/1или /org/ayatana/menu/DA00003. Пути объектов используют косую черту в качестве разделителя, как пути файловой системы.

  • Каждый объект может поддерживать один или несколько интерфейсов . Интерфейс - это не что иное, как набор методов и сигналов, в просторечии именуемых элементами (очень похожими на интерфейс ООП). Методы и сигналы имеют фиксированные подписи. Члены всегда располагаются внутри хорошо известных имен интерфейсов.

  • После публикации известные имена никогда не меняются .

  • Любой сервис может подключаться к сигналам другого сервиса и асинхронно вызывать его методы. Любой сервис может излучать сигналы.

сигналы

Теперь к вашим конкретным вопросам.

отправитель сигнала =: 1.1948 -> dest = (нулевое место назначения) serial = 1829990 путь = / org / ayatana / menu / DA00003; Интерфейс = org.ayatana.dbusmenu; Член = ItemPropertyUpdated
Int32 23
строка "включена"
вариант булево верно

Да, вы правы, это сигнал. Он транслируется службой :1.1948, а объект "Я" есть /org/ayatana/menu/DA00003. Сигнал имеет имя, ItemPropertyUpdatedкоторое определено в интерфейсе org.ayatana.dbusmenu(как org.ayatana.dbusmenu::ItemPropertyUpdatedв C ++). Сериал, я думаю, является своего рода уникальным идентификатором события в автобусе.

Затем мы видим сигнал аргументов. Согласно документации интерфейса , первый аргумент int32 является идентификатором элемента, вторая строка - именем его свойства, а третий вариант - значением свойства. Итак, /org/ayatana/menu/DA00003объект уведомляет нас о том, что идентификатор элемента № 23 изменил свое enabledсвойство на true.


Еще один пример по сигналам:

отправитель сигнала =: 1.1602 -> dest = (нулевое место назначения) serial = 20408 путь = / im / pidgin / purple / PurpleObject; Интерфейс = im.pidgin.purple.PurpleInterface; Член = SendingChatMsg
   int32 47893
   строка "тест"
   uint32 1
отправитель сигнала =: 1.1602 -> dest = (нулевое место назначения) serial = 20409 path = / im / pidgin / purple / PurpleObject; Интерфейс = im.pidgin.purple.PurpleInterface; Член = IrcSendingText
   int32 64170
   строка "PRIVMSG #chat: тест

Я отправил текстовое сообщение «test» с использованием Pidgin на канал IRC и отправил /im/pidgin/purple/PurpleObjectдва сигнала через im.pidgin.purple.PurpleInterfaceинтерфейс: сначала общий SendingChatMsg, а затем более конкретный IrcSendingText.

методы

Теперь методы. Методы - это способ попросить объекты D-Bus сделать что-то или выполнить какой-либо запрос и вернуть данные. Они очень похожи на классические методы ООП, за исключением того, что методы D-Bus вызываются асинхронно.

Давайте вызовем метод D-Bus программно.

import dbus, dbus.proxies

#-- connect to the session bus (as opposed to the system bus)
session = dbus.SessionBus()

#-- create proxy object of D-Bus object
obj_proxy = dbus.proxies.ProxyObject(conn=session,
         bus_name="org.freedesktop.Notifications",     #-- name of the service we are retrieving object from
         object_path="/org/freedesktop/Notifications") #-- the object path

#-- create proxy object of the D-Bus object wrapped into specific interface
intf_proxy = dbus.proxies.Interface(obj_proxy, "org.freedesktop.Notifications")

#-- lastly, create proxy object of the D-Bus method
method_proxy = intf_proxy.get_dbus_method("Notify")

#-- ... and call the method
method_proxy("test from python",
             dbus.UInt32(0),
             "bluetooth",     #-- icon name
             "Notification summary",
             "Here goes notification body",
             [], {},
             5) #-- timeout

Обратите внимание на аргументы, особенно на имя иконки. В вашем примере "notification-audio-volume-medium"была иконка громкоговорителя средней мощности.

Таможенные услуги

Абсолютно возможно запускать собственные службы D-Bus, экспортировать собственные объекты D-Bus и определять свои собственные интерфейсы D-Bus с помощью собственных методов и сигналов. Все это можно сделать в Python довольно легко, если вы поймете общую концепцию и прочитаете dbusдокументацию к модулю.:)

ulidtko
источник
Обсуждение приветствуется, хотя я могу быть недоступен через день или два.
ulidtko
Спасибо :) Это многое проясняет. Как-то забавно, что отправители могут быть анонимными, когда я использую DFeet, каждому отправителю соответствует имя процесса, но это не отражается в выводе dbus-monitor. Можно ли проследить процессы? Теперь с Python я видел, что могу отправлять сигналы или предоставлять методы или запускать методы других сторон. Возможно ли перехватить методы? Предположим, я хочу посмотреть, запускает ли программа A метод Dbus B и что-то с ним делать?
Бенджамин
Об уведомлениях: notify-osd пассивно запускается другими приложениями, а не активно ищет сигналы. Разве это не практично или я что-то неправильно понимаю в Dbus? Я хочу сделать приложение, которое заменит notify-osd и собирает уведомления в виде почтового ящика. Могу ли я перехватить уведомления, слушая сигналы тогда?
Бенджамин
@ Бенджамин, ну, когда вы хотите перехватить вызовы методов, направленные на сторонние сервисы, вы, скорее всего, подумаете о сломанном дизайне. Чтобы заменить notify-osd, вам нужно написать программу, предоставляющую эту org.freedesktop.Notificationsуслугу. Таким образом, все вызовы методов для этого сервиса будут обрабатываться вашим кодом.
Улидько
Что такое объект «я»?
kawing-
10

Я также искал решение для сбора уведомлений на рабочем столе через dbus с помощью скрипта Python. Этот вопрос был ближе всего к поиску, но написание замены для notify-osd казалось излишним :)

Просматривая источники апплета недавних уведомлений, я получил несколько советов, как отслеживать сообщения dbus, и вот реализация Python, с которой я столкнулся:

import gtk
import dbus
from dbus.mainloop.glib import DBusGMainLoop

def filter_cb(bus, message):
    # the NameAcquired message comes through before match string gets applied
    if message.get_member() != "Notify":
        return
    args = message.get_args_list()
    # args are
    # (app_name, notification_id, icon, summary, body, actions, hints, timeout)
    print("Notification from app '%s'" % args[0])
    print("Summary: %s" % args[3])
    print("Body: %s", args[4])


DBusGMainLoop(set_as_default=True)
bus = dbus.SessionBus()
bus.add_match_string(
    "type='method_call',interface='org.freedesktop.Notifications',member='Notify'")
bus.add_message_filter(filter_cb)
gtk.main()

Надеюсь, это кому-нибудь поможет, так как кажется, что не так много простых примеров на python, связанных с мониторингом сообщений dbus.

Кето
источник
1
Это, безусловно, помогло мне! Большое спасибо! Несколько советов для вас: "type = 'method_call'" не является необходимым, так как уведомления используют только вызовы методов. Нет сигналов в спецификации. Кроме того, "member = 'Notify'" также не требуется, поскольку вы уже фильтруете это в своей функции (и, как вы правильно сказали, вы не можете избежать этого из-за первого NameAquiredсообщения)
MestreLion