--- AnyEvent-FCP/FCP.pm 2015/09/05 13:26:47 1.16 +++ AnyEvent-FCP/FCP.pm 2015/09/05 19:36:12 1.17 @@ -118,6 +118,71 @@ { Scalar::Util::weaken (my $self = $self); + our $ENDMESSAGE = qr<\012(EndMessage|Data)\012>; + + # these are declared here for performance reasons + my ($k, $v, $type); + my $rdata; + + my $on_read = sub { + my ($hdl) = @_; + + # we only carve out whole messages here + while ($hdl->{rbuf} =~ /\012(EndMessage|Data)\012/) { + # remember end marker + $rdata = $1 eq "Data" + or $1 eq "EndMessage" + or die "protocol error, expected message end, got $1\n"; + + my @lines = split /\012/, substr $hdl->{rbuf}, 0, $-[0]; + + substr $hdl->{rbuf}, 0, $+[0], ""; # remove pkg + + $type = shift @lines; + $type = ($TOLC{$type} ||= tolc $type); + + my %kv; + + for (@lines) { + ($k, $v) = split /=/, $_, 2; + $k = ($TOLC{$k} ||= tolc $k); + + if ($k =~ /\./) { + # generic, slow case + my @k = split /\./, $k; + my $ro = \\%kv; + + while (@k) { + $k = shift @k; + if ($k =~ /^\d+$/) { + $ro = \$$ro->[$k]; + } else { + $ro = \$$ro->{$k}; + } + } + + $$ro = $v; + + next; + } + + # special comon case, for performance only + $kv{$k} = $v; + } + + if ($rdata) { + $_[0]->push_read (chunk => delete $kv{data_length}, sub { + $rdata = \$_[1]; + $self->recv ($type, \%kv, $rdata); + }); + + last; # do not tgry to parse more messages + } else { + $self->recv ($type, \%kv); + } + } + }; + $self->{hdl} = new AnyEvent::Handle connect => [$self->{host} => $self->{port}], timeout => $self->{timeout}, @@ -125,8 +190,9 @@ warn "@_\n";#d# exit 1; }, - on_read => sub { $self->on_read (@_) }, - on_eof => $self->{on_eof} || sub { }; + on_read => $on_read, + on_eof => $self->{on_eof} || sub { }, + ; Scalar::Util::weaken ($self->{hdl}{fcp} = $self); } @@ -255,57 +321,6 @@ } } -sub on_read { - my ($self) = @_; - - my ($k, $v, $type); - my %kv; - my $rdata; - - my $hdr_cb; $hdr_cb = sub { - if (($v = index $_[1], "=") >= 0) { - $k = substr $_[1], 0, $v; - $v = substr $_[1], $v + 1; - $k = ($TOLC{$k} ||= tolc $k); - - if ($k !~ /\./) { - # special case common case, for performance only - $kv{$k} = $v; - } else { - my @k = split /\./, $k; - my $ro = \\%kv; - - while (@k) { - $k = shift @k; - if ($k =~ /^\d+$/) { - $ro = \$$ro->[$k]; - } else { - $ro = \$$ro->{$k}; - } - } - - $$ro = $v; - } - - $_[0]->push_read (line => $hdr_cb); - } elsif ($_[1] eq "Data") { - $_[0]->push_read (chunk => delete $kv{data_length}, sub { - $rdata = \$_[1]; - $self->recv ($type, \%kv, $rdata); - }); - } elsif ($_[1] eq "EndMessage") { - $self->recv ($type, \%kv); - } else { - die "protocol error, expected message end, got $_[1]\n";#d# - } - }; - - $self->{hdl}->push_read (line => sub { - $type = ($TOLC{$_[1]} ||= tolc $_[1]); - $_[0]->push_read (line => $hdr_cb); - }); -} - sub default_recv { my ($self, $type, $kv, $rdata) = @_;