Como ler a saída dbus-monitor?

19

Estou brincando com o dbus-monitor para tentar entender como o dbus está funcionando Ambiente Ubuntu. Eu tenho várias perguntas a esse respeito:

  1. Você poderia por favor me avisar como ler o seguinte corretamente? Eu entendo a grande ideia, mas não os detalhes.

    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
    

    Eu entendo que o primeiro é um sinal enquanto o segundo é um método. O destino significa que pode haver um receptor / slot específico para um sinal? O que é um membro ? E os itens da lista seguem o sinal que os argumentos passaram no sinal? O que são remetente e seriais ?

  2. Eu notei algo sobre a relação entre controle de volume e notificações. Pelo que li da saída do monitor 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
    

    Parece que a notificação é acionada por seu método. Eu simplesmente não entendo porque isso funciona assim. A meu ver, faria mais sentido se houvesse um sinal "notificação-áudio-volume-mídia" enquanto a notificação escutasse este sinal e reagisse de acordo. Se o envio / recebimento fosse público e não privado, não permitiria mais flexibilidade e eficiência? Por exemplo, se houvesse um sinal público para "notificação-áudio-volume-médio" , vários aplicativos poderiam ouvir esse sinal (o que permitiria que os aplicativos de notificação concorrentes surgissem) e os desenvolvedores apenas tem que se preocupar com o envio de sinais, enquanto pegar e manusear um sinal seria o negócio da aplicação de notificação (ou qualquer outro programa que precise desses sinais).

  3. Sou novo no Dbus e quero aprender mais, já que estou trabalhando com o Dbus em Python, principalmente para desenvolver alguns applets. Eu vi o tutorial do dbus-python e ele ensina como ouvir todos os sinais (especificando nem interface nem caminho, etc.) Mas como rastrear métodos quando eles são chamados, como o dbus-monitor faz?

Se você tiver paciência para ensinar como isso funciona, de nada.

    
por Benjamin 01.05.2011 / 10:18

2 respostas

23

Introdução ao D-Bus

  • O D-Bus fornece meios para comunicação entre serviços . Os serviços podem ser anônimos (identificados apenas pelo endereço do barramento, como: 1.6), e os serviços podem adquirir nomes conhecidos , como org.freedesktop.Notifications ou org.freedesktop.NetworkManager . O remetente e o destino que você pode ver nos logs são serviços. "Destino nulo" significa transmissão: entrega para todos os serviços.

  • Um serviço pode exportar um ou vários objetos para o barramento. Os objetos recebem caminhos de objeto , como /org/freedesktop/NetworkManager/ActiveConnection/1 ou /org/ayatana/menu/DA00003 . Caminhos de objetos usam barra como separador, como caminhos do sistema de arquivos.

  • Cada objeto pode suportar uma ou várias interfaces . Uma interface nada mais é do que um conjunto de métodos e sinais, coloquialmente conhecidos como membros (muito semelhantes à interface OOP). Métodos e sinais possuem assinaturas fixas. Os membros são sempre namespaces em nomes de interfaces conhecidos .

  • Uma vez publicados, os nomes conhecidos nunca mudam .

  • Qualquer serviço pode se conectar aos sinais de outro serviço e chamar de forma assíncrona seus métodos. Qualquer serviço pode emitir sinais.

Sinais

Agora, para as suas perguntas específicas.

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

Sim, você está certo, isso é um sinal. Ele é transmitido pelo serviço :1.1948 e o objeto "auto" é /org/ayatana/menu/DA00003 . O sinal tem o nome ItemPropertyUpdated , que é definido na interface org.ayatana.dbusmenu (como org.ayatana.dbusmenu::ItemPropertyUpdated em C ++). A série, eu acho, é uma espécie de identificador único do evento no ônibus.

Então vemos os argumentos de sinal. De acordo com a documentação da interface , o primeiro argumento int32 é o id de um item, a segunda string é seu nome de propriedade e a terceira variante é o valor da propriedade. Então, o objeto /org/ayatana/menu/DA00003 está nos notificando que o item id # 23 alterou sua propriedade enabled para true.

Outro exemplo de sinais:

signal sender=:1.1602 -> dest=(null destination) serial=20408 path=/im/pidgin/purple/PurpleObject; interface=im.pidgin.purple.PurpleInterface; member=SendingChatMsg
   int32 47893
   string "test"
   uint32 1
signal sender=:1.1602 -> dest=(null destination) serial=20409 path=/im/pidgin/purple/PurpleObject; interface=im.pidgin.purple.PurpleInterface; member=IrcSendingText
   int32 64170
   string "PRIVMSG #chat :test

Enviei uma mensagem de texto "test" usando o Pidgin para um canal de IRC, e /im/pidgin/purple/PurpleObject emitiu dois sinais na interface im.pidgin.purple.PurpleInterface : primeiro, um% geral_de_co%, depois um% deSendingChatMsg mais específico.

Métodos

Agora métodos. Os métodos são uma maneira de fazer com que os objetos do D-Bus façam alguma coisa, ou para realizar alguma consulta e retornar dados. Eles são bastante semelhantes aos métodos OOP clássicos, exceto que os métodos D-Bus são chamados de forma assíncrona.

Vamos chamar um método D-Bus programaticamente.

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

Observe os argumentos, especialmente o nome do ícone. No seu exemplo, IrcSendingText era o ícone do alto-falante de volume de média potência.

Serviços personalizados

É absolutamente possível executar seus próprios serviços D-Bus, exportar seus próprios objetos D-Bus e definir suas próprias interfaces D-Bus com seus próprios métodos e sinais. Tudo isso pode ser feito em Python muito facilmente, uma vez que você compreenda o conceito geral e leia a documentação do módulo "notification-audio-volume-medium" . dbus

    
por ulidtko 01.05.2011 / 14:31
10

Eu também estava procurando solução para coletar as notificações da área de trabalho através do dbus com um script python. Esta questão foi a mais próxima que eu fiquei de googling, mas escrever um substituto para o noticie-osd parecia um exagero:)

Olhando para as notificações recentes fontes do applet, recebi algumas dicas de como monitorar as mensagens do dbus e aqui está a implementação do python I veio com:

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()

Espero que isso ajude alguém, pois parece que não há muitos exemplos simples de python relacionados ao monitoramento das mensagens dbus.

    
por Keto 27.05.2012 / 14:23