roblonium-web/Hexine/api/RCC/functions.php

339 lines
12 KiB
PHP

<?php
require $_SERVER["DOCUMENT_ROOT"] . '/Hexine/api/private/database.php';
// TODO: Move this to separate file?
class UUID {
public static function v5($namespace, $name) {
if(!self::is_valid($namespace)) return false;
// Get hexadecimal components of namespace
$nhex = str_replace(array('-','{','}'), '', $namespace);
// Binary Value
$nstr = '';
// Convert Namespace UUID to bits
for($i = 0; $i < strlen($nhex); $i+=2) {
$nstr .= chr(hexdec($nhex[$i].$nhex[$i+1]));
}
// Calculate hash value
$hash = sha1($nstr . $name);
return sprintf('%08s-%04s-%04x-%04x-%12s',
// 32 bits for "time_low"
substr($hash, 0, 8),
// 16 bits for "time_mid"
substr($hash, 8, 4),
// 16 bits for "time_hi_and_version",
// four most significant bits holds version number 5
(hexdec(substr($hash, 12, 4)) & 0x0fff) | 0x5000,
// 16 bits, 8 bits for "clk_seq_hi_res",
// 8 bits for "clk_seq_low",
// two most significant bits holds zero and one for variant DCE1.1
(hexdec(substr($hash, 16, 4)) & 0x3fff) | 0x8000,
// 48 bits for "node"
substr($hash, 20, 12)
);
}
public static function is_valid($uuid) {
return preg_match('/^\{?[0-9a-f]{8}\-?[0-9a-f]{4}\-?[0-9a-f]{4}\-?'.
'[0-9a-f]{4}\-?[0-9a-f]{12}\}?$/i', $uuid) === 1;
}
}
//UUID::v5('518383a0-66f5-416e-9722-03c8ba625034', 'SomeRandomString');
//access key UUID base: 42078d04-4a0d-11ea-aca5-e759e6572da7
//access key UUID Name: 127.0.0.1:64989 (url or ip+port)
//TODO: Remove this when support for multiple services has been implemented.
$RCCServiceSoap->ip = "127.0.0.1";
$RCCServiceSoap->url = $RCCServiceSoap->ip . ":64989";
$RCCServiceSoap->access = UUID::v5('42078d04-4a0d-11ea-aca5-e759e6572da7', $RCCServiceSoap->url);
class RCCService {
public static function verifyAccessKey($accessKey) {
//global $RCCServiceSoap;
global $database;
// Find service with the exact same access key and compare IPs
$RCCServiceSoap = $database->findRow("cloud", ["access" => $accessKey], ["ip", "port"]);
if ($RCCServiceSoap && $RCCServiceSoap->rowCount() > 0 && $RCCServiceSoap->rowCount() !== null) {
$RCCServiceSoap = $RCCServiceSoap->fetch(PDO::FETCH_OBJ);
}else {
return false;
}
// assemble the url
$RCCServiceSoap->url = $RCCServiceSoap->ip . ":" . $RCCServiceSoap->port;
if ($_SERVER['REMOTE_ADDR'] == $RCCServiceSoap->ip || $_SERVER['HTTP_X_FORWARDED_FOR'] == $RCCServiceSoap->ip) {
return true;
}else {
return false;
}
}
}
//Global variables??
$valueTypes = array( //this array kinda works as a function by converting PHP value types to Lua
'NULL' => 'LUA_TNIL',
'boolean' => 'LUA_TBOOLEAN',
'integer' => 'LUA_TNUMBER',
'string' => 'LUA_TSTRING',
'array' => 'LUA_TTABLE'
);
/*LuaValue types consist of
LUA_TNIL
LUA_TBOOLEAN
LUA_TNUMBER
LUA_TSTRING
LUA_TTABLE
*/
//TODO: Add support for Lua tables. For now RCCService should just throw an error.
function argumentParser($args) { //new and improved!
global $valueTypes;
$data = "";
$argAmmount = count($args);
for($i = 0; $i < $argAmmount; $i++){ //for each argument, append its value
if (gettype($args[$i]) == 'string') {
// html encode for strings
$args[$i] = htmlentities($args[$i], ENT_QUOTES);
}
$data = $data . "
<ns1:LuaValue>
<ns1:type>".$valueTypes[gettype($args[$i])]."</ns1:type>
<ns1:value>".$args[$i]."</ns1:value>
</ns1:LuaValue>";
}
return $data;
}
class SOAP {
public static function post($content, $action, $service) {
$header = array(
"Content-type: text/xml; charset=\"utf-8\"",
"Accept: text/xml",
"Cache-Control: no-cache",
"Pragma: no-cache",
"SOAPAction: ".$action,
"Content-length: ".strlen($content),
);
$content = '<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns2="http://roblox.com/RCCServiceSoap" xmlns:ns1="http://roblox.com/" xmlns:ns3="http://roblox.com/RCCServiceSoap12">
<SOAP-ENV:Body>'.$content;
$content = $content.' </SOAP-ENV:Body>
</SOAP-ENV:Envelope>';
$soap_do = curl_init();
curl_setopt($soap_do, CURLOPT_URL, $service->url );
curl_setopt($soap_do, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($soap_do, CURLOPT_TIMEOUT, 30);
curl_setopt($soap_do, CURLOPT_RETURNTRANSFER, true );
curl_setopt($soap_do, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($soap_do, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($soap_do, CURLOPT_POST, true );
curl_setopt($soap_do, CURLOPT_POSTFIELDS, $content);
curl_setopt($soap_do, CURLOPT_HTTPHEADER, $header);
$curl_response = curl_exec($soap_do);
if($curl_response === false) {
curl_close($soap_do);
return false;
} else {
curl_close($soap_do);
return $curl_response;
}
return false;
}
}
/*
DEPRECATED
Name: New Script Raw
Description: This function directly pings RCCService with a POST request.
Parameters: [
"scriptName" => "The name for the script that's going to be executed. It's also used as the SOAPAction in the header.",
"baseScript" => "The code that's going to be executed by RCCService.",
"jobId" => "The ID used when creating a job for RCCService."
]
DEPRECATED
*/
/*
function NewScriptRaw($scriptName, $baseScript, $jobId) {
//This way the job never expires. :D
$soap_request = '<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns2="http://roblox.com/RCCServiceSoap" xmlns:ns1="http://roblox.com/" xmlns:ns3="http://roblox.com/RCCServiceSoap12">
<SOAP-ENV:Body>
<ns1:Execute>
<ns1:jobID>'.jobId.'</ns1:jobID>
<ns1:script>
<ns1:name>'.$scriptName.'</ns1:name>
<ns1:script>'.$baseScript.'</ns1:script>
</ns1:script>
</ns1:Execute>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>';
$header = array(
"Content-type: text/xml; charset=\"utf-8\"",
"Accept: text/xml",
"Cache-Control: no-cache",
"Pragma: no-cache",
"SOAPAction: {$scriptName}",
"Content-length: ".strlen($soap_request),
);
$soap_do = curl_init();
curl_setopt($soap_do, CURLOPT_URL, "127.0.0.1:64989" );
curl_setopt($soap_do, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($soap_do, CURLOPT_TIMEOUT, 10);
curl_setopt($soap_do, CURLOPT_RETURNTRANSFER, true );
curl_setopt($soap_do, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($soap_do, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($soap_do, CURLOPT_POST, true );
curl_setopt($soap_do, CURLOPT_POSTFIELDS, $soap_request);
curl_setopt($soap_do, CURLOPT_HTTPHEADER, $header);
header('Content-Type: text/plain');
if(curl_exec($soap_do) === false) {
curl_close($soap_do);
return false;
} else {
curl_close($soap_do);
return true;
}
return false;
}
*/
/*
DEPRECATED
Name: New Script
Description: This function uses the given argument names to create a Lua function which is then executed with the $args variable.
Parameters: [
"scriptName" => "The name for the script that's going to be executed.",
"baseScript" => "The code that's going to be inserted into the new function.",
"jobId" => "The ID used when creating a job for RCCService.",
"args" => "These are the parameters used when building and executing the Lua function.
ex: array(
'url' => 'http://sitetest1.roblonium.com/Asset/?id=100',
'baseUrl' => 'http://sitetest1.roblonium.com/',
'fileType' => 'PNG',
'width' => 420,
'height' => 420,
'scriptIcon' => 'http:/roblonium.com/Thumbs/Script.png',
'toolIcon' => 'http:/roblonium.com/Thumbs/Tool.png'
)"
]
DEPRECATED
*/
/*
function NewScript($scriptName, $jobId, $baseScript, $args) {
function argumentParser($args, $nameOnly) {
$data = "";
$argAmmount = count($args);
if ($nameOnly !== true) {
for($i = 0; $i <= $argAmmount; $i++){ //for each argument, append its value
$data = $data . ", " . $args[$i];
}
}else {
for($i = 0; $i <= $argAmmount; $i++){ //for each argument, append its name
$data = $data . ", " . key($args);
next($args);
}
}
return $data;
}
//This uses a more basic script execution function to trim down the amount of space it takes up
$functionBase = '
function start('.argumentParser($args, true).')
'.$baseScript.'
end
start('.argumentParser($args, false).')';
return NewScriptRaw($scriptName, $functionBase, $jobId);
}
*/
/*
Name: Execute Script
Description: This function uses the given arguments to execute a script inside an existing job. Do not try to execute a script inside a non-existent job!!!
Parameters: [
"scriptName" => "The name for the script that's going to be executed.",
"baseScript" => "The code that's going to be executed.",
"jobId" => "The ID of the job in which the script is executed.",
"args" => "These are the parameters that RCCService uses when building and executing the Lua script.
ex: array('http://sitetest1.roblonium.com/Asset/?id=100', 'http://sitetest1.roblonium.com/', 'PNG', 420, 420, 'http:/roblonium.com/Thumbs/Script.png', 'http:/roblonium.com/Thumbs/Tool.png')
RCCService would do the following to the script:
'url, ext, h, v, scriptIcon, toolIcon = ...' (These are set by RCCService based on the order of the given parameters.)
'print({0}..{1}..{2}..{3})' (This would print 'http://sitetest1.roblonium.com/Asset/?id=100http://sitetest1.roblonium.com/PNG420') (This is exclusive to RCCService Arbiter's String.Format function. Though it could be implemented with PHP's sprintf function.)
"
]
*/
function ExecuteScript($service, $scriptName, $baseScript, $jobId, $args) {
$contents = ' <ns1:Execute>
<ns1:jobID>'.$jobId.'</ns1:jobID>
<ns1:script>
<ns1:name>'.$scriptName.'</ns1:name>
<ns1:script>'.$baseScript.'</ns1:script>
<ns1:arguments>'.argumentParser($args).'
</ns1:arguments>
</ns1:script>
</ns1:Execute>';
SOAP::post($contents, "Execute", $service);
}
/*
Name: Open Job
Description: This function opens a job in accordance with the given arguments.
Parameters: [
"scriptName" => "The name for the script that's going to be executed.",
"baseScript" => "The code that's going to be executed.",
"args" => "These are the parameters that RCCService uses when building and executing the Lua script. This is an array.",
"expirationInSeconds" (300) => "The amount of time before the job is terminated.",
"category" (0) => "According to carrot this is the placeId. thx :)",
"cores" => (1) "An unknown variable that RCCService requires. This might control the amount of resources that're allocated to the job."
]
*/
function OpenJob($service, $scriptName, $baseScript, $args = [], $expirationInSeconds = 300 /*(5 minutes) the default time for thumbnails*/, $category = 0, $cores = 1) {
$jobId = UUID::v5('518383a0-66f5-416e-9722-03c8ba625034', $scriptName . $service->url . time());
$contents = ' <ns1:OpenJob>
<ns1:job>
<ns1:id>'.$jobId.'</ns1:id>
<ns1:expirationInSeconds>'.$expirationInSeconds.'</ns1:script>
<ns1:category>'.$category.'</ns1:category>
<ns1:cores>'.$cores.'</ns1:cores>
</ns1:job>
<ns1:script>
<ns1:name>'.$scriptName.'</ns1:name>
<ns1:script><![CDATA['.$baseScript.']]></ns1:script>
<ns1:arguments>'.argumentParser($args).'
</ns1:arguments>
</ns1:script>
</ns1:OpenJob>';
//return $contents;
if (!(SOAP::post($contents, "OpenJob", $service) === FALSE)) {
$scriptInfo = explode("-", $scriptName);
// only add gameserver jobs to the database as thumbnails and stuff like that expire/finish in a matter of seconds
if ($scriptInfo[0] == "GameServer" || substr($scriptName, 0, 10) == "GameServer") {
global $database;
$database->insertRow("jobs", [ // add the job to the jobs database
"category" => $scriptInfo[1],
"jobId" => $jobId,
"ip" => $args[0],
"port" => $args[1],
"serviceId" => $service->access
], "category");
}
return true;
}else {
return false;
}
}
?>