Lines 100.00% 26 / 26
Methods 100.00% 15 / 15
Classes 100.00% 1 / 1
Name Lines Methods CRAP
 __construct 100.00% 1 / 1 100.00% 1 / 1 1
 forApp 100.00% 1 / 1 100.00% 1 / 1 1
 exposeSensor 100.00% 1 / 1 100.00% 1 / 1 1
 exposeBinarySensor 100.00% 1 / 1 100.00% 1 / 1 1
 exposeSwitch 100.00% 1 / 1 100.00% 1 / 1 1
 exposeButton 100.00% 1 / 1 100.00% 1 / 1 1
 exposeNumber 100.00% 1 / 1 100.00% 1 / 1 1
 exposeSelect 100.00% 1 / 1 100.00% 1 / 1 1
 exposeText 100.00% 1 / 1 100.00% 1 / 1 1
 exposeTime 100.00% 1 / 1 100.00% 1 / 1 1
 exposeDate 100.00% 1 / 1 100.00% 1 / 1 1
 exposeDateTime 100.00% 1 / 1 100.00% 1 / 1 1
 exposeAction 100.00% 1 / 1 100.00% 1 / 1 1
 claimKey 100.00% 5 / 5 100.00% 1 / 1 2
 exposeHandle 100.00% 8 / 8 100.00% 1 / 1 3
51final readonly class WorkerEntityExposure implements EntityExposure
52{
53    public function __construct(
54        private ExposureChannel $channel,
55        private ResourceScope $resourceScope,
56    ) {}
57
58    public function forApp(AppId $appId): self
59    {
60        return new self($this->channel, ResourceScope::forApp($appId));
61    }
62
63    public function exposeSensor(ExposedEntityKey|string $key, SensorConfig $config = new SensorConfig(), ?DeviceInfo $device = null): ExposedSensor
64    {
65        return $this->exposeHandle(new WorkerExposedSensor($this->channel, $this->resourceScope, $this->claimKey($key), $config), $config, $device);
66    }
67
68    public function exposeBinarySensor(
69        ExposedEntityKey|string $key,
70        BinarySensorConfig $config = new BinarySensorConfig(),
71        ?DeviceInfo $device = null,
72    ): ExposedBinarySensor {
73        return $this->exposeHandle(new WorkerExposedBinarySensor($this->channel, $this->resourceScope, $this->claimKey($key), $config), $config, $device);
74    }
75
76    public function exposeSwitch(ExposedEntityKey|string $key, SwitchConfig $config = new SwitchConfig(), ?DeviceInfo $device = null): ExposedSwitch
77    {
78        return $this->exposeHandle(new WorkerExposedSwitch($this->channel, $this->resourceScope, $this->claimKey($key), $config), $config, $device);
79    }
80
81    public function exposeButton(ExposedEntityKey|string $key, ButtonConfig $config = new ButtonConfig(), ?DeviceInfo $device = null): ExposedButton
82    {
83        return $this->exposeHandle(new WorkerExposedButton($this->channel, $this->resourceScope, $this->claimKey($key), $config), $config, $device);
84    }
85
86    public function exposeNumber(ExposedEntityKey|string $key, NumberConfig $config, ?DeviceInfo $device = null): ExposedNumber
87    {
88        return $this->exposeHandle(new WorkerExposedNumber($this->channel, $this->resourceScope, $this->claimKey($key), $config), $config, $device);
89    }
90
91    public function exposeSelect(ExposedEntityKey|string $key, SelectConfig $config, ?DeviceInfo $device = null): ExposedSelect
92    {
93        return $this->exposeHandle(new WorkerExposedSelect($this->channel, $this->resourceScope, $this->claimKey($key), $config), $config, $device);
94    }
95
96    public function exposeText(ExposedEntityKey|string $key, TextConfig $config = new TextConfig(), ?DeviceInfo $device = null): ExposedText
97    {
98        return $this->exposeHandle(new WorkerExposedText($this->channel, $this->resourceScope, $this->claimKey($key), $config), $config, $device);
99    }
100
101    public function exposeTime(ExposedEntityKey|string $key, TimeConfig $config = new TimeConfig(), ?DeviceInfo $device = null): ExposedTime
102    {
103        return $this->exposeHandle(new WorkerExposedTime($this->channel, $this->resourceScope, $this->claimKey($key), $config), $config, $device);
104    }
105
106    public function exposeDate(ExposedEntityKey|string $key, DateConfig $config = new DateConfig(), ?DeviceInfo $device = null): ExposedDate
107    {
108        return $this->exposeHandle(new WorkerExposedDate($this->channel, $this->resourceScope, $this->claimKey($key), $config), $config, $device);
109    }
110
111    public function exposeDateTime(ExposedEntityKey|string $key, DateTimeConfig $config = new DateTimeConfig(), ?DeviceInfo $device = null): ExposedDateTime
112    {
113        return $this->exposeHandle(new WorkerExposedDateTime($this->channel, $this->resourceScope, $this->claimKey($key), $config), $config, $device);
114    }
115
116    public function exposeAction(ExposedEntityKey|string $key, ActionConfig $config = new ActionConfig()): ExposedAction
117    {
118        return $this->exposeHandle(new WorkerExposedAction($this->channel, $this->resourceScope, $this->claimKey($key), $config), $config, null);
119    }
120
121    /** @throws ExposureException */
122    private function claimKey(ExposedEntityKey|string $key): ExposedEntityKey
123    {
124        $key = ExposedEntityKey::fromKeyOrString($key);
125        $appId = $this->resourceScope->appId ?? throw ExposureException::outsideApp($key);
126
127        if ($this->channel->handles->isKeyTaken($this->resourceScope, $key)) {
128            throw ExposureException::keyTaken($appId, $key);
129        }
130
131        return $key;
132    }
133
134    /**
135     * @template THandle of WorkerExposure<covariant ExposureConfig>
136     *
137     * @param THandle $handle
138     * @return THandle
139     * @throws ExposureException
140     */
141    private function exposeHandle(WorkerExposure $handle, ExposureConfig $config, ?DeviceInfo $device): WorkerExposure
142    {
143        // Recorded before the broker answers, so a second exposure of the same key fails while the first is in flight.
144        $this->channel->handles->recordHandle($this->resourceScope, $handle->getKey(), $handle);
145
146        try {
147            $snapshot = $this->channel->requester->requestExposure($this->resourceScope, $handle->getKey(), $config, $device, new ExposedStateChange());
148        } catch (ExposureException $e) {
149            $this->channel->handles->forgetHandle($this->resourceScope, $handle->getKey());
150
151            throw $e;
152        }
153
154        if ($snapshot !== null) {
155            $handle->applySnapshot($snapshot);
156        }
157
158        return $handle;
159    }
160}