This is a simple job server. It allows multiple clients to run jobs
on the server simultaneously. Clients' input is sent to their jobs
while they're running.
#!/usr/bin/perl
# http://poe.perl.org/?POE_Cookbook/Job_Server
use warnings;
use strict;
# Include POE, POE::Component::Server::TCP, and POE::Wheel::Run.
use POE qw(Component::Server::TCP Wheel::Run);
# The programs that are allowed to run, with their names.
my %programs = (
time => "/bin/date",
uptime => "/usr/bin/uptime",
ls => "/bin/ls /var/games/*",
echo => "/bin/cat -",
);
# Start a TCP server. The client will be presented with a list of
# valid commands. They can enter one command: that will execute, and
# its output will be sent back to the client. Then the server will
# close the connection.
POE::Component::Server::TCP->new(
Alias => "job_server",
Port => 32080,
# Send the client a list of available commands when it connects.
ClientConnected => sub {
$_[KERNEL]->yield("usage");
},
# Make sure the job is destroyed when the client exits.
ClientDisconnected => sub {
delete $_[HEAP]->{job};
},
# Process client input. When no job is running, accept input and
# try to spawn a new one. While a job is running, however, pass
# the client's input to it.
ClientInput => sub {
my ($heap, $input) = @_[HEAP, ARG0];
if ($heap->{job}) {
$heap->{job}->put($input);
return;
}
my $program = $programs{$input};
unless (defined $program) {
$_[KERNEL]->yield("usage");
return;
}
$heap->{job} = POE::Wheel::Run->new(
Program => $program,
StdioFilter => POE::Filter::Line->new(),
StderrFilter => POE::Filter::Line->new(),
StdoutEvent => "got_job_stdout",
StderrEvent => "got_job_stderr",
CloseEvent => "got_job_close",
);
$heap->{client}->put("Job " . $heap->{job}->PID . " started.");
},
# Inline states are custom event handlers. These add handlers for
# job output, job status, and a convenient usage message.
InlineStates => {
got_job_stdout => sub {
$_[HEAP]->{client}->put("out: $_[ARG0]");
},
got_job_stderr => sub {
$_[HEAP]->{client}->put("ERR: $_[ARG0]");
},
got_job_close => sub {
my ($kernel, $heap) = @_[KERNEL, HEAP];
my $job = delete $heap->{job};
$heap->{client}->put("Job " . $job->PID . " stopped.");
},
usage => sub {
my @commands = sort keys %programs;
$_[HEAP]->{client}->put("Commands: @commands");
},
},
);
# Run the server until it's done.
$poe_kernel->run();