1 |
=head1 NAME |
2 |
|
3 |
AnyEvent::DBus - adapt Net::DBus to AnyEvent |
4 |
|
5 |
=head1 SYNOPSIS |
6 |
|
7 |
use AnyEvent::DBus; |
8 |
|
9 |
# now use the Net::DBus API, preferably the non-blocking variants: |
10 |
|
11 |
use Net::DBus::Annotation qw(:call); |
12 |
|
13 |
$bus->get_object (...) |
14 |
->Method (dbus_call_async, $arg1, ...) |
15 |
->set_notify (sub { |
16 |
my @data = $_[0]->get_result |
17 |
... |
18 |
}); |
19 |
|
20 |
$bus->get_connection->send (...); |
21 |
|
22 |
=head1 DESCRIPTION |
23 |
|
24 |
This module is an L<AnyEvent> user, you need to make sure that you use and |
25 |
run a supported event loop. |
26 |
|
27 |
Loading this module will install the necessary magic to seamlessly |
28 |
integrate L<Net::DBus> into L<AnyEvent>. It does this by quite brutally |
29 |
hacking L<Net::DBus::Reactor> so that all dbus connections created after |
30 |
loading this module will automatically be managed by this module. |
31 |
|
32 |
Note that a) a lot inside Net::DBus is still blocking b) if you call a |
33 |
method that blocks, you again block your process (basically anything |
34 |
but calls to the Net::DBus::Binding::Connection objects block, but see |
35 |
Net::DBus::Annoation, specifically dbus_call_async) c) the underlying |
36 |
libdbus is often blocking itself, even with infinite timeouts and d) this |
37 |
module only implements the minimum API required to make Net::DBus work - |
38 |
Net::DBus unfortunately has no nice hooking API. |
39 |
|
40 |
However, unlike L<Net::DBus::Reactor>, this module should be fully |
41 |
non-blocking as long as you only use non-blocking APIs (Net::DBus::Reactor |
42 |
blocks on writes). It should also be faster, but Net::DBus is such a |
43 |
morass of unneeded method calls that speed won't matter much... |
44 |
|
45 |
=head2 EXAMPLE |
46 |
|
47 |
Here is a simple example. Both work with AnyEvent::DBus and do the same |
48 |
thing, but only the second is actually non-blocking. |
49 |
|
50 |
Example 1: list registered named, blocking version. |
51 |
|
52 |
use AnyEvent::DBus; |
53 |
|
54 |
my $conn = Net::DBus->find; |
55 |
my $bus = $conn->get_bus_object; |
56 |
|
57 |
for my $name (@{ $bus->ListNames }) { |
58 |
print " $name\n"; |
59 |
} |
60 |
|
61 |
Example 1: list registered named, somewhat non-blocking version. |
62 |
|
63 |
use AnyEvent; |
64 |
use AnyEvent::DBus; |
65 |
use Net::DBus::Annotation qw(:call); |
66 |
|
67 |
my $conn = Net::DBus->find; # always blocks :/ |
68 |
my $bus = $conn->get_bus_object; |
69 |
|
70 |
my $quit = AE::cv; |
71 |
|
72 |
# the trick here is to prepend dbus_call_async to any method |
73 |
# arguments and then to call the set_notify method on the |
74 |
# returned Net::DBus::AsyncReply object |
75 |
|
76 |
$bus->ListNames (dbus_call_async)->set_notify (sub { |
77 |
for my $name (@{ $_[0]->get_result }) { |
78 |
print " $name\n"; |
79 |
} |
80 |
$quit->send; |
81 |
}); |
82 |
|
83 |
$quit->recv; |
84 |
|
85 |
=cut |
86 |
|
87 |
package AnyEvent::DBus; |
88 |
|
89 |
use common::sense; |
90 |
|
91 |
use AnyEvent (); |
92 |
use Net::DBus (); |
93 |
use Net::DBus::Binding::Watch (); |
94 |
|
95 |
our $VERSION = '0.31'; |
96 |
|
97 |
# yup, Net::DBus checks by using exists on %INC... |
98 |
$INC{'Net/DBus/Reactor.pm'} = undef; |
99 |
|
100 |
# claim we are the main reactor mainloop |
101 |
*Net::DBus::Reactor::main = sub { __PACKAGE__ }; |
102 |
|
103 |
our $I = 0; |
104 |
our %O; # watchers and timers, unfortunately, dbus only supports attaching integers... |
105 |
|
106 |
sub watch_off { |
107 |
delete $O{$_[1]->get_data}; |
108 |
} |
109 |
|
110 |
sub io_toggle { |
111 |
my ($con, $w) = @_; |
112 |
|
113 |
my $id = $w->get_data; |
114 |
my $f = $w->get_flags; |
115 |
my $fd = $w->get_fileno; |
116 |
my $on = $w->is_enabled; |
117 |
|
118 |
$f & Net::DBus::Binding::Watch::READABLE () |
119 |
and |
120 |
$O{$id}[0] = $on && AE::io $fd, 0, sub { |
121 |
$w->handle (Net::DBus::Binding::Watch::READABLE ()); |
122 |
$con->dispatch; |
123 |
}; |
124 |
|
125 |
$f & Net::DBus::Binding::Watch::WRITABLE () |
126 |
and |
127 |
$O{$id}[1] = $on && AE::io $fd, 1, sub { |
128 |
$w->handle (Net::DBus::Binding::Watch::WRITABLE ()); |
129 |
$con->dispatch; |
130 |
}; |
131 |
} |
132 |
|
133 |
sub io_on { |
134 |
my ($con, $w) = @_; |
135 |
|
136 |
my $id = ++$I; |
137 |
$w->set_data ($id); |
138 |
|
139 |
&io_toggle; |
140 |
} |
141 |
|
142 |
sub timeout_toggle { |
143 |
my ($con, $w) = @_; |
144 |
|
145 |
my $id = $w->get_data; |
146 |
my $i = $w->get_interval * 0.001; |
147 |
|
148 |
$O{$id} = $w->is_enabled && AE::timer $i, $i, sub { |
149 |
$w->handle; |
150 |
$con->dispatch; |
151 |
}; |
152 |
} |
153 |
|
154 |
sub timeout_on { |
155 |
my ($con, $w) = @_; |
156 |
my $id = ++$I; |
157 |
$w->set_data ($id); |
158 |
|
159 |
&timeout_toggle; |
160 |
} |
161 |
|
162 |
sub manage { |
163 |
my (undef, $con) = @_; |
164 |
|
165 |
$con->set_watch_callbacks (\&io_on, \&watch_off, \&io_toggle); |
166 |
# if $con->can ("set_watch_callbacks"); |
167 |
|
168 |
$con->set_timeout_callbacks (\&timeout_on, \&watch_off, \&timeout_toggle); |
169 |
# if $con->can ("set_timeout_callbacks"); |
170 |
|
171 |
$con->dispatch; # for good measure |
172 |
} |
173 |
|
174 |
=head1 SEE ALSO |
175 |
|
176 |
L<AnyEvent>, L<Net::DBus>. |
177 |
|
178 |
=head1 AUTHOR |
179 |
|
180 |
Marc Lehmann <schmorp@schmorp.de> |
181 |
http://home.schmorp.de/ |
182 |
|
183 |
=cut |
184 |
|
185 |
1 |