1 | <?php |
||||||
2 | |||||||
3 | declare(strict_types=1); |
||||||
4 | |||||||
5 | namespace unreal4u\MQTT\Internals; |
||||||
6 | |||||||
7 | use unreal4u\MQTT\Exceptions\InvalidResponseType; |
||||||
8 | use unreal4u\MQTT\Utilities; |
||||||
9 | |||||||
10 | use function ord; |
||||||
11 | use function sprintf; |
||||||
12 | use function strlen; |
||||||
13 | |||||||
14 | /** |
||||||
15 | * Trait ReadableContent |
||||||
16 | * @package unreal4u\MQTT\Internals |
||||||
17 | */ |
||||||
18 | trait ReadableContent |
||||||
19 | { |
||||||
20 | /** |
||||||
21 | * The remaining length field may be from 1 to 4 bytes long, this field will represent that offset |
||||||
22 | * @var int |
||||||
23 | */ |
||||||
24 | private $sizeOfRemainingLengthField = 1; |
||||||
25 | |||||||
26 | /** |
||||||
27 | * @param string $rawMQTTHeaders |
||||||
28 | * @param ClientInterface $client |
||||||
29 | * @return bool |
||||||
30 | * @throws InvalidResponseType |
||||||
31 | */ |
||||||
32 | 8 | final public function instantiateObject(string $rawMQTTHeaders, ClientInterface $client): bool |
|||||
33 | { |
||||||
34 | //var_dump(base64_encode($rawMQTTHeaders)); // Make it a bit easier to create unit tests |
||||||
35 | 8 | $this->checkControlPacketValue(ord($rawMQTTHeaders[0]) >> 4); |
|||||
36 | 7 | $this->fillObject($rawMQTTHeaders, $client); |
|||||
37 | |||||||
38 | 7 | return true; |
|||||
39 | } |
||||||
40 | |||||||
41 | /** |
||||||
42 | * Checks whether the control packet corresponds to this object |
||||||
43 | * |
||||||
44 | * @param int $controlPacketValue |
||||||
45 | * @return bool |
||||||
46 | * @throws InvalidResponseType |
||||||
47 | */ |
||||||
48 | 8 | private function checkControlPacketValue(int $controlPacketValue): bool |
|||||
49 | { |
||||||
50 | // Check whether the first byte corresponds to the expected control packet value |
||||||
51 | 8 | if (static::CONTROL_PACKET_VALUE !== $controlPacketValue) { |
|||||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||||||
52 | 1 | throw new InvalidResponseType(sprintf( |
|||||
53 | 1 | 'Value of received value does not correspond to response (Expected: %d, Actual: %d)', |
|||||
54 | 1 | static::CONTROL_PACKET_VALUE, |
|||||
55 | 1 | $controlPacketValue |
|||||
56 | )); |
||||||
57 | } |
||||||
58 | |||||||
59 | 7 | return true; |
|||||
60 | } |
||||||
61 | |||||||
62 | /** |
||||||
63 | * Returns the correct format for the length in bytes of the remaining bytes |
||||||
64 | * |
||||||
65 | * @param ClientInterface $client |
||||||
66 | * @param string $rawMQTTHeaders |
||||||
67 | * @return int |
||||||
68 | */ |
||||||
69 | 15 | private function performRemainingLengthFieldOperations( |
|||||
70 | string &$rawMQTTHeaders, |
||||||
71 | ClientInterface $client |
||||||
72 | ): int { |
||||||
73 | // Early return: assume defaults if first digit has a value under 128, no further need for complex checks |
||||||
74 | 15 | if (ord($rawMQTTHeaders[1]) < 128) { |
|||||
75 | 11 | return ord($rawMQTTHeaders[1]); |
|||||
76 | } |
||||||
77 | |||||||
78 | // If we have less than 4 bytes now, we should really try to recover the rest of the remaining field data |
||||||
79 | 4 | if (strlen($rawMQTTHeaders) < 4) { |
|||||
80 | // At this point we could actually read at least 128 as a minimum, but restrict it to what we need right now |
||||||
81 | 1 | $rawMQTTHeaders .= $client->readBrokerData(4 - strlen($rawMQTTHeaders)); |
|||||
82 | } |
||||||
83 | |||||||
84 | 4 | $remainingBytes = Utilities::convertRemainingLengthStringToInt(substr($rawMQTTHeaders, 1, 4)); |
|||||
85 | |||||||
86 | // Estimate how much longer is the remaining length field, this will also set $this->sizeOfRemainingLengthField |
||||||
87 | 4 | $this->calculateSizeOfRemainingLengthField($remainingBytes); |
|||||
88 | 4 | return $remainingBytes; |
|||||
89 | } |
||||||
90 | |||||||
91 | /** |
||||||
92 | * Sets the offset of the remaining length field |
||||||
93 | * |
||||||
94 | * @param int $size |
||||||
95 | * @return int |
||||||
96 | */ |
||||||
97 | 13 | private function calculateSizeOfRemainingLengthField(int $size): int |
|||||
98 | { |
||||||
99 | 13 | $blockSize = $iterations = 0; |
|||||
100 | 13 | while ($size >= $blockSize) { |
|||||
101 | 13 | $iterations++; |
|||||
102 | 13 | $blockSize = 128 ** $iterations; |
|||||
103 | } |
||||||
104 | |||||||
105 | 13 | $this->sizeOfRemainingLengthField = $iterations; |
|||||
106 | 13 | return $iterations; |
|||||
107 | } |
||||||
108 | |||||||
109 | /** |
||||||
110 | * All classes must implement how to handle the object filling |
||||||
111 | * @param string $rawMQTTHeaders |
||||||
112 | * @param ClientInterface $client |
||||||
113 | * @return ReadableContentInterface |
||||||
114 | */ |
||||||
115 | abstract public function fillObject(string $rawMQTTHeaders, ClientInterface $client): ReadableContentInterface; |
||||||
116 | |||||||
117 | /** |
||||||
118 | * Any class can overwrite the default behaviour |
||||||
119 | * @param ClientInterface $client |
||||||
120 | * @param WritableContentInterface $originalRequest |
||||||
121 | * @return bool |
||||||
122 | */ |
||||||
123 | 1 | public function performSpecialActions(ClientInterface $client, WritableContentInterface $originalRequest): bool |
|||||
0 ignored issues
–
show
The parameter
$originalRequest is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. ![]() The parameter
$client is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. ![]() |
|||||||
124 | { |
||||||
125 | 1 | return false; |
|||||
126 | } |
||||||
127 | } |
||||||
128 |