Completed
Push — master ( 513769...fc6b51 )
by Camilo
02:35
created

Parameters::setCredentials()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 18
ccs 12
cts 12
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 11
nc 4
nop 2
crap 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace unreal4u\MQTT\Protocol\Connect;
6
7
use Psr\Log\LoggerInterface;
8
use unreal4u\Dummy\Logger;
9
use unreal4u\MQTT\DataTypes\BrokerPort;
10
use unreal4u\MQTT\DataTypes\ClientId;
11
use unreal4u\MQTT\DataTypes\Message;
12
use unreal4u\MQTT\DataTypes\ProtocolVersion;
13
14
/**
15
 * Special connection parameters will be defined in this class
16
 */
17
final class Parameters
18
{
19
    /**
20
     * The default protocol version this library will be talking with
21
     */
22
    const DEFAULT_PROTOCOL_VERSION = '3.1.1';
23
24
    /**
25
     * @var LoggerInterface
26
     */
27
    private $logger;
28
29
    /**
30
     * The host we'll be connecting to
31
     *
32
     * @var string
33
     */
34
    private $host;
35
36
    /**
37
     * The port we will connect to
38
     * @var BrokerPort
39
     */
40
    private $brokerPort;
41
42
    /**
43
     * Unique (per broker) client Id. Can be empty if $cleanSession is set to true.
44
     *
45
     * @var ClientId
46
     */
47
    private $clientId = '';
48
49
    /**
50
     * The keep alive is a time interval in seconds (defaults to 60), the clients commits to by sending regular PING
51
     * Request messages to the broker.
52
     *
53
     * The broker response with PING Response and this mechanism will allow both sides to determine if the other one is
54
     * still alive and reachable.
55
     *
56
     * @var int
57
     */
58
    private $keepAlivePeriod = 60;
59
60
    /**
61
     * Whether to create a persistent session (default = false).
62
     *
63
     * It means that the broker will store all subscriptions for the client and also all missed messages, when
64
     * subscribing with Quality of Service (QoS) 1 or 2
65
     * @var bool
66
     */
67
    private $cleanSession = false;
68
69
    /**
70
     * The corresponding field for the username flag
71
     * @var string
72
     */
73
    private $username = '';
74
75
    /**
76
     * The corresponding field for the password flag
77
     * @var string
78
     */
79
    private $password = '';
80
81
    /**
82
     * @var Message
83
     */
84
    private $will;
85
86
    /**
87
     * @var ProtocolVersion
88
     */
89
    private $protocolVersion;
90
91
    /**
92
     * The 10th byte of the Connect call will contain a series of flags
93
     *
94
     * The order of these flags are:
95
     *
96
     *   7-6-5-4-3-2-1-0
97
     * b'0-0-0-0-0-0-0-0'
98
     *
99
     * Where
100
     * Bit 7: if username is set, this bit is true
101
     * Bit 6: if password is set, this bit is true
102
     * Bit 5: This bit specifies if the Will Message is to be Retained when it is published
103
     * Bits 4 & 3: These two bits specify the QoS level to be used when publishing the Will Message
104
     * Bit 2: If the Will Flag is set to 1 this indicates that, if the Connect request is accepted, a Will Message MUST
105
     *        be stored on the Server and associated with the Network Connection
106
     * Bit 1: This bit specifies the handling of the Session state
107
     * Bit 0: Reserved
108
     *
109
     * @see http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/errata01/os/mqtt-v3.1.1-errata01-os-complete.html#_Toc442180843
110
     * @var string
111
     */
112
    private $bitFlag = b'00000000';
113
114
    /**
115
     * Builds up the connection parameters
116
     *
117
     * @param ClientId $clientId Will default to a clientId set by the broker
118
     * @param string $host Will default to localhost
119
     * @param LoggerInterface $logger
120
     * @throws \unreal4u\MQTT\Exceptions\InvalidBrokerPort
121
     * @throws \unreal4u\MQTT\Exceptions\Connect\UnacceptableProtocolVersion
122
     */
123 20
    public function __construct(ClientId $clientId = null, string $host = 'localhost', LoggerInterface $logger = null)
124
    {
125 20
        if ($logger === null) {
126 20
            $logger = new Logger();
127
        }
128
        // Insert name of class within the logger
129 20
        $this->logger = $logger->withName(str_replace('unreal4u\\MQTT\\', '', \get_class($this)));
0 ignored issues
show
Bug introduced by
The method withName() does not exist on Psr\Log\LoggerInterface. It seems like you code against a sub-type of Psr\Log\LoggerInterface such as unreal4u\Dummy\Logger or Monolog\Logger. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

129
        /** @scrutinizer ignore-call */ 
130
        $this->logger = $logger->withName(str_replace('unreal4u\\MQTT\\', '', \get_class($this)));
Loading history...
130
131
        // Once we have a logger, set the clientId
132 20
        if ($clientId === null) {
133 6
            $clientId = new ClientId('');
134
        }
135 20
        $this->setClientId($clientId);
136 20
        $this->setProtocolVersion(new ProtocolVersion(self::DEFAULT_PROTOCOL_VERSION));
137
        // Set 1883 as the default port
138 20
        $this->setBrokerPort(new BrokerPort(1883));
139
140 20
        $this->host = $host;
141 20
    }
142
143
    /**
144
     * Use this function to change the default broker port
145
     *
146
     * @param BrokerPort $brokerPort
147
     * @return Parameters
148
     */
149 20
    public function setBrokerPort(BrokerPort $brokerPort): self
150
    {
151 20
        $this->brokerPort = $brokerPort;
152 20
        return $this;
153
    }
154
155 20
    public function setProtocolVersion(ProtocolVersion $protocolVersion): self
156
    {
157 20
        $this->protocolVersion = $protocolVersion;
158 20
        return $this;
159
    }
160
161 2
    public function getProtocolVersionBinaryRepresentation(): string
162
    {
163 2
        return $this->protocolVersion->getProtocolVersionBinaryRepresentation();
164
    }
165
166
    /**
167
     * Handles everything related to setting the ClientId
168
     *
169
     * @param ClientId $clientId
170
     * @return Parameters
171
     */
172 20
    public function setClientId(ClientId $clientId): self
173
    {
174 20
        $this->clientId = $clientId;
175 20
        $this->logger->debug('Set clientId', ['actualClientString' => (string)$clientId]);
176 20
        if ($this->clientId->isEmptyClientId()) {
177 6
            $this->logger->debug('Empty clientId detected, forcing clean session bit to true');
178 6
            $this->setCleanSession(true);
179
        }
180
181 20
        return $this;
182
    }
183
184 4
    public function getClientId(): ClientId
185
    {
186 4
        return $this->clientId;
187
    }
188
189
    /**
190
     * Returns the connection string
191
     *
192
     * @TODO Currently only TCP connections supported, SSL will come
193
     *
194
     * @return string
195
     */
196 3
    public function getConnectionUrl(): string
197
    {
198 3
        return 'tcp://' . $this->host . ':' . $this->brokerPort->getBrokerPort();
199
    }
200
201
    /**
202
     * Returns the set of flags we are making the connection with
203
     *
204
     * @return int
205
     */
206 12
    public function getFlags(): int
207
    {
208 12
        return (int)$this->bitFlag;
209
    }
210
211
    /**
212
     * Keep alive period is measured in positive seconds. The maximum is 18h, 12m and 15s, equivalent to 65535 seconds
213
     *
214
     * @param int $keepAlivePeriod
215
     * @return Parameters
216
     * @throws \InvalidArgumentException
217
     */
218 2
    public function setKeepAlivePeriod(int $keepAlivePeriod): self
219
    {
220 2
        if ($keepAlivePeriod > 65535 || $keepAlivePeriod < 0) {
221 1
            $this->logger->error('Keep alive period must be between 0 and 65535');
222 1
            throw new \InvalidArgumentException('Keep alive period must be between 0 and 65535');
223
        }
224
225 1
        $this->keepAlivePeriod = $keepAlivePeriod;
226 1
        return $this;
227
    }
228
229
    /**
230
     * Sets the 6th and 7th bit of the connect flag
231
     *
232
     * @param string $username
233
     * @param string $password
234
     * @return Parameters
235
     */
236 4
    public function setCredentials(string $username, string $password): self
237
    {
238 4
        $this->bitFlag &= ~64;
239 4
        $this->bitFlag &= ~128;
240
241 4
        if ($username !== '') {
242 3
            $this->logger->debug('Username set, setting username flag');
243 3
            $this->bitFlag |= 128;
244 3
            $this->username = $username;
245
        }
246
247 4
        if ($password !== '') {
248 4
            $this->logger->debug('Password set, setting password flag');
249 4
            $this->bitFlag |= 64;
250 4
            $this->password = $password;
251
        }
252
253 4
        return $this;
254
    }
255
256
    /**
257
     * Sets the 5th bit of the connect flag
258
     *
259
     * @see http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc385349230
260
     * @param bool $willRetain
261
     * @return Parameters
262
     */
263 6
    private function setWillRetainBit(bool $willRetain): self
264
    {
265 6
        $this->bitFlag &= ~32;
266 6
        if ($willRetain === true) {
267 1
            $this->logger->debug('Setting will retain flag');
268 1
            $this->bitFlag |= 32;
269
        }
270 6
        return $this;
271
    }
272
273
    /**
274
     * Determines and sets the 3rd and 4th bits of the connect flag
275
     *
276
     * @see http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc385349230
277
     * @param int $QoSLevel
278
     * @return Parameters
279
     */
280 6
    private function setWillQoSLevelBit(int $QoSLevel): self
281
    {
282
        // Reset first the will QoS bits and proceed to set them
283 6
        $this->bitFlag &= ~8; // Third bit: 8
284 6
        $this->bitFlag &= ~16; // Fourth bit: 16
285
286 6
        if ($QoSLevel !== 0) {
287 2
            $this->logger->debug(sprintf(
288 2
                    'Setting will QoS level %d flag (bit %d)',
289 2
                    $QoSLevel,
290 2
                    $QoSLevel * 8)
291
            );
292 2
            $this->bitFlag |= $QoSLevel * 8;
293
        }
294
295 6
        return $this;
296
    }
297
298
    /**
299
     * Sets the given will. Will also set the 2nd bit of the connect flags if a message is provided
300
     *
301
     * @see http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc385349230
302
     * @param Message $message
303
     * @return Parameters
304
     * @throws \unreal4u\MQTT\Exceptions\InvalidQoSLevel
305
     * @throws \unreal4u\MQTT\Exceptions\MissingTopicName
306
     * @throws \unreal4u\MQTT\Exceptions\MessageTooBig
307
     */
308 6
    public function setWill(Message $message): self
309
    {
310
        // Proceed only if we have a valid message
311 6
        $this->bitFlag &= ~4;
312 6
        if ($message->getTopicName() !== '') {
313 6
            $this->logger->debug('Setting will flag');
314 6
            $this->bitFlag |= 4;
315
        }
316
317 6
        $this->will = $message;
318
        $this
319 6
            ->setWillRetainBit($message->isRetained())
320 6
            ->setWillQoSLevelBit($message->getQoSLevel());
321
322 6
        return $this;
323
    }
324
325
    /**
326
     * Sets the 1st bit of the connect flags
327
     *
328
     * @param bool $cleanSession
329
     * @return Parameters
330
     */
331 8
    public function setCleanSession(bool $cleanSession): self
332
    {
333 8
        $this->bitFlag &= ~2;
334 8
        if ($cleanSession === true) {
335 8
            $this->logger->debug('Clean session flag set');
336 8
            $this->bitFlag |= 2;
337
        }
338 8
        $this->cleanSession = $cleanSession;
339 8
        return $this;
340
    }
341
342
    /**
343
     * @return int
344
     */
345 3
    public function getKeepAlivePeriod(): int
346
    {
347 3
        return $this->keepAlivePeriod;
348
    }
349
350
    /**
351
     * @return bool
352
     */
353 2
    public function getCleanSession(): bool
354
    {
355 2
        return $this->cleanSession;
356
    }
357
358
    /**
359
     * @return string
360
     */
361 4
    public function getUsername(): string
362
    {
363 4
        return $this->username;
364
    }
365
366
    /**
367
     * @return string
368
     */
369 4
    public function getPassword(): string
370
    {
371 4
        return $this->password;
372
    }
373
374
    /**
375
     * @return string
376
     */
377 3
    public function getWillTopic(): string
378
    {
379 3
        if ($this->will === null) {
380 2
            return '';
381
        }
382
383 1
        return $this->will->getTopicName();
384
    }
385
386
    /**
387
     * @return string
388
     */
389 3
    public function getWillMessage(): string
390
    {
391 3
        if ($this->will === null) {
392 2
            return '';
393
        }
394
395 1
        return $this->will->getPayload();
396
    }
397
398
    /**
399
     * @return bool
400
     */
401 2
    public function getWillRetain(): bool
402
    {
403 2
        return $this->will->isRetained();
404
    }
405
}
406