1
0
Fork 0

Add simple API and starter for cron jobs

master
Anonymous Contributor 2023-09-10 04:41:21 +02:00
parent b18b960fb0
commit a213a38b3c
6 changed files with 116 additions and 26 deletions

View File

@ -77,7 +77,8 @@ class Mcp implements ConnectionProvider
public function config($key): string|array|int
{
return $this->config[strtolower($key)];
$realKey = strtolower($key);
return isset($this->config[$realKey]) ? $this->config[$realKey] : array();
}
public function csrfField(): string

View File

@ -14,6 +14,7 @@ class MigrationManager
'CREATE TABLE IF NOT EXISTS `mcp_invites` (`InviteCode` CHAR(64) NOT NULL, PRIMARY KEY (`InviteCode`)) ENGINE InnoDB',
'CREATE TABLE IF NOT EXISTS `mcp_offlineim_send` (`id` int(6) NOT NULL DEFAULT 0) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci',
'CREATE TABLE IF NOT EXISTS `mcp_regions_info` (`regionID` CHAR(36) NOT NULL COLLATE utf8_unicode_ci, `RegionVersion` VARCHAR(128) NOT NULL DEFAULT "" COLLATE utf8_unicode_ci, `ProcMem` INT(11) NOT NULL, `Prims` INT(11) NOT NULL, `SimFPS` INT(11) NOT NULL, `PhyFPS` INT(11) NOT NULL, `OfflineTimer` INT(11) NOT NULL DEFAULT 0, PRIMARY KEY (`regionID`) USING BTREE) COLLATE=utf8_unicode_ci ENGINE=InnoDB',
'CREATE TABLE IF NOT EXISTS `mcp_cron_runs` (`Name` VARCHAR(50) NOT NULL, `LastRun` INT(11) UNSIGNED NOT NULL, PRIMARY KEY(`Name`)) ENGINE InnoDB',
'CREATE TRIGGER IF NOT EXISTS del_id_trig AFTER DELETE ON UserAccounts FOR EACH ROW DELETE FROM mcp_user_identities WHERE mcp_user_identities.PrincipalID = OLD.PrincipalID OR mcp_user_identities.IdentityID = OLD.PrincipalID',
'CREATE TRIGGER IF NOT EXISTS del_pwres_trig AFTER DELETE ON UserAccounts FOR EACH ROW DELETE FROM mcp_password_reset WHERE mcp_password_reset.PrincipalID = OLD.PrincipalID'
];
@ -25,10 +26,13 @@ class MigrationManager
'ALTER TABLE mcp_regions_info MODIFY COLUMN regionID CHAR(36), MODIFY COLUMN ProcMem INT(11) UNSIGNED NOT NULL, MODIFY COLUMN Prims INT(11) UNSIGNED NOT NULL, MODIFY COLUMN SimFPS FLOAT NOT NULL, MODIFY COLUMN PhyFPS FLOAT NOT NULL, MODIFY COLUMN OfflineTimer BIGINT UNSIGNED NOT NULL DEFAULT 0',
'CREATE TRIGGER IF NOT EXISTS del_id_trig AFTER DELETE ON UserAccounts FOR EACH ROW DELETE FROM mcp_user_identities WHERE mcp_user_identities.PrincipalID = OLD.PrincipalID OR mcp_user_identities.IdentityID = OLD.PrincipalID',
'CREATE TRIGGER IF NOT EXISTS del_pwres_trig AFTER DELETE ON UserAccounts FOR EACH ROW DELETE FROM mcp_password_reset WHERE mcp_password_reset.PrincipalID = OLD.PrincipalID'
],
2 => [
'CREATE TABLE IF NOT EXISTS `mcp_cron_runs` (`Name` VARCHAR(50) NOT NULL, `LastRun` INT(11) UNSIGNED NOT NULL, PRIMARY KEY(`Name`)) ENGINE InnoDB'
]
];
private const MIGRATE_VERSION_CURRENT = 2;
private const MIGRATE_VERSION_CURRENT = 3;
private int $migrateVersion;
private string $migrateVersionFile;

44
app/api/CronStarter.php Normal file
View File

@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
namespace Mcp\Api;
use Mcp\RequestHandler;
class CronStarter extends RequestHandler
{
private const CRONJOBS_INTERNAL = ['SessionCleanup'];
public function get(): void
{
if ($this->app->config('cron-restriction') == 'key' && !(isset($_GET['key']) && hash_equals($this->app->config('cron-key'), $_GET['key']))) {
http_response_code(403);
return;
}
$cronJobs = array_merge($this->app->config('cronjobs'), $this::CRONJOBS_INTERNAL);
$cronStatement = $this->app->db()->prepare('SELECT Name,LastRun FROM mcp_cron_runs');
$cronStatement->execute();
$jobRuns = array();
while ($row = $cronStatement->fetch()) {
$jobRuns[$row['Name']] = $row['LastRun'];
}
$cronUpdateStatement = $this->app->db()->prepare('REPLACE INTO mcp_cron_runs(Name,LastRun) VALUES (?,?)');
foreach ($cronJobs as $jobName) {
$jobClass = "Mcp\\Cron\\".$jobName;
if (in_array($jobName, $cronJobs)) {
$job = (new $jobClass($this->app));
$now = time();
$nextRun = $job->getNextRun(isset($jobRuns[$jobName]) ? $jobRuns[$jobName] : $now - 60);
if ($now >= $nextRun && $job->run()) {
error_log($now.' <= '.$nextRun);
$cronUpdateStatement->execute([$jobName, time()]);
}
}
}
}
}

51
app/cron/CronJob.php Normal file
View File

@ -0,0 +1,51 @@
<?php
declare(strict_types=1);
namespace Mcp\Cron;
use DateInterval;
use DateTime;
use Mcp\Mcp;
abstract class CronJob {
protected Mcp $app;
private Frequency $freq;
public function __construct(Mcp $app, Frequency $freq)
{
$this->app = $app;
$this->freq = $freq;
}
public function getNextRun(int $lastRun)
{
$prevDate = getdate($lastRun);
$res = new DateTime('@'.$lastRun);
switch($this->freq) {
case Frequency::EACH_MINUTE:
$res->add(DateInterval::createFromDateString('1 minute'));
break;
case Frequency::HOURLY:
$res->add(DateInterval::createFromDateString('1 hour'));
break;
case Frequency::DAILY:
$res->add(DateInterval::createFromDateString('1 day'));
break;
case Frequency::WEEKLY:
$res->add(DateInterval::createFromDateString('1 week'));
break;
case Frequency::MONTHLY:
$res->setDate($prevDate['year'] + ($prevDate['mon'] == 12 ? 1 : 0), $prevDate['mon'] == 12 ? 1 : $prevDate['mon'] + 1, 1);
break;
case Frequency::YEARLY:
$res->setDate($prevDate['year'] + 1, 1, 1);
break;
default: break;
}
return $res->getTimestamp();
}
abstract public function run(): bool;
}

14
app/cron/Frequency.php Normal file
View File

@ -0,0 +1,14 @@
<?php
declare(strict_types=1);
namespace Mcp\Cron;
enum Frequency
{
case YEARLY;
case MONTHLY;
case WEEKLY;
case DAILY;
case HOURLY;
case EACH_MINUTE;
}

View File

@ -1,24 +0,0 @@
<?php
$RUNTIME = array();
$RUNTIME['BASEDIR'] = __DIR__;
set_include_path('.:'.$RUNTIME['BASEDIR']);
include_once "config.php";
if(!isset($RUNTIME['CRON_RESTRICTION'])) {
http_response_code(500);
die();
}
if ($RUNTIME['CRON_RESTRICTION'] != 'none' && (!isset($RUNTIME['CRON_KEY']) || !isset($REQUEST['key']) || $_REQUEST['key'] !== $RUNTIME['CRON_KEY'])) {
http_response_code(401);
die();
}
if ($handle = opendir('./cron/')) {
while (false !== ($entry = readdir($handle))) {
if ($entry != "." && $entry != "..") {
include_once "./cron/".$entry;
}
}
closedir($handle);
}