File Coverage

blib/lib/TRD/Watch/Web.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 TRD::Watch::Web;
2              
3 1     1   31213 use warnings;
  1         3  
  1         37  
4 1     1   6 use strict;
  1         2  
  1         37  
5 1     1   7 use Carp;
  1         7  
  1         113  
6 1     1   3366 use threads ( 'exit' => 'threads_only' );
  0            
  0            
7             use Time::HiRes qw(sleep);
8             use TRD::DebugLog;
9             #$TRD::DebugLog::enabled = 1;
10              
11             use version;
12             our $VERSION = qv('0.0.4');
13              
14             # Other recommended modules (uncomment to use):
15             # use IO::Prompt;
16             # use Perl6::Export;
17             # use Perl6::Slurp;
18             # use Perl6::Say;
19              
20             our $default_timeout = 5; # sec
21             our $default_interval = 60; # sec
22              
23             #=======================================================================
24             sub new {
25             my $pkg = shift;
26             my $name = (@_) ? shift : '';
27             my $url = (@_) ? shift : undef;
28             my $errfunc = (@_) ? shift : undef;
29             my $recoverfunc = (@_) ? shift : undef;
30             my $checkfunc = (@_) ? shift : undef;
31             my $timeout = (@_) ? shift : $default_timeout;
32             my $interval = (@_) ? shift : $default_interval;
33              
34             bless {
35             name => $name,
36             url => $url,
37             errfunc => $errfunc,
38             recoverfunc => $recoverfunc,
39             checkfunc => $checkfunc,
40             timeout => $timeout,
41             interval => $interval,
42             pid => undef,
43             start => 0,
44             }, $pkg;
45             }
46              
47             #=======================================================================
48             sub setName
49             {
50             my $self = shift;
51             my $name = (@_) ? shift : '';
52             $self->{'name'} = $name;
53             if( $self->{'start'} ){
54             $self->stop;
55             $self->start;
56             }
57             }
58              
59             #=======================================================================
60             sub setUrl
61             {
62             my $self = shift;
63             my $url = (@_) ? shift : undef;
64             $self->{'url'} = $url;
65             if( $self->{'start'} ){
66             $self->stop;
67             $self->start;
68             }
69             }
70              
71             #=======================================================================
72             sub setTimeout
73             {
74             my $self = shift;
75             my $timeout = (@_) ? shift : $default_timeout;
76             $self->{'timeout'} = $timeout;
77             if( $self->{'start'} ){
78             $self->stop;
79             $self->start;
80             }
81             }
82              
83             #=======================================================================
84             sub setInterval
85             {
86             my $self = shift;
87             my $interval = (@_) ? shift : $default_interval;
88             $self->{'interval'} = $interval;
89             if( $self->{'start'} ){
90             $self->stop;
91             $self->start;
92             }
93             }
94              
95             #=======================================================================
96             sub setErrorFunc
97             {
98             my $self = shift;
99             my $errfunc = (@_) ? shift : undef;
100             $self->{'errfunc'} = $errfunc;
101             if( $self->{'start'} ){
102             $self->stop;
103             $self->start;
104             }
105             }
106              
107             #=======================================================================
108             sub setRecoverFunc
109             {
110             my $self = shift;
111             my $func = (@_) ? shift : undef;
112             $self->{'recoverfunc'} = $func;
113             if( $self->{'start'} ){
114             $self->stop;
115             $self->start;
116             }
117             }
118              
119             #=======================================================================
120             sub setCheckFunc
121             {
122             my $self = shift;
123             my $func = (@_) ? shift : undef;
124             $self->{'checkfunc'} = $func;
125             if( $self->{'start'} ){
126             $self->stop;
127             $self->start;
128             }
129             }
130              
131             #=======================================================================
132             sub start
133             {
134             my $self = shift;
135              
136             my $stat = 1;
137             if( $self->{'start'} ){
138             dlog( "already started." );
139             } else {
140             my $pid = threads->new( \&web_thread, $self );
141             $self->{'pid'} = $pid;
142             $self->{'start'} = 1;
143             $stat = 0;
144             }
145             return $stat;
146             }
147              
148             #=======================================================================
149             sub stop
150             {
151             my $self = shift;
152              
153             my $stat = 1;
154             if( !$self->{'start'} ){
155             dlog( "already stoped." );
156             } else {
157             $self->{'pid'}->kill('KILL')->detach();
158             $self->{'pid'} = undef;
159             $self->{'start'} = 0;
160             $stat = 0;
161             }
162             return $stat;
163             }
164              
165             #=======================================================================
166             sub web_thread
167             {
168             my $self = shift;
169             my $stat = 1;
170             my $old_stat = undef;
171              
172             $SIG{'KILL'} = sub { threads->exit(); };
173              
174             while( 1 ){
175             my $pid = threads->new( \&web, $self );
176             my $t = 0;
177             while( 1 ){
178             if( $pid->is_running ){
179             $stat = 1;
180             } else {
181             $stat = $pid->join();
182             last;
183             }
184             if( $t > $self->{'timeout'} ){
185             $pid->kill('KILL')->detach();
186             $stat = 1;
187             last;
188             }
189             sleep( 0.1 );
190             $t += 0.1;
191             }
192             if( defined( $old_stat ) ){
193             if( $old_stat != $stat ){
194             my $func = undef;
195             if( $stat ){
196             $func = $self->{'errfunc'};
197             } else {
198             $func = $self->{'recoverfunc'};
199             }
200             if( ref( $func ) eq 'CODE' ){
201             &{$func}( $self->{'name'}, $self->{'url'} );
202             }
203             }
204             }
205             $old_stat = $stat;
206             sleep( $self->{'interval'} - $t );
207             }
208              
209             return $stat;
210             }
211              
212             #=======================================================================
213             sub web
214             {
215             my $self = shift;
216             dlog( "<<< ". $self->{'url'} );
217             $SIG{'KILL'} = sub { threads->exit(); };
218              
219             my $stat = 1;
220              
221             if( !$self->{'url'} ){
222             $stat = 1;
223             } else {
224             my $cmd = 'wget -q --timeout=5 -O - -nd '. $self->{'url'};
225             my $res = `${cmd}`;
226              
227             my $func = $self->{'checkfunc'};
228             if( ref( $func ) eq 'CODE' ){
229             $stat = &{$func}( $self->{'name'}, $self->{'url'}, $res );
230             } else {
231             if( $res =~m/OK/ ){
232             $stat = 0;
233             } else {
234             $stat = 1;
235             }
236             }
237             }
238             dlog( ">>> ". $stat );
239             return $stat;
240             }
241              
242             1; # Magic true value required at end of module
243             __END__
244              
245             =head1 NAME
246              
247             TRD::Watch::Web - [One line description of module's purpose here]
248              
249              
250             =head1 VERSION
251              
252             This document describes TRD::Watch::Web version 0.0.1
253              
254              
255             =head1 SYNOPSIS
256              
257             use TRD::Watch::Web;
258              
259             =for author to fill in:
260             Brief code example(s) here showing commonest usage(s).
261             This section will be as far as many users bother reading
262             so make it as educational and exeplary as possible.
263            
264            
265             =head1 DESCRIPTION
266              
267             =for author to fill in:
268             Write a full description of the module and its features here.
269             Use subsections (=head2, =head3) as appropriate.
270              
271              
272             =head1 INTERFACE
273              
274             =for author to fill in:
275             Write a separate section listing the public components of the modules
276             interface. These normally consist of either subroutines that may be
277             exported, or methods that may be called on objects belonging to the
278             classes provided by the module.
279              
280              
281             =head1 DIAGNOSTICS
282              
283             =for author to fill in:
284             List every single error and warning message that the module can
285             generate (even the ones that will "never happen"), with a full
286             explanation of each problem, one or more likely causes, and any
287             suggested remedies.
288              
289             =over
290              
291             =item C<< Error message here, perhaps with %s placeholders >>
292              
293             [Description of error here]
294              
295             =item C<< Another error message here >>
296              
297             [Description of error here]
298              
299             [Et cetera, et cetera]
300              
301             =back
302              
303              
304             =head1 CONFIGURATION AND ENVIRONMENT
305              
306             =for author to fill in:
307             A full explanation of any configuration system(s) used by the
308             module, including the names and locations of any configuration
309             files, and the meaning of any environment variables or properties
310             that can be set. These descriptions must also include details of any
311             configuration language used.
312            
313             TRD::Watch::Web requires no configuration files or environment variables.
314              
315              
316             =head1 DEPENDENCIES
317              
318             =for author to fill in:
319             A list of all the other modules that this module relies upon,
320             including any restrictions on versions, and an indication whether
321             the module is part of the standard Perl distribution, part of the
322             module's distribution, or must be installed separately. ]
323              
324             None.
325              
326              
327             =head1 INCOMPATIBILITIES
328              
329             =for author to fill in:
330             A list of any modules that this module cannot be used in conjunction
331             with. This may be due to name conflicts in the interface, or
332             competition for system or program resources, or due to internal
333             limitations of Perl (for example, many modules that use source code
334             filters are mutually incompatible).
335              
336             None reported.
337              
338              
339             =head1 BUGS AND LIMITATIONS
340              
341             =for author to fill in:
342             A list of known problems with the module, together with some
343             indication Whether they are likely to be fixed in an upcoming
344             release. Also a list of restrictions on the features the module
345             does provide: data types that cannot be handled, performance issues
346             and the circumstances in which they may arise, practical
347             limitations on the size of data sets, special cases that are not
348             (yet) handled, etc.
349              
350             No bugs have been reported.
351              
352             Please report any bugs or feature requests to
353             C<bug-trd-watch-web@rt.cpan.org>, or through the web interface at
354             L<http://rt.cpan.org>.
355              
356              
357             =head1 AUTHOR
358              
359             Takuya Ichikawa C<< <ichi@cpan.org> >>
360              
361              
362             =head1 LICENCE AND COPYRIGHT
363              
364             Copyright (c) 2009, Takuya Ichikawa C<< <ichi@cpan.org> >>. All rights reserved.
365              
366             This module is free software; you can redistribute it and/or
367             modify it under the same terms as Perl itself. See L<perlartistic>.
368              
369              
370             =head1 DISCLAIMER OF WARRANTY
371              
372             BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
373             FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
374             OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
375             PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
376             EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
377             WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
378             ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
379             YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
380             NECESSARY SERVICING, REPAIR, OR CORRECTION.
381              
382             IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
383             WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
384             REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
385             LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
386             OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
387             THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
388             RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
389             FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
390             SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
391             SUCH DAMAGES.