improvements of sockethandler, possibility for maniacontrol to maniacontrol connections
This commit is contained in:
parent
687bb7be1b
commit
35de1b1b87
@ -2,7 +2,8 @@
|
||||
|
||||
#Additions
|
||||
- added changelog
|
||||
- added SocketManager which acts like a communication interface you can connect to and interact with ManiaControl (also thanks to TGYoshi for some help)
|
||||
- added CommunicationManager which acts like a communication interface you can connect to and interact with ManiaControl (also thanks to TGYoshi for some help)
|
||||
- You can call ManiaControl from a Website or from ManiaControl itself
|
||||
- added "//removerights login" command
|
||||
- added new EchoManager which handles Interactions between different Controllers
|
||||
- It is possible to send an Echo command via the Method sendEcho, as message Parameter strings, objects or arrays can get used
|
||||
|
@ -53,7 +53,7 @@ class Chat implements CallbackListener, CommunicationListener {
|
||||
$this->maniaControl->getCallbackManager()->registerCallbackListener(CallbackManager::CB_MP_PLAYERCHAT, $this, 'onPlayerChat');
|
||||
|
||||
//Socket Listenings
|
||||
$this->maniaControl->getCommunicationManager()->registerCommunicationListener(CommunicationMethods::GET_SERVER_CHAT, $this, function ($data) {
|
||||
$this->maniaControl->getCommunicationManager()->registerCommunicationListener(CommunicationMethods::GET_SERVER_CHAT, $this, function ($error, $data) {
|
||||
return $this->chatBuffer;
|
||||
});
|
||||
}
|
||||
|
103
core/Communication/Communication.php
Normal file
103
core/Communication/Communication.php
Normal file
@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace ManiaControl\Communication;
|
||||
|
||||
/**
|
||||
* Class for Communicating with other ManiaControls
|
||||
* to call @see ManiaControl\Communication\CommunicationManager\createCommunication
|
||||
*
|
||||
* @author ManiaControl Team <mail@maniacontrol.com>
|
||||
* @copyright 2014-2015 ManiaControl Team
|
||||
* @license http://www.gnu.org/licenses/ GNU General Public License, Version 3
|
||||
*/
|
||||
class Communication {
|
||||
private $socket;
|
||||
private $ip;
|
||||
private $port;
|
||||
private $encryptionPassword;
|
||||
|
||||
private $buffer = "";
|
||||
private $messageQueue = array();
|
||||
|
||||
public function __construct($ip, $port, $encryptionPassword) {
|
||||
$this->ip = $ip;
|
||||
$this->port = $port;
|
||||
$this->encryptionPassword = $encryptionPassword;
|
||||
}
|
||||
|
||||
/** Create an Connection */
|
||||
public function createConnection() {
|
||||
$errno = null;
|
||||
$errstr = null;
|
||||
$this->socket = @fsockopen($this->ip, $this->port, $errno, $errstr, 2);
|
||||
|
||||
//socket_set_nonblock($this->socket);
|
||||
stream_set_blocking($this->socket, 0);
|
||||
|
||||
if ($errno != 0 || !$this->socket) {
|
||||
var_dump($errstr);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call an Method Asynchronously
|
||||
*
|
||||
* @param callable $function
|
||||
* @param $method
|
||||
* @param string $data
|
||||
* @return null
|
||||
*/
|
||||
public function call(callable $function, $method, $data = "") {
|
||||
//TODO throw an exception or smth
|
||||
if (!$this->socket) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$data = json_encode(array("method" => $method, "data" => $data));
|
||||
|
||||
$data = openssl_encrypt($data, CommunicationManager::ENCRYPTION_METHOD, $this->encryptionPassword, OPENSSL_RAW_DATA, CommunicationManager::ENCRYPTION_IV);
|
||||
|
||||
array_push($this->messageQueue, $function);
|
||||
|
||||
// Write Request on Socket
|
||||
fwrite($this->socket, strlen($data) . "\n" . $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process data on every Tick
|
||||
*/
|
||||
public function tick() {
|
||||
$data = fgets($this->socket, 1024); // reads as much as possible OR nothing at all
|
||||
if (strlen($data) > 0) { // got new data
|
||||
$this->buffer .= $data; // append new data to buffer
|
||||
// handle the data the exact same way
|
||||
$arr = explode("\n", $this->buffer, 2);
|
||||
while (count($arr) == 2 && strlen($arr[1]) >= (int) $arr[0]) {
|
||||
// received full message
|
||||
$len = (int) $arr[0];
|
||||
$msg = substr($arr[1], 0, $len); // clip msg
|
||||
$this->buffer = substr($this->buffer, strlen((string) $len) + 1 /* newline */ + $len); // clip buffer
|
||||
|
||||
// Decode Message
|
||||
$data = openssl_decrypt($msg, CommunicationManager::ENCRYPTION_METHOD, $this->encryptionPassword, OPENSSL_RAW_DATA, CommunicationManager::ENCRYPTION_IV);
|
||||
$data = json_decode($data);
|
||||
|
||||
// Received something!
|
||||
//Call Function with Data
|
||||
call_user_func(array_shift($this->messageQueue), $data->error, $data->data);
|
||||
|
||||
// next msg
|
||||
$arr = explode("\n", $this->buffer, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Closes the connection, don't call yourself, let it do the Communication Manager */
|
||||
public function closeConnection() {
|
||||
if ($this->socket) {
|
||||
fclose($this->socket);
|
||||
}
|
||||
}
|
||||
}
|
@ -22,6 +22,13 @@ use React\Socket\Server;
|
||||
* @license http://www.gnu.org/licenses/ GNU General Public License, Version 3
|
||||
*/
|
||||
class CommunicationManager implements CallbackListener {
|
||||
/** Constants */
|
||||
const SETTING_SOCKET_ENABLED = "Activate Socket";
|
||||
const SETTING_SOCKET_PASSWORD = "Password for the Socket Connection";
|
||||
const SETTING_SOCKET_PORT = "Socket Port for Server ";
|
||||
|
||||
const ENCRYPTION_IV = "kZ2Kt0CzKUjN2MJX";
|
||||
const ENCRYPTION_METHOD = "aes-192-cbc";
|
||||
|
||||
/** @var ManiaControl $maniaControl */
|
||||
private $maniaControl = null;
|
||||
@ -34,10 +41,8 @@ class CommunicationManager implements CallbackListener {
|
||||
|
||||
/** @var Server $socket */
|
||||
private $socket = null;
|
||||
|
||||
const SETTING_SOCKET_ENABLED = "Activate Socket";
|
||||
const SETTING_SOCKET_PASSWORD = "Password for the Socket Connection";
|
||||
const SETTING_SOCKET_PORT = "Socket Port for Server ";
|
||||
/** @var Communication[] $communcations */
|
||||
private $communications = array();
|
||||
|
||||
/**
|
||||
* Create a new Communication Handler Instance
|
||||
@ -49,8 +54,48 @@ class CommunicationManager implements CallbackListener {
|
||||
|
||||
$this->maniaControl->getCallbackManager()->registerCallbackListener(SettingManager::CB_SETTING_CHANGED, $this, 'updateSettings');
|
||||
$this->maniaControl->getCallbackManager()->registerCallbackListener(Callbacks::AFTERINIT, $this, 'initCommunicationManager');
|
||||
$this->maniaControl->getCallbackManager()->registerCallbackListener(Callbacks::ONSHUTDOWN, $this, 'onShutDown');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Communication to another ManiaControl
|
||||
*
|
||||
* @param $ip
|
||||
* @param $port
|
||||
* @return \ManiaControl\Communication\Communication
|
||||
*/
|
||||
public function createCommunication($ip, $port, $encryptionKey) {
|
||||
$communication = new Communication($ip, $port, $encryptionKey);
|
||||
$communication->createConnection();
|
||||
|
||||
$this->communications[] = $communication;
|
||||
return $communication;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Closes a opened Communication
|
||||
* Does not necessarily need be called, all connections get destroyed on ManiaControl Shutdown
|
||||
*
|
||||
* @param Communication $communication
|
||||
* @return bool
|
||||
*/
|
||||
public function closeCommunication($communication) {
|
||||
$key = array_search($communication, $this->communications);
|
||||
if (isset($this->communications[$key])) {
|
||||
$this->communications[$key]->closeConnection();
|
||||
unset($this->communications[$key]);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Close all Sockets on maniaControl Shutdown */
|
||||
public function onShutDown() {
|
||||
foreach ($this->communications as $communication) {
|
||||
$this->closeCommunication($communication);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new Communication Listener
|
||||
@ -138,7 +183,7 @@ class CommunicationManager implements CallbackListener {
|
||||
}
|
||||
|
||||
|
||||
$this->createSocket();
|
||||
$this->createListeningSocket();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -154,7 +199,7 @@ class CommunicationManager implements CallbackListener {
|
||||
$socketEnabled = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_SOCKET_ENABLED);
|
||||
|
||||
if ($socketEnabled && !$this->socket) {
|
||||
$this->createSocket();
|
||||
$this->createListeningSocket();
|
||||
}
|
||||
|
||||
if (!$socketEnabled) {
|
||||
@ -165,7 +210,7 @@ class CommunicationManager implements CallbackListener {
|
||||
/**
|
||||
* Creates The Socket
|
||||
*/
|
||||
private function createSocket() {
|
||||
private function createListeningSocket() {
|
||||
$socketEnabled = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_SOCKET_ENABLED);
|
||||
if ($socketEnabled) {
|
||||
|
||||
@ -183,7 +228,7 @@ class CommunicationManager implements CallbackListener {
|
||||
|
||||
$serverLogin = $this->maniaControl->getServer()->login;
|
||||
$socketPort = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_SOCKET_PORT . $serverLogin);
|
||||
$password = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_SOCKET_PASSWORD . $serverLogin);
|
||||
$password = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_SOCKET_PASSWORD);
|
||||
|
||||
try {
|
||||
$this->loop = Factory::create();
|
||||
@ -205,15 +250,16 @@ class CommunicationManager implements CallbackListener {
|
||||
$buffer = substr($buffer, strlen((string) $len) + 1 /* newline */ + $len); // clip buffer
|
||||
|
||||
// Decode Message
|
||||
$data = openssl_decrypt($msg, 'aes-192-cbc', $password, OPENSSL_RAW_DATA, 'kZ2Kt0CzKUjN2MJX');
|
||||
$data = openssl_decrypt($msg, self::ENCRYPTION_METHOD, $password, OPENSSL_RAW_DATA, self::ENCRYPTION_IV);
|
||||
$data = json_decode($data);
|
||||
|
||||
|
||||
if ($data == null) {
|
||||
$data = array("error" => true, "data" => "Data is not provided as an valid AES-196-encrypted encrypted JSON");
|
||||
} else if (!property_exists($data, "method") || !property_exists($data, "data")) {
|
||||
$data = array("error" => true, "data" => "Invalid Message");
|
||||
} else {
|
||||
$answer = $this->triggerCommuncationCallback($data->method, $data->data);
|
||||
$answer = $this->triggerCommuncationCallback($data->method, $data->error, $data->data);
|
||||
//Prepare Response
|
||||
if (!$answer) {
|
||||
$data = array("error" => true, "data" => "No listener or response on the given Message");
|
||||
@ -224,7 +270,7 @@ class CommunicationManager implements CallbackListener {
|
||||
|
||||
//Encode, Encrypt and Send Response
|
||||
$data = json_encode($data);
|
||||
$data = openssl_encrypt($data, 'aes-192-cbc', $password, OPENSSL_RAW_DATA, 'kZ2Kt0CzKUjN2MJX');
|
||||
$data = openssl_encrypt($data, self::ENCRYPTION_METHOD, $password, OPENSSL_RAW_DATA, self::ENCRYPTION_IV);
|
||||
$connection->write(strlen($data) . "\n" . $data);
|
||||
|
||||
// next msg
|
||||
@ -250,5 +296,9 @@ class CommunicationManager implements CallbackListener {
|
||||
if ($this->loop) {
|
||||
$this->loop->tick();
|
||||
}
|
||||
|
||||
foreach ($this->communications as $communication) {
|
||||
$communication->tick();
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,13 @@
|
||||
|
||||
namespace ManiaControl\Communication;
|
||||
|
||||
|
||||
/**
|
||||
* Communication Methods Interface
|
||||
*
|
||||
* @author ManiaControl Team <mail@maniacontrol.com>
|
||||
* @copyright 2014-2015 ManiaControl Team
|
||||
* @license http://www.gnu.org/licenses/ GNU General Public License, Version 3
|
||||
*/
|
||||
interface CommunicationMethods {
|
||||
/** Returns the last 200 lines of the chat (inclusive player logins and nicknames) */
|
||||
const GET_SERVER_CHAT = "Chat.GetServerChat";
|
||||
|
@ -1,7 +1,21 @@
|
||||
Ingame you can activate the Communication Manager and set Password and Port of it.
|
||||
The CommuncationListening of the Communcation Manager can be enabled in the ingame Settings.
|
||||
|
||||
Sample Web Implementation
|
||||
<?php
|
||||
There the following settings are existing:
|
||||
-- Enable Socket Listening (Let the CommunicationManager listen for incoming calls)
|
||||
-- Passsword (Password which get used to encrypt and decrypt the messages for the openssl connection)
|
||||
-- Listening port for every server (this is the port the CommunicationManager listens at)
|
||||
|
||||
Sample ManiaControl Implementation (for ManiaControl to ManiaControl connections)
|
||||
|
||||
##php code begin
|
||||
$communication = $this->maniaControl->getCommunicationManager()->createCommunication(IP/Domain, PORT, 'YOUR_PASSWORD');
|
||||
$communication->call(function($error, $data){
|
||||
var_dump($data);
|
||||
}, CommunicationMethods::GET_SERVER_CHAT);
|
||||
##php code end
|
||||
|
||||
Sample Web Implementation (to call ManiaControl from a website)
|
||||
##php code begin
|
||||
$errno = null;
|
||||
$errstr = null;
|
||||
$socket = fsockopen("xx.xxx.xx.xx", xxxxx, $errno, $errstr, 2);
|
||||
@ -31,4 +45,4 @@ Sample Web Implementation
|
||||
|
||||
//Close the Socket
|
||||
fclose($socket);
|
||||
?>
|
||||
##php code end
|
Loading…
Reference in New Issue
Block a user