Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
yanick committed Feb 20, 2011
0 parents commit 3c2079e
Show file tree
Hide file tree
Showing 75 changed files with 9,412 additions and 0 deletions.
21 changes: 21 additions & 0 deletions Makefile.PL
@@ -0,0 +1,21 @@
use strict;
use warnings;
use ExtUtils::MakeMaker;

WriteMakefile(
NAME => 'chorus',
AUTHOR => q{YOUR NAME <youremail@example.com>},
VERSION_FROM => 'lib/chorus.pm',
ABSTRACT => 'YOUR APPLICATION ABSTRACT',
($ExtUtils::MakeMaker::VERSION >= 6.3002
? ('LICENSE'=> 'perl')
: ()),
PL_FILES => {},
PREREQ_PM => {
'Test::More' => 0,
'YAML' => 0,
'Dancer' => 1.1902,
},
dist => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', },
clean => { FILES => 'chorus-*' },
);
210 changes: 210 additions & 0 deletions a
@@ -0,0 +1,210 @@
package Dancer::Plugin::WebSocket;
use Carp;
use Dancer ':syntax';

our $VERSION = 0.0100;# VERSION

use AnyMQ;
use Dancer::Plugin;
use Plack;
use Web::Hippie;
use Carp;

my $bus;
sub _bus {
return $bus if $bus;
return $bus = AnyMQ->new;
}

my $topic;
sub _topic {
return $topic if $topic;
return $topic = _bus->topic('dancer-plugin-websocket');
}

my $triggers = {};

set plack_middlewares_map => {
'/_hippie' => [
[ '+Web::Hippie' ],
[ '+Web::Hippie::Pipe', bus => _bus ],
]
};

# /new_listener and /message are routes needed by Web::Hippie

get '/new_listener' => sub {

if (defined $triggers->{on_new_listener}) {
$triggers->{on_new_listener}->();
}

request->env->{'hippie.listener'}->subscribe(_topic);
};

get '/message' => sub {
my $msg = request->env->{'hippie.message'};

if ( defined $triggers->{on_message} ) {
$msg = $triggers->{on_message}->($msg);
}
_topic->publish($msg);
};

my $ws_send = sub {
my $msg = shift;
_topic->publish({ msg => $msg });
};

register ws_on_message => sub {
$triggers->{on_message} = shift;
};

register ws_on_new_listener => sub {
$triggers->{on_new_listener} = shift;
};

register ws_send => sub {
$ws_send->(@_);
};

register websocket_send => sub {
carp "'websocket_send' is deprecated. You should use 'ws_send' instead.";
$ws_send->(@_);
};

register_plugin;

# ABSTRACT: A Dancer plugin for easily creating WebSocket apps


1;

__END__
=pod

=head1 NAME

Dancer::Plugin::WebSocket - A Dancer plugin for easily creating WebSocket apps

=head1 VERSION

version 0.0100

=head1 SYNOPSIS

# ./bin/app.pl
use Dancer;
use Dancer::Plugin::WebSocket;

get '/' => sub {q[
<html>
<head>
<script>
var ws_path = "ws://localhost:5000/_hippie/ws";
var socket = new WebSocket(ws_path);
socket.onopen = function() {
document.getElementById('conn-status').innerHTML = 'Connected';
};
socket.onmessage = function(e) {
var data = JSON.parse(e.data);
if (data.msg)
alert (data.msg);
};
function send_msg(message) {
socket.send(JSON.stringify({ msg: message }));
}
</script>
</head>
<body>
Connection Status: <span id="conn-status"> Disconnected </span>
<input value="Send Message" type=button onclick="send_msg('hello')" />
</body>
</html>
]};

dance;

# Run app with Twiggy
twiggy --listen :5000 bin/app.pl

# Now you can visit http://localhost:5000 with a browser that supports
# WebSockets, such as Chrome.

=head1 DESCRIPTION

This goal of this plugin is to make it as easy as possible to create WebSocket
enabled apps with L<Dancer>.
It is built on top of L<Web::Hippie>, but it abstracts that out as much as
possible.
You should be aware that it registers 2 routes that Web::Hippie needs:
get('/new_listener') and get('/message').
Be careful to not define those routes in your app.

This plugin currently requires that you run your app via L<Twiggy>.
For example:

twiggy --listen :5000 bin/app.pl

=head1 METHODS

These methods allow you to interact with WebSockets from the server side.
If you are only going to interact with WebSockets from javascript,
as shown in the L</SYNOPSIS>, then these are not necessary.

=head2 ws_on_message (\&handler)

Registers a handler that gets triggered when a new message arrives.
The handler gets passed 1 argument, a data structure containing the message.
Note that if you register a handler in this way, the onmessage callback
of the WebSocket object in your javascript will not get triggered.

ws_on_message sub {
my $data = shift;
debug $data->{msg};
};

=head2 ws_on_new_listener (\&handler)

Registers a handler that gets triggered when a new listener is created.
The handler gets passed no arguments.

ws_on_new_listener sub {
# do something when a new listener is created
};

=head2 ws_send ($message)

Allows you to send a WebSocket message from within a Dancer route.

any '/send_msg' => sub {
my $msg = params->{msg};
ws_send $msg;
};

# Now you can send a message to your application via curl:
curl http://localhost:5000/send_msg?msg=hello

=head1 AUTHORS

=over 4

=item *

Naveed Massjouni <naveedm9@gmail.com>

=item *

Franck Cuny <franck@lumberjaph.net>

=back

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2010 by Naveed Massjouni.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut

41 changes: 41 additions & 0 deletions chorus.pl
@@ -0,0 +1,41 @@
#!/usr/bin/env perl

use strict;

use Dancer;

use lib path(dirname(__FILE__), 'lib');
load_app 'chorus';

use AnyMQ;
use Plack::Builder;

my $bus = AnyMQ->new;
my $topic = $bus->topic('demo');

my $token = 'master';
$chorus::first_connect = 1;

# Web::Hippie routes
get '/new_listener' => sub {
request->env->{'hippie.listener'}->subscribe($topic);
};
get '/message' => sub {
my $msg = request->env->{'hippie.message'};
if ( $chorus::first_connect ) {
$chorus::first_connect = 0;
$topic->publish( { master => $token } );
}
else {
$topic->publish( $msg );
}
};

builder {
mount '/' => dance;
mount '/_hippie' => builder {
enable '+Web::Hippie';
enable '+Web::Hippie::Pipe', bus => $bus;
dance;
};
};
4 changes: 4 additions & 0 deletions config.yml
@@ -0,0 +1,4 @@
logger: "file"
appname: "chorus"
template: 'mason'

8 changes: 8 additions & 0 deletions environments/development.yml
@@ -0,0 +1,8 @@
log: "core"
warnings: 0
show_errors: 1

# auto_reload is a development feature
# you should enable it by yourself if you want it
# Module::Refresh is needed
auto_reload: 0
7 changes: 7 additions & 0 deletions environments/production.yml
@@ -0,0 +1,7 @@
log: "warning"
warnings: 0
show_errors: 0
route_cache: 1
# never enable auto_reload in production
auto_reload: 0

25 changes: 25 additions & 0 deletions lib/chorus.pm
@@ -0,0 +1,25 @@
package chorus;

use 5.10.0;

use Dancer ':syntax';
#use Dancer::Plugin::WebSocket;

use Text::Markdown qw/ markdown /;
use File::Slurp qw/ slurp /;

our $VERSION = '0.1';

my $prez = "<div class='slide'>". markdown( scalar slurp 'prez' ) . "</div>";
my $heads;
$prez =~ s#(?=<h1>)# $heads++ ? "</div><div class='slide'>" : "" #eg;

get '/' => sub {
template 'index' => {
presentation => $prez,
prez_url => request->base,
base_url => request->base->opaque,
};
};

true;
Empty file added logs/deployment.log
Empty file.

0 comments on commit 3c2079e

Please sign in to comment.