Broadcast game_finished when a player's own timeout check catches it

Previously only the cron's timeout sweep broadcast to everyone;
check-finished (called by a player's own client the moment their
local countdown hits zero) just updated the database silently. Now
whichever path notices the timeout first broadcasts - both only act
while the session is still PLAYING, so there's no double broadcast.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Frank
2026-08-16 17:56:24 +02:00
co-authored by Claude Sonnet 5
parent 2951a39204
commit aba79251e0
+12 -1
View File
@@ -12,6 +12,8 @@ use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Mercure\HubInterface;
use Symfony\Component\Mercure\Update;
#[Route('/game/api', name: 'game_api_')]
final class GameApiController extends AbstractController
@@ -19,7 +21,8 @@ final class GameApiController extends AbstractController
public function __construct(
protected GameResponseService $gameResponseService,
private EntityManagerInterface $entityManager
private EntityManagerInterface $entityManager,
private HubInterface $hub,
) {
}
@@ -46,6 +49,14 @@ final class GameApiController extends AbstractController
$session->setFinishedAt(new \DateTime());
$this->entityManager->persist($session);
$this->entityManager->flush();
try {
$topic = '/game/hub/' . $session->getId();
$this->hub->publish(new Update($topic, json_encode(['type' => 'game_finished', 'status' => 'lost'])));
} catch (\Exception $e) {
// Mercure might be down
}
$isFinished = true;
}
} elseif ($session->getStatus() === SessionStatus::LOST || $session->getStatus() === SessionStatus::WON) {