#!/usr/bin/perl
use warnings;
use strict;
use POE qw(Wheel::SocketFactory Wheel::ReadWrite);
### Start the server session.  Map events to the functions that will
### handle them.  Run all the sessions until they stop, and then exit.
POE::Session->create(
  inline_states => {
    _start          => \&server_start,
    server_accepted => \&server_accepted,
    server_error    => \&server_error,
    client_input    => \&client_input,
    client_error    => \&client_error,
  }
);
POE::Kernel->run();
exit;
### Initialize the newly created server.  Create the server socket,
### and then create the wheel to listen on it and accept connections.
sub server_start {
  $_[HEAP]->{server} = POE::Wheel::SocketFactory->new(
    BindPort     => 12345,
    SuccessEvent => "server_accepted",
    FailureEvent => "server_error",
  );
}
### Handle new connections from the ListenAccept wheel.  Create
### ReadWrite wheels to interact with them.  Store them by each
### wheel's unique ID so they don't clobber each other.
sub server_accepted {
  my $client_socket = $_[ARG0];
  my $wheel         = POE::Wheel::ReadWrite->new(
    Handle     => $client_socket,
    InputEvent => "client_input",
    ErrorEvent => "client_error",
  );
  $_[HEAP]->{client}->{$wheel->ID()} = $wheel;
}
### Handle input from a ReadWrite wheel.  Echo it back to the client.
### Each wheel event comes with the wheel's ID, so we can match the
### input back to the wheel for resending.
sub client_input {
  my ($heap, $input, $wheel_id) = @_[HEAP, ARG0, ARG1];
  $heap->{client}->{$wheel_id}->put($input);
}
### Handle client errors.  Delete the ReadWrite wheel associated with
### the client.
sub client_error {
  my ($heap, $wheel_id) = @_[HEAP, ARG3];
  delete $heap->{client}->{$wheel_id};
}
### Handle server socket errors.  Delete the ListenAccept wheel,
### shutting down the server.
sub server_error {
  delete $_[HEAP]->{server};
}