Private
Public Access
1
0
Files
MineSeeker/src/Util/TopicManager.php

241 lines
8.0 KiB
PHP
Raw Normal View History

<?php declare(strict_types=1);
/**
* This file is part of the SplendidBear Websites' projects.
*
* Copyright (c) 2019 @ www.splendidbear.org
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Util;
use App\Entity\Gamer;
use App\Entity\PlayedGame;
use App\Entity\Step;
use App\Entity\User;
use App\Interfaces\TopicManagerInterface;
use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use Exception;
use RuntimeException;
use JsonException;
use Psr\Log\LoggerInterface;
use Symfony\Component\Mercure\HubInterface;
use Symfony\Component\Mercure\Update;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* Class TopicManager
*
* @package App\Util
* @author Lang <https://www.splendidbear.org>
* @category Class
* @license https://www.gnu.org/licenses/lgpl-3.0.en.html GNU Lesser General Public License
* @link www.splendidbear.org
* @since 2026. 04. 09.
*/
class TopicManager implements TopicManagerInterface
{
public function __construct(
private readonly HubInterface $hub,
private readonly EntityManagerInterface $entityManager,
private readonly LoggerInterface $logger
) {
}
public function subscribe(string $gameAssoc, string $userName, ?UserInterface $user): void
{
$playedGame = $this->getPlayedGame($gameAssoc);
if (null === $playedGame) {
return;
}
$users = $this->getUserCollection($playedGame);
$count = $this->getPlayerCount($users);
$isKnown = in_array($userName, array_filter(array_values($users)), true);
/** Reject a third player who is not a reconnecting player */
if ($count >= 2 && !$isKnown) {
return;
}
/** Save the player to the database on a fresh join */
if (!$isKnown && $count < 2) {
$users = $this->saveUserToDb($gameAssoc, $userName, $user, $count + 1);
$count = $this->getPlayerCount($users);
}
$topic = 'mineseeker/channel/' . $gameAssoc;
try {
$this->hub->publish(new Update(
$topic,
json_encode([
'userTopicId' => $userName,
'channel' => $topic,
'user' => $userName,
'userCnt' => $count,
'users' => $users,
], JSON_THROW_ON_ERROR)
));
} catch (JsonException $e) {
throw new RuntimeException($e->getMessage());
}
}
public function unSubscribe(string $gameAssoc, string $userName): void
{
$topic = 'mineseeker/channel/' . $gameAssoc;
$this->hub->publish(new Update(
$topic,
json_encode(['msg' => $userName . ' has left ' . $topic])
));
}
public function publish(string $gameAssoc, string $userName, array $event): void
{
null === $event['resign']
? $this->saveStepToDb($gameAssoc, $event)
: $this->saveResignToDb($gameAssoc, $event['resign']);
$playedGame = $this->getPlayedGame($gameAssoc);
$users = $this->getUserCollection($playedGame);
$count = $this->getPlayerCount($users);
$topic = 'mineseeker/channel/' . $gameAssoc;
try {
$this->hub->publish(new Update(
$topic,
json_encode([
'userTopicId' => $userName,
'channel' => $topic,
'user' => $userName,
'userCnt' => $count,
'data' => $event,
], JSON_THROW_ON_ERROR)
));
} catch (JsonException $e) {
throw new RuntimeException($e->getMessage());
}
}
private function getPlayedGame(string $gameAssoc): ?PlayedGame
{
return $this->entityManager
->getRepository(PlayedGame::class)
->findOneByGameAssoc($gameAssoc);
}
private function getPlayerCount(array $users): int
{
$red = '' !== $users['red'] || '' !== $users['redAnon'] ? 1 : 0;
$blue = '' !== $users['blue'] || '' !== $users['blueAnon'] ? 1 : 0;
return $red + $blue;
}
private function saveResignToDb(string $gameAssoc, string $color): void
{
$playedGame = $this->getPlayedGame($gameAssoc);
$playedGame->setResign($color);
$this->entityManager->persist($playedGame);
$this->entityManager->flush();
}
private function saveStepToDb(string $gameAssoc, array $event): void
{
try {
$playedGame = $this->getPlayedGame($gameAssoc);
$step = new Step();
$step->setRow($event['coords'][0]);
$step->setCol($event['coords'][1]);
$step->setWBomb($event['bomb']);
$step->setPlayedGame($playedGame);
$step->setCreated(new DateTime());
$this->entityManager->persist($step);
$playedGame->setBluePoints($event['bluePoints']);
$playedGame->setRedPoints($event['redPoints']);
$playedGame->setBlueExplodedBomb($event['blueExplodedBomb'] ? true : null);
$playedGame->setRedExplodedBomb($event['redExplodedBomb'] ? true : null);
$playedGame->setUpdated(new DateTime());
$this->entityManager->persist($playedGame);
$this->entityManager->flush();
} catch (Exception $e) {
$this->logger->error($e->getMessage());
}
}
private function saveUserToDb(string $gameAssoc, string $userName, ?UserInterface $user, int $count): array
{
$playedGame = $this->getPlayedGame($gameAssoc);
null !== $user
? $this->saveRegisteredUser($userName, $count, $playedGame)
: $this->saveAnonUser($userName, $count, $playedGame);
$this->entityManager->persist($playedGame);
$this->entityManager->flush();
return $this->getUserCollection($playedGame);
}
private function saveRegisteredUser(string $userName, int $count, PlayedGame $playedGame): void
{
/** @var User $user */
$user = $this->entityManager
->getRepository(User::class)
->findOneByUsername($userName);
try {
if ($count === 1) {
$random = random_int(0, 1);
!$random ? $playedGame->setRed($user) : $playedGame->setBlue($user);
} else {
null === $playedGame->getRed() && null === $playedGame->getRedAnon()
? $playedGame->setRed($user)
: $playedGame->setBlue($user);
}
} catch (Exception $e) {
$this->logger->error($e->getMessage());
}
}
private function saveAnonUser(string $userName, int $count, PlayedGame $playedGame): void
{
try {
$anon = new Gamer();
$anon->setUsername($userName);
$anon->setConnTimestamp(new DateTime());
$this->entityManager->persist($anon);
if ($count === 1) {
$random = random_int(0, 1);
!$random ? $playedGame->setRedAnon($anon) : $playedGame->setBlueAnon($anon);
} else {
null === $playedGame->getRed() && null === $playedGame->getRedAnon()
? $playedGame->setRedAnon($anon)
: $playedGame->setBlueAnon($anon);
}
} catch (Exception $e) {
$this->logger->error($e->getMessage());
}
}
private function getUserCollection(PlayedGame $playedGame): array
{
return [
'red' => null !== $playedGame->getRed() ? $playedGame->getRed()->getUsername() : '',
'blue' => null !== $playedGame->getBlue() ? $playedGame->getBlue()->getUsername() : '',
'redAnon' => null !== $playedGame->getRedAnon() ? $playedGame->getRedAnon()->getUserName() : '',
'blueAnon' => null !== $playedGame->getBlueAnon() ? $playedGame->getBlueAnon()->getUserName() : '',
];
}
}