Completed
Push — master ( 3865aa...ed1e17 )
by Camilo
02:27
created

Connect::expectAnswer()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 15
ccs 0
cts 8
cp 0
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 8
nc 2
nop 2
crap 6
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->keepAlivePeriod);
71 2
        return $bitString;
72
    }
73
74 3
    public function createPayload(): string
75
    {
76 3
        $output = '';
77
        // The order in a connect string is clientId first
78 3
        if ($this->connectionParameters->getClientId() !== '') {
79 3
            $output .= $this->createUTF8String($this->connectionParameters->getClientId());
80
        }
81
82
        // Then the willTopic if it is set
83 3
        if ($this->connectionParameters->getWillTopic() !== '') {
84 1
            $output .= $this->createUTF8String($this->connectionParameters->getWillTopic());
85
        }
86
87
        // The willMessage will come next
88 3
        if ($this->connectionParameters->getWillMessage() !== '') {
89 1
            $output .= $this->createUTF8String($this->connectionParameters->getWillMessage());
90
        }
91
92
        // If the username is set, it will come next
93 3
        if ($this->connectionParameters->getUsername() !== '') {
94 1
            $output .= $this->createUTF8String($this->connectionParameters->getUsername());
95
        }
96
97
        // And finally the password as last parameter
98 3
        if ($this->connectionParameters->getPassword() !== '') {
99 2
            if ($this->connectionParameters->getUsername() === '') {
100 1
                throw new MustProvideUsername('A password can not be set without a username! Please set username');
101
            }
102 1
            $output .= $this->createUTF8String($this->connectionParameters->getPassword());
103
        }
104
105 2
        return $output;
106
    }
107
108 1
    public function shouldExpectAnswer(): bool
109
    {
110 1
        return true;
111
    }
112
113
    /**
114
     * Special handling of the ConnAck object: be able to inject more information into the object before throwing it
115
     *
116
     * @param string $data
117
     * @param ClientInterface $client
118
     *
119
     * @return ReadableContentInterface
120
     */
121
    public function expectAnswer(string $data, ClientInterface $client): ReadableContentInterface
122
    {
123
        $this->logger->info('String of incoming data confirmed, returning new object', ['callee' => \get_class($this)]);
124
125
        $eventManager = new EventManager($this->logger);
126
        try {
127
            $connAck = $eventManager->analyzeHeaders($data, $client);
128
        } catch (IdentifierRejected $e) {
129
            // TODO perform all checks here about
130
            $e->fillPossibleReason('TODO');
131
            // Re-throw the exception with all information filled in
132
            throw $e;
133
        }
134
135
        return $connAck;
136
    }
137
}
138