Completed
Push — master ( f55639...d36af8 )
by Camilo
02:28
created

Connect::setConnectionParameters()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace unreal4u\MQTT\Protocol;
6
7
use unreal4u\MQTT\Exceptions\Connect\IdentifierRejected;
8
use unreal4u\MQTT\Exceptions\Connect\NoConnectionParametersDefined;
9
use unreal4u\MQTT\Exceptions\MustProvideUsername;
10
use unreal4u\MQTT\Internals\ClientInterface;
11
use unreal4u\MQTT\Internals\EventManager;
12
use unreal4u\MQTT\Internals\ProtocolBase;
13
use unreal4u\MQTT\Internals\ReadableContentInterface;
14
use unreal4u\MQTT\Internals\WritableContent;
15
use unreal4u\MQTT\Internals\WritableContentInterface;
16
use unreal4u\MQTT\Protocol\Connect\Parameters;
17
use unreal4u\MQTT\Utilities;
18
19
/**
20
 * After a Network Connection is established by a Client to a Server, the first Packet sent from the Client to the
21
 * Server MUST be a CONNECT Packet
22
 */
23
final class Connect extends ProtocolBase implements WritableContentInterface
24
{
25
    use WritableContent;
26
27
    const CONTROL_PACKET_VALUE = 1;
28
29
    /**
30
     * @var Parameters
31
     */
32
    private $connectionParameters;
33
34
    /**
35
     * Saves the mandatory connection parameters onto this object
36
     * @param Parameters $connectionParameters
37
     *
38
     * @return Connect
39
     */
40 5
    public function setConnectionParameters(Parameters $connectionParameters): self
41
    {
42 5
        $this->connectionParameters = $connectionParameters;
43 5
        return $this;
44
    }
45
46
    /**
47
     * Get the connection parameters from the private object
48
     *
49
     * @return Parameters
50
     * @throws \unreal4u\MQTT\Exceptions\Connect\NoConnectionParametersDefined
51
     */
52 2
    public function getConnectionParameters(): Parameters
53
    {
54 2
        if ($this->connectionParameters === null) {
55 1
            throw new NoConnectionParametersDefined('You must pass on the connection parameters before connecting');
56
        }
57
58 1
        return $this->connectionParameters;
59
    }
60
61
    /**
62
     * @return string
63
     * @throws \OutOfRangeException
64
     */
65 2
    public function createVariableHeader(): string
66
    {
67 2
        $bitString = $this->createUTF8String('MQTT'); // Connect MUST begin with MQTT
68 2
        $bitString .= $this->connectionParameters->getProtocolVersionBinaryRepresentation(); // Protocol level
69 2
        $bitString .= \chr($this->connectionParameters->getFlags());
70 2
        $bitString .= Utilities::convertNumberToBinaryString($this->connectionParameters->getKeepAlivePeriod());
71 2
        return $bitString;
72
    }
73
74
    /**
75
     * @return string
76
     * @throws \unreal4u\MQTT\Exceptions\MustProvideUsername
77
     * @throws \OutOfRangeException
78
     */
79 3
    public function createPayload(): string
80
    {
81
        // The order in a connect string is clientId first
82 3
        $output = $this->createUTF8String((string)$this->connectionParameters->getClientId());
83
84
        // Then the willTopic if it is set
85 3
        $output .= $this->createUTF8String($this->connectionParameters->getWillTopic());
86
87
        // The willMessage will come next
88 3
        $output .= $this->createUTF8String($this->connectionParameters->getWillMessage());
89
90
        // If the username is set, it will come next
91 3
        $output .= $this->createUTF8String($this->connectionParameters->getUsername());
92
93
        // And finally the password as last parameter
94 3
        if ($this->connectionParameters->getPassword() !== '') {
95 2
            if ($this->connectionParameters->getUsername() === '') {
96 1
                throw new MustProvideUsername('A password can not be set without a username! Please set username');
97
            }
98 1
            $output .= $this->createUTF8String($this->connectionParameters->getPassword());
99
        }
100
101 2
        return $output;
102
    }
103
104 1
    public function shouldExpectAnswer(): bool
105
    {
106 1
        return true;
107
    }
108
109
    /**
110
     * Special handling of the ConnAck object: be able to inject more information into the object before throwing it
111
     *
112
     * @param string $brokerBitStream
113
     * @param ClientInterface $client
114
     *
115
     * @return ReadableContentInterface
116
     * @throws \DomainException
117
     * @throws \unreal4u\MQTT\Exceptions\Connect\IdentifierRejected
118
     */
119 1
    public function expectAnswer(string $brokerBitStream, ClientInterface $client): ReadableContentInterface
120
    {
121 1
        $this->logger->info('String of incoming data confirmed, returning new object', ['callee' => \get_class($this)]);
122
123 1
        $eventManager = new EventManager($this->logger);
124
        try {
125 1
            $connAck = $eventManager->analyzeHeaders($brokerBitStream, $client);
126
        } catch (IdentifierRejected $e) {
127
            $possibleReasons = '';
128
            foreach ($this->connectionParameters->getClientId()->performStrictValidationCheck() as $errorMessage) {
129
                $possibleReasons .= $errorMessage . PHP_EOL;
130
            }
131
132
            $e->fillPossibleReason($possibleReasons);
133
            // Re-throw the exception with all information filled in
134
            throw $e;
135
        }
136
137 1
        return $connAck;
138
    }
139
}
140