ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-FCP/FCP.pm
(Generate patch)

Comparing AnyEvent-FCP/FCP.pm (file contents):
Revision 1.8 by root, Fri Jun 18 16:59:13 2010 UTC vs.
Revision 1.9 by root, Tue Aug 4 00:35:16 2015 UTC

66 66
67use Scalar::Util (); 67use Scalar::Util ();
68 68
69use AnyEvent; 69use AnyEvent;
70use AnyEvent::Handle; 70use AnyEvent::Handle;
71use AnyEvent::Util ();
71 72
72sub touc($) { 73sub touc($) {
73 local $_ = shift; 74 local $_ = shift;
74 1 while s/((?:^|_)(?:svk|chk|uri|fcp|ds|mime)(?:_|$))/\U$1/; 75 1 while s/((?:^|_)(?:svk|chk|uri|fcp|ds|mime|dda)(?:_|$))/\U$1/;
75 s/(?:^|_)(.)/\U$1/g; 76 s/(?:^|_)(.)/\U$1/g;
76 $_ 77 $_
77} 78}
78 79
79sub tolc($) { 80sub tolc($) {
80 local $_ = shift; 81 local $_ = shift;
81 1 while s/(SVK|CHK|URI|FCP|DS|MIME)([^_])/$1\_$2/i; 82 1 while s/(SVK|CHK|URI|FCP|DS|MIME|DDA)([^_])/$1\_$2/i;
82 1 while s/([^_])(SVK|CHK|URI|FCP|DS|MIME)/$1\_$2/i; 83 1 while s/([^_])(SVK|CHK|URI|FCP|DS|MIME|DDA)/$1\_$2/i;
83 s/(?<=[a-z])(?=[A-Z])/_/g; 84 s/(?<=[a-z])(?=[A-Z])/_/g;
84 lc 85 lc
85} 86}
86 87
87=item $fcp = new AnyEvent::FCP [host => $host][, port => $port][, progress => \&cb][, name => $name] 88=item $fcp = new AnyEvent::FCP [host => $host][, port => $port][, progress => \&cb][, name => $name]
149 my ($self, $type, %kv) = @_; 150 my ($self, $type, %kv) = @_;
150 151
151 my $data = delete $kv{data}; 152 my $data = delete $kv{data};
152 153
153 if (exists $kv{id_cb}) { 154 if (exists $kv{id_cb}) {
154 my $id = $kv{identifier} || ++$self->{id}; 155 my $id = $kv{identifier} ||= ++$self->{id};
155 $self->{id}{$id} = delete $kv{id_cb}; 156 $self->{id}{$id} = delete $kv{id_cb};
156 $kv{identifier} = $id;
157 } 157 }
158 158
159 my $msg = (touc $type) . "\012" 159 my $msg = (touc $type) . "\012"
160 . join "", map +(touc $_) . "=$kv{$_}\012", keys %kv; 160 . join "", map +(touc $_) . "=$kv{$_}\012", keys %kv;
161 161
173 } 173 }
174 174
175 $self->{hdl}->push_write ($msg); 175 $self->{hdl}->push_write ($msg);
176} 176}
177 177
178sub on {
179 my ($self, $cb) = @_;
180
181 # cb return undef - message eaten, remove cb
182 # cb return 0 - message eaten
183 # cb return 1 - pass to next
184
185 push @{ $self->{on} }, $cb;
186}
187
188sub _push_queue {
189 my ($self, $queue) = @_;
190
191 warn "oush @$queue\n";#d#
192 shift @$queue;
193 $queue->[0]($self, AnyEvent::Util::guard { $self->_push_queue ($queue) })
194 if @$queue;
195}
196
197# lock so only one $type (arbitrary string) is in flight,
198# to work around horribly misdesigned protocol.
199sub serialise {
200 my ($self, $type, $cb) = @_;
201
202 my $queue = $self->{serialise}{$type} ||= [];
203 push @$queue, $cb;
204 $cb->($self, AnyEvent::Util::guard { $self->_push_queue ($queue) })
205 unless $#$queue;
206}
207
178sub on_read { 208sub on_read {
179 my ($self) = @_; 209 my ($self) = @_;
180 210
181 my $type; 211 my $type;
182 my %kv; 212 my %kv;
183 my $rdata; 213 my $rdata;
184 214
185 my $done_cb = sub { 215 my $done_cb = sub {
186 $kv{pkt_type} = $type; 216 $kv{pkt_type} = $type;
217
218 my $on = $self->{on};
219 for (0 .. $#$on) {
220 unless (my $res = $on->[$_]($type, \%kv, $rdata)) {
221 splice @$on, $_, 1 unless defined $res;
222 return;
223 }
224 }
187 225
188 if (my $cb = $self->{queue}[0]) { 226 if (my $cb = $self->{queue}[0]) {
189 $cb->($self, $type, \%kv, $rdata) 227 $cb->($self, $type, \%kv, $rdata)
190 and shift @{ $self->{queue} }; 228 and shift @{ $self->{queue} };
191 } else { 229 } else {
453 1 491 1
454 }, 492 },
455 ); 493 );
456}; 494};
457 495
496=item $cv = $fcp->test_dda_sync ($local_directory, $remote_directory, $want_read, $want_write)
497
498=item ($can_read, $can_write) = $fcp->test_dda_sync ($local_directory, $remote_directory, $want_read, $want_write))
499
500The DDA test in FCP is probably the single most broken protocol - only
501one directory test can be outstanding at any time, and some guessing and
502heuristics are involved in mangling the paths.
503
504This function combines C<TestDDARequest> and C<TestDDAResponse> in one
505request, handling file reading and writing as well.
506
507=cut
508
509_txn test_dda => sub {
510 my ($self, $cv, $local, $remote, $want_read, $want_write) = @_;
511
512 $self->serialise (test_dda => sub {
513 my ($self, $guard) = @_;
514
515 $self->send_msg (test_dda_request =>
516 directory => $remote,
517 want_read_directory => $want_read ? "true" : "false",
518 want_write_directory => $want_write ? "true" : "false",
519 );
520 $self->on (sub {
521 my ($type, $kv) = @_;
522
523 if ($type eq "test_dda_reply") {
524 # the filenames are all relative to the server-side directory,
525 # which might or might not match $remote anymore, so we
526 # need to rewrite the paths to be relative to $local
527 for my $k (qw(read_filename write_filename)) {
528 my $f = $kv->{$k};
529 for my $dir ($kv->{directory}, $remote) {
530 if ($dir eq substr $f, 0, length $dir) {
531 substr $f, 0, 1 + length $dir, "";
532 $kv->{$k} = $f;
533 last;
534 }
535 }
536 }
537
538 my %response = (directory => $remote);
539
540 if (length $kv->{read_filename}) {
541 warn "$local/$kv->{read_filename}";#d#
542 if (open my $fh, "<:raw", "$local/$kv->{read_filename}") {
543 sysread $fh, my $buf, -s $fh;
544 $response{read_content} = $buf;
545 }
546 }
547
548 if (length $kv->{write_filename}) {
549 if (open my $fh, ">:raw", "$local/$kv->{write_filename}") {
550 syswrite $fh, $kv->{content_to_write};
551 }
552 }
553
554 $self->send_msg (test_dda_response => %response);
555
556 $self->on (sub {
557 my ($type, $kv) = @_;
558
559 $guard if 0; # reference
560
561 if ($type eq "test_dda_complete") {
562 $cv->(
563 $kv->{read_directory_allowed} eq "true",
564 $kv->{write_directory_allowed} eq "true",
565 );
566 } elsif ($type eq "protocol_error" && $kv->{identifier} eq $remote) {
567 $cv->croak ($kv->{extra_description});
568 return;
569 }
570
571 1
572 });
573
574 return;
575 } elsif ($type eq "protocol_error" && $kv->{identifier} eq $remote) {
576 $cv->croak ($kv->{extra_description});
577 return;
578 }
579
580 1
581 });
582 });
583};
584
458=back 585=back
459 586
460=head1 EXAMPLE PROGRAM 587=head1 EXAMPLE PROGRAM
461 588
462 use AnyEvent::FCP; 589 use AnyEvent::FCP;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines