Completed
Push — master ( 2dcc62...2dcc62 )
by thomas
151:35 queued 116:37
created

Locator::dnsSeedHosts()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 18
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 18
ccs 0
cts 12
cp 0
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 12
nc 2
nop 1
crap 6
1
<?php
2
3
namespace BitWasp\Bitcoin\Networking\Peer;
4
5
use BitWasp\Bitcoin\Networking\DnsSeeds\DnsSeedList;
6
use BitWasp\Bitcoin\Networking\Ip\Ipv4;
7
use BitWasp\Bitcoin\Networking\Services;
8
use BitWasp\Bitcoin\Networking\Structure\NetworkAddress;
9
use BitWasp\Bitcoin\Networking\Structure\NetworkAddressInterface;
10
use React\Dns\Resolver\Resolver;
11
use React\Promise\Deferred;
12
13
class Locator
14
{
15
16
    /**
17
     * @var Resolver
18
     */
19
    private $dns;
20
21
    /**
22
     * @var DnsSeedList
23
     */
24
    private $seeds;
25
26
    /**
27
     * @var NetworkAddressInterface[]
28
     */
29
    private $knownAddresses = [];
30
31
    /**
32
     * Locator constructor.
33
     * @param DnsSeedList $list
34
     * @param Resolver $dns
35
     */
36 9
    public function __construct(DnsSeedList $list, Resolver $dns)
37
    {
38 9
        $this->seeds = $list;
39 9
        $this->dns = $dns;
40 9
    }
41
42
    /**
43
     * @param int $numSeeds
44
     * @return \React\Promise\Promise|\React\Promise\PromiseInterface
45
     */
46
    private function getPeerList($numSeeds = 1)
47
    {
48
        $peerList = new Deferred();
49
50
        // Take $numSeeds
51
        $seedHosts = $this->seeds->getHosts();
52
        shuffle($seedHosts);
53
        $seeds = array_slice($seedHosts, 0, min($numSeeds, count($seedHosts)));
54
55
        // Connect to $numSeeds peers
56
        /** @var Peer[] $vNetAddr */
57
        $vNetAddr = [];
58
        $c = 0;
59
        foreach ($seeds as $seed) {
60
            $this->dns
61
                ->resolve($seed)
62
                ->then(function ($ipList) use (&$vNetAddr, $peerList, &$numSeeds, &$c) {
63
                    $vNetAddr = array_merge($vNetAddr, $ipList);
64
                    if ($numSeeds === ++$c) {
65
                        $peerList->resolve($vNetAddr);
66
                    }
67
                }, function ($error) use ($peerList) {
68
                    $peerList->reject($error);
69 6
                })
70
            ;
71 6
        }
72
73
        // Compile the list of lists of peers into $this->knownAddresses
74 6
        return $peerList->promise();
75 6
    }
76 6
77
    /**
78
     * Connect to $numSeeds DNS seeds
79
     *
80 6
     * @param int $numSeeds
81 6
     * @return \React\Promise\Promise|\React\Promise\PromiseInterface
82 6
     */
83 6
    public function queryDnsSeeds($numSeeds = 1)
84 6
    {
85
        $deferred = new Deferred();
86 5
        $this
87 5
            ->getPeerList($numSeeds)
88 5
            ->then(
89 3
                function (array $vPeerVAddrs) use ($deferred) {
90
                    shuffle($vPeerVAddrs);
91 1
92 6
                    /** @var NetworkAddressInterface[] $addresses */
93
                    $addresses = [];
94 4
                    foreach ($vPeerVAddrs as $ip) {
95
                        $addresses[] = new NetworkAddress(
96
                            Services::NETWORK,
97 6
                            new Ipv4($ip),
98
                            8333
99
                        );
100
                    }
101
102
                    $this->knownAddresses = array_merge(
103
                        $this->knownAddresses,
104
                        $addresses
105
                    );
106 6
107
                    $deferred->resolve($this);
108 6
                },
109 4
                function ($error) use ($deferred) {
110 6
                    $deferred->reject($error);
111 6
                }
112
            )
113 5
        ;
114
115
        return $deferred->promise();
116 5
    }
117 5
118 5
    /**
119 5
     * @return NetworkAddressInterface[]
120 5
     */
121 2
    public function getKnownAddresses()
122 3
    {
123 3
        return $this->knownAddresses;
124
    }
125 5
126 5
    /**
127
     * Pop an address from the discovered peers
128 3
     *
129
     * @return NetworkAddressInterface
130 5
     * @throws \Exception
131 6
     */
132 3
    public function popAddress()
133 1
    {
134 3
        if (count($this->knownAddresses) < 1) {
135 4
            throw new \Exception('No peers');
136
        }
137
138 6
        return array_pop($this->knownAddresses);
139
    }
140
}
141