Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BCrwHHnGCB5XH968Nxokqw
71 lines
2.4 KiB
PHP
71 lines
2.4 KiB
PHP
<?php
|
||
|
||
namespace App\Channels;
|
||
|
||
use App\Enums\Presence;
|
||
use App\Http\Controllers\Api\EventsController as Presenter;
|
||
use App\Models\Delivery;
|
||
use App\Models\Event;
|
||
use App\Models\User;
|
||
use Illuminate\Support\Facades\Http;
|
||
use Throwable;
|
||
|
||
/** Универсальный webhook. В нашем случае — Home Assistant. */
|
||
final class WebhookChannel implements ChannelDriver
|
||
{
|
||
public function __construct(private readonly int $presenceTimeout) {}
|
||
|
||
public function presence(User $user, array $config): Presence
|
||
{
|
||
try {
|
||
$response = Http::timeout($this->presenceTimeout)->acceptJson()->get($config['presence_url']);
|
||
if (! $response->successful()) {
|
||
return Presence::Unknown;
|
||
}
|
||
|
||
return $response->json('present') === true ? Presence::Present : Presence::Absent;
|
||
} catch (Throwable) {
|
||
return Presence::Unknown;
|
||
}
|
||
}
|
||
|
||
public function deliver(Event $event, User $user, array $config, Delivery $delivery): DeliveryOutcome
|
||
{
|
||
try {
|
||
$response = Http::timeout(5)->asJson()->post($config['deliver_url'], self::payload($event, $delivery));
|
||
if ($response->successful()) {
|
||
return DeliveryOutcome::ok();
|
||
}
|
||
|
||
return DeliveryOutcome::failed("HTTP {$response->status()}: ".mb_substr($response->body(), 0, 200));
|
||
} catch (Throwable $e) {
|
||
return DeliveryOutcome::failed($e->getMessage());
|
||
}
|
||
}
|
||
|
||
public function onDone(Event $event, Delivery $delivery): void {}
|
||
|
||
/** @return array<string,mixed> */
|
||
public static function payload(Event $event, Delivery $delivery): array
|
||
{
|
||
$presented = Presenter::present($event);
|
||
|
||
return [
|
||
'event' => [
|
||
'id' => $event->id,
|
||
'state' => $presented['state'],
|
||
'due_at' => $presented['due_at'],
|
||
'source' => $event->source->name,
|
||
'title' => $event->payload['title'],
|
||
'subtitle' => $event->payload['subtitle'] ?? null,
|
||
'deep_link' => $event->payload['deep_link'] ?? null,
|
||
'done_label' => $event->payload['done_label'] ?? 'Сделано',
|
||
],
|
||
'actions' => [
|
||
'ack' => route('action.ack', $delivery->action_token),
|
||
'done' => route('action.done', $delivery->action_token),
|
||
],
|
||
];
|
||
}
|
||
}
|