mirror of
https://github.com/ericasch6/scrum-poker-internal.git
synced 2026-10-13 16:12:09 +00:00
112 lines
4.2 KiB
PHP
112 lines
4.2 KiB
PHP
<?php
|
|
|
|
namespace App\Jobs;
|
|
|
|
use App\Enums\RoomStateChange;
|
|
use App\Events\RoomStateChanged;
|
|
use App\Models\Player;
|
|
use App\Models\Room;
|
|
use App\Services\Rooms\RoomRealtimeStateService;
|
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
|
use Illuminate\Foundation\Queue\Queueable;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class RemoveAbsentPlayers implements ShouldQueue
|
|
{
|
|
use Queueable;
|
|
|
|
public function handle(RoomRealtimeStateService $realtimeState): void
|
|
{
|
|
$cutoff = now()->subHour();
|
|
|
|
Player::query()
|
|
->where(function ($query) use ($cutoff): void {
|
|
$query->where('last_seen_at', '<=', $cutoff)
|
|
->orWhere(function ($query) use ($cutoff): void {
|
|
$query->whereNull('last_seen_at')
|
|
->where('created_at', '<=', $cutoff);
|
|
});
|
|
})
|
|
->select(['id', 'room_id'])
|
|
->chunkById(100, function ($players) use ($cutoff, $realtimeState): void {
|
|
foreach ($players as $player) {
|
|
$result = DB::transaction(function () use ($player, $cutoff): ?array {
|
|
$room = Room::withTrashed()
|
|
->lockForUpdate()
|
|
->find($player->room_id);
|
|
|
|
if ($room === null) {
|
|
return null;
|
|
}
|
|
|
|
$currentPlayer = $room->players()
|
|
->lockForUpdate()
|
|
->find($player->id);
|
|
|
|
if ($currentPlayer === null) {
|
|
return null;
|
|
}
|
|
|
|
$lastActivity = $currentPlayer->last_seen_at ?? $currentPlayer->created_at;
|
|
|
|
if ($lastActivity === null || $lastActivity->greaterThan($cutoff)) {
|
|
return null;
|
|
}
|
|
|
|
$currentPlayer->delete();
|
|
$roomDeleted = false;
|
|
|
|
if ($room->owner_id === null && ! $room->trashed()) {
|
|
if (! $room->players()->exists()) {
|
|
$room->delete();
|
|
$roomDeleted = true;
|
|
} elseif (! $room->players()->where('is_moderator', true)->exists()) {
|
|
$successor = $room->players()
|
|
->where(function ($query) use ($cutoff): void {
|
|
$query->where('last_seen_at', '>', $cutoff)
|
|
->orWhere(function ($query) use ($cutoff): void {
|
|
$query->whereNull('last_seen_at')
|
|
->where('created_at', '>', $cutoff);
|
|
});
|
|
})
|
|
->orderBy('created_at')
|
|
->orderBy('id')
|
|
->first();
|
|
|
|
$successor?->update(['is_moderator' => true]);
|
|
}
|
|
}
|
|
|
|
$room->update([
|
|
'state_version' => $room->state_version + 1,
|
|
]);
|
|
|
|
return [$room, $roomDeleted];
|
|
});
|
|
|
|
if ($result === null) {
|
|
continue;
|
|
}
|
|
|
|
[$room, $roomDeleted] = $result;
|
|
|
|
if ($roomDeleted) {
|
|
RoomStateChanged::dispatch(
|
|
$room->id,
|
|
$room->state_version,
|
|
RoomStateChange::RoomDeleted,
|
|
);
|
|
} elseif (! $room->trashed()) {
|
|
RoomStateChanged::dispatch(
|
|
$room->id,
|
|
$room->state_version,
|
|
RoomStateChange::PlayerKicked,
|
|
$realtimeState->for($room),
|
|
$player->id,
|
|
);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|