Completed
Push — EventLoopContainer ( c9a84d...6e77fa )
by Vasily
04:04
created

Connection::onRead()   F

Complexity

Conditions 33
Paths 0

Size

Total Lines 96
Code Lines 72

Duplication

Lines 0
Ratio 0 %

Importance

Changes 6
Bugs 1 Features 0
Metric Value
cc 33
dl 0
loc 96
rs 2
eloc 72
c 6
b 1
f 0
nc 0
nop 0

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
namespace PHPDaemon\Clients\Mongo;
3
4
use PHPDaemon\Core\Daemon;
5
use PHPDaemon\Network\ClientConnection;
6
7
/**
8
 * @package    Applications
9
 * @subpackage MongoClientAsync
10
 * @author     Vasily Zorin <[email protected]>
11
 */
12
class Connection extends ClientConnection
13
{
14
15
    /**
16
     * @TODO DESCR
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
17
     */
18
    const STATE_PACKET = 1;
19
20
    /**
21
     * @var string Database name
22
     */
23
    public $dbname;
24
    /**
25
     * @var array Active cursors
26
     */
27
    public $cursors = [];
28
    /**
29
     * @var array Pending requests
30
     */
31
    public $requests = [];
32
    /**
33
     * @var integer ID of the last request
34
     */
35
    public $lastReqId = 0;
36
    /**
37
     * @var integer Initial value of the minimal amout of bytes in buffer
38
     */
39
    protected $lowMark = 16;
40
    /**
41
     * @var integer Initial value of the maximum amout of bytes in buffer
42
     */
43
    protected $highMark = 0xFFFFFF;
44
    /**
45
     * @var array
46
     */
47
    protected $hdr;
48
    protected $maxQueue = 10;
49
50
    /**
51
     * @TODO DESCR
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
52
     * @return void
53
     */
54
    public function onReady()
55
    {
56
        if ($this->user === null) {
57
            $this->connected = true;
58
        }
59
        if ($this->connected) {
60
            parent::onReady();
61
            return;
62
        }
63
        $this->dbname = $this->path;
64
        $this->pool->saslScrumSHA1Auth(
65
            [
66
                'user' => $this->user,
67
                'password' => $this->password,
68
                'dbname' => $this->dbname,
69
                'conn' => $this
70
            ],
71
            function ($result) {
72
                if (!isset($result['ok']) || !$result['ok']) {
73
                    Daemon::log('MongoClient: authentication error with ' . $this->url . ': ' . $result['errmsg']);
74
                    $this->finish();
75
                    return;
76
                }
77
                $this->connected = true;
78
                $this->onReady();
79
            },
80
            $this
81
        );
82
    }
83
84
    /**
85
     * Called when new data received
86
     * @return void
87
     */
88
    public function onRead()
89
    {
90
        start:
91
        if ($this->freed) {
92
            return;
93
        }
94
        if ($this->state === self::STATE_ROOT) {
95
            if (false === ($hdr = $this->readExact(16))) {
96
                return; // we do not have a header
97
            }
98
            $this->hdr = unpack('Vlen/VreqId/VresponseTo/VopCode', $hdr);
99
            $this->hdr['plen'] = $this->hdr['len'] - 16;
100
            $this->setWatermark($this->hdr['plen'], $this->hdr['plen']);
101
            $this->state = self::STATE_PACKET;
102
        }
103
        if ($this->state === self::STATE_PACKET) {
104
            if (false === ($pct = $this->readExact($this->hdr['plen']))) {
105
                return; //we do not have a whole packet
106
            }
107
            $this->state = self::STATE_ROOT;
108
            $this->setWatermark(16, 0xFFFFFF);
109
            if ($this->hdr['opCode'] === Pool::OP_REPLY) {
110
                $r = unpack('Vflag/VcursorID1/VcursorID2/Voffset/Vlength', mb_orig_substr($pct, 0, 20));
111
                $r['cursorId'] = mb_orig_substr($pct, 4, 8);
112
                $id = (int)$this->hdr['responseTo'];
113
                if (isset($this->requests[$id])) {
114
                    $req = $this->requests[$id];
115
                    if (sizeof($req) === 1) { // get more
116
                        $r['cursorId'] = $req[0];
117
                    }
118
                } else {
119
                    $req = false;
120
                }
121
                $flagBits = str_pad(strrev(decbin($r['flag'])), 8, '0', STR_PAD_LEFT);
122
                $curId = ($r['cursorId'] !== "\x00\x00\x00\x00\x00\x00\x00\x00" ? 'c' . $r['cursorId'] : 'r' . $this->hdr['responseTo']);
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 137 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
123
124
                if ($req && isset($req[2]) && ($req[2] === false) && !isset($this->cursors[$curId])) {
125
                    $cur = new Cursor($curId, $req[0], $this);
126
                    $this->cursors[$curId] = $cur;
127
                    $cur->failure = $flagBits[1] === '1';
128
                    $cur->await = $flagBits[3] === '1';
129
                    $cur->callback = $req[1];
130
                    $cur->parseOplog = isset($req[3]) && $req[3];
131
                    $cur->tailable = isset($req[4]) && $req[4];
132
                } else {
133
                    $cur = isset($this->cursors[$curId]) ? $this->cursors[$curId] : false;
134
                }
135
                if ($cur && (($r['length'] === 0) || (mb_orig_substr($curId, 0, 1) === 'r'))) {
136
                    if ($cur->tailable) {
137
                        if ($cur->finished = ($flagBits[0] === '1')) {
138
                            $cur->destroy();
139
                        }
140
                    } else {
141
                        $cur->finished = true;
142
                    }
143
                }
144
145
                $p = 20;
146
                $items = [];
147
                while ($p < $this->hdr['plen']) {
148
                    $dl = unpack('Vlen', mb_orig_substr($pct, $p, 4));
149
                    $doc = bson_decode(mb_orig_substr($pct, $p, $dl['len']));
150
151
                    if ($cur) {
152
                        if ($cur->parseOplog && isset($doc['ts'])) {
153
                            $tsdata = unpack('Vsec/Vinc', mb_orig_substr($pct, $p + 8, 8));
154
                            $doc['ts'] = $tsdata['sec'] . ' ' . $tsdata['inc'];
155
                        }
156
                        $cur->items[] = $doc;
157
                        ++$cur->counter;
158
                    } else {
159
                        $items[] = $doc;
160
                    }
161
                    $p += $dl['len'];
162
                }
163
                $this->setFree(true);
164
                if (isset($req[2]) && $req[2] && $req[1]) {
165
                    $req[1](sizeof($items) ? $items[0] : false);
166
167
                    if ($cur) {
168
                        if ($cur instanceof Cursor) {
169
                            $cur->destroy();
170
                        } else {
171
                            unset($this->cursors[$curId]);
172
                        }
173
                    }
174
                } elseif ($cur) {
175
                    $func = $cur->callback;
176
                    $func($cur);
177
                }
178
                unset($this->requests[$id]);
179
                $req = null;
0 ignored issues
show
Unused Code introduced by
$req is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
180
            }
181
        }
182
        goto start;
183
    }
184
185
    /**
186
     * onFinish
187
     * @return void
188
     */
189
    public function onFinish()
190
    {
191
        foreach ($this->cursors as $curId => $cur) {
192
            if ($cur instanceof Cursor) {
193
                $cur->destroy(true);
194
            }
195
        }
196
        $this->cursors = null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array of property $cursors.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
197
        $this->requests = null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array of property $requests.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
198
        parent::onFinish();
199
    }
200
}
201