Passed
Push — master ( d5b9c5...238a05 )
by Timo
26s
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 Tidal\WampWatch\Adapter\React\PromiseAdapter;
30
use Tidal\WampWatch\Adapter\React\DeferredAdapter;
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
        $this->subscriptions[$topicName] = static::createDeferredAdapter();
0 ignored issues
show
Bug introduced by
Since createDeferredAdapter() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of createDeferredAdapter() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
116
        $this->subscribing[$topicName] = new SubscribeMessage(
117
            count($this->subscriptions),
118
            (object) $options,
119
            $topicName
120
        );
121
122
        return $this->subscriptions[$topicName]->promise();
123
    }
124
125
    /**
126
     * Trigger a SUBSCRIBED message for given topic.
127
     *
128
     * @param $topicName
129
     * @param $requestId
130
     * @param $subscriptionId
131
     *
132
     * @throws UnknownTopicException if the topic is unknown
133
     */
134 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...
135
    {
136
        if (!isset($this->subscriptions[$topicName])) {
137
            throw new UnknownTopicException($topicName);
138
        }
139
140
        /* @var $futureResult Deferred */
141
        $futureResult = $this->subscriptions[$topicName];
142
        $result = new SubscribedMessage($requestId, $subscriptionId);
143
144
        $futureResult->resolve($result);
145
    }
146
147
    public function hasSubscription($topicName)
148
    {
149
        return isset($this->subscriptions[$topicName]);
150
    }
151
152
    /**
153
     * Publish.
154
     *
155
     * @param string      $topicName
156
     * @param array|mixed $arguments
157
     * @param array|mixed $argumentsKw
158
     * @param array|mixed $options
159
     *
160
     * @return PromiseAdapter
161
     */
162 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...
163
    {
164
        $this->publications[$topicName] = static::createDeferredAdapter();
0 ignored issues
show
Bug introduced by
Since createDeferredAdapter() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of createDeferredAdapter() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
165
        $this->publishing[$topicName] = new PublishMessage(
166
            count($this->publishing),
167
            $options,
168
            $topicName,
169
            $arguments,
170
            $argumentsKw
171
        );
172
173
        return $this->publications[$topicName]->promise();
174
    }
175
176
    /**
177
     * Trigger a PUBLISHED message for given topic.
178
     *
179
     * @param string $topicName
180
     * @param int    $requestId
181
     * @param int    $publicationId
182
     *
183
     * @throws UnknownTopicException if the topic is unknown
184
     */
185 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...
186
    {
187
        if (!isset($this->publications[$topicName])) {
188
            throw new UnknownTopicException($topicName);
189
        }
190
191
        $futureResult = $this->publications[$topicName];
192
        $result = new PublishedMessage($requestId, $publicationId);
193
194
        $futureResult->resolve($result);
195
    }
196
197
    /**
198
     * @param string $topicName
199
     * @param mixed  $error
200
     * @param int    $requestId
201
     */
202
    public function failPublication($topicName, $error, $requestId = 1)
203
    {
204
        if (!isset($this->publications[$topicName])) {
205
            throw new UnknownTopicException($topicName);
206
        }
207
208
        $futureResult = $this->publications[$topicName];
209
        $result = new ErrorMessage($error, $requestId, new \stdClass(), $topicName);
210
211
        $futureResult->reject($result);
212
    }
213
214
    /**
215
     * Register.
216
     *
217
     * @param string      $procedureName
218
     * @param callable    $callback
219
     * @param array|mixed $options
220
     *
221
     * @return PromiseAdapter
222
     */
223 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...
224
    {
225
        $this->procedures[$procedureName] = $callback;
226
227
        $this->registrations[$procedureName] = static::createDeferredAdapter();
0 ignored issues
show
Bug introduced by
Since createDeferredAdapter() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of createDeferredAdapter() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
228
        $this->registering[$procedureName] = new RegisterMessage(
229
            count($this->registering),
230
            $options,
231
            $procedureName
232
        );
233
234
        return $this->registrations[$procedureName]->promise();
235
    }
236
237
    /**
238
     * Trigger a REGISTERED message for given procedure.
239
     *
240
     * @param string $procedureName
241
     * @param int    $requestId
242
     * @param int    $registrationId
243
     *
244
     * @throws UnknownProcedureException if the procedure is unknown
245
     */
246 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...
247
    {
248
        if (!isset($this->registrations[$procedureName])) {
249
            throw new UnknownProcedureException($procedureName);
250
        }
251
252
        $futureResult = $this->registrations[$procedureName];
253
        $result = new RegisteredMessage($requestId, $registrationId);
254
255
        $futureResult->resolve($result);
256
    }
257
258
    /**
259
     * Triggers a call to a registered procedure and returns its result.
260
     *
261
     * @param string $procedureName
262
     * @param array  $args
263
     *
264
     * @throws UnknownProcedureException if the procedure is unknown
265
     *
266
     * @return mixed the procedure result
267
     */
268
    public function callRegistration($procedureName, array $args = [])
269
    {
270
        if (!isset($this->procedures[$procedureName])) {
271
            throw new UnknownProcedureException($procedureName);
272
        }
273
274
        $procedure = $this->procedures[$procedureName];
275
276
        return $procedure($args);
277
    }
278
279
    /**
280
     * Unregister.
281
     *
282
     * @param string $procedureName
283
     *
284
     * @return PromiseAdapter
285
     */
286
    public function unregister($procedureName)
287
    {
288
        $this->unregistrations[$procedureName] = static::createDeferredAdapter();
0 ignored issues
show
Bug introduced by
Since createDeferredAdapter() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of createDeferredAdapter() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
289
290
        return $this->unregistrations[$procedureName]->promise();
291
    }
292
293
    /**
294
     * Triggers a UNREGISTERED message for given procedure.
295
     *
296
     * @param string $procedureName
297
     * @param int    $requestId
298
     *
299
     * @throws UnknownProcedureException
300
     */
301 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...
302
    {
303
        if (!isset($this->unregistrations[$procedureName])) {
304
            throw new UnknownProcedureException($procedureName);
305
        }
306
307
        $futureResult = $this->unregistrations[$procedureName];
308
        $result = new UnregisteredMessage($requestId);
309
310
        $futureResult->resolve($result);
311
    }
312
313
    /**
314
     * Call.
315
     *
316
     * @param string      $procedureName
317
     * @param array|mixed $arguments
318
     * @param array|mixed $argumentsKw
319
     * @param array|mixed $options
320
     *
321
     * @return PromiseAdapter
322
     */
323 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...
324
    {
325
        $this->calls[$procedureName] = static::createDeferredAdapter();
0 ignored issues
show
Bug introduced by
Since createDeferredAdapter() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of createDeferredAdapter() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
326
        $this->calling[$procedureName] = new CallMessage(
327
            count($this->calling),
328
            $options,
329
            $procedureName,
330
            $arguments,
331
            $argumentsKw
332
        );
333
334
        return $this->calls[$procedureName]->promise();
335
    }
336
337
    /**
338
     * Process ResultMessage.
339
     *
340
     * @param string $procedureName
341
     * @param mixed  $result
342
     */
343
    public function respondToCall($procedureName, $result)
344
    {
345
        if (!isset($this->calls[$procedureName])) {
346
            throw new UnknownProcedureException($procedureName);
347
        }
348
349
        /* @var $futureResult Deferred */
350
        $futureResult = $this->calls[$procedureName];
351
352
        $futureResult->resolve($result);
353
    }
354
355
    /**
356
     * @param string $procedureName
357
     * @param mixed  $error
358
     */
359
    public function failCall($procedureName, $error)
360
    {
361
        if (!isset($this->calls[$procedureName])) {
362
            throw new UnknownProcedureException($procedureName);
363
        }
364
365
        /* @var $futureResult Deferred */
366
        $futureResult = $this->calls[$procedureName];
367
368
        $futureResult->reject($error);
369
    }
370
371
    /**
372
     * @param string $procedureName
373
     *
374
     * @return bool
375
     */
376
    public function hasCall($procedureName)
377
    {
378
        return isset($this->calls[$procedureName]);
379
    }
380
381
    /**
382
     * @param int $sessionId
383
     */
384
    public function setSessionId($sessionId)
385
    {
386
        $this->sessionId = $sessionId;
387
    }
388
389
    /**
390
     * @return int the Session Id
391
     */
392
    public function getSessionId()
393
    {
394
        return $this->sessionId;
395
    }
396
397
    /**
398
     * Generate a unique id for sessions and requests.
399
     *
400
     * @return mixed
401
     */
402
    public static function getUniqueId()
403
    {
404
        $filter = 0x1fffffffffffff; // 53 bits
405
        $randomBytes = openssl_random_pseudo_bytes(8);
406
        list($high, $low) = array_values(unpack('N2', $randomBytes));
407
408
        return abs(($high << 32 | $low) & $filter);
409
    }
410
411
    /**
412
     * @param $msg
413
     *
414
     * @return mixed
415
     */
416
    public function sendMessage($msg)
417
    {
418
        return $msg;
419
    }
420
421
    /**
422
     * @param callable $canceller
423
     *
424
     * @return DeferredAdapter
425
     */
426
    private static function createDeferredAdapter(callable $canceller = null)
427
    {
428
        return new DeferredAdapter(new Deferred($canceller));
429
    }
430
}
431