AnyEvent-BitTorrent

 view release on metacpan or  search on metacpan

lib/AnyEvent/BitTorrent.pm  view on Meta::CPAN

        $total_offset = 0;
    }
    return length $data;
}

sub hashcheck (;@) {
    my $s = shift;
    my @indexes = @_ ? @_ : (0 .. $s->piece_count);
    AE::log trace => sub {
        require Data::Dump;
        'Hashcheck of : ' . Data::Dump::dump(\@indexes);
    };
    $s->bitfield;    # Makes sure it's built
    my $total_size = $s->size;
    for my $index (@indexes) {
        next if $index < 0 || $index > $s->piece_count;
        my $piece = $s->_read($index,
                              0,
                              $index == $s->piece_count
                              ?
                                  $total_size % $s->piece_length
                              : $s->piece_length
        );
        my $expected = substr($s->pieces, $index * 20, 20);
        my $reality  = sha1($piece);
        my $ok       = defined($piece)
            && ($expected eq $reality);
        vec($s->{bitfield}, $index, 1) = $ok;
        AE::log trace => sub {
            "Validate piece #%06d %s, Expected: %s\n"
                . "                         Reality:  %s",
                $index, ($ok ? 'PASS' : 'FAIL'), unpack('H*', $expected),
                unpack('H*', $reality);
        };
        $ok ?
            $s->_trigger_hash_pass($index)
            : $s->_trigger_hash_fail($index);
    }
}
has peers => (is      => 'ro',
              lazy    => 1,
              isa     => HashRef,
              clearer => '_clear_peers',
              builder => '_build_peers'
);
sub _build_peers { {} }

sub _add_peer {
    my ($s, $h) = @_;
    $s->{peers}{+$h} = {
        handle            => $h,
        peerid            => '',
        bitfield          => (pack 'b*', "\0" x $s->piece_count),
        remote_choked     => 1,
        remote_interested => 0,
        remote_requests   => [],
        local_choked      => 1,
        local_interested  => 0,
        local_requests    => [],
        timeout           => AE::timer(20, 0, sub { $s->_del_peer($h) }),
        keepalive         => AE::timer(
            30, 120,
            sub {
                $s->_send_encrypted($h, build_keepalive());
            }
        ),

        # BEP06
        local_allowed  => [],
        remote_allowed => [],
        local_suggest  => [],
        remote_suggest => [],

        # No encryption :(
        encryption => '?'
    };
}

sub _del_peer {
    my ($s, $h) = @_;
    $s->peers->{$h} // return;
    for my $req (@{$s->peers->{$h}{local_requests}}) {
        my ($i, $o, $l) = @$req;
        $s->working_pieces->{$i}{$o}[3] = ();
    }
    delete $s->peers->{$h};
    $h->destroy;
}
my $shuffle;
has trackers => (is       => 'ro',
                 lazy     => 1,
                 builder  => '_build_trackers',
                 isa      => ArrayRef [HashRef],
                 init_arg => undef
);

sub _build_trackers {
    my $s = shift;
    $shuffle //= sub {
        my $deck = shift;    # $deck is a reference to an array
        return unless @$deck;    # must not be empty!
        my $i = @$deck;
        while (--$i) {
            my $j = int rand($i + 1);
            @$deck[$i, $j] = @$deck[$j, $i];
        }
    };
    my $trackers = [
        map {
            {urls       => $_,
             complete   => 0,
             incomplete => 0,
             peers      => '',
             peers6     => '',
             announcer  => undef,
             ticker     => AE::timer(
                 1,
                 15 * 60,
                 sub {
                     return if $s->state eq 'stopped';
                     $s->announce('started');
                 }
             ),
             failures => 0



( run in 0.790 second using v1.01-cache-2.11-cpan-df04353d9ac )