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