Completed
Push — master ( dac7df...b079db )
by Daniel
03:09
created

Client::alive()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 6

Duplication

Lines 11
Ratio 100 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 11
loc 11
ccs 0
cts 6
cp 0
rs 9.4285
cc 1
eloc 6
nc 1
nop 1
crap 2
1
<?php
2
/**
3
 * This file is part of the Ssdp project.
4
 *
5
 * @author Daniel Schröder <[email protected]>
6
 */
7
8
namespace GravityMedia\Ssdp;
9
10
use Clue\React\Multicast\Factory as MulticastFactory;
11
use GravityMedia\Ssdp\Options\AliveOptions;
12
use GravityMedia\Ssdp\Options\ByebyeOptions;
13
use GravityMedia\Ssdp\Options\DiscoverOptions;
14
use GravityMedia\Ssdp\Options\UpdateOptions;
15
use GravityMedia\Ssdp\Request\Factory\AliveFactory;
16
use GravityMedia\Ssdp\Request\Factory\ByebyeFactory;
17
use GravityMedia\Ssdp\Request\Factory\DiscoverFactory;
18
use GravityMedia\Ssdp\Request\Factory\UpdateFactory;
19
use React\EventLoop\LoopInterface;
20
use React\Promise\Deferred;
21
use React\Promise\PromiseInterface;
22
use Zend\Diactoros\Request\Serializer as RequestSerializer;
23
use Zend\Diactoros\Response\Serializer as ResponseSerializer;
24
use Zend\Diactoros\Uri;
25
26
/**
27
 * Ssdp client class
28
 *
29
 * @package GravityMedia\Ssdp
30
 */
31
class Client
32
{
33
    /**
34
     * The multicast address
35
     */
36
    const MULTICAST_ADDRESS = '239.255.255.250';
37
38
    /**
39
     * The multicast port
40
     */
41
    const MULTICAST_PORT = 1900;
42
43
    /**
44
     * @var LoopInterface
45
     */
46
    private $loop;
47
48
    /**
49
     * @var MulticastFactory
50
     */
51
    private $multicastFactory;
52
53
    /**
54
     * @var AliveFactory
55
     */
56
    protected $aliveRequestFactory;
57
58
    /**
59
     * @var ByebyeFactory
60
     */
61
    protected $byebyeRequestFactory;
62
63
    /**
64
     * @var DiscoverFactory
65
     */
66
    protected $discoverRequestFactory;
67
68
    /**
69
     * @var UpdateFactory
70
     */
71
    protected $updateRequestFactory;
72
73
    /**
74
     * Create client object
75
     *
76
     * @param LoopInterface $loop
77
     */
78 4
    public function __construct(LoopInterface $loop)
79
    {
80 4
        $this->loop = $loop;
81 4
    }
82
83
    /**
84
     * Get multicast factory
85
     *
86
     * @return MulticastFactory
87
     */
88 4
    public function getMulticastFactory()
89
    {
90 4
        if (null === $this->multicastFactory) {
91 2
            $this->multicastFactory = new MulticastFactory($this->loop);
92 1
        }
93
94 4
        return $this->multicastFactory;
95
    }
96
97
    /**
98
     * Set multicast factory
99
     *
100
     * @param MulticastFactory $multicastFactory
101
     *
102
     * @return $this
103
     */
104 2
    public function setMulticastFactory(MulticastFactory $multicastFactory)
105
    {
106 2
        $this->multicastFactory = $multicastFactory;
107 2
        return $this;
108
    }
109
110
    /**
111
     * Get alive request factory
112
     *
113
     * @return AliveFactory
114
     */
115
    public function getAliveRequestFactory()
116
    {
117
        if (null === $this->aliveRequestFactory) {
118
            $this->aliveRequestFactory = new AliveFactory();
119
        }
120
121
        return $this->aliveRequestFactory;
122
    }
123
124
    /**
125
     * Get byebye request factory
126
     *
127
     * @return ByebyeFactory
128
     */
129
    public function getByebyeRequestFactory()
130
    {
131
        if (null === $this->byebyeRequestFactory) {
132
            $this->byebyeRequestFactory = new ByebyeFactory();
133
        }
134
135
        return $this->byebyeRequestFactory;
136
    }
137
138
    /**
139
     * Get discover request factory
140
     *
141
     * @return DiscoverFactory
142
     */
143 4
    protected function getDiscoverRequestFactory()
144
    {
145 4
        if (null === $this->discoverRequestFactory) {
146 4
            $this->discoverRequestFactory = new DiscoverFactory();
147 2
        }
148
149 4
        return $this->discoverRequestFactory;
150
    }
151
152
    /**
153
     * Get update request factory
154
     *
155
     * @return UpdateFactory
156
     */
157
    public function getUpdateRequestFactory()
158
    {
159
        if (null === $this->updateRequestFactory) {
160
            $this->updateRequestFactory = new UpdateFactory();
161
        }
162
163
        return $this->updateRequestFactory;
164
    }
165
166
    /**
167
     * Send alive request
168
     *
169
     * @param AliveOptions $options
170
     *
171
     * @return PromiseInterface
172
     */
173 View Code Duplication
    public function alive(AliveOptions $options)
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...
174
    {
175
        $request = $this->getAliveRequestFactory()->createRequest($options);
176
        $data = trim(RequestSerializer::toString($request)) . "\r\n\r\n";
177
178
        $socket = $this->getMulticastFactory()->createSender();
179
180
        $socket->send($data, sprintf('%s:%s', self::MULTICAST_ADDRESS, self::MULTICAST_PORT));
181
182
        return $this;
183
    }
184
185
    /**
186
     * Send byebye request
187
     *
188
     * @param ByebyeOptions $options
189
     *
190
     * @return PromiseInterface
191
     */
192 View Code Duplication
    public function byebye(ByebyeOptions $options)
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...
193
    {
194
        $request = $this->getByebyeRequestFactory()->createRequest($options);
195
        $data = trim(RequestSerializer::toString($request)) . "\r\n\r\n";
196
197
        $socket = $this->getMulticastFactory()->createSender();
198
199
        $socket->send($data, sprintf('%s:%s', self::MULTICAST_ADDRESS, self::MULTICAST_PORT));
200
201
        return $this;
202
    }
203
204
    /**
205
     * Send discover request
206
     *
207
     * @param DiscoverOptions $options
208
     * @param int $timeout
209
     *
210
     * @return PromiseInterface
211
     */
212 4
    public function discover(DiscoverOptions $options, $timeout = 2)
213
    {
214 4
        $request = $this->getDiscoverRequestFactory()->createRequest($options);
215 4
        $data = trim(RequestSerializer::toString($request)) . "\r\n\r\n";
216
217 4
        $socket = $this->getMulticastFactory()->createSender();
218
219
        $timer = $this->loop->addTimer($timeout, function () use ($socket, &$deferred) {
220 2
            $deferred->resolve();
221 2
            $socket->close();
222 4
        });
223
224
        $deferred = new Deferred(function () use ($socket, &$timer) {
0 ignored issues
show
Bug introduced by
Consider using a different name than the imported variable $deferred, or did you forget to import by reference?

It seems like you are assigning to a variable which was imported through a use statement which was not imported by reference.

For clarity, we suggest to use a different name or import by reference depending on whether you would like to have the change visibile in outer-scope.

Change not visible in outer-scope

$x = 1;
$callable = function() use ($x) {
    $x = 2; // Not visible in outer scope. If you would like this, how
            // about using a different variable name than $x?
};

$callable();
var_dump($x); // integer(1)

Change visible in outer-scope

$x = 1;
$callable = function() use (&$x) {
    $x = 2;
};

$callable();
var_dump($x); // integer(2)
Loading history...
225 2
            $timer->cancel();
226 2
            $socket->close();
227 2
            throw new \RuntimeException('Discovery cancelled.');
228 4
        });
229
230 4
        $socket->on('message', function ($message, $remote) use ($deferred) {
231
            $deferred->notify([
232
                'message' => $this->parseMessage($message),
233
                'remote' => $remote
234
            ]);
235 4
        });
236
237 4
        $socket->send($data, sprintf('%s:%s', self::MULTICAST_ADDRESS, self::MULTICAST_PORT));
238
239 4
        return $deferred->promise();
240
    }
241
242
    /**
243
     * Send update request
244
     *
245
     * @param UpdateOptions $options
246
     *
247
     * @return PromiseInterface
248
     */
249 View Code Duplication
    public function update(UpdateOptions $options)
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...
250
    {
251
        $request = $this->getUpdateRequestFactory()->createRequest($options);
252
        $data = trim(RequestSerializer::toString($request)) . "\r\n\r\n";
253
254
        $socket = $this->getMulticastFactory()->createSender();
255
256
        $socket->send($data, sprintf('%s:%s', self::MULTICAST_ADDRESS, self::MULTICAST_PORT));
257
258
        return $this;
259
    }
260
261
    /**
262
     * Parse message
263
     *
264
     * @param string $message
265
     *
266
     * @return Message
267
     */
268
    protected function parseMessage($message)
269
    {
270
        $response = ResponseSerializer::fromString($message);
271
        $message = new Message();
272
273
        if ($response->hasHeader('CACHE-CONTROL')) {
274
            $value = $response->getHeaderLine('CACHE-CONTROL');
275
            $message->setLifetime(intval(substr($value, strpos($value, '=') + 1)));
276
        }
277
278
        if ($response->hasHeader('DATE')) {
279
            $message->setDate(new \DateTime($response->getHeaderLine('DATE')));
280
        }
281
282
        if ($response->hasHeader('LOCATION')) {
283
            $message->setDescriptionUrl(new Uri($response->getHeaderLine('LOCATION')));
284
        }
285
286
        if ($response->hasHeader('SERVER')) {
287
            $message->setServerString($response->getHeaderLine('SERVER'));
288
        }
289
290
        if ($response->hasHeader('ST')) {
291
            $message->setSearchTargetString($response->getHeaderLine('ST'));
292
        }
293
294
        if ($response->hasHeader('USN')) {
295
            $message->setUniqueServiceNameString($response->getHeaderLine('USN'));
296
        }
297
298
        return $message;
299
    }
300
}
301