ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-DBus/DBus.pm
Revision: 1.5
Committed: Mon Jun 21 10:24:44 2010 UTC (13 years, 10 months ago) by root
Branch: MAIN
CVS Tags: rel-0_3
Changes since 1.4: +14 -3 lines
Log Message:
0.3

File Contents

# Content
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
35 see Net::DBus::Annoation, specifically dbus_call_async) and c) this
36 module only implements the minimum API required to make Net::DBus work -
37 Net::DBus unfortunately has no nice hooking API.
38
39 However, unlike L<Net::DBus::Reactor>, this module should be fully
40 non-blocking as long as you only use non-blocking APIs (Net::DBus::Reactor
41 blocks on writes). It should also be faster, but Net::DBus is such a
42 morass os unneeded method calls that speed won't matter much...
43
44 =head2 EXAMPLE
45
46 Here is a simple example. Both work with AnyEvent::DBus and do the same
47 thing, but only the second is actually non-blocking.
48
49 Example 1: list registered named, blocking version.
50
51 use AnyEvent::DBus;
52
53 my $conn = Net::DBus->find;
54 my $bus = $conn->get_bus_object;
55
56 for my $name (@{ $bus->ListNames }) {
57 print " $name\n";
58 }
59
60 Example 1: list registered named, somewhat non-blocking version.
61
62 use AnyEvent;
63 use AnyEvent::DBus;
64 use Net::DBus::Annotation qw(:call);
65
66 my $conn = Net::DBus->find; # always blocks :/
67 my $bus = $conn->get_bus_object;
68
69 my $quit = AE::cv;
70
71 # the trick here is to prepend dbus_call_async to any method
72 # arguments and then to call the set_notify method on the
73 # returned Net::DBus::AsyncReply object
74
75 $bus->ListNames (dbus_call_async)->set_notify (sub {
76 for my $name (@{ $_[0]->get_result }) {
77 print " $name\n";
78 }
79 $quit->send;
80 });
81
82 $quit->recv;
83
84 =cut
85
86 package AnyEvent::DBus;
87
88 use common::sense;
89
90 use AnyEvent ();
91 use Net::DBus ();
92 use Net::DBus::Binding::Watch ();
93
94 our $VERSION = '0.3';
95
96 # yup, Net::DBus checks by using exists on %INC...
97 $INC{'Net/DBus/Reactor.pm'} = undef;
98
99 # claim we are the main reactor mainloop
100 *Net::DBus::Reactor::main = sub { __PACKAGE__ };
101
102 our $I = 0;
103 our %O; # watchers and timers, unfortunately, dbus only supports attaching integers...
104
105 sub watch_off {
106 delete $O{$_[1]->get_data};
107 }
108
109 sub io_toggle {
110 my ($con, $w) = @_;
111
112 my $id = $w->get_data;
113 my $f = $w->get_flags;
114 my $fd = $w->get_fileno;
115 my $on = $w->is_enabled;
116
117 $f & Net::DBus::Binding::Watch::READABLE ()
118 and
119 $O{$id}[0] = $on && AE::io $fd, 0, sub {
120 $w->handle (Net::DBus::Binding::Watch::READABLE ());
121 $con->dispatch; # wtf., we tell it data is ready, but have to call dispatch ourselves???
122 };
123
124 $f & Net::DBus::Binding::Watch::WRITABLE ()
125 and
126 $O{$id}[1] = $on && AE::io $fd, 1, sub {
127 $w->handle (Net::DBus::Binding::Watch::WRITABLE ());
128 # calling flush, as NEt::DBus::Reactor does, is blocking :/
129 };
130 }
131
132 sub io_on {
133 my ($con, $w) = @_;
134
135 my $id = ++$I;
136 $w->set_data ($id);
137
138 &io_toggle;
139 }
140
141 sub timeout_toggle {
142 my ($con, $w) = @_;
143
144 my $id = $w->get_data;
145 my $i = $w->get_interval * 0.001;
146
147 $O{$id} = $w->is_enabled && AE::timer $i, $i, sub { $w->handle };
148 }
149
150 sub timeout_on {
151 my ($con, $w) = @_;
152 my $id = ++$I;
153 $w->set_data ($id);
154
155 &timeout_toggle;
156 }
157
158 sub manage {
159 my (undef, $con) = @_;
160
161 $con->set_watch_callbacks (\&io_on, \&watch_off, \&io_toggle);
162 # if $con->can ("set_watch_callbacks");
163
164 $con->set_timeout_callbacks (\&timeout_on, \&watch_off, \&timeout_toggle);
165 # if $con->can ("set_timeout_callbacks");
166 }
167
168 =head1 SEE ALSO
169
170 L<AnyEvent>, L<Net::DBus>.
171
172 =head1 AUTHOR
173
174 Marc Lehmann <schmorp@schmorp.de>
175 http://home.schmorp.de/
176
177 =cut
178
179 1