Private
Public Access
1
0

chg: dev: refactor Rpc and Topic classes #3

This commit is contained in:
2019-10-27 18:51:28 +01:00
parent 8355cc90ed
commit 2daab7140e
8 changed files with 767 additions and 414 deletions

View File

@@ -0,0 +1,35 @@
<?php
/**
* 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\Interfaces;
/**
* Interface RpcManagerInterface
*/
interface RpcManagerInterface
{
/**
* Gets all connect informations
*
* @param $params
*
* @return string
*/
public function getConnectInformation($params): string;
/**
* It saves the whole grid table to database
*
* @param $data
*
* @return boolean
*/
public function saveGrid($data): bool;
}

View File

@@ -0,0 +1,45 @@
<?php
/**
* 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\Interfaces;
use Ratchet\ConnectionInterface;
use Ratchet\Wamp\Topic;
/**
* Interfaces TopicManagerInterface
*/
interface TopicManagerInterface
{
/**
* It handles the subscribe to a topic
*
* @param Topic $topic
* @param ConnectionInterface $connection
*/
public function subscribe(Topic $topic, ConnectionInterface $connection): void;
/**
* It handles the unsibscribe from the topic
*
* @param Topic $topic
* @param ConnectionInterface $connection
*/
public function unSubscribe(Topic $topic, ConnectionInterface $connection): void;
/**
* It publishes events on the topic
*
* @param Topic $topic
* @param ConnectionInterface $connection
* @param $event
*/
public function publish(Topic $topic, ConnectionInterface $connection, $event): void;
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* 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\Interfaces;
use Doctrine\ORM\EntityManagerInterface;
/**
* Interfaces WebsocketManagerInterface
*/
interface WebsocketManagerInterface
{
/**
* Handle prod MySQL timeout
*
* @param EntityManagerInterface $entityManager
*
* @return EntityManagerInterface|null
*/
public function reConnect(EntityManagerInterface $entityManager): ?EntityManagerInterface;
}

182
src/Util/RpcManager.php Normal file
View File

@@ -0,0 +1,182 @@
<?php
/**
* 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\Grid;
use App\Entity\GridRow;
use App\Entity\PlayedGame;
use App\Util\Interfaces\RpcManagerInterface;
use DateTime;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\ORMException;
use Exception;
use Psr\Log\LoggerInterface;
/**
* Class RpcManager
*
* @package App\Utils
* @author system7 <https://www.splendidbear.org>
*/
class RpcManager extends WebsocketManager implements RpcManagerInterface
{
/** @var EntityManager $em */
protected $entityManager;
/** @var LoggerInterface $logger */
private $logger;
/**
* MineseekerRpc constructor.
*
* @param EntityManagerInterface $entityManager
* @param LoggerInterface $logger
*/
public function __construct(EntityManagerInterface $entityManager, LoggerInterface $logger)
{
$this->entityManager = $this->reConnect($entityManager);
$this->logger = $logger;
parent::__construct($logger);
}
/**
* {@inheritDoc}
*/
public function getConnectInformation($params): string
{
$grid = $this->getGrid($params);
$users = null !== $grid ? $this->getUsers($params) : null;
return base64_encode(json_encode(array(
'grid' => $grid,
'users' => $users
), JSON_THROW_ON_ERROR, 512));
}
/**
* {@inheritDoc}
*/
public function saveGrid($data): bool
{
$playedGame = new PlayedGame();
$grid = new Grid();
$rows = json_decode(base64_decode($data[0]), true, 512, JSON_THROW_ON_ERROR);
try {
foreach ($rows as $row) {
$gridRow = new GridRow();
$gridRow->setGridCol($row);
/** Save Row */
$gridRow->setGrid($grid);
$this->entityManager->persist($gridRow);
}
/** Save Grid */
$grid->setPlayedGame($playedGame);
$this->entityManager->persist($grid);
/** Save PlayedGame */
$playedGame->setGameAssoc($data[1]);
$playedGame->setGrid($grid);
$playedGame->setCreated(new DateTime());
$playedGame->setUpdated(new DateTime());
$this->entityManager->persist($playedGame);
$this->entityManager->flush();
} catch (ORMException $e) {
$this->logger->error($e->getMessage());
} catch (Exception $e) {
$this->logger->error($e->getMessage());
}
return true;
}
/**
* It gets the current Grid by PlayedGame/gameAssoc
*
* @param $gameAssoc
*
* @return array
*/
private function getGrid($gameAssoc): ?array
{
$gridCols = array();
try {
$this->entityManager->clear();
/** @var PlayedGame $playedGame */
$playedGame = $this->entityManager
->getRepository(PlayedGame::class)
->findOneByGameAssoc($gameAssoc);
if (null === $playedGame) {
return null;
}
if (null === $rows = $playedGame->getGrid()) {
return null;
}
$rows = $rows->getGridRow();
/** @var GridRow $row */
foreach ($rows as $row) {
$gridCols[] = $row->getGridCol();
}
return $gridCols;
} catch (Exception $e) {
$this->logger->error($e->getMessage());
}
return null;
}
/**
* Get the Users by PlayedGame
*
* @param $gameAssoc
*
* @return array
*/
private function getUsers($gameAssoc): array
{
return $this->getUserCollection(
$this->entityManager
->getRepository(PlayedGame::class)
->findOneByGameAssoc($gameAssoc)
);
}
/**
* Get user collection from PlayedGame entity
*
* @param PlayedGame $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() : ''
);
}
}

328
src/Util/TopicManager.php Normal file
View File

@@ -0,0 +1,328 @@
<?php
/**
* 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\Application\Sonata\UserBundle\Entity\User;
use App\Entity\Gamer;
use App\Entity\PlayedGame;
use App\Entity\Step;
use App\Util\Interfaces\TopicManagerInterface;
use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use Exception;
use Gos\Bundle\WebSocketBundle\Client\ClientManipulatorInterface;
use Psr\Log\LoggerInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Wamp\Topic;
use Symfony\Component\HttpFoundation\RequestStack;
/**
* Class TopicManager
*
* @package App\Util
* @author system7 <https://www.splendidbear.org>
*/
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 = 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
]);
}
}
/**
* {@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 = is_string($user) ? $user : $user->getUsername();
/** 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, $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, $user, $count)
{
$gameAssoc = explode('/', $topic->getId())[2];
/** @var PlayedGame $playedGame */
$playedGame = $this->entityManager
->getRepository(PlayedGame::class)
->findOneByGameAssoc($gameAssoc);
/** when the user is not anonym */
!is_string($user)
? $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() : ''
);
}
}

View File

@@ -0,0 +1,57 @@
<?php
/**
* 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\Util\Interfaces\WebsocketManagerInterface;
use Doctrine\DBAL\Driver\PDOException;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
/**
* Class WebsocketManager
*
* @package App\Util
* @author system7 <https://www.splendidbear.org>
*/
class WebsocketManager implements WebsocketManagerInterface
{
/** @var LoggerInterface $logger */
private $logger;
/**
* WebsocketManager constructor.
*
* @param LoggerInterface $logger
*/
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
/**
* {@inheritDoc}
*/
public function reConnect(EntityManagerInterface $entityManager): ?EntityManagerInterface
{
try {
$connection = $entityManager->getConnection();
if (false === $connection->ping()) {
$connection->close();
$connection->connect();
}
} catch (PDOException $e) {
$this->logger->error($e->getMessage());
}
return $entityManager;
}
}