Skip to content

Commit

Permalink
added HTML5 EventSource recipe to cookbook
Browse files Browse the repository at this point in the history
  • Loading branch information
kraih committed Oct 31, 2011
1 parent d4a2a1b commit b048792
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 12 deletions.
4 changes: 2 additions & 2 deletions lib/Mojo/HelloWorld.pm
Expand Up @@ -167,10 +167,10 @@ File:
%= javascript begin
var ws;
if ("MozWebSocket" in window) {
ws = new MozWebSocket("<%= $url %>");
ws = new MozWebSocket('<%= $url %>');
}
else if ("WebSocket" in window) {
ws = new WebSocket("<%= $url %>");
ws = new WebSocket('<%= $url %>');
}
if(typeof(ws) !== 'undefined') {
function wsmessage(event) {
Expand Down
92 changes: 88 additions & 4 deletions lib/Mojolicious/Guides/Cookbook.pod
Expand Up @@ -231,19 +231,25 @@ into alien environments like foreign event loops.

=head1 REAL-TIME WEB

The real-time web is a collection of technologies that includes Comet
The real-time web is a collection of technologies that include Comet
(long-polling), HTML5 EventSource and WebSockets, which allow content to be
pushed to consumers as soon as it is generated, instead of relying on the
more traditional pull model.

=head2 WebSocket echo service

Receiving WebSocket messages is as easy as subscribing to the C<message>
event of the current transaction, just be aware that this is all event based,
so you should not block for too long.
The WebSocket protocol offers full bi-directional low-latency communication
channels between clients and servers.
Receiving messages is as easy as subscribing to the C<message> event of the
transaction, just be aware that all of this is event based, so you should not
block for too long.

use Mojolicious::Lite;

# Template with browser-side code
get '/' => 'index';

# WebSocket echo service
websocket '/echo' => sub {
my $self = shift;

Expand All @@ -264,6 +270,27 @@ so you should not block for too long.
};

app->start;
__DATA__

@@ index.html.ep
<!doctype html><html>
<head><title>Echo</title></head>
<body>
<script>
var ws = new WebSocket('<%= url_for('echo')->to_abs %>');

// Incoming messages
ws.onmessage = function(event) {
document.body.innerHTML += event.data + '<br/>';
};

// Outgoing messages
window.setInterval(function() {
ws.send('Hello Mojo!');
}, 1000);
</script>
</body>
</html>

The C<finish> event will always be emitted after a WebSocket connection has
been closed.
Expand All @@ -286,6 +313,63 @@ pleasant L<Test::Mojo> API to be used.
$t->websocket_ok('/echo')->send_message_ok('Hello Mojo!')
->message_is('echo: Hello Mojo!')->finish_ok;

=head2 Live logging with HTML5 EventSource

HTML5 EventSource is a special form of long-polling where you can directly
send DOM events from servers to clients.
It is uni-directional, that means you will have to use Ajax requests for
sending data from clients to servers, the advantage however is low
infrastructure requirements, since it reuses the HTTP protocol for transport.

use Mojolicious::Lite;

# Template with browser-side code
get '/' => 'index';

# EventSource for log messages
get '/events' => sub {
my $self = shift;

# Increase connection timeout a bit
Mojo::IOLoop->connection_timeout($self->tx->connection => 300);

# Change content type
$self->res->headers->content_type('text/event-stream');

# Subscribe to "message" event and forward "log" events to browser
my $cb = $self->app->log->on(message => sub {
my ($log, $level, $message) = @_;
$self->write("event:log\ndata: [$level] $message\n\n");
});

# Unsubscribe from "message" event again once we are done
$self->on(finish => sub {
my $self = shift;
$self->app->log->unsubscribe(message => $cb);
});
};

app->start;
__DATA__

@@ index.html.ep
<!doctype html><html>
<head><title>LiveLog</title></head>
<body>
<script>
var events = new EventSource('<%= url_for 'events' %>');

// Subscribe to "log" event
events.addEventListener('log', function(event) {
document.body.innerHTML += event.data + '<br/>';
}, false);
</script>
</body>
</html>

The C<finish> event will always be emitted after the transaction has been
finished.

=head1 USER AGENT

When we say L<Mojolicious> is a web framework we actually mean it.
Expand Down
4 changes: 2 additions & 2 deletions lib/Mojolicious/Guides/Growing.pod
Expand Up @@ -62,7 +62,7 @@ The fundamental idea here is that all resources are uniquely addressable with
URLs and every resource can have different representations such as HTML, RSS
or JSON.
User interface concerns are separated from data storage concerns and all
session state is kept client side.
session state is kept client-side.

.---------. .------------.
| | -> PUT /foo -> | |
Expand Down Expand Up @@ -108,7 +108,7 @@ information across several HTTP requests.
Content-Length: 16
Hello again sri!

Traditionally all session data was stored on the server side and only session
Traditionally all session data was stored on the server-side and only session
ids were exchanged between browser and web server in the form of cookies.

HTTP/1.1 200 OK
Expand Down
2 changes: 1 addition & 1 deletion lib/Mojolicious/Sessions.pm
Expand Up @@ -98,7 +98,7 @@ Mojolicious::Sessions - Signed cookie based sessions
L<Mojolicious::Sessions> is a very simple signed cookie based session
implementation.
All data gets serialized with L<Mojo::JSON> and stored on the client side,
All data gets serialized with L<Mojo::JSON> and stored on the client-side,
but is protected from unwanted changes with a signature.
=head1 ATTRIBUTES
Expand Down
6 changes: 3 additions & 3 deletions t/mojo/websocket.t
Expand Up @@ -342,7 +342,7 @@ is $result2, 'test0test1', 'right result';
is $finished, 7, 'finished client websocket';
is $subreq, 9, 'finished server websocket';

# WebSocket /echo (user agent side drain callback)
# WebSocket /echo (client-side drain callback)
$flag2 = undef;
$result = '';
my $counter = 0;
Expand Down Expand Up @@ -370,7 +370,7 @@ $loop->start;
is $result, 'hi!there!', 'right result';
is $flag2, 25, 'finish event has been emitted';

# WebSocket /double_echo (server side drain callback)
# WebSocket /double_echo (server-side drain callback)
$flag2 = undef;
$result = '';
$counter = 0;
Expand Down Expand Up @@ -442,7 +442,7 @@ $ua->websocket(
);
$loop->start;

# Server side "finished" callback
# Server-side "finished" callback
is $flag, 24, 'finish event has been emitted';

# WebSocket /echo (16bit length)
Expand Down

0 comments on commit b048792

Please sign in to comment.