Contenu connexe Similaire à AnyMQ, Hippie, and the real-time web (20) AnyMQ, Hippie, and the real-time web1. AnyMQ, Hippie
and the real-time web
YAPC::Asia 2010 Tokyo
Chia-liang Kao clkao@clkao.org
10. • PSGI, Plack
• AnyEvent, AnyMQ, AMQP
• Server-push, comet
• Websocket
• Web::Hippie, Web::Hippie:Pipe
11. • PSGI, Plack
• AnyEvent, AnyMQ, AMQP
• Server-push, comet
• Websocket
• Web::Hippie, Web::Hippie::Pipe
14. $env
[
'200',
[ 'Content-Type' => 'text/plain' ],
[ "Hello World" ],
]
16. $env->{PATH_INFO}
Plack::Request->new($env)->path_info
$env
[
'200',
[ 'Content-Type' => 'text/plain' ],
[ "Hello World" ],
]
17. $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();
}
18. $env
Streaming Interface(Cont.)
sub {
my $responder = shift;
my $writer = $responder->([
'200',
[ 'Content-Type' => 'text/plain' ]);
# later, of in a callback
my $w; $w = AnyEvent->timer(after => 3,
cb => sub {
$writer->write(“Hello world!”);
$writer->close();
});
}
20. • PSGI, Plack
• AnyEvent, AnyMQ, AMQP
• Server-push, comet
• Websocket
• Web::Hippie, Web::Hippie::Pipe
22. AnyEvent
•
•
use AnyEvent::HTTP;
http_get "http://yapc.asia/",
sub { print $_[1] };
# do something else
24. 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];
}
27. 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
36. 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)
37. 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)
39. AnyMQ with AMQP
my $bus = AnyMQ->new_with_traits my $bus = AnyMQ->new_with_traits
( traits => [ ‘AMQP’], ( traits => [ ‘AMQP’],
# host => ..., port => ..); # host => ..., port => ..);
my $topic = $bus->topic("Foo"); my $topic = $bus->topic("Foo");
my $sub = $bus->new_listener($topic); my $sub = $bus->new_listener($topic);
$sub->poll(sub { my $msg = shift; }) $sub->poll(sub { my $msg = shift; })
$topic->publish($msg) $topic->publish($msg)
my $bus = AnyMQ->new_with_traits my $bus = AnyMQ->new_with_traits
( traits => [ ‘AMQP’], ( traits => [ ‘AMQP’],
# host => ..., port => ..); # host => ..., port => ..);
my $topic = $bus->topic("Foo"); my $topic = $bus->topic("Foo");
my $sub = $bus->new_listener($topic); my $sub = $bus->new_listener($topic);
$sub->poll(sub { my $msg = shift; }) $sub->poll(sub { my $msg = shift; })
$topic->publish($msg) $topic->publish($msg)
40. AnyMQ with AMQP
my $bus = AnyMQ->new_with_traits my $bus = AnyMQ->new_with_traits
( traits => [ ‘AMQP’], ( traits => [ ‘AMQP’],
# host => ..., port => ..); # host => ..., port => ..);
my $topic = $bus->topic("Foo"); my $topic = $bus->topic("Foo");
my $sub = $bus->new_listener($topic); my $sub = $bus->new_listener($topic);
$sub->poll(sub { my $msg = shift; }) $sub->poll(sub { my $msg = shift; })
$topic->publish($msg) $topic->publish($msg)
AMQP
Server
my $bus = AnyMQ->new_with_traits my $bus = AnyMQ->new_with_traits
( traits => [ ‘AMQP’], ( traits => [ ‘AMQP’],
# host => ..., port => ..); # host => ..., port => ..);
my $topic = $bus->topic("Foo"); my $topic = $bus->topic("Foo");
my $sub = $bus->new_listener($topic); my $sub = $bus->new_listener($topic);
$sub->poll(sub { my $msg = shift; }) $sub->poll(sub { my $msg = shift; })
$topic->publish($msg) $topic->publish($msg)
42. • PSGI, Plack
• AnyEvent, AnyMQ, AMQP
• Server-push, comet
• Websocket
• Web::Hippie, Web::Hippie::Pipe
44. 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.
-
45. 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
•
47. !
• XHR
• iframe
• FF IE
•
48. • PSGI, Plack
• AnyEvent, AnyMQ, AMQP
• Server-push, comet
• Websocket
• Web::Hippie, Web::Hippie::Pipe
52. Request:
GET /demo HTTP/1.1
Host: example.com
Connection: Upgrade
Sec-WebSocket-Key2: 12998 5 Y3 1 .P00
Sec-WebSocket-Protocol: sample
Upgrade: WebSocket
Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5
Origin: http://example.com
^n:ds[4U
53. Request:
GET /demo HTTP/1.1
Host: example.com
Connection: Upgrade
Sec-WebSocket-Key2: 12998 5 Y3 1 .P00
Sec-WebSocket-Protocol: sample
Upgrade: WebSocket
Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5
Origin: http://example.com
^n:ds[4U
54. Request:
GET /demo HTTP/1.1
Host: example.com
Connection: Upgrade
Sec-WebSocket-Key2: 12998 5 Y3 1 .P00
Sec-WebSocket-Protocol: sample
Upgrade: WebSocket
Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5
Origin: http://example.com
^n:ds[4U
55. Request:
GET /demo HTTP/1.1
Host: example.com
Connection: Upgrade
Sec-WebSocket-Key2: 12998 5 Y3 1 .P00
Sec-WebSocket-Protocol: sample
Upgrade: WebSocket
Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5
Origin: http://example.com
^n:ds[4U
56. Request:
GET /demo HTTP/1.1
Host: example.com
Connection: Upgrade
Sec-WebSocket-Key2: 12998 5 Y3 1 .P00
Sec-WebSocket-Protocol: sample
Upgrade: WebSocket
Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5
Origin: http://example.com
^n:ds[4U
57. Request:
GET /demo HTTP/1.1
Host: example.com
Connection: Upgrade
Sec-WebSocket-Key2: 12998 5 Y3 1 .P00
Sec-WebSocket-Protocol: sample
Upgrade: WebSocket
Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5
Origin: http://example.com
^n:ds[4U Response:
HTTP/1.1 101 WebSocket Protocol Handshake
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Origin: http://example.com
Sec-WebSocket-Location: ws://example.com/demo
Sec-WebSocket-Protocol: sample
8jKS'y:G*Co,Wxa-
58. Request:
GET /demo HTTP/1.1
Host: example.com
Connection: Upgrade
Sec-WebSocket-Key2: 12998 5 Y3 1 .P00
Sec-WebSocket-Protocol: sample
Upgrade: WebSocket
Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5
Origin: http://example.com
^n:ds[4U Response:
HTTP/1.1 101 WebSocket Protocol Handshake
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Origin: http://example.com
Sec-WebSocket-Location: ws://example.com/demo
Sec-WebSocket-Protocol: sample
8jKS'y:G*Co,Wxa-
59. Request:
GET /demo HTTP/1.1
Host: example.com
Connection: Upgrade
Sec-WebSocket-Key2: 12998 5 Y3 1 .P00
Sec-WebSocket-Protocol: sample
Upgrade: WebSocket
Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5
Origin: http://example.com
^n:ds[4U Response:
HTTP/1.1 101 WebSocket Protocol Handshake
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Origin: http://example.com
Sec-WebSocket-Location: ws://example.com/demo
Sec-WebSocket-Protocol: sample
8jKS'y:G*Co,Wxa-
60. Request:
GET /demo HTTP/1.1
Host: example.com
Connection: Upgrade
Sec-WebSocket-Key2: 12998 5 Y3 1 .P00
Sec-WebSocket-Protocol: sample
Upgrade: WebSocket
Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5
Origin: http://example.com
New in draft#76
^n:ds[4U Response:
HTTP/1.1 101 WebSocket Protocol Handshake
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Origin: http://example.com
Sec-WebSocket-Location: ws://example.com/demo
Sec-WebSocket-Protocol: sample
8jKS'y:G*Co,Wxa-
61. my @keys = map {
my $k = $env>{'HTTP_SEC_WEBSOCKET_KEY'.$_};
join('', $k =~ m/d/g) / scalar @{[$k =~ m/ /g]};
} (1,2);
md5(pack('NN', @keys) . $key3);
64. Websockets API
ws = new WebSocket("ws://foo.com:5000”));
ws.onopen = function(ev) { ... }
ws.onmessage = function(ev) { ... }
ws.onclose = function(ev) { ... }
ws.onerror = function(ev) { ... }
ws.send(....);
65. Websockets API
ws = new WebSocket("ws://foo.com:5000”));
ws.onopen = function(ev) { ... }
ws.onmessage = function(ev) { ... }
ws.onclose = function(ev) { ... }
ws.onerror = function(ev) { ... }
ws.send(....);
Can accept cross-site connection with Origin and Sec-
WebSocket-Origin headers
66. Request:
GET /demo HTTP/1.1
Host: example.com
Connection: Upgrade
Sec-WebSocket-Key2: 12998 5 Y3 1 .P00
Sec-WebSocket-Protocol: sample
Upgrade: WebSocket
Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5
Origin: http://example.com
^n:ds[4U
67. Request:
GET /demo HTTP/1.1
Host: example.com
Connection: Upgrade
Sec-WebSocket-Key2: 12998 5 Y3 1 .P00
Sec-WebSocket-Protocol: sample
Upgrade: WebSocket
Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5
Origin: http://example.com
^n:ds[4U Response:
HTTP/1.1 101 WebSocket Protocol Handshake
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Origin: http://example.com
Sec-WebSocket-Location: ws://example.com/demo
Sec-WebSocket-Protocol: sample
8jKS'y:G*Co,Wxa-
69. • PSGI, Plack
• AnyEvent, AnyMQ, AMQP
• Server-push, comet
• Websocket
• Web::Hippie, Web::Hippie::Pipe
73. • : Websocket, MXHR
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
}
74. • : 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
}
75. • : Websocket, MXHR
mount it to /_hippie
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
}
77. Must use PSGI servers supporting
psgi.nonblocking:
twiggy
feersum
83. Hippie::Pipe
• :
Websocket MXHR poll AnyMQ support
enable "+Web::Hippie";
enable "+Web::Hippie::Pipe", bus => AnyMQ->new;
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:
# /new_listener, /error, /message
}
85. Hippie::Pipe(Cont.)
my $topic = $bus->topic(‘news’);
# my $sub = $env->{'hippie.listener'};
if ($env->{PATH_INFO} eq ‘/new_listener’) {
$sub->subscribe($topic);
}
# $topic->publish({type => ‘news.yapc’,
message => ‘something’});
86. Hippie::Pipe(Cont.)
my $topic = $bus->topic(‘news’);
# my $sub = $env->{'hippie.listener'};
if ($env->{PATH_INFO} eq ‘/new_listener’) {
$sub->subscribe($topic);
}
# $topic->publish({type => ‘news.yapc’,
message => ‘something’});
87. Hippie::Pipe(Cont.)
my $topic = $bus->topic(‘news’);
# my $sub = $env->{'hippie.listener'};
if ($env->{PATH_INFO} eq ‘/new_listener’) {
$sub->subscribe($topic);
}
# $topic->publish({type => ‘news.yapc’,
message => ‘something’});
88. hpipe = new Hippie.Pipe();
$(hpipe)
.bind(“ready”, function() {
hpipe.send({type: ‘news.viewer’,
ident: ‘clkao’})
})
.bind(“disconnected”, function() {})
.bind(“message.news.yapc”,
function(e, data) {});
hpipe.init();
89. hpipe = new Hippie.Pipe();
$(hpipe)
.bind(“ready”, function() {
hpipe.send({type: ‘news.viewer’,
ident: ‘clkao’})
})
.bind(“disconnected”, function() {})
.bind(“message.news.yapc”,
function(e, data) {});
hpipe.init();
90. hpipe = new Hippie.Pipe();
$(hpipe)
.bind(“ready”, function() {
hpipe.send
hpipe.send({type: ‘news.viewer’,
ident: ‘clkao’})
})
.bind(“disconnected”, function() {})
.bind(“message.news.yapc”,
function(e, data) {});
hpipe.init();
91. hpipe = new Hippie.Pipe();
$(hpipe)
.bind(“ready”, function() {
hpipe.send
hpipe.send({type: ‘news.viewer’,
ident: ‘clkao’})
})
.bind(“disconnected”, function() {})
.bind(“message.news.yapc”,
function(e, data) {});
hpipe.init();
93. Hippie::Pipe(Cont.)
# my $sub = $env->{'hippie.listener'};
# my $msg = $env->{'hippie.message'};
if ($env->{PATH_INFO} eq ‘/message’) {
if ($msg->{type} eq ‘news.viewer’) {
$topic->publish({type => ‘news.viewer’,
user => $msg->{user});
}
}
94. Hippie::Pipe(Cont.)
# my $sub = $env->{'hippie.listener'};
# my $msg = $env->{'hippie.message'};
if ($env->{PATH_INFO} eq ‘/message’) {
if ($msg->{type} eq ‘news.viewer’) {
$topic->publish({type => ‘news.viewer’,
user => $msg->{user});
}
}
95. Hippie::Pipe(Cont.)
# my $sub = $env->{'hippie.listener'};
# my $msg = $env->{'hippie.message'};
if ($env->{PATH_INFO} eq ‘/message’) {
if ($msg->{type} eq ‘news.viewer’) {
$topic->publish({type => ‘news.viewer’,
user => $msg->{user});
}
}
# Client:
# bind(“message.news.viewer”, function(){..})
Notes de l'éditeur
most of the time i am cooking
sometimes i wrote some code
things i ve been playing with
multiple event loop
time out handler supported
time out handler supported
time out handler supported
time out handler supported
time out handler supported
time out handler supported
time out handler supported
time out handler supported
please help writing mq bindings
2006, coined by Alex Russell
Server push for real time notification
2006, coined by Alex Russell
Server push for real time notification
multi-part XHR
forever iframe, with script callbacks
spinning “loading” indicator for FF and IE
number of connections limits
only websockets and mxhr?
maybe hippies should be more relaxed