Private
Public Access
1
0

ssl handling #22 && reconnection issues #20, #21

This commit is contained in:
2016-11-30 20:15:56 +01:00
parent e6264c4eb0
commit 50b3663889
10 changed files with 199 additions and 57 deletions

View File

@@ -3,6 +3,7 @@
namespace Mine\SeekerBundle\Controller; namespace Mine\SeekerBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
class GameController extends Controller class GameController extends Controller
{ {
@@ -11,10 +12,11 @@ class GameController extends Controller
return $this->render('MineSeekerBundle:Game:index.html.twig'); return $this->render('MineSeekerBundle:Game:index.html.twig');
} }
public function playAction() public function playAction(Request $request)
{ {
return $this->render('MineSeekerBundle:Game:play.html.twig', array( return $this->render('MineSeekerBundle:Game:play.html.twig', array(
'env' => $this->container->getParameter('kernel.environment') 'env' => $this->container->getParameter('kernel.environment'),
'ssl' => $request->isSecure() ? 'true' : 'false'
)); ));
} }

View File

@@ -74,6 +74,13 @@ class Gamer
*/ */
private $userAgent; private $userAgent;
/**
* @var \DateTime
*
* @ORM\Column(name="conn_timestamp", type="datetime", nullable=false)
*/
private $connTimestamp;
/** /**
* Get id * Get id
@@ -180,4 +187,28 @@ class Gamer
{ {
return $this->userAgent; return $this->userAgent;
} }
/**
* Set connTimestamp
*
* @param \DateTime $connTimestamp
*
* @return Gamer
*/
public function setConnTimestamp($connTimestamp)
{
$this->connTimestamp = $connTimestamp;
return $this;
}
/**
* Get connTimestamp
*
* @return \DateTime
*/
public function getConnTimestamp()
{
return $this->connTimestamp;
}
} }

View File

@@ -74,6 +74,13 @@ class Gamer
*/ */
private $userAgent; private $userAgent;
/**
* @var \DateTime
*
* @ORM\Column(name="conn_timestamp", type="datetime", nullable=false)
*/
private $connTimestamp;
/** /**
* Get id * Get id

View File

@@ -405,4 +405,28 @@ class PlayedGame
{ {
return $this->step; return $this->step;
} }
/**
* Set resign
*
* @param string $resign
*
* @return PlayedGame
*/
public function setResign($resign)
{
$this->resign = $resign;
return $this;
}
/**
* Get resign
*
* @return string
*/
public function getResign()
{
return $this->resign;
}
} }

View File

@@ -4,6 +4,7 @@ import MineSeeker from './mine-seeker/app';
ReactDOM.render( ReactDOM.render(
<MineSeeker env={document.getElementById('mine-wrapper').dataset.env} <MineSeeker env={document.getElementById('mine-wrapper').dataset.env}
gameId={document.getElementById('mine-wrapper').dataset.gameId}/>, gameId={document.getElementById('mine-wrapper').dataset.gameId}
ssl={document.getElementById('mine-wrapper').dataset.ssl}/>,
document.getElementById('mine-wrapper') document.getElementById('mine-wrapper')
); );

View File

@@ -11,13 +11,15 @@ class MineSeeker extends React.Component {
this.state = { this.state = {
env: props.env, env: props.env,
ssl: props.ssl,
gameInherited: props.gameId !== '', gameInherited: props.gameId !== '',
gameAssoc: gameAssoc, gameAssoc: gameAssoc,
channel: channel, channel: channel,
session: null, session: null,
createGrid: false, createGrid: false,
stepCache: [], stepCache: [],
disconnect: false connectionLost: false,
end: false
} }
} }
@@ -30,7 +32,12 @@ class MineSeeker extends React.Component {
return text; return text;
} }
/** STEP */ /**
* STEP
*
* @param coords
* @returns {{red: *, blue: *}}
*/
makePointsCalcAndStep(coords) { makePointsCalcAndStep(coords) {
let users = this.refs.gridControl.refs.userControl, let users = this.refs.gridControl.refs.userControl,
activePlayer = users.state.activePlayer ? 'blue' : 'red', activePlayer = users.state.activePlayer ? 'blue' : 'red',
@@ -51,7 +58,38 @@ class MineSeeker extends React.Component {
return {red: redPoints, blue: bluePoints}; return {red: redPoints, blue: bluePoints};
} }
/** THE END */ /**
* START
*
* @param payload
*/
makeGameStart(payload) {
/** every time the blue starts */
this.refs.gridControl.refs.userControl.setState({activePlayer: 1});
/** Set up player names w/ server data */
this.refs.gridControl.refs.userControl.refs.red.setState({
name: payload.users.red !== '' ? payload.users.red : payload.users.redAnon,
});
this.refs.gridControl.refs.userControl.refs.blue.setState({
name: payload.users.blue !== '' ? payload.users.blue : payload.users.blueAnon,
desc: this.refs.gridControl.state.webPlayer === 'blue'
? this.refs.gridControl.state.desc.you
: this.refs.gridControl.state.desc.buddy,
active: true,
});
this.refs.gridControl.setState({overlay: false});
}
/**
* THE END
*
* @param bluePoints
* @param redPoints
* @param resign
*/
makeGameEndIfItEnds(bluePoints, redPoints, resign = false) { makeGameEndIfItEnds(bluePoints, redPoints, resign = false) {
let redWins = redPoints > 25, let redWins = redPoints > 25,
blueWins = bluePoints > 25; blueWins = bluePoints > 25;
@@ -86,10 +124,13 @@ class MineSeeker extends React.Component {
: "You WIN!" : "You WIN!"
}); });
this.setState({end: true});
this.makeGameEndIfItEnds(0, 0, true); this.makeGameEndIfItEnds(0, 0, true);
} }
clickResign() { clickResign() {
/** PUBLISH */
this.state.session.publish(this.state.channel, { this.state.session.publish(this.state.channel, {
'resign': this.refs.gridControl.refs.userControl.state.activePlayer ? 'blue' : 'red' 'resign': this.refs.gridControl.refs.userControl.state.activePlayer ? 'blue' : 'red'
}); });
@@ -119,13 +160,13 @@ class MineSeeker extends React.Component {
} }
} }
wInit(session, gridServer, gridClient) { wInit(session, data, gridClient) {
this.setState({session: session}); this.setState({session: session});
/** save session to GridControl */ /** save session to GridControl */
/** render grid fields - #12 */ /** render grid fields - #12 */
this.refs.gridControl.setState({ this.refs.gridControl.setState({
grid: this.state.gameInherited ? JSON.parse(Base64.decode(gridServer)) : gridClient, grid: this.state.gameInherited ? JSON.parse(Base64.decode(data))['grid'] : gridClient,
channel: this.state.channel, channel: this.state.channel,
desc: { desc: {
buddy: <div> buddy: <div>
@@ -157,39 +198,31 @@ class MineSeeker extends React.Component {
}); });
} }
wSubscribe(payload) { wSubscribe(payload, rpcUsers = null) {
this.state.env === 'dev' && console.info( this.state.env === 'dev' && console.info(
(typeof payload.user !== 'undefined' ? payload.user : 'user') + " has been subscribed to the channel!" (typeof payload.user !== 'undefined' ? payload.user : 'user') + " has been subscribed to the channel!"
); );
if (!this.state.disconnect) { let firstUser = !rpcUsers;
/** setup the web player */
null === this.refs.gridControl.state.webPlayer && this.refs.gridControl.setState({
webPlayer: payload.user === payload.users.blue || payload.user === payload.users.blueAnon
? 'blue'
: 'red'
});
/** every user has been came */ this.refs.gridControl.state.webPlayer === null && this.refs.gridControl.setState({
if (payload.userCnt === 2) { webPlayer: payload.user === payload.users.blue ||
/** every time the blue starts */ (
this.refs.gridControl.refs.userControl.setState({activePlayer: 1}); firstUser && payload.users.blueAnon !== '' ||
!firstUser && (rpcUsers.blueAnon === '' && rpcUsers.blue === '')
)
? 'blue' : 'red'
});
/** Set up player names w/ server data */ /** every user has been came */
this.refs.gridControl.refs.userControl.refs.red.setState({ if (
name: payload.users.red !== '' ? payload.users.red : payload.users.redAnon, payload.userCnt === 2 &&
}); (
!this.state.connectionLost ||
this.refs.gridControl.refs.userControl.refs.blue.setState({ this.state.connectionLost && false === this.refs.gridControl.refs.userControl.state.activePlayer && !this.state.end
name: payload.users.blue !== '' ? payload.users.blue : payload.users.blueAnon, )
desc: this.refs.gridControl.state.webPlayer === 'blue' ) {
? this.refs.gridControl.state.desc.you this.makeGameStart(payload);
: this.refs.gridControl.state.desc.buddy,
active: true,
});
this.refs.gridControl.setState({overlay: false});
}
} }
} }
@@ -226,7 +259,7 @@ class MineSeeker extends React.Component {
} }
/** Connect - Subscribe */ /** Connect - Subscribe */
subscribe() { subscribe(rpcUsers = null) {
this.state.session.subscribe( this.state.session.subscribe(
this.state.channel, this.state.channel,
(uri, payload, log) => { (uri, payload, log) => {
@@ -238,30 +271,31 @@ class MineSeeker extends React.Component {
this.wTopic(payload); this.wTopic(payload);
} else { } else {
if (isNotUnsubscribe) { if (isNotUnsubscribe) {
this.wSubscribe(payload); this.wSubscribe(payload, rpcUsers);
} else { } else {
this.wUnsubscribe(payload); this.wUnsubscribe(payload);
} }
} }
/** RECONNECTION */ /** RECONNECTION */
if (payload.userCnt === 2 && this.state.disconnect) { if (payload.userCnt === 2 && this.state.connectionLost) {
this.state.env === 'dev' && console.info('Reconnection process'); this.state.env === 'dev' && console.info('Reconnection process');
/** PUBLISH */
let cache = this.state.stepCache; let cache = this.state.stepCache;
cache.forEach((item) => this.state.session.publish(this.state.channel, item)); cache.forEach((item) => this.state.session.publish(this.state.channel, item));
this.setState({disconnect: false, stepCache: []}); this.setState({connectionLost: false, stepCache: []});
} }
}); });
} }
/** after rendering */ /** After rendering */
componentDidMount() { componentDidMount() {
/** Create Websocket w/ Bahnhof.js */ /** Create Websocket w/ Bahnhof.js */
let websocket = WS.connect( let websocket = WS.connect(
this.state.env === 'dev' this.state.env === 'dev'
? "ws://mine.dev:6450" ? "ws://mine.dev:6450"
: "ws://www.mineseeker.ninja:6450" : (this.state.ssl === 'true' ? "wss" : "ws") + "://www.mineseeker.ninja:6450"
); );
/** /**
@@ -271,7 +305,7 @@ class MineSeeker extends React.Component {
websocket.on("socket/connect", (session) => { websocket.on("socket/connect", (session) => {
this.state.env === 'dev' && console.info("Successfully connected to the Server!"); this.state.env === 'dev' && console.info("Successfully connected to the Server!");
if (!this.state.disconnect) { if (!this.state.connectionLost) {
let gridClient = this.state.gameInherited || new Grid().state.grid; let gridClient = this.state.gameInherited || new Grid().state.grid;
/** /**
@@ -284,11 +318,11 @@ class MineSeeker extends React.Component {
this.state.gameInherited ? this.state.gameAssoc : [Base64.encode(JSON.stringify(gridClient)), this.state.gameAssoc] this.state.gameInherited ? this.state.gameAssoc : [Base64.encode(JSON.stringify(gridClient)), this.state.gameAssoc]
) )
.then( .then(
(gridServer) => { (data) => {
this.state.env === 'dev' && console.info("Grid has been created! Return w/ gameAssoc."); this.state.env === 'dev' && console.info('RPC has been called');
this.wInit(session, gridServer, gridClient); this.wInit(session, data, gridClient);
this.subscribe(); this.subscribe(this.state.gameInherited && JSON.parse(Base64.decode(data))['users']);
}, },
(error, desc) => this.state.env === 'dev' && console.error(["RPC Error", error, desc]) (error, desc) => this.state.env === 'dev' && console.error(["RPC Error", error, desc])
); );
@@ -304,7 +338,11 @@ class MineSeeker extends React.Component {
*/ */
websocket.on("socket/disconnect", (error) => { websocket.on("socket/disconnect", (error) => {
this.state.env === 'dev' && console.error("Disconnected for " + error.reason + " with code " + error.code); this.state.env === 'dev' && console.error("Disconnected for " + error.reason + " with code " + error.code);
this.setState({disconnect: true});
error.code === 6 && this.setState({connectionLost: true});
error.code === 3 && setTimeout(function () {
this.componentDidMount();
}.bind(this), 500);
}); });
} }
@@ -344,7 +382,7 @@ class MineSeeker extends React.Component {
}; };
/** PUBLISH */ /** PUBLISH */
!this.state.disconnect !this.state.connectionLost
? this.state.session.publish(this.state.channel, dataPack) ? this.state.session.publish(this.state.channel, dataPack)
: this.cachePublish(dataPack); : this.cachePublish(dataPack);
} }

View File

@@ -2,7 +2,7 @@
{% block header %} {% block header %}
<h1>MineSeeker</h1> <h1>MineSeeker</h1>
<h3>version 1.0a</h3> <h3>version 1.1.3a</h3>
<a href="{{ path('MineSeekerBundle_gamePlay') }}">Play now</a> <a href="{{ path('MineSeekerBundle_gamePlay') }}">Play now</a>
<img src="{{ asset('bundles/mineseeker/images/homepage/mineseeker-2.png') }}" alt="" border="0"> <img src="{{ asset('bundles/mineseeker/images/homepage/mineseeker-2.png') }}" alt="" border="0">
{% endblock %} {% endblock %}

View File

@@ -4,6 +4,7 @@
<div class="mine-container"> <div class="mine-container">
<div id="mine-wrapper" <div id="mine-wrapper"
data-env="{{ env }}" data-env="{{ env }}"
data-ssl="{{ ssl }}"
data-game-id="{{ app.request.get('gameAssoc') }}"> data-game-id="{{ app.request.get('gameAssoc') }}">
</div> </div>
</div> </div>

View File

@@ -56,7 +56,12 @@ class MineseekerRpc implements RpcInterface
*/ */
public function connectGame(ConnectionInterface $connection, WampRequest $request, array $params) public function connectGame(ConnectionInterface $connection, WampRequest $request, array $params)
{ {
return base64_encode(json_encode($this->getGrid($params))); return base64_encode(json_encode(
array(
'grid' => $this->getGrid($params),
'users' => $this->getUsers($params)
)
));
} }
/** /**
@@ -82,6 +87,36 @@ class MineseekerRpc implements RpcInterface
return $getsee; return $getsee;
} }
/**
* @param $gameAssoc
* @return array
*/
private function getUsers($gameAssoc)
{
$this->reConnect();
return $this->getUserCollection(
$this->em
->getRepository('MineSeekerBundle:PlayedGame')
->findOneByGameAssoc($gameAssoc)
);
}
/**
* 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() : ''
);
}
/** /**
* @param $data * @param $data
* @return boolean * @return boolean

View File

@@ -194,14 +194,17 @@ class MineseekerTopic implements TopicInterface
->getRepository('MineSeekerBundle:PlayedGame') ->getRepository('MineSeekerBundle:PlayedGame')
->findOneByGameAssoc($gameAssoc); ->findOneByGameAssoc($gameAssoc);
/** @var $users {array} */
$users = $this->getUserCollection($playedGame); $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 */ /** This checks it is a reconnection */
if ( if (($one && ($red + $blue === 0)) || ($two && ($red + $blue === 1))) {
(null !== $users['red'] || null !== $users['redAnon']) && /** @var $users {array} w/ save users to database */
(null !== $users['blue'] || null !== $users['blueAnon'])
) {
/** @var $users array Save users to database */
$users = $this->saveUserToDb($topic, $userName, $user, $topic->count()); $users = $this->saveUserToDb($topic, $userName, $user, $topic->count());
} }
@@ -226,6 +229,7 @@ class MineseekerTopic implements TopicInterface
->getRepository('MineSeekerBundle:PlayedGame') ->getRepository('MineSeekerBundle:PlayedGame')
->findOneByGameAssoc($gameAssoc); ->findOneByGameAssoc($gameAssoc);
/** the user is not anonym */
if (!is_string($user)) { if (!is_string($user)) {
$FOSUser = $this->em $FOSUser = $this->em
->getRepository('JotunheimrUserBundle:User') ->getRepository('JotunheimrUserBundle:User')
@@ -234,7 +238,6 @@ class MineseekerTopic implements TopicInterface
if ($count == 1) { if ($count == 1) {
/** @var $random {integer} Active player: red: 0, blue: 1 */ /** @var $random {integer} Active player: red: 0, blue: 1 */
$random = rand(0, 1); $random = rand(0, 1);
!$random ? $playedGame->setRed($FOSUser) : $playedGame->setBlue($FOSUser); !$random ? $playedGame->setRed($FOSUser) : $playedGame->setBlue($FOSUser);
} else { } else {
null === $playedGame->getRed() && null === $playedGame->getRedAnon() null === $playedGame->getRed() && null === $playedGame->getRedAnon()
@@ -246,12 +249,12 @@ class MineseekerTopic implements TopicInterface
$anon = new Gamer(); $anon = new Gamer();
$anon->setUserName($userName); $anon->setUserName($userName);
$anon->setConnTimestamp(new \DateTime());
$this->em->persist($anon); $this->em->persist($anon);
if ($count == 1) { if ($count == 1) {
/** @var $random {integer} Active player: red: 0, blue: 1 */ /** @var $random {integer} Active player: red: 0, blue: 1 */
$random = rand(0, 1); $random = rand(0, 1);
!$random ? $playedGame->setRedAnon($anon) : $playedGame->setBlueAnon($anon); !$random ? $playedGame->setRedAnon($anon) : $playedGame->setBlueAnon($anon);
} else { } else {
null === $playedGame->getRed() && null === $playedGame->getRedAnon() null === $playedGame->getRed() && null === $playedGame->getRedAnon()