{"id":800,"date":"2011-08-23T01:22:29","date_gmt":"2011-08-23T00:22:29","guid":{"rendered":"http:\/\/blog.rastersoft.com\/?p=800"},"modified":"2011-08-23T01:22:29","modified_gmt":"2011-08-23T00:22:29","slug":"dbus-en-vala","status":"publish","type":"post","link":"https:\/\/blog.rastersoft.com\/?p=800","title":{"rendered":"DBus en Vala"},"content":{"rendered":"<p><strong>Actualizado<\/strong> Estoy trabajando en un nuevo proyecto, escrito \u00edntegramente en <a href=\"https:\/\/live.gnome.org\/Vala\" target=\"_blank\">Vala<\/a>, y la verdad es que cuantas m\u00e1s cosas aprendo sobre \u00e9l, m\u00e1s me gusta.<\/p>\n<p>Lo \u00faltimo que descubr\u00ed fue como trabajar con <a href=\"http:\/\/en.wikipedia.org\/wiki\/D-Bus\" target=\"_blank\">DBus<\/a> en Vala, y resulta que es extremadamente sencillo y elegante, aunque tuve que investigar bastante hasta encontrar como hacer algunas cosas, pues los ejemplos que vienen en la p\u00e1gina tratan de como trabajar con un servidor hecho por uno mismo, cuando yo necesitaba acceder a un servicio del sistema.<\/p>\n<p>As\u00ed pues, y sin m\u00e1s dilaci\u00f3n, veamos como se puede usar DBus para obtener una lista de los discos duros conectados por USB al ordenador, y como formatearlos.<\/p>\n<p>Lo primero que vemos es que toda esa informaci\u00f3n la gestiona el demonio <a href=\"http:\/\/www.freedesktop.org\/wiki\/Software\/udisks\" target=\"_blank\">UDisk<\/a>, el cual exporta una serie de funciones y objetos a trav\u00e9s de DBus para que cualquier programa pueda acceder a ellos. Si echamos un vistazo a la <a href=\"http:\/\/hal.freedesktop.org\/docs\/udisks\/UDisks.html\" target=\"_blank\">documentaci\u00f3n de la API<\/a>, vemos que se exporta el m\u00e9todo <a href=\"http:\/\/hal.freedesktop.org\/docs\/udisks\/UDisks.html#UDisks.EnumerateDevices\" target=\"_blank\">EnumerateDevices<\/a>, el cual nos devuelve un array de objetos.<\/p>\n<p>\u00bfY como accedemos a este m\u00e9todo del objeto UDisk desde Vala? Pues con este c\u00f3digo:<\/p>\n<div class=\"mycode\">\n<pre class=\"mycode\">[DBus (name = \"org.freedesktop.UDisks\")]\ninterface UDisk_if : GLib.Object {\n    public abstract ObjectPath[] EnumerateDevices() throws IOError;\n}\n\nUDisk_if udisk = Bus.get_proxy_sync&lt;UDisk_if&gt; (BusType.SYSTEM, \"org.freedesktop.UDisks\",\"\/org\/freedesktop\/UDisks\");\nvar retval = udisk.EnumerateDevices();<\/pre>\n<\/div>\n<p>Aqu\u00ed vemos que primero definimos una interfaz con todos los m\u00e9todos a los que vamos a querer acceder (en este caso s\u00f3lo uno), sacando de la documentaci\u00f3n los par\u00e1metros y dem\u00e1s, y le a\u00f1adimos antes una cabecera con el nombre del objeto. Luego, creamos un proxy s\u00edncrono, conect\u00e1ndonos a trav\u00e9s del bus del sistema (<em>BusType.SYSTEM<\/em>), al servidor UDisk (<em>org.freedesktop.UDisks<\/em>) y pedimos acceso al objeto deseado (<em>\/org\/freedesktop\/UDisks<\/em>). Finalmente, llamamos al m\u00e9todo deseado, almacenando el resultado en una nueva variable.<\/p>\n<p>Es importante recalcar que cualquier m\u00e9todo que se defina puede emitir, siempre, una excepci\u00f3n de tipo <em>IOError<\/em>, por lo que <strong>siempre<\/strong> se debe a\u00f1adir al final de la definici\u00f3n la coletilla <em>throws IOError<\/em>. De no hacerlo se producir\u00e1 un error de compilaci\u00f3n. Tambi\u00e9n comentar que dado que esta funci\u00f3n s\u00f3lo devuelve un par\u00e1metro, la he escrito en formato <em>resultado metodo(parametros)<\/em>; sin embargo, tambi\u00e9n es perfectamente v\u00e1lida la sintaxis <em>void metodo (parametros,&#8230;, out resultado)<\/em>. Esta segunda forma es obligatoria cuando un m\u00e9todo devuelve m\u00e1s de un resultado. Con esa sintaxis, la interfaz tendr\u00eda esta forma:<\/p>\n<div class=\"mycode\">\n<pre class=\"mycode\">[DBus (name = \"org.freedesktop.UDisks\")]\ninterface UDisk_if : GLib.Object {\n    public abstract void EnumerateDevices(out ObjectPath[] path) throws IOError;\n}<\/pre>\n<\/div>\n<p>En <em>retval<\/em> tenemos ahora un array de objetos <em>ObjectPath<\/em>, cada uno de tipo <em>Device<\/em>, representando una unidad extra\u00edble. \u00bfY ahora, qu\u00e9? Pues ahora vamos a imprimir el punto de montaje de cada uno de ellos. Si miramos la <a href=\"http:\/\/hal.freedesktop.org\/docs\/udisks\/Device.html\" target=\"_blank\"><em>documentaci\u00f3n del objeto Device<\/em><\/a>, vemos que dicha informaci\u00f3n se almacena como una propiedad, as\u00ed que definimos nuestra interfaz as\u00ed:<\/p>\n<div class=\"mycode\">\n<pre class=\"mycode\">[DBus (name = \"org.freedesktop.UDisks.Device\")]\ninterface Device_if : GLib.Object {\n    public abstract string IdLabel { owned get; }\n    public abstract string[] DeviceMountPaths { owned get; }\n\n    public abstract void FilesystemUnmount(string[] options) throws IOError;\n    public abstract void FilesystemCreate(string type, string[] options) throws IOError;\n    public abstract void PartitionModify (string type, string label, string[] options) throws IOError;\n    public abstract void FilesystemMount(string type, string[] options, out string mount_path) throws IOError;\n}<\/pre>\n<\/div>\n<p>Ponemos { owned get; } en lugar de {owned get; set; } porque los campos son de s\u00f3lo lectura. Tambi\u00e9n he a\u00f1adido los cuatro m\u00e9todos necesarios para poder formatear una partici\u00f3n, aunque en el ejemplo no los voy a utilizar.<\/p>\n<p>Ahora llega el momento del c\u00f3digo que accede a los datos, que es \u00e9ste:<\/p>\n<div class=\"mycode\">\n<pre class=\"mycode\">Device_if device2;\nforeach (ObjectPath o in retval) {\n    device2 = Bus.get_proxy_sync&lt;Device_if&gt; (BusType.SYSTEM, \"org.freedesktop.UDisks\",o);\n    GLib.stdout.printf(\"Disco %s montado en:n\",device2.IdLabel);\n    foreach (string s in device2.DeviceMountPaths) {\n        GLib.stdout.printf(\"    %sn\",s);\n    }\n}<\/pre>\n<\/div>\n<p>As\u00ed, primero recorremos la lista de objetos que obtuvimos con la anterior llamada (en <em>retval<\/em>), y creamos un proxy s\u00edncrono para cada uno de ellos, contra el servidor de UDisk (\u00e9l es quien nos dio la lista de objetos, por lo que estos tienen que estar en \u00e9l). Luego imprimimos la etiqueta simplemente leyendo la propiedad del objeto, y por \u00faltimo imprimimos todos los puntos de montaje (una misma partici\u00f3n puede estar montada en varios sitios a la vez).<\/p>\n<p><strong>Actualizaci\u00f3n:<\/strong> Uno de los problemas que tuve fue que la llamada a <em>FilesystemCreate<\/em> (que formatea la unidad especificada) tarda varios segundos en ejecutarse, lo que hac\u00eda que la GUI se quedase colgada. La primera soluci\u00f3n que encontr\u00e9 fue ejecutarla en un thread aparte, y usar espera activa para detectar cuando termin\u00f3, pero era muy poco elegante. La soluci\u00f3n definitiva consiste en realizar <a href=\"https:\/\/live.gnome.org\/Vala\/Tutorial#Asynchronous_Methods\" target=\"_blank\">llamadas as\u00edncronas a DBus, explicadas en el tutorial de Vala<\/a>. La idea consiste en a\u00f1adir la palabra reservada <em>async<\/em> en la definici\u00f3n de la funci\u00f3n en la clase, con lo que la llamada a DBus ser\u00e1 no-bloqueante, y definir un callback an\u00f3nimo.<\/p>\n<div class=\"mycode\">\n<pre class=\"mycode\">[DBus (name = \"org.freedesktop.UDisks.Device\")]\ninterface Device_if : GLib.Object {\n  [...]\n  public abstract async void FilesystemCreate(string type, string[] options) throws IOError;\n  [...]\n}\n\n  \/\/ Llamamos a la funci\u00f3n, a\u00f1adi\u00e9ndo como \u00faltimo par\u00e1metro\n  \/\/ una funci\u00f3n an\u00f3nima que se ejecutar\u00e1 al terminar la\n  \/\/ ejecuci\u00f3n\n  device2.FilesystemCreate.begin(format,options, (obj,res) =&gt; {\n    try {\n      \/\/ La llamada a .end recoge los valores devueltos (de haberlos)\n      \/\/ y dispara cualquier excepci\u00f3n que se haya producido\n      device2.FilesystemCreate.end(res);\n      return;\n    } catch (IOError e) {\n      \/\/ Captura de excepciones (en este caso, fallo durante el formateo)\n    }\n  });<\/pre>\n<\/div>\n<p>Una vez que hemos hecho la llamada, podemos volver al bucle principal de GTK o llamar a la funci\u00f3n <em>run()<\/em> de un cuadro de di\u00e1logo, y \u00e9ste seguir\u00e1 funcionando en paralelo a la ejecuci\u00f3n de nuestra llamada a DBus.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Actualizado Estoy trabajando en un nuevo proyecto, escrito \u00edntegramente en Vala, y la verdad es que cuantas m\u00e1s cosas aprendo sobre \u00e9l, m\u00e1s me gusta. Lo \u00faltimo que descubr\u00ed fue como trabajar con DBus en Vala, y resulta que es extremadamente sencillo y elegante, aunque tuve que investigar bastante hasta encontrar como hacer algunas cosas, &hellip; <a href=\"https:\/\/blog.rastersoft.com\/?p=800\" class=\"more-link\">Seguir leyendo <span class=\"screen-reader-text\">DBus en Vala<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,7],"tags":[],"class_list":["post-800","post","type-post","status-publish","format-standard","hentry","category-programacion","category-tutoriales"],"_links":{"self":[{"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/posts\/800","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=800"}],"version-history":[{"count":0,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/posts\/800\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=800"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=800"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=800"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}