Fetching contributors…
Cannot retrieve contributors at this time
200 lines (147 sloc) 4.54 KB
# A simple socket client. Generic enough to be used for INET and UNIX
# sockets, although we may need to specialize for each kind later.
# TODO - This is a simple strawman implementation. It needs
# refinement.
package Reflex::Client;
# vim: ts=2 sw=2 noexpandtab
use Moose;
use Reflex::Stream;
extends 'Reflex::Connector';
with 'Reflex::Role::Collectible';
use Reflex::Trait::Watched qw(watches);
has protocol => (
is => 'rw',
isa => 'Str',
default => 'Reflex::Stream',
watches connection => (
isa => 'Maybe[Reflex::Stream]',
# Maps $self->put() to $self->connection()->put().
# TODO - Would be nice to have something like this for outbout
# events. See on_connection_data() later in this module for more.
handles => ['put'],
sub on_connection {
my ($self, $socket) = @_;
handle => $socket->handle(),
rd => 1,
$self->emit( -name => "connected" );
#$self->re_emit( $socket, -name => "connected" );
sub on_error {
my ($self, $error) = @_;
# TODO - Emit rather than warn.
warn $error->formatted(), "\n";
sub on_connection_closed {
my ($self, $eof) = @_;
# TODO - Emit rather than warn.
warn "server closed connection.\n";
sub on_connection_failure {
my ($self, $error) = @_;
# TODO - Emit rather than warn.
warn $error->formatted(), "\n";
# This odd construct lets us rethrow a low-level event as a
# higher-level event. It's similar to the way Moose "handles" works,
# although in the other (outbound) direction.
# TODO - It's rather inefficient to rethrow like this at runtime.
# Some compile- or init-time remapping construct would be better.
# TODO - While we're rethrowing, we should consider a generic facility
# for passing -type through.
sub on_connection_data {
my ($self, $data) = @_;
$self->re_emit( $data, -name => "data" );
sub stop {
my $self = shift();
=for Pod::Coverage on_connection_closed on_connection_data on_connection_failure stop
=head1 NAME
Reflex::Client - A non-blocking socket client.
This is a complete working TCP echo client. It's the version of
eg/ available at the time of this writing.
use lib qw(../lib);
package TcpEchoClient;
use Moose;
extends 'Reflex::Client';
sub on_client_connected {
my ($self, $event) = @_;
$self->connection()->put("Hello, world!\n");
sub on_client_data {
my ($self, $event) = @_;
# Not chomped.
warn "got from server: ", $event->data();
# Disconnect after we receive the echo.
remote_addr => '',
remote_port => 12345,
Reflex::Client is scheduled for substantial changes. One of its base
classes, Reflex::Handle, will be deprecated in favor of
Reflex::Role::Readable and Reflex::Role::Writable. Hopefully
Reflex::Client's interfaces won't change much as a result, but
there are no guarantees.
Your ideas and feedback for Reflex::Client's future implementation
are welcome.
Reflex::Client is a high-level base class for non-blocking socket
clients. As with other Reflex::Base classes, this one may be
subclassed, composed with "has", or driven inline with promises.
=head2 Attributes
Reflex::Client extends (and includes the attributes of)
Reflex::Connector, which extends Reflex::Handle. It also provides its
own attributes.
=head3 protocol
The "protocol" attribute contains the name of a class that will handle
I/O for the client. It contains "Reflex::Stream" by default.
Protocol classes should extend Reflex::Stream or at least follow its
=head2 Public Methods
Reflex::Client extends Reflex::Handle, but it currently provides no
additional methods.
=head2 Events
Reflex::Client emits some of its own high-level events based on its
components' activities.
=head3 connected
Reflex::Client emits "connected" to notify consumers when the client
has connected, and it's safe to begin sending data.
=head3 data
Reflex::Client emits stream data with the "data" event. This event is
provided by Reflex::Stream. Please see L<Reflex::Stream/data> for the
most current documentation.
eg/ subclasses Reflex::Client as TcpEchoClient.
=head1 SEE ALSO