File Coverage

blib/lib/PITA/Guest/Server.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 PITA::Guest::Server;
2              
3 1     1   2330 use 5.008;
  1         5  
  1         47  
4 1     1   5 use strict;
  1         3  
  1         42  
5 1     1   6 use Params::Util 1.00 ();
  1         26  
  1         22  
6 1     1   6071 use POE::Wheel::Run 1.299 ();
  0            
  0            
7             use POE::Declare::HTTP::Server 0.05 ();
8             use PITA::Guest::Server::HTTP ();
9              
10             our $VERSION = '0.60';
11              
12             use POE::Declare 0.58 {
13             Hostname => 'Param',
14             Port => 'Param',
15             Program => 'Param',
16             Uploads => 'Param',
17             Mirrors => 'Param',
18             StartupEvent => 'Message',
19             ShutdownEvent => 'Message',
20             pinged => 'Attribute',
21             uploaded => 'Attribute',
22             mirrored => 'Attribute',
23             status => 'Internal',
24             http => 'Internal',
25             child => 'Internal',
26             };
27              
28             use constant {
29             STOPPED => 1,
30             STARTING => 1,
31             RUNNING => 1,
32             STOPPING => 1,
33             };
34              
35              
36              
37              
38              
39             ######################################################################
40             # Constructor and Accessors
41              
42             sub new {
43             my $self = shift->SUPER::new(@_);
44              
45             # Set up tracking variables
46             $self->{status} = STOPPED;
47             $self->{pinged} = 0;
48             $self->{mirrored} = [ ];
49             $self->{uploaded} = [ ];
50              
51             # Check params
52             unless ( Params::Util::_ARRAY($self->Program) ) {
53             die "Missing or invalid 'Program' param";
54             }
55              
56             # Create the web server
57             $self->{http} = PITA::Guest::Server::HTTP->new(
58             Hostname => $self->Hostname,
59             Port => $self->Port,
60             Mirrors => $self->Mirrors,
61             StartupEvent => $self->lookback('http_startup_event'),
62             StartupError => $self->lookback('http_startup_error'),
63             ShutdownEvent => $self->lookback('http_shutdown_event'),
64             PingEvent => $self->lookback('http_ping'),
65             MirrorEvent => $self->lookback('http_mirror'),
66             UploadEvent => $self->lookback('http_upload'),
67             );
68              
69             return $self;
70             }
71              
72              
73              
74              
75              
76              
77              
78              
79              
80              
81             ######################################################################
82             # Main Methods
83              
84             # Sort of half-assed Process compatibility for testing purposes
85             sub run {
86             $_[0]->start;
87             POE::Kernel->run;
88             return 1;
89             }
90              
91             sub start {
92             my $self = shift;
93             unless ( $self->spawned ) {
94             $self->spawn;
95             $self->post('startup');
96             }
97             return 1;
98             }
99              
100             sub stop {
101             my $self = shift;
102             if ( $self->spawned ) {
103             $self->post('shutdown');
104             }
105             return 1;
106             }
107              
108              
109              
110              
111              
112             ######################################################################
113             # Event Methods
114              
115             sub startup : Event {
116             # Kick off the blanket startup timeout
117             $_[SELF]->{status} = STARTING;
118             $_[SELF]->startup_timeout_start;
119             $_[SELF]->post('http_startup');
120             }
121              
122             sub http_startup : Event {
123             $_[SELF]->{http}->start;
124             }
125              
126             sub http_startup_event : Event {
127             $_[SELF]->post('child_startup');
128             }
129              
130             sub http_startup_error : Event {
131             die "Failed to start the web server";
132             }
133              
134             sub http_shutdown_event : Event {
135             # Nothing to do?
136             }
137              
138             sub http_ping : Event {
139             $_[SELF]->startup_timeout_stop;
140             $_[SELF]->activity_timeout_start;
141             $_[SELF]->{status} = RUNNING;
142             $_[SELF]->{pinged} = 1;
143             $_[SELF]->StartupEvent;
144             }
145              
146             sub http_mirror : Event {
147             $_[SELF]->activity_timeout_start;
148             push @{$_[SELF]->{mirrored}}, [ $_[ARG1], $_[ARG2], $_[ARG3] ];
149             }
150              
151             sub http_upload : Event {
152             $_[SELF]->activity_timeout_start;
153             push @{$_[SELF]->{uploaded}}, [ $_[ARG1], $_[ARG2] ];
154              
155             # Do we have everything?
156             unless ( grep { not defined $_ } values %{$_[SELF]} ) {
157             $_[SELF]->{status} = STOPPING;
158             $_[SELF]->activity_timeout_stop;
159             $_[SELF]->shutdown_timeout_start;
160             }
161             }
162              
163             sub child_startup : Event {
164             # Spawn the program
165             $_[SELF]->{child} = POE::Wheel::Run->new(
166             Program => $_[SELF]->Program,
167             StdoutEvent => 'child_stdout',
168             StderrEvent => 'child_stderr',
169             CloseEvent => 'child_close',
170             );
171              
172             # Trap signals from the child as well.
173             # NOTE: This needs to be brought under the management of POE::Declare.
174             $_[KERNEL]->sig_child( $_[SELF]->{child}->PID => 'child_signal' );
175             }
176              
177             sub child_stdout : Event {
178             # Do nothing for now
179             # print STDERR "# CHILD STDOUT $_[ARG0]\n";
180             }
181              
182             sub child_stderr : Event {
183             # Do nothing for now
184             # print STDERR "# CHILD STDERR $_[ARG0]\n";
185             }
186              
187             sub child_close : Event {
188             # print STDERR "# CHILD CLOSE\n";
189             if ( $_[SELF]->{child} ) {
190             # Wait for a little to give the child time to SIGCHILD us
191             $_[SELF]->child_signal_timeout_start;
192             }
193             }
194              
195             sub child_signal : Event {
196             # print STDERR "# CHILD SIGCHILD $_[ARG2]\n";
197             $_[SELF]->child_signal_timeout_stop;
198             if ( $_[SELF]->{child} ) {
199             $_[SELF]->post('shutdown');
200             }
201             }
202              
203             sub child_signal_timeout : Timeout(5) {
204             if ( $_[SELF]->{child} ) {
205             $_[SELF]->post('shutdown');
206             }
207             }
208              
209             sub startup_timeout : Timeout(30) {
210             $_[SELF]->post('shutdown');
211             }
212              
213             sub activity_timeout : Timeout(3600) {
214             $_[SELF]->post('shutdown');
215             }
216              
217             sub shutdown_timeout : Timeout(60) {
218             $_[SELF]->post('shutdown');
219             }
220              
221             sub shutdown : Event {
222             $_[SELF]->finish;
223             $_[SELF]->ShutdownEvent(
224             $_[SELF]->pinged,
225             $_[SELF]->mirrored,
226             $_[SELF]->uploaded,
227             );
228             $_[SELF]->{status} = STOPPED;
229             }
230              
231              
232              
233              
234              
235             ######################################################################
236             # Support Methods
237              
238             sub finish {
239             my $self = shift;
240              
241             # Clean up our children
242             if ( $self->{child} ) {
243             $self->{child}->kill(9);
244             $self->{child} = undef;
245             }
246             if ( $self->{http}->spawned ) {
247             $self->{http}->call('shutdown');
248             }
249              
250             # Call parent method to clean out other things
251             $self->SUPER::finish(@_);
252             }
253              
254             compile;