Deploy Ladill Meet / deploy (push) Failing after 7s
Phases 0–18: core meetings, webinar, breakouts, team chat, live streaming, town hall, billing, and Ladill Mail calendar wiring. Co-authored-by: Cursor <cursoragent@cursor.com>
115 lines
3.9 KiB
PHP
115 lines
3.9 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Integrations;
|
|
|
|
use App\Models\Recording;
|
|
use App\Models\Room;
|
|
use App\Models\Session;
|
|
use App\Models\WebhookEndpoint;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class WebhookDispatcher
|
|
{
|
|
public function meetingStarted(Session $session): void
|
|
{
|
|
$session->loadMissing('room');
|
|
$this->dispatch($session->room->organization_id, 'meeting.started', $this->sessionPayload($session));
|
|
}
|
|
|
|
public function meetingEnded(Session $session): void
|
|
{
|
|
$session->loadMissing('room');
|
|
$this->dispatch($session->room->organization_id, 'meeting.ended', $this->sessionPayload($session));
|
|
}
|
|
|
|
public function recordingReady(Recording $recording): void
|
|
{
|
|
$recording->loadMissing('session.room');
|
|
$payload = array_merge($this->sessionPayload($recording->session), [
|
|
'recording' => [
|
|
'uuid' => $recording->uuid,
|
|
'status' => $recording->status,
|
|
'duration_seconds' => $recording->duration_seconds,
|
|
'download_url' => route('meet.recordings.download', $recording),
|
|
],
|
|
]);
|
|
|
|
$this->dispatch($recording->session->room->organization_id, 'recording.ready', $payload);
|
|
}
|
|
|
|
public function roomCreated(Room $room): void
|
|
{
|
|
$this->dispatch($room->organization_id, 'meeting.scheduled', $this->roomPayload($room));
|
|
}
|
|
|
|
public function roomCancelled(Room $room): void
|
|
{
|
|
$this->dispatch($room->organization_id, 'meeting.cancelled', $this->roomPayload($room));
|
|
}
|
|
|
|
/** @param array<string, mixed> $payload */
|
|
protected function dispatch(int $organizationId, string $event, array $payload): void
|
|
{
|
|
$body = array_merge(['event' => $event, 'timestamp' => now()->toIso8601String()], $payload);
|
|
|
|
WebhookEndpoint::query()
|
|
->where('organization_id', $organizationId)
|
|
->where('is_active', true)
|
|
->get()
|
|
->filter(fn (WebhookEndpoint $endpoint) => $endpoint->subscribesTo($event))
|
|
->each(fn (WebhookEndpoint $endpoint) => $this->send($endpoint, $body));
|
|
}
|
|
|
|
/** @param array<string, mixed> $payload */
|
|
protected function send(WebhookEndpoint $endpoint, array $payload): void
|
|
{
|
|
$body = json_encode($payload);
|
|
$headers = ['Content-Type' => 'application/json', 'X-Ladill-Meet-Event' => $payload['event']];
|
|
|
|
if ($endpoint->secret) {
|
|
$headers['X-Ladill-Meet-Signature'] = hash_hmac('sha256', $body, $endpoint->secret);
|
|
}
|
|
|
|
try {
|
|
Http::timeout(10)->withHeaders($headers)->withBody($body, 'application/json')->post($endpoint->url);
|
|
} catch (\Throwable $e) {
|
|
Log::warning('Meet webhook delivery failed', [
|
|
'endpoint_id' => $endpoint->id,
|
|
'url' => $endpoint->url,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
}
|
|
}
|
|
|
|
/** @return array<string, mixed> */
|
|
protected function roomPayload(Room $room): array
|
|
{
|
|
return [
|
|
'room' => [
|
|
'uuid' => $room->uuid,
|
|
'title' => $room->title,
|
|
'status' => $room->status,
|
|
'type' => $room->type,
|
|
'scheduled_at' => $room->scheduled_at?->toIso8601String(),
|
|
'join_url' => $room->joinUrl(),
|
|
'source' => $room->source,
|
|
],
|
|
];
|
|
}
|
|
|
|
/** @return array<string, mixed> */
|
|
protected function sessionPayload(Session $session): array
|
|
{
|
|
return array_merge($this->roomPayload($session->room), [
|
|
'session' => [
|
|
'uuid' => $session->uuid,
|
|
'status' => $session->status,
|
|
'started_at' => $session->started_at?->toIso8601String(),
|
|
'ended_at' => $session->ended_at?->toIso8601String(),
|
|
'peak_participants' => $session->peak_participants,
|
|
],
|
|
]);
|
|
}
|
|
}
|