ruby-dbus 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,365 +0,0 @@
1
- <style>
2
- code { background-color: #F0E7E7; }
3
- pre code { background-color: #F0DDDD; }
4
- pre {
5
- font-size: 90%;
6
- overflow: hidden;
7
- padding-left: 10pt;
8
- border: thin solid #F0B4B4;
9
- background-color: #F0DDDD;
10
- }
11
- </style>
12
-
13
- <h1>Welcome</h1>
14
- <p>This is the Ruby D-Bus tutorial. It aims to show you the features of Ruby
15
- D-Bus and as you read through the tutorial also how to use them.</p>
16
- <p>&copy; Arnaud Cornet and Paul van Tilburg; this tutorial is part of
17
- free software; you can redistribute it and/or modify it under the
18
- terms of the <a href="http://www.gnu.org/licenses/lgpl.html">GNU Lesser General Public License,
19
- version 2.1</a> as published by the
20
- <a href="http://www.fsf.org/">Free Software Foundation</a>.</p>
21
- <h1>Introduction</h1>
22
- <p>This is a tutorial for Ruby D-Bus, a library to access D-Bus facilities of your
23
- system.</p>
24
- <h2>What is D-Bus?</h2>
25
- <p>D-Bus is an RPC(Remote Procedure Call) protocol. A common setup can have
26
- multiple D-Bus daemons running that route procedure calls and signals in
27
- the form of messages. Each of these daemons supports a bus. A bus that
28
- is often used by modern desktop environments, and is available per session, is
29
- called the <em>session bus</em>. Another bus that can be available, but in a
30
- system-wide manner, is called the <em>system bus</em>. It is used for example by
31
- the <a href="http://hal.freedesktop.org/">Hardware Abstraction Layer</a> daemon. Note
32
- that theoretically the D-Bus RPC protocol can be used without a system or
33
- session bus. I never came across any actual use of this though.</p>
34
- <p>At the desktop level, D-Bus allows some components to interact. Typically
35
- if you are writing an application or a personal script that wants to
36
- interact with your web browser, your music player, or that simply wants to
37
- pop-up a desktop notification, D-Bus comes into play.</p>
38
- <p>At the system level, the Hardware Abstraction Layer is a privileged daemon
39
- that notifies other software of hardware activities. Typically, if you
40
- want to be notified if a CD-ROM has been loaded in, of if you want to
41
- explore hardware, the system daemon comes into play.</p>
42
- <p>The D-Bus RPC system is as we will see <em>object oriented</em>.</p>
43
- <p>Buses provide access to <em>services</em> provided in turn by running or ready to
44
- run processes. Let me introduce some D-Bus terminology before we discuss
45
- the API of Ruby D-Bus.</p>
46
- <h2>Client</h2>
47
- <p>A D-Bus client is a process that connects to a D-Bus. They issue method
48
- calls and register to the bus for signals and events.</p>
49
- <h2>Service</h2>
50
- <p>A connected client can export some of its objects and let other clients
51
- call some of its methods. Such clients typically register a special name
52
- like <code>org.freedesktop.Notifications</code>, the service name.</p>
53
- <p>There is slightly different type of service. They are provided by
54
- processes that can be launched by a D-Bus daemon on demand. Once they are
55
- started by D-Bus they register a service name and behave like another
56
- client.</p>
57
- <p>Note that the buses themselves provide the <code>org.freedesktop.DBus</code> service,
58
- and provide some features through it.</p>
59
- <h2>Object path</h2>
60
- <p>An object path is the D-Bus way to specify an object <em>instance</em> address. A
61
- service can provide different object instances to the outside world, so
62
- that external processes can call methods on each of them. An object path
63
- is an address of an instance in a very similar way that the path is an
64
- address of a file on a file system. For example:
65
- <code>/org/freedesktop/Notification</code> is an object path of an object provided by
66
- the <code>org.freedesktop.Notification</code> service</p>
67
- <p><strong>Beware</strong>: service names and object paths can, but do <em>not</em> have to be
68
- related! You'll probably encounter a lot of cases though, where the
69
- object path is a slashed version of the dotted service name.</p>
70
- <h2>Interface</h2>
71
- <p>Classically in an object model, classes can implement interfaces. That is,
72
- some method definitions grouped in an interface. This is exactly what a
73
- D-Bus interface is as well. In D-Bus interfaces have names. These names must be
74
- specified on method calls.</p>
75
- <p>The <code>org.freedesktop.Notification</code> service provides an object instance
76
- called <code>/org/freedesktop/Notification</code>. This instance object implements an
77
- interface called <code>org.freedesktop.Notifications</code>. It also provides two
78
- special D-Bus specific interfaces: <code>org.freedesktop.DBus.Introspect</code> and
79
- <code>org.freedesktop.DBus.Properties</code>. Again, object paths, service names,
80
- and interface names can be related but do not have to be.</p>
81
- <p>Basically the <code>org.freedesktop.DBus.Introspect</code> has an <code>Introspect</code> method,
82
- that returns XML data describing the <code>/org/freedesktop/Notification</code> object
83
- interfaces. This is used heavily internally by Ruby D-Bus.</p>
84
- <h2>Method</h2>
85
- <p>A method is, well, a method in the classical meaning. It's a function that
86
- is called in the context of an object instance. Methods have typed
87
- parameters and return typed return values.</p>
88
- <h2>Signal</h2>
89
- <p>Signals are simplified method calls that do not have a return value. They
90
- do have typed parameters though.</p>
91
- <h2>Message</h2>
92
- <p>Method calls, method returns, signals, errors: all are encoded as D-Bus
93
- messages sent over a bus. They are made of a packet header with source and
94
- destination address, a type (method call, method reply, signal) and the
95
- body containing the parameters (for signals and method calls) or the return
96
- values (for a method return message).</p>
97
- <h2>Signature</h2>
98
- <p>Because D-Bus is typed and dynamic, each message comes with a signature that
99
- describes the types of the data that is contained within the message. The
100
- signature is a string with an extremely basic language that only describes
101
- a data type. You will need to have some knowledge of what a signature
102
- looks like if you are setting up a service. If you are just programming a
103
- D-Bus client, you can live without knowing about them.</p>
104
- <h1>Client Usage</h1>
105
- <p>This chapter discusses basic client usage
106
- and has the following topics:</p>
107
- <h2>Using the library</h2>
108
- <p>If you want to use the library, you have to make Ruby load it by issuing:</p>
109
- <pre><code>require 'dbus'
110
- </code></pre>
111
- <p>That's all! Now we can move on to really using it...</p>
112
- <h2>Connecting to a bus</h2>
113
- <p>On a typical system, two buses are running, the system bus and the session
114
- bus. The system bus can be accessed by:</p>
115
- <pre><code>bus = DBus::SystemBus.instance
116
- </code></pre>
117
- <p>Probably you already have guessed how to access the session bus. This
118
- can be done by:</p>
119
- <pre><code>bus = DBus::SessionBus.instance
120
- </code></pre>
121
- <h2>Performing method calls</h2>
122
- <p>Let me continue this example using the session bus. Let's say that I want
123
- to access an object of some client on the session bus. This particular
124
- D-Bus client provides a service called <code>org.gnome.Rhythmbox</code>. Let me
125
- access this service:</p>
126
- <pre><code>rb_service = bus.service("org.gnome.Rhythmbox")
127
- </code></pre>
128
- <p>In this example I access the <code>org.gnome.Rhythmbox</code> service, which is
129
- provided by the application
130
- <a href="http://www.gnome.org/projects/rhythmbox/">Rhythmbox</a>.
131
- OK, I have a service handle now, and I know that it exports the object
132
- "/org/gnome/Rhythmbox/Player". I will trivially access this remote object
133
- using:</p>
134
- <pre><code>rb_player = rb_service.object("/org/gnome/Rhythmbox/Player")
135
- </code></pre>
136
- <h2>Introspection</h2>
137
- <p>Well, that was easy. Let's say that I know that this particular object is
138
- introspectable. In real life most of them are. The <code>rb_object</code> object we
139
- have here is just a handle of a remote object, in general they are called
140
- <em>proxy objects</em>, because they are the local handle of a remote object. It
141
- would be nice to be able to make it have methods, and that its methods send
142
- a D-Bus call to remotely execute the actual method in another process.
143
- Well, instating these methods for a <em>introspectable</em> object is trivial:</p>
144
- <pre><code>rb_player.introspect
145
- </code></pre>
146
- <p>And there you go. Note that not all services or objects can be
147
- introspected, therefore you have to do this manually! Let me remind you
148
- that objects in D-Bus have interfaces and interfaces have methods. Let's
149
- now access these methods:</p>
150
- <pre><code>rb_player_iface = rb_player["org.gnome.Rhythmbox.Player"]
151
- puts rb_player_iface.getPlayingUri
152
- </code></pre>
153
- <p>As you can see, when you want to call a method on an instance object, you have
154
- to get the correct interface. It is a bit tedious, so we have the following
155
- shortcut that does the same thing as before:</p>
156
- <pre><code>rb_player.default_iface = "org.gnome.Rhythmbox.Player"
157
- puts rb_player.getPlayingUri
158
- </code></pre>
159
- <p>The <code>default_iface=</code> call specifies the default interface that should be
160
- used when non existing methods are called directly on a proxy object, and
161
- not on one of its interfaces.</p>
162
- <p>Note that the bus itself has a corresponding introspectable object. You can
163
- access it with <code>bus.proxy</code> method. For example, you can retrieve an array of
164
- exported service names of a bus like this:</p>
165
- <pre><code>bus.proxy.ListNames[0]
166
- </code></pre>
167
- <h2>Properties</h2>
168
- <p>Some D-Bus objects provide access to properties. They are accessed by
169
- treating a proxy interface as a hash:</p>
170
- <pre><code>nm_iface = network_manager_object["org.freedesktop.NetworkManager"]
171
- enabled = nm_iface["WirelessEnabled"]
172
- puts "Wireless is " + (enabled ? "enabled":"disabled")
173
- puts "Toggling wireless"
174
- nm_iface["WirelessEnabled"] = ! enabled
175
- </code></pre>
176
- <h2>Calling a method asynchronously</h2>
177
- <p>D-Bus is <em>asynchronous</em>. This means that you do not have to wait for a
178
- reply when you send a message. When you call a remote method that takes a
179
- lot of time to process remotely, you don't want your application to hang,
180
- right? Well the asychronousness exists for this reason. What if you dont'
181
- want to wait for the return value of a method, but still you want to take
182
- some action when you receive it?</p>
183
- <p>There is a classical method to program this event-driven mechanism. You do
184
- some computation, perform some method call, and at the same time you setup
185
- a callback that will be triggered once you receive a reply. Then you run a
186
- main loop that is responsible to call the callbacks properly. Here is how
187
- you do it:</p>
188
- <pre><code>rb_player.getPlayingUri do |resp|
189
- puts "The playing URI is #{resp}"
190
- end
191
- puts "See, I'm not waiting!"
192
- loop = DBus::Main.new
193
- loop &lt;&lt; bus
194
- loop.run
195
- </code></pre>
196
- <p>This code will print the following:</p>
197
- <pre><code>See, I'm not waiting!
198
- The playing URI is file:///music/papapingoin.mp3
199
- </code></pre>
200
- <h2>Waiting for a signal</h2>
201
- <p>Signals are calls from the remote object to your program. As a client, you
202
- set yourself up to receive a signal and handle it with a callback. Then running
203
- the main loop triggers the callback. You can register a callback handler
204
- as allows:</p>
205
- <pre><code>rb_player.on_signal("elapsedChanged") do |u|
206
- puts u
207
- end
208
- </code></pre>
209
- <h2>More about introspection</h2>
210
- <p>There are various ways to inspect a remote service. You can simply call
211
- <code>Introspect()</code> and read the XML output. However, in this tutorial I assume
212
- that you want to do it using the Ruby D-Bus API.</p>
213
- <p>Notice that you can introspect a service, and not only objects:</p>
214
- <pre><code>rb_service = bus.service("org.gnome.Rhythmbox")
215
- rb_service.introspect
216
- p rb_service.root
217
- </code></pre>
218
- <p>This dumps a tree-like structure that represents multiple object paths. In
219
- this particular case the output is:</p>
220
- <pre><code>&lt;/: {org =&gt; {gnome =&gt; {Rhythmbox =&gt; {Player =&gt; ..fdbe625de {},Shell =&gt; ..fdbe6852e {},PlaylistManager =&gt; ..fdbe4e340 {}}&gt;
221
- </code></pre>
222
- <p>Read this left to right: the root node is "/", it has one child node "org",
223
- "org" has one child node "gnome", and "gnome" has one child node "Rhythmbox".
224
- Rhythmbox has Tree child nodes "Player", "Shell" and "PlaylistManager".
225
- These three last child nodes have a weird digit that means it has an object
226
- instance. Such object instances are already introspected.</p>
227
- <p>If the prose wasn't clear, maybe the following ASCII art will help you:</p>
228
- <pre><code>/
229
- org
230
- gnome
231
- Rhythmbox
232
- Shell (with object)
233
- Player (with object)
234
- PlaylistManager (with object)
235
- </code></pre>
236
- <h3>Walking the object tree</h3>
237
- <p>You can have an object on any node, i.e. it is not limited to leaves.
238
- You can access a specific node like this:</p>
239
- <pre><code>rb_player = rb_service.root["org"]["gnome"]["Rhythmbox"]["Player"]
240
- rb_player = rb_service.object("/org/gnome/Rhythmbox/Player")
241
- </code></pre>
242
- <p>The difference between the two is that for the first one, <code>rb_service</code>
243
- needs to have been introspected. Also the obtained <code>rb_player</code> is already
244
- introspected whereas the second <code>rb_player</code> isn't yet.</p>
245
- <h2>Errors</h2>
246
- <p>D-Bus calls can reply with an error instead of a return value. An error is
247
- translated to a Ruby exception.</p>
248
- <pre><code>begin
249
- network_manager.sleep
250
- rescue DBus::Error =&gt; e
251
- puts e unless e.name == "org.freedesktop.NetworkManager.AlreadyAsleepOrAwake"
252
- end
253
- </code></pre>
254
- <h1>Creating a Service</h1>
255
- <p>This chapter deals with the opposite side of the basic client usage, namely
256
- the creation of a D-Bus service.</p>
257
- <h2>Registering a service</h2>
258
- <p>Now that you know how to perform D-Bus calls, and how to wait for and
259
- handle signals, you might want to learn how to publish some object and
260
- interface to provide them to the D-Bus world. Here is how you do that.</p>
261
- <p>As you should already know, D-Bus clients that provide some object to be
262
- called remotely are services. Here is how to allocate a name on a bus:</p>
263
- <pre><code>bus = DBus.session_bus
264
- service = bus.request_service("org.ruby.service")
265
- </code></pre>
266
- <p>Now this client is know to the outside world as <code>org.ruby.service</code>.
267
- Note that this is a request and it <em>can</em> be denied! When it
268
- is denied, an exception (<code>DBus::NameRequestError</code>) is thrown.</p>
269
- <h2>Exporting an object</h2>
270
- <p>Now, let's define a class that we want to export:</p>
271
- <pre><code>class Test &lt; DBus::Object
272
- # Create an interface.
273
- dbus_interface "org.ruby.SampleInterface" do
274
- # Create a hello method in that interface.
275
- dbus_method :hello, "in name:s, in name2:s" do |name, name2|
276
- puts "hello(#{name}, #{name2})"
277
- end
278
- end
279
- end
280
- </code></pre>
281
- <p>As you can see, we define a <code>Test</code> class in which we define a
282
- <code>org.ruby.SampleInterface</code> interface. In this interface, we define a
283
- method. The given code block is the method's implementation. This will be
284
- executed when remote programs performs a D-Bus call. Now the annoying part:
285
- the actual method definition. As you can guess the call</p>
286
- <pre><code>dbus_method :hello, "in name:s, in name2:s" do ...
287
- </code></pre>
288
- <p>creates a <code>hello</code> method that takes two parameters both of type string.
289
- The <em>:s</em> means "of type string". Let's have a look at some other common
290
- parameter types:</p>
291
- <ul>
292
- <li><em>u</em> means unsigned integer</li>
293
- <li><em>i</em> means integer</li>
294
- <li><em>y</em> means byte</li>
295
- <li><em>(ui)</em> means a structure having a unsigned integer and a signed one.</li>
296
- <li><em>a</em> means array, so that "ai" means array of integers<ul>
297
- <li><em>as</em> means array of string</li>
298
- <li><em>a(is)</em> means array of structures, each having an integer and a string.</li>
299
- </ul>
300
- </li>
301
- </ul>
302
- <p>For a full description of the available D-Bus types, please refer to the
303
- <a href="http://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-signatures">D-Bus specification</a>.</p>
304
- <p>Now that the class has been defined, we can instantiate an object
305
- and export it as follows:</p>
306
- <pre><code>exported_obj = Test.new("/org/ruby/MyInstance")
307
- service.export(exported_obj)
308
- </code></pre>
309
- <p>This piece of code above instantiates a <code>Test</code> object with a D-Bus object
310
- path. This object is reachable from the outside world after
311
- <code>service.export(exported_obj)</code> is called.</p>
312
- <p>We also need a loop which will read and process the calls coming over the bus:</p>
313
- <pre><code>loop = DBus::Main.new
314
- loop &lt;&lt; bus
315
- loop.run
316
- </code></pre>
317
- <h3>Using the exported object</h3>
318
- <p>Now, let's consider another program that will access our newly created service:</p>
319
- <pre><code>ruby_service = bus.service("org.ruby.service")
320
- obj = ruby_service.object("/org/ruby/MyInstance")
321
- obj.introspect
322
- obj.default_iface = "org.ruby.SampleInterface"
323
- obj.hello("giligiligiligili", "haaaaaaa")
324
- </code></pre>
325
- <p>As you can see, the object we defined earlier is automatically introspectable.
326
- See also "Basic Client Usage".</p>
327
- <h2>Emitting a signal</h2>
328
- <p>Let's add some example method so you can see how to return a value to the
329
- caller and let's also define another example interface that has a signal.</p>
330
- <pre><code>class Test2 &lt; DBus::Object
331
- # Create an interface
332
- dbus_interface "org.ruby.SampleInterface" do
333
- # Create a hello method in the interface:
334
- dbus_method :hello, "in name:s, in name2:s" do |name, name2|
335
- puts "hello(#{name}, #{name2})"
336
- end
337
- # Define a signal in the interface:
338
- dbus_signal :SomethingJustHappened, "toto:s, tutu:u"
339
- end
340
-
341
- dbus_interface "org.ruby.AnotherInterface" do
342
- dbus_method :ThatsALongMethodNameIThink, "in name:s, out ret:s" do |name|
343
- ["So your name is #{name}"]
344
- end
345
- end
346
- end
347
- </code></pre>
348
- <p>Triggering the signal is a easy as calling a method, but then this time on
349
- a local (exported) object and not on a remote/proxy object:</p>
350
- <pre><code>exported_obj.SomethingJustHappened("blah", 1)
351
- </code></pre>
352
- <p>Note that the <code>ThatsALongMethodNameIThink</code> method is returning a single
353
- value to the caller. Notice that you always have to return an array. If
354
- you want to return multiple values, just have an array with multiple
355
- values.</p>
356
- <h2>Replying with an error</h2>
357
- <p>To reply to a dbus_method with a D-Bus error, raise a <code>DBus::Error</code>,
358
- as constructed by the <code>error</code> convenience function:</p>
359
- <pre><code>raise DBus.error("org.example.Error.SeatOccupied"), "Seat #{seat} is occupied"
360
- </code></pre>
361
- <p>If the error name is not specified, the generic
362
- <code>org.freedesktop.DBus.Error.Failed</code> is used.</p>
363
- <pre><code>raise DBus.error, "Seat #{seat} is occupied"
364
- raise DBus.error
365
- </code></pre>
@@ -1,22 +0,0 @@
1
- #!/usr/bin/env ruby
2
- #
3
- # How to call overloaded methods.
4
-
5
- require 'dbus'
6
-
7
- bus = DBus::SessionmBus.instance
8
-
9
- konsole_svc = bus["org.freedesktop.konsole"]
10
- konsole_obj = konsole_svc["/Konsole"]
11
- poi = DBus::ProxyObjectInterface.new(konsole_obj, "org.kde.konsole.Konsole")
12
-
13
-
14
- begin
15
- poi.define_method("getDevices", "") # NM 0.6
16
- p poi.getDevices
17
- rescue Exception
18
- poi.define_method("GetDevices", "") # NM 0.7
19
- p poi.GetDevices
20
- end
21
-
22
-