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

Commit ca40091

Browse files
justinwraygsingh93
authored andcommitted
Automated Game Start and Stop (#449)
* 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.
1 parent 899ab2b commit ca40091

File tree

6 files changed

+150
-0
lines changed

6 files changed

+150
-0
lines changed

database/schema.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ INSERT INTO `configuration` (field, value, description) VALUES("scoring", "0", "
196196
INSERT INTO `configuration` (field, value, description) VALUES("gameboard", "1", "(Boolean) Refresh all data in the gameboard");
197197
INSERT INTO `configuration` (field, value, description) VALUES("progressive_cycle", "300", "(Integer) Frequency to take progressive scoreboard in seconds");
198198
INSERT INTO `configuration` (field, value, description) VALUES("bases_cycle", "5", "(Integer) Frequency to score base levels in seconds");
199+
INSERT INTO `configuration` (field, value, description) VALUES("autorun_cycle", "30", "(Integer) Frequency to cycle autorun in seconds");
199200
INSERT INTO `configuration` (field, value, description) VALUES("registration", "0", "(Boolean) Ability to register teams");
200201
INSERT INTO `configuration` (field, value, description) VALUES("registration_names", "0", "(Boolean) Registration will ask for names");
201202
INSERT INTO `configuration` (field, value, description) VALUES("registration_type", "1", "(Integer) Type of registration: 1 - Open; 2 - Tokenized;");

database/test_schema.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ INSERT INTO `configuration` (field, value, description) VALUES("scoring", "0", "
196196
INSERT INTO `configuration` (field, value, description) VALUES("gameboard", "1", "(Boolean) Refresh all data in the gameboard");
197197
INSERT INTO `configuration` (field, value, description) VALUES("progressive_cycle", "300", "(Integer) Frequency to take progressive scoreboard in seconds");
198198
INSERT INTO `configuration` (field, value, description) VALUES("bases_cycle", "5", "(Integer) Frequency to score base levels in seconds");
199+
INSERT INTO `configuration` (field, value, description) VALUES("autorun_cycle", "30", "(Integer) Frequency to cycle autorun in seconds");
199200
INSERT INTO `configuration` (field, value, description) VALUES("registration", "0", "(Boolean) Ability to register teams");
200201
INSERT INTO `configuration` (field, value, description) VALUES("registration_names", "0", "(Boolean) Registration will ask for names");
201202
INSERT INTO `configuration` (field, value, description) VALUES("registration_type", "1", "(Integer) Type of registration: 1 - Open; 2 - Tokenized;");

src/Router.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class Router {
1616
$xhp = await self::genRouteModal($page, strval($modal));
1717
return strval($xhp);
1818
} else {
19+
await Control::genRunAutoRunScript();
1920
$response = await self::genRouteNormal($page);
2021
return strval($response);
2122
}

src/controllers/AdminController.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,7 @@ class="fb-cta cta--yellow"
290290
'default_bonus' => Configuration::gen('default_bonus'),
291291
'default_bonusdec' => Configuration::gen('default_bonusdec'),
292292
'bases_cycle' => Configuration::gen('bases_cycle'),
293+
'autorun_cycle' => Configuration::gen('autorun_cycle'),
293294
'start_ts' => Configuration::gen('start_ts'),
294295
'end_ts' => Configuration::gen('end_ts'),
295296
};
@@ -314,6 +315,7 @@ class="fb-cta cta--yellow"
314315
$default_bonus = $results['default_bonus'];
315316
$default_bonusdec = $results['default_bonusdec'];
316317
$bases_cycle = $results['bases_cycle'];
318+
$autorun_cycle = $results['autorun_cycle'];
317319
$start_ts = $results['start_ts'];
318320
$end_ts = $results['end_ts'];
319321

@@ -714,6 +716,14 @@ class="fb-cta cta--yellow"
714716
</div>
715717
</div>
716718
<div class="col col-pad col-4-4">
719+
<div class="form-el el--block-label">
720+
<label>{tr('Autorun Cycle (s)')}</label>
721+
<input
722+
type="number"
723+
value={$autorun_cycle->getValue()}
724+
name="fb--conf--autorun_cycle"
725+
/>
726+
</div>
717727
<div class="form-el el--block-label"></div>
718728
</div>
719729
</div>

src/models/Control.php

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,95 @@ class Control extends Model {
216216
await Level::genBaseScoring();
217217
}
218218

219+
public static async function genAutoBegin(): Awaitable<void> {
220+
// Get start time
221+
$config_start_ts = await Configuration::gen('start_ts');
222+
$start_ts = intval($config_start_ts->getValue());
223+
224+
// Get end time
225+
$config_end_ts = await Configuration::gen('end_ts');
226+
$end_ts = intval($config_end_ts->getValue());
227+
228+
// Get paused status
229+
$config_game_paused = await Configuration::gen('game_paused');
230+
$game_paused = intval($config_game_paused->getValue());
231+
232+
if (($game_paused === 0) && ($start_ts <= time()) && ($end_ts > time())) {
233+
// Start the game
234+
await Control::genBegin();
235+
}
236+
}
237+
238+
public static async function genAutoEnd(): Awaitable<void> {
239+
// Get start time
240+
$config_start_ts = await Configuration::gen('start_ts');
241+
$start_ts = intval($config_start_ts->getValue());
242+
243+
// Get end time
244+
$config_end_ts = await Configuration::gen('end_ts');
245+
$end_ts = intval($config_end_ts->getValue());
246+
247+
// Get paused status
248+
$config_game_paused = await Configuration::gen('game_paused');
249+
$game_paused = intval($config_game_paused->getValue());
250+
251+
if (($game_paused === 0) && ($end_ts <= time())) {
252+
// Start the game
253+
await Control::genEnd();
254+
}
255+
}
256+
257+
public static async function genAutoRun(): Awaitable<void> {
258+
// Get start time
259+
$config_game = await Configuration::gen('game');
260+
$game = intval($config_game->getValue());
261+
262+
if ($game === 0) {
263+
// Check and start the game
264+
await Control::genAutoBegin();
265+
} else {
266+
// Check and stop the game
267+
await Control::genAutoEnd();
268+
}
269+
}
270+
271+
public static async function genRunAutoRunScript(): Awaitable<void> {
272+
$autorun_status = await Control::checkScriptRunning('autorun');
273+
if ($autorun_status === false) {
274+
$autorun_location = escapeshellarg(
275+
must_have_string(Utils::getSERVER(), 'DOCUMENT_ROOT').
276+
'/scripts/autorun.php',
277+
);
278+
$cmd =
279+
'hhvm -vRepo.Central.Path=/var/run/hhvm/.hhvm.hhbc_autorun '.
280+
$autorun_location.
281+
' > /dev/null 2>&1 & echo $!';
282+
$pid = shell_exec($cmd);
283+
await Control::genStartScriptLog(intval($pid), 'autorun', $cmd);
284+
}
285+
}
286+
287+
public static async function checkScriptRunning(
288+
string $name,
289+
): Awaitable<bool> {
290+
$db = await self::genDb();
291+
$result = await $db->queryf(
292+
'SELECT pid FROM scripts WHERE name = %s AND status = 1 LIMIT 1',
293+
$name,
294+
);
295+
if ($result->numRows() >= 1) {
296+
$pid = intval(must_have_idx($result->mapRows()[0], 'pid'));
297+
$status = file_exists("/proc/$pid");
298+
if ($status === false) {
299+
await Control::genStopScriptLog($pid);
300+
await Control::genClearScriptLog();
301+
}
302+
return $status;
303+
} else {
304+
return false;
305+
}
306+
}
307+
219308
public static async function importGame(): Awaitable<bool> {
220309
$data_game = JSONImporterController::readJSON('game_file');
221310
if (is_array($data_game)) {

src/scripts/autorun.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?hh
2+
3+
if (php_sapi_name() !== 'cli') {
4+
http_response_code(405); // method not allowed
5+
exit(0);
6+
}
7+
8+
require_once (__DIR__.'/../Db.php');
9+
require_once (__DIR__.'/../Utils.php');
10+
require_once (__DIR__.'/../models/Model.php');
11+
require_once (__DIR__.'/../models/Importable.php');
12+
require_once (__DIR__.'/../models/Exportable.php');
13+
require_once (__DIR__.'/../models/Level.php');
14+
require_once (__DIR__.'/../models/Progressive.php');
15+
require_once (__DIR__.'/../models/Configuration.php');
16+
require_once (__DIR__.'/../models/Control.php');
17+
require_once (__DIR__.'/../models/Team.php');
18+
require_once (__DIR__.'/../models/MultiTeam.php');
19+
require_once (__DIR__.'/../models/ScoreLog.php');
20+
require_once (__DIR__.'/../models/HintLog.php');
21+
require_once (__DIR__.'/../models/FailureLog.php');
22+
23+
while (1) {
24+
\HH\Asio\join(Control::genAutoRun());
25+
26+
$conf_sleep = \HH\Asio\join(Configuration::gen('autorun_cycle'));
27+
$conf_sleep_secs = intval($conf_sleep->getValue());
28+
$sleep = $conf_sleep_secs;
29+
$conf_game = \HH\Asio\join(Configuration::gen('game'));
30+
$config_start_ts = \HH\Asio\join(Configuration::gen('start_ts'));
31+
$start_ts = intval($config_start_ts->getValue());
32+
$config_end_ts = \HH\Asio\join(Configuration::gen('end_ts'));
33+
$end_ts = intval($config_end_ts->getValue());
34+
35+
if (($conf_game->getValue() === '1') &&
36+
(($end_ts - time()) < $conf_sleep_secs)) {
37+
$sleep = $end_ts - time();
38+
} else if (($conf_game->getValue() === '0') &&
39+
(($start_ts - time()) < $conf_sleep_secs)) {
40+
$sleep = $start_ts - time();
41+
}
42+
43+
if ($sleep < 0) {
44+
$sleep = $conf_sleep_secs;
45+
}
46+
47+
sleep($sleep);
48+
}

0 commit comments

Comments
 (0)