Tuesday, October 21, 2008

DBus por consola.

Después de hora y media de investigación he descubierto cómo cojones se usa d-bus desde línea de comandos. Horrible la documentación que hay.

El origen del tema es kdialog, una herramienta genial para proveer de manera "fácil" de una GUI a los scripts de bash. Todo es bonito y maravilloso hasta que se llega a la parte de progressbar, barra de progreso. Como el resto de llamadas son bloqueantes y esta lógicamente no puede serlo (no habría manera de seguir haciendo algo para hacer progresar la barra) el modo de funcionamiento cambia. Lo que devuelve kdialog es un "handler" de dbus, para enviarle mensajes. Todo lo que hay en Internet, incluida la documentación de KDE, es con dcop, la versión KDE3 de IPC, sustituida en KDE4 por dbus.

El control de DCOP por consola era una maravilla, pero con dbus la cosa es muy distinta. El comando dcop era autoexplicativo: si no se daba un comando valido, respondía con una lista de comandos válidos. Para saber que programas habia escuchando se hacía "dcop". Para saber que interfaces ofrecía amarok se hacia "dcop amarok". Para saber que funciones ofrecía la interfaz player de amarok, se hacia "dcop amarok player". Mágico.

Con dbus-send, la herramienta básica de dbus, si no se da un comando válido, dbus-send devuelve un bonito error nada explicativo y muere.
n0rdik0@telstar ~ $ dbus-send --print-reply --dest=org.kde.kdialog-27831 /ProgressDialog org.kde.kdialog.ProgressDialog.value int32:1
Error org.freedesktop.DBus.Error.ServiceUnknown: The name org.kde.kdialog-27831 was not provided by any .service files
n0rdik0@telstar ~ $

Ale, y tan pancho. La traduccion al cristiano (descubierta por otro lado) es que el puerto kdialog-27831 no existe, ya que le mandaba mensajes al kdialog que habia cerrado antes y el bueno era el 34981.

El caso es que tras mucho leer por la página de KDE y freedesktop.org llegué por fin a sacar algo en claro: cómo saber los servicios dbus ofrecidos por un programa. Es decir, la llamada "dcop kdialog ProgressBar" es sustitudia por "dbus-send --print-reply --dest=org.kde.kdialog-31498 /ProgressDialog org.freedesktop.DBus.Introspectable.Introspect". Super intuitivo, ¿a que sí?

Para más inri, kdialog no ofrece ningún método para cambiar el progreso, así que hay que hacerlo cambiado el valor de la propiedad "value" en "org.kde.kdialog.ProgressDialog". ¿Cómo se hace esto?

n0rdik0@telstar ~ $ dbus-send --print-reply --dest=org.kde.kdialog-31498 /ProgressDialog org.kde.kdialog.ProgressDialog.value
Error org.freedesktop.DBus.Error.UnknownMethod: No such method 'value' in interface 'org.kde.kdialog.ProgressDialog' at object path '/ProgressDialog' (signature '')
n0rdik0@telstar ~ $ dbus-send --print-reply --dest=org.kde.kdialog-31498 /ProgressDialog org.kde.kdialog.ProgressDialog.value int32:1
Error org.freedesktop.DBus.Error.UnknownMethod: No such method 'value' in interface 'org.kde.kdialog.ProgressDialog' at object path '/ProgressDialog' (signature 'i')
n0rdik0@telstar ~ $ dbus-send --print-reply --dest=org.kde.kdialog-31498 /ProgressDialog org.kde.kdialog.ProgressDialog.value=1
process 5324: arguments to dbus_message_new_method_call() were incorrect, assertion "_dbus_check_is_valid_member (method)" failed in file dbus-message.c line 1077.
This is normally a bug in some application using the D-Bus library.
D-Bus not built with -rdynamic so unable to print a backtrace
Aborted
n0rdik0@telstar ~ $

Lo primero es pensar: pues con "org.kde.kdialog.ProgressDialog.value 1". ¡Eeeeeck! Value no es un método. Pasarle in parámetro (hay que indicar el tipo int con "int32:") tampoco. Bien, pues con "org.kde.kdialog.ProgressDialog.value=1". ¡Ja, más quisieras! Así, aparte de no funcionar, da fallo de un assert.

Siguiendo la documentación, encuentro las funciones para manipular propiedades, con una ruta del servicio totalmente distinta a la anterior, dado que son funciones "genéricas", y son a quienes hay que decir la ruta a la propiedad deseada.

n0rdik0@telstar ~ $ dbus-send --print-reply --dest=org.kde.kdialog-31498 /ProgressDialog org.freedesktop.DBus.Properties.Get string:'org.kde.kdialog.ProgressDialog' string:'maximum'
method return sender=:1.15176 -> dest=:1.17121 reply_serial=2
variant int32 100
n0rdik0@telstar ~ $ dbus-send --print-reply --dest=org.kde.kdialog-31498 /ProgressDialog org.freedesktop.DBus.Properties.Get string:'org.kde.kdialog.ProgressDialog' string:'value'
method return sender=:1.15176 -> dest=:1.17122 reply_serial=2
variant int32 5
n0rdik0@telstar ~ $

¡Bien, funciona! Ahora el Set:
n0rdik0@telstar ~ $ dbus-send --print-reply --dest=org.kde.kdialog-31498 /ProgressDialog org.freedesktop.DBus.Properties.Set string:'org.kde.kdialog.ProgressDialog' string:'value' int32:6
Error org.freedesktop.DBus.Error.UnknownMethod: No such method 'Set' in interface 'org.freedesktop.DBus.Properties' at object path '/ProgressDialog' (signature 'ssi')
n0rdik0@telstar ~ $

¡Ups! ¿Cómo que no está? Pufffff... Después de un rato vi que el "(signature 'ssi')" es la calve, el prolema es que recibe 2 string y un int y espera 2 srtings y 1 "v", es decir "VARIANT". Perfecto:
n0rdik0@telstar ~ $ dbus-send --print-reply --dest=org.kde.kdialog-31498 /ProgressDialog org.freedesktop.DBus.Properties.Set string:'org.kde.kdialog.ProgressDialog' string:'value' variant:6
dbus-send: Data item "6" is badly formed
n0rdik0@telstar ~ $

¡Toma ya! Item "6" mal formado. Eso sí que es un error útil y explicativo. Google, nada. Documentación, nada. Pues nada, prueba y error.

Tras un rato, la Solución:
n0rdik0@telstar ~ $ dbus-send --print-reply --dest=org.kde.kdialog-31498 /ProgressDialog org.freedesktop.DBus.Properties.Set string:'org.kde.kdialog.ProgressDialog' string:'value' variant:'int32:6'
method return sender=:1.15176 -> dest=:1.17164 reply_serial=2
n0rdik0@telstar ~ $

Hora y media para eso. Con 2 minutos de documentación hubiera estado de sobra, pero no :(

Por suerte hay aplicaciones mucho mas amigables como qdbus o con GUI: qbusviewer. Con qdbus el funcionamiento es igual que dcop, aunque las propiedades siguen sin poder cambiarse de manera "intuitiva" y hace falta recurrir al "Get/Set" genérico para ello. Vaya estipicio. Hay que joderse con las regresiones parece que todo funciona peor segun pasa el tiempo. A este ritmo echaremos de menos lo buenos tiempos de Windows95.

1 comment:

Anonymous said...

Genial, justo andaba buscando algo de dbus... ahora para usarlo con python y no perder media vida en ello... q lio.

feed agregado

saludo