clientManipulator = $clientManipulator; $this->em = $entityManager; $this->requestStack = $requestStack; } /** * This will receive any Subscription requests for this topic. * * @param ConnectionInterface $connection * @param Topic $topic * @param WampRequest $request * @return void */ public function onSubscribe(ConnectionInterface $connection, Topic $topic, WampRequest $request) { /** this will broadcast the message to ALL subscribers of this topic. */ $user = $this->clientManipulator->getClient($connection); $userName = is_string($user) ? $user : $user->getUsername(); /** 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, 'steps' => $this->getSteps($topic), ]); } } /** * This will receive any UnSubscription requests for this topic. * * @param ConnectionInterface $connection * @param Topic $topic * @param WampRequest $request * @return void */ public function onUnSubscribe(ConnectionInterface $connection, Topic $topic, WampRequest $request) { /** this will broadcast the message to ALL subscribers of this topic. */ $topic->broadcast(['msg' => $connection->resourceId . " has left " . $topic->getId()]); } /** * This will receive any Publish requests for this topic. * * @param ConnectionInterface $connection * @param Topic $topic * @param WampRequest $request * @param $event * @param array $exclude * @param array $eligible * @return mixed|void * @internal param Topic $Topic * @internal param array $eligibles */ public function onPublish(ConnectionInterface $connection, Topic $topic, WampRequest $request, $event, array $exclude, array $eligible) { $user = $this->clientManipulator->getClient($connection); $userName = is_string($user) ? $user : $user->getUsername(); /** Save every step by user to db */ if (null === $event['resign']) { $this->saveStepToDb($topic, $event); } else { $this->saveResignToDb($topic, $event['resign']); } $topic->broadcast([ 'userTopicId' => $connection->resourceId, 'channel' => $topic->getId(), 'user' => $userName, 'userCnt' => $topic->count(), 'data' => $event ]); } /** * Like RPC is will use to prefix the channel * * @return string */ public function getName() { return 'mineseeker.topic'; } /** * Save Resign event to database * * @param $topic * @param $color */ private function saveResignToDb($topic, $color) { $this->reConnect(); $gameAssoc = explode('/', $topic->getId())[2]; $playedGame = $this->em ->getRepository('MineSeekerBundle:PlayedGame') ->findOneByGameAssoc($gameAssoc); $playedGame->setResign($color); $this->em->persist($playedGame); $this->em->flush(); } /** * Save steps and point information to database * * @param $topic * @param $event */ private function saveStepToDb($topic, $event) { $this->reConnect(); $gameAssoc = explode('/', $topic->getId())[2]; $playedGame = $this->em ->getRepository('MineSeekerBundle:PlayedGame') ->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->em->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->em->persist($playedGame); $this->em->flush(); } private function getSteps($topic) { $this->reConnect(); $gameAssoc = explode('/', $topic->getId())[2]; $playedGame = $this->em ->getRepository('MineSeekerBundle:PlayedGame') ->findOneByGameAssoc($gameAssoc); $steps = array(); foreach ($playedGame->getStep()->toArray() as $item) { $steps[] = array( 'row' => $item->getRow(), 'col' => $item->getCol(), 'wBomb' => $item->getWBomb(), ); } return base64_encode(json_encode($steps)); } /** * Control all users in a channel * * @param $topic * @param $userName * @param $user * @return array */ private function controlUsers($topic, $userName, $user) { $this->reConnect(); $gameAssoc = explode('/', $topic->getId())[2]; $playedGame = $this->em ->getRepository('MineSeekerBundle:PlayedGame') ->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($playedGame, $userName, $user, $topic->count()); } return $users; } /** * Save user data to database * * @param $playedGame * @param $userName * @param $user * @param $count * @return array */ private function saveUserToDb($playedGame, $userName, $user, $count) { $this->reConnect(); /** the user is not anonym */ if (!is_string($user)) { $FOSUser = $this->em ->getRepository('JotunheimrUserBundle:User') ->findOneByUsername($userName); if ($count == 1) { /** @var $random {integer} Active player: red: 0, blue: 1 */ $random = rand(0, 1); !$random ? $playedGame->setRed($FOSUser) : $playedGame->setBlue($FOSUser); } else { null === $playedGame->getRed() && null === $playedGame->getRedAnon() ? $playedGame->setRed($FOSUser) : $playedGame->setBlue($FOSUser); } } else { // $request = $this->requestStack->getCurrentRequest(); // TODO nem megy... $anon = new Gamer(); $anon->setUserName($userName); $anon->setConnTimestamp(new \DateTime()); $this->em->persist($anon); if ($count == 1) { /** @var $random {integer} Active player: red: 0, blue: 1 */ $random = rand(0, 1); !$random ? $playedGame->setRedAnon($anon) : $playedGame->setBlueAnon($anon); } else { null === $playedGame->getRed() && null === $playedGame->getRedAnon() ? $playedGame->setRedAnon($anon) : $playedGame->setBlueAnon($anon); } } $this->em->persist($playedGame); $this->em->flush(); return $this->getUserCollection($playedGame); } /** * Get user collection from PlayedGame entity * * @param $playedGame * @return array */ private function getUserCollection($playedGame) { 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() : '' ); } /** * Handle prod MySQL timeout */ private function reConnect() { try { $connection = $this->em->getConnection(); if (false === $connection->ping()) { $connection->close(); $connection->connect(); } } catch (PDOException $ex) { throw PDOException::class; } } }