Files
ladill-meet/app/Services/Meet/BreakoutService.php
T
isaaccladandCursor 965fb992e9
Deploy Ladill Meet / deploy (push) Failing after 7s
Initial Ladill Meet release.
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>
2026-06-30 23:35:29 +00:00

107 lines
3.7 KiB
PHP

<?php
namespace App\Services\Meet;
use App\Models\BreakoutAssignment;
use App\Models\BreakoutRoom;
use App\Models\Message;
use App\Models\Participant;
use App\Models\Session;
use App\Services\Meet\Media\MediaProviderInterface;
use Illuminate\Support\Str;
class BreakoutService
{
public function __construct(
protected MediaProviderInterface $media,
) {}
/**
* @param array<int, array{participant_id: int, breakout_room_id?: int}>|null $assignments
* @return \Illuminate\Support\Collection<int, BreakoutRoom>
*/
public function createRooms(Session $session, int $count, ?int $timerMinutes = null, ?array $assignments = null)
{
$timerMinutes ??= config('meet.breakouts.default_timer_minutes', 15);
$closesAt = now()->addMinutes($timerMinutes);
$rooms = collect();
for ($i = 1; $i <= $count; $i++) {
$mediaName = $session->media_room_name.'-breakout-'.Str::random(8);
$this->media->createRoom($mediaName);
$rooms->push(BreakoutRoom::create([
'owner_ref' => $session->owner_ref,
'session_id' => $session->id,
'name' => 'Breakout '.$i,
'media_room_name' => $mediaName,
'status' => 'open',
'closes_at' => $closesAt,
]));
}
$participants = $session->participants()->where('status', 'joined')->get();
if ($assignments) {
foreach ($assignments as $assignment) {
$this->assignParticipant(
$rooms->firstWhere('id', $assignment['breakout_room_id']) ?? $rooms->first(),
Participant::findOrFail($assignment['participant_id']),
);
}
} else {
$participants->values()->each(function (Participant $participant, int $index) use ($rooms) {
$this->assignParticipant($rooms[$index % $rooms->count()], $participant);
});
}
return $rooms;
}
public function assignParticipant(BreakoutRoom $breakout, Participant $participant): void
{
BreakoutAssignment::updateOrCreate(
['breakout_room_id' => $breakout->id, 'participant_id' => $participant->id],
);
$participant->update(['breakout_room_id' => $breakout->id]);
}
public function moveParticipant(Participant $participant, BreakoutRoom $breakout): void
{
$this->assignParticipant($breakout, $participant);
}
public function returnToMain(Participant $participant): void
{
$participant->update(['breakout_room_id' => null]);
BreakoutAssignment::where('participant_id', $participant->id)->delete();
}
public function broadcast(Session $session, string $message, string $senderName): Message
{
return Message::create([
'owner_ref' => $session->owner_ref,
'session_id' => $session->id,
'sender_name' => $senderName,
'type' => 'breakout_broadcast',
'body' => $message,
]);
}
public function closeAll(Session $session): void
{
$session->breakoutRooms()->update(['status' => 'closed']);
$session->participants()->whereNotNull('breakout_room_id')->update(['breakout_room_id' => null]);
BreakoutAssignment::whereIn('breakout_room_id', $session->breakoutRooms()->pluck('id'))->delete();
}
public function mediaRoomForParticipant(Participant $participant): string
{
if ($participant->breakout_room_id) {
return $participant->breakoutRoom?->media_room_name ?? $participant->session->media_room_name;
}
return $participant->session->media_room_name;
}
}