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>
125 lines
3.5 KiB
PHP
125 lines
3.5 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Meet;
|
|
|
|
use App\Models\Recording;
|
|
use App\Models\Session;
|
|
use App\Models\User;
|
|
use App\Jobs\ProcessRecording;
|
|
use Illuminate\Support\Facades\Storage;
|
|
|
|
class RecordingService
|
|
{
|
|
public function start(Session $session, User $host, string $layout = 'gallery'): Recording
|
|
{
|
|
$active = $session->recordings()->where('status', 'recording')->first();
|
|
if ($active) {
|
|
return $active;
|
|
}
|
|
|
|
$recording = Recording::create([
|
|
'owner_ref' => $session->owner_ref,
|
|
'session_id' => $session->id,
|
|
'status' => 'recording',
|
|
'layout' => $layout,
|
|
'started_by_ref' => $host->ownerRef(),
|
|
'started_at' => now(),
|
|
]);
|
|
|
|
AuditLogger::record(
|
|
$session->owner_ref,
|
|
'recording.started',
|
|
$session->room->organization_id,
|
|
$host->ownerRef(),
|
|
Recording::class,
|
|
$recording->id,
|
|
);
|
|
|
|
return $recording;
|
|
}
|
|
|
|
public function stop(Recording $recording, string $actorRef): Recording
|
|
{
|
|
if ($recording->status !== 'recording') {
|
|
return $recording;
|
|
}
|
|
|
|
$recording->update([
|
|
'status' => 'processing',
|
|
'ended_at' => now(),
|
|
'duration_seconds' => $recording->started_at
|
|
? (int) $recording->started_at->diffInSeconds(now())
|
|
: null,
|
|
]);
|
|
|
|
AuditLogger::record(
|
|
$recording->owner_ref,
|
|
'recording.stopped',
|
|
$recording->session->room->organization_id,
|
|
$actorRef,
|
|
Recording::class,
|
|
$recording->id,
|
|
);
|
|
|
|
ProcessRecording::dispatch($recording->id);
|
|
|
|
return $recording->fresh();
|
|
}
|
|
|
|
public function process(Recording $recording): Recording
|
|
{
|
|
$session = $recording->session;
|
|
$filename = 'recordings/'.$session->uuid.'/'.$recording->uuid.'.mp4';
|
|
$disk = Storage::disk(config('meet.recordings.disk', 'local'));
|
|
|
|
// Placeholder until LiveKit Egress writes the file; create empty marker for dev.
|
|
if (! $disk->exists($filename)) {
|
|
$disk->put($filename, '');
|
|
}
|
|
|
|
$recording->update([
|
|
'status' => 'ready',
|
|
'storage_path' => $filename,
|
|
'file_size' => $disk->size($filename) ?: null,
|
|
'thumbnail_path' => null,
|
|
]);
|
|
|
|
AuditLogger::record(
|
|
$recording->owner_ref,
|
|
'recording.ready',
|
|
$session->room->organization_id,
|
|
null,
|
|
Recording::class,
|
|
$recording->id,
|
|
);
|
|
|
|
app(MeetNotificationService::class)->recordingReady($recording);
|
|
|
|
app(\App\Services\Integrations\WebhookDispatcher::class)->recordingReady($recording);
|
|
|
|
if ($session->room->setting('auto_ai_summary', false) || config('meet.ai.auto_summarize', true)) {
|
|
app(TranscriptService::class)->ensureForSession($session, $recording);
|
|
}
|
|
|
|
return $recording->fresh();
|
|
}
|
|
|
|
public function delete(Recording $recording, string $actorRef): void
|
|
{
|
|
if ($recording->storage_path) {
|
|
Storage::disk(config('meet.recordings.disk', 'local'))->delete($recording->storage_path);
|
|
}
|
|
|
|
AuditLogger::record(
|
|
$recording->owner_ref,
|
|
'recording.deleted',
|
|
$recording->session->room->organization_id,
|
|
$actorRef,
|
|
Recording::class,
|
|
$recording->id,
|
|
);
|
|
|
|
$recording->delete();
|
|
}
|
|
}
|