File Coverage

blib/lib/POE/Component/Daemon/Win32.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package POE::Component::Daemon::Win32;
2            
3 1     1   7151 use strict;
  1         2  
  1         32  
4 1     1   6 use Carp;
  1         2  
  1         50  
5 1     1   4 use Exporter;
  1         5  
  1         31  
6 1     1   1576 use Win32::Daemon;
  0            
  0            
7             use POE;
8            
9             use vars qw( $VERSION @ISA @EXPORT %SERVICE_STATES );
10            
11             use constant DEFAULT_ALIAS => 'win32daemon';
12             use constant DEFAULT_POLL_INTERVAL => 1;
13             use constant DEFAULT_SHUTDOWN_DELAY => 30 * 1000;
14            
15             @ISA = qw( Exporter );
16             @EXPORT = @Win32::Daemon::EXPORT;
17             $VERSION = '0.01';
18             %SERVICE_STATES = (
19             not_ready => SERVICE_NOT_READY,
20             stopped => SERVICE_STOPPED,
21             running => SERVICE_RUNNING,
22             paused => SERVICE_PAUSED,
23             start_pending => SERVICE_START_PENDING,
24             stop_pending => SERVICE_STOP_PENDING,
25             continue_pending => SERVICE_CONTINUE_PENDING,
26             pause_pending => SERVICE_PAUSE_PENDING
27             );
28            
29             sub spawn {
30            
31             my ($class, %args) = @_;
32            
33             $args{'Alias'} ||= DEFAULT_ALIAS;
34             $args{'PollInterval'} ||= DEFAULT_POLL_INTERVAL;
35            
36             my %callback;
37            
38             unless (defined $args{'Callback'}) {
39            
40             croak 'POE::Component::Daemon::Win32 "Callback" parameter missing';
41            
42             }
43            
44             if (ref $args{'Callback'} eq 'HASH') {
45            
46             %callback = %{$args{'Callback'}};
47            
48             } elsif (ref $args{'Callback'} eq 'CODE') {
49            
50             %callback = map { $_ => $args{'Callback'} } ('shutdown', keys %SERVICE_STATES);
51            
52             } else {
53            
54             croak 'POE::Component::Daemon::Win32 "Callback" parameter must be a HASHREF or CODEREF';
55            
56             }
57            
58             POE::Session->create (
59             inline_states => {
60             _start => \&_start,
61             _stop => \&_stop,
62             shutdown => \&shutdown,
63             poll => \&poll,
64             state => \&state,
65             next_state => \&next_state,
66            
67             service_not_ready => \&service_not_ready,
68             service_running => \&service_running,
69             service_paused => \&service_paused,
70             service_start_pending => \&service_start_pending,
71             service_stop_pending => \&service_stop_pending,
72             service_pause_pending => \&service_pause_pending,
73             service_continue_pending => \&service_continue_pending,
74             service_stopped => \&service_stopped,
75             service_unhandled => \&service_unhandled,
76             service_shutdown => \&service_shutdown
77            
78             }, args => [ @args{qw( Alias PollInterval )}, \%callback ]
79             );
80            
81             $args{'Alias'};
82            
83             }
84            
85             sub _start {
86            
87             my ($kernel, $heap, $session, $alias, $poll_interval, $callback)
88             = @_[KERNEL, HEAP, SESSION, ARG0..ARG2]
89             ;
90             $heap->{'Alias'} = $alias;
91             $heap->{'PollInterval'} = $poll_interval;
92             $heap->{'Callback'} = $callback;
93             $kernel->alias_set ($alias);
94             $heap->{'last_state'} = SERVICE_START_PENDING;
95             Win32::Daemon::StartService();
96             $kernel->delay (poll => $heap->{'PollInterval'});
97            
98             }
99            
100             sub _stop {}
101            
102             sub poll {
103            
104             my ($kernel, $heap) = @_[KERNEL, HEAP];
105             my $state = Win32::Daemon::State();
106            
107             if (SERVICE_RUNNING == $state) {
108            
109             $kernel->yield ('service_running', $state);
110            
111             } elsif (SERVICE_NOT_READY) {
112            
113             $kernel->yield ('service_not_ready', $state);
114            
115             } elsif (SERVICE_START_PENDING == $state) {
116            
117             $kernel->yield ('service_start_pending', $state);
118            
119             } elsif (SERVICE_STOP_PENDING == $state) {
120            
121             $kernel->yield ('service_stop_pending', $state);
122            
123             } elsif (SERVICE_PAUSE_PENDING == $state) {
124            
125             $kernel->yield ('service_pause_pending', $state);
126            
127             } elsif (SERVICE_CONTINUE_PENDING == $state) {
128            
129             $kernel->yield ('service_continue_pending', $state);
130            
131             } elsif (SERVICE_PAUSED == $state) {
132            
133             $kernel->yield ('service_paused', $state);
134            
135             } elsif (SERVICE_STOPPED == $state) {
136            
137             $kernel->yield ('service_stopped', $state);
138            
139             } else {
140            
141             $kernel->yield ('service_unhandled', $state);
142            
143             }
144            
145             if (SERVICE_CONTROL_NONE != (
146             my $message = Win32::Daemon::QueryLastMessage (1)
147             )) {
148            
149             if (SERVICE_CONTROL_INTERROGATE == $message) {
150            
151             $kernel->yield ('state', $heap->{'last_state'});
152            
153             } elsif (SERVICE_CONTROL_SHUTDOWN == $message) {
154            
155             $kernel->yield ('service_shutdown', $state, $message);
156            
157             }
158            
159             }
160            
161             $kernel->delay (poll => $heap->{'PollInterval'});
162            
163             }
164            
165             sub shutdown {
166            
167             my ($kernel, $heap) = @_[KERNEL, HEAP];
168             $kernel->alias_remove ($heap->{'Alias'});
169             $kernel->alarm_remove_all;
170            
171             }
172            
173             sub state {
174            
175             my ($kernel, $heap, $state) = @_[KERNEL, HEAP, ARG0];
176            
177             if (scalar @_ > ARG0) {
178            
179             my $href;
180            
181             if (ref $state eq 'HASH') {
182            
183             $href = $state;
184             $state = $href->{'state'};
185            
186             }
187            
188             $state = $SERVICE_STATES{$state} unless $state =~ /^\d+$/;
189             Win32::Daemon::State ($href || $state);
190             $heap->{'last_state'} = $state
191             if $state == SERVICE_RUNNING
192             || $state == SERVICE_PAUSED
193             || $state == SERVICE_STOPPED
194             ;
195            
196             } else {
197            
198             $state = Win32::Daemon::State();
199            
200             }
201            
202             $state;
203            
204             }
205            
206             sub next_state {
207            
208             my ($kernel, $heap, $delay) = @_[KERNEL, HEAP, ARG0];
209             my $state = Win32::Daemon::State();
210             my $message = Win32::Daemon::QueryLastMessage (1);
211             my $next_state;
212            
213             return if $state == SERVICE_RUNNING
214             || $state == SERVICE_NOT_READY
215             || $state == SERVICE_PAUSED
216             || $state == SERVICE_STOPPED
217             ;
218            
219             if ($state == SERVICE_START_PENDING) {
220            
221             $next_state = SERVICE_RUNNING;
222            
223             } elsif ($state == SERVICE_PAUSE_PENDING) {
224            
225             $next_state = SERVICE_PAUSED;
226            
227             } elsif ($state == SERVICE_CONTINUE_PENDING) {
228            
229             $next_state = SERVICE_RUNNING;
230            
231             } elsif ($state == SERVICE_STOP_PENDING) {
232            
233             $next_state = SERVICE_STOPPED;
234            
235             } elsif ($message == SERVICE_CONTROL_SHUTDOWN) {
236            
237             $next_state = SERVICE_STOP_PENDING;
238            
239             $kernel->yield (state => {
240             state => $next_state,
241             waithint => $delay || DEFAULT_SHUTDOWN_DELAY
242             });
243             return;
244            
245             } else {
246            
247             return unless defined $heap->{'last_state'};
248             $next_state = $heap->{'last_state'};
249            
250             }
251            
252             $kernel->yield (state => $next_state);
253            
254             }
255            
256             # callbacks
257            
258             sub service_not_ready {
259            
260             my ($kernel, $heap) = @_[KERNEL, HEAP];
261            
262             if (my $callback = $heap->{'Callback'}->{'not_ready'}) {
263            
264             $callback->(@_);
265            
266             }
267            
268             }
269            
270             sub service_start_pending {
271            
272             my ($kernel, $heap) = @_[KERNEL, HEAP];
273            
274             if (my $callback = $heap->{'Callback'}->{'start_pending'}) {
275            
276             $callback->(@_);
277            
278             } else {
279            
280             $kernel->yield ('next_state');
281            
282             }
283            
284             }
285            
286             sub service_stop_pending {
287            
288             my ($kernel, $heap) = @_[KERNEL, HEAP];
289            
290             if (my $callback = $heap->{'Callback'}->{'stop_pending'}) {
291            
292             $callback->(@_);
293            
294             } else {
295            
296             $kernel->yield ('next_state');
297            
298             }
299            
300             }
301            
302             sub service_pause_pending {
303            
304             my ($kernel, $heap) = @_[KERNEL, HEAP];
305            
306             if (my $callback = $heap->{'Callback'}->{'pause_pending'}) {
307            
308             $callback->(@_);
309            
310             } else {
311            
312             $kernel->yield ('next_state');
313            
314             }
315            
316             }
317            
318             sub service_continue_pending {
319            
320             my ($kernel, $heap) = @_[KERNEL, HEAP];
321            
322             if (my $callback = $heap->{'Callback'}->{'continue_pending'}) {
323            
324             $callback->(@_);
325            
326             } else {
327            
328             $kernel->yield ('next_state');
329            
330             }
331            
332             }
333            
334             sub service_running {
335            
336             my ($kernel, $heap) = @_[KERNEL, HEAP];
337            
338             if (my $callback = $heap->{'Callback'}->{'running'}) {
339            
340             $callback->(@_);
341            
342             }
343            
344             }
345            
346             sub service_stopped {
347            
348             my ($kernel, $heap) = @_[KERNEL, HEAP];
349            
350             if (my $callback = $heap->{'Callback'}->{'stopped'}) {
351            
352             $callback->(@_);
353            
354             }
355            
356             Win32::Daemon::StopService();
357             $kernel->yield ('shutdown');
358            
359             }
360            
361             sub service_paused {
362            
363             my ($kernel, $heap) = @_[KERNEL, HEAP];
364            
365             if (my $callback = $heap->{'Callback'}->{'paused'}) {
366            
367             $callback->(@_);
368            
369             }
370            
371             }
372            
373             sub service_unhandled {
374            
375             my ($kernel, $heap) = @_[KERNEL, HEAP];
376            
377             if (my $callback = $heap->{'Callback'}->{'unhandled'}) {
378            
379             $callback->(@_);
380            
381             } else {
382            
383             $kernel->yield ('next_state');
384            
385             }
386            
387             }
388            
389             sub service_shutdown {
390            
391             my ($kernel, $heap) = @_[KERNEL, HEAP];
392            
393             if (my $callback = $heap->{'Callback'}->{'shutdown'}) {
394            
395             $callback->(@_);
396            
397             } else {
398            
399             $kernel->yield ('next_state');
400            
401             }
402            
403             }
404            
405             1;
406             __END__