D-Bus
Co je D-Bus jsem tu už prezentoval dříve, je to systémová sběrnice, po které spolu mohou komunikovat různé aplikace. V XML formátu. DBus běží ve dvou vrstvách, systémové a uživatelské pro každé sezení (session). Aplikace může fungovat jako server, klient, nebo obojí. Server nabízí svůj interface jiným, client ho pak může využívat. Interface může obsahovat metody a signály. Jako klient se můžete připojit na signály jiné aplikace a na ně navázat volání metod aplikace vlastní. Například aplikace email vyšle signál, že přišla zpráva a všechny aplikace, které se na tento signál připojily, na to mohou reagovat. Třeba mohou zavolat DBus metodu aplikace email, která jim vrátí odesílatele a znění subjektu a zobrazit je v systémové notifikaci, samozřejmě také přes DBus. Ale dnes signály řešit nebudu, jen si do nějaké služby cvičně jednorázově šťouchnu.D-Feet D-Bus debuger
Na prolézání a testování DBus sběrnice je D-Feet slušný nástroj. Umí vyhledávat, ke každé metodě vám napíše jaké chce parametry a co vrací a můžete metody DBus rovnou testovat. V Ubuntu 12.04 mi funguje okno aplikace normálně, ale v 13.04 je jakési rozmrdané. Když vám začne kvůli delším textům lézt obsah mimo okno doleva(!), i s posuvníkem, nezbyde, než celé okno zvětšit, nebo měnit velikost postranního panelu. Jinak je to psané v Pythonu a GTK.Instalace
sudo apt-get install d-feet
Jak se do DBus volá, tak se z něho ozývá
Nebudu tu propírat kompletní obsluhu DBus, ukážu jen to, jak je možné volat metody existující služby ve zmíněných jazycích. Pro příklad jsem zvolil screensaver GNOME. Na obrázku z D-Feet můžete vidět strukturu této služby, která krom spouštění spořiče zamyká obrazovku, následně na ní umí zobrazit zprávu pro uživatele a také podává zprávy o změně a stavu spořiče. Dokonce umí simulovat aktivitu uživatele, takže pokud chcete zabránit jeho aktivaci, můžete v intervalu volat příslušnou metodu. No a jak takové volání DBus metod vypadá...Shell
#!/bin/sh
dbus-send --type=method_call --dest=org.gnome.ScreenSaver / \
org.gnome.ScreenSaver.Lock
dbus-send --type=method_call --dest=org.gnome.ScreenSaver / \
org.gnome.ScreenSaver.ShowMessage \
string:"Titulek" string:"Tělo zprávy" string:"ikona"
dbus-send --type=method_call --dest=org.gnome.ScreenSaver / \
org.gnome.ScreenSaver.Lock
dbus-send --type=method_call --dest=org.gnome.ScreenSaver / \
org.gnome.ScreenSaver.ShowMessage \
string:"Titulek" string:"Tělo zprávy" string:"ikona"
Řešení přímočaré, prostě napíšete jméno služby, cestu k němu (v tomto případě jsem napsal pouze lomítko, protože si to dbus-send umí najít sám, když tam není víc možností), jméno interfejsu a přímo za něj přes tečku metodu a její parametry. Jsou to příkazy jednořádkové, zpětná lomítka ho umožňují rozdělit na řádků více, aby to bylo přehlednější. Pokud tento skript spustíte, zamkne se obrazovka a pak se na ní zobrazí zpráva pro uživatele. Ikonu to normálně nezobrazuje, i když dáte správnou cestu, prázdný řetězec udělá to samé, to platí obecně.
Upozorňuji, že třeba v Ubuntu 12.04 chce ještě metoda Lock parametr typu string (stačí prázdný), D-Feet vám to ukáže.
Python
V Pythonu si vyžádáte přes modul dbus proxy dané služby, proxy požádáte o konkrétní metodu a tu pak voláte. Dá se to naprasit i na jeden řádek..#!/usr/bin/env python3 import dbus session_bus = dbus.SessionBus () proxy = session_bus.get_object ( "org.gnome.ScreenSaver", "/org/gnome/ScreenSaver") set_active = proxy.get_dbus_method ("SetActive", "org.gnome.ScreenSaver") lock = proxy.get_dbus_method ("Lock", "org.gnome.ScreenSaver") show_message = proxy.get_dbus_method ("ShowMessage","org.gnome.ScreenSaver") set_active (True) lock () show_message ("Titulek", "Tělo zprávy", "ikona")
Vala
Vala vyžaduje trochu jiný přístup. Když si od DBus knihovny vyžádáte proxy nějaké služby, dostanete objekt, který má jakýsi obecný typ a je třeba mu dopsat inteface, jenž definuje jeho metody a signály v rozsahu, který potřebujete. Interface přiřadíte onomu proxy objektu, čímž tento přestane být pro kompilátor neznámým a metody dané interfejsem můžete volat běžným způsobem.[DBus (name = "org.gnome.ScreenSaver")] interface ScreenSaver : Object { public abstract void set_active (bool active) throws IOError; public abstract void lock () throws IOError; public abstract void show_message (string summary, string body, string icon) throws IOError; } public int main (string[] args) { try { ScreenSaver proxy = Bus.get_proxy_sync ( BusType.SESSION, "org.gnome.ScreenSaver", "/org/gnome/ScreenSaver" ); proxy.set_active (true); proxy.lock (); proxy.show_message ( "Titulek", "Tělo zprávy", "ikona"); } catch (Error e) { print ("Něco se podělalo!\n"); return 1;} return 0; }
Kompilace:
valac --pkg gio-2.0 soubor.vala
Jak je vidět, interface je třeba uvést speciálním zaklínadlem (atributem) se jménem DBus interfejsu, který má popisovat. V něm si deklarujete metody, které budete chtít v rámci služby používat. Metody by měly mít dovětek throws IOError. Vala také předpokládá, že názvy metod a signálů DBusu přepíšete do interfejsu z DBusCamelCaseNames na vala_lower_case_names. ShowMessage tedy bude show_message a použitá knihovna si to přežvýká na konkrétní DBus jméno. Ovšem i pokud použijete původní názvy DBus metod, bude váš program volat správné metody, jen budou v rámci konvencí Vala vypadat jako třídy, místo metod. Vizuálně v kódu. Další zajímavostí je fakt, že pokud jsem schválně umazal konec cesty k objektu při získávání proxy (to je ten druhý parametr s lomítky, popravdě jsem vymazal skoro vše a nechal jen první tři písmena za org/), program fungoval bez problémů, knihovník si cestu k interfejsu prostě domyslel, protože tam nic jiného nebylo. Metody služeb na DBus ovšem nemusí dodržovat naznačené konvence a na rozdíl od Vala rozliší jména ShowMessage a show_message ... Ale asi nikdo takové kraviny dělat nebude... ;)
Obsluhu výjimky vám připomene překladač, pokud ji zapomenete, protože ví, že v práci s DBus může nastat IOError, každopádně může nastat i jiný error, když se třeba změní jméno interfejsu, o změně jména sužby nemluvě. Obecným Errorem zachytíte i tyto chyby, nejen ty komunikační, napsal jsem ho tam, abych neměl počmáranou celou obrazovku, když jsem testoval co všechno jsou si Vala/DBus schopny domyslet.
Závěr
Zkrátka různý přístup k jednomu problému. Jsem teprve na začátku a zatím mi není jasné, jak bych ve Vala dosáhl volání metody, kterou bych si za běhu na DBus zjistil přes introspekci. Například, kdybych chtěl přepsat D-Feet do Vala. Snad časem..Faktem je, že přístup Vala k DBus může programátorovi přidat trochu psaní navíc. Ve chvíli, kdy potřebujete otestovat více služeb a vybrat si podle dostupnosti tu, kterou skutečně použijete, budete mít třeba v Pythonu psaní o poznání méně a to i vzhledem k ne/typovosti použitého programovacího jazyka. Na to, jak může vypadat třída, která má na starosti selekci a následné použití dostupné služby, se můžete podívat zde. Tím, že kompilátor dopředu potřebuje znát vlastnosti volaného objektu, se věci malinko komplikují.
Moc pěkný porovnání, i když tíhnu k tomu skriptovacímu pojetí, tak kód ve Vale je taky hezkej ;-)
OdpovědětVymazatJe to jednoduché a přehledné. Jen jsem trochu v popisu pomotal co je co a co je důležité, už jsem to opravil. Já každopádně obecně tíhnu k Vala, protože ten kód je pro mě přehlednější. Všude přesně vidím, jaké parametry kam lezou (nutnost definovat typ na každém vstupu) a díky tomu taky začínám lépe chápat fungování knihoven, které používám, například GTK, ke které mám přesnou dokumentaci, protože céčková sedí. Plno věcí je překvapivě s Vala jednodušších, než s Pythonem, začíná to tím, že když si třeba pro přehlednost program rozhážu do x souborů, nemusím řešit žádné moduly, importy, kraviny, jen kompilátoru vyjmenuju ty soubory a hotovo. Bastlí se mi v tom fakt líp :)
Vymazat