Completed
Pull Request — master (#64)
by thomas
56:33 queued 53:42
created

Locator::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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