¿Cómo enumerar todas las rutas de objetos bajo un servicio dbus?


16

Esta es una pregunta de seguimiento a una lista de servicios DBus disponibles .

El siguiente código de Python enumerará todos los servicios DBus disponibles.

import dbus
for service in dbus.SystemBus().list_names():
    print(service)

¿Cómo enumeramos las rutas de objetos bajo los servicios en Python? Está bien si la respuesta no involucra a Python, aunque es preferible.

Estoy usando Ubuntu 14.04


Está bien si la respuesta no involucra a Python, aunque es preferible.
user768421

Respuestas:


15

Según los documentos oficiales (bajo interfaces estándar ):

Hay algunas interfaces estándar que pueden ser útiles en varias aplicaciones de D-Bus.

org.freedesktop.DBus.Introspectable

Esta interfaz tiene un método:

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

Se pueden implementar instancias de objetos Introspectque devuelven una descripción XML del objeto, incluidas sus interfaces (con señales y métodos), los objetos debajo de él en el árbol de ruta del objeto y sus propiedades.

Así que aquí hay un ejemplo muy simple que debería comenzar. Utiliza xml.etree.ElementTreey dbus:

#!/usr/bin/env python

import dbus
from xml.etree import ElementTree

def rec_intro(bus, service, object_path):
    print(object_path)
    obj = bus.get_object(service, object_path)
    iface = dbus.Interface(obj, 'org.freedesktop.DBus.Introspectable')
    xml_string = iface.Introspect()
    for child in ElementTree.fromstring(xml_string):
        if child.tag == 'node':
            if object_path == '/':
                object_path = ''
            new_path = '/'.join((object_path, child.attrib['name']))
            rec_intro(bus, service, new_path)

bus = dbus.SystemBus()
rec_intro(bus, 'org.freedesktop.UPower', '/org/freedesktop/UPower')

Introspectivamente recursivamente a org.freedesktop.UPowerpartir de, por ejemplo, /org/freedesktop/UPowere imprime todas las rutas de objetos (nombres de nodo):

/org/freedesktop/UPower
/org/freedesktop/UPower/Wakeups
/org/freedesktop/UPower/devices
/org/freedesktop/UPower/devices/DisplayDevice
/org/freedesktop/UPower/devices/battery_BAT0
/org/freedesktop/UPower/devices/line_power_ADP0

que es más o menos lo que obtendrías si lo usaras d-feet(no es que lo necesites):

ingrese la descripción de la imagen aquí


Claro, puede obtener fácilmente las rutas de los objetos a través de la línea de comandos, por ejemplo, con gdbus:

gdbus introspect --system --dest org.freedesktop.UPower --object-path \
/ org / freedesktop / UPower --recurse | awk '/ ^ * node / {print $ 2}'
/ org / freedesktop / UPower
/ org / freedesktop / UPower / Wakeups
/ org / freedesktop / UPower / devices
/ org / freedesktop / UPower / devices / DisplayDevice
/ org / freedesktop / UPower / devices / battery_BAT0
/ org / freedesktop / UPower / devices / line_power_ADP0

No lo he qdbusinstalado pero según esta página

qdbus --system org.freedesktop.UPower

debería producir un resultado similar.


¿Cómo creo una lista de rutas de objetos desde rec_intro(bus, 'org.freedesktop.UPower', '/org/freedesktop/UPower')?
Khurshid Alam

No, me refiero a crear una lista de rutas de objetos de Python, de modo que pueda verificar (en mi script) si existe una ruta de objeto particular en la lista. Imprime el objectpath bien, pero quiero algo así k = rec_intro(bus, 'org.freedesktop.UPower', '/org/freedesktop/UPower'). Supongo que es posible modificando un poco la función.
Khurshid Alam

Código de ejemplo con qbus:bus = dbus.SessionBus()..... obj_path = '/org/gnome/Gnote/RemoteControl'.......... cmd = 'qdbus org.gnome.Gnote'......... while obj_path not in ((subprocess.check_output(cmd, shell=True)).decode("utf-8")).split("\n"): ........pass
Khurshid Alam

@ KhurshidAlam: inicialice una lista antes de la función, por ejemplo, mylist=[]luego reemplácela printcon mylist.appendy luego como el último comando en ese bloque de funcionesreturn mylist : eso es más o menos lo que hay ... luego puede iterar sobre la lista o lo que sea, por ejemplo, agregar al final del script for x in mylist: print("OBJ_PATH", x)para que se impriman con un OBJ_PATHprefijo ...
don_crissti

4

No estoy seguro de que pueda hacer esto mediante programación en Python. Podría, pero será un gran dolor de cabeza descubrir cómo. Traté de hacerlo antes y terminé odiando a Dbus. De todos modos, recomiendo usar d-pies si quieres investigar cosas. A continuación hay una captura de pantalla que robé de mi blog .

ingrese la descripción de la imagen aquí

Una vez que sepa el nombre del programa, la ruta del objeto, etc., puede usar Python para acceder a esas cosas.

Ejemplo

progname = 'org.freedesktop.NetworkManager'
objpath  = '/org/freedesktop/NetworkManager'
intfname = 'org.freedesktop.NetworkManager'
methname = 'GetDevices'

bus = dbus.SystemBus()

obj  = bus.get_object(progname, objpath)  # Here we get object
intf = dbus.Interface(obj, intfname)      # Here we get interface
meth = inf.get_dbus_method(methname)      # Here we get method

meth()                                    # And finally calling the method

Como puede ver, es un fastidio hacer algo simple. ¡Pero este es el flujo de trabajo más fácil que puede obtener con Dbus!

Entonces, use una herramienta GUI para descubrir las rutas de objetos, interfaces, etc. Luego use el fragmento de código anterior como plantilla para acceder a esas cosas. También le sugiero que haga esto a través del intérprete de IPython para ver qué métodos, propiedades, etc. tiene cada objeto (presionando la pestaña).



1

Lo que sé por experiencia para obtener las rutas de objetos de un nombre de bus (servicio) es posible introspectar con la ruta de objetos '/', es decir (usando el ejemplo anterior)

introspectfunc('org.freedesktop.UPower', '/') 

esto debería devolver:

<node name="/"> 
<node name="org"/>
<node name="org"/>
<node name="org"/>
<node name="org"/>
<node name="org"/>
<node name="org"/></node>

luego introspect con path '/ org'

introspectfunc('org.freedesktop.UPower', '/org')

esto debería devolver:

<node name="/org"> 
<node name="freedesktop"/>
<node name="freedesktop"/>
<node name="freedesktop"/>
<node name="freedesktop"/>
<node name="freedesktop"/>
<node name="freedesktop"/></node>

y así:

introspectfunc('org.freedesktop.UPower', '/org/freedesktop')
introspectfunc('org.freedesktop.UPower', '/org/freedesktop/UPower')
etc.

Es como recorrer la estructura de carpetas del disco duro donde la ruta del objeto '/' es la raíz y cada nodo es una subcarpeta. Esta parece ser la mejor manera de recuperar las rutas de objetos de un nombre de bus (servicio) en particular y construir una colección que contenga las rutas de objetos


1

Según las respuestas de #don_crissti , implementé, esta solución proporciona información sobre el nombre y el método de la interfaz y las señales

import dbus
from xml.etree import ElementTree
bus = dbus.SystemBus()

def busNames():
    return [ name for name in  bus.list_names() if not name.startswith(":") ]


def pathNames(service,object_path="/",paths=None,serviceDict=None):
    if paths == None:
        paths = {}
    paths[object_path] = {}
    obj = bus.get_object(service, object_path)
    iface = dbus.Interface(obj, 'org.freedesktop.DBus.Introspectable')
    xml_string = iface.Introspect()
    root = ElementTree.fromstring(xml_string)
    for child in root:
        if child.tag == 'node':
            if object_path == '/':
                    object_path = ''
            new_path = '/'.join((object_path, child.attrib['name']))
            pathNames(service, new_path,paths)
        else:
            if object_path == "":
                object_path = "/"
            functiondict = {}
            paths[object_path][child.attrib["name"]] = functiondict
            for func in child.getchildren():
                if func.tag not in functiondict.keys():
                    functiondict[func.tag] =[]
                functiondict[func.tag].append(func.attrib["name"])
    if serviceDict == None:
        serviceDict = {}
    serviceDict[service] = paths
    return serviceDict



import json
import random
service=random.sample(busNames(),1).pop()
print service
print json.dumps(pathNames(service),indent=3)
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.