File Coverage

blib/lib/Net/WebSocket/Endpoint/Server.pm
Criterion Covered Total %
statement 9 9 100.0
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 12 12 100.0


line stmt bran cond sub pod time code
1             package Net::WebSocket::Endpoint::Server;
2              
3             =encoding utf-8
4              
5             =head1 NAME
6              
7             Net::WebSocket::Endpoint::Server
8              
9             =head1 SYNOPSIS
10              
11             my $ept = Net::WebSocket::Endpoint::Server->new(
12             parser => $parser_obj,
13              
14             out => $out_fh,
15              
16             #optional, # of pings to send before we send a close
17             max_pings => 5,
18              
19             #optional
20             on_data_frame => sub {
21             my ($frame_obj) = @_;
22              
23             #...
24             },
25             );
26              
27             if ( _we_timed_out_waiting_for_read_readiness() ) {
28             $ept->check_heartbeat();
29             }
30             else {
31              
32             #Only necessary for non-blocking I/O;
33             #it’s meaningless in blocking I/O.
34             #See below for an alternative pattern for use with POE, etc.
35             if ( $ept->get_write_queue_size() ) {
36             $ept->flush_write_queue();
37             }
38              
39             #This should only be called when reading won’t produce an error.
40             #For example, in non-blocking I/O you’ll need a select() in front
41             #of this. (Blocking I/O can just call it and wait!)
42             $ept->get_next_message();
43              
44             #INSTEAD OF flush_write_queue(), you might want to send the write
45             #queue off to a multiplexing framework like POE, for which this
46             #would be useful:
47             while ( my $frame = $ept->shift_write_queue() ) {
48             #… do something with $frame->to_bytes() -- probably send it
49             }
50              
51             #Check for this at the end of each cycle.
52             _custom_logic_to_finish_up() if $ept->is_closed();
53             }
54              
55             =head1 DESCRIPTION
56              
57             This module, like its twin, L, attempts
58             to wrap up “obvious” bits of a WebSocket endpoint’s workflow into a
59             reusable component.
60              
61             The basic workflow is shown in the SYNOPSIS; descriptions of the individual
62             methods follow:
63              
64             =head1 METHODS
65              
66             =head2 I->new( %OPTS )
67              
68             Instantiate the class. Nothing is actually done here. Options are:
69              
70             =over
71              
72             =item * C (required) - An instance of L.
73              
74             =item * C (required) - The endpoint’s output object. An
75             instance of L or a compatible class.
76              
77             =item * C (optional) - The maximum # of pings to send before
78             we send a C frame (which ends the session).
79              
80             =item * C (optional) - A callback that receives every data
81             frame that C receives. Use this to facilitate chunking.
82              
83             If you want to avoid buffering a large message, you can do this:
84              
85             on_data_frame => sub {
86             #... however you’re going to handle this chunk
87              
88             $_[0] = (ref $_[0])->new(
89             payload_sr => \q<>,
90             fin => $_[0]->get_fin(),
91             );
92             },
93              
94             =back
95              
96             =head2 I->get_next_message()
97              
98             The “workhorse” method. It returns a data message if one is available
99             and is the next frame; otherwise, it returns undef.
100              
101             This method also handles control frames that arrive before or among
102             message frames:
103              
104             =over
105              
106             =item * close: Respond (immediately) with the identical close frame.
107             See below for more information.
108              
109             =item * ping: Send the appropriate pong frame.
110              
111             =item * pong: Set the internal ping counter to zero. If the pong is
112             unrecognized (i.e., we’ve not sent the payload in a ping), then we send
113             a PROTOCOL_ERROR close frame.
114              
115             =back
116              
117             This method may not be called after a close frame has been sent (i.e.,
118             if the C method returns true).
119              
120             =head2 I->check_heartbeat()
121              
122             Ordinarily, sends a distinct ping frame to the remote server
123             and increments the ping counter. Once a sent ping is
124             received back (i.e., a pong), the ping counter gets reset.
125              
126             If the internal ping counter has already reached C, then we
127             send a PROTOCOL_ERROR close frame. Further I/O attempts on this object
128             will prompt an appropriate exception to be thrown.
129              
130             =head2 I->sent_close_frame()
131              
132             Returns a C object or undef to represent the
133             frame that the object has sent, either via the C method directly
134             or automatically via the internal handling of control messages.
135              
136             =head2 I->received_close_frame()
137              
138             Returns a C object or undef to represent the
139             frame that the object has received.
140              
141             =head2 I->is_closed()
142              
143             DEPRECATED: Returns 1 or 0 to indicate whether we have sent a close frame.
144             Note that C provides a more useful variant of the
145             same functionality; there is no good reason to use this method anymore.
146              
147             =head1 WHEN A CLOSE FRAME IS RECEIVED
148              
149             C will automatically send a close frame in response
150             when it receives one. The received close frame is not returned to the
151             application but, like ping and pong, is handled transparently.
152              
153             Rationale: WebSocket is often billed as “TCP for the web”; however, the
154             protocol curiously diverges from TCP in not supporting “half-close”; a
155             WebSocket connection is either fully open (i.e., bidirectional) or fully
156             closed. (There is some leeway given for finishing up an in-progress message,
157             but this is a much more limited concept.)
158              
159             =head1 EXTENSIONS
160              
161             This module has several controls for supporting WebSocket extensions:
162              
163             =over
164              
165             =item * C’s returned messages will always contain
166             a C method, which you can use to read the reserved bits
167             of the individual data frames.
168              
169             =item * You can create C methods on a subclass of this module
170             to handle different types of control frames. (e.g., C)
171             to handle frames of type C.) The C object that you pass
172             to the constructor has to be aware of such messages; for more details,
173             see the documentation for L.
174              
175             =back
176              
177             =cut
178              
179 1     1   99072 use strict;
  1         7  
  1         54  
180 1     1   7 use warnings;
  1         1  
  1         28  
181              
182 1         4 use parent qw(
183             Net::WebSocket::Endpoint
184             Net::WebSocket::Masker::Server
185 1     1   4 );
  1         2  
186              
187             1;