SlideShare una empresa de Scribd logo
1 de 38
AnyEvent Internals (samples of async programming) Mons Anderson <mons@cpan.org>
AnyEvent::Internals AE::* use  AE  5 ; my   $w  = AE::io  $fh ,  0 , sub  { w arn   '$fh is readable' ; }; my   $w  = AE::io  $fh ,  1 , sub  {  warn   '$fh is writable' ; }; my   $w  = AE::timer  1 , 0 , sub  {  warn   '1 second passed' ; }; my   $w  = AE::timer  0 , 1, sub  {  warn   'every 1 second' ; }; my   $w  = AE::signal TERM =>  sub  {  warn   'TERM received' ; }; my   $w  = AE::idle { warn   'Event loop is idle' ; };
AnyEvent::Internals AE::cv use  AE  5 ; my   $cv  = AE:: cv ; any  sub  { async   sub  { calls   sub  { $cv -> send ; }; }; }; $cv -> recv ;  # Run loop until get send
AnyEvent::Internals AE::cv use  AE  5 ; my  $cv   =  AE :: cv  {  warn  &quot;All done&quot;   }; for   ( 1 . .10 ) { $cv -> begin ; async_call   sub   { may_be_nested   sub   { $cv -> end ; } } }
AnyEvent::Internals AE::HTTP use  AnyEvent:: HTTP ; my   $cv  =  AE:: cv ; http_request GET  =>  'http://www.google.ru' , sub  { my  ( $body , $hdr ) =  @_ ; warn   &quot;$hdr->{Status}: $hdr->{Reason}  &quot; ; warn   &quot;Body: &quot; . length ( $body ). &quot; bytes  &quot; ; $cv -> send ; }, ; $cv -> recv ; $ perl http_request.pl 200: OK Body: 10875 bytes
AnyEvent::Internals AE::HTTP sub   http_request ($$@) { my   $cb  =  pop ; my  ( $method , $url ) = (uc shift, shift); my  ( %arg ) = ( timeout =>  10 , recurse =>  10 ,  @_ ); my   %state ;  my   %hdr  = (connection =>  'close' ); my   $err  =  sub  { %state  = (); $cb ->(undef, { Status =>  $_ [ 1 ], Reason =>  $_ [ 0 ] ||  599 , URL  =>  $_ [ 2 ] ||  $url  } ); }; return   $err ->( &quot;Too many redirections&quot; )  if   $arg {recurse} <  0 ; while  ( my  ( $k ,  $v ) = each %{ $arg {headers}}) { $hdr {lc  $k } =  $v }; $hdr { &quot;user-agent&quot; }  // =  &quot;AnyEvent/$AnyEvent::VERSION&quot; ; $hdr { &quot;content-length&quot; } = length  $arg {body} if  length  $arg {body}  or   $method   ne   &quot;GET&quot; ; # ... }
AnyEvent::Internals AE::HTTP use AnyEvent :: Socket ; sub   http_request ($$@) { # ... my  ( $rscheme ,  $uauthority ,  $rpath ,  $query ,  $fragment ) = $url  =~ m{ (?:([^:/?#]+):)?(?://([^/?#]*))? ([^?#]*)(?:([^#]*))?(?:#(.*))? }x; $rscheme  = lc  $rscheme ; my   $rport  =  $rscheme   eq   &quot;http&quot;   ?  80  : $rscheme   eq   &quot;https&quot;  ?  443 : return   $err ->( &quot;Only http/https are supported&quot; ); $uauthority  =~  /^(?: .* )? ([^:]+) (?: : (+) )?$/ x or return   $err ->( &quot;Unparsable URL&quot; ); my   $rhost  =  $1 ;  $rport  =  $2   if  defined  $2 ; $hdr {host}  // = defined  $2  ?  &quot;$uhost:$2&quot;  :  &quot;$uhost&quot; ; $rhost  =~  s/^(.*)$/$1/ ; $rpath  .=  &quot;?$query&quot;   if  length  $query ;  $rpath  =~ s%^ /?%/ %; $state {connect_guard} = tcp_connect  $rhost ,  $rport ,  sub  { # ... },  sub  {  $arg {timeout} }; defined wantarray  && AnyEvent::Util::guard {  %state  = () }; }
AnyEvent::Internals AE::HTTP use AnyEvent :: Socket ; tcp_connect $host , $port , sub   { # Connect sub my   ( $fh ,  $addr ,  $port ) =   @_ ; # ... }, sub   { # Prepare sub my   ( $socket ) =   @_ ; return   $timeout ; };
AnyEvent::Internals AE::HTTP use AnyEvent :: Handle ; sub  http_request ($$ @ ) { # ... $state { connect_guard } =  tcp_connect  $rhost ,   $rport ,  sub  { $state { fh } =  shift or return  $err ->( &quot;$!&quot; ); return unless delete  $state { connect_guard }; $state { handle } =  new AnyEvent :: Handle fh   =>   $state { fh },  timeout  =>   $arg { timeout }, on_error   =>  sub  {   $err ->( $_ [ 2 ]) }, on_eof   =>  sub  {   $err ->( &quot;Unexpected end-of-file&quot; ) } ; $state { handle }-> starttls   ( &quot;connect&quot; )  if  $rscheme  eq  &quot;https&quot; ; $state { handle }-> push_write   ( &quot;$method $rpath HTTP/1.0 1512 &quot; . join (   &quot;&quot; ,  map  {  defined  $hdr { $_ } ?   &quot;$_: &quot; . delete ( $hdr { $_ }). &quot; 1512 &quot; :  delete  $hdr { $_ }||() }  keys  %hdr   ). &quot; 1512 &quot; . delete ( $arg { body }) ); $state { handle }-> push_read   ( line  =>  qr { 15 ? 12 },  sub  { # ... }); },  sub  {   $arg { timeout } }; # ... }
AnyEvent::Internals AE::HTTP use AnyEvent :: Handle ; $h -> push_write ( $data ); $h -> push_read (  chunk =>   $bytes ,  sub  { my  ( $h , $data ) =   @_ ; # ... }); $h -> push_read (  line =>  qr /EOL/ ,  sub  { ... } ); $h -> unshift_read (  chunk =>   $bytes ,  sub  { ... } ); $h -> unshift_read ( line => qr /EOL/ ,  sub  { ... } ); $h -> on_read (  sub  { ... } ); $h ->{ rbuf }
AnyEvent::Internals AE::HTTP sub  http_request ($$ @ ) { # ... $state { handle }-> push_read   ( line  =>  qr { 15 ? 12 }, sub   { $_ [ 1 ] =~   /^HTTP ([ 0 - 9 .]+)   + ([ 0 - 9 ]{ 3 }) ( ? :   + ([^ 1512 ]*) ) ? / ix or return   $err ->( &quot;Invalid server response ($_[1])&quot; ); my   %hdr   = (  Status  =>   &quot;,$2&quot; , Reason  =>   &quot;,$3&quot; , URL  =>   &quot;,$url&quot;   ); $_[0] -> unshift_read   ( line  =>  qr {( ? <![^ 12 ]) 15 ? 12 }, sub   { # ... } ); } ); # ... }
AnyEvent::Internals AE::HTTP sub  http_request ($$ @ ) { # ... $_[0] -> unshift_read   ( line  =>  qr {( ? <![^ 12 ]) 15 ? 12 }, sub   { for   ( &quot;$_[1]&quot; ) {  y /15/ / d ; $hdr { lc  $1 } .=   &quot;,$2&quot;   while /  G   ([^: 00 - 37 ]*): [ 1140 ]* ((  ? : [^ 12 ]+ |   12 [ 1140 ] )*)   12   / gxc ; /$/   or return   $err ->( &quot;Garbled response headers&quot; ); } substr   $_ ,   0 ,   1 ,   ''   for  values  %hdr ; if   ( $hdr { location } !~   /^(?: $ | [^: ?#]+ : )/x) { $hdr { location } =~   s/^+/ /; my   $url   =   &quot;$rscheme://$rhost:$rport&quot; ; unless   ( $hdr { location } =~  s {^/}{}) { $url   .=   $rpath ; $url   =~  s { /[^/ ]*$}{}; } $hdr { location } =   &quot;$url/$hdr{location}&quot; ; } # ... }); # ... }
AnyEvent::Internals AE::HTTP sub  http_request ($$ @ ) { # ... my   $redirect ; if   ( $arg { recurse }) { if   ( ( $hdr { Status } =~   /^30[12]$/   and   $method   ne   &quot;POST&quot;   ) or   ( $hdr { Status } ==   307 and   $method   =~   /^(?:GET|HEAD)$/ ) ) { $redirect   =   1 ; }   elsif   ( $hdr { Status } ==   303 ) { $method   =   &quot;GET&quot;   unless   $method   eq   &quot;HEAD&quot; ; $redirect   =   1 ; } } my   $finish   =  sub   { $state { handle }-> destroy if   $state { handle }; %state   = (); if   ( $redirect   &&  exists  $hdr { location }) { http_request   $method   =>   $hdr { location }, %arg ,  recurse  =>   $arg { recurse } -   1 ,   $cb ; }  else   { $cb ->( $_ [ 0 ],   $_ [ 1 ]); } }; # ... }
AnyEvent::Internals AE::HTTP sub  http_request ($$ @ ) { # ... my   $len   =   $hdr { &quot;content-length&quot; }; if   (   $hdr { Status } =~   /^(?:1..|[23]04)$/ or   $method   eq   &quot;HEAD&quot; or   ( defined  $len   && ! $len ) ) { # no body $finish ->( &quot;&quot; ,  %hdr ); }   else   { # ...   } # ... }
AnyEvent::Internals AE::HTTP sub  http_request ($$ @ ) { # ... $_ [ 0 ]-> on_eof   ( undef ); if   ( $len ) {   # have content length $_ [ 0 ]-> on_error   ( sub  { $finish ->( undef , {  Status  =>   599 , Reason  =>   $_ [ 2 ], URL  =>   $url   }); }); $_ [ 0 ]-> on_read   ( sub  { $finish ->( substr ( delete  $_ [ 0 ]{ rbuf },   0 ,   $len ,   &quot;&quot; ), %hdr )  if  $len   <=  length  $_ [ 0 ]{ rbuf }; }); }  else   {   # have no content-length, read until end $_ [ 0 ]-> on_error   ( sub  { $!{  EPIPE } || !$! ?   $finish ->( delete  $_ [ 0 ]{ rbuf },  %hdr ) :  $finish ->( undef ,{  Status  =>   599 , Reason  =>   $_ [ 2 ], URL  =>   $url   }); }); $_ [ 0 ]-> on_read ( sub  {}); } # ... }
AnyEvent::Internals AE::HTTP use  AnyEvent :: Socket ; use  AnyEvent :: Handle ; sub   http_request ($$ @ ) { my  $cb   =   pop ; my  ( $method , $url ) = ( uc shift ,  shift ); my  ( %arg ) = (  timeout  =>   10 ,  recurse  =>   10 ,   @_ ); my  %state ;  my   %hdr   = ( connection  =>   'close' ); my  $err   =   sub   {   %state   = (); $cb ->( undef ,  Status  =>   $_ [ 1 ],  Reason  =>   $_ [ 0 ]|| 599 ,  URL  =>   $_ [ 2 ]|| $url   ) }; return   $err ->( &quot;Too many redirections&quot; )   if   $arg { recurse } <   0 ; while   ( my  ( $k ,   $v ) =  each  %{ $arg { headers }}) {   $hdr { lc  $k } =   $v   }; my  ( $rscheme ,   $uauthority ,   $rpath ,   $query ,   $fragment ) = $url   =~  m |( ? :([^: /?#]+):)?(?://([^/? #]*))?([^?#]*)(?:([^#]*))?(?:#(.*))?|; $rscheme   =  lc  $rscheme ; my  $rport   =   $rscheme   eq   &quot;http&quot;   ?  80   :   $rscheme   eq   &quot;https&quot;  ?  443 :   return   $err ->( &quot;Only http and https URL schemes supported&quot; ); $uauthority   =~  /^(?: .* )? ([^:]+) (?: : (+) )?$/ x or return   $err ->( &quot;Unparsable URL&quot; ); my  $rhost   =   $1 ;   $rport   =   $2   if  defined  $2 ; $hdr { host }  // =  defined  $2  ?  &quot;$rhost:$2&quot;   :   &quot;$rhost&quot; ; $rhost   =~  s/^(.*)$/$1/ ; $rpath   .=   &quot;?$query&quot;   if  length  $query ;   $rpath   =~  s %^ /?%/ %; $hdr { &quot;user-agent&quot; }  // =   &quot;AnyEvent/$AnyEvent::VERSION&quot; ; $hdr { &quot;content-length&quot; } =  length  $arg { body }   if  length  $arg { body }   or   $method   ne   &quot;GET&quot; ; $state { connect_guard } =  tcp_connect  $rhost ,   $rport ,   sub   { $state { fh } =  shift  or return   %state =(), $err ->( &quot;$!&quot; ); return unless  delete  $state { connect_guard }; $state { handle } =  new AnyEvent :: Handle fh   =>   $state { fh },  timeout  =>   $arg { timeout }, on_error   =>   sub   {   $err ->( $_ [ 2 ]) }, on_eof   =>   sub   {   $err ->( &quot;Unexpected end-of-file&quot; ) }, ; $state { handle }-> starttls   ( &quot;connect&quot; )   if   $rscheme   eq   &quot;https&quot; ; $state { handle }-> push_write   ( &quot;$method $rpath HTTP/1.0 1512 &quot; . join (   &quot;&quot; ,  map  {  defined  $hdr { $_ } ?   &quot;$_: &quot; . delete ( $hdr { $_ }). &quot; 1512 &quot; :  delete  $hdr { $_ }||() }  keys  %hdr   ). &quot; 1512 &quot; . delete ( $arg { body }) ); $state { handle }-> push_read   ( line  =>  qr { 15 ? 12 },   sub   { $_ [ 1 ] =~  /^HTTP ([ 0 - 9 .]+)   + ([ 0 - 9 ]{ 3 }) ( ? :   + ([^ 1512 ]*) ) ? / ix or return   $err ->( &quot;Invalid server response ($_[1])&quot; ); my  %hdr   = (  Status  =>   &quot;,$2&quot; ,  Reason  =>   &quot;,$3&quot; ,  URL  =>   &quot;,$url&quot;   ); $state { handle }-> unshift_read   ( line  =>  qr {( ? <![^ 12 ]) 15 ? 12 },   sub   { for   ( &quot;$_[1]&quot; ) {  y/15/ / d ; $hdr { lc  $1 } .=   &quot;,$2&quot;   while /  G   ([^: 00 - 37 ]*): [ 1140 ]* ((  ? : [^ 12 ]+ |   12 [ 1140 ] )*)   12   / gxc ; /$/  or return   $err ->( &quot;Garbled response headers&quot; ); } substr   $_ ,   0 ,   1 ,   ''   for  values  %hdr ; if   ( $hdr { location } !~  /^(?: $ | [^:?#]+ : )/x) { $hdr { location } =~  s/^+/ /; my  $url   =   &quot;$rscheme://$rhost:$rport&quot; ; unless   ( $hdr { location } =~  s {^/}{}) { $url   .=   $rpath ; $url   =~  s { /[^/ ]*$}{}; } $hdr { location } =   &quot;$url/$hdr{location}&quot; ; } my  $redirect ; if   ( $arg { recurse }) { if   ( ( $hdr { Status } =~  /^30[12]$/   and   $method   ne   &quot;POST&quot;   ) or   ( $hdr { Status } ==   307   and   $method   =~  /^(?:GET|HEAD)$/ ) ) { $redirect   =   1 ; }   elsif   ( $hdr { Status } ==   303 ) { $method   =   &quot;GET&quot;   unless   $method   eq   &quot;HEAD&quot; ; $redirect   =   1 ; } } my  $finish   =   sub   { $state { handle }-> destroy  if   $state { handle }; %state   = (); if   ( $redirect   &&  exists  $hdr { location }) { http_request   $method   =>   $hdr { location }, %arg ,  recurse  =>   $arg { recurse } -   1 ,   $cb ; }   else   { $cb ->( $_ [ 0 ],   $_ [ 1 ]); } }; my  $len   =   $hdr { &quot;content-length&quot; }; if   (   $hdr { Status } =~  /^(?:1..|[23]04)$/ or   $method   eq   &quot;HEAD&quot; or   ( defined  $len   && ! $len ) ) { # no body $finish ->( &quot;&quot; ,  %hdr ); }   else   { $_ [ 0 ]-> on_eof   ( undef ); if   ( $len ) {   # have content length $_ [ 0 ]-> on_error   ( sub   {   $finish ->( undef , {  Status  =>   599 ,  Reason  =>   $_ [ 2 ],  URL  =>   $url   }) }); $_ [ 0 ]-> on_read   ( sub   { $finish ->( substr ( delete  $_ [ 0 ]{ rbuf },   0 ,   $len ,   &quot;&quot; ),  %hdr ) if   $len   <=  length  $_ [ 0 ]{ rbuf }; }); }   else   {   # have no content-length, read until end $_ [ 0 ]-> on_error   ( sub   { $!{  EPIPE } || !$! ?   $finish ->( delete  $_ [ 0 ]{ rbuf },  %hdr ) :   $finish ->( undef ,{  Status  =>   599 ,  Reason  =>   $_ [ 2 ],  URL  =>   $url   }); }); $_ [ 0 ]-> on_read ( sub   {}); } } }); }); },   sub   {   $arg { timeout } }; defined wantarray   &&  AnyEvent :: Util :: guard  {   %state   = () } }
AnyEvent::Internals AE::HTTPServer my   $server   =  AnyEvent :: HTTP :: Server -> new ( port   =>   80 , request   =>   sub   { my   $r   =   shift ; if   ( $r -> wants_websocket ) { $r -> upgrade ( 'websocket' ,   sub   { if   ( my   $ws   =  shift ) { $ws -> onmessage ( sub   { $ws -> send ( &quot;@_&quot; ); }); $ws -> send ( &quot;Hello!&quot; ); }   else   { warn   &quot;Upgrade failed: @_&quot; ; } }); }   else   { # ... } }, );
AnyEvent::Internals AE::HTTPServer tcp_server  $self ->{ host },   $self ->{ port },   sub   { my   $fh   =  shift or return  warn  &quot;couldn't accept client: $!&quot; ; my   ( $host ,   $port ) =   @_ ; my   $con   =   $self ->{ connection_class }-> new ( server   =>   $self , fh   =>   $fh , host   =>   $host , port   =>   $port , on_error   =>   sub   { my   $con   =   shift ; warn   &quot;@_&quot; ; delete   $self ->{ con }{ $con ->{ id }}; }, ); $self ->{ con }{ $con ->{ id }} =   $con ; },   sub   { 1024 ; };
AnyEvent::Internals AE::HTTPServer sub  Connection :: new  { my   $self   =  bless  {},   shift ; weaken   ( my   $this   =   $self ); my   %args   =   @_ ; my   $srv   =   $args { server };   my   $fh   =   $args { fh }; my   $h   =  AnyEvent :: Handle :: Writer -> new ( fh   =>   $args { fh }, on_eof   =>   sub   {   $this   or return ;   $this -> error ( &quot;EOF&quot; ) }, on_error  =>   sub   {   $this   or return ;   $this -> error ( &quot;$!&quot; ) }, ); weaken ( $self ->{ srv } =   $args { server }); $self ->{ id } =  int  $self ; $self ->{ fh } =   $args { fh };   $self ->{ h }  =   $h ; $self ->{ host } =   $args { host }; $self ->{ port } =   $args { port }; $self ->{ r }  = [];   # Request queue $self ->{ ka_timeout } =   $srv ->{ keep_alive_timeout } ||   30 ; if   ( $srv ->{ keep_alive }) { $self ->{ touch } =  AE :: now ; $self -> ka_timer ; } $self -> read_header (); return   $self ; }
AnyEvent::Internals AE::HTTPServer sub  Connection :: ka_timer  { my   $self   =   shift ; $self ->{ srv }   or return   $self -> destroy ; weaken   ( my   $this   =   $self ); $self ->{ ka } =  AE :: timer $this ->{ ka_timeout } +   1 ,   0 ,   sub   { $this   or return ; if   ( AE :: now  -   $this ->{ touch } >=   $this ->{ ka_timeout }) { $this -> close ; }   else   { $this -> ka_timer ; } } ; }
AnyEvent::Internals AE::HTTPServer sub  Connection :: read_header  { my   $self   =   shift ;   $self ->{ srv }   or return   $self -> destroy ; weaken   ( my   $con   =   $self ); $con ->{ h }-> push_read ( chunk  =>   3   =>   sub   {   $con   or return ;   shift ; my   $pre   =   shift ; if   ( $pre   =~  m {^<}) { $con ->{ h }-> unshift_read ( regex  =>  qr {.+ ? >} =>   sub   { my   $xml   =   $pre . shift (); # Hanlde XML here $con -> destroy (); }); }   else   { $con ->{ h }-> unshift_read ( line  =>   sub   {   $con   or return ; shift ; my   $line   =   $pre . shift ; if   ( $line   =~   /(+) 40 (+) 40 HTTP (  + .  +)/ xso ) { my   ( $meth ,   $url ,   $hv ) = ( $1 ,   $2 ,   $3 ); $con ->{ method }  =   $meth ; $con ->{ uri }  =   $url ; $con ->{ version } =   $hv ; $con -> read_headers (); } elsif   ( $line   eq   '' ) {   $con -> read_header ();   } else   {   $con -> fatal_error ( 400 );   } }); }; }); }
AnyEvent::Internals AE::HTTPServer sub  Connection :: read_headers  { my   ( $self ) =   @_ ;   $self ->{ srv }   or return   $self -> destroy ; weaken   ( my   $con   =   $self ); $self ->{ h }-> unshift_read ( line   =>  qr {( ? <![^ 12 ]) 15 ? 12 } o , sub   {   $con   or return ; my   ( $h ,   $data ) =   @_ ; my   $hdr   =  HTTP :: Easy :: Headers -> decode ( $data ) //   return   $con -> fatal_error ( 400 ); my   $r   =   $con ->{ srv }{ request_class }-> new ( method   =>  delete  $con ->{ method }, uri   =>  delete  $con ->{ uri }, host   =>   $hdr ->{ Host }, headers   =>   $hdr , ); push @ {   $con ->{ r } },   $r ; weaken ( $r ->{ con } =   $con ); weaken ( $con ->{ r }[- 1 ]); # ... } ); }
AnyEvent::Internals AE::HTTPServer sub   {   $con   or return ; # ... $hdr ->{ connection } =  lc  $hdr ->{ connection }; if   ( $hdr ->{ connection }   eq   'close'   or   $con ->{ version } <   1.1 ) { delete  $con ->{ ka };  $con ->{ type } =   'close' ; $con ->{ close } =   1 ;   } elsif   ( $hdr ->{ connection } =~   /keep-alive/ ) { $con ->{ close } =   0 ;   $con ->{ type } =   'keep-alive' ; } elsif   ( $hdr ->{ connection }   eq   'upgrade' ) { delete   $con ->{ ka };   $con ->{ type } =   'upgrade' ; $con ->{ close } =   0 ; } if   ( defined  $hdr ->{ 'content-length' }) { $con ->{ h }-> unshift_read ( chunk  =>   $hdr ->{ 'content-length' },   sub   { my   ( $hdl ,   $data ) =   @_ ; $con -> handle_request ( $r ,   $data ); $con -> read_header ()   if   $con ->{ ka }; }); }   else   { $con -> handle_request ( $r ); $con -> read_header ()   if   $con ->{ ka }; } }
AnyEvent::Internals AE::HTTPServer sub  Request :: response  { my   $self   =   shift ; $self ->{ con }   or return   $self -> dispose ; $self ->{ con }-> response ( $self ,   @_ ); $self -> dispose ; } sub  Request :: dispose  { my   $self   =   shift ; return   % $self   = (); } sub  Request :: DESTROY  { my   $self   =   shift ; $self ->{ con }   or return   % $self   = (); $self ->{ con }-> response ( $self ,   404 ,   '' , msg  =>   &quot;Request not handled&quot; ); } sub  Request :: wants_websocket  { my   $self   =   shift ; return  lc  $self ->{ headers }{ connection }   eq   'upgrade' &&  lc  $self ->{ headers }{ upgrade }   eq   'websocket'  ?  1   :   0 ; }
AnyEvent::Internals AE::HTTPServer sub  Request :: upgrade  { my   $self   =   shift ; my   $cb   =   pop ; my   $type   =   shift ; my   $headers  =   shift  ||  HTTP:: Easy:: Headers-> new ({}); if  ( lc  $type   eq   'websocket' ) { $headers ->{ upgrade} =   'WebSocket' ; $headers ->{ connection} =   'Upgrade' ; $headers ->{ 'websocket-origin' } ||=   $self ->{headers}{ origin}; $headers ->{ 'websocket-location' } ||=   do  { my   $loc  =  URI-> new_abs ( $self ->{ uri}, &quot;http://$self->{headers}{host}&quot; ); $loc  =   &quot;$loc&quot; ;  $loc  =~  s{^ http}{ ws};  $loc ; }; $self ->{ con}-> response ( $self , 101 , '' , headers =>   $headers , msg  =>   &quot;Web Socket Protocol Handshake&quot; ); my   $ws  =   $self ->{con}{ srv}{ websocket_class}-> new ( con  =>   $self ->{con}, ); $self -> dispose ; return   $cb ->( $ws ); } else  { return   $cb ->(undef,   &quot;Unsupported upgrade type: $type&quot; ); } }
AnyEvent::Internals AE::HTTPServer sub  Connection :: response  { my   ( $con , $r , $code , $content , %args ) =   @_ ; my   $msg   =   $args { msg } ||   $HTTP :: Easy :: Status :: MSG { $code } ; my   $hdr   =   $args { headers } ||  HTTP :: Easy :: Headers -> new ({}); # Resolve pipeline if   ( @ { $con ->{ r }}   and   $con ->{ r }[ 0 ] ==   $r ) { shift @ {   $con ->{ r } }; }   else   { $r ->{ ready } = [   $code ,   $msg ,   $hdr ,   $content   ]; return ; } my   $res   =   &quot;HTTP/$con->{version} $code $msg 1512 &quot; ; $hdr ->{ 'content-type' } ||=   'text/html' ; if   ( ref  $content   eq   'HASH' ) { if   ( $content ->{ sendfile }) { $content ->{ size } = $hdr ->{ 'content-length' } = - s  $content ->{ sendfile }; } } $hdr ->{ connection } ||=   $con ->{ type }; if   ( $code   >=   400   and   ! length  $content   ) { $content   =   &quot;<h1>$code $msg</h1>&quot; ; } # ...
AnyEvent::Internals AE::HTTPServer # ... $hdr ->{ 'content-length' } =  length  $content if not   ( defined  $hdr ->{ 'content-length' }) and not  ref  $content and   $code   !~   /^(?:1|[23]04)$/ ; $res   .=   $hdr -> encode (); $con ->{ h }-> push_write ( $res ); if   ( ref  $content   eq   'HASH' ) { if   ( $content ->{ sendfile }) { $con ->{ h }-> push_sendfile ( $content ->{ sendfile },   $content ->{ size }); }   else   { die   &quot;Bad response content&quot; ; } }   else   { $con ->{ h }-> push_write ( $content )   if  length  $content ; } if   ( $con ->{ close }) {   $con -> close (); } elsif   (  @ { $con ->{ r }}   and   $con ->{ r }[ 0 ]{ ready }) { $con -> response ( $con ->{ r }[ 0 ], @ { $con ->{ r }[ 0 ]{ ready }}); } }
AnyEvent::Internals AE::Memcached my   $cv   =  AE :: cv ; $cv -> begin ; $cv -> begin ( sub   {   $cv -> send  }); my   $memd   =  AnyEvent :: Memcached -> new ( servers   => [   '127.0.0.1:11211'   ], cv   =>   $cv , namespace   =>   &quot;test:&quot; , ); $memd -> set ( &quot;key1&quot; ,   &quot;val1&quot; ,  cb  =>   sub   { shift   or return  warn  &quot;Set key1 failed: @_&quot; ; $memd -> get ( &quot;key1&quot; ,  cb  =>   sub   { my   ( $v , $e ) =   @_ ; $e   and return  warn  &quot;Get failed: $e&quot; ; warn   &quot;Got value for key1: $v&quot; ; }); }); $cv -> end ; $cv -> recv ;
AnyEvent::Internals AE::Memcached sub  set  {  shift -> _set (  set  =>   @_ ) } sub  _set  { my   $self , $cmd , $key ) =  splice  @_ , 0 , 3 ; my   $cas ; if   ( $cmd   eq   'cas' ) {   $cas   =   shift ; } my   $val   =   shift ; # Some preparations... $self -> _do ( $key , &quot;$cmd $self->{namespace}%s $flags $expire $len&quot; . (  defined  $cas  ?  ' ' . $cas   :   '' ). &quot; 1512 $val&quot; , sub   { local   $_   =   shift ; if   ( $_   eq   'STORED' )  {   return   1   } elsif   ( $_   eq   'NOT_STORED' ) {   return   0   } elsif   ( $_   eq   'EXISTS' )  {   return   0   } else   {   return  undef ,   $_   } }, cb   =>   $args { cb }, ); }
AnyEvent::Internals AE::Memcached sub  _do  { my   ( $self , $key , $com , $wrk , %args ) =   @_ ; my   $servers   =   $self ->{ hash }-> servers ( $key ); my   %res ; my   %err ; my   $res ; $_   and   $_ -> begin  for   $self ->{ cv },   $args { cv }; my   $cv   =  AE :: cv  { if   ( $res   != - 1 ) {   $args { cb }( $res ); } else   {   $args { cb }(  undef ,   dumper ( %err ) ); } $_   and   $_ -> end  for   $args { cv },   $self ->{ cv }; }; for   my   $srv   (  keys  % $servers   ) { for   my   $real   ( @ {   $servers ->{ $srv } }) { $cv -> begin ; my   $cmd   =   $com ; substr ( $cmd ,   index ( $cmd , '%s' ), 2 ) =   $real ; $self ->{ peers }{ $srv }{ con }-> command ( '...'   ); } } return ; }
AnyEvent::Internals AE::Memcached # ... $self ->{ peers }{ $srv }{ con }-> command ( $cmd , cb   =>   sub   { if   ( defined (   local   $_   =  shift  )) { my   ( $ok , $fail ) =   $wrk ->( $_ ); if   ( defined  $ok ) { $res { $real }{ $srv } =   $ok ; $res   = (! defined  $res ) ||   $res   ==   $ok ?  $ok   : - 1 ; }   else   { $err { $real }{ $srv } =   $fail ; $res   = - 1 ; } }   else   { $err { $real }{ $srv } =   $_ ; $res   = - 1 ; } $cv -> end ; } ); # ...
AnyEvent::Internals AE::Memcached sub  Peer :: command  { my   $self   =   shift ; if   ( $self ->{ connected }) { return   $self ->{ con }-> command (   @_   ); } else   { my   ( $cmd , %args ) =   @_ ; $self -> conntrack (  command  =>  @_ ,   $args { cb } ); } }
AnyEvent::Internals AE::Memcached sub  Peer :: conntrack  { my   $self   =   shift ; my   ( $method , $args , $cb ) =   @_ ; if ( $self ->{ connecting }   and   $self ->{ failed }) { $cb   and   $cb ->( undef ,   &quot;Not connected&quot; ); return ; } elsif   (! $self ->{ connected }) { # connect } else   { return   $self ->{ con }-> $method ( @ $args ); } }
AnyEvent::Internals AE::Memcached sub  Peer :: connect  { my   $self   =   shift ; $self ->{ connecting }   and return ; $self -> reg_cb (  connected  =>   sub   {   $self ->{ failed } =   0 ; } ); $self -> reg_cb (  connfail  =>   sub   {   $self ->{ failed } =   1 ; } ); $self -> reg_cb (  disconnect  =>   sub   { shift ; shift ; % $self   or return ; my   $e   =   @_  ?  &quot;@_&quot;   :   &quot;disconnected&quot; ; for   (  keys  %{ $self ->{ waitingcb }} ) { if   ( $self ->{ waitingcb }{ $_ }) { $self ->{ waitingcb }{ $_ }( undef , $e ); } delete   $self ->{ waitingcb }{ $_ }; } } ); $self -> next :: method ( @_ ); return ; }
AnyEvent::Internals AE::Memcached elsif   (! $self ->{ connected }) { my   @args   =  @ $args ;   # copy to avoid rewriting my  ( $c , $t ); weaken (  $self  ); weaken (  $self ->{waitingcb}{int  $cb } =  $cb  )  if   $cb ; $c  =  $self -> reg_cb (  connected  =>  sub  { shift -> unreg_me ; undef  $c ; undef  $t ; $self   or return ; delete   $self ->{waitingcb}{int  $cb }  if   $cb ; return   $self ->{con}-> $method ( @args ); }); $t  = AE:: timer  $self ->{timeout}, 0,  sub  { undef   $c ;undef  $t ; $self   or return ; if  ( $cb ){ delete   $self ->{waitingcb}{int  $cb }; $cb ->(undef,  &quot;Connect timeout&quot; ); } }, ); $self -> connect (); }
AnyEvent::Internals Resources Documentation ,[object Object]
AnyEvent
AnyEvent::Intro Authors

Más contenido relacionado

La actualidad más candente

R57shell
R57shellR57shell
R57shell
ady36
 

La actualidad más candente (20)

Code obfuscation, php shells & more
Code obfuscation, php shells & moreCode obfuscation, php shells & more
Code obfuscation, php shells & more
 
Creating own language made easy
Creating own language made easyCreating own language made easy
Creating own language made easy
 
Groovy every day
Groovy every dayGroovy every day
Groovy every day
 
Simple Ways To Be A Better Programmer (OSCON 2007)
Simple Ways To Be A Better Programmer (OSCON 2007)Simple Ways To Be A Better Programmer (OSCON 2007)
Simple Ways To Be A Better Programmer (OSCON 2007)
 
R57shell
R57shellR57shell
R57shell
 
PHP code examples
PHP code examplesPHP code examples
PHP code examples
 
Parsing JSON with a single regex
Parsing JSON with a single regexParsing JSON with a single regex
Parsing JSON with a single regex
 
Electrify your code with PHP Generators
Electrify your code with PHP GeneratorsElectrify your code with PHP Generators
Electrify your code with PHP Generators
 
Perl Bag of Tricks - Baltimore Perl mongers
Perl Bag of Tricks  -  Baltimore Perl mongersPerl Bag of Tricks  -  Baltimore Perl mongers
Perl Bag of Tricks - Baltimore Perl mongers
 
wget.pl
wget.plwget.pl
wget.pl
 
The Magic Of Tie
The Magic Of TieThe Magic Of Tie
The Magic Of Tie
 
Routing System In Symfony 1.2
Routing System In Symfony 1.2Routing System In Symfony 1.2
Routing System In Symfony 1.2
 
Inc
IncInc
Inc
 
Bag of tricks
Bag of tricksBag of tricks
Bag of tricks
 
循環参照のはなし
循環参照のはなし循環参照のはなし
循環参照のはなし
 
Text in search queries with examples in Perl 6
Text in search queries with examples in Perl 6Text in search queries with examples in Perl 6
Text in search queries with examples in Perl 6
 
Looping the Loop with SPL Iterators
Looping the Loop with SPL IteratorsLooping the Loop with SPL Iterators
Looping the Loop with SPL Iterators
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & REST
 
Writing Modular Command-line Apps with App::Cmd
Writing Modular Command-line Apps with App::CmdWriting Modular Command-line Apps with App::Cmd
Writing Modular Command-line Apps with App::Cmd
 
dotCloud and go
dotCloud and godotCloud and go
dotCloud and go
 

Destacado

Владимир Перепелица "Модули"
Владимир Перепелица "Модули"Владимир Перепелица "Модули"
Владимир Перепелица "Модули"
Media Gorod
 
Buytaert kris tools
Buytaert kris toolsBuytaert kris tools
Buytaert kris tools
kuchinskaya
 
Развитие интернета в регионах России
Развитие интернета в регионах РоссииРазвитие интернета в регионах России
Развитие интернета в регионах России
Media Gorod
 
Communication Online
Communication OnlineCommunication Online
Communication Online
kraemera
 

Destacado (9)

Введение в веб-технологии. Лекция.
Введение в веб-технологии. Лекция. Введение в веб-технологии. Лекция.
Введение в веб-технологии. Лекция.
 
Разработка документации для RESTful API: как убить трёх зайцев одним. Moscow....
Разработка документации для RESTful API: как убить трёх зайцев одним. Moscow....Разработка документации для RESTful API: как убить трёх зайцев одним. Moscow....
Разработка документации для RESTful API: как убить трёх зайцев одним. Moscow....
 
Guitar Hero, Wikipedia, VK, Perl, Like it!
Guitar Hero, Wikipedia, VK, Perl, Like it!Guitar Hero, Wikipedia, VK, Perl, Like it!
Guitar Hero, Wikipedia, VK, Perl, Like it!
 
Владимир Перепелица "Модули"
Владимир Перепелица "Модули"Владимир Перепелица "Модули"
Владимир Перепелица "Модули"
 
Hexlet Deck
Hexlet DeckHexlet Deck
Hexlet Deck
 
Buytaert kris tools
Buytaert kris toolsBuytaert kris tools
Buytaert kris tools
 
Развитие интернета в регионах России
Развитие интернета в регионах РоссииРазвитие интернета в регионах России
Развитие интернета в регионах России
 
Ленивые итераторы для разбора разнородных данных. Михаил Озеров. Moscow.pm 6 ...
Ленивые итераторы для разбора разнородных данных. Михаил Озеров. Moscow.pm 6 ...Ленивые итераторы для разбора разнородных данных. Михаил Озеров. Moscow.pm 6 ...
Ленивые итераторы для разбора разнородных данных. Михаил Озеров. Moscow.pm 6 ...
 
Communication Online
Communication OnlineCommunication Online
Communication Online
 

Similar a Ae internals

High-level Web Testing
High-level Web TestingHigh-level Web Testing
High-level Web Testing
petersergeant
 
20 modules i haven't yet talked about
20 modules i haven't yet talked about20 modules i haven't yet talked about
20 modules i haven't yet talked about
Tatsuhiko Miyagawa
 
C A S Sample Php
C A S Sample PhpC A S Sample Php
C A S Sample Php
JH Lee
 
Intro to #memtech PHP 2011-12-05
Intro to #memtech PHP   2011-12-05Intro to #memtech PHP   2011-12-05
Intro to #memtech PHP 2011-12-05
Jeremy Kendall
 
2014 database - course 2 - php
2014 database - course 2 - php2014 database - course 2 - php
2014 database - course 2 - php
Hung-yu Lin
 

Similar a Ae internals (20)

Exploiting Php With Php
Exploiting Php With PhpExploiting Php With Php
Exploiting Php With Php
 
High-level Web Testing
High-level Web TestingHigh-level Web Testing
High-level Web Testing
 
London XQuery Meetup: Querying the World (Web Scraping)
London XQuery Meetup: Querying the World (Web Scraping)London XQuery Meetup: Querying the World (Web Scraping)
London XQuery Meetup: Querying the World (Web Scraping)
 
Secure Coding With Wordpress (BarCamp Orlando 2009)
Secure Coding With Wordpress (BarCamp Orlando 2009)Secure Coding With Wordpress (BarCamp Orlando 2009)
Secure Coding With Wordpress (BarCamp Orlando 2009)
 
And the Greatest of These Is ... Rack Support
And the Greatest of These Is ... Rack SupportAnd the Greatest of These Is ... Rack Support
And the Greatest of These Is ... Rack Support
 
Modern Perl
Modern PerlModern Perl
Modern Perl
 
Modern Web Development with Perl
Modern Web Development with PerlModern Web Development with Perl
Modern Web Development with Perl
 
Introduction to CodeIgniter (RefreshAugusta, 20 May 2009)
Introduction to CodeIgniter (RefreshAugusta, 20 May 2009)Introduction to CodeIgniter (RefreshAugusta, 20 May 2009)
Introduction to CodeIgniter (RefreshAugusta, 20 May 2009)
 
20 modules i haven't yet talked about
20 modules i haven't yet talked about20 modules i haven't yet talked about
20 modules i haven't yet talked about
 
Web Scraping with PHP
Web Scraping with PHPWeb Scraping with PHP
Web Scraping with PHP
 
Php My Sql
Php My SqlPhp My Sql
Php My Sql
 
Rack Middleware
Rack MiddlewareRack Middleware
Rack Middleware
 
Introduction To Lamp
Introduction To LampIntroduction To Lamp
Introduction To Lamp
 
PHP 102: Out with the Bad, In with the Good
PHP 102: Out with the Bad, In with the GoodPHP 102: Out with the Bad, In with the Good
PHP 102: Out with the Bad, In with the Good
 
C A S Sample Php
C A S Sample PhpC A S Sample Php
C A S Sample Php
 
Os Nixon
Os NixonOs Nixon
Os Nixon
 
Intro to #memtech PHP 2011-12-05
Intro to #memtech PHP   2011-12-05Intro to #memtech PHP   2011-12-05
Intro to #memtech PHP 2011-12-05
 
Web Scraping with PHP
Web Scraping with PHPWeb Scraping with PHP
Web Scraping with PHP
 
2014 database - course 2 - php
2014 database - course 2 - php2014 database - course 2 - php
2014 database - course 2 - php
 
SQL Injection Part 2
SQL Injection Part 2SQL Injection Part 2
SQL Injection Part 2
 

Último

Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Victor Rentea
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
panagenda
 

Último (20)

AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistan
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 
Exploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusExploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with Milvus
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf
 
Vector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxVector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptx
 
Platformless Horizons for Digital Adaptability
Platformless Horizons for Digital AdaptabilityPlatformless Horizons for Digital Adaptability
Platformless Horizons for Digital Adaptability
 
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
 
WSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering DevelopersWSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering Developers
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
 

Ae internals

  • 1. AnyEvent Internals (samples of async programming) Mons Anderson <mons@cpan.org>
  • 2. AnyEvent::Internals AE::* use AE 5 ; my $w = AE::io $fh , 0 , sub { w arn '$fh is readable' ; }; my $w = AE::io $fh , 1 , sub { warn '$fh is writable' ; }; my $w = AE::timer 1 , 0 , sub { warn '1 second passed' ; }; my $w = AE::timer 0 , 1, sub { warn 'every 1 second' ; }; my $w = AE::signal TERM => sub { warn 'TERM received' ; }; my $w = AE::idle { warn 'Event loop is idle' ; };
  • 3. AnyEvent::Internals AE::cv use AE 5 ; my $cv = AE:: cv ; any sub { async sub { calls sub { $cv -> send ; }; }; }; $cv -> recv ; # Run loop until get send
  • 4. AnyEvent::Internals AE::cv use AE 5 ; my $cv = AE :: cv { warn &quot;All done&quot; }; for ( 1 . .10 ) { $cv -> begin ; async_call sub { may_be_nested sub { $cv -> end ; } } }
  • 5. AnyEvent::Internals AE::HTTP use AnyEvent:: HTTP ; my $cv = AE:: cv ; http_request GET => 'http://www.google.ru' , sub { my ( $body , $hdr ) = @_ ; warn &quot;$hdr->{Status}: $hdr->{Reason} &quot; ; warn &quot;Body: &quot; . length ( $body ). &quot; bytes &quot; ; $cv -> send ; }, ; $cv -> recv ; $ perl http_request.pl 200: OK Body: 10875 bytes
  • 6. AnyEvent::Internals AE::HTTP sub http_request ($$@) { my $cb = pop ; my ( $method , $url ) = (uc shift, shift); my ( %arg ) = ( timeout => 10 , recurse => 10 , @_ ); my %state ; my %hdr = (connection => 'close' ); my $err = sub { %state = (); $cb ->(undef, { Status => $_ [ 1 ], Reason => $_ [ 0 ] || 599 , URL => $_ [ 2 ] || $url } ); }; return $err ->( &quot;Too many redirections&quot; ) if $arg {recurse} < 0 ; while ( my ( $k , $v ) = each %{ $arg {headers}}) { $hdr {lc $k } = $v }; $hdr { &quot;user-agent&quot; } // = &quot;AnyEvent/$AnyEvent::VERSION&quot; ; $hdr { &quot;content-length&quot; } = length $arg {body} if length $arg {body} or $method ne &quot;GET&quot; ; # ... }
  • 7. AnyEvent::Internals AE::HTTP use AnyEvent :: Socket ; sub http_request ($$@) { # ... my ( $rscheme , $uauthority , $rpath , $query , $fragment ) = $url =~ m{ (?:([^:/?#]+):)?(?://([^/?#]*))? ([^?#]*)(?:([^#]*))?(?:#(.*))? }x; $rscheme = lc $rscheme ; my $rport = $rscheme eq &quot;http&quot; ? 80 : $rscheme eq &quot;https&quot; ? 443 : return $err ->( &quot;Only http/https are supported&quot; ); $uauthority =~ /^(?: .* )? ([^:]+) (?: : (+) )?$/ x or return $err ->( &quot;Unparsable URL&quot; ); my $rhost = $1 ; $rport = $2 if defined $2 ; $hdr {host} // = defined $2 ? &quot;$uhost:$2&quot; : &quot;$uhost&quot; ; $rhost =~ s/^(.*)$/$1/ ; $rpath .= &quot;?$query&quot; if length $query ; $rpath =~ s%^ /?%/ %; $state {connect_guard} = tcp_connect $rhost , $rport , sub { # ... }, sub { $arg {timeout} }; defined wantarray && AnyEvent::Util::guard { %state = () }; }
  • 8. AnyEvent::Internals AE::HTTP use AnyEvent :: Socket ; tcp_connect $host , $port , sub { # Connect sub my ( $fh , $addr , $port ) = @_ ; # ... }, sub { # Prepare sub my ( $socket ) = @_ ; return $timeout ; };
  • 9. AnyEvent::Internals AE::HTTP use AnyEvent :: Handle ; sub http_request ($$ @ ) { # ... $state { connect_guard } = tcp_connect $rhost , $rport , sub { $state { fh } = shift or return $err ->( &quot;$!&quot; ); return unless delete $state { connect_guard }; $state { handle } = new AnyEvent :: Handle fh => $state { fh }, timeout => $arg { timeout }, on_error => sub { $err ->( $_ [ 2 ]) }, on_eof => sub { $err ->( &quot;Unexpected end-of-file&quot; ) } ; $state { handle }-> starttls ( &quot;connect&quot; ) if $rscheme eq &quot;https&quot; ; $state { handle }-> push_write ( &quot;$method $rpath HTTP/1.0 1512 &quot; . join ( &quot;&quot; , map { defined $hdr { $_ } ? &quot;$_: &quot; . delete ( $hdr { $_ }). &quot; 1512 &quot; : delete $hdr { $_ }||() } keys %hdr ). &quot; 1512 &quot; . delete ( $arg { body }) ); $state { handle }-> push_read ( line => qr { 15 ? 12 }, sub { # ... }); }, sub { $arg { timeout } }; # ... }
  • 10. AnyEvent::Internals AE::HTTP use AnyEvent :: Handle ; $h -> push_write ( $data ); $h -> push_read ( chunk => $bytes , sub { my ( $h , $data ) = @_ ; # ... }); $h -> push_read ( line => qr /EOL/ , sub { ... } ); $h -> unshift_read ( chunk => $bytes , sub { ... } ); $h -> unshift_read ( line => qr /EOL/ , sub { ... } ); $h -> on_read ( sub { ... } ); $h ->{ rbuf }
  • 11. AnyEvent::Internals AE::HTTP sub http_request ($$ @ ) { # ... $state { handle }-> push_read ( line => qr { 15 ? 12 }, sub { $_ [ 1 ] =~ /^HTTP ([ 0 - 9 .]+) + ([ 0 - 9 ]{ 3 }) ( ? : + ([^ 1512 ]*) ) ? / ix or return $err ->( &quot;Invalid server response ($_[1])&quot; ); my %hdr = ( Status => &quot;,$2&quot; , Reason => &quot;,$3&quot; , URL => &quot;,$url&quot; ); $_[0] -> unshift_read ( line => qr {( ? <![^ 12 ]) 15 ? 12 }, sub { # ... } ); } ); # ... }
  • 12. AnyEvent::Internals AE::HTTP sub http_request ($$ @ ) { # ... $_[0] -> unshift_read ( line => qr {( ? <![^ 12 ]) 15 ? 12 }, sub { for ( &quot;$_[1]&quot; ) { y /15/ / d ; $hdr { lc $1 } .= &quot;,$2&quot; while / G ([^: 00 - 37 ]*): [ 1140 ]* (( ? : [^ 12 ]+ | 12 [ 1140 ] )*) 12 / gxc ; /$/ or return $err ->( &quot;Garbled response headers&quot; ); } substr $_ , 0 , 1 , '' for values %hdr ; if ( $hdr { location } !~ /^(?: $ | [^: ?#]+ : )/x) { $hdr { location } =~ s/^+/ /; my $url = &quot;$rscheme://$rhost:$rport&quot; ; unless ( $hdr { location } =~ s {^/}{}) { $url .= $rpath ; $url =~ s { /[^/ ]*$}{}; } $hdr { location } = &quot;$url/$hdr{location}&quot; ; } # ... }); # ... }
  • 13. AnyEvent::Internals AE::HTTP sub http_request ($$ @ ) { # ... my $redirect ; if ( $arg { recurse }) { if ( ( $hdr { Status } =~ /^30[12]$/ and $method ne &quot;POST&quot; ) or ( $hdr { Status } == 307 and $method =~ /^(?:GET|HEAD)$/ ) ) { $redirect = 1 ; } elsif ( $hdr { Status } == 303 ) { $method = &quot;GET&quot; unless $method eq &quot;HEAD&quot; ; $redirect = 1 ; } } my $finish = sub { $state { handle }-> destroy if $state { handle }; %state = (); if ( $redirect && exists $hdr { location }) { http_request $method => $hdr { location }, %arg , recurse => $arg { recurse } - 1 , $cb ; } else { $cb ->( $_ [ 0 ], $_ [ 1 ]); } }; # ... }
  • 14. AnyEvent::Internals AE::HTTP sub http_request ($$ @ ) { # ... my $len = $hdr { &quot;content-length&quot; }; if ( $hdr { Status } =~ /^(?:1..|[23]04)$/ or $method eq &quot;HEAD&quot; or ( defined $len && ! $len ) ) { # no body $finish ->( &quot;&quot; , %hdr ); } else { # ... } # ... }
  • 15. AnyEvent::Internals AE::HTTP sub http_request ($$ @ ) { # ... $_ [ 0 ]-> on_eof ( undef ); if ( $len ) { # have content length $_ [ 0 ]-> on_error ( sub { $finish ->( undef , { Status => 599 , Reason => $_ [ 2 ], URL => $url }); }); $_ [ 0 ]-> on_read ( sub { $finish ->( substr ( delete $_ [ 0 ]{ rbuf }, 0 , $len , &quot;&quot; ), %hdr ) if $len <= length $_ [ 0 ]{ rbuf }; }); } else { # have no content-length, read until end $_ [ 0 ]-> on_error ( sub { $!{ EPIPE } || !$! ? $finish ->( delete $_ [ 0 ]{ rbuf }, %hdr ) : $finish ->( undef ,{ Status => 599 , Reason => $_ [ 2 ], URL => $url }); }); $_ [ 0 ]-> on_read ( sub {}); } # ... }
  • 16. AnyEvent::Internals AE::HTTP use AnyEvent :: Socket ; use AnyEvent :: Handle ; sub http_request ($$ @ ) { my $cb = pop ; my ( $method , $url ) = ( uc shift , shift ); my ( %arg ) = ( timeout => 10 , recurse => 10 , @_ ); my %state ; my %hdr = ( connection => 'close' ); my $err = sub { %state = (); $cb ->( undef , Status => $_ [ 1 ], Reason => $_ [ 0 ]|| 599 , URL => $_ [ 2 ]|| $url ) }; return $err ->( &quot;Too many redirections&quot; ) if $arg { recurse } < 0 ; while ( my ( $k , $v ) = each %{ $arg { headers }}) { $hdr { lc $k } = $v }; my ( $rscheme , $uauthority , $rpath , $query , $fragment ) = $url =~ m |( ? :([^: /?#]+):)?(?://([^/? #]*))?([^?#]*)(?:([^#]*))?(?:#(.*))?|; $rscheme = lc $rscheme ; my $rport = $rscheme eq &quot;http&quot; ? 80 : $rscheme eq &quot;https&quot; ? 443 : return $err ->( &quot;Only http and https URL schemes supported&quot; ); $uauthority =~ /^(?: .* )? ([^:]+) (?: : (+) )?$/ x or return $err ->( &quot;Unparsable URL&quot; ); my $rhost = $1 ; $rport = $2 if defined $2 ; $hdr { host } // = defined $2 ? &quot;$rhost:$2&quot; : &quot;$rhost&quot; ; $rhost =~ s/^(.*)$/$1/ ; $rpath .= &quot;?$query&quot; if length $query ; $rpath =~ s %^ /?%/ %; $hdr { &quot;user-agent&quot; } // = &quot;AnyEvent/$AnyEvent::VERSION&quot; ; $hdr { &quot;content-length&quot; } = length $arg { body } if length $arg { body } or $method ne &quot;GET&quot; ; $state { connect_guard } = tcp_connect $rhost , $rport , sub { $state { fh } = shift or return %state =(), $err ->( &quot;$!&quot; ); return unless delete $state { connect_guard }; $state { handle } = new AnyEvent :: Handle fh => $state { fh }, timeout => $arg { timeout }, on_error => sub { $err ->( $_ [ 2 ]) }, on_eof => sub { $err ->( &quot;Unexpected end-of-file&quot; ) }, ; $state { handle }-> starttls ( &quot;connect&quot; ) if $rscheme eq &quot;https&quot; ; $state { handle }-> push_write ( &quot;$method $rpath HTTP/1.0 1512 &quot; . join ( &quot;&quot; , map { defined $hdr { $_ } ? &quot;$_: &quot; . delete ( $hdr { $_ }). &quot; 1512 &quot; : delete $hdr { $_ }||() } keys %hdr ). &quot; 1512 &quot; . delete ( $arg { body }) ); $state { handle }-> push_read ( line => qr { 15 ? 12 }, sub { $_ [ 1 ] =~ /^HTTP ([ 0 - 9 .]+) + ([ 0 - 9 ]{ 3 }) ( ? : + ([^ 1512 ]*) ) ? / ix or return $err ->( &quot;Invalid server response ($_[1])&quot; ); my %hdr = ( Status => &quot;,$2&quot; , Reason => &quot;,$3&quot; , URL => &quot;,$url&quot; ); $state { handle }-> unshift_read ( line => qr {( ? <![^ 12 ]) 15 ? 12 }, sub { for ( &quot;$_[1]&quot; ) { y/15/ / d ; $hdr { lc $1 } .= &quot;,$2&quot; while / G ([^: 00 - 37 ]*): [ 1140 ]* (( ? : [^ 12 ]+ | 12 [ 1140 ] )*) 12 / gxc ; /$/ or return $err ->( &quot;Garbled response headers&quot; ); } substr $_ , 0 , 1 , '' for values %hdr ; if ( $hdr { location } !~ /^(?: $ | [^:?#]+ : )/x) { $hdr { location } =~ s/^+/ /; my $url = &quot;$rscheme://$rhost:$rport&quot; ; unless ( $hdr { location } =~ s {^/}{}) { $url .= $rpath ; $url =~ s { /[^/ ]*$}{}; } $hdr { location } = &quot;$url/$hdr{location}&quot; ; } my $redirect ; if ( $arg { recurse }) { if ( ( $hdr { Status } =~ /^30[12]$/ and $method ne &quot;POST&quot; ) or ( $hdr { Status } == 307 and $method =~ /^(?:GET|HEAD)$/ ) ) { $redirect = 1 ; } elsif ( $hdr { Status } == 303 ) { $method = &quot;GET&quot; unless $method eq &quot;HEAD&quot; ; $redirect = 1 ; } } my $finish = sub { $state { handle }-> destroy if $state { handle }; %state = (); if ( $redirect && exists $hdr { location }) { http_request $method => $hdr { location }, %arg , recurse => $arg { recurse } - 1 , $cb ; } else { $cb ->( $_ [ 0 ], $_ [ 1 ]); } }; my $len = $hdr { &quot;content-length&quot; }; if ( $hdr { Status } =~ /^(?:1..|[23]04)$/ or $method eq &quot;HEAD&quot; or ( defined $len && ! $len ) ) { # no body $finish ->( &quot;&quot; , %hdr ); } else { $_ [ 0 ]-> on_eof ( undef ); if ( $len ) { # have content length $_ [ 0 ]-> on_error ( sub { $finish ->( undef , { Status => 599 , Reason => $_ [ 2 ], URL => $url }) }); $_ [ 0 ]-> on_read ( sub { $finish ->( substr ( delete $_ [ 0 ]{ rbuf }, 0 , $len , &quot;&quot; ), %hdr ) if $len <= length $_ [ 0 ]{ rbuf }; }); } else { # have no content-length, read until end $_ [ 0 ]-> on_error ( sub { $!{ EPIPE } || !$! ? $finish ->( delete $_ [ 0 ]{ rbuf }, %hdr ) : $finish ->( undef ,{ Status => 599 , Reason => $_ [ 2 ], URL => $url }); }); $_ [ 0 ]-> on_read ( sub {}); } } }); }); }, sub { $arg { timeout } }; defined wantarray && AnyEvent :: Util :: guard { %state = () } }
  • 17. AnyEvent::Internals AE::HTTPServer my $server = AnyEvent :: HTTP :: Server -> new ( port => 80 , request => sub { my $r = shift ; if ( $r -> wants_websocket ) { $r -> upgrade ( 'websocket' , sub { if ( my $ws = shift ) { $ws -> onmessage ( sub { $ws -> send ( &quot;@_&quot; ); }); $ws -> send ( &quot;Hello!&quot; ); } else { warn &quot;Upgrade failed: @_&quot; ; } }); } else { # ... } }, );
  • 18. AnyEvent::Internals AE::HTTPServer tcp_server $self ->{ host }, $self ->{ port }, sub { my $fh = shift or return warn &quot;couldn't accept client: $!&quot; ; my ( $host , $port ) = @_ ; my $con = $self ->{ connection_class }-> new ( server => $self , fh => $fh , host => $host , port => $port , on_error => sub { my $con = shift ; warn &quot;@_&quot; ; delete $self ->{ con }{ $con ->{ id }}; }, ); $self ->{ con }{ $con ->{ id }} = $con ; }, sub { 1024 ; };
  • 19. AnyEvent::Internals AE::HTTPServer sub Connection :: new { my $self = bless {}, shift ; weaken ( my $this = $self ); my %args = @_ ; my $srv = $args { server }; my $fh = $args { fh }; my $h = AnyEvent :: Handle :: Writer -> new ( fh => $args { fh }, on_eof => sub { $this or return ; $this -> error ( &quot;EOF&quot; ) }, on_error => sub { $this or return ; $this -> error ( &quot;$!&quot; ) }, ); weaken ( $self ->{ srv } = $args { server }); $self ->{ id } = int $self ; $self ->{ fh } = $args { fh }; $self ->{ h } = $h ; $self ->{ host } = $args { host }; $self ->{ port } = $args { port }; $self ->{ r } = []; # Request queue $self ->{ ka_timeout } = $srv ->{ keep_alive_timeout } || 30 ; if ( $srv ->{ keep_alive }) { $self ->{ touch } = AE :: now ; $self -> ka_timer ; } $self -> read_header (); return $self ; }
  • 20. AnyEvent::Internals AE::HTTPServer sub Connection :: ka_timer { my $self = shift ; $self ->{ srv } or return $self -> destroy ; weaken ( my $this = $self ); $self ->{ ka } = AE :: timer $this ->{ ka_timeout } + 1 , 0 , sub { $this or return ; if ( AE :: now - $this ->{ touch } >= $this ->{ ka_timeout }) { $this -> close ; } else { $this -> ka_timer ; } } ; }
  • 21. AnyEvent::Internals AE::HTTPServer sub Connection :: read_header { my $self = shift ; $self ->{ srv } or return $self -> destroy ; weaken ( my $con = $self ); $con ->{ h }-> push_read ( chunk => 3 => sub { $con or return ; shift ; my $pre = shift ; if ( $pre =~ m {^<}) { $con ->{ h }-> unshift_read ( regex => qr {.+ ? >} => sub { my $xml = $pre . shift (); # Hanlde XML here $con -> destroy (); }); } else { $con ->{ h }-> unshift_read ( line => sub { $con or return ; shift ; my $line = $pre . shift ; if ( $line =~ /(+) 40 (+) 40 HTTP ( + . +)/ xso ) { my ( $meth , $url , $hv ) = ( $1 , $2 , $3 ); $con ->{ method } = $meth ; $con ->{ uri } = $url ; $con ->{ version } = $hv ; $con -> read_headers (); } elsif ( $line eq '' ) { $con -> read_header (); } else { $con -> fatal_error ( 400 ); } }); }; }); }
  • 22. AnyEvent::Internals AE::HTTPServer sub Connection :: read_headers { my ( $self ) = @_ ; $self ->{ srv } or return $self -> destroy ; weaken ( my $con = $self ); $self ->{ h }-> unshift_read ( line => qr {( ? <![^ 12 ]) 15 ? 12 } o , sub { $con or return ; my ( $h , $data ) = @_ ; my $hdr = HTTP :: Easy :: Headers -> decode ( $data ) // return $con -> fatal_error ( 400 ); my $r = $con ->{ srv }{ request_class }-> new ( method => delete $con ->{ method }, uri => delete $con ->{ uri }, host => $hdr ->{ Host }, headers => $hdr , ); push @ { $con ->{ r } }, $r ; weaken ( $r ->{ con } = $con ); weaken ( $con ->{ r }[- 1 ]); # ... } ); }
  • 23. AnyEvent::Internals AE::HTTPServer sub { $con or return ; # ... $hdr ->{ connection } = lc $hdr ->{ connection }; if ( $hdr ->{ connection } eq 'close' or $con ->{ version } < 1.1 ) { delete $con ->{ ka }; $con ->{ type } = 'close' ; $con ->{ close } = 1 ; } elsif ( $hdr ->{ connection } =~ /keep-alive/ ) { $con ->{ close } = 0 ; $con ->{ type } = 'keep-alive' ; } elsif ( $hdr ->{ connection } eq 'upgrade' ) { delete $con ->{ ka }; $con ->{ type } = 'upgrade' ; $con ->{ close } = 0 ; } if ( defined $hdr ->{ 'content-length' }) { $con ->{ h }-> unshift_read ( chunk => $hdr ->{ 'content-length' }, sub { my ( $hdl , $data ) = @_ ; $con -> handle_request ( $r , $data ); $con -> read_header () if $con ->{ ka }; }); } else { $con -> handle_request ( $r ); $con -> read_header () if $con ->{ ka }; } }
  • 24. AnyEvent::Internals AE::HTTPServer sub Request :: response { my $self = shift ; $self ->{ con } or return $self -> dispose ; $self ->{ con }-> response ( $self , @_ ); $self -> dispose ; } sub Request :: dispose { my $self = shift ; return % $self = (); } sub Request :: DESTROY { my $self = shift ; $self ->{ con } or return % $self = (); $self ->{ con }-> response ( $self , 404 , '' , msg => &quot;Request not handled&quot; ); } sub Request :: wants_websocket { my $self = shift ; return lc $self ->{ headers }{ connection } eq 'upgrade' && lc $self ->{ headers }{ upgrade } eq 'websocket' ? 1 : 0 ; }
  • 25. AnyEvent::Internals AE::HTTPServer sub Request :: upgrade { my $self = shift ; my $cb = pop ; my $type = shift ; my $headers = shift || HTTP:: Easy:: Headers-> new ({}); if ( lc $type eq 'websocket' ) { $headers ->{ upgrade} = 'WebSocket' ; $headers ->{ connection} = 'Upgrade' ; $headers ->{ 'websocket-origin' } ||= $self ->{headers}{ origin}; $headers ->{ 'websocket-location' } ||= do { my $loc = URI-> new_abs ( $self ->{ uri}, &quot;http://$self->{headers}{host}&quot; ); $loc = &quot;$loc&quot; ; $loc =~ s{^ http}{ ws}; $loc ; }; $self ->{ con}-> response ( $self , 101 , '' , headers => $headers , msg => &quot;Web Socket Protocol Handshake&quot; ); my $ws = $self ->{con}{ srv}{ websocket_class}-> new ( con => $self ->{con}, ); $self -> dispose ; return $cb ->( $ws ); } else { return $cb ->(undef, &quot;Unsupported upgrade type: $type&quot; ); } }
  • 26. AnyEvent::Internals AE::HTTPServer sub Connection :: response { my ( $con , $r , $code , $content , %args ) = @_ ; my $msg = $args { msg } || $HTTP :: Easy :: Status :: MSG { $code } ; my $hdr = $args { headers } || HTTP :: Easy :: Headers -> new ({}); # Resolve pipeline if ( @ { $con ->{ r }} and $con ->{ r }[ 0 ] == $r ) { shift @ { $con ->{ r } }; } else { $r ->{ ready } = [ $code , $msg , $hdr , $content ]; return ; } my $res = &quot;HTTP/$con->{version} $code $msg 1512 &quot; ; $hdr ->{ 'content-type' } ||= 'text/html' ; if ( ref $content eq 'HASH' ) { if ( $content ->{ sendfile }) { $content ->{ size } = $hdr ->{ 'content-length' } = - s $content ->{ sendfile }; } } $hdr ->{ connection } ||= $con ->{ type }; if ( $code >= 400 and ! length $content ) { $content = &quot;<h1>$code $msg</h1>&quot; ; } # ...
  • 27. AnyEvent::Internals AE::HTTPServer # ... $hdr ->{ 'content-length' } = length $content if not ( defined $hdr ->{ 'content-length' }) and not ref $content and $code !~ /^(?:1|[23]04)$/ ; $res .= $hdr -> encode (); $con ->{ h }-> push_write ( $res ); if ( ref $content eq 'HASH' ) { if ( $content ->{ sendfile }) { $con ->{ h }-> push_sendfile ( $content ->{ sendfile }, $content ->{ size }); } else { die &quot;Bad response content&quot; ; } } else { $con ->{ h }-> push_write ( $content ) if length $content ; } if ( $con ->{ close }) { $con -> close (); } elsif ( @ { $con ->{ r }} and $con ->{ r }[ 0 ]{ ready }) { $con -> response ( $con ->{ r }[ 0 ], @ { $con ->{ r }[ 0 ]{ ready }}); } }
  • 28. AnyEvent::Internals AE::Memcached my $cv = AE :: cv ; $cv -> begin ; $cv -> begin ( sub { $cv -> send }); my $memd = AnyEvent :: Memcached -> new ( servers => [ '127.0.0.1:11211' ], cv => $cv , namespace => &quot;test:&quot; , ); $memd -> set ( &quot;key1&quot; , &quot;val1&quot; , cb => sub { shift or return warn &quot;Set key1 failed: @_&quot; ; $memd -> get ( &quot;key1&quot; , cb => sub { my ( $v , $e ) = @_ ; $e and return warn &quot;Get failed: $e&quot; ; warn &quot;Got value for key1: $v&quot; ; }); }); $cv -> end ; $cv -> recv ;
  • 29. AnyEvent::Internals AE::Memcached sub set { shift -> _set ( set => @_ ) } sub _set { my $self , $cmd , $key ) = splice @_ , 0 , 3 ; my $cas ; if ( $cmd eq 'cas' ) { $cas = shift ; } my $val = shift ; # Some preparations... $self -> _do ( $key , &quot;$cmd $self->{namespace}%s $flags $expire $len&quot; . ( defined $cas ? ' ' . $cas : '' ). &quot; 1512 $val&quot; , sub { local $_ = shift ; if ( $_ eq 'STORED' ) { return 1 } elsif ( $_ eq 'NOT_STORED' ) { return 0 } elsif ( $_ eq 'EXISTS' ) { return 0 } else { return undef , $_ } }, cb => $args { cb }, ); }
  • 30. AnyEvent::Internals AE::Memcached sub _do { my ( $self , $key , $com , $wrk , %args ) = @_ ; my $servers = $self ->{ hash }-> servers ( $key ); my %res ; my %err ; my $res ; $_ and $_ -> begin for $self ->{ cv }, $args { cv }; my $cv = AE :: cv { if ( $res != - 1 ) { $args { cb }( $res ); } else { $args { cb }( undef , dumper ( %err ) ); } $_ and $_ -> end for $args { cv }, $self ->{ cv }; }; for my $srv ( keys % $servers ) { for my $real ( @ { $servers ->{ $srv } }) { $cv -> begin ; my $cmd = $com ; substr ( $cmd , index ( $cmd , '%s' ), 2 ) = $real ; $self ->{ peers }{ $srv }{ con }-> command ( '...' ); } } return ; }
  • 31. AnyEvent::Internals AE::Memcached # ... $self ->{ peers }{ $srv }{ con }-> command ( $cmd , cb => sub { if ( defined ( local $_ = shift )) { my ( $ok , $fail ) = $wrk ->( $_ ); if ( defined $ok ) { $res { $real }{ $srv } = $ok ; $res = (! defined $res ) || $res == $ok ? $ok : - 1 ; } else { $err { $real }{ $srv } = $fail ; $res = - 1 ; } } else { $err { $real }{ $srv } = $_ ; $res = - 1 ; } $cv -> end ; } ); # ...
  • 32. AnyEvent::Internals AE::Memcached sub Peer :: command { my $self = shift ; if ( $self ->{ connected }) { return $self ->{ con }-> command ( @_ ); } else { my ( $cmd , %args ) = @_ ; $self -> conntrack ( command => @_ , $args { cb } ); } }
  • 33. AnyEvent::Internals AE::Memcached sub Peer :: conntrack { my $self = shift ; my ( $method , $args , $cb ) = @_ ; if ( $self ->{ connecting } and $self ->{ failed }) { $cb and $cb ->( undef , &quot;Not connected&quot; ); return ; } elsif (! $self ->{ connected }) { # connect } else { return $self ->{ con }-> $method ( @ $args ); } }
  • 34. AnyEvent::Internals AE::Memcached sub Peer :: connect { my $self = shift ; $self ->{ connecting } and return ; $self -> reg_cb ( connected => sub { $self ->{ failed } = 0 ; } ); $self -> reg_cb ( connfail => sub { $self ->{ failed } = 1 ; } ); $self -> reg_cb ( disconnect => sub { shift ; shift ; % $self or return ; my $e = @_ ? &quot;@_&quot; : &quot;disconnected&quot; ; for ( keys %{ $self ->{ waitingcb }} ) { if ( $self ->{ waitingcb }{ $_ }) { $self ->{ waitingcb }{ $_ }( undef , $e ); } delete $self ->{ waitingcb }{ $_ }; } } ); $self -> next :: method ( @_ ); return ; }
  • 35. AnyEvent::Internals AE::Memcached elsif (! $self ->{ connected }) { my @args = @ $args ; # copy to avoid rewriting my ( $c , $t ); weaken ( $self ); weaken ( $self ->{waitingcb}{int $cb } = $cb ) if $cb ; $c = $self -> reg_cb ( connected => sub { shift -> unreg_me ; undef $c ; undef $t ; $self or return ; delete $self ->{waitingcb}{int $cb } if $cb ; return $self ->{con}-> $method ( @args ); }); $t = AE:: timer $self ->{timeout}, 0, sub { undef $c ;undef $t ; $self or return ; if ( $cb ){ delete $self ->{waitingcb}{int $cb }; $cb ->(undef, &quot;Connect timeout&quot; ); } }, ); $self -> connect (); }
  • 36.
  • 39. Marc Lehmann (MLEHMANN)
  • 40. Robin Redeker (ELMEX)
  • 41. Mons Anderson (MONS)
  • 43. AnyEvent::Internals Author Mons Anderson ( aka Владимир Перепелица ) Rambler Internet Holding < [email_address] > < [email_address] > DevConf::Perl() © 2010 $cv -> send ;