Passed
Push — master ( 4cc39f...d5b9c5 )
by Timo
03:08
created

ClientSessionStub::createPromiseAdapter()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
/*
4
 * This file is part of the Tidal/WampWatch package.
5
 *   (c) 2016 Timo Michna <timomichna/yahoo.de>
6
 *
7
 *  For the full copyright and license information, please view the LICENSE
8
 *  file that was distributed with this source code.
9
 *
10
 */
11
12
namespace Tidal\WampWatch\Stub;
13
14
use Evenement\EventEmitterInterface;
15
use Evenement\EventEmitterTrait;
16
use React\Promise\Deferred;
17
use Thruway\Message\PublishedMessage;
18
use Thruway\Message\PublishMessage;
19
use Thruway\Message\SubscribedMessage;
20
use Thruway\Message\SubscribeMessage;
21
use Thruway\Message\RegisteredMessage;
22
use Thruway\Message\RegisterMessage;
23
use Thruway\Message\UnregisteredMessage;
24
use Thruway\Message\CallMessage;
25
use Thruway\Message\ErrorMessage;
26
use Tidal\WampWatch\ClientSessionInterface;
27
use Tidal\WampWatch\Exception\UnknownProcedureException;
28
use Tidal\WampWatch\Exception\UnknownTopicException;
29
use React\Promise\Promise;
30
use Tidal\WampWatch\Adapter\React\PromiseAdapter;
31
32
/**
33
 * !!! WARNING !!!!
34
 * This Class should only be used for testing or demos.
35
 * It allows for testing client method calls but behaves differently to
36
 * real client session implementation in that it only stores one (the last)
37
 * subscription, registration etc. for a specific topic/procedure.
38
 */
39
40
/**
41
 * Class ClientSessionStub.
42
 */
43
class ClientSessionStub implements ClientSessionInterface, EventEmitterInterface
44
{
45
    use EventEmitterTrait;
46
47
    /**
48
     * @var int
49
     */
50
    protected $sessionId;
51
52
    /**
53
     * @var array
54
     */
55
    protected $subscriptions = [];
56
57
    /**
58
     * @var array
59
     */
60
    protected $subscribing = [];
61
62
    /**
63
     * @var array
64
     */
65
    protected $publications = [];
66
67
    /**
68
     * @var array
69
     */
70
    protected $publishing = [];
71
72
    /**
73
     * @var array
74
     */
75
    protected $registrations = [];
76
77
    /**
78
     * @var array
79
     */
80
    protected $registering = [];
81
82
    /**
83
     * @var array
84
     */
85
    protected $unregistrations = [];
86
87
    /**
88
     * @var array
89
     */
90
    protected $calls = [];
91
92
    /**
93
     * @var array
94
     */
95
    protected $calling = [];
96
97
    /**
98
     * @var array
99
     */
100
    protected $procedures = [];
101
102
    /**
103
     * Subscribe.
104
     *
105
     * @param string   $topicName
106
     * @param callable $callback
107
     * @param          $options   array
108
     *
109
     * @return PromiseAdapter
110
     */
111 View Code Duplication
    public function subscribe($topicName, callable $callback, $options = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
112
    {
113
        $this->on($topicName, $callback);
114
115
        $futureResult = new Deferred();
116
117
        $this->subscriptions[$topicName] = $futureResult;
118
        $this->subscribing[$topicName] = new SubscribeMessage(
119
            count($this->subscriptions),
120
            (object) $options,
121
            $topicName
122
        );
123
124
        return $this->createPromiseAdapter(
125
            $futureResult->promise()
0 ignored issues
show
Compatibility introduced by
$futureResult->promise() of type object<React\Promise\PromiseInterface> is not a sub-type of object<React\Promise\Promise>. It seems like you assume a concrete implementation of the interface React\Promise\PromiseInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
126
        );
127
    }
128
129
    /**
130
     * Trigger a SUBSCRIBED message for given topic.
131
     *
132
     * @param $topicName
133
     * @param $requestId
134
     * @param $subscriptionId
135
     *
136
     * @throws UnknownTopicException if the topic is unknown
137
     */
138 View Code Duplication
    public function completeSubscription($topicName, $requestId = 1, $subscriptionId = 1)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
139
    {
140
        if (!isset($this->subscriptions[$topicName])) {
141
            throw new UnknownTopicException($topicName);
142
        }
143
144
        /* @var $futureResult Deferred */
145
        $futureResult = $this->subscriptions[$topicName];
146
        $result = new SubscribedMessage($requestId, $subscriptionId);
147
148
        $futureResult->resolve($result);
149
    }
150
151
    public function hasSubscription($topicName)
152
    {
153
        return isset($this->subscriptions[$topicName]);
154
    }
155
156
    /**
157
     * Publish.
158
     *
159
     * @param string      $topicName
160
     * @param array|mixed $arguments
161
     * @param array|mixed $argumentsKw
162
     * @param array|mixed $options
163
     *
164
     * @return PromiseAdapter
165
     */
166 View Code Duplication
    public function publish($topicName, $arguments = null, $argumentsKw = null, $options = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
167
    {
168
        $futureResult = new Deferred();
169
170
        $this->publications[$topicName] = $futureResult;
171
        $this->publishing[$topicName] = new PublishMessage(
172
            count($this->publishing),
173
            $options,
174
            $topicName,
175
            $arguments,
176
            $argumentsKw
177
        );
178
179
        return $this->createPromiseAdapter(
180
            $futureResult->promise()
0 ignored issues
show
Compatibility introduced by
$futureResult->promise() of type object<React\Promise\PromiseInterface> is not a sub-type of object<React\Promise\Promise>. It seems like you assume a concrete implementation of the interface React\Promise\PromiseInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
181
        );
182
    }
183
184
    /**
185
     * Trigger a PUBLISHED message for given topic.
186
     *
187
     * @param string $topicName
188
     * @param int    $requestId
189
     * @param int    $publicationId
190
     *
191
     * @throws UnknownTopicException if the topic is unknown
192
     */
193 View Code Duplication
    public function confirmPublication($topicName, $requestId = 1, $publicationId = 1)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
194
    {
195
        if (!isset($this->publications[$topicName])) {
196
            throw new UnknownTopicException($topicName);
197
        }
198
199
        $futureResult = $this->publications[$topicName];
200
        $result = new PublishedMessage($requestId, $publicationId);
201
202
        $futureResult->resolve($result);
203
    }
204
205
    /**
206
     * @param string $topicName
207
     * @param mixed  $error
208
     * @param int    $requestId
209
     */
210
    public function failPublication($topicName, $error, $requestId = 1)
211
    {
212
        if (!isset($this->publications[$topicName])) {
213
            throw new UnknownTopicException($topicName);
214
        }
215
216
        $futureResult = $this->publications[$topicName];
217
        $result = new ErrorMessage($error, $requestId, new \stdClass(), $topicName);
218
219
        $futureResult->reject($result);
220
    }
221
222
    /**
223
     * Register.
224
     *
225
     * @param string      $procedureName
226
     * @param callable    $callback
227
     * @param array|mixed $options
228
     *
229
     * @return PromiseAdapter
230
     */
231 View Code Duplication
    public function register($procedureName, callable $callback, $options = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
232
    {
233
        $this->procedures[$procedureName] = $callback;
234
235
        $futureResult = new Deferred();
236
237
        $this->registrations[$procedureName] = $futureResult;
238
        $this->registering[$procedureName] = new RegisterMessage(
239
            count($this->registering),
240
            $options,
241
            $procedureName
242
        );
243
244
        return $this->createPromiseAdapter(
245
            $futureResult->promise()
0 ignored issues
show
Compatibility introduced by
$futureResult->promise() of type object<React\Promise\PromiseInterface> is not a sub-type of object<React\Promise\Promise>. It seems like you assume a concrete implementation of the interface React\Promise\PromiseInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
246
        );
247
    }
248
249
    /**
250
     * Trigger a REGISTERED message for given procedure.
251
     *
252
     * @param string $procedureName
253
     * @param int    $requestId
254
     * @param int    $registrationId
255
     *
256
     * @throws UnknownProcedureException if the procedure is unknown
257
     */
258 View Code Duplication
    public function confirmRegistration($procedureName, $requestId = 1, $registrationId = 1)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
259
    {
260
        if (!isset($this->registrations[$procedureName])) {
261
            throw new UnknownProcedureException($procedureName);
262
        }
263
264
        $futureResult = $this->registrations[$procedureName];
265
        $result = new RegisteredMessage($requestId, $registrationId);
266
267
        $futureResult->resolve($result);
268
    }
269
270
    /**
271
     * Triggers a call to a registered procedure and returns its result.
272
     *
273
     * @param string $procedureName
274
     * @param array  $args
275
     *
276
     * @throws UnknownProcedureException if the procedure is unknown
277
     *
278
     * @return mixed the procedure result
279
     */
280
    public function callRegistration($procedureName, array $args = [])
281
    {
282
        if (!isset($this->procedures[$procedureName])) {
283
            throw new UnknownProcedureException($procedureName);
284
        }
285
286
        $procedure = $this->procedures[$procedureName];
287
288
        return $procedure($args);
289
    }
290
291
    /**
292
     * Unregister.
293
     *
294
     * @param string $procedureName
295
     *
296
     * @return PromiseAdapter
297
     */
298
    public function unregister($procedureName)
299
    {
300
        $futureResult = new Deferred();
301
302
        $this->unregistrations[$procedureName] = $futureResult;
303
304
        return $this->createPromiseAdapter(
305
            $futureResult->promise()
0 ignored issues
show
Compatibility introduced by
$futureResult->promise() of type object<React\Promise\PromiseInterface> is not a sub-type of object<React\Promise\Promise>. It seems like you assume a concrete implementation of the interface React\Promise\PromiseInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
306
        );
307
    }
308
309
    /**
310
     * Triggers a UNREGISTERED message for given procedure.
311
     *
312
     * @param string $procedureName
313
     * @param int    $requestId
314
     *
315
     * @throws UnknownProcedureException
316
     */
317 View Code Duplication
    public function confirmUnregistration($procedureName, $requestId = 1)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
318
    {
319
        if (!isset($this->unregistrations[$procedureName])) {
320
            throw new UnknownProcedureException($procedureName);
321
        }
322
323
        $futureResult = $this->unregistrations[$procedureName];
324
        $result = new UnregisteredMessage($requestId);
325
326
        $futureResult->resolve($result);
327
    }
328
329
    /**
330
     * Call.
331
     *
332
     * @param string      $procedureName
333
     * @param array|mixed $arguments
334
     * @param array|mixed $argumentsKw
335
     * @param array|mixed $options
336
     *
337
     * @return PromiseAdapter
338
     */
339 View Code Duplication
    public function call($procedureName, $arguments = null, $argumentsKw = null, $options = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
340
    {
341
        $futureResult = new Deferred();
342
343
        $this->calls[$procedureName] = $futureResult;
344
        $this->calling[$procedureName] = new CallMessage(
345
            count($this->calling),
346
            $options,
347
            $procedureName,
348
            $arguments,
349
            $argumentsKw
350
        );
351
352
        return $this->createPromiseAdapter(
353
            $futureResult->promise()
0 ignored issues
show
Compatibility introduced by
$futureResult->promise() of type object<React\Promise\PromiseInterface> is not a sub-type of object<React\Promise\Promise>. It seems like you assume a concrete implementation of the interface React\Promise\PromiseInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
354
        );
355
    }
356
357
    /**
358
     * Process ResultMessage.
359
     *
360
     * @param string $procedureName
361
     * @param mixed  $result
362
     */
363
    public function respondToCall($procedureName, $result)
364
    {
365
        if (!isset($this->calls[$procedureName])) {
366
            throw new UnknownProcedureException($procedureName);
367
        }
368
369
        /* @var $futureResult Deferred */
370
        $futureResult = $this->calls[$procedureName];
371
372
        $futureResult->resolve($result);
373
    }
374
375
    /**
376
     * @param string $procedureName
377
     * @param mixed  $error
378
     */
379
    public function failCall($procedureName, $error)
380
    {
381
        if (!isset($this->calls[$procedureName])) {
382
            throw new UnknownProcedureException($procedureName);
383
        }
384
385
        /* @var $futureResult Deferred */
386
        $futureResult = $this->calls[$procedureName];
387
388
        $futureResult->reject($error);
389
    }
390
391
    /**
392
     * @param string $procedureName
393
     *
394
     * @return bool
395
     */
396
    public function hasCall($procedureName)
397
    {
398
        return isset($this->calls[$procedureName]);
399
    }
400
401
    /**
402
     * @param int $sessionId
403
     */
404
    public function setSessionId($sessionId)
405
    {
406
        $this->sessionId = $sessionId;
407
    }
408
409
    /**
410
     * @return int the Session Id
411
     */
412
    public function getSessionId()
413
    {
414
        return $this->sessionId;
415
    }
416
417
    /**
418
     * Generate a unique id for sessions and requests.
419
     *
420
     * @return mixed
421
     */
422
    public static function getUniqueId()
423
    {
424
        $filter = 0x1fffffffffffff; // 53 bits
425
        $randomBytes = openssl_random_pseudo_bytes(8);
426
        list($high, $low) = array_values(unpack('N2', $randomBytes));
427
428
        return abs(($high << 32 | $low) & $filter);
429
    }
430
431
    /**
432
     * @param $msg
433
     *
434
     * @return mixed
435
     */
436
    public function sendMessage($msg)
437
    {
438
        return $msg;
439
    }
440
441
    /**
442
     * @param Promise $promise
443
     *
444
     * @return PromiseAdapter
445
     */
446
    private function createPromiseAdapter(Promise $promise)
447
    {
448
        return new PromiseAdapter($promise);
449
    }
450
}
451