Riding the D-Bus with Ruby
The last time I looked at D-Bus is a couple of years ago. What I saw back then was promising in technology but ugly in (C-)programming. D-Bus has come a long way 'til then.And so have my programming skills with scripting languages, esp. with Ruby. The ruby-dbus project provides a nice and easy-to-use programming API, once one has mastered the lack of examples and the D-Bus nomenclature.
About D-Bus
There is plenty of information available on D-Bus. I personally found the Introduction to D-Bus most valuable from a developers point of view.
D-Bus originates from the freedesktop.org initiative and is hosted at www.freedesktop.org
Basically, D-Bus is a RPC (remote procedure call) mechanism, allowing different programs to talk to each other and provide services in a standardized way.
The transport used for talking is called a bus, meaning everyone can ride (connect to) it. Usually there are two independent buses available
- System bus
This is for system-wide services, like hardware information (usually provided by HAL) - Session bus
This is for per-login services, like a Gnome Desktop session.
The nice thing about D-Bus is that it allows introspection. You can ask a service about its capabilities. And the D-Bus itself is a service, so you just need to know about org.freedesktop.DBus to find all other services.
Services provide objects. These are organized in a tree-like fashion and typically addressed using slash-separated paths, just like filenames. Iterating over the objects of org.freedesktop.Hal gives you all devices.
Objects then have members. Members are methods to call, providing the functionality of the service. To make things more
Putting it all together gives you this chain
Bus (System/Session)
-> Service (e.g. org.freedesktop.Hal)
-> Object (e.g. /org/freedesktop/Hal/devices/storage_model_DVDRW_LH_20A1S)
-> Interface (e.g. org.freedesktop.Hal.Device.Storage.Removable)
-> Member (e.g. bool CheckForMedia())
Using ruby-dbus
Connecting to the bus in Ruby is as easy asrequire 'dbus' bus = DBus::SystemBus.instance # resp. 'bus = DBus::SessionBus.instance'DBus::SystemBus is a Singleton, hence the .instance instead of the usual .new for creating the object.
Now you can create a proxy object. Its named 'proxy' because the real object lives on the other side of the connection, in the service. The proxy object is in your application and proxy-ing calls via D-Bus to the service object. You can use this to find all services on the bus
require 'dbus' bus = DBus::SystemBus.instance bus.proxy.ListNames[0].each do |service| puts "Service: #{service}" endGiven a known service, D-Bus introspection allows to find its objects, subnodes and interfaces
require 'dbus' bus = DBus::SystemBus.instance # Create the proxy object proxy = bus.introspect "org.freedesktop.Hal", "/" # proxy.bus gives you the bus # proxy.path is the object path # proxy.destination is the service name # Print object interfaces proxy.interfaces.each do |interface| puts "Object #{proxy.path} provides #{interface}" end # Print object subnodes proxy.subnodes.each do |path| puts "-> #{proxy.path}/#{path}" endA specific interface of an object can be accessed by the [] operator. And the interface knows about the signature of its methods.
require 'dbus' bus = DBus::SystemBus.instance # create proxy for the 'computer' device proxy = bus.introspect "org.freedesktop.Hal", "/org/freedesktop/Hal/devices/computer" # Print object interfaces proxy.interfaces.each do |interface| puts "Object #{proxy.path} provides #{interface}" proxy[interface].methods.each do |key,value| puts " #{value.rets} #{key}( #{value.params} )" end endDue to the dynamic nature of Ruby, Object methods are directly accessible in normal Ruby conventions. One just has to select the right interface first.
require 'dbus' bus = DBus::SystemBus.instance proxy = bus.introspect "org.freedesktop.Hal", "/org/freedesktop/Hal/devices/computer" iface = proxy["org.freedesktop.Hal.Device.CPUFreq"] freq = iface.GetCPUFreqPerformance gov = iface.GetCPUFreqGovernor puts "Frequency #{freq}, Governor #{gov}"Riding the D-Bus with Ruby is easy and fun !
No comments:
Post a Comment