Completed
Push — GearmanClient ( 9cbb32...e50ad6 )
by Vasily
04:03
created

Connection::onReady()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 3
eloc 6
nc 4
nop 0
dl 0
loc 10
rs 9.4285
1
<?php
2
namespace PHPDaemon\Clients\GearmanClient;
3
4
use PHPDaemon\Network\ClientConnection;
5
use PHPDaemon\Utils\Crypt;
6
7
8
/**
9
 * @package NetworkClients
10
 * @subpackage GearmanClient
11
 * @protocol http://gearman.org/protocol/
12
 *
13
 * @interface http://php.net/manual/ru/class.gearmanclient.php
14
 *
15
 * @author Popov Gennadiy <[email protected]>
16
 */
17
class  Connection extends ClientConnection {
0 ignored issues
show
Coding Style introduced by
Expected 1 space between class keyword and class name; 2 found
Loading history...
18
19
    /**
20
     * Magic code for request
21
     */
22
    const MAGIC_REQUEST         = "\0REQ";
23
24
    /**
25
     * Magic code for response
26
     */
27
    const MAGIC_RESPONSE        = "\0RES";
28
29
    /*
30
     * Byte length of header
31
     */
32
    const HEADER_LENGTH         = 12;
33
34
    /**
35
     * Header binary format
36
     */
37
    const HEADER_WRITE_FORMAT   = "a4NN";
38
39
    /**
40
     * Header read format
41
     */
42
    const HEADER_READ_FORMAT    = "a4magic/Ntype/Nsize";
43
44
    /**
45
     * Delimeter for function arguments
46
     */
47
    const ARGS_DELIMITER        = "\0";
48
49
50
51
    /**
52
     * Request codes
53
     *
54
     * @var array
55
     */
56
    protected static $requestCommandList = [
57
        'CAN_DO' => 1,
58
        'CANT_DO' => 2,
59
        'RESET_ABILITIES' => 3,
60
        'PRE_SLEEP' => 4,
61
        'SUBMIT_JOB' => 7,
62
        'GRAB_JOB' => 9,
63
        'WORK_STATUS' => 12,
64
        'WORK_COMPLETE' => 13,
65
        'WORK_FAIL' => 14,
66
        'GET_STATUS' => 15,
67
        'ECHO_REQ' => 16,
68
        'SUBMIT_JOB_BG' => 18,
69
        'SUBMIT_JOB_HIGH' => 21,
70
        'SET_CLIENT_ID' => 22,
71
        'CAN_DO_TIMEOUT' => 23,
72
        'ALL_YOURS' => 24,
73
        'WORK_EXCEPTION' => 25,
74
        'OPTION_REQ' => 26,
75
        'OPTION_RES' => 27,
76
        'WORK_DATA' => 28,
77
        'WORK_WARNING' => 29,
78
        'GRAB_JOB_UNIQ' => 30,
79
        'SUBMIT_JOB_HIGH_BG' => 32,
80
        'SUBMIT_JOB_LOW' => 33,
81
        'SUBMIT_JOB_LOW_BG' => 34,
82
        'SUBMIT_JOB_SCHED' => 35,
83
        'SUBMIT_JOB_EPOCH' => 36,
84
    ];
85
    protected static $requestCommandListFlipped;
86
87
    /**
88
     * Response codes
89
     *
90
     * @var array
91
     */
92
    protected static $responseCommandList = [
93
        'NOOP' => 6,
94
        'JOB_CREATED' => 8,
95
        'NO_JOB' => 10,
96
        'JOB_ASSIGN' => 11,
97
        'WORK_STATUS' => 12,
98
        'WORK_COMPLETE' => 13,
99
        'WORK_FAIL' => 14,
100
        'ECHO_RES' => 17,
101
        'ERROR' => 19,
102
        'STATUS_RES' => 20,
103
        'WORK_EXCEPTION' => 25,
104
        'OPTION_RES' => 27,
105
        'WORK_WARNING' => 29,
106
        'JOB_ASSIGN_UNIQ' => 31,
107
    ];
108
109
    protected static $responseCommandListFlipped;
110
111
    /**
112
     * @var mixed
113
     */
114
    public $response;
115
116
    /**
117
     * @var string
118
     */
119
    public $responseType;
120
121
    /**
122
     * @var string
123
     */
124
    public $responseCommand;
125
126
    /**
127
     * Called when new data received
128
     *
129
     * @return void
130
     */
131
    public function onRead()
132
    {
133
        if (($head = $this->lookExact(static::HEADER_LENGTH)) === false) {
134
            return;
135
        }
136
137
        list($magic, $typeInt, $size) = unpack(static::HEADER_READ_FORMAT, $head);
138
139
        if ($this->getInputLength() < static::HEADER_LENGTH + $size) {
140
            return;
141
        }
142
143
        $this->drain(static::HEADER_LENGTH);
144
        $pct = $this->read($size);
145
146
        if ($magic === static::MAGIC_RESPONSE) {
147
            $this->responseType = static::responseCommandListFlipped[$typeInt];
148
            $this->response = explode(static::ARGS_DELIMITER, $pct);
149
            $this->onResponse->executeOne($this);
150
            $this->responseType = null;
151
            $this->responseCommand = null;
152
            $this->responseType = null;
153
            $this->checkFree();
154
            return;
155
        } else {
156
            $type = static::$requestCommandListFlipped[$typeInt];
0 ignored issues
show
Unused Code introduced by
$type 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...
157
            // @TODO
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...
158
        }
159
    }
160
    
161
    /**
162
     * Called when the connection is handshaked (at low-level), and peer is ready to recv. data
163
     * @return void
164
     */
165
    public function onReady()
166
    {
167
        if (static::$requestCommandListFlipped === null) {
168
            static::$requestCommandListFlipped = array_flip(static::$requestCommandList);
169
        }
170
        if (static::$responseCommandListFlipped === null) {
171
            static::$responseCommandListFlipped = array_flip(static::$responseCommandList);
172
        }
173
        parent::onReady();
174
    }
175
176
177
    /**
178
     * Function send ECHO
179
     *
180
     * @param $payload
181
     * @param callable|null $cb
182
     */
183
    public function sendEcho ($payload, $cb = null)
184
    {
185
        $this->sendCommand('ECHO_REQ', $payload, $cb);
186
    }
187
188
    /**
189
     * Function run task and wait result in callback
190
     *
191
     * @param $params
192
     * @param callable $cb = null
0 ignored issues
show
Documentation introduced by
Should the type for parameter $cb not be callable|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
193
     * @param boolean $unique
0 ignored issues
show
Bug introduced by
There is no parameter named $unique. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
194
     */
195
    public function submitJob($params, $cb = null)
196
    {
197
        $closure = function () use (&$params, $cb)
198
        {
199
            $this->sendCommand('SUBMIT_JOB'
200
                . (isset($params['pri']) ? '_ ' . strtoupper($params['pri']) : '')
201
                . (isset($params['bg']) && $params['bg'] ? '_BG' : ''),
202
                [$params['function'], $params['unique'], $params['payload']],
203
                $cb
204
            );
205
        };
206
        if (isset($params['unique'])) {
207
            $closure();
208
        } else {
209
            Crypt::randomString(10, '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', function($random) use ($closure) {
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 136 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...
210
                $params['unique'] = $random;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$params was never initialized. Although not strictly required by PHP, it is generally a good practice to add $params = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
211
                $closure();
212
            });
213
        }
214
    }
215
216
    /**
217
     * Get job status
218
     * 
219
     * @param mixed $jobHandle Job handle that was given in JOB_CREATED packet.
220
     * @param callable $cb = null
0 ignored issues
show
Documentation introduced by
Should the type for parameter $cb not be callable|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
221
     *
222
     */
223
    public function getStatus($jobHandle, $cb = null) {
224
        $this->sendCommand('GET_STATUS', [$jobHandle], $cb);
225
    }
226
227
    /**
228
     * Function set settings for current connection
229
     * Available settings
230
     * 'exceptions' - Forward WORK_EXCEPTION packets to the client.
231
     *
232
     * @url http://gearman.org/protocol/
233
     *
234
     *
235
     * @param int $optionName
236
     * @param callable $cb = null
0 ignored issues
show
Documentation introduced by
Should the type for parameter $cb not be callable|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
237
     */
238
    public function setConnectionOption($optionName, $cb = null) {
239
        $this->sendCommand('OPTION_RES', [$optionName], $cb);
240
    }
241
242
    /**
243
     * Send a command
244
     *
245
     * @param $commandName
246
     * @param $payload
247
     * @param callable $cb = null
0 ignored issues
show
Documentation introduced by
Should the type for parameter $cb not be callable|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
248
     */
249
    public function sendCommand($commandName, $payload, $cb = null) {
250
251
        $pct = implode(
252
            static::ARGS_DELIMITER,
253
            array_map(function($item){ return !is_scalar($item) ? serialize($item) : $item; }, (array) $payload)
254
        );
255
        $this->onResponse->push($cb);
0 ignored issues
show
Bug introduced by
It seems like $cb defined by parameter $cb on line 249 can also be of type null; however, PHPDaemon\Structures\StackCallbacks::push() does only seem to accept callable, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
256
        $this->write(pack(
257
            static::HEADER_WRITE_FORMAT,
258
            static::MAGIC_REQUEST, $this->requestCommandList[$commandName], mb_orig_strlen($pct)));
259
        $this->write($pct);
260
    }
261
}