switch to newboos dedicated api + idletime check
This commit is contained in:
parent
0aed71b067
commit
85bc053fb3
@ -20,19 +20,19 @@ class Connection
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* XML-RPC client instance
|
* XML-RPC client instance
|
||||||
* @var Xmlrpc\ClientMulticall
|
* @var Xmlrpc\GbxRemote
|
||||||
*/
|
*/
|
||||||
protected $xmlrpcClient;
|
protected $xmlrpcClient;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $host
|
* @param string $host
|
||||||
* @param int $port
|
* @param int $port
|
||||||
* @param int $timeout
|
* @param int $timeout (in ms)
|
||||||
* @param string $user
|
* @param string $user
|
||||||
* @param string $password
|
* @param string $password
|
||||||
* @return Connection
|
* @return Connection
|
||||||
*/
|
*/
|
||||||
static function factory($host = '127.0.0.1', $port = 5000, $timeout = 5, $user = 'SuperAdmin', $password = 'SuperAdmin')
|
static function factory($host = '127.0.0.1', $port = 5000, $timeout = 50, $user = 'SuperAdmin', $password = 'SuperAdmin')
|
||||||
{
|
{
|
||||||
$key = $host.':'.$port;
|
$key = $host.':'.$port;
|
||||||
if(!isset(self::$instances[$key]))
|
if(!isset(self::$instances[$key]))
|
||||||
@ -56,6 +56,24 @@ class Connection
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change client timeouts
|
||||||
|
* @param int $read read timeout (in ms), null or 0 to leave unchanged
|
||||||
|
* @param int $write write timeout (in ms), null or 0 to leave unchanged
|
||||||
|
*/
|
||||||
|
function setTimeouts($read=null, $write=null)
|
||||||
|
{
|
||||||
|
$this->xmlrpcClient->setTimeouts($read, $write);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int Network idle time in seconds
|
||||||
|
*/
|
||||||
|
function getIdleTime()
|
||||||
|
{
|
||||||
|
return $this->xmlrpcClient->getIdleTime();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $host
|
* @param string $host
|
||||||
* @param int $port
|
* @param int $port
|
||||||
@ -65,7 +83,7 @@ class Connection
|
|||||||
*/
|
*/
|
||||||
protected function __construct($host, $port, $timeout, $user, $password)
|
protected function __construct($host, $port, $timeout, $user, $password)
|
||||||
{
|
{
|
||||||
$this->xmlrpcClient = new Xmlrpc\ClientMulticall($host, $port, $timeout);
|
$this->xmlrpcClient = new Xmlrpc\GbxRemote($host, $port, array('open' => $timeout));
|
||||||
$this->authenticate($user, $password);
|
$this->authenticate($user, $password);
|
||||||
$this->setApiVersion('2013-04-16');
|
$this->setApiVersion('2013-04-16');
|
||||||
}
|
}
|
||||||
@ -86,9 +104,7 @@ class Connection
|
|||||||
*/
|
*/
|
||||||
function executeCallbacks()
|
function executeCallbacks()
|
||||||
{
|
{
|
||||||
$this->xmlrpcClient->readCallbacks();
|
return $this->xmlrpcClient->getCallbacks();
|
||||||
$calls = $this->xmlrpcClient->getCallbackResponses();
|
|
||||||
return $calls;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -97,7 +113,7 @@ class Connection
|
|||||||
*/
|
*/
|
||||||
function executeMulticall()
|
function executeMulticall()
|
||||||
{
|
{
|
||||||
$this->xmlrpcClient->multiqueryIgnoreResult();
|
$this->xmlrpcClient->multiquery();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -114,9 +130,7 @@ class Connection
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
array_unshift($params, $methodName);
|
return $this->xmlrpcClient->query($methodName, $params);
|
||||||
call_user_func_array(array($this->xmlrpcClient, 'query'), $params);
|
|
||||||
return $this->xmlrpcClient->getResponse();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,9 +241,9 @@ class Connection
|
|||||||
throw new InvalidArgumentException('vote->cmdParam = '.print_r($vote->cmdParam, true));
|
throw new InvalidArgumentException('vote->cmdParam = '.print_r($vote->cmdParam, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
$tmpCmd = new Xmlrpc\Request($vote->cmdName, $vote->cmdParam);
|
$tmpCmd = Xmlrpc\Request::encode($vote->cmdName, $vote->cmdName);
|
||||||
|
|
||||||
return $this->execute(ucfirst(__FUNCTION__).'Ex', array($tmpCmd->getXml(), $ratio, $timeout, $voters), $multicall);
|
return $this->execute(ucfirst(__FUNCTION__).'Ex', array($tmpCmd, $ratio, $timeout, $voters), $multicall);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -264,9 +278,9 @@ class Connection
|
|||||||
throw new InvalidArgumentException('voters = '.print_r($voters, true));
|
throw new InvalidArgumentException('voters = '.print_r($voters, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
$tmpCmd = new Xmlrpc\Request('Kick', array($login));
|
$tmpCmd = Xmlrpc\Request::encode('Kick', array($login));
|
||||||
|
|
||||||
return $this->execute('CallVoteEx', array($tmpCmd->getXml(), $ratio, $timeout, $voters), $multicall);
|
return $this->execute('CallVoteEx', array($tmpCmd, $ratio, $timeout, $voters), $multicall);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -301,9 +315,9 @@ class Connection
|
|||||||
throw new InvalidArgumentException('voters = '.print_r($voters, true));
|
throw new InvalidArgumentException('voters = '.print_r($voters, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
$tmpCmd = new Xmlrpc\Request('Ban', array($login));
|
$tmpCmd = Xmlrpc\Request::encode('Ban', array($login));
|
||||||
|
|
||||||
return $this->execute('CallVoteEx', array($tmpCmd->getXml(), $ratio, $timeout, $voters), $multicall);
|
return $this->execute('CallVoteEx', array($tmpCmd, $ratio, $timeout, $voters), $multicall);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -333,9 +347,9 @@ class Connection
|
|||||||
throw new InvalidArgumentException('voters = '.print_r($voters, true));
|
throw new InvalidArgumentException('voters = '.print_r($voters, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
$tmpCmd = new Xmlrpc\Request('RestartMap', array());
|
$tmpCmd = Xmlrpc\Request::encode('RestartMap', array());
|
||||||
|
|
||||||
return $this->execute('CallVoteEx', array($tmpCmd->getXml(), $ratio, $timeout, $voters), $multicall);
|
return $this->execute('CallVoteEx', array($tmpCmd, $ratio, $timeout, $voters), $multicall);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -365,9 +379,9 @@ class Connection
|
|||||||
throw new InvalidArgumentException('voters = '.print_r($voters, true));
|
throw new InvalidArgumentException('voters = '.print_r($voters, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
$tmpCmd = new Xmlrpc\Request('NextMap', array());
|
$tmpCmd = Xmlrpc\Request::encode('NextMap', array());
|
||||||
|
|
||||||
return $this->execute('CallVoteEx', array($tmpCmd->getXml(), $ratio, $timeout, $voters), $multicall);
|
return $this->execute('CallVoteEx', array($tmpCmd, $ratio, $timeout, $voters), $multicall);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -832,11 +846,11 @@ class Connection
|
|||||||
{
|
{
|
||||||
return $this->execute(ucfirst(__FUNCTION__));
|
return $this->execute(ucfirst(__FUNCTION__));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens a link in the client with the specified players.
|
* Opens a link in the client with the specified players.
|
||||||
* The parameters are the login of the client to whom the link to open is sent, the link url, and the 'LinkType'
|
* The parameters are the login of the client to whom the link to open is sent, the link url, and the 'LinkType'
|
||||||
* (0 in the external browser, 1 in the internal manialink browser).
|
* (0 in the external browser, 1 in the internal manialink browser).
|
||||||
* Login can be a single login or a list of comma-separated logins. Only available to
|
* Login can be a single login or a list of comma-separated logins. Only available to
|
||||||
* @param Structures\Player|string|mixed[] $player
|
* @param Structures\Player|string|mixed[] $player
|
||||||
* @param string $link
|
* @param string $link
|
||||||
@ -859,7 +873,7 @@ class Connection
|
|||||||
{
|
{
|
||||||
throw new InvalidArgumentException('linkType = '.print_r($linkType, true));
|
throw new InvalidArgumentException('linkType = '.print_r($linkType, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->execute('SendOpenLinkToLogin', array($login, $link, $linkType), $multicall);
|
return $this->execute('SendOpenLinkToLogin', array($login, $link, $linkType), $multicall);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1229,14 +1243,8 @@ class Connection
|
|||||||
}
|
}
|
||||||
|
|
||||||
$inputData = file_get_contents($localFilename);
|
$inputData = file_get_contents($localFilename);
|
||||||
|
|
||||||
$data = new Xmlrpc\Base64($inputData);
|
$data = new Xmlrpc\Base64($inputData);
|
||||||
|
|
||||||
if(strlen($data->getXml()) > 1024 * 1024 - 15)
|
|
||||||
{
|
|
||||||
throw new InvalidArgumentException('file is too big');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->execute(ucfirst(__FUNCTION__), array($filename, $data), $multicall);
|
return $this->execute(ucfirst(__FUNCTION__), array($filename, $data), $multicall);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1257,11 +1265,6 @@ class Connection
|
|||||||
|
|
||||||
$data = new Xmlrpc\Base64($data);
|
$data = new Xmlrpc\Base64($data);
|
||||||
|
|
||||||
if(strlen($data->getXml()) > 1024 * 1024 - 15)
|
|
||||||
{
|
|
||||||
throw new InvalidArgumentException('data are too big');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->execute('WriteFile', array($filename, $data), $multicall);
|
return $this->execute('WriteFile', array($filename, $data), $multicall);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1284,13 +1287,8 @@ class Connection
|
|||||||
{
|
{
|
||||||
throw new InvalidArgumentException('filename = '.print_r($filename, true));
|
throw new InvalidArgumentException('filename = '.print_r($filename, true));
|
||||||
}
|
}
|
||||||
if(filesize($filename) > 4 * 1024)
|
|
||||||
{
|
|
||||||
throw new InvalidArgumentException('file is too big');
|
|
||||||
}
|
|
||||||
|
|
||||||
$inputData = file_get_contents($filename);
|
$inputData = file_get_contents($filename);
|
||||||
|
|
||||||
$data = new Xmlrpc\Base64($inputData);
|
$data = new Xmlrpc\Base64($inputData);
|
||||||
|
|
||||||
return $this->execute('TunnelSendDataToLogin', array($login, $data), $multicall);
|
return $this->execute('TunnelSendDataToLogin', array($login, $data), $multicall);
|
||||||
@ -1541,9 +1539,9 @@ class Connection
|
|||||||
|
|
||||||
return $this->execute(ucfirst(__FUNCTION__), array($downloadRate, $uploadRate), $multicall);
|
return $this->execute(ucfirst(__FUNCTION__), array($downloadRate, $uploadRate), $multicall);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the list of tags and associated values set on this server.
|
* Returns the list of tags and associated values set on this server.
|
||||||
* The list is an array of structures {string Name, string Value}.
|
* The list is an array of structures {string Name, string Value}.
|
||||||
* Only available to Admin.
|
* Only available to Admin.
|
||||||
* @return array
|
* @return array
|
||||||
@ -1552,10 +1550,10 @@ class Connection
|
|||||||
{
|
{
|
||||||
return $this->execute(ucfirst(__FUNCTION__));
|
return $this->execute(ucfirst(__FUNCTION__));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a tag and its value on the server. This method takes two parameters.
|
* Set a tag and its value on the server. This method takes two parameters.
|
||||||
* The first parameter specifies the name of the tag, and the second one its value.
|
* The first parameter specifies the name of the tag, and the second one its value.
|
||||||
* Only available to Admin.
|
* Only available to Admin.
|
||||||
* @param string $key
|
* @param string $key
|
||||||
* @param string $value
|
* @param string $value
|
||||||
@ -1575,9 +1573,9 @@ class Connection
|
|||||||
}
|
}
|
||||||
return $this->execute(ucfirst(__FUNCTION__), array($key, $value), $multicall);
|
return $this->execute(ucfirst(__FUNCTION__), array($key, $value), $multicall);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unset the tag with the specified name on the server.
|
* Unset the tag with the specified name on the server.
|
||||||
* Only available to Admin.
|
* Only available to Admin.
|
||||||
* @param string $key
|
* @param string $key
|
||||||
* @param bool $multicall
|
* @param bool $multicall
|
||||||
@ -1592,9 +1590,9 @@ class Connection
|
|||||||
}
|
}
|
||||||
return $this->execute(ucfirst(__FUNCTION__), array($key), $multicall);
|
return $this->execute(ucfirst(__FUNCTION__), array($key), $multicall);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset all tags on the server.
|
* Reset all tags on the server.
|
||||||
* Only available to Admin.
|
* Only available to Admin.
|
||||||
* @param bool $multicall
|
* @param bool $multicall
|
||||||
* @return bool
|
* @return bool
|
||||||
@ -1833,7 +1831,7 @@ class Connection
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get whether the server if a lobby, the number and maximum number of players currently managed by it.
|
* Get whether the server if a lobby, the number and maximum number of players currently managed by it.
|
||||||
* The struct returned contains 4 fields IsLobby, LobbyPlayers, LobbyMaxPlayers, and LobbyPlayersLevel.
|
* The struct returned contains 4 fields IsLobby, LobbyPlayers, LobbyMaxPlayers, and LobbyPlayersLevel.
|
||||||
* @return Structures\LobbyInfo
|
* @return Structures\LobbyInfo
|
||||||
*/
|
*/
|
||||||
@ -1842,9 +1840,9 @@ class Connection
|
|||||||
$result = $this->execute(ucfirst(__FUNCTION__));
|
$result = $this->execute(ucfirst(__FUNCTION__));
|
||||||
return Structures\LobbyInfo::fromArray($result);
|
return Structures\LobbyInfo::fromArray($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Customize the clients 'leave server' dialog box.
|
* Customize the clients 'leave server' dialog box.
|
||||||
* Parameters are: ManialinkPage, SendToServer url '#qjoin=login@title',
|
* Parameters are: ManialinkPage, SendToServer url '#qjoin=login@title',
|
||||||
* ProposeAddToFavorites and DelayQuitButton (in milliseconds).
|
* ProposeAddToFavorites and DelayQuitButton (in milliseconds).
|
||||||
* Only available to Admin.
|
* Only available to Admin.
|
||||||
@ -2077,7 +2075,7 @@ class Connection
|
|||||||
* Returns a replay containing the data needed to validate the current best time of the player.
|
* Returns a replay containing the data needed to validate the current best time of the player.
|
||||||
* The parameter is the login of the player.
|
* The parameter is the login of the player.
|
||||||
* @param Structures\Player|string $player
|
* @param Structures\Player|string $player
|
||||||
* @return string base64 encoded
|
* @return string
|
||||||
* @throws InvalidArgumentException
|
* @throws InvalidArgumentException
|
||||||
*/
|
*/
|
||||||
function getValidationReplay($player)
|
function getValidationReplay($player)
|
||||||
@ -2086,7 +2084,7 @@ class Connection
|
|||||||
{
|
{
|
||||||
throw new InvalidArgumentException('player must be set');
|
throw new InvalidArgumentException('player must be set');
|
||||||
}
|
}
|
||||||
return $this->execute(ucfirst(__FUNCTION__), array($login));
|
return $this->execute(ucfirst(__FUNCTION__), array($login))->scalar;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2639,7 +2637,7 @@ class Connection
|
|||||||
{
|
{
|
||||||
return $this->execute(ucfirst(__FUNCTION__), array($rules), $multicall);
|
return $this->execute(ucfirst(__FUNCTION__), array($rules), $multicall);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send commands to the mode script.
|
* Send commands to the mode script.
|
||||||
* Only available to Admin.
|
* Only available to Admin.
|
||||||
@ -2651,9 +2649,9 @@ class Connection
|
|||||||
{
|
{
|
||||||
return $this->execute(ucfirst(__FUNCTION__), array($commands), $multicall);
|
return $this->execute(ucfirst(__FUNCTION__), array($commands), $multicall);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change the settings and send commands to the mode script.
|
* Change the settings and send commands to the mode script.
|
||||||
* Only available to Admin.
|
* Only available to Admin.
|
||||||
* @param array $settings
|
* @param array $settings
|
||||||
* @param array $commands
|
* @param array $commands
|
||||||
@ -3590,9 +3588,9 @@ class Connection
|
|||||||
}
|
}
|
||||||
return $this->execute(ucfirst(__FUNCTION__), array($fakePlayerLogin), $multicall);
|
return $this->execute(ucfirst(__FUNCTION__), array($fakePlayerLogin), $multicall);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the token infos for a player.
|
* Returns the token infos for a player.
|
||||||
* The returned structure is { TokenCost, CanPayToken }.
|
* The returned structure is { TokenCost, CanPayToken }.
|
||||||
* @param Structures\Player|string $player
|
* @param Structures\Player|string $player
|
||||||
* @return array
|
* @return array
|
||||||
@ -4392,28 +4390,9 @@ class Connection
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Exception Dedicated to Query Error
|
|
||||||
*/
|
|
||||||
class QueryException extends \Exception
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exception Dedicated to Connection Error
|
|
||||||
*/
|
|
||||||
class ConnectionException extends \Exception
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exception Dedicated to Invalid Argument Error on Request Call
|
* Exception Dedicated to Invalid Argument Error on Request Call
|
||||||
*/
|
*/
|
||||||
class InvalidArgumentException extends \Exception
|
class InvalidArgumentException extends \Exception {}
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
@ -7,18 +7,17 @@
|
|||||||
|
|
||||||
namespace Maniaplanet\DedicatedServer\Xmlrpc;
|
namespace Maniaplanet\DedicatedServer\Xmlrpc;
|
||||||
|
|
||||||
class Base64
|
class Base64
|
||||||
{
|
{
|
||||||
public $data;
|
public $scalar;
|
||||||
|
public $xmlrpc_type = 'base64';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $data
|
||||||
|
*/
|
||||||
function __construct($data)
|
function __construct($data)
|
||||||
{
|
{
|
||||||
$this->data = $data;
|
$this->scalar = $data;
|
||||||
}
|
|
||||||
|
|
||||||
function getXml()
|
|
||||||
{
|
|
||||||
return '<base64>'.base64_encode($this->data).'</base64>';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,481 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* ManiaPlanet dedicated server Xml-RPC client
|
|
||||||
*
|
|
||||||
* @license http://www.gnu.org/licenses/lgpl.html LGPL License 3
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Maniaplanet\DedicatedServer\Xmlrpc;
|
|
||||||
|
|
||||||
if (!defined('LF'))
|
|
||||||
{
|
|
||||||
define('LF', "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!defined('SIZE_MAX'))
|
|
||||||
{
|
|
||||||
define('SIZE_MAX', 4096*1024);
|
|
||||||
}
|
|
||||||
|
|
||||||
class Client
|
|
||||||
{
|
|
||||||
public $socket;
|
|
||||||
public $message = false;
|
|
||||||
public $cb_message = array();
|
|
||||||
public $reqhandle;
|
|
||||||
public $protocol = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var int Timeout in milli-seconds
|
|
||||||
*/
|
|
||||||
public $timeout;
|
|
||||||
|
|
||||||
static $received;
|
|
||||||
static $sent;
|
|
||||||
|
|
||||||
function bigEndianTest()
|
|
||||||
{
|
|
||||||
list($endiantest) = array_values(unpack('L1L', pack('V', 1)));
|
|
||||||
if ($endiantest != 1)
|
|
||||||
{
|
|
||||||
if(!function_exists(__NAMESPACE__.'\\unpack'))
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The following code is a workaround for php's unpack function which
|
|
||||||
* does not have the capability of unpacking double precision floats
|
|
||||||
* that were packed in the opposite byte order of the current machine.
|
|
||||||
*/
|
|
||||||
function unpack($format, $data)
|
|
||||||
{
|
|
||||||
$ar = unpack($format, $data);
|
|
||||||
$vals = array_values($ar);
|
|
||||||
$f = explode('/', $format);
|
|
||||||
$i = 0;
|
|
||||||
foreach ($f as $f_k => $f_v)
|
|
||||||
{
|
|
||||||
$repeater = intval(substr($f_v, 1));
|
|
||||||
if ($repeater == 0)
|
|
||||||
{
|
|
||||||
$repeater = 1;
|
|
||||||
}
|
|
||||||
if ($f_v{1} == '*')
|
|
||||||
{
|
|
||||||
$repeater = count($ar) - $i;
|
|
||||||
}
|
|
||||||
if ($f_v{0} != 'd')
|
|
||||||
{
|
|
||||||
$i += $repeater;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$j = $i + $repeater;
|
|
||||||
for ($a = $i; $a < $j; ++$a)
|
|
||||||
{
|
|
||||||
$p = pack('d', $vals[$i]);
|
|
||||||
$p = strrev($p);
|
|
||||||
list($vals[$i]) = array_values(unpack('d1d', $p));
|
|
||||||
++$i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$a = 0;
|
|
||||||
foreach ($ar as $ar_k => $ar_v)
|
|
||||||
{
|
|
||||||
$ar[$ar_k] = $vals[$a];
|
|
||||||
++$a;
|
|
||||||
}
|
|
||||||
return $ar;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param string $hostname
|
|
||||||
* @param int $port
|
|
||||||
* @param int $timeout In milliseconds
|
|
||||||
*/
|
|
||||||
function __construct($hostname, $port, $timeout = 50)
|
|
||||||
{
|
|
||||||
$this->socket = false;
|
|
||||||
$this->reqhandle = 0x80000000;
|
|
||||||
$this->timeout = $timeout;
|
|
||||||
$this->init($hostname, $port);
|
|
||||||
}
|
|
||||||
|
|
||||||
function __destruct()
|
|
||||||
{
|
|
||||||
$this->terminate();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function init($hostname, $port)
|
|
||||||
{
|
|
||||||
|
|
||||||
$this->bigEndianTest();
|
|
||||||
|
|
||||||
// open connection
|
|
||||||
$this->socket = @fsockopen($hostname, $port, $errno, $errstr, $this->timeout);
|
|
||||||
if (!$this->socket)
|
|
||||||
{
|
|
||||||
throw new FatalException("transport error - could not open socket (error: $errno, $errstr)", FatalException::NOT_INITIALIZED);
|
|
||||||
}
|
|
||||||
// handshake
|
|
||||||
$array_result = unpack('Vsize', fread($this->socket, 4));
|
|
||||||
$size = $array_result['size'];
|
|
||||||
if ($size > 64)
|
|
||||||
{
|
|
||||||
throw new FatalException('transport error - wrong lowlevel protocol header', FatalException::OTHER);
|
|
||||||
}
|
|
||||||
$handshake = fread($this->socket, $size);
|
|
||||||
if ($handshake == 'GBXRemote 1')
|
|
||||||
{
|
|
||||||
$this->protocol = 1;
|
|
||||||
}
|
|
||||||
elseif ($handshake == 'GBXRemote 2')
|
|
||||||
{
|
|
||||||
$this->protocol = 2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new FatalException('transport error - wrong lowlevel protocol version', FatalException::OTHER);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function terminate()
|
|
||||||
{
|
|
||||||
if ($this->socket)
|
|
||||||
{
|
|
||||||
fclose($this->socket);
|
|
||||||
$this->socket = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function sendRequest(Request $request)
|
|
||||||
{
|
|
||||||
$xml = $request->getXml();
|
|
||||||
|
|
||||||
@stream_set_timeout($this->socket, 0, $this->timeout * 1000 * 200);
|
|
||||||
// send request
|
|
||||||
$this->reqhandle++;
|
|
||||||
if ($this->protocol == 1)
|
|
||||||
{
|
|
||||||
$bytes = pack('Va*', strlen($xml), $xml);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$bytes = pack('VVa*', strlen($xml), $this->reqhandle, $xml);
|
|
||||||
}
|
|
||||||
|
|
||||||
$bytes_to_write = strlen($bytes);
|
|
||||||
|
|
||||||
// increase sent counter ...
|
|
||||||
self::$sent += $bytes_to_write;
|
|
||||||
|
|
||||||
while ($bytes_to_write > 0)
|
|
||||||
{
|
|
||||||
$r = fwrite($this->socket, $bytes);
|
|
||||||
if ($r === false || $r == 0)
|
|
||||||
{
|
|
||||||
throw new FatalException('Connection interupted', FatalException::INTERRUPTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
$bytes_to_write -= $r;
|
|
||||||
if ($bytes_to_write == 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
$bytes = substr($bytes, $r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getResult()
|
|
||||||
{
|
|
||||||
$contents = '';
|
|
||||||
$contents_length = 0;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
$size = 0;
|
|
||||||
$recvhandle = 0;
|
|
||||||
@stream_set_timeout($this->socket, 0, $this->timeout * 1000 * 1000);
|
|
||||||
// Get result
|
|
||||||
if ($this->protocol == 1)
|
|
||||||
{
|
|
||||||
$contents = fread($this->socket, 4);
|
|
||||||
if (strlen($contents) == 0 || $contents === false)
|
|
||||||
{
|
|
||||||
throw new FatalException('transport error - connection interrupted!', FatalException::INTERRUPTED);
|
|
||||||
}
|
|
||||||
$array_result = unpack('Vsize', $contents);
|
|
||||||
$size = $array_result['size'];
|
|
||||||
$recvhandle = $this->reqhandle;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$contents = fread($this->socket, 8);
|
|
||||||
if (strlen($contents) == 0 || $contents === false)
|
|
||||||
{
|
|
||||||
throw new FatalException('transport error - connection interrupted!', FatalException::INTERRUPTED);
|
|
||||||
}
|
|
||||||
$array_result = unpack('Vsize/Vhandle', $contents);
|
|
||||||
$size = $array_result['size'];
|
|
||||||
$recvhandle = $array_result['handle'];
|
|
||||||
// -- amd64 support --
|
|
||||||
$bits = sprintf('%b', $recvhandle);
|
|
||||||
if (strlen($bits) == 64)
|
|
||||||
{
|
|
||||||
$recvhandle = bindec(substr($bits, 32));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($recvhandle == 0 || $size == 0)
|
|
||||||
{
|
|
||||||
throw new FatalException('transport error - connection interrupted!', FatalException::INTERRUPTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($size > SIZE_MAX)
|
|
||||||
{
|
|
||||||
throw new Exception("transport error - answer too big ($size)", Exception::ANWSER_TOO_BIG);
|
|
||||||
}
|
|
||||||
|
|
||||||
self::$received += $size;
|
|
||||||
|
|
||||||
$contents = '';
|
|
||||||
$contents_length = 0;
|
|
||||||
@stream_set_timeout($this->socket, 0, $this->timeout * 1000);
|
|
||||||
while ($contents_length < $size)
|
|
||||||
{
|
|
||||||
$contents .= fread($this->socket, $size-$contents_length);
|
|
||||||
$contents_length = strlen($contents);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (($recvhandle & 0x80000000) == 0)
|
|
||||||
{
|
|
||||||
// this is a callback, not our answer! handle= $recvhandle, xml-rpc= $contents
|
|
||||||
// just add it to the message list for the user to read
|
|
||||||
$new_cb_message = new Message($contents);
|
|
||||||
if ($new_cb_message->parse() && $new_cb_message->messageType != 'fault')
|
|
||||||
{
|
|
||||||
array_push($this->cb_message, array($new_cb_message->methodName, $new_cb_message->params));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while ((int)$recvhandle != (int)$this->reqhandle);
|
|
||||||
|
|
||||||
$this->message = new Message($contents);
|
|
||||||
if (!$this->message->parse())
|
|
||||||
{
|
|
||||||
// XML error
|
|
||||||
throw new Exception('parse error. not well formed', Exception::OTHER);
|
|
||||||
}
|
|
||||||
// Is the message a fault?
|
|
||||||
if ($this->message->messageType == 'fault')
|
|
||||||
{
|
|
||||||
throw new Exception($this->message->faultString, $this->message->faultCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->message;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function query()
|
|
||||||
{
|
|
||||||
$args = func_get_args();
|
|
||||||
$method = array_shift($args);
|
|
||||||
|
|
||||||
if (!$this->socket || $this->protocol == 0)
|
|
||||||
{
|
|
||||||
throw new FatalException('deb4 transport error - Client not initialized', FatalException::NOT_INITIALIZED);
|
|
||||||
}
|
|
||||||
|
|
||||||
$request = new Request($method, $args);
|
|
||||||
|
|
||||||
// Check if request is larger than 1024 Kbytes
|
|
||||||
if ($request->getLength() > 1024*1024-8)
|
|
||||||
{
|
|
||||||
throw new Exception('transport error - request too large!', Exception::REQUEST_TOO_BIG);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->sendRequest($request);
|
|
||||||
return $this->getResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Non-blocking query method: doesn't read the response
|
|
||||||
function queryIgnoreResult()
|
|
||||||
{
|
|
||||||
$args = func_get_args();
|
|
||||||
$method = array_shift($args);
|
|
||||||
|
|
||||||
if (!$this->socket || $this->protocol == 0)
|
|
||||||
{
|
|
||||||
throw new FatalException('deb 5transport error - Client not initialized', FatalException::NOT_INITIALIZED);
|
|
||||||
}
|
|
||||||
|
|
||||||
$request = new Request($method, $args);
|
|
||||||
|
|
||||||
// Check if the request is greater than 512 Kbytes to avoid errors
|
|
||||||
// If the method is system.multicall, make two calls (possibly recursively)
|
|
||||||
if ($request->getLength() > 1024*1024-8)
|
|
||||||
{
|
|
||||||
if ($method == 'system.multicall' && isset($args[0]))
|
|
||||||
{
|
|
||||||
$count = count($args[0]);
|
|
||||||
// If count is 1, query cannot be reduced
|
|
||||||
if ($count < 2)
|
|
||||||
{
|
|
||||||
throw new Exception('transport error - request too large!', Exception::REQUEST_TOO_BIG);
|
|
||||||
}
|
|
||||||
$length = floor($count/2);
|
|
||||||
|
|
||||||
$args1 = array_slice($args[0], 0, $length);
|
|
||||||
$args2 = array_slice($args[0], $length, ($count-$length));
|
|
||||||
|
|
||||||
$res1 = $this->queryIgnoreResult('system.multicall', $args1);
|
|
||||||
$res2 = $this->queryIgnoreResult('system.multicall', $args2);
|
|
||||||
return ($res1 && $res2);
|
|
||||||
}
|
|
||||||
// If the method is not a multicall, just stop
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new Exception('transport error - request too large!', Exception::REQUEST_TOO_BIG);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->sendRequest($request);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getResponse()
|
|
||||||
{
|
|
||||||
// methodResponses can only have one param - return that
|
|
||||||
return $this->message->params[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
function readCallbacks()
|
|
||||||
{
|
|
||||||
if (!$this->socket || $this->protocol == 0)
|
|
||||||
throw new FatalException('transport error - Client not initialized', FatalException::NOT_INITIALIZED);
|
|
||||||
if ($this->protocol == 1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
@stream_set_timeout($this->socket, 0, $this->timeout * 20); // timeout 1 ms (to read available data)
|
|
||||||
// (assignment in arguments is forbidden since php 5.1.1)
|
|
||||||
$read = array($this->socket);
|
|
||||||
$write = NULL;
|
|
||||||
$except = NULL;
|
|
||||||
$nb = false;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
$nb = @stream_select($read, $write, $except, 0, $this->timeout * 20);
|
|
||||||
}
|
|
||||||
catch (\Exception $e)
|
|
||||||
{
|
|
||||||
if (strpos($e->getMessage(), 'Invalid CRT') !== false)
|
|
||||||
{
|
|
||||||
$nb = true;
|
|
||||||
}
|
|
||||||
elseif (strpos($e->getMessage(), 'Interrupted system call') !== false)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw $e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// workaround for stream_select bug with amd64
|
|
||||||
if ($nb !== false)
|
|
||||||
{
|
|
||||||
$nb = count($read);
|
|
||||||
}
|
|
||||||
|
|
||||||
while ($nb !== false && $nb > 0)
|
|
||||||
{
|
|
||||||
// Get result
|
|
||||||
$contents = '';
|
|
||||||
while(strlen($contents) < 8){
|
|
||||||
$contents .= fread($this->socket, 8 - strlen($contents));
|
|
||||||
if (strlen($contents) == 0 || $contents === false)
|
|
||||||
{
|
|
||||||
var_dump("deb6 transport error");
|
|
||||||
//throw new FatalException('deb6 transport error - connection interrupted!', FatalException::INTERRUPTED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$array_result = unpack('Vsize/Vhandle', $contents);
|
|
||||||
$size = $array_result['size'];
|
|
||||||
$recvhandle = $array_result['handle'];
|
|
||||||
|
|
||||||
if ($recvhandle == 0 || $size == 0)
|
|
||||||
{
|
|
||||||
throw new FatalException('deb7 transport error - connection interrupted!', FatalException::INTERRUPTED);
|
|
||||||
}
|
|
||||||
if ($size > SIZE_MAX)
|
|
||||||
{
|
|
||||||
throw new Exception("transport error - answer too big ($size)", Exception::ANWSER_TOO_BIG);
|
|
||||||
}
|
|
||||||
|
|
||||||
self::$received += $size;
|
|
||||||
|
|
||||||
$contents = '';
|
|
||||||
$contents_length = 0;
|
|
||||||
while ($contents_length < $size)
|
|
||||||
{
|
|
||||||
$contents .= fread($this->socket, $size-$contents_length);
|
|
||||||
$contents_length = strlen($contents);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (($recvhandle & 0x80000000) == 0)
|
|
||||||
{
|
|
||||||
// this is a callback. handle= $recvhandle, xml-rpc= $contents
|
|
||||||
//echo 'CALLBACK('.$contents_length.')[ '.$contents.' ]' . LF;
|
|
||||||
$new_cb_message = new Message($contents);
|
|
||||||
if ($new_cb_message->parse() && $new_cb_message->messageType != 'fault')
|
|
||||||
{
|
|
||||||
array_push($this->cb_message, array($new_cb_message->methodName, $new_cb_message->params));
|
|
||||||
}
|
|
||||||
// flo: moved to end ...
|
|
||||||
// $something_received = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// (assignment in arguments is forbidden since php 5.1.1)
|
|
||||||
$read = array($this->socket);
|
|
||||||
$write = NULL;
|
|
||||||
$except = NULL;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
$nb = @stream_select($read, $write, $except, 0, 0); // Notimeout, just flush the data
|
|
||||||
}
|
|
||||||
catch (\Exception $e)
|
|
||||||
{
|
|
||||||
if (strpos($e->getMessage(), 'Invalid CRT') !== false)
|
|
||||||
{
|
|
||||||
$nb = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw $e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// workaround for stream_select bug with amd64
|
|
||||||
if ($nb !== false)
|
|
||||||
{
|
|
||||||
$nb = count($read);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//stream_set_blocking($this->socket, true);
|
|
||||||
return !empty($this->cb_message);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getCallbackResponses()
|
|
||||||
{
|
|
||||||
// (look at the end of basic.php for an example)
|
|
||||||
$messages = $this->cb_message;
|
|
||||||
$this->cb_message = array();
|
|
||||||
return $messages;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
@ -1,47 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* ManiaPlanet dedicated server Xml-RPC client
|
|
||||||
*
|
|
||||||
* @license http://www.gnu.org/licenses/lgpl.html LGPL License 3
|
|
||||||
*/
|
|
||||||
|
|
||||||
// TODO XMLRPCLib: remettre les credits
|
|
||||||
|
|
||||||
namespace Maniaplanet\DedicatedServer\Xmlrpc;
|
|
||||||
|
|
||||||
if (!defined('LF')) define('LF', "\n");
|
|
||||||
|
|
||||||
class ClientMulticall extends Client
|
|
||||||
{
|
|
||||||
public $calls = array();
|
|
||||||
|
|
||||||
function addCall($methodName, $args)
|
|
||||||
{
|
|
||||||
$struct = array('methodName' => $methodName, 'params' => $args);
|
|
||||||
$this->calls[] = $struct;
|
|
||||||
|
|
||||||
return (count($this->calls) - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
function multiquery()
|
|
||||||
{
|
|
||||||
$result = array();
|
|
||||||
if(count($this->calls))
|
|
||||||
{
|
|
||||||
$result = parent::query('system.multicall', $this->calls);
|
|
||||||
$this->calls = array(); // reset for next calls
|
|
||||||
}
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function multiqueryIgnoreResult()
|
|
||||||
{
|
|
||||||
if(count($this->calls))
|
|
||||||
{
|
|
||||||
parent::queryIgnoreResult('system.multicall', $this->calls);
|
|
||||||
$this->calls = array(); // reset for next calls
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
@ -1,68 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* ManiaPlanet dedicated server Xml-RPC client
|
|
||||||
*
|
|
||||||
* @license http://www.gnu.org/licenses/lgpl.html LGPL License 3
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Maniaplanet\DedicatedServer\Xmlrpc;
|
|
||||||
|
|
||||||
class Date
|
|
||||||
{
|
|
||||||
public $year;
|
|
||||||
public $month;
|
|
||||||
public $day;
|
|
||||||
public $hour;
|
|
||||||
public $minute;
|
|
||||||
public $second;
|
|
||||||
|
|
||||||
function __construct($time)
|
|
||||||
{
|
|
||||||
// $time can be a PHP timestamp or an ISO one
|
|
||||||
if (is_numeric($time))
|
|
||||||
{
|
|
||||||
$this->parseTimestamp($time);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$this->parseIso($time);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseTimestamp($timestamp)
|
|
||||||
{
|
|
||||||
$this->year = date('Y', $timestamp);
|
|
||||||
$this->month = date('m', $timestamp);
|
|
||||||
$this->day = date('d', $timestamp);
|
|
||||||
$this->hour = date('H', $timestamp);
|
|
||||||
$this->minute = date('i', $timestamp);
|
|
||||||
$this->second = date('s', $timestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseIso($iso)
|
|
||||||
{
|
|
||||||
$this->year = substr($iso, 0, 4);
|
|
||||||
$this->month = substr($iso, 4, 2);
|
|
||||||
$this->day = substr($iso, 6, 2);
|
|
||||||
$this->hour = substr($iso, 9, 2);
|
|
||||||
$this->minute = substr($iso, 12, 2);
|
|
||||||
$this->second = substr($iso, 15, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getIso()
|
|
||||||
{
|
|
||||||
return $this->year.$this->month.$this->day.'T'.$this->hour.':'.$this->minute.':'.$this->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getXml()
|
|
||||||
{
|
|
||||||
return '<dateTime.iso8601>'.$this->getIso().'</dateTime.iso8601>';
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTimestamp()
|
|
||||||
{
|
|
||||||
return mktime($this->hour, $this->minute, $this->second, $this->month, $this->day, $this->year);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
@ -7,11 +7,6 @@
|
|||||||
|
|
||||||
namespace Maniaplanet\DedicatedServer\Xmlrpc;
|
namespace Maniaplanet\DedicatedServer\Xmlrpc;
|
||||||
|
|
||||||
class Exception extends \Exception
|
class Exception extends \Exception {}
|
||||||
{
|
|
||||||
const ANWSER_TOO_BIG = 1;
|
|
||||||
const REQUEST_TOO_BIG = 2;
|
|
||||||
const OTHER = 999;
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* @version $Revision: $:
|
|
||||||
* @author $Author: $:
|
|
||||||
* @date $Date: $:
|
|
||||||
*/
|
|
||||||
namespace Maniaplanet\DedicatedServer\Xmlrpc;
|
|
||||||
|
|
||||||
class FatalException extends Exception
|
|
||||||
{
|
|
||||||
const NOT_INITIALIZED = 1;
|
|
||||||
const INTERRUPTED = 2;
|
|
||||||
const OTHER = 999;
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
@ -0,0 +1,321 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ManiaPlanet dedicated server Xml-RPC client
|
||||||
|
*
|
||||||
|
* @license http://www.gnu.org/licenses/lgpl.html LGPL License 3
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Maniaplanet\DedicatedServer\Xmlrpc;
|
||||||
|
|
||||||
|
class GbxRemote
|
||||||
|
{
|
||||||
|
const MAX_REQUEST_SIZE = 0x200000; // 2MB
|
||||||
|
const MAX_RESPONSE_SIZE = 0x400000; // 4MB
|
||||||
|
|
||||||
|
public static $received;
|
||||||
|
public static $sent;
|
||||||
|
|
||||||
|
private $socket;
|
||||||
|
private $timeouts = array(
|
||||||
|
'open' => 5,
|
||||||
|
'read' => 1000,
|
||||||
|
'write' => 1000
|
||||||
|
);
|
||||||
|
private $requestHandle;
|
||||||
|
private $callbacksBuffer = array();
|
||||||
|
private $multicallBuffer = array();
|
||||||
|
private $lastNetworkActivity = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $host
|
||||||
|
* @param int $port
|
||||||
|
* @param int[string] $timeouts Override default timeouts for 'open' (in s), 'read' (in ms) and 'write' (in ms) socket operations
|
||||||
|
*/
|
||||||
|
function __construct($host, $port, $timeouts = array())
|
||||||
|
{
|
||||||
|
$this->requestHandle = (int) 0x80000000;
|
||||||
|
$this->timeouts = array_merge($this->timeouts, $timeouts);
|
||||||
|
$this->connect($host, $port);
|
||||||
|
}
|
||||||
|
|
||||||
|
function __destruct()
|
||||||
|
{
|
||||||
|
$this->terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change timeouts
|
||||||
|
* @param int $read read timeout (in ms), null or 0 to leave unchanged
|
||||||
|
* @param int $write write timeout (in ms), null or 0 to leave unchanged
|
||||||
|
*/
|
||||||
|
function setTimeouts($read=null, $write=null)
|
||||||
|
{
|
||||||
|
if($read)
|
||||||
|
$this->timeouts['read'] = $read;
|
||||||
|
if($write)
|
||||||
|
$this->timeouts['write'] = $write;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int Network idle time in seconds
|
||||||
|
*/
|
||||||
|
function getIdleTime()
|
||||||
|
{
|
||||||
|
$this->assertConnected();
|
||||||
|
return time() - $this->lastNetworkActivity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $host
|
||||||
|
* @param int $port
|
||||||
|
* @throws TransportException
|
||||||
|
*/
|
||||||
|
private function connect($host, $port)
|
||||||
|
{
|
||||||
|
$this->socket = @fsockopen($host, $port, $errno, $errstr, $this->timeouts['open']);
|
||||||
|
stream_set_write_buffer($this->socket, 0);
|
||||||
|
if(!$this->socket)
|
||||||
|
throw new TransportException('Cannot open socket', TransportException::NOT_INITIALIZED);
|
||||||
|
|
||||||
|
// handshake
|
||||||
|
$header = $this->read(15);
|
||||||
|
if($header === false)
|
||||||
|
throw new TransportException('Connection interrupted during handshake', TransportException::INTERRUPTED);
|
||||||
|
|
||||||
|
extract(unpack('Vsize/a*protocol', $header));
|
||||||
|
/** @var $size int */
|
||||||
|
/** @var $protocol string */
|
||||||
|
if($size != 11 || $protocol != 'GBXRemote 2')
|
||||||
|
throw new TransportException('Wrong protocol header', TransportException::WRONG_PROTOCOL);
|
||||||
|
$this->lastNetworkActivity = time();
|
||||||
|
}
|
||||||
|
|
||||||
|
function terminate()
|
||||||
|
{
|
||||||
|
if($this->socket)
|
||||||
|
{
|
||||||
|
fclose($this->socket);
|
||||||
|
$this->socket = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $method
|
||||||
|
* @param mixed[] $args
|
||||||
|
* @return mixed
|
||||||
|
* @throws MessageException
|
||||||
|
*/
|
||||||
|
function query($method, $args=array())
|
||||||
|
{
|
||||||
|
$this->assertConnected();
|
||||||
|
$xml = Request::encode($method, $args);
|
||||||
|
|
||||||
|
if(strlen($xml) > self::MAX_REQUEST_SIZE-8)
|
||||||
|
{
|
||||||
|
if($method != 'system.multicall' || count($args) < 2)
|
||||||
|
throw new MessageException('Request too large', MessageException::REQUEST_TOO_LARGE);
|
||||||
|
|
||||||
|
$mid = count($args) >> 1;
|
||||||
|
$this->query('system.multicall', array_slice($args, 0, $mid));
|
||||||
|
$this->query('system.multicall', array_slice($args, $mid));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->writeMessage($xml);
|
||||||
|
return $this->flush(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $method
|
||||||
|
* @param mixed[] $args
|
||||||
|
*/
|
||||||
|
function addCall($method, $args)
|
||||||
|
{
|
||||||
|
$this->multicallBuffer[] = array(
|
||||||
|
'methodName' => $method,
|
||||||
|
'params' => $args
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
function multiquery()
|
||||||
|
{
|
||||||
|
switch(count($this->multicallBuffer))
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return;
|
||||||
|
case 1:
|
||||||
|
$call = array_shift($this->multicallBuffer);
|
||||||
|
return $this->query($call['methodName'], $call['params']);
|
||||||
|
default:
|
||||||
|
$result = $this->query('system.multicall', $this->multicallBuffer);
|
||||||
|
$this->multicallBuffer = array();
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed[]
|
||||||
|
*/
|
||||||
|
function getCallbacks()
|
||||||
|
{
|
||||||
|
$this->assertConnected();
|
||||||
|
$this->flush();
|
||||||
|
$cb = $this->callbacksBuffer;
|
||||||
|
$this->callbacksBuffer = array();
|
||||||
|
return $cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws TransportException
|
||||||
|
*/
|
||||||
|
private function assertConnected()
|
||||||
|
{
|
||||||
|
if(!$this->socket)
|
||||||
|
throw new TransportException('Connection not initialized', TransportException::NOT_INITIALIZED);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bool $waitResponse
|
||||||
|
* @return mixed
|
||||||
|
* @throws FaultException
|
||||||
|
*/
|
||||||
|
private function flush($waitResponse=false)
|
||||||
|
{
|
||||||
|
$n = @stream_select($r=array($this->socket), $w=null, $e=null, 0);
|
||||||
|
while($waitResponse || $n > 0)
|
||||||
|
{
|
||||||
|
list($handle, $xml) = $this->readMessage();
|
||||||
|
list($type, $value) = Request::decode($xml);
|
||||||
|
switch($type)
|
||||||
|
{
|
||||||
|
case 'fault':
|
||||||
|
throw FaultException::create($value['faultString'], $value['faultCode']);
|
||||||
|
case 'response':
|
||||||
|
if($handle == $this->requestHandle)
|
||||||
|
return $value;
|
||||||
|
break;
|
||||||
|
case 'call':
|
||||||
|
$this->callbacksBuffer[] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!$waitResponse)
|
||||||
|
$n = @stream_select($r=array($this->socket), $w=null, $e=null, 0);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed[]
|
||||||
|
* @throws TransportException
|
||||||
|
* @throws MessageException
|
||||||
|
*/
|
||||||
|
private function readMessage()
|
||||||
|
{
|
||||||
|
$header = $this->read(8);
|
||||||
|
if($header === false)
|
||||||
|
throw new TransportException('Connection interrupted while reading header', TransportException::INTERRUPTED);
|
||||||
|
|
||||||
|
extract(unpack('Vsize/Vhandle', $header));
|
||||||
|
/** @var $size int */
|
||||||
|
/** @var $handle int */
|
||||||
|
if($size == 0 || $handle == 0)
|
||||||
|
throw new TransportException('Incorrect header', TransportException::PROTOCOL_ERROR);
|
||||||
|
|
||||||
|
if($size > self::MAX_RESPONSE_SIZE)
|
||||||
|
throw new MessageException('Response too large', MessageException::RESPONSE_TOO_LARGE);
|
||||||
|
|
||||||
|
$data = $this->read($size);
|
||||||
|
if($data === false)
|
||||||
|
throw new TransportException('Connection interrupted while reading data', TransportException::INTERRUPTED);
|
||||||
|
|
||||||
|
$this->lastNetworkActivity = time();
|
||||||
|
return array($handle, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $xml
|
||||||
|
* @throws TransportException
|
||||||
|
*/
|
||||||
|
private function writeMessage($xml)
|
||||||
|
{
|
||||||
|
$data = pack('V2a*', strlen($xml), ++$this->requestHandle, $xml);
|
||||||
|
if(!$this->write($data))
|
||||||
|
throw new TransportException('Connection interrupted while writing', TransportException::INTERRUPTED);
|
||||||
|
$this->lastNetworkActivity = time();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $size
|
||||||
|
* @return boolean|string
|
||||||
|
*/
|
||||||
|
private function read($size)
|
||||||
|
{
|
||||||
|
@stream_set_timeout($this->socket, 0, $this->timeouts['read'] * 1000);
|
||||||
|
|
||||||
|
$data = '';
|
||||||
|
while(strlen($data) < $size)
|
||||||
|
{
|
||||||
|
$buf = fread($this->socket, $size - strlen($data));
|
||||||
|
if($buf === '' || $buf === false)
|
||||||
|
return false;
|
||||||
|
$data .= $buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
self::$received += $size;
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $data
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
private function write($data)
|
||||||
|
{
|
||||||
|
@stream_set_timeout($this->socket, 0, $this->timeouts['write'] * 1000);
|
||||||
|
|
||||||
|
while(strlen($data) > 0)
|
||||||
|
{
|
||||||
|
$written = fwrite($this->socket, $data);
|
||||||
|
if($written === 0 || $written === false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
$data = substr($data, $written);
|
||||||
|
}
|
||||||
|
|
||||||
|
self::$sent += strlen($data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TransportException extends Exception
|
||||||
|
{
|
||||||
|
const NOT_INITIALIZED = 1;
|
||||||
|
const INTERRUPTED = 2;
|
||||||
|
const WRONG_PROTOCOL = 3;
|
||||||
|
const PROTOCOL_ERROR = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MessageException extends Exception
|
||||||
|
{
|
||||||
|
const REQUEST_TOO_LARGE = 1;
|
||||||
|
const RESPONSE_TOO_LARGE = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
class FaultException extends Exception
|
||||||
|
{
|
||||||
|
static function create($faultString, $faultCode)
|
||||||
|
{
|
||||||
|
switch($faultString)
|
||||||
|
{
|
||||||
|
case 'Login unknown.':
|
||||||
|
return new LoginUnknownException($faultString, $faultCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new self($faultString, $faultCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LoginUnknownException extends FaultException {}
|
||||||
|
|
||||||
|
?>
|
@ -1,189 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* ManiaPlanet dedicated server Xml-RPC client
|
|
||||||
*
|
|
||||||
* @license http://www.gnu.org/licenses/lgpl.html LGPL License 3
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Maniaplanet\DedicatedServer\Xmlrpc;
|
|
||||||
|
|
||||||
class Message
|
|
||||||
{
|
|
||||||
public $message;
|
|
||||||
public $messageType; // methodCall / methodResponse / fault
|
|
||||||
public $faultCode;
|
|
||||||
public $faultString;
|
|
||||||
public $methodName;
|
|
||||||
public $params;
|
|
||||||
// Current variable stacks
|
|
||||||
protected $arrayStructs = array(); // Stack to keep track of the current array/struct
|
|
||||||
protected $arrayStructsTypes = array(); // Stack to keep track of whether things are structs or array
|
|
||||||
protected $currentStructName = array(); // A stack as well
|
|
||||||
protected $param;
|
|
||||||
protected $value;
|
|
||||||
protected $currentTag;
|
|
||||||
protected $currentTagContents;
|
|
||||||
// The XML parser
|
|
||||||
protected $parser;
|
|
||||||
|
|
||||||
function __construct ($message)
|
|
||||||
{
|
|
||||||
$this->message = $message;
|
|
||||||
}
|
|
||||||
|
|
||||||
function parse()
|
|
||||||
{
|
|
||||||
|
|
||||||
// first remove the XML declaration
|
|
||||||
$this->message = preg_replace('/<\?xml(.*)?\?'.'>/', '', $this->message);
|
|
||||||
if (trim($this->message) == '')
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$this->parser = xml_parser_create();
|
|
||||||
// Set XML parser to take the case of tags into account
|
|
||||||
xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, false);
|
|
||||||
// Set XML parser callback functions
|
|
||||||
xml_set_object($this->parser, $this);
|
|
||||||
xml_set_element_handler($this->parser, 'tag_open', 'tag_close');
|
|
||||||
xml_set_character_data_handler($this->parser, 'cdata');
|
|
||||||
if (!xml_parse($this->parser, $this->message))
|
|
||||||
{
|
|
||||||
/* die(sprintf('GbxRemote XML error: %s at line %d',
|
|
||||||
xml_error_string(xml_get_error_code($this->_parser)),
|
|
||||||
xml_get_current_line_number($this->_parser))); */
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
xml_parser_free($this->parser);
|
|
||||||
// Grab the error messages, if any
|
|
||||||
if ($this->messageType == 'fault')
|
|
||||||
{
|
|
||||||
$this->faultCode = $this->params[0]['faultCode'];
|
|
||||||
$this->faultString = $this->params[0]['faultString'];
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function tag_open($parser, $tag, $attr)
|
|
||||||
{
|
|
||||||
$this->currentTag = $tag;
|
|
||||||
switch ($tag)
|
|
||||||
{
|
|
||||||
case 'methodCall':
|
|
||||||
case 'methodResponse':
|
|
||||||
case 'fault':
|
|
||||||
$this->messageType = $tag;
|
|
||||||
break;
|
|
||||||
// Deal with stacks of arrays and structs
|
|
||||||
case 'data': // data is to all intents and purposes more interesting than array
|
|
||||||
$this->arrayStructsTypes[] = 'array';
|
|
||||||
$this->arrayStructs[] = array();
|
|
||||||
break;
|
|
||||||
case 'struct':
|
|
||||||
$this->arrayStructsTypes[] = 'struct';
|
|
||||||
$this->arrayStructs[] = array();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function cdata($parser, $cdata)
|
|
||||||
{
|
|
||||||
$this->currentTagContents .= $cdata;
|
|
||||||
}
|
|
||||||
|
|
||||||
function tag_close($parser, $tag)
|
|
||||||
{
|
|
||||||
$valueFlag = false;
|
|
||||||
switch ($tag)
|
|
||||||
{
|
|
||||||
case 'int':
|
|
||||||
case 'i4':
|
|
||||||
$value = (int)trim($this->currentTagContents);
|
|
||||||
$this->currentTagContents = '';
|
|
||||||
$valueFlag = true;
|
|
||||||
break;
|
|
||||||
case 'double':
|
|
||||||
$value = (double)trim($this->currentTagContents);
|
|
||||||
$this->currentTagContents = '';
|
|
||||||
$valueFlag = true;
|
|
||||||
break;
|
|
||||||
case 'string':
|
|
||||||
$value = (string)trim($this->currentTagContents);
|
|
||||||
$this->currentTagContents = '';
|
|
||||||
$valueFlag = true;
|
|
||||||
break;
|
|
||||||
case 'dateTime.iso8601':
|
|
||||||
$value = new Date(trim($this->currentTagContents));
|
|
||||||
// $value = $iso->getTimestamp();
|
|
||||||
$this->currentTagContents = '';
|
|
||||||
$valueFlag = true;
|
|
||||||
break;
|
|
||||||
case 'value':
|
|
||||||
// If no type is indicated, the type is string
|
|
||||||
if (trim($this->currentTagContents) != '') {
|
|
||||||
$value = (string)$this->currentTagContents;
|
|
||||||
$this->currentTagContents = '';
|
|
||||||
$valueFlag = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'boolean':
|
|
||||||
$value = (boolean)trim($this->currentTagContents);
|
|
||||||
$this->currentTagContents = '';
|
|
||||||
$valueFlag = true;
|
|
||||||
break;
|
|
||||||
case 'base64':
|
|
||||||
$value = base64_decode($this->currentTagContents);
|
|
||||||
$this->currentTagContents = '';
|
|
||||||
$valueFlag = true;
|
|
||||||
break;
|
|
||||||
// Deal with stacks of arrays and structs
|
|
||||||
case 'data':
|
|
||||||
case 'struct':
|
|
||||||
$value = array_pop($this->arrayStructs);
|
|
||||||
array_pop($this->arrayStructsTypes);
|
|
||||||
$valueFlag = true;
|
|
||||||
break;
|
|
||||||
case 'member':
|
|
||||||
array_pop($this->currentStructName);
|
|
||||||
break;
|
|
||||||
case 'name':
|
|
||||||
$this->currentStructName[] = trim($this->currentTagContents);
|
|
||||||
$this->currentTagContents = '';
|
|
||||||
break;
|
|
||||||
case 'methodName':
|
|
||||||
$this->methodName = trim($this->currentTagContents);
|
|
||||||
$this->currentTagContents = '';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($valueFlag)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
if (!is_array($value) && !is_object($value)) {
|
|
||||||
$value = trim($value);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
if (count($this->arrayStructs) > 0)
|
|
||||||
{
|
|
||||||
// Add value to struct or array
|
|
||||||
if ($this->arrayStructsTypes[count($this->arrayStructsTypes)-1] == 'struct')
|
|
||||||
{
|
|
||||||
// Add to struct
|
|
||||||
$this->arrayStructs[count($this->arrayStructs)-1][$this->currentStructName[count($this->currentStructName)-1]] = $value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Add to array
|
|
||||||
$this->arrayStructs[count($this->arrayStructs)-1][] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Just add as a paramater
|
|
||||||
$this->params[] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
@ -7,36 +7,162 @@
|
|||||||
|
|
||||||
namespace Maniaplanet\DedicatedServer\Xmlrpc;
|
namespace Maniaplanet\DedicatedServer\Xmlrpc;
|
||||||
|
|
||||||
class Request
|
if(extension_loaded('xmlrpc'))
|
||||||
{
|
{
|
||||||
public $method;
|
abstract class Request
|
||||||
public $args;
|
|
||||||
public $xml;
|
|
||||||
|
|
||||||
function __construct($method, $args)
|
|
||||||
{
|
{
|
||||||
$this->method = $method;
|
/**
|
||||||
$this->args = $args;
|
* @param string $method
|
||||||
$this->xml = '<?xml version="1.0" encoding="utf-8" ?><methodCall><methodName>' . $this->method . '</methodName><params>';
|
* @param mixed[] $args
|
||||||
foreach ($this->args as $arg)
|
* @return string
|
||||||
|
*/
|
||||||
|
static function encode($method, $args)
|
||||||
{
|
{
|
||||||
$this->xml .= '<param><value>';
|
return xmlrpc_encode_request($method, $args, array('encoding' => 'utf-8', 'verbosity' => 'no_white_space'));
|
||||||
$v = new Value($arg);
|
|
||||||
$this->xml .= $v->getXml();
|
|
||||||
$this->xml .= '</value></param>' . LF;
|
|
||||||
}
|
}
|
||||||
$this->xml .= '</params></methodCall>';
|
|
||||||
}
|
|
||||||
|
|
||||||
function getLength()
|
/**
|
||||||
{
|
* @param string $message
|
||||||
return strlen($this->xml);
|
* @return mixed
|
||||||
}
|
* @throws ParseException
|
||||||
|
*/
|
||||||
|
static function decode($message)
|
||||||
|
{
|
||||||
|
$value = xmlrpc_decode_request($message, $method, 'utf-8');
|
||||||
|
if($value === null)
|
||||||
|
throw new ParseException();
|
||||||
|
|
||||||
function getXml()
|
if($method === null)
|
||||||
|
{
|
||||||
|
if(@xmlrpc_is_fault($value))
|
||||||
|
return array('fault', $value);
|
||||||
|
return array('response', $value);
|
||||||
|
}
|
||||||
|
return array('call', array($method, $value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
abstract class Request
|
||||||
{
|
{
|
||||||
return $this->xml;
|
const DATE_FORMAT = 'Ymd\TH:i:s';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $method
|
||||||
|
* @param mixed[] $args
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
static function encode($method, $args)
|
||||||
|
{
|
||||||
|
$xml = '<?xml version="1.0" encoding="utf-8"?><methodCall><methodName>'.$method.'</methodName><params>';
|
||||||
|
foreach($args as $arg)
|
||||||
|
$xml .= '<param><value>'.self::encodeValue($arg).'</value></param>';
|
||||||
|
$xml .= '</params></methodCall>';
|
||||||
|
return $xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed $v
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private static function encodeValue($v)
|
||||||
|
{
|
||||||
|
switch(gettype($v))
|
||||||
|
{
|
||||||
|
case 'boolean':
|
||||||
|
return '<boolean>'.((int) $v).'</boolean>';
|
||||||
|
case 'integer':
|
||||||
|
return '<int>'.$v.'</int>';
|
||||||
|
case 'double':
|
||||||
|
return '<double>'.$v.'</double>';
|
||||||
|
case 'string':
|
||||||
|
return '<string>'.htmlspecialchars($v).'</string>';
|
||||||
|
case 'object':
|
||||||
|
if($v instanceof Base64)
|
||||||
|
return '<base64>'.base64_encode($v->scalar).'</base64>';
|
||||||
|
if($v instanceof \DateTime)
|
||||||
|
return '<dateTime.iso8601>'.$v->format(self::DATE_FORMAT).'</dateTime.iso8601>';
|
||||||
|
$v = get_object_vars($v);
|
||||||
|
// fallthrough
|
||||||
|
case 'array':
|
||||||
|
$return = '';
|
||||||
|
// pure array case
|
||||||
|
if(array_keys($v) == range(0, count($v) - 1))
|
||||||
|
{
|
||||||
|
foreach($v as $item)
|
||||||
|
$return .= '<value>'.self::encodeValue($item).'</value>';
|
||||||
|
return '<array><data>'.$return.'</data></array>';
|
||||||
|
}
|
||||||
|
// else it's a struct
|
||||||
|
foreach($v as $name => $value)
|
||||||
|
$return .= '<member><name>'.$name.'</name><value>'.self::encodeValue($value).'</value></member>';
|
||||||
|
return '<struct>'.$return.'</struct>';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $message
|
||||||
|
* @return mixed
|
||||||
|
* @throws ParseException
|
||||||
|
*/
|
||||||
|
static function decode($message)
|
||||||
|
{
|
||||||
|
$xml = @simplexml_load_string($message);
|
||||||
|
if(!$xml)
|
||||||
|
throw new ParseException();
|
||||||
|
|
||||||
|
if($xml->getName() == 'methodResponse')
|
||||||
|
{
|
||||||
|
if($xml->fault)
|
||||||
|
return array('fault', self::decodeValue($xml->fault->value));
|
||||||
|
return array('response', self::decodeValue($xml->params->param->value));
|
||||||
|
}
|
||||||
|
$params = array();
|
||||||
|
foreach($xml->params->param as $param)
|
||||||
|
$params[] = self::decodeValue($param->value);
|
||||||
|
return array('call', array((string) $xml->methodName, $params));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \SimpleXMLElement $elt
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
private static function decodeValue($elt)
|
||||||
|
{
|
||||||
|
$elt = $elt->children();
|
||||||
|
$elt = $elt[0];
|
||||||
|
switch($elt->getName())
|
||||||
|
{
|
||||||
|
case 'boolean':
|
||||||
|
return (bool) $elt;
|
||||||
|
case 'i4':
|
||||||
|
case 'int':
|
||||||
|
return (int) $elt;
|
||||||
|
case 'double':
|
||||||
|
return (double) $elt;
|
||||||
|
case 'string':
|
||||||
|
return (string) $elt;
|
||||||
|
case 'base64':
|
||||||
|
return new Base64(base64_decode($elt));
|
||||||
|
case 'dateTime.iso8601':
|
||||||
|
return \DateTime::createFromFormat(self::DATE_FORMAT, (string) $elt);
|
||||||
|
case 'array':
|
||||||
|
$arr = array();
|
||||||
|
foreach($elt->data->value as $v)
|
||||||
|
$arr[] = self::decodeValue($v);
|
||||||
|
return $arr;
|
||||||
|
case 'struct':
|
||||||
|
$struct = array();
|
||||||
|
foreach($elt as $member)
|
||||||
|
$struct[(string) $member->name] = self::decodeValue($member->value);
|
||||||
|
return $struct;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
class ParseException extends Exception {}
|
||||||
|
|
||||||
|
?>
|
||||||
|
@ -1,144 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* ManiaPlanet dedicated server Xml-RPC client
|
|
||||||
*
|
|
||||||
* @license http://www.gnu.org/licenses/lgpl.html LGPL License 3
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Maniaplanet\DedicatedServer\Xmlrpc;
|
|
||||||
|
|
||||||
class Value
|
|
||||||
{
|
|
||||||
public $data;
|
|
||||||
public $type;
|
|
||||||
|
|
||||||
function __construct($data, $type = false)
|
|
||||||
{
|
|
||||||
$this->data = $data;
|
|
||||||
if (!$type)
|
|
||||||
{
|
|
||||||
$type = $this->calculateType();
|
|
||||||
}
|
|
||||||
$this->type = $type;
|
|
||||||
if ($type == 'struct')
|
|
||||||
{
|
|
||||||
// Turn all the values in the array into new Value objects
|
|
||||||
foreach ($this->data as $key => $value)
|
|
||||||
{
|
|
||||||
$this->data[$key] = new Value($value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($type == 'array')
|
|
||||||
{
|
|
||||||
for ($i = 0, $j = count($this->data); $i < $j; $i++)
|
|
||||||
{
|
|
||||||
$this->data[$i] = new Value($this->data[$i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function calculateType()
|
|
||||||
{
|
|
||||||
if ($this->data === true || $this->data === false)
|
|
||||||
{
|
|
||||||
return 'boolean';
|
|
||||||
}
|
|
||||||
if (is_integer($this->data))
|
|
||||||
{
|
|
||||||
return 'int';
|
|
||||||
}
|
|
||||||
if (is_double($this->data))
|
|
||||||
{
|
|
||||||
return 'double';
|
|
||||||
}
|
|
||||||
// Deal with IXR object types base64 and date
|
|
||||||
if (is_object($this->data) && $this->data instanceof Date)
|
|
||||||
{
|
|
||||||
return 'date';
|
|
||||||
}
|
|
||||||
if (is_object($this->data) && $this->data instanceof Base64)
|
|
||||||
{
|
|
||||||
return 'base64';
|
|
||||||
}
|
|
||||||
// If it is a normal PHP object convert it into a struct
|
|
||||||
if (is_object($this->data))
|
|
||||||
{
|
|
||||||
$this->data = get_object_vars($this->data);
|
|
||||||
return 'struct';
|
|
||||||
}
|
|
||||||
if (!is_array($this->data))
|
|
||||||
{
|
|
||||||
return 'string';
|
|
||||||
}
|
|
||||||
// We have an array - is it an array or a struct?
|
|
||||||
if ($this->isStruct($this->data))
|
|
||||||
{
|
|
||||||
return 'struct';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return 'array';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getXml()
|
|
||||||
{
|
|
||||||
// Return XML for this value
|
|
||||||
switch ($this->type)
|
|
||||||
{
|
|
||||||
case 'boolean':
|
|
||||||
return '<boolean>' . ($this->data ? '1' : '0') . '</boolean>';
|
|
||||||
break;
|
|
||||||
case 'int':
|
|
||||||
return '<int>' . $this->data . '</int>';
|
|
||||||
break;
|
|
||||||
case 'double':
|
|
||||||
return '<double>' . $this->data . '</double>';
|
|
||||||
break;
|
|
||||||
case 'string':
|
|
||||||
return '<string>' . htmlspecialchars($this->data) . '</string>';
|
|
||||||
break;
|
|
||||||
case 'array':
|
|
||||||
$return = '<array><data>' . LF;
|
|
||||||
foreach ($this->data as $item)
|
|
||||||
{
|
|
||||||
$return .= ' <value>' . $item->getXml() . '</value>' . LF;
|
|
||||||
}
|
|
||||||
$return .= '</data></array>';
|
|
||||||
return $return;
|
|
||||||
break;
|
|
||||||
case 'struct':
|
|
||||||
$return = '<struct>' . LF;
|
|
||||||
foreach ($this->data as $name => $value)
|
|
||||||
{
|
|
||||||
$return .= ' <member><name>' . $name . '</name><value>';
|
|
||||||
$return .= $value->getXml() . '</value></member>' . LF;
|
|
||||||
}
|
|
||||||
$return .= '</struct>';
|
|
||||||
return $return;
|
|
||||||
break;
|
|
||||||
case 'date':
|
|
||||||
case 'base64':
|
|
||||||
return $this->data->getXml();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isStruct($array)
|
|
||||||
{
|
|
||||||
// Nasty function to check if an array is a struct or not
|
|
||||||
$expected = 0;
|
|
||||||
foreach ($array as $key => $value)
|
|
||||||
{
|
|
||||||
if ((string)$key != (string)$expected)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
$expected++;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
@ -23,8 +23,8 @@ use ManiaControl\Settings\SettingManager;
|
|||||||
use ManiaControl\Statistics\StatisticManager;
|
use ManiaControl\Statistics\StatisticManager;
|
||||||
use ManiaControl\Update\UpdateManager;
|
use ManiaControl\Update\UpdateManager;
|
||||||
use Maniaplanet\DedicatedServer\Connection;
|
use Maniaplanet\DedicatedServer\Connection;
|
||||||
|
use Maniaplanet\DedicatedServer\Transport\TransportException;
|
||||||
use Maniaplanet\DedicatedServer\Xmlrpc\Exception;
|
use Maniaplanet\DedicatedServer\Xmlrpc\Exception;
|
||||||
use Maniaplanet\DedicatedServer\Xmlrpc\FatalException;
|
|
||||||
|
|
||||||
require_once __DIR__ . '/Libs/Maniaplanet/DedicatedServer/Connection.php';
|
require_once __DIR__ . '/Libs/Maniaplanet/DedicatedServer/Connection.php';
|
||||||
require_once __DIR__ . '/Libs/GbxDataFetcher/gbxdatafetcher.inc.php';
|
require_once __DIR__ . '/Libs/GbxDataFetcher/gbxdatafetcher.inc.php';
|
||||||
@ -35,25 +35,25 @@ require_once __DIR__ . '/Libs/curl-easy/autoload.php';
|
|||||||
/**
|
/**
|
||||||
* ManiaControl Server Controller for ManiaPlanet Server
|
* ManiaControl Server Controller for ManiaPlanet Server
|
||||||
*
|
*
|
||||||
* @author steeffeen & kremsy
|
* @author steeffeen & kremsy
|
||||||
* @copyright ManiaControl Copyright © 2014 ManiaControl Team
|
* @copyright ManiaControl Copyright © 2014 ManiaControl Team
|
||||||
* @license http://www.gnu.org/licenses/ GNU General Public License, Version 3
|
* @license http://www.gnu.org/licenses/ GNU General Public License, Version 3
|
||||||
*/
|
*/
|
||||||
class ManiaControl implements CommandListener, TimerListener {
|
class ManiaControl implements CommandListener, TimerListener {
|
||||||
/*
|
/*
|
||||||
* Constants
|
* Constants
|
||||||
*/
|
*/
|
||||||
const VERSION = '0.01';
|
const VERSION = '0.01';
|
||||||
const API_VERSION = '2013-04-16';
|
const API_VERSION = '2013-04-16';
|
||||||
const MIN_DEDIVERSION = '2014-04-02_18_00';
|
const MIN_DEDIVERSION = '2014-04-02_18_00';
|
||||||
const OS_UNIX = 'Unix';
|
const OS_UNIX = 'Unix';
|
||||||
const OS_WIN = 'Windows';
|
const OS_WIN = 'Windows';
|
||||||
const CONNECT_TIMEOUT = 50;
|
const CONNECT_TIMEOUT = 50;
|
||||||
const SCRIPT_TIMEOUT = 20;
|
const SCRIPT_TIMEOUT = 20;
|
||||||
const URL_WEBSERVICE = 'http://ws.maniacontrol.com/';
|
const URL_WEBSERVICE = 'http://ws.maniacontrol.com/';
|
||||||
const SETTING_PERMISSION_SHUTDOWN = 'Shutdown ManiaControl';
|
const SETTING_PERMISSION_SHUTDOWN = 'Shutdown ManiaControl';
|
||||||
const SETTING_PERMISSION_RESTART = 'Restart ManiaControl';
|
const SETTING_PERMISSION_RESTART = 'Restart ManiaControl';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Public Properties
|
* Public Properties
|
||||||
*/
|
*/
|
||||||
@ -79,7 +79,7 @@ class ManiaControl implements CommandListener, TimerListener {
|
|||||||
public $timerManager = null;
|
public $timerManager = null;
|
||||||
public $fileReader = null;
|
public $fileReader = null;
|
||||||
public $billManager = null;
|
public $billManager = null;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Private Properties
|
* Private Properties
|
||||||
*/
|
*/
|
||||||
@ -91,40 +91,53 @@ class ManiaControl implements CommandListener, TimerListener {
|
|||||||
public function __construct() {
|
public function __construct() {
|
||||||
// Construct Error Handler
|
// Construct Error Handler
|
||||||
$this->errorHandler = new ErrorHandler($this);
|
$this->errorHandler = new ErrorHandler($this);
|
||||||
|
|
||||||
$this->log('Loading ManiaControl v' . self::VERSION . '...');
|
$this->log('Loading ManiaControl v' . self::VERSION . '...');
|
||||||
|
|
||||||
// Load config
|
// Load config
|
||||||
$this->config = FileUtil::loadConfig('server.xml');
|
$this->config = FileUtil::loadConfig('server.xml');
|
||||||
|
|
||||||
// Load ManiaControl Modules
|
// Load ManiaControl Modules
|
||||||
$this->callbackManager = new CallbackManager($this);
|
$this->callbackManager = new CallbackManager($this);
|
||||||
$this->timerManager = new TimerManager($this);
|
$this->timerManager = new TimerManager($this);
|
||||||
$this->database = new Database($this);
|
$this->database = new Database($this);
|
||||||
$this->fileReader = new AsynchronousFileReader($this);
|
$this->fileReader = new AsynchronousFileReader($this);
|
||||||
$this->billManager = new BillManager($this);
|
$this->billManager = new BillManager($this);
|
||||||
$this->settingManager = new SettingManager($this);
|
$this->settingManager = new SettingManager($this);
|
||||||
$this->statisticManager = new StatisticManager($this);
|
$this->statisticManager = new StatisticManager($this);
|
||||||
$this->manialinkManager = new ManialinkManager($this);
|
$this->manialinkManager = new ManialinkManager($this);
|
||||||
$this->actionsMenu = new ActionsMenu($this);
|
$this->actionsMenu = new ActionsMenu($this);
|
||||||
$this->chat = new Chat($this);
|
$this->chat = new Chat($this);
|
||||||
$this->commandManager = new CommandManager($this);
|
$this->commandManager = new CommandManager($this);
|
||||||
$this->server = new Server($this);
|
$this->server = new Server($this);
|
||||||
$this->authenticationManager = new AuthenticationManager($this);
|
$this->authenticationManager = new AuthenticationManager($this);
|
||||||
$this->playerManager = new PlayerManager($this);
|
$this->playerManager = new PlayerManager($this);
|
||||||
$this->mapManager = new MapManager($this);
|
$this->mapManager = new MapManager($this);
|
||||||
$this->configurator = new Configurator($this);
|
$this->configurator = new Configurator($this);
|
||||||
$this->pluginManager = new PluginManager($this);
|
$this->pluginManager = new PluginManager($this);
|
||||||
$this->updateManager = new UpdateManager($this);
|
$this->updateManager = new UpdateManager($this);
|
||||||
|
|
||||||
// Define Permission Levels
|
// Define Permission Levels
|
||||||
$this->authenticationManager->definePermissionLevel(self::SETTING_PERMISSION_SHUTDOWN, AuthenticationManager::AUTH_LEVEL_SUPERADMIN);
|
$this->authenticationManager->definePermissionLevel(self::SETTING_PERMISSION_SHUTDOWN, AuthenticationManager::AUTH_LEVEL_SUPERADMIN);
|
||||||
$this->authenticationManager->definePermissionLevel(self::SETTING_PERMISSION_RESTART, AuthenticationManager::AUTH_LEVEL_SUPERADMIN);
|
$this->authenticationManager->definePermissionLevel(self::SETTING_PERMISSION_RESTART, AuthenticationManager::AUTH_LEVEL_SUPERADMIN);
|
||||||
|
|
||||||
// Register for commands
|
// Register for commands
|
||||||
$this->commandManager->registerCommandListener('version', $this, 'command_Version');
|
$this->commandManager->registerCommandListener('version', $this, 'command_Version');
|
||||||
$this->commandManager->registerCommandListener('restart', $this, 'command_Restart', true);
|
$this->commandManager->registerCommandListener('restart', $this, 'command_Restart', true);
|
||||||
$this->commandManager->registerCommandListener('shutdown', $this, 'command_Shutdown', true);
|
$this->commandManager->registerCommandListener('shutdown', $this, 'command_Shutdown', true);
|
||||||
|
|
||||||
|
//Check connection every 2 minutes
|
||||||
|
$this->timerManager->registerTimerListening($this, 'checkConnection', 1000 * 180);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks connection every xxx Minutes
|
||||||
|
* @param $time
|
||||||
|
*/
|
||||||
|
public function checkConnection($time){
|
||||||
|
if($this->client->getIdleTime() > 300){
|
||||||
|
$this->client->getServerName();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -165,7 +178,7 @@ class ManiaControl implements CommandListener, TimerListener {
|
|||||||
/**
|
/**
|
||||||
* Handle Version Command
|
* Handle Version Command
|
||||||
*
|
*
|
||||||
* @param array $chatCallback
|
* @param array $chatCallback
|
||||||
* @param Player $player
|
* @param Player $player
|
||||||
*/
|
*/
|
||||||
public function command_Version(array $chatCallback, Player $player) {
|
public function command_Version(array $chatCallback, Player $player) {
|
||||||
@ -176,7 +189,7 @@ class ManiaControl implements CommandListener, TimerListener {
|
|||||||
/**
|
/**
|
||||||
* Handle Restart AdminCommand
|
* Handle Restart AdminCommand
|
||||||
*
|
*
|
||||||
* @param array $chatCallback
|
* @param array $chatCallback
|
||||||
* @param Player $player
|
* @param Player $player
|
||||||
*/
|
*/
|
||||||
public function command_Restart(array $chatCallback, Player $player) {
|
public function command_Restart(array $chatCallback, Player $player) {
|
||||||
@ -190,7 +203,7 @@ class ManiaControl implements CommandListener, TimerListener {
|
|||||||
/**
|
/**
|
||||||
* Handle //shutdown command
|
* Handle //shutdown command
|
||||||
*
|
*
|
||||||
* @param array $chat
|
* @param array $chat
|
||||||
* @param Player $player
|
* @param Player $player
|
||||||
*/
|
*/
|
||||||
public function command_Shutdown(array $chat, Player $player) {
|
public function command_Shutdown(array $chat, Player $player) {
|
||||||
@ -210,7 +223,7 @@ class ManiaControl implements CommandListener, TimerListener {
|
|||||||
if ($message) {
|
if ($message) {
|
||||||
$this->log($message);
|
$this->log($message);
|
||||||
}
|
}
|
||||||
|
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,32 +233,31 @@ class ManiaControl implements CommandListener, TimerListener {
|
|||||||
public function handleShutdown() {
|
public function handleShutdown() {
|
||||||
// OnShutdown callback
|
// OnShutdown callback
|
||||||
$this->callbackManager->triggerCallback(CallbackManager::CB_ONSHUTDOWN);
|
$this->callbackManager->triggerCallback(CallbackManager::CB_ONSHUTDOWN);
|
||||||
|
|
||||||
// Announce quit
|
// Announce quit
|
||||||
$this->chat->sendInformation('ManiaControl shutting down.');
|
$this->chat->sendInformation('ManiaControl shutting down.');
|
||||||
|
|
||||||
if ($this->client) {
|
if ($this->client) {
|
||||||
try {
|
try {
|
||||||
// Hide manialinks
|
// Hide manialinks
|
||||||
$this->client->sendHideManialinkPage();
|
$this->client->sendHideManialinkPage();
|
||||||
// Close the client connection
|
// Close the client connection
|
||||||
$this->client->delete($this->server->ip, $this->server->port);
|
$this->client->delete($this->server->ip, $this->server->port);
|
||||||
}
|
} catch(FatalException $e) {
|
||||||
catch (FatalException $e) {
|
|
||||||
$this->errorHandler->triggerDebugNotice($e->getMessage() . " File: " . $e->getFile() . " Line: " . $e->getLine());
|
$this->errorHandler->triggerDebugNotice($e->getMessage() . " File: " . $e->getFile() . " Line: " . $e->getLine());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check and Trigger Fatal Errors
|
// Check and Trigger Fatal Errors
|
||||||
$error = error_get_last();
|
$error = error_get_last();
|
||||||
if ($error && ($error['type'] & E_FATAL)) {
|
if ($error && ($error['type'] & E_FATAL)) {
|
||||||
$this->errorHandler->errorHandler($error['type'], $error['message'], $error['file'], $error['line']);
|
$this->errorHandler->errorHandler($error['type'], $error['message'], $error['file'], $error['line']);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable Garbage Collector
|
// Disable Garbage Collector
|
||||||
$this->collectGarbage();
|
$this->collectGarbage();
|
||||||
gc_disable();
|
gc_disable();
|
||||||
|
|
||||||
$this->log('Quitting ManiaControl!');
|
$this->log('Quitting ManiaControl!');
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
@ -258,24 +270,23 @@ class ManiaControl implements CommandListener, TimerListener {
|
|||||||
public function restart($message = null) {
|
public function restart($message = null) {
|
||||||
// Shutdown callback
|
// Shutdown callback
|
||||||
$this->callbackManager->triggerCallback(CallbackManager::CB_ONSHUTDOWN);
|
$this->callbackManager->triggerCallback(CallbackManager::CB_ONSHUTDOWN);
|
||||||
|
|
||||||
// Announce restart
|
// Announce restart
|
||||||
$this->chat->sendInformation('Restarting ManiaControl...');
|
$this->chat->sendInformation('Restarting ManiaControl...');
|
||||||
if ($message) {
|
if ($message) {
|
||||||
$this->log($message);
|
$this->log($message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hide widgets
|
// Hide widgets
|
||||||
$this->client->sendHideManialinkPage();
|
$this->client->sendHideManialinkPage();
|
||||||
|
|
||||||
$this->log('Restarting ManiaControl!');
|
$this->log('Restarting ManiaControl!');
|
||||||
|
|
||||||
// Execute start script in background
|
// Execute start script in background
|
||||||
if ($this->getOS(self::OS_UNIX)) {
|
if ($this->getOS(self::OS_UNIX)) {
|
||||||
$command = 'sh ' . escapeshellarg(ManiaControlDir . '/ManiaControl.sh') . ' > /dev/null &';
|
$command = 'sh ' . escapeshellarg(ManiaControlDir . '/ManiaControl.sh') . ' > /dev/null &';
|
||||||
exec($command);
|
exec($command);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
$command = escapeshellarg(ManiaControlDir . "\ManiaControl.bat");
|
$command = escapeshellarg(ManiaControlDir . "\ManiaControl.bat");
|
||||||
system($command); // TODO, windows stucks here as long controller is running
|
system($command); // TODO, windows stucks here as long controller is running
|
||||||
}
|
}
|
||||||
@ -287,10 +298,10 @@ class ManiaControl implements CommandListener, TimerListener {
|
|||||||
*/
|
*/
|
||||||
public function run() {
|
public function run() {
|
||||||
$this->log('Starting ManiaControl v' . self::VERSION . '!');
|
$this->log('Starting ManiaControl v' . self::VERSION . '!');
|
||||||
|
|
||||||
// Register shutdown handler
|
// Register shutdown handler
|
||||||
register_shutdown_function(array($this, 'handleShutdown'));
|
register_shutdown_function(array($this, 'handleShutdown'));
|
||||||
|
|
||||||
// Connect to server
|
// Connect to server
|
||||||
$this->connect();
|
$this->connect();
|
||||||
|
|
||||||
@ -300,59 +311,60 @@ class ManiaControl implements CommandListener, TimerListener {
|
|||||||
if($version->build < self::MIN_DEDIVERSION) {
|
if($version->build < self::MIN_DEDIVERSION) {
|
||||||
trigger_error("The server has version ".$version->build.", while at least ".self::MIN_DEDIVERSION." is required!", E_USER_ERROR);
|
trigger_error("The server has version ".$version->build.", while at least ".self::MIN_DEDIVERSION." is required!", E_USER_ERROR);
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
// OnInit callback
|
// OnInit callback
|
||||||
$this->callbackManager->triggerCallback(CallbackManager::CB_ONINIT);
|
$this->callbackManager->triggerCallback(CallbackManager::CB_ONINIT);
|
||||||
|
|
||||||
// Load plugins
|
// Load plugins
|
||||||
$this->pluginManager->loadPlugins();
|
$this->pluginManager->loadPlugins();
|
||||||
$this->updateManager->checkPluginsUpdate();
|
$this->updateManager->checkPluginsUpdate();
|
||||||
|
|
||||||
// AfterInit callback
|
// AfterInit callback
|
||||||
$this->callbackManager->triggerCallback(CallbackManager::CB_AFTERINIT);
|
$this->callbackManager->triggerCallback(CallbackManager::CB_AFTERINIT);
|
||||||
|
|
||||||
// Enable Garbage Collecting
|
// Enable Garbage Collecting
|
||||||
gc_enable();
|
gc_enable();
|
||||||
$this->timerManager->registerTimerListening($this, 'collectGarbage', 1000 * 60);
|
$this->timerManager->registerTimerListening($this, 'collectGarbage', 1000 * 60);
|
||||||
|
|
||||||
// Announce ManiaControl
|
// Announce ManiaControl
|
||||||
$this->chat->sendInformation('ManiaControl v' . self::VERSION . ' successfully started!');
|
$this->chat->sendInformation('ManiaControl v' . self::VERSION . ' successfully started!');
|
||||||
|
|
||||||
// Loading finished
|
// Loading finished
|
||||||
$this->log('Loading completed!');
|
$this->log('Loading completed!');
|
||||||
$this->log('Link: maniaplanet://#join=' . $this->server->login . '@' . $this->server->titleId);
|
$this->log('Link: maniaplanet://#join=' . $this->server->login . '@' . $this->server->titleId);
|
||||||
|
|
||||||
// Main loop
|
// Main loop
|
||||||
while (!$this->shutdownRequested) {
|
while(!$this->shutdownRequested) {
|
||||||
$loopStart = microtime(true);
|
$loopStart = microtime(true);
|
||||||
|
|
||||||
// Disable script timeout
|
// Disable script timeout
|
||||||
set_time_limit(self::SCRIPT_TIMEOUT);
|
set_time_limit(self::SCRIPT_TIMEOUT);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Manager callbacks
|
// Manager callbacks
|
||||||
$this->callbackManager->manageCallbacks();
|
$this->callbackManager->manageCallbacks();
|
||||||
}
|
} catch(TransportException $e) {
|
||||||
catch (FatalException $e) {
|
$this->log("Connection interrupted!");
|
||||||
// TODO remove
|
// TODO remove
|
||||||
if ($this->errorHandler) {
|
if ($this->errorHandler) {
|
||||||
$this->errorHandler->triggerDebugNotice("Fatal Exception: " . $e->getMessage() . " Trace: " . $e->getTraceAsString());
|
$this->errorHandler->triggerDebugNotice("Fatal Exception: " . $e->getMessage() . " Trace: " . $e->getTraceAsString());
|
||||||
}
|
}
|
||||||
$this->quit($e->getMessage());
|
$this->quit($e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Manage FileReader
|
// Manage FileReader
|
||||||
$this->fileReader->appendData();
|
$this->fileReader->appendData();
|
||||||
|
|
||||||
// Yield for next tick
|
// Yield for next tick
|
||||||
$loopEnd = microtime(true);
|
$loopEnd = microtime(true);
|
||||||
|
|
||||||
$sleepTime = (int) (2000 - ($loopEnd - $loopStart) * 1000000);
|
$sleepTime = (int)(2000 - ($loopEnd - $loopStart) * 1000000);
|
||||||
if ($sleepTime > 0) {
|
if ($sleepTime > 0) {
|
||||||
usleep($sleepTime);
|
usleep($sleepTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shutdown
|
// Shutdown
|
||||||
$this->quit();
|
$this->quit();
|
||||||
}
|
}
|
||||||
@ -370,60 +382,59 @@ class ManiaControl implements CommandListener, TimerListener {
|
|||||||
private function connect() {
|
private function connect() {
|
||||||
// Load remote client
|
// Load remote client
|
||||||
$success = $this->server->loadConfig();
|
$success = $this->server->loadConfig();
|
||||||
|
|
||||||
$this->log("Connecting to server at {$this->server->config->host}:{$this->server->config->port}...");
|
$this->log("Connecting to server at {$this->server->config->host}:{$this->server->config->port}...");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->client = Connection::factory($this->server->config->host, $this->server->config->port, self::CONNECT_TIMEOUT,
|
$this->client = Connection::factory($this->server->config->host, $this->server->config->port, self::CONNECT_TIMEOUT, $this->server->config->login, $this->server->config->pass);
|
||||||
$this->server->config->login, $this->server->config->pass);
|
} catch(Exception $e) {
|
||||||
}
|
|
||||||
catch (Exception $e) {
|
|
||||||
trigger_error("Couldn't authenticate on server with user '{$this->server->config->login}'! " . $e->getMessage(), E_USER_ERROR);
|
trigger_error("Couldn't authenticate on server with user '{$this->server->config->login}'! " . $e->getMessage(), E_USER_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable callback system
|
// Enable callback system
|
||||||
$this->client->enableCallbacks(true);
|
$this->client->enableCallbacks(true);
|
||||||
|
|
||||||
// Wait for server to be ready
|
// Wait for server to be ready
|
||||||
try {
|
try {
|
||||||
if (!$this->server->waitForStatus(4)) {
|
if (!$this->server->waitForStatus(4)) {
|
||||||
trigger_error("Server couldn't get ready!", E_USER_ERROR);
|
trigger_error("Server couldn't get ready!", E_USER_ERROR);
|
||||||
}
|
}
|
||||||
}
|
} catch(FatalException $e) {
|
||||||
catch (FatalException $e) {
|
|
||||||
// TODO remove
|
// TODO remove
|
||||||
if ($this->errorHandler) {
|
if ($this->errorHandler) {
|
||||||
$this->errorHandler->triggerDebugNotice("Fatal Exception: " . $e->getMessage() . " Trace: " . $e->getTraceAsString());
|
$this->errorHandler->triggerDebugNotice("Fatal Exception: " . $e->getMessage() . " Trace: " . $e->getTraceAsString());
|
||||||
}
|
}
|
||||||
$this->quit($e->getMessage());
|
$this->quit($e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connect finished
|
// Connect finished
|
||||||
$this->log("Server Connection successfully established!");
|
$this->log("Server Connection successfully established!");
|
||||||
|
|
||||||
// Hide old widgets
|
// Hide old widgets
|
||||||
$this->client->sendHideManialinkPage();
|
$this->client->sendHideManialinkPage();
|
||||||
|
|
||||||
// Enable script callbacks if needed
|
// Enable script callbacks if needed
|
||||||
if ($this->server->getGameMode() != 0) return;
|
if ($this->server->getGameMode() != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$scriptSettings = $this->client->getModeScriptSettings();
|
$scriptSettings = $this->client->getModeScriptSettings();
|
||||||
}
|
} catch(Exception $e) {
|
||||||
catch (Exception $e) {
|
|
||||||
if ($e->getMessage() == 'Not in script mode.') {
|
if ($e->getMessage() == 'Not in script mode.') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!array_key_exists('S_UseScriptCallbacks', $scriptSettings)) return;
|
if (!array_key_exists('S_UseScriptCallbacks', $scriptSettings)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$scriptSettings['S_UseScriptCallbacks'] = true;
|
$scriptSettings['S_UseScriptCallbacks'] = true;
|
||||||
try {
|
try {
|
||||||
$this->client->setModeScriptSettings($scriptSettings);
|
$this->client->setModeScriptSettings($scriptSettings);
|
||||||
}
|
} catch(Exception $e) {
|
||||||
catch (Exception $e) {
|
|
||||||
trigger_error("Couldn't set mode script settings to enable script callbacks. " . $e->getMessage());
|
trigger_error("Couldn't set mode script settings to enable script callbacks. " . $e->getMessage());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -111,6 +111,7 @@ class ManiaExchangeList implements CallbackListener, ManialinkPageAnswerListener
|
|||||||
$this->showManiaExchangeList($maps, $player);
|
$this->showManiaExchangeList($maps, $player);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// search for matching maps
|
// search for matching maps
|
||||||
$this->maniaControl->mapManager->mxManager->getMapsAsync($function, $searchString, $author, $environment);
|
$this->maniaControl->mapManager->mxManager->getMapsAsync($function, $searchString, $author, $environment);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user