improvements of sockethandler, possibility for maniacontrol to maniacontrol connections
This commit is contained in:
parent
687bb7be1b
commit
35de1b1b87
@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
#Additions
|
#Additions
|
||||||
- added changelog
|
- 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 "//removerights login" command
|
||||||
- added new EchoManager which handles Interactions between different Controllers
|
- 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
|
- 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');
|
$this->maniaControl->getCallbackManager()->registerCallbackListener(CallbackManager::CB_MP_PLAYERCHAT, $this, 'onPlayerChat');
|
||||||
|
|
||||||
//Socket Listenings
|
//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;
|
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
|
* @license http://www.gnu.org/licenses/ GNU General Public License, Version 3
|
||||||
*/
|
*/
|
||||||
class CommunicationManager implements CallbackListener {
|
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 */
|
/** @var ManiaControl $maniaControl */
|
||||||
private $maniaControl = null;
|
private $maniaControl = null;
|
||||||
@ -34,10 +41,8 @@ class CommunicationManager implements CallbackListener {
|
|||||||
|
|
||||||
/** @var Server $socket */
|
/** @var Server $socket */
|
||||||
private $socket = null;
|
private $socket = null;
|
||||||
|
/** @var Communication[] $communcations */
|
||||||
const SETTING_SOCKET_ENABLED = "Activate Socket";
|
private $communications = array();
|
||||||
const SETTING_SOCKET_PASSWORD = "Password for the Socket Connection";
|
|
||||||
const SETTING_SOCKET_PORT = "Socket Port for Server ";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new Communication Handler Instance
|
* 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(SettingManager::CB_SETTING_CHANGED, $this, 'updateSettings');
|
||||||
$this->maniaControl->getCallbackManager()->registerCallbackListener(Callbacks::AFTERINIT, $this, 'initCommunicationManager');
|
$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
|
* 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);
|
$socketEnabled = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_SOCKET_ENABLED);
|
||||||
|
|
||||||
if ($socketEnabled && !$this->socket) {
|
if ($socketEnabled && !$this->socket) {
|
||||||
$this->createSocket();
|
$this->createListeningSocket();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$socketEnabled) {
|
if (!$socketEnabled) {
|
||||||
@ -165,7 +210,7 @@ class CommunicationManager implements CallbackListener {
|
|||||||
/**
|
/**
|
||||||
* Creates The Socket
|
* Creates The Socket
|
||||||
*/
|
*/
|
||||||
private function createSocket() {
|
private function createListeningSocket() {
|
||||||
$socketEnabled = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_SOCKET_ENABLED);
|
$socketEnabled = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_SOCKET_ENABLED);
|
||||||
if ($socketEnabled) {
|
if ($socketEnabled) {
|
||||||
|
|
||||||
@ -183,7 +228,7 @@ class CommunicationManager implements CallbackListener {
|
|||||||
|
|
||||||
$serverLogin = $this->maniaControl->getServer()->login;
|
$serverLogin = $this->maniaControl->getServer()->login;
|
||||||
$socketPort = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_SOCKET_PORT . $serverLogin);
|
$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 {
|
try {
|
||||||
$this->loop = Factory::create();
|
$this->loop = Factory::create();
|
||||||
@ -205,15 +250,16 @@ class CommunicationManager implements CallbackListener {
|
|||||||
$buffer = substr($buffer, strlen((string) $len) + 1 /* newline */ + $len); // clip buffer
|
$buffer = substr($buffer, strlen((string) $len) + 1 /* newline */ + $len); // clip buffer
|
||||||
|
|
||||||
// Decode Message
|
// 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);
|
$data = json_decode($data);
|
||||||
|
|
||||||
|
|
||||||
if ($data == null) {
|
if ($data == null) {
|
||||||
$data = array("error" => true, "data" => "Data is not provided as an valid AES-196-encrypted encrypted JSON");
|
$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")) {
|
} else if (!property_exists($data, "method") || !property_exists($data, "data")) {
|
||||||
$data = array("error" => true, "data" => "Invalid Message");
|
$data = array("error" => true, "data" => "Invalid Message");
|
||||||
} else {
|
} else {
|
||||||
$answer = $this->triggerCommuncationCallback($data->method, $data->data);
|
$answer = $this->triggerCommuncationCallback($data->method, $data->error, $data->data);
|
||||||
//Prepare Response
|
//Prepare Response
|
||||||
if (!$answer) {
|
if (!$answer) {
|
||||||
$data = array("error" => true, "data" => "No listener or response on the given Message");
|
$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
|
//Encode, Encrypt and Send Response
|
||||||
$data = json_encode($data);
|
$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);
|
$connection->write(strlen($data) . "\n" . $data);
|
||||||
|
|
||||||
// next msg
|
// next msg
|
||||||
@ -250,5 +296,9 @@ class CommunicationManager implements CallbackListener {
|
|||||||
if ($this->loop) {
|
if ($this->loop) {
|
||||||
$this->loop->tick();
|
$this->loop->tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach ($this->communications as $communication) {
|
||||||
|
$communication->tick();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,7 +2,13 @@
|
|||||||
|
|
||||||
namespace ManiaControl\Communication;
|
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 {
|
interface CommunicationMethods {
|
||||||
/** Returns the last 200 lines of the chat (inclusive player logins and nicknames) */
|
/** Returns the last 200 lines of the chat (inclusive player logins and nicknames) */
|
||||||
const GET_SERVER_CHAT = "Chat.GetServerChat";
|
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
|
There the following settings are existing:
|
||||||
<?php
|
-- 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;
|
$errno = null;
|
||||||
$errstr = null;
|
$errstr = null;
|
||||||
$socket = fsockopen("xx.xxx.xx.xx", xxxxx, $errno, $errstr, 2);
|
$socket = fsockopen("xx.xxx.xx.xx", xxxxx, $errno, $errstr, 2);
|
||||||
@ -31,4 +45,4 @@ Sample Web Implementation
|
|||||||
|
|
||||||
//Close the Socket
|
//Close the Socket
|
||||||
fclose($socket);
|
fclose($socket);
|
||||||
?>
|
##php code end
|
Loading…
Reference in New Issue
Block a user