*/ class TopicManager extends WebsocketManager implements TopicManagerInterface { /** @var ClientManipulatorInterface $clientManipulator */ protected $clientManipulator; /** @var EntityManagerInterface $entityManager */ protected $entityManager; /** @var RequestStack $requestStack */ protected $requestStack; /** @var LoggerInterface $logger */ protected $logger; /** * TopicManager constructor. * * @param ClientManipulatorInterface $clientManipulator * @param EntityManagerInterface $entityManager * @param RequestStack $requestStack * @param LoggerInterface $logger */ public function __construct( ClientManipulatorInterface $clientManipulator, EntityManagerInterface $entityManager, RequestStack $requestStack, LoggerInterface $logger ) { $this->clientManipulator = $clientManipulator; $this->entityManager = $this->reConnect($entityManager); $this->requestStack = $requestStack; $this->logger = $logger; parent::__construct($logger); } /** * {@inheritDoc} */ public function subscribe(Topic $topic, ConnectionInterface $connection): void { /** this will broadcast the message to ALL subscribers of this topic. */ $user = $this->clientManipulator->getClient($connection); $userName = $user->getUserIdentifier() ?: 'anon_' . $connection->resourceId; /** if more user wants to connect than 2 to one channel */ if ($topic->count() > 2) { $topic->remove($connection); } else { $users = $this->controlUsers($topic, $userName, $user); $topic->broadcast([ 'userTopicId' => $connection->resourceId, 'channel' => $topic->getId(), 'user' => $userName, 'userCnt' => $topic->count(), 'users' => $users ]); } } /** * {@inheritDoc} */ public function unSubscribe(Topic $topic, ConnectionInterface $connection): void { /** This will broadcasts the message to ALL subscribers of this topic. */ $topic->broadcast(array('msg' => $connection->resourceId . ' has left ' . $topic->getId())); } /** * {@inheritDoc} */ public function publish(Topic $topic, ConnectionInterface $connection, $event): void { $user = $this->clientManipulator->getClient($connection); $userName = $user->getUserIdentifier(); /** Save every step by user to db */ null === $event['resign'] ? $this->saveStepToDb($topic, $event) : $this->saveResignToDb($topic, $event['resign']); $topic->broadcast([ 'userTopicId' => $connection->resourceId, 'channel' => $topic->getId(), 'user' => $userName, 'userCnt' => $topic->count(), 'data' => $event ]); } /** * Save Resign event to database * * @param $topic * @param $color */ private function saveResignToDb(Topic $topic, $color): void { $gameAssoc = explode('/', $topic->getId())[2]; /** @var PlayedGame $playedGame */ $playedGame = $this->entityManager ->getRepository(PlayedGame::class) ->findOneByGameAssoc($gameAssoc); $playedGame->setResign($color); $this->entityManager->persist($playedGame); $this->entityManager->flush(); } /** * Save steps and point information to database * * @param $topic * @param $event */ private function saveStepToDb(Topic $topic, $event): void { try { $gameAssoc = explode('/', $topic->getId())[2]; /** @var PlayedGame $playedGame */ $playedGame = $this->entityManager ->getRepository(PlayedGame::class) ->findOneByGameAssoc($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()); } } /** * Control all users in a channel * * @param Topic $topic * @param string $userName * @param $user * * @return array */ private function controlUsers(Topic $topic, string $userName, TokenInterface $user): array { $gameAssoc = explode('/', $topic->getId())[2]; /** @var PlayedGame $playedGame */ $playedGame = $this->entityManager ->getRepository(PlayedGame::class) ->findOneByGameAssoc($gameAssoc); /** @var $users {array} */ $users = $this->getUserCollection($playedGame); $red = '' !== $users['red'] || '' !== $users['redAnon'] ? 1 : 0; $blue = '' !== $users['blue'] || '' !== $users['blueAnon'] ? 1 : 0; $one = $topic->count() === 1; $two = $topic->count() === 2; /** This checks it is a reconnection */ if (($one && ($red + $blue === 0)) || ($two && ($red + $blue === 1))) { /** @var $users {array} w/ save users to database */ $users = $this->saveUserToDb($topic, $userName, $user, $topic->count()); } return $users; } /** * Save user data to database * * @param $topic * @param $userName * @param $user * @param $count * * @return array */ private function saveUserToDb(Topic $topic, string $userName, TokenInterface $user, $count) { $gameAssoc = explode('/', $topic->getId())[2]; /** @var PlayedGame $playedGame */ $playedGame = $this->entityManager ->getRepository(PlayedGame::class) ->findOneByGameAssoc($gameAssoc); /** when the user is not anonym */ null !== $user->getUser() ? $this->saveRegisteredUser($userName, $count, $playedGame) : $this->saveAnonUser($userName, $count, $playedGame); $this->entityManager->persist($playedGame); $this->entityManager->flush(); return $this->getUserCollection($playedGame); } /** * Saves the registered user to the database * * @param string $userName * @param int $count * @param PlayedGame $playedGame */ private function saveRegisteredUser(string $userName, int $count, PlayedGame $playedGame) { /** @var User $FOSUser */ $user = $this->entityManager ->getRepository(User::class) ->findOneByUsername($userName); try { if ($count === 1) { /** @var $random {integer} Active player: red: 0, blue: 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()); } } /** * Save anonymous Gamer to database * * @param string $userName * @param int $count * @param PlayedGame $playedGame */ private function saveAnonUser(string $userName, int $count, PlayedGame $playedGame) { // $request = $this->requestStack->getCurrentRequest(); // TODO nem megy... try { $anon = new Gamer(); $anon->setUsername($userName); $anon->setConnTimestamp(new DateTime()); $this->entityManager->persist($anon); if ($count === 1) { /** @var $random {integer} Active player: red: 0, blue: 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()); } } /** * Get user collection from PlayedGame entity * * @param $playedGame * * @return array */ private function getUserCollection(PlayedGame $playedGame): array { return array( '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() : '' ); } }