Add 'Peers' message support
[VCS-Git-Torrent.git] / lib / VCS / Git / Torrent / PWP / Message / Peers.pm
blobd569b87e0641dfa6c6a7147dcf2353d82ae795fa
2 package VCS::Git::Torrent::PWP::Message::Peers;
4 =head1 NAME
6 VCS::Git::Torrent::PWP::Message::Peers
8 =head2 DESCRIPTION
10 Implements the Peers message from the RFC.
11 L<http://gittorrent.utsl.gen.nz/rfc.html#pwp-peers>
13 =cut
15 use Moose;
16 with "VCS::Git::Torrent::PWP::Message";
17 use Carp;
18 use VCS::Git::Torrent::PWP qw(:pwp_constants unpack_hex pack_hex pack_num unpack_num);
20 has 'peers' =>
21 isa => "ArrayRef[VCS::Git::Torrent::Peer]",
22 is => "rw",
25 sub pack_payload {
26 my $self = shift;
27 my $payload = "";
29 for my $peer ( @{ $self->peers } ) {
30 $payload .= $peer->peer_id;
31 $payload .= pack('n', $peer->port);
32 $payload .= pack_num(length($peer->address));
33 $payload .= $peer->address;
36 $payload;
39 my $temp_peers = [];
41 sub unpack_payload {
42 my $self = shift;
43 my $payload = shift;
45 while ( length($payload) ) {
46 my $peer_id = substr($payload, 0, 20);
47 my $peer_port = unpack('n', substr($payload, 20, 2));
48 my $addr_len = unpack_num(substr($payload, 22, 4));
49 die 'invalid size' if ( 26 + $addr_len > length($payload) );
50 my $peer_addr = substr($payload, 26, $addr_len);
52 substr($payload, 0, 26 + $addr_len) = '';
54 push @{ $temp_peers }, [ $peer_id, $peer_port, $peer_addr ];
58 sub args {
59 my $class = shift;
60 my $peers;
62 if ( ref($_[0]) eq 'ARRAY' ) {
63 foreach(@_) {
64 push @{ $peers }, @{ $_ };
67 else {
68 $peers = [ @_ ];
71 return( peers => $peers );
74 sub action {
75 my $self = shift;
76 my $local_peer = shift;
77 my $connection = shift;
79 if ( scalar(@{ $temp_peers }) ) { # we got some peers from someone
80 my @peers = ();
82 for my $peer (@{ $temp_peers }) {
83 push @peers, VCS::Git::Torrent::Peer->new(
84 repo_hash => $local_peer->repo_hash,
85 peer_id => $peer->[0],
86 peer_port => $peer->[1],
87 peer_addr => $peer->[2],
91 $self->peers(\@peers);
93 # check for duplicates
94 my @new_peers = map {
95 my $peer = $_;
97 my $num = grep {
98 $peer->peer_id eq $_->peer_id # && ?
99 } @{ $local_peer->knows };
101 $num ? () : ($peer)
102 } @{ $self->peers };
104 push @{ $local_peer->knows }, @new_peers;
105 # push @{ $connection->remote->peers }, @{ $self->peers };
107 else { # it was a request for our peers
108 my @remotes = map {
109 $_->remote->port ? $_->remote : ()
110 } @{ $local_peer->connections };
112 $local_peer->send_message($connection->remote, GTP_PWP_PEERS,
113 $local_peer->knows,
114 \@remotes,
115 ) if (
116 scalar(@{ $local_peer->knows }) ||
117 scalar(@remotes)