Completed
Pull Request — master (#85)
by thomas
02:06
created

Locator   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 141
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 92.86%

Importance

Changes 0
Metric Value
wmc 10
lcom 1
cbo 6
dl 0
loc 141
ccs 52
cts 56
cp 0.9286
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A setDefaultPort() 0 4 1
A querySeeds() 0 22 2
A getPeerList() 0 9 1
B queryDnsSeeds() 0 34 2
A getKnownAddresses() 0 4 1
A popAddress() 0 8 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 12
    public function __construct(DnsSeedList $list, Resolver $dns, $defaultNetPort = 8333)
37
    {
38 12
        $this->seeds = $list;
39 12
        $this->dns = $dns;
40 12
        $this->defaultPort = $defaultNetPort;
0 ignored issues
show
Bug introduced by
The property defaultPort does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
41 12
    }
42
43
    /**
44
     * Sets the default port for network addresses returned by this instance.
45
     *
46
     * @param int $defaultNetPort
47
     */
48
    public function setDefaultPort($defaultNetPort)
49
    {
50
        $this->defaultPort = $defaultNetPort;
51
    }
52
53 9
    public function querySeeds(array $seeds)
54
    {
55 9
        $peerList = new Deferred();
56
57
        // Connect to $numSeeds peers
58
        /** @var Peer[] $vNetAddr */
59 9
        $vNetAddr = [];
60 9
        $c = 0;
61 9
        foreach ($seeds as $seed) {
62 9
            $this->dns
63 9
                ->resolve($seed)
64
                ->then(function ($ipList) use (&$vNetAddr, $peerList, &$numSeeds, &$c) {
65 6
                    $peerList->resolve($ipList);
66
                }, function ($error) use ($peerList) {
67 3
                    $peerList->reject($error);
68 9
                })
69
            ;
70 3
        }
71
72
        // Compile the list of lists of peers into $this->knownAddresses
73 9
        return $peerList->promise();
74
    }
75
76
    /**
77
     * @param int $numSeeds
78
     * @return \React\Promise\Promise|\React\Promise\PromiseInterface
79
     */
80 6
    private function getPeerList($numSeeds = 1)
81
    {
82
        // Take $numSeeds
83 6
        $seedHosts = $this->seeds->getHosts();
84 6
        shuffle($seedHosts);
85 6
        $seeds = array_slice($seedHosts, 0, min($numSeeds, count($seedHosts)));
86
87 6
        return $this->querySeeds($seeds);
88
    }
89
90
    /**
91
     * Connect to $numSeeds DNS seeds
92
     *
93
     * @param int $numSeeds
94
     * @return \React\Promise\Promise|\React\Promise\PromiseInterface
95
     */
96 6
    public function queryDnsSeeds($numSeeds = 1)
97
    {
98 6
        $deferred = new Deferred();
99 2
        $this
100 6
            ->getPeerList($numSeeds)
101 6
            ->then(
102
                function (array $vPeerVAddrs) use ($deferred) {
103 6
                    shuffle($vPeerVAddrs);
104
105
                    /** @var NetworkAddressInterface[] $addresses */
106 6
                    $addresses = [];
107 6
                    foreach ($vPeerVAddrs as $ip) {
108 6
                        $addresses[] = new NetworkAddress(
109 6
                            Services::NETWORK,
110 6
                            new Ipv4($ip),
111 6
                            $this->defaultPort
112 2
                        );
113 2
                    }
114
115 6
                    $this->knownAddresses = array_merge(
116 6
                        $this->knownAddresses,
117 2
                        $addresses
118 2
                    );
119
120 6
                    $deferred->resolve($this);
121 6
                },
122 4
                function ($error) use ($deferred) {
123
                    $deferred->reject($error);
124 4
                }
125 2
            )
126
        ;
127
128 6
        return $deferred->promise();
129
    }
130
131
    /**
132
     * @return NetworkAddressInterface[]
133
     */
134 3
    public function getKnownAddresses()
135
    {
136 3
        return $this->knownAddresses;
137
    }
138
139
    /**
140
     * Pop an address from the discovered peers
141
     *
142
     * @return NetworkAddressInterface
143
     * @throws \Exception
144
     */
145 6
    public function popAddress()
146
    {
147 6
        if (count($this->knownAddresses) < 1) {
148 3
            throw new \Exception('No peers');
149
        }
150
151 3
        return array_pop($this->knownAddresses);
152
    }
153
}
154