File Coverage

blib/lib/AnyEvent/DBus.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
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 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 into L. It does this by quite brutally
29             hacking L 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, 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 so 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 1     1   2014 use common::sense;
  1         10  
  1         5  
90              
91 1     1   1973 use AnyEvent ();
  1         6071  
  1         23  
92 1     1   1584 use Net::DBus ();
  0            
  0            
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, L.
177              
178             =head1 AUTHOR
179              
180             Marc Lehmann
181             http://home.schmorp.de/
182              
183             =cut
184              
185             1