* @copyright 2014 ManiaControl Team * @license http://www.gnu.org/licenses/ GNU General Public License, Version 3 */ class ManiaControl implements CallbackListener, CommandListener, TimerListener { /* * Constants */ const VERSION = '0.153'; const API_VERSION = '2013-04-16'; const MIN_DEDIVERSION = '2014-04-02_18_00'; const SCRIPT_TIMEOUT = 10; const URL_WEBSERVICE = 'http://ws.maniacontrol.com/'; const SETTING_PERMISSION_SHUTDOWN = 'Shutdown ManiaControl'; const SETTING_PERMISSION_RESTART = 'Restart ManiaControl'; /* * Public properties */ /** @var ActionsMenu $actionsMenu */ /** @deprecated see getActionsMenu() */ public $actionsMenu = null; /** @var AuthenticationManager $authenticationManager */ /** @deprecated see getAuthenticationManager() */ public $authenticationManager = null; /** @var CallbackManager $callbackManager */ /** @deprecated see getCallbackManager() */ public $callbackManager = null; /** @var Chat $chat */ /** @deprecated see getChat() */ public $chat = null; /** @var \SimpleXMLElement $config */ /** @deprecated see getConfig() */ public $config = null; /** @var Configurator $configurator */ /** @deprecated see getConfigurator() */ public $configurator = null; /** @var Connection $client */ /** @deprecated see getClient() */ public $client = null; /** @var CommandManager $commandManager */ /** @deprecated see getCommandManager() */ public $commandManager = null; /** @var Database $database */ /** @deprecated see getDatabase() */ public $database = null; /** @var ManialinkManager $manialinkManager */ /** @deprecated see getManialinkManager */ public $manialinkManager = null; /** @var MapManager $mapManager */ /** @deprecated see getMapManager() */ public $mapManager = null; /** @var PlayerManager $playerManager */ /** @deprecated see getPlayerManager() */ public $playerManager = null; /** @var PluginManager $pluginManager */ /** @deprecated see getPluginManager() */ public $pluginManager = null; /** @var Server $server */ /** @deprecated see getServer() */ public $server = null; /** @var SettingManager $settingManager */ /** @deprecated see getSettingManager() */ public $settingManager = null; /** @var StatisticManager $statisticManager */ /** @deprecated see getStatisticManager() */ public $statisticManager = null; /** @var UpdateManager $updateManager */ /** @deprecated see getUpdateManager() */ public $updateManager = null; /** @var ErrorHandler $errorHandler */ /** @deprecated see getErrorHandler() */ public $errorHandler = null; /** @var TimerManager $timerManager */ /** @deprecated see getTimerManager() */ public $timerManager = null; /** @var AsynchronousFileReader $fileReader */ /** @deprecated see getFileReader() */ public $fileReader = null; /** @var BillManager $billManager */ /** @deprecated see getBillManager() */ public $billManager = null; /* * Private properties */ private $requestQuitMessage = null; /** * Construct a new ManiaControl instance */ public function __construct() { Logger::log('Loading ManiaControl v' . self::VERSION . ' ...'); $this->errorHandler = new ErrorHandler($this); $this->loadConfig(); // Load ManiaControl Modules $this->callbackManager = new CallbackManager($this); $this->timerManager = new TimerManager($this); $this->database = new Database($this); $this->fileReader = new AsynchronousFileReader($this); $this->billManager = new BillManager($this); $this->settingManager = new SettingManager($this); $this->statisticManager = new StatisticManager($this); $this->manialinkManager = new ManialinkManager($this); $this->actionsMenu = new ActionsMenu($this); $this->chat = new Chat($this); $this->commandManager = new CommandManager($this); $this->server = new Server($this); $this->authenticationManager = new AuthenticationManager($this); $this->playerManager = new PlayerManager($this); $this->mapManager = new MapManager($this); $this->configurator = new Configurator($this); $this->pluginManager = new PluginManager($this); $this->updateManager = new UpdateManager($this); $this->getErrorHandler()->init(); // Permissions $this->getAuthenticationManager()->definePermissionLevel(self::SETTING_PERMISSION_SHUTDOWN, AuthenticationManager::AUTH_LEVEL_SUPERADMIN); $this->getAuthenticationManager()->definePermissionLevel(self::SETTING_PERMISSION_RESTART, AuthenticationManager::AUTH_LEVEL_SUPERADMIN); // Commands $this->getCommandManager()->registerCommandListener('version', $this, 'commandVersion', false, 'Shows ManiaControl version.'); $this->getCommandManager()->registerCommandListener('restart', $this, 'commandRestart', true, 'Restarts ManiaControl.'); $this->getCommandManager()->registerCommandListener('shutdown', $this, 'commandShutdown', true, 'Shuts ManiaControl down.'); // Check connection every 30 seconds $this->getTimerManager()->registerTimerListening($this, 'checkConnection', 1000 * 30); } /** * Print a message to console and log * * @param string $message * @param bool $stripCodes * @deprecated * @see Logger::log() */ public function log($message, $stripCodes = false) { Logger::log($message, $stripCodes); } /** * Load the Config XML-File */ private function loadConfig() { $configId = CommandLineHelper::getParameter('-config'); $configFileName = ($configId ? $configId : 'server.xml'); $config = FileUtil::loadConfig($configFileName); if (!$config) { $this->quit("Error loading Configuration XML-File! ('{$configFileName}')", true); } if ($config->count() < 3) { $this->quit("Your Configuration File ('{$configFileName}') doesn't seem to be maintained properly. Please check it again!", true); } $this->config = $config; } /** * Quit ManiaControl and log the given message * * @param string $message * @param bool $errorPrefix */ public function quit($message = null, $errorPrefix = false) { Connection::delete($this->getClient()); $this->client = null; SystemUtil::quit($message, $errorPrefix); } /** * Return the actions menu * * @return ActionsMenu */ public function getActionsMenu() { return $this->actionsMenu; } /** * Return the authentication manager * * @return AuthenticationManager */ public function getAuthenticationManager() { return $this->authenticationManager; } /** * Return the callback manager * * @return CallbackManager */ public function getCallbackManager() { return $this->callbackManager; } /** * Return the chat * * @return Chat */ public function getChat() { return $this->chat; } /** * Return the config * * @return \SimpleXMLElement */ public function getConfig() { return $this->config; } /** * Return the configurator * * @return Configurator */ public function getConfigurator() { return $this->configurator; } /** * Return the client * * @return Connection */ public function getClient() { return $this->client; } /** * Return the command manager * * @return CommandManager */ public function getCommandManager() { return $this->commandManager; } /** * Return the database * * @return Database */ public function getDatabase() { return $this->database; } /** * Return the manialink manager * * @return ManialinkManager */ public function getManialinkManager() { return $this->manialinkManager; } /** * Return the map manager * * @return MapManager */ public function getMapManager() { return $this->mapManager; } /** * Return the player manager * * @return PlayerManager */ public function getPlayerManager() { return $this->playerManager; } /** * Return the plugin manager * * @return PluginManager */ public function getPluginManager() { return $this->pluginManager; } /** * Return the server * * @return Server */ public function getServer() { return $this->server; } /** * Return the setting manager * * @return SettingManager */ public function getSettingManager() { return $this->settingManager; } /** * Return the statistic manager * * @return StatisticManager */ public function getStatisticManager() { return $this->statisticManager; } /** * Return the update manager * * @return UpdateManager */ public function getUpdateManager() { return $this->updateManager; } /** * Return the error handler * * @return ErrorHandler */ public function getErrorHandler() { return $this->errorHandler; } /** * Return the timer manager * * @return TimerManager */ public function getTimerManager() { return $this->timerManager; } /** * Return the file reader * * @return AsynchronousFileReader */ public function getFileReader() { return $this->fileReader; } /** * Return the bill manager * * @return BillManager */ public function getBillManager() { return $this->billManager; } /** * Check connection */ public function checkConnection() { if ($this->getClient()->getIdleTime() > 180) { $this->getClient()->getServerName(); } } /** * Handle Version Command * * @param array $chatCallback * @param Player $player */ public function commandVersion(array $chatCallback, Player $player) { $message = 'This server is using ManiaControl v' . ManiaControl::VERSION . '!'; $this->getChat()->sendInformation($message, $player); } /** * Handle Restart AdminCommand * * @param array $chatCallback * @param Player $player */ public function commandRestart(array $chatCallback, Player $player) { if (!$this->getAuthenticationManager()->checkPermission($player, self::SETTING_PERMISSION_RESTART)) { $this->getAuthenticationManager()->sendNotAllowed($player); return; } $this->restart("ManiaControl Restart requested by '{$player->login}'!"); } /** * Restart ManiaControl * * @param string $message */ public function restart($message = null) { // Shutdown callback $this->getCallbackManager()->triggerCallback(Callbacks::ONSHUTDOWN); // Announce restart if ($message) { Logger::log($message); } $this->getChat()->sendInformation('Restarting ManiaControl...'); Logger::log('Restarting ManiaControl!'); // Hide widgets if ($this->getClient()) { $this->getClient()->sendHideManialinkPage(); } // Start new instance SystemUtil::restart(); // Quit old instance $this->quit('Quitting ManiaControl to restart.'); } /** * Handle Shutdown Command * * @param array $chat * @param Player $player */ public function commandShutdown(array $chat, Player $player) { if (!$this->getAuthenticationManager()->checkPermission($player, self::SETTING_PERMISSION_SHUTDOWN)) { $this->getAuthenticationManager()->sendNotAllowed($player); return; } $this->requestQuit("ManiaControl Shutdown requested by '{$player->login}'!"); } /** * Request ManiaControl to quit * * @param mixed $message */ public function requestQuit($message = true) { $this->requestQuitMessage = $message; } /** * Run ManiaControl */ public function run() { Logger::log('Starting ManiaControl v' . self::VERSION . '!'); // Connect to server try { $this->connect(); } catch (TransportException $e) { $this->quit($e->getMessage(), true); } // Check if the version of the server is high enough $version = $this->getClient()->getVersion(); if ($version->build < self::MIN_DEDIVERSION) { $this->quit("The Server has Version '{$version->build}', while at least '" . self::MIN_DEDIVERSION . "' is required!", true); } // Listen for shutdown $this->getCallbackManager()->registerCallbackListener(CallbackManager::CB_MP_SERVERSTOP, $this, 'handleServerStopCallback'); // OnInit callback $this->getCallbackManager()->triggerCallback(Callbacks::ONINIT); // Load plugins $this->getPluginManager()->loadPlugins(); $this->getUpdateManager()->getPluginUpdateManager()->checkPluginsUpdate(); // AfterInit callback $this->getCallbackManager()->triggerCallback(Callbacks::AFTERINIT); // Loading finished Logger::log('Loading completed!'); Logger::log('Link: '.$this->getServer()->getJoinLink()); $this->getChat()->sendInformation('ManiaControl v' . self::VERSION . ' successfully started!'); // Main loop while (!$this->requestQuitMessage) { $this->loop(); } // Shutdown $this->quit($this->requestQuitMessage); } /** * Connect to ManiaPlanet server */ private function connect() { // Load remote client $serverConfig = $this->getServer()->loadConfig(); Logger::log("Connecting to Server at {$serverConfig->host}:{$serverConfig->port}..."); try { $this->client = Connection::factory($serverConfig->host, $serverConfig->port, self::SCRIPT_TIMEOUT, $serverConfig->user, $serverConfig->pass, self::API_VERSION); } catch (TransportException $exception) { $message = "Couldn't connect to the server: '{$exception->getMessage()}'"; $this->quit($message, true); } catch (AuthenticationException $exception) { $message = "Couldn't authenticate on Server with User '{$serverConfig->user}' & Pass '{$serverConfig->pass}'! " . $exception->getMessage(); $this->quit($message, true); } // Enable callback system $this->getClient()->enableCallbacks(true); // Wait for server to be ready if (!$this->getServer()->waitForStatus(4)) { $this->quit("Server couldn't get ready!"); } // Connect finished Logger::log('Server Connection successfully established!'); // Hide old widgets $this->getClient()->sendHideManialinkPage(); // Enable script callbacks $this->getServer()->getScriptManager() ->enableScriptCallbacks(); } /** * Perform the Main Loop */ private function loop() { $loopStart = microtime(true); // Extend script timeout set_time_limit(self::SCRIPT_TIMEOUT); try { $this->getCallbackManager()->manageCallbacks(); } catch (TransportException $e) { Logger::logError('Connection interrupted!'); $this->quit($e->getMessage(), true); } // Manage FileReader $this->getFileReader()->appendData(); // Yield for next tick $loopEnd = microtime(true); $loopDuration = $loopEnd - $loopStart; $sleepTime = (int)(2500 - $loopDuration * 1000000); if ($sleepTime > 0) { usleep($sleepTime); } } /** * Handle Server Stop Callback */ public function handleServerStopCallback() { $this->requestQuit('The Server has been shut down!'); } }