use of dedicatedserver api

This commit is contained in:
kremsy 2014-01-16 16:56:24 +01:00 committed by Steffen Schröder
parent a404edf280
commit 13fe48e4ce
28 changed files with 5988 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,56 @@
<?php
/**
* ManiaPlanet dedicated server Xml-RPC client
*
* @license http://www.gnu.org/licenses/lgpl.html LGPL License 3
*/
namespace Maniaplanet\DedicatedServer\Structures;
abstract class AbstractStructure
{
static public function fromArray($array)
{
if(!is_array($array))
return $array;
$object = new static;
foreach($array as $key => $value)
$object->{lcfirst($key)} = $value;
return $object;
}
static public function fromArrayOfArray($array)
{
if(!is_array($array))
return $array;
$result = array();
foreach($array as $key => $value)
$result[$key] = static::fromArray($value);
return $result;
}
static public function getPropertyFromArray($array, $property)
{
return array_map(get_called_class().'::extractProperty', $array, array_fill(0, count($array), $property));
}
static protected function extractProperty($element, $property)
{
if(!is_a($element, get_called_class()) || !property_exists($element, $property))
throw new \InvalidArgumentException('property '.$property.' does not exists in class: '.get_called_class());
return $element->$property;
}
function toArray()
{
$out = array();
foreach(get_object_vars($this) as $key => $value)
$out[ucfirst($key)] = $value;
return $out;
}
}
?>

View File

@ -0,0 +1,22 @@
<?php
/**
* ManiaPlanet dedicated server Xml-RPC client
*
* @license http://www.gnu.org/licenses/lgpl.html LGPL License 3
*/
namespace Maniaplanet\DedicatedServer\Structures;
class Bill extends AbstractStructure
{
const STATE_CREATING_TRANSACTION = 1;
const STATE_ISSUED = 2;
const STATE_VALIDATING_PAYMENT = 3;
const STATE_PAYED = 4;
const STATE_REFUSED = 5;
const STATE_ERROR = 6;
public $state;
public $stateName;
public $transactionId;
}
?>

View File

@ -0,0 +1,47 @@
<?php
/**
* ManiaPlanet dedicated server Xml-RPC client
*
* @license http://www.gnu.org/licenses/lgpl.html LGPL License 3
*/
namespace Maniaplanet\DedicatedServer\Structures;
class GameInfos extends AbstractStructure
{
/**
* Game Modes
*/
const GAMEMODE_SCRIPT = 0;
const GAMEMODE_ROUNDS = 1;
const GAMEMODE_TIMEATTACK = 2;
const GAMEMODE_TEAM = 3;
const GAMEMODE_LAPS = 4;
const GAMEMODE_CUP = 5;
const GAMEMODE_STUNTS = 6;
public $gameMode;
public $scriptName;
public $nbMaps;
public $chatTime;
public $finishTimeout;
public $allWarmUpDuration;
public $disableRespawn;
public $forceShowAllOpponents;
public $roundsPointsLimit;
public $roundsForcedLaps;
public $roundsUseNewRules;
public $roundsPointsLimitNewRules;
public $teamPointsLimit;
public $teamMaxPoints;
public $teamUseNewRules;
public $teamPointsLimitNewRules;
public $timeAttackLimit;
public $timeAttackSynchStartPeriod;
public $lapsNbLaps;
public $lapsTimeLimit;
public $cupPointsLimit;
public $cupRoundsPerMap;
public $cupNbWinners;
public $cupWarmUpDuration;
}
?>

View File

@ -0,0 +1,17 @@
<?php
/**
* ManiaPlanet dedicated server Xml-RPC client
*
* @license http://www.gnu.org/licenses/lgpl.html LGPL License 3
*/
namespace Maniaplanet\DedicatedServer\Structures;
class LobbyInfo extends AbstractStructure
{
public $isLobby;
public $lobbyPlayers;
public $lobbyMaxPlayers;
public $lobbyPlayersLevel;
}
?>

View File

@ -0,0 +1,27 @@
<?php
/**
* ManiaPlanet dedicated server Xml-RPC client
*
* @license http://www.gnu.org/licenses/lgpl.html LGPL License 3
*/
namespace Maniaplanet\DedicatedServer\Structures;
class Map extends AbstractStructure
{
public $uId;
public $name;
public $fileName;
public $author;
public $environnement;
public $mood;
public $bronzeTime;
public $silverTime;
public $goldTime;
public $authorTime;
public $copperPrice;
public $lapRace;
public $nbLaps;
public $nbCheckpoints;
public $mapType;
public $mapStyle;
}

View File

@ -0,0 +1,18 @@
<?php
/**
* ManiaPlanet dedicated server Xml-RPC client
*
* @license http://www.gnu.org/licenses/lgpl.html LGPL License 3
*/
namespace Maniaplanet\DedicatedServer\Structures;
class Mod extends AbstractStructure
{
public $env;
public $url;
function toArray()
{
return array('Env'=>$this->env,'Url'=>$this->url);
}
}

View File

@ -0,0 +1,14 @@
<?php
/**
* ManiaPlanet dedicated server Xml-RPC client
*
* @license http://www.gnu.org/licenses/lgpl.html LGPL License 3
*/
namespace Maniaplanet\DedicatedServer\Structures;
class Music extends AbstractStructure
{
public $override;
public $url;
public $file;
}

View File

@ -0,0 +1,27 @@
<?php
/**
* ManiaPlanet dedicated server Xml-RPC client
*
* @license http://www.gnu.org/licenses/lgpl.html LGPL License 3
*/
namespace Maniaplanet\DedicatedServer\Structures;
class NetworkStats extends AbstractStructure
{
public $uptime;
public $nbrConnection;
public $meanConnectionTime;
public $meanNbrPlayer;
public $recvNetRate;
public $sendNetRate;
public $totalReceivingSize;
public $totalSendingSize;
public $playerNetInfos;
static public function fromArray($array)
{
$object = parent::fromArray($array);
$object->playerNetInfos = Player::fromArrayOfArray($object->playerNetInfos);
return $object;
}
}

View File

@ -0,0 +1,97 @@
<?php
/**
* ManiaPlanet dedicated server Xml-RPC client
*
* @license http://www.gnu.org/licenses/lgpl.html LGPL License 3
*/
namespace Maniaplanet\DedicatedServer\Structures;
class Player extends AbstractStructure
{
public $playerId;
public $login;
public $nickName;
public $teamId;
public $path;
public $language;
public $clientVersion;
public $clientName;
public $iPAddress;
public $downloadRate;
public $uploadRate;
public $isSpectator;
public $isInOfficialMode;
public $avatar;
public $skins;
public $ladderStats;
public $hoursSinceZoneInscription;
public $onlineRights;
public $rank;
public $bestTime;
public $bestCheckpoints;
public $score;
public $nbrLapsFinished;
public $ladderScore;
public $stateUpdateLatency;
public $stateUpdatePeriod;
public $latestNetworkActivity;
public $packetLossRate;
public $spectatorStatus;
public $ladderRanking;
public $flags;
public $isConnected = true;
public $allies = array();
public $clubLink;
//Flags details
public $forceSpectator;
public $isReferee;
public $isPodiumReady;
public $isUsingStereoscopy;
public $isManagedByAnOtherServer;
public $isServer;
public $hasPlayerSlot;
public $isBroadcasting;
public $hasJoinedGame;
//SpectatorStatus details
public $spectator;
public $temporarySpectator;
public $pureSpectator;
public $autoTarget;
public $currentTargetId;
function getArrayFromPath()
{
return explode('|', $this->path);
}
/**
* @return Player
*/
static public function fromArray($array)
{
$object = parent::fromArray($array);
$object->skins = Skin::fromArrayOfArray($object->skins);
//Detail flags
$object->forceSpectator = $object->flags % 10; // 0, 1 or 2
$object->isReferee = (bool) (intval($object->flags / 10) % 10);
$object->isPodiumReady = (bool) (intval($object->flags / 100) % 10);
$object->isUsingStereoscopy = (bool) (intval($object->flags / 1000) % 10);
$object->isManagedByAnOtherServer = (bool) (intval($object->flags / 10000) % 10);
$object->isServer = (bool) (intval($object->flags / 100000) % 10);
$object->hasPlayerSlot = (bool) (intval($object->flags / 1000000) % 10);
$object->isBroadcasting = (bool) (intval($object->flags / 10000000) % 10);
$object->hasJoinedGame = (bool) (intval($object->flags / 100000000) % 10);
//Details spectatorStatus
$object->spectator = (bool) ($object->spectatorStatus % 10);
$object->temporarySpectator = (bool) (intval($object->spectatorStatus / 10) % 10);
$object->pureSpectator = (bool) (intval($object->spectatorStatus / 100) % 10);
$object->autoTarget = (bool) (intval($object->spectatorStatus / 1000) % 10);
$object->currentTargetId = intval($object->spectatorStatus / 10000);
return $object;
}
}
?>

View File

@ -0,0 +1,32 @@
<?php
/**
* ManiaPlanet dedicated server Xml-RPC client
*
* @license http://www.gnu.org/licenses/lgpl.html LGPL License 3
*/
namespace Maniaplanet\DedicatedServer\Structures;
class ScriptInfo extends AbstractStructure
{
public $name;
public $compatibleMapTypes;
public $description;
public $version;
public $paramDescs = array();
static public function fromArray($array)
{
$object = parent::fromArray($array);
if($object->paramDescs)
{
$object->paramDescs = ScriptSettings::fromArrayOfArray($object->paramDescs);
}
return $object;
}
}
?>

View File

@ -0,0 +1,20 @@
<?php
/**
* ManiaPlanet dedicated server Xml-RPC client
*
* @license http://www.gnu.org/licenses/lgpl.html LGPL License 3
*/
namespace Maniaplanet\DedicatedServer\Structures;
final class ScriptSettings extends AbstractStructure
{
public $name;
public $desc;
public $type;
public $default;
}
?>

View File

@ -0,0 +1,42 @@
<?php
/**
* ManiaPlanet dedicated server Xml-RPC client
*
* @license http://www.gnu.org/licenses/lgpl.html LGPL License 3
*/
namespace Maniaplanet\DedicatedServer\Structures;
class ServerOptions extends AbstractStructure
{
public $name;
public $comment;
public $password;
public $passwordForSpectator;
public $hideServer;
public $currentMaxPlayers;
public $nextMaxPlayers;
public $currentMaxSpectators;
public $nextMaxSpectators;
public $isP2PUpload;
public $isP2PDownload;
public $currentLadderMode;
public $nextLadderMode;
public $ladderServerLimitMax;
public $ladderServerLimitMin;
public $currentVehicleNetQuality;
public $nextVehicleNetQuality;
public $currentCallVoteTimeOut;
public $nextCallVoteTimeOut;
public $callVoteRatio;
public $allowMapDownload;
public $autoSaveReplays;
public $autoSaveValidationReplays;
public $refereePassword;
public $refereeMode;
public $currentUseChangingValidationSeed;
public $useChangingValidationSeed;
public $nextUseChangingValidationSeed;
public $clientInputsMaxLatency;
public $keepPlayerSlots;
}

View File

@ -0,0 +1,16 @@
<?php
/**
* ManiaPlanet dedicated server Xml-RPC client
*
* @license http://www.gnu.org/licenses/lgpl.html LGPL License 3
*/
namespace Maniaplanet\DedicatedServer\Structures;
class Skin extends AbstractStructure
{
public $orig;
public $name;
public $checksum;
public $url;
}

View File

@ -0,0 +1,20 @@
<?php
/**
* ManiaPlanet dedicated server Xml-RPC client
*
* @license http://www.gnu.org/licenses/lgpl.html LGPL License 3
*/
namespace Maniaplanet\DedicatedServer\Structures;
class Status extends AbstractStructure
{
const UNKNOWN = 0;
const WAITING = 1;
const LAUNCHING = 2;
const SYNCHRONIZATION = 3;
const PLAY = 4;
const EXITING = 6;
public $code;
public $name;
}

View File

@ -0,0 +1,22 @@
<?php
/**
* ManiaPlanet dedicated server Xml-RPC client
*
* @license http://www.gnu.org/licenses/lgpl.html LGPL License 3
*/
namespace Maniaplanet\DedicatedServer\Structures;
class SystemInfos extends AbstractStructure
{
public $publishedIp;
public $port;
public $p2PPort;
public $titleId;
public $serverLogin;
public $serverPlayerId;
public $connectionDownloadRate;
public $connectionUploadRate;
public $isServer;
public $isDedicated;
}
?>

View File

@ -0,0 +1,22 @@
<?php
/**
* ManiaPlanet dedicated server Xml-RPC client
*
* @license http://www.gnu.org/licenses/lgpl.html LGPL License 3
*/
namespace Maniaplanet\DedicatedServer\Structures;
class Team extends AbstractStructure
{
public $name;
public $zonePath;
public $city;
public $emblemUrl;
public $huePrimary;
public $hueSecondary;
public $rGB;
public $clubLinkUrl;
}
?>

View File

@ -0,0 +1,18 @@
<?php
/**
* ManiaPlanet dedicated server Xml-RPC client
*
* @license http://www.gnu.org/licenses/lgpl.html LGPL License 3
*/
namespace Maniaplanet\DedicatedServer\Structures;
class Version extends AbstractStructure
{
public $name;
public $titleId;
public $version;
public $build;
public $apiVersion;
}
?>

View File

@ -0,0 +1,22 @@
<?php
/**
* ManiaPlanet dedicated server Xml-RPC client
*
* @license http://www.gnu.org/licenses/lgpl.html LGPL License 3
*/
namespace Maniaplanet\DedicatedServer\Structures;
class Vote extends AbstractStructure
{
const STATE_NEW = 'NewVote';
const STATE_CANCELLED = 'VoteCancelled';
const STATE_PASSED = 'VotePassed';
const STATE_FAILED = 'VoteFailed';
public $status;
public $callerLogin;
public $cmdName;
public $cmdParam;
}
?>

View File

@ -0,0 +1,31 @@
<?php
/**
* ManiaPlanet dedicated server Xml-RPC client
*
* @license http://www.gnu.org/licenses/lgpl.html LGPL License 3
*/
namespace Maniaplanet\DedicatedServer\Structures;
class VoteRatio extends AbstractStructure
{
const COMMAND_SCRIPT_SETTINGS = 'SetModeScriptSettingsAndCommands';
const COMMAND_NEXT_MAP = 'NextMap';
const COMMAND_JUMP_MAP = 'JumpToMapIndex';
const COMMAND_SET_NEXT_MAP = 'SetNextMapIndex';
const COMMAND_RESTART_MAP = 'RestartMap';
const COMMAND_TEAM_BALANCE = 'AutoTeamBalance';
const COMMAND_KICK = 'Kick';
const COMMAND_BAN = 'Ban';
public $command;
public $param;
public $ratio;
public function __construct($command = null, $ratio = null)
{
$this->command = $command;
$this->ratio = $ratio;
}
}
?>

View File

@ -0,0 +1,25 @@
<?php
/**
* ManiaPlanet dedicated server Xml-RPC client
*
* @license http://www.gnu.org/licenses/lgpl.html LGPL License 3
*/
namespace Maniaplanet\DedicatedServer\Xmlrpc;
class Base64
{
public $data;
function __construct($data)
{
$this->data = $data;
}
function getXml()
{
return '<base64>'.base64_encode($this->data).'</base64>';
}
}
?>

View File

@ -0,0 +1,472 @@
<?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;
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;
}
}
}
}
function __construct($hostname = 'localhost', $port = 5000, $timeout)
{
$this->socket = false;
$this->reqhandle = 0x80000000;
$this->init($hostname, $port, $timeout);
}
function __destruct()
{
$this->terminate();
}
protected function init($hostname, $port, $timeout)
{
$this->bigEndianTest();
// open connection
$this->socket = @fsockopen($hostname, $port, $errno, $errstr, $timeout);
if (!$this->socket)
{
throw new Exception("transport error - could not open socket (error: $errno, $errstr)", -32300);
}
// handshake
$array_result = unpack('Vsize', fread($this->socket, 4));
$size = $array_result['size'];
if ($size > 64)
{
throw new Exception('transport error - wrong lowlevel protocol header', -32300);
}
$handshake = fread($this->socket, $size);
if ($handshake == 'GBXRemote 1')
{
$this->protocol = 1;
}
elseif ($handshake == 'GBXRemote 2')
{
$this->protocol = 2;
}
else
{
throw new Exception('transport error - wrong lowlevel protocol version', -32300);
}
}
function terminate()
{
if ($this->socket)
{
fclose($this->socket);
$this->socket = false;
}
}
protected function sendRequest(Request $request)
{
$xml = $request->getXml();
@stream_set_timeout($this->socket, 20); // timeout 20 s (to write the request)
// 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 Exception('Connection interupted');
}
$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, 5); // timeout 20 s (to read the reply header)
// Get result
if ($this->protocol == 1)
{
$contents = fread($this->socket, 4);
if (strlen($contents) == 0)
{
throw new Exception('transport error - connection interrupted!', -32700);
}
$array_result = unpack('Vsize', $contents);
$size = $array_result['size'];
$recvhandle = $this->reqhandle;
}
else
{
$contents = fread($this->socket, 8);
if (strlen($contents) == 0)
{
throw new Exception('transport error - connection interrupted!', -32700);
}
$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 Exception('transport error - connection interrupted!', -32700);
}
if ($size > SIZE_MAX)
{
throw new Exception("transport error - answer too big ($size)", -32700);
}
self::$received += $size;
$contents = '';
$contents_length = 0;
@stream_set_timeout($this->socket, 0, 10000); // timeout 10 ms (for successive reads until end)
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', -32700);
}
// 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 Exception('transport error - Client not initialized', -32300);
}
$request = new Request($method, $args);
// Check if request is larger than 512 Kbytes
if ($request->getLength() > 512*1024-8)
{
throw new Exception('transport error - request too large!', -32700);
}
$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 Exception('transport error - Client not initialized', -32300);
}
$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() > 512*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!', -32700);
}
$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!', -32700);
}
}
$this->sendRequest($request);
}
function getResponse()
{
// methodResponses can only have one param - return that
return $this->message->params[0];
}
function readCallbacks($timeout = 2000)
{
if (!$this->socket || $this->protocol == 0)
throw new Exception('transport error - Client not initialized', -32300);
if ($this->protocol == 1)
return false;
// flo: moved to end
//$something_received = count($this->cb_message)>0;
$contents = '';
$contents_length = 0;
@stream_set_timeout($this->socket, 0, 10000); // timeout 10 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, $timeout);
}
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)
{
$timeout = 0; // we don't want to wait for the full time again, just flush the available data
$size = 0;
$recvhandle = 0;
// Get result
$contents = fread($this->socket, 8);
if (strlen($contents) == 0)
{
throw new Exception('transport error - connection interrupted!', -32700);
}
$array_result = unpack('Vsize/Vhandle', $contents);
$size = $array_result['size'];
$recvhandle = $array_result['handle'];
if ($recvhandle == 0 || $size == 0)
{
throw new Exception('transport error - connection interrupted!', -32700);
}
if ($size > SIZE_MAX)
{
throw new Exception("transport error - answer too big ($size)", -32700);
}
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, $timeout);
}
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);
}
}
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;
}
}
?>

View File

@ -0,0 +1,47 @@
<?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
}
}
}
?>

View File

@ -0,0 +1,68 @@
<?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);
}
}
?>

View File

@ -0,0 +1,12 @@
<?php
/**
* ManiaPlanet dedicated server Xml-RPC client
*
* @license http://www.gnu.org/licenses/lgpl.html LGPL License 3
*/
namespace Maniaplanet\DedicatedServer\Xmlrpc;
class Exception extends \Exception {}
?>

View File

@ -0,0 +1,189 @@
<?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;
}
}
}
}
?>

View File

@ -0,0 +1,42 @@
<?php
/**
* ManiaPlanet dedicated server Xml-RPC client
*
* @license http://www.gnu.org/licenses/lgpl.html LGPL License 3
*/
namespace Maniaplanet\DedicatedServer\Xmlrpc;
class Request
{
public $method;
public $args;
public $xml;
function __construct($method, $args)
{
$this->method = $method;
$this->args = $args;
$this->xml = '<?xml version="1.0" encoding="utf-8" ?><methodCall><methodName>' . $this->method . '</methodName><params>';
foreach ($this->args as $arg)
{
$this->xml .= '<param><value>';
$v = new Value($arg);
$this->xml .= $v->getXml();
$this->xml .= '</value></param>' . LF;
}
$this->xml .= '</params></methodCall>';
}
function getLength()
{
return strlen($this->xml);
}
function getXml()
{
return $this->xml;
}
}
?>

View File

@ -0,0 +1,144 @@
<?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;
}
}
?>