Completed
Push — master ( fc4613...2e6493 )
by thomas
30:51
created

Locator::popAddress()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 4
cts 4
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 0
crap 2
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 bool $randomize - return a randomized list of dns seeds
44
     * @return string[]
45
     */
46
    public static function dnsSeedHosts($randomize = true)
47
    {
48
        $seeds = [
49
            'seed.bitcoin.sipa.be',
50
            'dnsseed.bluematt.me',
51
            'dnsseed.bitcoin.dashjr.org',
52
            'seed.bitcoinstats.com',
53
            'bitseed.xf2.org',
54
            'seed.bitnodes.io',
55
            "seed.bitcoin.jonasschnelli.ch"
56
        ];
57
58
        if ($randomize) {
59
            shuffle($seeds);
60
        }
61
62
        return $seeds;
63
    }
64
65
    /**
66
     * Connect to $numSeeds DNS seeds
67
     *
68
     * @param int $numSeeds
69
     * @return \React\Promise\Promise|\React\Promise\PromiseInterface
70
     */
71 6
    public function queryDnsSeeds($numSeeds = 1)
72
    {
73 6
        $peerList = new Deferred();
74
75
        // Take $numSeeds
76 6
        $seedHosts = $this->seeds->getHosts();
77 6
        $seeds = array_slice($seedHosts, 0, min($numSeeds, count($seedHosts)));
78
79
        // Connect to $numSeeds peers
80
        /** @var Peer[] $vNetAddr */
81 6
        $vNetAddr = [];
82 6
        foreach ($seeds as $seed) {
83 6
            $this->dns
84 6
                ->resolve($seed)
85
                ->then(function ($ipList) use (&$vNetAddr, $peerList, &$numSeeds) {
86 6
                    $vNetAddr[] = $ipList;
87 6
                    if (count($vNetAddr) == $numSeeds) {
88 6
                        $peerList->resolve($vNetAddr);
89 4
                    }
90 6
                })
91
            ;
92 4
        }
93
94
        // Compile the list of lists of peers into $this->knownAddresses
95
        return $peerList
96 6
            ->promise()
97 6
            ->then(
98
                function (array $vPeerVAddrs) {
99 6
                    shuffle($vPeerVAddrs);
100
101
                    /** @var NetworkAddressInterface[] $addresses */
102 6
                    $addresses = [];
103 6
                    array_map(
104 6
                        function (array $value) use (&$addresses) {
105 6
                            foreach ($value as $ip) {
106 6
                                $addresses[] = new NetworkAddress(
107 6
                                    Services::NETWORK,
108 6
                                    new Ipv4($ip),
109 2
                                    8333
110 4
                                );
111 4
                            }
112 6
                        },
113
                        $vPeerVAddrs
114 4
                    );
115
116 6
                    $this->knownAddresses = array_merge(
117 6
                        $this->knownAddresses,
118
                        $addresses
119 4
                    );
120
                    
121 6
                    return $this;
122 2
                }
123 4
            )
124 4
        ;
125
    }
126
127
    /**
128
     * @return NetworkAddressInterface[]
129
     */
130 3
    public function getKnownAddresses()
131
    {
132 3
        return $this->knownAddresses;
133
    }
134
135
    /**
136
     * Pop an address from the discovered peers
137
     *
138
     * @return NetworkAddressInterface
139
     * @throws \Exception
140
     */
141 6
    public function popAddress()
142
    {
143 6
        if (count($this->knownAddresses) < 1) {
144 3
            throw new \Exception('No peers');
145
        }
146
147 3
        return array_pop($this->knownAddresses);
148
    }
149
}
150