Skip to content
This repository has been archived by the owner on Mar 3, 2020. It is now read-only.

Commit

Permalink
Automated Game Start and Stop (#449)
Browse files Browse the repository at this point in the history
* Automated Game Start and Stop

* Games will automatically start and stop at their scheduled times.  Administrators can still manually start or stop a game regardless of the configured schedule.

* Both Control::genAutoBegin() and Control::genAutoEnd() were added to check the current time against the scheduled start or stop time and perform the relevant action (Control::genBegin or Control::getEnd).

* Control::genAutoRun() checks the current game status and determine if the game should be starting or ending, calling the appropriate function (Control::genAutoBegin or Control::getAutoEnd) and is exclusively used in the new autorun.php script.

* Control::genRunAutoRunScript() runs the new autorun.php script, ensuring the script is not already running before starting a new copy.

* The Router class was updated to include a call to Control::genRunAutoRunScript(), this ensures the script is always running.  This script status check, and execution when needed, only takes place on a full page load.

* The autorun.php script runs Control::genAutoRun() and sleeps up to 30 seconds.

* If the game is scheduled to start or stop within 30 seconds, the script will sleep for the necessary amount of time.

* Games will always start with at most a 29-second difference from the scheduled time.  This discrepancy can only take place if the schedule is changed within 30 seconds of the previously scheduled time.  Otherwise, the execution will happen at the scheduled time.

* This automation is self-contained and requires no additional dependencies or external services (like cron, etc.).

* * Allow administrators to define the cycle time (in seconds) for the autorun process.  This time will be used for the sliding sleep.

* * Added sanitization to the autorun script path/file.
  • Loading branch information
justinwray authored and gsingh93 committed Feb 21, 2017
1 parent 899ab2b commit ca40091
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 0 deletions.
1 change: 1 addition & 0 deletions database/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ INSERT INTO `configuration` (field, value, description) VALUES("scoring", "0", "
INSERT INTO `configuration` (field, value, description) VALUES("gameboard", "1", "(Boolean) Refresh all data in the gameboard");
INSERT INTO `configuration` (field, value, description) VALUES("progressive_cycle", "300", "(Integer) Frequency to take progressive scoreboard in seconds");
INSERT INTO `configuration` (field, value, description) VALUES("bases_cycle", "5", "(Integer) Frequency to score base levels in seconds");
INSERT INTO `configuration` (field, value, description) VALUES("autorun_cycle", "30", "(Integer) Frequency to cycle autorun in seconds");
INSERT INTO `configuration` (field, value, description) VALUES("registration", "0", "(Boolean) Ability to register teams");
INSERT INTO `configuration` (field, value, description) VALUES("registration_names", "0", "(Boolean) Registration will ask for names");
INSERT INTO `configuration` (field, value, description) VALUES("registration_type", "1", "(Integer) Type of registration: 1 - Open; 2 - Tokenized;");
Expand Down
1 change: 1 addition & 0 deletions database/test_schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ INSERT INTO `configuration` (field, value, description) VALUES("scoring", "0", "
INSERT INTO `configuration` (field, value, description) VALUES("gameboard", "1", "(Boolean) Refresh all data in the gameboard");
INSERT INTO `configuration` (field, value, description) VALUES("progressive_cycle", "300", "(Integer) Frequency to take progressive scoreboard in seconds");
INSERT INTO `configuration` (field, value, description) VALUES("bases_cycle", "5", "(Integer) Frequency to score base levels in seconds");
INSERT INTO `configuration` (field, value, description) VALUES("autorun_cycle", "30", "(Integer) Frequency to cycle autorun in seconds");
INSERT INTO `configuration` (field, value, description) VALUES("registration", "0", "(Boolean) Ability to register teams");
INSERT INTO `configuration` (field, value, description) VALUES("registration_names", "0", "(Boolean) Registration will ask for names");
INSERT INTO `configuration` (field, value, description) VALUES("registration_type", "1", "(Integer) Type of registration: 1 - Open; 2 - Tokenized;");
Expand Down
1 change: 1 addition & 0 deletions src/Router.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class Router {
$xhp = await self::genRouteModal($page, strval($modal));
return strval($xhp);
} else {
await Control::genRunAutoRunScript();
$response = await self::genRouteNormal($page);
return strval($response);
}
Expand Down
10 changes: 10 additions & 0 deletions src/controllers/AdminController.php
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ class="fb-cta cta--yellow"
'default_bonus' => Configuration::gen('default_bonus'),
'default_bonusdec' => Configuration::gen('default_bonusdec'),
'bases_cycle' => Configuration::gen('bases_cycle'),
'autorun_cycle' => Configuration::gen('autorun_cycle'),
'start_ts' => Configuration::gen('start_ts'),
'end_ts' => Configuration::gen('end_ts'),
};
Expand All @@ -314,6 +315,7 @@ class="fb-cta cta--yellow"
$default_bonus = $results['default_bonus'];
$default_bonusdec = $results['default_bonusdec'];
$bases_cycle = $results['bases_cycle'];
$autorun_cycle = $results['autorun_cycle'];
$start_ts = $results['start_ts'];
$end_ts = $results['end_ts'];

Expand Down Expand Up @@ -714,6 +716,14 @@ class="fb-cta cta--yellow"
</div>
</div>
<div class="col col-pad col-4-4">
<div class="form-el el--block-label">
<label>{tr('Autorun Cycle (s)')}</label>
<input
type="number"
value={$autorun_cycle->getValue()}
name="fb--conf--autorun_cycle"
/>
</div>
<div class="form-el el--block-label"></div>
</div>
</div>
Expand Down
89 changes: 89 additions & 0 deletions src/models/Control.php
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,95 @@ class Control extends Model {
await Level::genBaseScoring();
}

public static async function genAutoBegin(): Awaitable<void> {
// Get start time
$config_start_ts = await Configuration::gen('start_ts');
$start_ts = intval($config_start_ts->getValue());

// Get end time
$config_end_ts = await Configuration::gen('end_ts');
$end_ts = intval($config_end_ts->getValue());

// Get paused status
$config_game_paused = await Configuration::gen('game_paused');
$game_paused = intval($config_game_paused->getValue());

if (($game_paused === 0) && ($start_ts <= time()) && ($end_ts > time())) {
// Start the game
await Control::genBegin();
}
}

public static async function genAutoEnd(): Awaitable<void> {
// Get start time
$config_start_ts = await Configuration::gen('start_ts');
$start_ts = intval($config_start_ts->getValue());

// Get end time
$config_end_ts = await Configuration::gen('end_ts');
$end_ts = intval($config_end_ts->getValue());

// Get paused status
$config_game_paused = await Configuration::gen('game_paused');
$game_paused = intval($config_game_paused->getValue());

if (($game_paused === 0) && ($end_ts <= time())) {
// Start the game
await Control::genEnd();
}
}

public static async function genAutoRun(): Awaitable<void> {
// Get start time
$config_game = await Configuration::gen('game');
$game = intval($config_game->getValue());

if ($game === 0) {
// Check and start the game
await Control::genAutoBegin();
} else {
// Check and stop the game
await Control::genAutoEnd();
}
}

public static async function genRunAutoRunScript(): Awaitable<void> {
$autorun_status = await Control::checkScriptRunning('autorun');
if ($autorun_status === false) {
$autorun_location = escapeshellarg(
must_have_string(Utils::getSERVER(), 'DOCUMENT_ROOT').
'/scripts/autorun.php',
);
$cmd =
'hhvm -vRepo.Central.Path=/var/run/hhvm/.hhvm.hhbc_autorun '.
$autorun_location.
' > /dev/null 2>&1 & echo $!';
$pid = shell_exec($cmd);
await Control::genStartScriptLog(intval($pid), 'autorun', $cmd);
}
}

public static async function checkScriptRunning(
string $name,
): Awaitable<bool> {
$db = await self::genDb();
$result = await $db->queryf(
'SELECT pid FROM scripts WHERE name = %s AND status = 1 LIMIT 1',
$name,
);
if ($result->numRows() >= 1) {
$pid = intval(must_have_idx($result->mapRows()[0], 'pid'));
$status = file_exists("/proc/$pid");
if ($status === false) {
await Control::genStopScriptLog($pid);
await Control::genClearScriptLog();
}
return $status;
} else {
return false;
}
}

public static async function importGame(): Awaitable<bool> {
$data_game = JSONImporterController::readJSON('game_file');
if (is_array($data_game)) {
Expand Down
48 changes: 48 additions & 0 deletions src/scripts/autorun.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?hh

if (php_sapi_name() !== 'cli') {
http_response_code(405); // method not allowed
exit(0);
}

require_once (__DIR__.'/../Db.php');
require_once (__DIR__.'/../Utils.php');
require_once (__DIR__.'/../models/Model.php');
require_once (__DIR__.'/../models/Importable.php');
require_once (__DIR__.'/../models/Exportable.php');
require_once (__DIR__.'/../models/Level.php');
require_once (__DIR__.'/../models/Progressive.php');
require_once (__DIR__.'/../models/Configuration.php');
require_once (__DIR__.'/../models/Control.php');
require_once (__DIR__.'/../models/Team.php');
require_once (__DIR__.'/../models/MultiTeam.php');
require_once (__DIR__.'/../models/ScoreLog.php');
require_once (__DIR__.'/../models/HintLog.php');
require_once (__DIR__.'/../models/FailureLog.php');

while (1) {
\HH\Asio\join(Control::genAutoRun());

$conf_sleep = \HH\Asio\join(Configuration::gen('autorun_cycle'));
$conf_sleep_secs = intval($conf_sleep->getValue());
$sleep = $conf_sleep_secs;
$conf_game = \HH\Asio\join(Configuration::gen('game'));
$config_start_ts = \HH\Asio\join(Configuration::gen('start_ts'));
$start_ts = intval($config_start_ts->getValue());
$config_end_ts = \HH\Asio\join(Configuration::gen('end_ts'));
$end_ts = intval($config_end_ts->getValue());

if (($conf_game->getValue() === '1') &&
(($end_ts - time()) < $conf_sleep_secs)) {
$sleep = $end_ts - time();
} else if (($conf_game->getValue() === '0') &&
(($start_ts - time()) < $conf_sleep_secs)) {
$sleep = $start_ts - time();
}

if ($sleep < 0) {
$sleep = $conf_sleep_secs;
}

sleep($sleep);
}

0 comments on commit ca40091

Please sign in to comment.