Як читати вихід монітора dbus?


20

Я граю з dbus-монітором, щоб спробувати зрозуміти, як 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-монітора

    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

    Здається, що сповіщення запускається його методом. Я просто не розумію, чому це працює так. На мій погляд, було б більше сенсу, якби був сигнал, що випромінюється "сповіщення-звук-об'єм-носій", тоді як сповіщення слухатиме цей сигнал і реагуватиме відповідно. Якщо відправлення / отримання буде публічним, а не приватним, чи не дозволить це досягти більшої гнучкості та ефективності? Наприклад, якщо був загальнодоступний сигнал для "сповіщення-аудіо-об'єм-носій" тоді декілька додатків могли прослухати цей сигнал (що дозволило б з’являтися конкуруючим додаткам для сповіщень), а розробникам просто слід було б перейматися надсиланням сигналів, тоді як підбір та обробка сигналу - це справа програми сповіщення (або будь-який інший програма, яка потребує цих сигналів).

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

Якщо у вас є терпіння викладати, як це працює, вас вітає.

Відповіді:


24

Введення D-Bus

  • D-Bus надає засоби для спілкування між службами . Послуги можуть бути анонімними (ідентифіковані виключно за адресою автобуса, як-от: 1.6), а служби можуть отримати відомі імена , як-от org.freedesktop.Notificationsабо org.freedesktop.NetworkManager. Відправник і адреса, які ви можете бачити в журналах, - це послуги. "Недійсне призначення" означає трансляцію: доставка на всі послуги.

  • Сервіс може експортувати один або кілька об'єктів на шину. Об'єктам даються об'єктні шляхи , як /org/freedesktop/NetworkManager/ActiveConnection/1або /org/ayatana/menu/DA00003. Об'єктні шляхи використовують косу рису як роздільник, як і шляхи файлової системи.

  • Кожен об'єкт може підтримувати один або кілька інтерфейсів . Інтерфейс - це не що інше, як сукупність методів та сигналів, колокально відомих як члени (дуже схожі на інтерфейс OOP). Методи та сигнали мають фіксовану сигнатуру. Учасники завжди мають проміжки імен у межах відомих імен інтерфейсу.

  • Щойно опубліковані, відомі імена ніколи не змінюються .

  • Будь-яка служба може підключитися до сигналів іншої служби та асинхронно викликати її методи. Будь-яка служба може випромінювати сигнали.

Сигнали

Тепер до ваших конкретних питань.

відправник сигналу =: 1.1948 -> dest = (нульове призначення) serial = 1829990 шлях = / org / ayatana / menu / DA00003; інтерфейс = org.ayatana.dbusmenu; member = ItemPropertyUp updated
int32 23
рядок "увімкнено"
варіант булева правда

Так, ти маєш рацію, це сигнал. Це транслюється службою :1.1948, а об’єкт "Я" є /org/ayatana/menu/DA00003. Сигнал має ім'я, ItemPropertyUpdatedяке визначено в інтерфейсі org.ayatana.dbusmenu(наприклад, org.ayatana.dbusmenu::ItemPropertyUpdatedу C ++). Можливо, серіал - це свого роду унікальний ідентифікатор події в автобусі.

Потім ми бачимо сигнальні аргументи. Відповідно до документації на інтерфейс , перший аргумент int32 - це ідентифікатор елемента, другий рядок - його властивість, а третій варіант - значення властивості. Отже, /org/ayatana/menu/DA00003об’єкт повідомляє нас про те, що ідентифікатор елемента № 23 змінив enabledвластивість на справжню.


Ще один приклад сигналів:

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

Я надіслав текстове повідомлення "тест" за допомогою Pidgin на канал IRC і /im/pidgin/purple/PurpleObjectвипустив два сигнали в im.pidgin.purple.PurpleInterfaceінтерфейсі: спочатку загальний SendingChatMsg, потім більш конкретний IrcSendingText.

Методи

Тепер методи. Методи - це спосіб попросити об'єкти D-Bus зробити щось, або виконати запит і повернути дані. Вони досить схожі на класичні методи OOP, за винятком того, що методи 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

Дякую :) Це багато що уточнює. Як-небудь смішно, що відправники можуть бути анонімними, коли я використовую DFeet, є ім'я процесу, відповідне кожному відправнику, але це не відображається у висновку dbus-монітора. Чи можна простежити процеси? Тепер із Python я бачив, що я можу надсилати сигнали чи надавати методи або запускати методи інших сторін. Чи можливо також перехопити методи? Припустимо, я хочу перевірити, чи програма A запускає метод Dbus B і ​​щось з цим робити?
Бенджамін

Про сповіщення: інші notify-osd пасивно спрацьовують іншими програмами, а не активно шукають сигнали. Хіба це непрактично чи я неправильно розумію щось про Dbus? Я хочу зробити програму, яка б замінила notify-osd та збирала сповіщення у своєрідну скриньку. Чи можу я перехоплювати сповіщення, прослуховуючи сигнали тоді?
Бенджамін

@ Бенджамін, ну коли ви хочете перехопити виклики методів, спрямовані на іноземні служби, ви, швидше за все, думаєте про зламану конструкцію. Те , що ви повинні зробити , щоб замінити повідомить-ОНЕ написати програму , яка забезпечує на org.freedesktop.Notificationsслужбу. Таким чином, всі виклики методу до цієї послуги будуть оброблятися вашим кодом.
ulidtko

Що таке "я"?
kawing-chiu

10

Я також шукав рішення для збору сповіщень на робочому столі через dbus із сценарієм python. Це питання було найближчим у мене з googling, але написання заміни 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 =" Повідомляти "" також не потрібно, оскільки ви вже фільтруєте це у своїй функції (і, як ви правильно сказали, цього не уникнути завдяки першому NameAquiredповідомленню)
MestreLion
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.