ruby-dbus 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
-