File Coverage

blib/lib/IO/Framed.pm
Criterion Covered Total %
statement 12 12 100.0
branch n/a
condition 2 3 66.6
subroutine 4 4 100.0
pod 0 1 0.0
total 18 20 90.0


line stmt bran cond sub pod time code
1             package IO::Framed;
2              
3 3     3   70164 use strict;
  3         6  
  3         84  
4 3     3   14 use warnings;
  3         5  
  3         256  
5              
6             our $VERSION = '0.15';
7              
8             =encoding utf-8
9              
10             =head1 NAME
11              
12             IO::Framed - Convenience wrapper for frame-based I/O
13              
14             =head1 SYNOPSIS
15              
16             Reading:
17              
18             #See below about seed bytes.
19             my $iof = IO::Framed->new( $fh, 'seed bytes' );
20              
21             #This returns undef if the $in_fh doesn’t have at least
22             #the given length (5 in this case) of bytes to read.
23             $frame = $iof->read(5);
24              
25             #Don’t call this after an incomplete read().
26             $line_or_undef = $iof->read_until("\x0a");
27              
28             Writing, unqueued (i.e., for blocking writes):
29              
30             #The second parameter (if given) is executed immediately after the final
31             #byte of the payload is written. For blocking I/O this happens
32             #before the following method returns.
33             $iof->write('hoohoo', sub { print 'sent!' } );
34              
35             Writing, queued (for non-blocking writes):
36              
37             $iof->enable_write_queue();
38              
39             #This just adds to a memory queue:
40             $iof->write('hoohoo', sub { print 'sent!' } );
41              
42             #This will be 1, since we have 1 message/frame queued to send.
43             $iof->get_write_queue_count();
44              
45             #Returns 1 if it empties out the queue; 0 otherwise.
46             #Partial frame writes are accommodated; the callback given as 2nd
47             #argument to write() only fires when the queue item is sent completely.
48             my $empty = $iof->flush_write_queue();
49              
50             You can also use C and C, which
51             contain just the read and write features. (C is actually a
52             subclass of them both.)
53              
54             =head1 DESCRIPTION
55              
56             While writing L I noticed that I was reimplementing some of the
57             same patterns I’d used in L to parse frames from a stream:
58              
59             =over
60              
61             =item * Only read() entire frames, with a read queue for any partials.
62              
63             =item * Continuance when a partial frame is delivered.
64              
65             =item * Write queue with callbacks for non-blocking I/O
66              
67             =item * Signal resilience: resume read/write after Perl receives a trapped
68             signal rather than throwing/giving EINTR. (cf. L)
69              
70             =back
71              
72             These are now made available in this distribution.
73              
74             =head1 ABOUT READS
75              
76             The premise here is that you expect a given number of bytes at a given time
77             and that a partial read should be continued once it is sensible to do so.
78              
79             As a result, C will throw an exception if the number of bytes given
80             for a continuance is not the same number as were originally requested.
81             C will throw a similar exception if called between an incomplete
82             C and its completion.
83              
84             Example:
85              
86             #This reads only 2 bytes, so read() will return undef.
87             $iof->read(10);
88              
89             #… wait for readiness if non-blocking …
90              
91             #XXX This die()s because we’re in the middle of trying to read
92             #10 bytes, not 4.
93             $iof->read(4);
94              
95             #If this completes the read (i.e., takes in 8 bytes), then it’ll
96             #return the full 10 bytes; otherwise, it’ll return undef again.
97             $iof->read(10);
98              
99             EINTR prompts a redo of the read operation. EAGAIN and EWOULDBLOCK (the same
100             error generally, but not always) prompt an undef return.
101             Any other failures prompt an instance of L to be
102             thrown.
103              
104             =head2 End-Match Reads
105              
106             Reader modules now implement a C method, which reads arbitrarily
107             many bytes until
108             a given sequence of bytes appears then returns those bytes (plus the looked-for
109             sequence in the return). An obvious application for this feature
110             is line-by-line reads, e.g., to implement HTTP or other line-based protocols.
111              
112             =head2 Empty Reads
113              
114             This class’s C and C methods will, by default, throw
115             an instance of
116             L on an empty read. This is normal and logical
117             behavior in contexts (like L) where the data stream itself
118             indicates when no more data will come across. In such cases an empty read
119             is genuinely an error condition: it either means you’re reading past when
120             you should, or the other side prematurely went away.
121              
122             In some other cases, though, that empty read is the normal and expected way
123             to know that a filehandle/socket has no more data to read.
124              
125             If you prefer, then, you can call the C method to switch
126             to a different behavior, e.g.:
127              
128             $framed->allow_empty_read();
129              
130             my $frame = $framed->read(10);
131              
132             if (length $frame) {
133             #yay, we got a frame!
134             }
135             elsif (defined $frame) {
136             #no more data will come in, so let’s close up shop
137             }
138             else {
139             #undef means we just haven’t gotten as much data as we want yet;
140             #in this case, that means fewer than 10 bytes are available.
141             }
142              
143             #----------------------------------------------------------------------
144             # The same example as above with line-oriented input …
145              
146             my $line = $framed->read_until("\x0a");
147              
148             if (length $line) {
149             #yay, we got a line!
150             }
151             elsif (defined $line) {
152             #no more data will come in, so let’s close up shop
153             }
154             else {
155             #undef means we just haven’t gotten a full line yet.
156             }
157              
158             Instead of throwing the aforementioned exception, C now returns
159             empty-string on an empty read. That means that you now have to distinguish
160             between multiple “falsey” states: undef for when the requested number
161             of bytes hasn’t yet arrived, and empty string for when no more bytes
162             will ever arrive. But it is also true now that the only exceptions thrown
163             are bona fide B, which will suit some applications better than the
164             default behavior.
165              
166             NB: If you want to be super-light, you can bring in IO::Framed::Read instead
167             of the full IO::Framed. (IO::Framed is already pretty lightweight, though.)
168              
169             =head1 ABOUT WRITES
170              
171             Writes for blocking I/O are straightforward: the system will always send
172             the entire buffer. The OS’s C won’t return until everything
173             meant to be written is written. Life is pleasant; life is simple. :)
174              
175             Non-blocking I/O is trickier. Not only can the OS’s C write
176             a subset of the data it’s given, but we also can’t know that the output
177             filehandle is ready right when we want it. This means that we have to queue up
178             our writes
179             then write them once we know (e.g., through C) that the filehandle
180             is ready. Each C call, then, enqueues one new buffer to write.
181              
182             Since it’s often useful to know when a payload has been sent,
183             C accepts an optional callback that will be executed immediately
184             after the last byte of the payload is written to the output filehandle.
185              
186             Empty out the write queue by calling C and looking for
187             a truthy response. (A falsey response means there is still data left in the
188             queue.) C gives you the number of queue items left
189             to write. (A partially-written item is treated the same as a fully-unwritten
190             one.)
191              
192             Note that, while it’s acceptable to activate and deactive the write queue,
193             the write queue must be empty in order to deactivate it. (You’ll get a
194             nasty, untyped exception otherwise!)
195              
196             C returns undef on EAGAIN and EWOULDBLOCK. It retries on EINTR,
197             so you should never actually see this error from this module.
198             Other errors prompt a thrown exception.
199              
200             NB: C and C return the object,
201             so you can instantiate thus:
202              
203             my $nb_writer = IO::Framed::Write->new($fh)->enable_write_queue();
204              
205             NB: If you want to be super-light, you can bring in IO::Framed::Write instead
206             of the full IO::Framed. (IO::Framed is already pretty lightweight, though.)
207              
208             =head1 CUSTOM READ & WRITE LOGIC
209              
210             As of version 0.04, you can override READ and WRITE methods with your
211             preferred logic. For example, in Linux you might prefer C rather than
212             C to avoid SIGPIPE, thus:
213              
214             package My::Framed;
215              
216             use parent qw( IO::Framed::Write );
217              
218             #Only these two arguments are given.
219             sub WRITE {
220             return send( $_[0], $_[1], Socket::MSG_NOSIGNAL );
221             }
222              
223             (NB: In *BSD OSes you can set SO_SIGNOPIPE on the filehandle instead.)
224              
225             You can likewise set C to achieve the same effect for reads.
226             (C receives all four arguments that C can consume.)
227              
228             B Unlike most inherited methods, C and C do
229             NOT receive the object instance. They must follow the same semantics as
230             Perl’s C and C: i.e., they must return the number
231             of bytes read/written, or return undef and set C<$!> appropriately on error.
232              
233             =head1 ERROR RESPONSES
234              
235             An empty read or any I/O error besides the ones mentioned previously
236             are indicated via an instance of one of the following exceptions.
237              
238             All exceptions subclass L, which itself
239             subclasses C.
240              
241             =over
242              
243             =item L
244              
245             =item L
246              
247             These both have an C property (cf. L’s accessor
248             method).
249              
250             =item L
251              
252             No properties. If this is thrown, your peer has probably closed the connection.
253             Unless you have called C to set an alternate behavior,
254             you might want to trap this exception if you call C.
255              
256             =back
257              
258             B This distribution doesn’t write to C<$!>. EAGAIN and EWOULDBLOCK on
259             C are ignored; all other errors are converted
260             to thrown exceptions.
261              
262             =cut
263              
264 3         32 use parent qw(
265             IO::Framed::Read
266             IO::Framed::Write
267 3     3   477 );
  3         372  
268              
269             sub new {
270 3     3 0 1717 my ( $class, $in_fh, $out_fh, $initial_buffer ) = @_;
271              
272 3         18 my $self = $class->SUPER::new( $in_fh, $initial_buffer );
273              
274 3   66     39 $self->{'_out_fh'} = $out_fh || $in_fh,
275              
276             return (bless $self, $class)->disable_write_queue();
277             }
278              
279             1;
280              
281             =head1 LEGACY CLASSES
282              
283             This distribution also includes the following B legacy classes:
284              
285             =over
286              
287             =item * IO::Framed::Write::Blocking
288              
289             =item * IO::Framed::Write::NonBlocking
290              
291             =item * IO::Framed::ReadWrite
292              
293             =item * IO::Framed::ReadWrite::Blocking
294              
295             =item * IO::Framed::ReadWrite::NonBlocking
296              
297             =back
298              
299             I’ll keep these in for the time being but eventually B remove them.
300             Please adjust any calling code that you might have.
301              
302             =head1 REPOSITORY
303              
304             L
305              
306             =head1 AUTHOR
307              
308             Felipe Gasper (FELIPE)
309              
310             =head1 COPYRIGHT
311              
312             Copyright 2017 by L
313              
314             =head1 LICENSE
315              
316             This distribution is released under the same license as Perl.
317              
318             =cut