Completed
Pull Request — master (#3)
by thomas
17:25 queued 15:04
created

Connection::onMessage()   C

Complexity

Conditions 15
Paths 14

Size

Total Lines 56
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 37
CRAP Score 15

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 56
ccs 37
cts 37
cp 1
rs 6.6357
cc 15
eloc 37
nc 14
nop 1
crap 15

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 20
    public function __construct(Stream $stream, RequestFactory $requestFactory)
47
    {
48 20
        $this->factory = $requestFactory;
49 20
        $this->stream = $stream;
50 20
        $this->stream->on('data', [$this, 'onData']);
51 20
    }
52
53 7
    public function close()
54
    {
55 7
        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 2
    public function request($method, array $params = [])
64
    {
65 2
        $request = $this->factory->create($method, $params);
66 2
        return $this->send($request);
67
    }
68
69
    /**
70
     * @param NotificationInterface $notification
71
     * @return \React\Promise\Promise|\React\Promise\PromiseInterface
72
     */
73 1
    public function notify(NotificationInterface $notification)
74
    {
75 1
        return $this->stream->write($notification->toRequest()->write());
76
    }
77
78
    /**
79
     * @param Request $request
80
     * @return \React\Promise\Promise|\React\Promise\PromiseInterface
81
     */
82 3
    public function send(Request $request)
83
    {
84 3
        $result = new Deferred();
85 3
        $this->deferred[$request->getId()] = $result;
86 3
        $this->stream->write($request->write());
87
88 3
        return $result->promise();
89
    }
90
91
    /**
92
     * @param string $data
93
     */
94 8
    public function onData($data)
95
    {
96 8
        $buffer = $this->streamBuffer . $data;
97
98 8
        while (($nextPos = strpos($buffer, "\n"))) {
99 8
            $msg = substr($buffer, 0, $nextPos);
100 8
            $buffer = substr($buffer, $nextPos);
101 8
            if (substr($buffer, -1) == "\n") {
102 8
                $buffer = substr($buffer, 1);
103
            }
104 8
            $this->onMessage($msg);
105
        }
106
107 8
        if (!$buffer) {
108 8
            $this->streamBuffer = '';
109
        } else {
110 1
            $this->streamBuffer = $buffer;
111
        }
112 8
    }
113
114
    /**
115
     * @param string $data
116
     * @throws Exceptions\ApiError
117
     * @throws \Exception
118
     */
119 15
    public function onMessage($data)
120
    {
121 15
        $response = $this->factory->response($data);
122 15
        if (isset($this->deferred[$response->getId()])) {
123 1
            $this->deferred[$response->getId()]->resolve($response);
124
        } else {
125 14
            $this->emit('message', [$response]);
126
127 14
            if ($response instanceof Request) {
128 12
                $params = $response->getParams();
129
130 12
                switch ($response->getMethod()) {
131 12
                    case ElectrumClient::HEADERS_SUBSCRIBE:
132 3
                        if (!isset($params[0])) {
133 1
                            throw new \RuntimeException('Headers notification missing body');
134
                        }
135
                        
136 2
                        $header = $params[0];
137 2
                        if (count($header) !== 8) {
138 1
                            throw new \RuntimeException('Headers notification missing parameter');
139
                        }
140
141 1
                        $this->emit(ElectrumClient::HEADERS_SUBSCRIBE, [new HeadersNotification($header[0], $header[1], $header[2], $header[3], $header[4], $header[5], $header[6], $header[7])]);
142 1
                        break;
143 9
                    case ElectrumClient::ADDRESS_SUBSCRIBE:
144 3
                        if (!isset($params[0]) || !isset($params[1])) {
145 2
                            throw new \RuntimeException('Address notification missing address/txid');
146
                        }
147
148 1
                        $this->emit(ElectrumClient::ADDRESS_SUBSCRIBE, [new AddressNotification($params[0], $params[1])]);
149 1
                        break;
150 6
                    case ElectrumClient::NUMBLOCKS_SUBSCRIBE:
151 2
                        if (!isset($params[0])) {
152 1
                            throw new \RuntimeException('Missing notification parameter: height');
153
                        }
154
155 1
                        $this->emit(ElectrumClient::NUMBLOCKS_SUBSCRIBE, [new NumBlocksNotification($params[0])]);
156 1
                        break;
157 4
                    case MiningClient::SET_DIFFICULTY:
158 2
                        if (count($params) !== 1) {
159 1
                            throw new \RuntimeException('Missing mining difficulty notification parameter');
160
                        }
161
162 1
                        $this->emit(MiningClient::SET_DIFFICULTY, [new SetDifficultyNotification($params[0])]);
163 1
                        break;
164 2
                    case MiningClient::NOTIFY:
165 2
                        if (count($params) !== 9) {
166 1
                            throw new \RuntimeException('Missing mining notification parameter');
167
                        }
168
169 1
                        $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 1
                        break;
171
                }
172
            }
173
        }
174 8
    }
175
}
176