Completed
Pull Request — master (#3)
by thomas
21:44
created

Connection   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 157
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 11

Importance

Changes 3
Bugs 0 Features 0
Metric Value
wmc 24
c 3
b 0
f 0
lcom 1
cbo 11
dl 0
loc 157
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A close() 0 4 1
A request() 0 5 1
A notify() 0 4 1
A send() 0 8 1
A onData() 0 19 4
C onMessage() 0 56 15
1
<?php
2
3
namespace BitWasp\Stratum;
4
5
use BitWasp\Stratum\Api\ElectrumClient;
6
use BitWasp\Stratum\Api\MiningClient;
7
use BitWasp\Stratum\Notification\AddressNotification;
8
use BitWasp\Stratum\Notification\HeadersNotification;
9
use BitWasp\Stratum\Notification\MiningNotification;
10
use BitWasp\Stratum\Notification\NotificationInterface;
11
use BitWasp\Stratum\Notification\NumBlocksNotification;
12
use BitWasp\Stratum\Notification\SetDifficultyNotification;
13
use BitWasp\Stratum\Request\Request;
14
use BitWasp\Stratum\Request\RequestFactory;
15
use Evenement\EventEmitter;
16
use React\Promise\Deferred;
17
use React\Stream\Stream;
18
19
class Connection extends EventEmitter
20
{
21
    /**
22
     * @var Stream
23
     */
24
    private $stream;
25
    
26
    /**
27
     * @var RequestFactory
28
     */
29
    private $factory;
30
    
31
    /**
32
     * @var Deferred[]
33
     */
34
    private $deferred = [];
35
36
    /**
37
     * @var string
38
     */
39
    private $streamBuffer = '';
40
41
    /**
42
     * Connection constructor.
43
     * @param Stream $stream
44
     * @param RequestFactory $requestFactory
45
     */
46
    public function __construct(Stream $stream, RequestFactory $requestFactory)
47
    {
48
        $this->factory = $requestFactory;
49
        $this->stream = $stream;
50
        $this->stream->on('data', [$this, 'onData']);
51
    }
52
53
    public function close()
54
    {
55
        return $this->stream->close();
56
    }
57
58
    /**
59
     * @param string $method
60
     * @param array $params
61
     * @return \React\Promise\Promise|\React\Promise\PromiseInterface
62
     */
63
    public function request($method, array $params = [])
64
    {
65
        $request = $this->factory->create($method, $params);
66
        return $this->send($request);
67
    }
68
69
    /**
70
     * @param NotificationInterface $notification
71
     * @return \React\Promise\Promise|\React\Promise\PromiseInterface
72
     */
73
    public function notify(NotificationInterface $notification)
74
    {
75
        return $this->stream->write($notification->toRequest()->write());
76
    }
77
78
    /**
79
     * @param Request $request
80
     * @return \React\Promise\Promise|\React\Promise\PromiseInterface
81
     */
82
    public function send(Request $request)
83
    {
84
        $result = new Deferred();
85
        $this->deferred[$request->getId()] = $result;
86
        $this->stream->write($request->write());
87
88
        return $result->promise();
89
    }
90
91
    /**
92
     * @param string $data
93
     */
94
    public function onData($data)
95
    {
96
        $buffer = $this->streamBuffer . $data;
97
98
        while (($nextPos = strpos($buffer, "\n"))) {
99
            $msg = substr($buffer, 0, $nextPos);
100
            $buffer = substr($buffer, $nextPos);
101
            if (substr($buffer, -1) == "\n") {
102
                $buffer = substr($buffer, 1);
103
            }
104
            $this->onMessage($msg);
105
        }
106
107
        if (!$buffer) {
108
            $this->streamBuffer = '';
109
        } else {
110
            $this->streamBuffer = $buffer;
111
        }
112
    }
113
114
    /**
115
     * @param string $data
116
     * @throws Exceptions\ApiError
117
     * @throws \Exception
118
     */
119
    public function onMessage($data)
120
    {
121
        $response = $this->factory->response($data);
122
        if (isset($this->deferred[$response->getId()])) {
123
            $this->deferred[$response->getId()]->resolve($response);
124
        } else {
125
            $this->emit('message', [$response]);
126
127
            if ($response instanceof Request) {
128
                $params = $response->getParams();
129
130
                switch ($response->getMethod()) {
131
                    case ElectrumClient::HEADERS_SUBSCRIBE;
0 ignored issues
show
Coding Style introduced by
CASE statements must be defined using a colon

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
132
                        if (!isset($params[0])) {
133
                            throw new \RuntimeException('Headers notification missing body');
134
                        }
135
                        
136
                        $header = $params[0];
137
                        if (count($header) !== 8) {
138
                            throw new \RuntimeException('Headers notification missing parameter');
139
                        }
140
141
                        $this->emit(ElectrumClient::HEADERS_SUBSCRIBE, [new HeadersNotification($header[0], $header[1], $header[2], $header[3], $header[4], $header[5], $header[6], $header[7])]);
142
                        break;
143
                    case ElectrumClient::ADDRESS_SUBSCRIBE;
0 ignored issues
show
Coding Style introduced by
CASE statements must be defined using a colon

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
144
                        if (!isset($params[0]) || !isset($params[1])) {
145
                            throw new \RuntimeException('Address notification missing address/txid');
146
                        }
147
148
                        $this->emit(ElectrumClient::ADDRESS_SUBSCRIBE, [new AddressNotification($params[0], $params[1])]);
149
                        break;
150
                    case ElectrumClient::NUMBLOCKS_SUBSCRIBE;
0 ignored issues
show
Coding Style introduced by
CASE statements must be defined using a colon

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
151
                        if (!isset($params[0])) {
152
                            throw new \RuntimeException('Missing notification parameter: height');
153
                        }
154
155
                        $this->emit(ElectrumClient::NUMBLOCKS_SUBSCRIBE, [new NumBlocksNotification($params[0])]);
156
                        break;
157
                    case MiningClient::SET_DIFFICULTY;
0 ignored issues
show
Coding Style introduced by
CASE statements must be defined using a colon

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
158
                        if (count($params) !== 1) {
159
                            throw new \RuntimeException('Missing mining difficulty notification parameter');
160
                        }
161
162
                        $this->emit(MiningClient::SET_DIFFICULTY, [new SetDifficultyNotification($params[0])]);
163
                        break;
164
                    case MiningClient::NOTIFY;
0 ignored issues
show
Coding Style introduced by
CASE statements must be defined using a colon

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
165
                        if (count($params) !== 9) {
166
                            throw new \RuntimeException('Missing mining notification parameter');
167
                        }
168
169
                        $this->emit(MiningClient::NOTIFY, [new MiningNotification($params[0], $params[1], $params[2], $params[3], $params[4], $params[5], $params[6], $params[7], $params[8])]);
170
                        break;
171
                }
172
            }
173
        }
174
    }
175
}
176