Passed
Push — master ( b7a059...7a6b49 )
by Camilo
02:58
created

WritableContent::setProtocolVersion()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 3
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace unreal4u\MQTT\Internals;
6
7
use Psr\Log\LoggerInterface;
8
use unreal4u\MQTT\Exceptions\MessageTooBig;
9
use unreal4u\MQTT\Utilities;
10
11
/**
12
 * Trait WritableContent
13
 * @package unreal4u\MQTT\Internals
14
 */
15
trait WritableContent
16
{
17
    /**
18
     * @var LoggerInterface
19
     */
20
    protected $logger;
21
22
    /**
23
     * Any special flags that are set on runtime
24
     *
25
     * PUBLISH for example needs to know QoS, the retain bit and duplicate delivery settings
26
     * PUBREL, SUBSCRIBE and UNSUBSCRIBE has always bit 1 set to true
27
     *
28
     * @var int
29
     */
30
    protected $specialFlags = 0;
31
32
    /**
33
     * Returns the fixed header part needed for all methods
34
     *
35
     * This takes into account the basic control packet value, any special flags and, in the second byte, the variable
36
     * header length
37
     *
38
     * @param int $variableHeaderLength
39
     * @return string
40
     * @throws \unreal4u\MQTT\Exceptions\MessageTooBig
41
     */
42 3
    final public function createFixedHeader(int $variableHeaderLength): string
43
    {
44 3
        $this->logger->debug('Creating fixed header with values', [
45 3
            'controlPacketValue' => static::CONTROL_PACKET_VALUE,
0 ignored issues
show
Bug introduced by
The constant unreal4u\MQTT\Internals\...t::CONTROL_PACKET_VALUE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
46 3
            'specialFlags' => $this->specialFlags,
47 3
            'variableHeaderLength' => $variableHeaderLength,
48 3
            'composed' => decbin(\chr((static::CONTROL_PACKET_VALUE << 4) | $this->specialFlags)),
0 ignored issues
show
Bug introduced by
chr(static::CONTROL_PACK... | $this->specialFlags) of type string is incompatible with the type integer expected by parameter $number of decbin(). ( Ignorable by Annotation )

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

48
            'composed' => decbin(/** @scrutinizer ignore-type */ \chr((static::CONTROL_PACKET_VALUE << 4) | $this->specialFlags)),
Loading history...
49
        ]);
50
51
        // Binary OR is safe to do because the first 4 bits are always 0 after shifting
52
        return
53 3
            \chr((static::CONTROL_PACKET_VALUE << 4) | $this->specialFlags) .
54 3
            $this->getRemainingLength($variableHeaderLength);
55
    }
56
57
    /**
58
     * Returns the correct format for the length in bytes of the remaining bytes
59
     *
60
     * @param int $lengthInBytes
61
     * @return string
62
     * @throws \unreal4u\MQTT\Exceptions\MessageTooBig
63
     */
64 3
    final public function getRemainingLength(int $lengthInBytes): string
65
    {
66 3
        if ($lengthInBytes > 268435455) {
67
            throw new MessageTooBig('The message cannot exceed 268435455 bytes in length');
68
        }
69
70 3
        $x = $lengthInBytes;
71 3
        $outputString = '';
72
        do {
73 3
            $encodedByte = $x % 128;
74 3
            $x >>= 7; // Shift 7 bytes
75
            // if there are more data to encode, set the top bit of this byte
76 3
            if ($x > 0) {
77
                $encodedByte |= 128;
78
            }
79 3
            $outputString .= \chr($encodedByte);
80 3
        } while ($x > 0);
81
82 3
        return $outputString;
83
    }
84
85
    /**
86
     * Creates the entire message
87
     * @return string
88
     * @throws \unreal4u\MQTT\Exceptions\MessageTooBig
89
     */
90 2
    final public function createSendableMessage(): string
91
    {
92 2
        $variableHeader = $this->createVariableHeader();
93 2
        $this->logger->debug('Created variable header', ['variableHeader' => base64_encode($variableHeader)]);
94 2
        $payload = $this->createPayload();
95 2
        $this->logger->debug('Created payload', ['payload' => base64_encode($payload)]);
96 2
        $fixedHeader = $this->createFixedHeader(\strlen($variableHeader . $payload));
97 2
        $this->logger->debug('Created fixed header', ['fixedHeader' => base64_encode($fixedHeader)]);
98
99 2
        return $fixedHeader . $variableHeader . $payload;
100
    }
101
102
    /**
103
     * Creates the variable header that each method has
104
     *
105
     * @return string
106
     */
107
    abstract public function createVariableHeader(): string;
108
109
    /**
110
     * Creates the actual payload to be sent
111
     *
112
     * @return string
113
     */
114
    abstract public function createPayload(): string;
115
116
    /**
117
     * Creates a UTF8 big-endian representation of the given string
118
     *
119
     * @param string $data
120
     * @return string
121
     * @throws \OutOfRangeException
122
     */
123 9
    final public function createUTF8String(string $data): string
124
    {
125 9
        $returnString = '';
126 9
        if ($data !== '') {
127 8
            $returnString = Utilities::convertNumberToBinaryString(\strlen($data)) . $data;
128
        }
129
130 9
        return $returnString;
131
    }
132
133
    /**
134
     * Will return an object of the type the broker has returned to us
135
     *
136
     * @param string $data
137
     * @param ClientInterface $client
138
     *
139
     * @return ReadableContentInterface
140
     * @throws \DomainException
141
     */
142
    public function expectAnswer(string $data, ClientInterface $client): ReadableContentInterface
143
    {
144
        $this->logger->info('String of incoming data confirmed, returning new object', ['callee' => \get_class($this)]);
145
146
        $eventManager = new EventManager($this->logger);
147
        return $eventManager->analyzeHeaders($data, $client);
148
    }
149
150
    /**
151
     * Gets the control packet value for this object
152
     *
153
     * @return int
154
     */
155 1
    final public static function getControlPacketValue(): int
156
    {
157 1
        return static::CONTROL_PACKET_VALUE;
0 ignored issues
show
Bug introduced by
The constant unreal4u\MQTT\Internals\...t::CONTROL_PACKET_VALUE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
158
    }
159
}
160