Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
added experimental frame support to Mojo::Message::WebSocket and chan…
…ged syntax for binary messages
  • Loading branch information
kraih committed Oct 25, 2011
1 parent 748c652 commit 3446bc3
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 109 deletions.
95 changes: 50 additions & 45 deletions Changes
@@ -1,6 +1,11 @@
This file documents the revision history for Perl extension Mojolicious.

2.10 2011-10-24 00:00:00
2.10 2011-10-25 00:00:00
- Added EXPERIMENTAL send_frame method to
Mojo::Transaction::WebSocket.
- Added EXPERIMENTAL frame event to Mojo::Transaction::WebSocket.
- Changed syntax for binary messages in Mojo::Transaction::WebSocket.
[$bytes] becomes [binary => $bytes]
- Improved documentation.
- Improved tests.

Expand Down Expand Up @@ -1209,9 +1214,9 @@ This file documents the revision history for Perl extension Mojolicious.
0.999923 2010-03-07 00:00:00
- Made Mojo::Client sync by default with optional async support, this
massively improves usability!
my $tx = $client->get('http://mojolicious.org');
print $client->get('http://search.cpan.org')->res->body;
my $tx = $client->post_form('http://kraih.com', {q => 'mojo'});
my $tx = $client->get('http://mojolicious.org');
print $client->get('http://search.cpan.org')->res->body;
my $tx = $client->post_form('http://kraih.com', {q => 'mojo'});
- Made plugins much more configurable.
- Improved PSGI support and added "psgi" command.
- Added automatic environment detection for Plack based servers,
Expand Down Expand Up @@ -1295,10 +1300,10 @@ This file documents the revision history for Perl extension Mojolicious.
- Added UNIX domain socket support to daemons.
- Added transparent kqueue and epoll support to daemons and client.
- Added support for listening to multiple locations to the daemons.
mojo daemon --listen http://127.0.0.1:3000
mojo daemon --listen http://*:3000,http://*:3001,http://*:3002
mojo daemon --listen http://[::1]:3000
mojo daemon --listen https://*:443:/x/server.crt:/x/server.key
mojo daemon --listen http://127.0.0.1:3000
mojo daemon --listen http://*:3000,http://*:3001,http://*:3002
mojo daemon --listen http://[::1]:3000
mojo daemon --listen https://*:443:/x/server.crt:/x/server.key
- Added routes captures to params in Mojolicious.
- Added native PSGI support.
- Added the ability to have multiple Mojolicious::Lite apps at once.
Expand All @@ -1307,11 +1312,11 @@ This file documents the revision history for Perl extension Mojolicious.
- Added simple reverse proxy support with tests.
- Added simpler way to define default controller and action for a
route.
$r->route('/foo')->to('mycontroller#myaction');
$r->route('/foo')->to('mycontroller#myaction');
- Added simple way to define default controller or action for a
route. (mvuets)
$r->route('/foo/:controller')->to('#myaction');
$r->route('/foo/:action')->to('mycontroller#');
$r->route('/foo/:controller')->to('#myaction');
$r->route('/foo/:action')->to('mycontroller#');
- Added multipart post support to Test::Mojo. (yuki-kimoto)
- Added env attribute to Mojo::Message::Request.
- Added range support to MojoX::Dispatcher::Static. (xantus)
Expand Down Expand Up @@ -1472,12 +1477,12 @@ This file documents the revision history for Perl extension Mojolicious.
- Added more designer friendly .ep templates to Mojolicious.
The default template format for your application can be controlled
with the default_handler attribute of the mojolicious renderer.
Mojolicious (in the startup method):
$self->renderer->default_handler('epl');
$self->renderer->default_handler('ep');
Mojolicious::Lite:
app->renderer->default_handler('epl');
app->renderer->default_handler('ep');
Mojolicious (in the startup method):
$self->renderer->default_handler('epl');
$self->renderer->default_handler('ep');
Mojolicious::Lite:
app->renderer->default_handler('epl');
app->renderer->default_handler('ep');
- Added helper support for .ep templates.
- Added callback tests. (melo)
- Added support for MOJO_CHUNK_SIZE=1. (melo)
Expand Down Expand Up @@ -1537,35 +1542,35 @@ This file documents the revision history for Perl extension Mojolicious.
"Mojo(licious)::Script" with "Mojo(licious)::Command" manually.
- Removed unused features from Mojo::Base and simplified API, this
change is not backwards compatible!
__PACKAGE__->attr('foo', default => 'bar');
__PACKAGE__->attr('foo', default => 'bar');
becomes
__PACKAGE__->attr(foo => 'bar');
__PACKAGE__->attr(foo => 'bar');
- Merged eplite and epl, this change is not backwards compatible, you
will have to rename all your eplite templates to epl.
- Simplified MojoX::Renderer, this change is not backwards
compatible!
Handler can no longer be detected, that means "default_handler" or
the "handler" argument are required.
The template argument can no longer contain format or handler.
$self->render(template => 'foo.html.epl')
$self->render(template => 'foo.html.epl')
becomes
$self->render('foo', format => 'html', handler => 'epl')
$self->render('foo', format => 'html', handler => 'epl')
The following forms are available now.
$self->render;
$self->render(controller => 'foo', action => 'bar');
$self->render({controller => 'foo', action => 'bar'});
$self->render(text => 'Hello!');
$self->render(template => 'index');
$self->render(template => 'foo/index');
$self->render(
template => 'index',
format => 'html',
handler => 'epl'
);
$self->render(handler => 'something');
$self->render('foo/bar');
$self->render('foo/bar', format => 'html');
$self->render('foo/bar', {format => 'html'});
$self->render;
$self->render(controller => 'foo', action => 'bar');
$self->render({controller => 'foo', action => 'bar'});
$self->render(text => 'Hello!');
$self->render(template => 'index');
$self->render(template => 'foo/index');
$self->render(
template => 'index',
format => 'html',
handler => 'epl'
);
$self->render(handler => 'something');
$self->render('foo/bar');
$self->render('foo/bar', format => 'html');
$self->render('foo/bar', {format => 'html'});
For renderers the stash will no longer get an updated template,
instead a new argument will be passed along.
{template => 'foo/bar', format => 'html', handler => 'epl'}
Expand All @@ -1579,15 +1584,15 @@ This file documents the revision history for Perl extension Mojolicious.
everything is in $self now.
- Refactored and renamed Mojo::Transaction and Mojo::Pipeline, this
change is not backwards compatible!
Mojo::Transaction -> Mojo::Transaction::Single
Mojo::Pipeline -> Mojo::Transaction::Pipeline
Mojo::Transaction -> Mojo::Transaction::Single
Mojo::Pipeline -> Mojo::Transaction::Pipeline
- Refactored and renamed Mojo::File and Mojo::File::Memory, this
change is not backwards compatible!
Mojo::File -> Mojo::Asset::File
Mojo::File::Memory -> Mojo::Asset::Memory
Mojo::File -> Mojo::Asset::File
Mojo::File::Memory -> Mojo::Asset::Memory
- Refactored and renamed Mojo::Content, this change is not backwards
compatible!
Mojo::Content -> Mojo::Content::Single
Mojo::Content -> Mojo::Content::Single
- Added conditions to MojoX::Routes.
- Added routes script to Mojolicious.
- Simplified Mojo::Base.
Expand Down Expand Up @@ -1638,8 +1643,8 @@ This file documents the revision history for Perl extension Mojolicious.
0.991242 2009-07-27 00:00:00
- Cleaned up the whole script system, this change is mostly backwards
compatible except for a few cases.
"daemon $port" now becomes "daemon -p $port"
"mojolicious mojo $script" becomes "mojolicious $script"
"daemon $port" now becomes "daemon -p $port"
"mojolicious mojo $script" becomes "mojolicious $script"
- Added HTML escape expression marks "<%==" and "%==" to
Mojo::Template.
- Added more Mojolicious::Lite examples and reformatted them into a
Expand All @@ -1656,8 +1661,8 @@ This file documents the revision history for Perl extension Mojolicious.
- Changed routes syntax again, this change is not entirely backwards
compatible but will only affect you if you are using the relaxed
and wildcard variations.
"/((foo))" becomes "/(.foo)"
"/(((foo)))" becomes "/(*foo)"
"/((foo))" becomes "/(.foo)"
"/(((foo)))" becomes "/(*foo)"
- Updated Mojolicious to support ->render(text => 'Hello World!').
- Updated Mojo::Script::get_data to use "@@ $name" instead of
"__$name__".
Expand Down
140 changes: 90 additions & 50 deletions lib/Mojo/Transaction/WebSocket.pm
Expand Up @@ -29,6 +29,41 @@ has handshake => sub { Mojo::Transaction::HTTP->new };
has 'masked';
has max_websocket_size => sub { $ENV{MOJO_MAX_WEBSOCKET_SIZE} || 262144 };

sub new {
my $self = shift->SUPER::new(@_);

# Prepare "message" event
$self->on(
frame => sub {
my ($self, $frame) = @_;

# Ping
my $op = $frame->[1] || CONTINUATION;
return $self->send_frame(1, PONG, $frame->[2]) if $op == PING;

# Close
return $self->finish if $op == CLOSE;

# Append chunk and check message size
$self->{op} = $op unless exists $self->{op};
$self->{message} .= $frame->[2];
return $self->finish
if length $self->{message} > $self->max_websocket_size;

# No FIN bit (Continuation)
return unless $frame->[0];

# Message
my $message = $self->{message};
$self->{message} = '';
decode 'UTF-8', $message if $message && delete $self->{op} == TEXT;
$self->emit(message => $message);
}
);

return $self;
}

sub build_frame {
my ($self, $fin, $op, $payload) = @_;
warn "BUILDING FRAME\n" if DEBUG;
Expand Down Expand Up @@ -121,7 +156,7 @@ sub connection { shift->handshake->connection(@_) }

sub finish {
my $self = shift;
$self->_send_frame(CLOSE, '');
$self->send_frame(1, CLOSE, '');
$self->{finished} = 1;
return $self;
}
Expand Down Expand Up @@ -216,17 +251,30 @@ sub resume {
return $self;
}

sub send_message {
my ($self, $message, $cb) = @_;
$message //= '';
sub send_frame {
my ($self, $fin, $type, $payload, $cb) = @_;

# Binary
# Prepare frame
$self->{drain} = $cb if $cb;
return $self->_send_frame(BINARY, $message->[0]) if ref $message;
$self->{write} //= '';
$self->{write} .= $self->build_frame($fin, $type, $payload);
$self->{state} = 'write';

# Resume
$self->emit('resume');
}

sub send_message {
my ($self, $m, $cb) = @_;
$m //= '';

# Binary or raw text
return $self->send_frame(1, $m->[0] eq 'text' ? TEXT : BINARY, $m->[1], $cb)
if ref $m;

# Text
encode 'UTF-8', $message;
$self->_send_frame(TEXT, $message);
encode 'UTF-8', $m;
$self->send_frame(1, TEXT, $m, $cb);
}

sub server_handshake {
Expand Down Expand Up @@ -256,35 +304,7 @@ sub server_read {
$self->{read} .= $chunk if defined $chunk;
$self->{message} //= '';
while (my $frame = $self->parse_frame(\$self->{read})) {
my $op = $frame->[1] || CONTINUATION;

# Ping
if ($op == PING) {
$self->_send_frame(PONG, $frame->[2]);
next;
}

# Close
elsif ($op == CLOSE) {
$self->finish;
next;
}

# Append chunk and check message size
$self->{op} = $op unless exists $self->{op};
$self->{message} .= $frame->[2];
$self->finish and last
if length $self->{message} > $self->max_websocket_size;

# No FIN bit (Continuation)
next unless $frame->[0];

# Message
my $message = $self->{message};
$self->{message} = '';
decode 'UTF-8', $message if $message && delete $self->{op} == TEXT;
return $self->finish unless $self->has_subscribers('message');
$self->emit(message => $message);
$self->emit(frame => $frame);
}

# Resume
Expand Down Expand Up @@ -324,16 +344,6 @@ sub _challenge {
return $challenge;
}

sub _send_frame {
my ($self, $op, $payload) = @_;

# Build frame and resume
$self->{write} //= '';
$self->{write} .= $self->build_frame(1, $op, $payload);
$self->{state} = 'write';
$self->emit('resume');
}

sub _xor_mask {
my ($input, $mask) = @_;

Expand Down Expand Up @@ -371,13 +381,28 @@ Note that this module is EXPERIMENTAL and might change without warning!
L<Mojo::Transaction::WebSocket> inherits all events from L<Mojo::Transaction>
and can emit the following new ones.
=head2 C<frame>
$ws->on(frame => sub {
my ($ws, $frame) = @_;
});
Emitted when a WebSocket frame has been received.
$ws->on(frame => sub {
my ($ws, $frame) = @_;
say 'Fin: ', $frame->[0];
say 'Type: ', $frame->[1];
say 'Payload: ', $frame->[2];
});
=head2 C<message>
$ws->on(message => sub {
my ($ws, $message) = @_;
});
Emitted when a new WebSocket message arrives.
Emitted when a complete WebSocket message has been received.
$ws->on(message => sub {
my ($ws, $message) = @_;
Expand Down Expand Up @@ -417,6 +442,13 @@ C<MOJO_MAX_WEBSOCKET_SIZE> or C<262144>.
L<Mojo::Transaction::WebSocket> inherits all methods from
L<Mojo::Transaction> and implements the following new ones.
=head2 C<new>
my $ws = Mojo::Transaction::WebSocket->new;
my $ws = Mojo::Transaction::WebSocket->new(handshake => $tx);
Construct a new L<Mojo::Transaction::WebSocket> object.
=head2 C<build_frame>
my $bytes = $ws->build_frame($fin, $op, $payload);
Expand Down Expand Up @@ -513,12 +545,20 @@ The original handshake response.
Resume transaction.
=head2 C<send_frame>
$ws->send_frame($fin, $op, $payload);
$ws->send_frame($fin, $op, $payload, sub {...});
Send a single frame non-blocking via WebSocket, the optional drain callback
will be invoked once all data has been written.
=head2 C<send_message>
$ws->send_message([binary => $bytes]);
$ws->send_message([text => $bytes]);
$ws->send_message('Hi there!');
$ws->send_message('Hi there!', sub {...});
$ws->send_message([$bytes]);
$ws->send_message([$bytes], sub {...});
Send a message non-blocking via WebSocket, the optional drain callback will
be invoked once all data has been written.
Expand Down
2 changes: 0 additions & 2 deletions lib/Mojolicious/Controller.pm
Expand Up @@ -944,8 +944,6 @@ Note that this method is EXPERIMENTAL and might change without warning!
$c = $c->send_message('Hi there!');
$c = $c->send_message('Hi there!', sub {...});
$c = $c->send_message([$bytes]);
$c = $c->send_message([$bytes], sub {...});
Send a message non-blocking via WebSocket, the optional drain callback will
be invoked once all data has been written.
Expand Down

0 comments on commit 3446bc3

Please sign in to comment.