Lines 95.23% 20 / 21
Functions and Methods 75.00% 3 / 4
Classes and Traits 0.00% 0 / 1
Name Lines Functions and Methods CRAP Classes and Traits
MqttMessageConverter 95.23% 20 / 21 75.00% 3 / 4 9 0.00% 0 / 1
 handledClass 100.00% 1 / 1 100.00% 1 / 1 1
 keySuffix 100.00% 1 / 1 100.00% 1 / 1 1
 encodeValue 100.00% 7 / 7 100.00% 1 / 1 1
 decodeValue 91.66% 11 / 12 0.00% 0 / 1 6.02
1<?php
2
3declare(strict_types=1);
4
5namespace Stewart\Runtime\Ipc\Wire;
6
7use Stewart\Contracts\Mqtt\MqttMessage;
8use Stewart\Contracts\Mqtt\MqttQos;
9use Stewart\Runtime\Json\ValueConverter;
10use Stewart\Support\Exception\JsonShapeException;
11use Stewart\Support\Json\JsonShape;
12
13// Payloads are bytes and IPC frames are JSON, so the payload travels base64-encoded.
14final readonly class MqttMessageConverter implements ValueConverter
15{
16    public function handledClass(): string
17    {
18        return MqttMessage::class;
19    }
20
21    public function keySuffix(): string
22    {
23        return '';
24    }
25
26    /** @return array{topic: string, payload_base64: string, qos: int, retain: bool} */
27    public function encodeValue(object $value): array
28    {
29        \assert($value instanceof MqttMessage);
30
31        return [
32            'topic' => $value->topic,
33            'payload_base64' => base64_encode($value->payload),
34            'qos' => $value->qos->value,
35            'retain' => $value->retain,
36        ];
37    }
38
39    /** @throws JsonShapeException */
40    public function decodeValue(mixed $value, string $path): MqttMessage
41    {
42        if (!\is_array($value)) {
43            throw JsonShapeException::wrongType($path, 'an object', get_debug_type($value));
44        }
45
46        $payload = base64_decode(JsonShape::requireString($value, 'payload_base64'), true);
47        $qos = \is_int($value['qos'] ?? null) ? MqttQos::tryFrom($value['qos']) : null;
48        $retain = $value['retain'] ?? null;
49
50        if ($payload === false) {
51            throw JsonShapeException::unexpectedValue($path . '.payload_base64', 'base64 text', $value['payload_base64']);
52        }
53
54        if ($qos === null) {
55            throw JsonShapeException::unexpectedValue($path . '.qos', '0 or 1', $value['qos'] ?? null);
56        }
57
58        if (!\is_bool($retain)) {
59            throw JsonShapeException::wrongType($path . '.retain', 'a boolean', get_debug_type($retain));
60        }
61
62        return new MqttMessage(JsonShape::requireString($value, 'topic'), $payload, $qos, $retain);
63    }
64}