1# A simple socket client. Generic enough to be used for INET and UNIX 2# sockets, although we may need to specialize for each kind later. 3 4# TODO - This is a simple strawman implementation. It needs 5# refinement. 6 7package Reflex::Client; 8# vim: ts=2 sw=2 noexpandtab 9$Reflex::Client::VERSION = '0.100'; 10use Moose; 11use Reflex::Stream; 12 13extends 'Reflex::Connector'; 14with 'Reflex::Role::Collectible'; 15use Reflex::Trait::Watched qw(watches); 16 17has protocol => ( 18 is => 'rw', 19 isa => 'Str', 20 default => 'Reflex::Stream', 21); 22 23watches connection => ( 24 isa => 'Maybe[Reflex::Stream]', 25 # Maps $self->put() to $self->connection()->put(). 26 # TODO - Would be nice to have something like this for outbout 27 # events. See on_connection_data() later in this module for more. 28 handles => ['put'], 29); 30 31sub on_connection { 32 my ($self, $socket) = @_; 33 34 $self->connection( 35 $self->protocol()->new( 36 handle => $socket->handle(), 37 rd => 1, 38 ) 39 ); 40 41 $self->emit( -name => "connected" ); 42 #$self->re_emit( $socket, -name => "connected" ); 43} 44 45sub on_error { 46 my ($self, $error) = @_; 47 # TODO - Emit rather than warn. 48 warn $error->formatted(), "\n"; 49} 50 51sub on_connection_closed { 52 my ($self, $eof) = @_; 53 $self->connection()->stop(); 54 # TODO - Emit rather than warn. 55 warn "server closed connection.\n"; 56} 57 58sub on_connection_failure { 59 my ($self, $error) = @_; 60 $self->connection()->stop(); 61 # TODO - Emit rather than warn. 62 warn $error->formatted(), "\n"; 63} 64 65# This odd construct lets us rethrow a low-level event as a 66# higher-level event. It's similar to the way Moose "handles" works, 67# although in the other (outbound) direction. 68# 69# TODO - It's rather inefficient to rethrow like this at runtime. 70# Some compile- or init-time remapping construct would be better. 71# 72# TODO - While we're rethrowing, we should consider a generic facility 73# for passing -type through. 74 75sub on_connection_data { 76 my ($self, $data) = @_; 77 $self->re_emit( $data, -name => "data" ); 78} 79 80sub stop { 81 my $self = shift(); 82 $self->connection(undef); 83 $self->stopped(); 84}; 85 86__PACKAGE__->meta->make_immutable; 87 881; 89 90__END__ 91 92=pod 93 94=encoding UTF-8 95 96=for :stopwords Rocco Caputo 97 98=head1 NAME 99 100Reflex::Client - A non-blocking socket client. 101 102=head1 VERSION 103 104This document describes version 0.100, released on April 02, 2017. 105 106=head1 SYNOPSIS 107 108This is a complete working TCP echo client. It's the version of 109eg/eg-35-tcp-client.pl available at the time of this writing. 110 111 use lib qw(../lib); 112 113 { 114 package TcpEchoClient; 115 use Moose; 116 extends 'Reflex::Client'; 117 118 sub on_client_connected { 119 my ($self, $event) = @_; 120 $self->connection()->put("Hello, world!\n"); 121 }; 122 123 sub on_client_data { 124 my ($self, $event) = @_; 125 126 # Not chomped. 127 warn "got from server: ", $event->data(); 128 129 # Disconnect after we receive the echo. 130 $self->stop(); 131 } 132 } 133 134 TcpEchoClient->new( 135 remote_addr => '127.0.0.1', 136 remote_port => 12345, 137 )->run_all(); 138 139=head1 DESCRIPTION 140 141Reflex::Client is scheduled for substantial changes. One of its base 142classes, Reflex::Handle, will be deprecated in favor of 143Reflex::Role::Readable and Reflex::Role::Writable. Hopefully 144Reflex::Client's interfaces won't change much as a result, but 145there are no guarantees. 146Your ideas and feedback for Reflex::Client's future implementation 147are welcome. 148 149Reflex::Client is a high-level base class for non-blocking socket 150clients. As with other Reflex::Base classes, this one may be 151subclassed, composed with "has", or driven inline with promises. 152 153=head2 Attributes 154 155Reflex::Client extends (and includes the attributes of) 156Reflex::Connector, which extends Reflex::Handle. It also provides its 157own attributes. 158 159=head3 protocol 160 161The "protocol" attribute contains the name of a class that will handle 162I/O for the client. It contains "Reflex::Stream" by default. 163 164Protocol classes should extend Reflex::Stream or at least follow its 165interface. 166 167=head2 Public Methods 168 169Reflex::Client extends Reflex::Handle, but it currently provides no 170additional methods. 171 172=head2 Events 173 174Reflex::Client emits some of its own high-level events based on its 175components' activities. 176 177=head3 connected 178 179Reflex::Client emits "connected" to notify consumers when the client 180has connected, and it's safe to begin sending data. 181 182=head3 data 183 184Reflex::Client emits stream data with the "data" event. This event is 185provided by Reflex::Stream. Please see L<Reflex::Stream/data> for the 186most current documentation. 187 188=for Pod::Coverage on_connection_closed on_connection_data on_connection_failure stop 189 190=head1 EXAMPLES 191 192eg/eg-35-tcp-client.pl subclasses Reflex::Client as TcpEchoClient. 193 194=head1 SEE ALSO 195 196Please see those modules/websites for more information related to this module. 197 198=over 4 199 200=item * 201 202L<Reflex|Reflex> 203 204=item * 205 206L<Reflex> 207 208=item * 209 210L<Reflex::Client> 211 212=item * 213 214L<Reflex/ACKNOWLEDGEMENTS> 215 216=item * 217 218L<Reflex/ASSISTANCE> 219 220=item * 221 222L<Reflex/AUTHORS> 223 224=item * 225 226L<Reflex/BUGS> 227 228=item * 229 230L<Reflex/BUGS> 231 232=item * 233 234L<Reflex/CONTRIBUTORS> 235 236=item * 237 238L<Reflex/COPYRIGHT> 239 240=item * 241 242L<Reflex/LICENSE> 243 244=item * 245 246L<Reflex/TODO> 247 248=back 249 250=head1 BUGS AND LIMITATIONS 251 252You can make new bug reports, and view existing ones, through the 253web interface at L<http://rt.cpan.org/Public/Dist/Display.html?Name=Reflex>. 254 255=head1 AUTHOR 256 257Rocco Caputo <rcaputo@cpan.org> 258 259=head1 COPYRIGHT AND LICENSE 260 261This software is copyright (c) 2017 by Rocco Caputo. 262 263This is free software; you can redistribute it and/or modify it under 264the same terms as the Perl 5 programming language system itself. 265 266=head1 AVAILABILITY 267 268The latest version of this module is available from the Comprehensive Perl 269Archive Network (CPAN). Visit L<http://www.perl.com/CPAN/> to find a CPAN 270site near you, or see L<https://metacpan.org/module/Reflex/>. 271 272=head1 DISCLAIMER OF WARRANTY 273 274BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 275FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT 276WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER 277PARTIES PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, 278EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 279IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 280PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 281SOFTWARE IS WITH YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME 282THE COST OF ALL NECESSARY SERVICING, REPAIR, OR CORRECTION. 283 284IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 285WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 286REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE LIABLE 287TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, OR 288CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 289SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 290RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 291FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 292SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 293DAMAGES. 294 295=cut 296