use
Errno
qw( EINPROGRESS EWOULDBLOCK EISCONN )
;
sub
new {
my
(
$class
,
$dest
,
$nslen
,
$on_item
) =
@_
;
return
bless
[
$dest
,
$nslen
,
$on_item
,
''
, 0, 0],
$class
;
}
sub
current_key {
return
$_
[0][KEY];
}
sub
parse_from_sock {
my
(
$self
,
$sock
) =
@_
;
my
$res
;
if
(
$self
->[STATE]) {
my
$ret
=
$self
->[DEST];
$res
=
sysread
(
$sock
,
$ret
->{
$self
->[KEY]},
$self
->[STATE] -
$self
->[OFFSET],
$self
->[OFFSET]);
return
0
if
!
defined
(
$res
) and $!==EWOULDBLOCK;
if
(
$res
== 0) {
$self
->[ON_ITEM] =
undef
;
return
-1;
}
$self
->[OFFSET] +=
$res
;
if
(
$self
->[OFFSET] ==
$self
->[STATE]) {
$self
->[ON_ITEM]->(
$self
->[KEY],
$self
->[FLAGS]);
$self
->[OFFSET] = 0;
$self
->[STATE] = 0;
}
return
0;
}
$res
=
sysread
(
$sock
,
$self
->[BUF],
128*1024,
$self
->[OFFSET]);
return
0
if
!
defined
(
$res
) and $!==EWOULDBLOCK;
if
(!
defined
(
$res
) ||
$res
== 0) {
$self
->[ON_ITEM] =
undef
;
return
-1;
}
$self
->[OFFSET] +=
$res
;
return
$self
->parse_buffer;
}
sub
parse_buffer {
my
(
$self
) =
@_
;
my
$ret
=
$self
->[DEST];
SEARCH:
while
(1) {
if
(
$self
->[BUF] =~ /^END\r\n/) {
$self
->[ON_ITEM] =
undef
;
return
1;
}
if
(
$self
->[BUF] =~ /^VALUE (\S+) (\d+) (\d+)\r\n/) {
(
$self
->[KEY],
$self
->[FLAGS],
$self
->[STATE]) =
(
substr
($1,
$self
->[NSLEN]),
int
($2), $3+2);
my
$p
= $+[0];
my
$len
=
length
(
$self
->[BUF]);
my
$copy
=
$len
-
$p
>
$self
->[STATE] ?
$self
->[STATE] :
$len
-
$p
;
$ret
->{
$self
->[KEY]} =
substr
(
$self
->[BUF],
$p
,
$copy
)
if
$copy
;
$self
->[OFFSET] =
$copy
;
substr
(
$self
->[BUF], 0,
$p
+
$copy
,
''
);
if
(
$self
->[OFFSET] ==
$self
->[STATE]) {
$self
->[ON_ITEM]->(
$self
->[KEY],
$self
->[FLAGS]);
$self
->[OFFSET] = 0;
$self
->[STATE] = 0;
next
SEARCH;
}
last
SEARCH;
}
$self
->[OFFSET] =
length
(
$self
->[BUF]);
last
SEARCH;
}
return
0;
}
1;