Handle authenticated room instance takeover
CI/CD / test_and_check_app (push) Failing after 2m7s
CI/CD / Publish immutable image (push) Skipped

This commit is contained in:
2026-09-10 16:33:13 +02:00
parent 2ab95cebdf
commit 640a2970c3
18 changed files with 351 additions and 22 deletions
@@ -205,6 +205,17 @@ class RoomParticipationService
?User $user,
mixed $sessionPlayerId,
): ?Player {
if ($user !== null) {
$userPlayer = $room->players()
->where('user_id', $user->id)
->lockForUpdate()
->first();
if ($userPlayer !== null) {
return $userPlayer;
}
}
if (is_numeric($sessionPlayerId)) {
$sessionPlayer = $room->players()
->whereKey((int) $sessionPlayerId)
@@ -216,14 +227,53 @@ class RoomParticipationService
}
}
if ($user === null) {
return null;
return null;
}
public function activateInstance(Room $room, Player $player, string $instanceId): Player
{
[$activePlayer, $replacedInstanceId, $stateVersion] = DB::transaction(function () use ($room, $player, $instanceId): array {
$lockedRoom = Room::query()
->lockForUpdate()
->findOrFail($room->id);
$lockedPlayer = $lockedRoom->players()
->lockForUpdate()
->findOrFail($player->id);
if ($lockedPlayer->active_instance_id === $instanceId) {
return [$lockedPlayer, null, null];
}
$replacedInstanceId = $lockedPlayer->active_instance_id;
$lockedPlayer->update([
'active_instance_id' => $instanceId,
'last_seen_at' => now(),
]);
if ($replacedInstanceId === null) {
return [$lockedPlayer, null, null];
}
$lockedRoom->update([
'last_activity_at' => now(),
'state_version' => $lockedRoom->state_version + 1,
]);
return [$lockedPlayer, $replacedInstanceId, $lockedRoom->state_version];
});
if (is_string($replacedInstanceId) && is_int($stateVersion)) {
RoomStateChanged::dispatch(
$room->id,
$stateVersion,
RoomStateChange::PlayerInstanceReplaced,
$this->realtimeState->for($room),
$activePlayer->id,
$replacedInstanceId,
);
}
return $room->players()
->where('user_id', $user->id)
->lockForUpdate()
->first();
return $activePlayer;
}
public function kick(