ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-DBus/DBus.pm
Revision: 1.9
Committed: Sun Aug 14 13:22:52 2022 UTC (20 months, 2 weeks ago) by root
Branch: MAIN
CVS Tags: HEAD
Changes since 1.8: +1 -1 lines
Log Message:
*** empty log message ***

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 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