Lines 23.07% 6 / 26
Functions and Methods 66.66% 2 / 3
Classes and Traits 0.00% 0 / 1
Name Lines Functions and Methods CRAP Classes and Traits
HaClientError 23.07% 6 / 26 66.66% 2 / 3 333.69 0.00% 0 / 1
 messageTemplate 0.00% 0 / 20 0.00% 0 / 1 420
 isFatal 100.00% 3 / 3 100.00% 1 / 1 3
 isCommandRefusal 100.00% 3 / 3 100.00% 1 / 1 3
1<?php
2
3declare(strict_types=1);
4
5namespace Stewart\Client\Exception;
6
7use Stewart\Contracts\Exception\ExceptionReason;
8
9enum HaClientError: string implements ExceptionReason
10{
11    case ClosedLocally = 'closed_locally';
12    case ConnectTimedOut = 'connect_timed_out';
13    case ConnectFailed = 'connect_failed';
14    case NotConnected = 'not_connected';
15    case SendFailed = 'send_failed';
16    case ClosedDuringAuthentication = 'closed_during_authentication';
17    case ConnectionDropped = 'connection_dropped';
18    case MessageTooLarge = 'message_too_large';
19    case ProtocolViolation = 'protocol_violation';
20    case CommandTimedOut = 'command_timed_out';
21    case CommandRejected = 'command_rejected';
22    case CommandUnauthorized = 'command_unauthorized';
23    case CommandUnencodable = 'command_unencodable';
24    case UnexpectedGreeting = 'unexpected_greeting';
25    case TokenRejected = 'token_rejected';
26    case AdministratorRequired = 'administrator_required';
27    case EventBacklogExceeded = 'event_backlog_exceeded';
28    case EventQueueReentered = 'event_queue_reentered';
29    case UrlInvalid = 'url_invalid';
30    case ComponentInstanceInvalid = 'component_instance_invalid';
31
32    public function messageTemplate(): string
33    {
34        return match ($this) {
35            self::ClosedLocally => 'The connection was closed locally while {phase}.',
36            self::ConnectTimedOut => 'Connecting to Home Assistant at {url} timed out after {timeout}. Check home_assistant.url.',
37            self::ConnectFailed => 'Could not connect to Home Assistant at {url}: {cause}',
38            self::NotConnected => 'Not connected to Home Assistant.',
39            self::SendFailed => 'Failed to send {command}: {cause}',
40            self::ClosedDuringAuthentication => 'Home Assistant closed the connection during authentication.',
41            self::ConnectionDropped => 'The connection to Home Assistant was lost ({detail}).',
42            self::MessageTooLarge => 'Home Assistant sent a message over the size limit, so the connection was dropped. Raise home_assistant.message_size_limit or home_assistant.frame_size_limit.',
43            self::ProtocolViolation => 'Home Assistant sent {detail}.',
44            self::CommandTimedOut => 'Home Assistant did not answer {command} within {timeout}.',
45            self::CommandRejected, self::CommandUnauthorized => '{command} failed: {detail}',
46            self::CommandUnencodable => '{command} could not be encoded: {cause}',
47            self::UnexpectedGreeting => 'Expected auth_required from Home Assistant, got "{receivedType}".',
48            self::TokenRejected => 'Home Assistant rejected the access token: {reason}. Check STEWART_HOME_ASSISTANT__TOKEN.',
49            self::AdministratorRequired => 'Home Assistant refused the event subscription; the access token must belong to an administrator. Update STEWART_HOME_ASSISTANT__TOKEN.',
50            self::EventBacklogExceeded => 'Event handlers are more than {limit} events behind; dropping the connection.',
51            self::EventQueueReentered => 'An event callback cannot wait for the event queue it is being delivered by.',
52            self::UrlInvalid => '"{url}" is not a Home Assistant URL; use http://, https://, ws:// or wss:// and a host.',
53            self::ComponentInstanceInvalid => '"{instance}" is not an instance name; use lowercase letters, digits and underscores, starting with a letter, up to 64 characters.',
54        };
55    }
56
57    public function isFatal(): bool
58    {
59        return match ($this) {
60            self::UnexpectedGreeting, self::TokenRejected, self::AdministratorRequired => true,
61            default => false,
62        };
63    }
64
65    public function isCommandRefusal(): bool
66    {
67        return match ($this) {
68            self::CommandRejected, self::CommandUnauthorized, self::CommandUnencodable, self::AdministratorRequired => true,
69            default => false,
70        };
71    }
72}