AnyMQ, Hippie
 and the real-time web

      OSDC.TW 2010 Taipei
   Chia-liang Kao clkao@clkao.org
clkao
Things I’ve
been playing
    with
• PSGI, Plack
• AnyEvent, AnyMQ, AMQP
• Server-push, comet
• Websocket
• Web::Hippie, Web::Hippie:Pipe
• PSGI, Plack
• AnyEvent, AnyMQ, AMQP
• Server-push, comet
• Websocket
• Web::Hippie, Web::Hippie::Pipe
Plack: Perl Web Superglue
PSGI
$env->{PATH_INFO}

       Plack::Request->new($env)->path_info
$env




[
       '200',
       [ 'Content-Type' => 'text/plain' ],
       [ "Hello World" ],
]
$env
                 Streaming Interface

sub {
     my $responder = shift;
      my $writer = $responder->([
           '200',
           [ 'Content-Type' => 'text/plain' ]);
      # later, of in a callback
      $writer->write(“Hello world!”);
      $writer->close();
}
CGI.pm
MUST DIE!
 ☠! ☠! ☠
• PSGI, Plack
• AnyEvent, AnyMQ, AMQP
• Server-push, comet
• Websocket
• Web::Hippie, Web::Hippie::Pipe
AnyEvent
• event-driven programming, painless
• compatible with many other event loops
  use AnyEvent::HTTP;

  http_get "http://osdc.tw/",
                sub { print $_[1] };
Let’s try
this in POE
sub POE::Kernel::ASSERT_DEFAULT () { 1 }

use HTTP::Request;
use POE qw(Component::Client::HTTP);

POE::Component::Client::HTTP->spawn(
  Alias     => 'ua',                   # defaults to 'weeble'
  Timeout   => 20,                     # defaults to 180 seconds
);

POE::Session->create(
  inline_states => {
    _start => sub {
      POE::Kernel->post(
        'ua',         # posts to the 'ua' alias
        'request',    # posts to ua's 'request' state
        'response', # which of our states will receive the response
        HTTP::Request->new(GET => “http://osdc.tw”),
      );
    },
    _stop => sub {},
    response => &response_handler,
  },
);

POE::Kernel->run();
exit;

sub response_handler {
  my ($request_packet, $response_packet) = @_[ARG0, ARG1];
  my $request_object = $request_packet->[0];
  my $response_object = $response_packet->[0];
}
☹
use AnyEvent::HTTP;

http_get "http://osdc.tw/",
              sub { print $_[1] };




      ☺
AnyEvent::*
  AnyEvent-AIO AnyEvent-APNS AnyEvent-Atom-Stream AnyEvent-BDB AnyEvent-
  Beanstalk AnyEvent-Connection AnyEvent-CouchDB AnyEvent-DBI AnyEvent-DBI-
 Abstract AnyEvent-EditText AnyEvent-FCGI AnyEvent-FCP AnyEvent-FIFO AnyEvent-
   FastPing AnyEvent-Feed AnyEvent-Filesys-Notify AnyEvent-FriendFeed-Realtime
    AnyEvent-GPSD AnyEvent-Gearman AnyEvent-Gearman AnyEvent-Gmail-Feed
AnyEvent-HTTP AnyEvent-HTTP-MXHR AnyEvent-HTTPD AnyEvent-I3 AnyEvent-IRC
 AnyEvent-JSONRPC-Lite AnyEvent-Kanye AnyEvent-MP AnyEvent-MPRPC AnyEvent-
 Memcached AnyEvent-Mojo AnyEvent-Monitor-CPU AnyEvent-Pcap AnyEvent-Plurk
    AnyEvent-Postfix-Logs AnyEvent-RTPG AnyEvent-Redis AnyEvent-RetryTimer
AnyEvent-ReverseHTTP AnyEvent-Riak AnyEvent-Run AnyEvent-SCGI AnyEvent-SMTP
    AnyEvent-SNMP AnyEvent-Subprocess AnyEvent-Superfeedr AnyEvent-Twitter
AnyEvent-Twitter-Stream AnyEvent-Watchdog AnyEvent-Worker AnyEvent-XMLRPC
                         AnyEvent-XMPP AnyEvent-mDNS
AnyMQ
• Inspired by Tatsumaki::MessageQueue
• Refactored to support timeout handler,
  multiple subscription
• Support binding to other message queues
  using moose traits
• Available on CPAN and github
AnyMQ

my $bus = AnyMQ->new;
my $topic = $bus->topic("Foo");

my $sub = $bus->new_listener($topic);
$sub->poll(sub { my $msg = shift; })

$topic->publish($msg)
AnyMQ with AMQP
my $bus = AnyMQ->new_with_traits
          ( traits => [ ‘AMQP’],
            # host => ..., port => ..);
my $topic = $bus->topic("Foo");

my $sub = $bus->new_listener($topic);
$sub->poll(sub { my $msg = shift; })

$topic->publish($msg)
Please help adding
  message queue
     bindings!
• PSGI, Plack
• AnyEvent, AnyMQ, AMQP
• Server-push, comet
• Websocket
• Web::Hippie, Web::Hippie::Pipe
Comet
The word comet came to English by way of the Latin word cometes. This word, in turn, came
from the Greek word κόμη, which means "hair of the head". The Greek scientist and
philosopher Aristotlefirst used the derived form of κόμη, κομήτης, to describe what he saw
as "stars with hair." Theastronomical symbol for comets is (☄), consisting of a small disc with
three hairlike extensions.




• 2006, coined by Alex Russell
• Server push for real time notification
Widely used

• gmail
• plurk
• facebook updates
Lots of hacks!

• multi-part XHR
• forever iframe, with script callbacks
• spinning “loading” indicator for FF and IE
• number of connections limits
• PSGI, Plack
• AnyEvent, AnyMQ, AMQP
• Server-push, comet
• Websocket
• Web::Hippie, Web::Hippie::Pipe
Websocket
• HTML5 Websocket
• Bidirectional communication
ws = new WebSocket("ws://foo.com:5000”));
ws.onmessage = function(ev) { ... }
ws.send(....);

• Available in latest Chrome / Safari
Putting
Everything
 Together
• PSGI, Plack
• AnyEvent, AnyMQ, AMQP
• Server-push, comet
• Websocket
• Web::Hippie, Web::Hippie::Pipe
The Long
Hair Web
Hippie
Hippie
• Abstracts persistent connections:
  Websocket, MXHR
                         Just a normal PSGI-app!
 enable "+Web::Hippie";
 sub { my $env    = shift;
       my $args   = $env->{'hippie.args'};
       my $handle = $env->{'hippie.handle'};

        # Your handler based on PATH_INFO:
        # /init, /error, /message
 }
Only
Websocket
and mxhr?
Maybe Hippies
  should be
more relaxed...
To relax a
hippie, we
 need.....
Hippie::Pipe


     +
Hippie::Pipe
• Abstracts persistent bidirectional
  connections: Websocket, MXHR, poll
 enable "+Web::Hippie";
 enable "+Web::Hippie::Pipe";
 sub { my $env    = shift;
       my $sub = $env->{'hippie.listener'};
       my $bus = $env->{'hippie.bus'};
       my $msg = $env->{'hippie.message'};
       # Your handler based on PATH_INFO:
       # /init, /error, /message
 }
Client side
hpipe = new Hippie.Pipe();
$(hpipe)
    .bind(“ready”, function() {
         hpipe.send({type:    ‘chat.join’,
                     channel: ‘foo’,
                     ident:   ‘clkao’})
     })
    .bind(“disconnected”, function() {})
    .bind(“message.chat.message”,
           function(e, data) {});
hpipe.init();
DEMO
Thank you!

AnyMQ, Hippie, and the real-time web

  • 1.
    AnyMQ, Hippie andthe real-time web OSDC.TW 2010 Taipei Chia-liang Kao clkao@clkao.org
  • 3.
  • 4.
  • 5.
    • PSGI, Plack •AnyEvent, AnyMQ, AMQP • Server-push, comet • Websocket • Web::Hippie, Web::Hippie:Pipe
  • 6.
    • PSGI, Plack •AnyEvent, AnyMQ, AMQP • Server-push, comet • Websocket • Web::Hippie, Web::Hippie::Pipe
  • 7.
    Plack: Perl WebSuperglue
  • 8.
  • 9.
    $env->{PATH_INFO} Plack::Request->new($env)->path_info $env [ '200', [ 'Content-Type' => 'text/plain' ], [ "Hello World" ], ]
  • 10.
    $env Streaming Interface sub { my $responder = shift; my $writer = $responder->([ '200', [ 'Content-Type' => 'text/plain' ]); # later, of in a callback $writer->write(“Hello world!”); $writer->close(); }
  • 11.
  • 12.
    • PSGI, Plack •AnyEvent, AnyMQ, AMQP • Server-push, comet • Websocket • Web::Hippie, Web::Hippie::Pipe
  • 13.
    AnyEvent • event-driven programming,painless • compatible with many other event loops use AnyEvent::HTTP; http_get "http://osdc.tw/", sub { print $_[1] };
  • 14.
  • 15.
    sub POE::Kernel::ASSERT_DEFAULT (){ 1 } use HTTP::Request; use POE qw(Component::Client::HTTP); POE::Component::Client::HTTP->spawn(   Alias => 'ua', # defaults to 'weeble'   Timeout => 20, # defaults to 180 seconds ); POE::Session->create(   inline_states => {     _start => sub {       POE::Kernel->post(         'ua', # posts to the 'ua' alias         'request', # posts to ua's 'request' state         'response', # which of our states will receive the response         HTTP::Request->new(GET => “http://osdc.tw”),       );     },     _stop => sub {},     response => &response_handler,   }, ); POE::Kernel->run(); exit; sub response_handler {   my ($request_packet, $response_packet) = @_[ARG0, ARG1];   my $request_object = $request_packet->[0];   my $response_object = $response_packet->[0]; }
  • 16.
  • 17.
  • 18.
    AnyEvent::* AnyEvent-AIOAnyEvent-APNS AnyEvent-Atom-Stream AnyEvent-BDB AnyEvent- Beanstalk AnyEvent-Connection AnyEvent-CouchDB AnyEvent-DBI AnyEvent-DBI- Abstract AnyEvent-EditText AnyEvent-FCGI AnyEvent-FCP AnyEvent-FIFO AnyEvent- FastPing AnyEvent-Feed AnyEvent-Filesys-Notify AnyEvent-FriendFeed-Realtime AnyEvent-GPSD AnyEvent-Gearman AnyEvent-Gearman AnyEvent-Gmail-Feed AnyEvent-HTTP AnyEvent-HTTP-MXHR AnyEvent-HTTPD AnyEvent-I3 AnyEvent-IRC AnyEvent-JSONRPC-Lite AnyEvent-Kanye AnyEvent-MP AnyEvent-MPRPC AnyEvent- Memcached AnyEvent-Mojo AnyEvent-Monitor-CPU AnyEvent-Pcap AnyEvent-Plurk AnyEvent-Postfix-Logs AnyEvent-RTPG AnyEvent-Redis AnyEvent-RetryTimer AnyEvent-ReverseHTTP AnyEvent-Riak AnyEvent-Run AnyEvent-SCGI AnyEvent-SMTP AnyEvent-SNMP AnyEvent-Subprocess AnyEvent-Superfeedr AnyEvent-Twitter AnyEvent-Twitter-Stream AnyEvent-Watchdog AnyEvent-Worker AnyEvent-XMLRPC AnyEvent-XMPP AnyEvent-mDNS
  • 19.
    AnyMQ • Inspired byTatsumaki::MessageQueue • Refactored to support timeout handler, multiple subscription • Support binding to other message queues using moose traits • Available on CPAN and github
  • 20.
    AnyMQ my $bus =AnyMQ->new; my $topic = $bus->topic("Foo"); my $sub = $bus->new_listener($topic); $sub->poll(sub { my $msg = shift; }) $topic->publish($msg)
  • 21.
    AnyMQ with AMQP my$bus = AnyMQ->new_with_traits ( traits => [ ‘AMQP’], # host => ..., port => ..); my $topic = $bus->topic("Foo"); my $sub = $bus->new_listener($topic); $sub->poll(sub { my $msg = shift; }) $topic->publish($msg)
  • 22.
    Please help adding message queue bindings!
  • 23.
    • PSGI, Plack •AnyEvent, AnyMQ, AMQP • Server-push, comet • Websocket • Web::Hippie, Web::Hippie::Pipe
  • 24.
    Comet The word cometcame to English by way of the Latin word cometes. This word, in turn, came from the Greek word κόμη, which means "hair of the head". The Greek scientist and philosopher Aristotlefirst used the derived form of κόμη, κομήτης, to describe what he saw as "stars with hair." Theastronomical symbol for comets is (☄), consisting of a small disc with three hairlike extensions. • 2006, coined by Alex Russell • Server push for real time notification
  • 25.
    Widely used • gmail •plurk • facebook updates
  • 26.
    Lots of hacks! •multi-part XHR • forever iframe, with script callbacks • spinning “loading” indicator for FF and IE • number of connections limits
  • 27.
    • PSGI, Plack •AnyEvent, AnyMQ, AMQP • Server-push, comet • Websocket • Web::Hippie, Web::Hippie::Pipe
  • 28.
    Websocket • HTML5 Websocket •Bidirectional communication ws = new WebSocket("ws://foo.com:5000”)); ws.onmessage = function(ev) { ... } ws.send(....); • Available in latest Chrome / Safari
  • 29.
  • 30.
    • PSGI, Plack •AnyEvent, AnyMQ, AMQP • Server-push, comet • Websocket • Web::Hippie, Web::Hippie::Pipe
  • 31.
  • 32.
  • 33.
    Hippie • Abstracts persistentconnections: Websocket, MXHR Just a normal PSGI-app! enable "+Web::Hippie"; sub { my $env = shift; my $args = $env->{'hippie.args'}; my $handle = $env->{'hippie.handle'}; # Your handler based on PATH_INFO: # /init, /error, /message }
  • 34.
  • 35.
    Maybe Hippies should be more relaxed...
  • 36.
    To relax a hippie,we need.....
  • 37.
  • 38.
    Hippie::Pipe • Abstracts persistentbidirectional connections: Websocket, MXHR, poll enable "+Web::Hippie"; enable "+Web::Hippie::Pipe"; sub { my $env = shift; my $sub = $env->{'hippie.listener'}; my $bus = $env->{'hippie.bus'}; my $msg = $env->{'hippie.message'}; # Your handler based on PATH_INFO: # /init, /error, /message }
  • 39.
    Client side hpipe =new Hippie.Pipe(); $(hpipe) .bind(“ready”, function() { hpipe.send({type: ‘chat.join’, channel: ‘foo’, ident: ‘clkao’}) }) .bind(“disconnected”, function() {}) .bind(“message.chat.message”, function(e, data) {}); hpipe.init();
  • 40.
  • 41.