From 69c4c664abaeb3b69016a00e0d03015383372c8f Mon Sep 17 00:00:00 2001 From: Sebastian Wassen Date: Fri, 18 Aug 2017 16:06:15 +0200 Subject: [PATCH] initial commit --- .gitignore | 1 + composer.json | 16 ++++ composer.lock | 46 ++++++++++ src/Connection.php | 145 +++++++++++++++++++++++++++++++ src/RemoteConnection.php | 183 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 391 insertions(+) create mode 100644 .gitignore create mode 100644 composer.json create mode 100644 composer.lock create mode 100644 src/Connection.php create mode 100644 src/RemoteConnection.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..57872d0 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/vendor/ diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..007c143 --- /dev/null +++ b/composer.json @@ -0,0 +1,16 @@ +{ + "name": "graphit/graph-client", + "type": "library", + "authors": [ + { + "name": "Graph-IT", + "email": "info@graph-it.com" + } + ], + "require": { + "graphit/graph-common": "dev-master" + }, + "autoload": { + "psr-4": { "Graphit\\Graph\\Client\\": "src/" } + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..b45a5bc --- /dev/null +++ b/composer.lock @@ -0,0 +1,46 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "content-hash": "ea6b729336e3f588b73de24a48480b85", + "packages": [ + { + "name": "graphit/graph-common", + "version": "dev-master", + "source": { + "type": "git", + "url": "ssh://git@git.graph-it.com/graphit/graph-common", + "reference": "96f2657f44cefb3aa5c1de2b2ea95d9411a13098" + }, + "require": { + "php": ">=5.6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Graphit\\Graph\\Common\\": "src/" + } + }, + "authors": [ + { + "name": "Graph-IT", + "email": "info@graph-it.com" + } + ], + "description": "Vom Graphserver und -Client geteilte Sourcen.", + "time": "2017-08-18T12:42:07+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": { + "graphit/graph-common": 20 + }, + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} diff --git a/src/Connection.php b/src/Connection.php new file mode 100644 index 0000000..2b4567d --- /dev/null +++ b/src/Connection.php @@ -0,0 +1,145 @@ +url = $url; + $this->options = $options; + + $matches = []; + $pattern = '/^(?[^:]+):\/\//'; + if (preg_match($pattern, $this->url, $matches) !== 1) { + throw new \Exception('Unable to find Transport in URL '.$this->url.'!'); + } + $this->protocoll = $matches['protocoll']; + + $this->cryptoType = false; + $cryptoTypes = [ + 'tls' => STREAM_CRYPTO_METHOD_TLS_CLIENT, + ]; + if (isset($cryptoTypes[$this->protocoll])) { + $this->cryptoType = $cryptoTypes[$this->protocoll]; + } + } + + public function __destruct() + { + if ($this->socket) { + fclose($this->socket); + } + } + + protected function _connect() + { + $context = stream_context_create(); + + if ($this->cryptoType) { + stream_context_set_option($context, [ + 'ssl' => [ + 'verify_peer' => true, + 'verify_peer_name' => false, + 'ciphers' => 'HIGH', + 'cafile' => $this->options['cafile'], + 'local_cert' => $this->options['lofile'], + ], + ]); + } + + $this->socket = stream_socket_client($this->url, $errno, $errstr, ini_get('default_socket_timeout'), STREAM_CLIENT_CONNECT, $context); + if ($this->socket === false) { + throw new \Exception("stream_socket_server() failed: $errstr\n"); + } + $this->_readMessage(); + } + + protected function _readBytes($size) { + $bytes = ''; + while (strlen($bytes) < $size) { + $fread = fread($this->socket, $size - strlen($bytes)); + if ($fread === false) { + break; + } + $bytes.= $fread; + } + if (strlen($bytes) != $size) { + throw new \Exception("Unable to read $size Bytes from the socket"); + } + return $bytes; + } + + protected function _readMessage() { + $size = $this->_readBytes(4); + $size = unpack('Vsize', $size)['size']; + + $message = $this->_readBytes($size); + return msgpack_unpack($message); + } + + protected function _writeBytes($bytes) { + $size = strlen($bytes); + for ($written = 0; $written < strlen($bytes); $written += $fwrite) { + $fwrite = fwrite($this->socket, substr($bytes, $written)); + if ($fwrite === false) { + break; + } + } + if ($written != $size) { + throw new \Exception("Unable to write $size Bytes request to socket"); + } + } + + protected function _writeMessage($message) { + $message = msgpack_pack($message); + $message = pack('V', strlen($message)).$message; + $this->_writeBytes($message); + } + + /** */ + protected function call($method, array $params) + { + static $id = 0; + + if ( !$this->socket) { + $this->_connect(); + } + + $request = [ + 'jsonrpc' => '2.0', + 'method' => $method, + 'params' => $params, + 'id' => ++$id, + ]; + $this->_writeMessage($request); + + $response = $this->_readMessage(); + if ( !isset($response['jsonrpc']) || $response['jsonrpc'] != $request['jsonrpc']) { + throw new \Exception('Not a JSON-RPC 2.0 response!'); + } + if (isset($response['error'])) { + $error = implode(' ', $response['error']); + throw new \Exception("JSON-RPC: Remote error: {$error}"); + } + if ( !isset($response['id']) || $response['id'] != $request['id']) { + throw new \Exception('JSON-RPC id missing or invalid'); + } + + return $response['result']; + } +} diff --git a/src/RemoteConnection.php b/src/RemoteConnection.php new file mode 100644 index 0000000..4f9e798 --- /dev/null +++ b/src/RemoteConnection.php @@ -0,0 +1,183 @@ + + */ +abstract class RemoteConnection implements ConnectionInterface +{ + /** + * Leitet den Methodenaufruf an den Graphen weiter. + * + * @param string $method die aufgerufene Methode + * @param array $params die Paremeter der Methode + * + * @return mixed|null die Antwort vom Graphen + */ + protected abstract function call($method, array $params); + + /** */ + public function erzeuge($knoten_typ) + { + return $this->call('erzeuge', array($knoten_typ)); + } + + /** */ + public function vernichte($node_guid) + { + return $this->call('vernichte', array($node_guid)); + } + + /** */ + public function knotentyp($node_guid) + { + return $this->call('knotentyp', array($node_guid)); + } + + /** */ + public function setze($node_guid, $attributknoten_typ, $wert) + { + return $this->call('setze', array($node_guid, $attributknoten_typ, $wert)); + } + + /** */ + public function attribut($node_guid, $attributknoten_typ) + { + return $this->call('attribut', array($node_guid, $attributknoten_typ)); + } + + /** */ + public function attribute($node_guid, $knoten_typ, $attribute) + { + return $this->call('attribute', array($node_guid, $knoten_typ, $attribute)); + } + + /** */ + public function attributsknoten($attributknoten_typ, $wert) + { + return $this->call('attributsknoten', array($attributknoten_typ, $wert)); + } + + /** */ + public function berechne($node_guid, $datenfunktion_name) + { + return $this->call('berechne', array($node_guid, $datenfunktion_name)); + } + + /** */ + public function verknuepfe($node_guid1, $node_guid2) + { + return $this->call('verknuepfe', array($node_guid1, $node_guid2)); + } + + /** */ + public function entknuepfe($node_guid1, $node_guid2) + { + return $this->call('entknuepfe', array($node_guid1, $node_guid2)); + } + + /** */ + public function knoten($node_guid, $knoten_typ) + { + return $this->call('knoten', array($node_guid, $knoten_typ)); + } + + /** */ + public function liste($node_guid, $knoten_typ, $reihenfolge = false, $eingrenzung = false, array $parameter = array()) + { + return $this->call('liste', array($node_guid, $knoten_typ, $reihenfolge, $eingrenzung, $parameter)); + } + + /** */ + public function listeattribute($node_guid, $knoten_typ, $attribute, $reihenfolge = false, $eingrenzung = false, array $parameter = array()) + { + return $this->call('listeattribute', array($node_guid, $knoten_typ, $attribute, $reihenfolge, $eingrenzung, $parameter)); + } + + /** */ + public function listezahl($node_guid, $knoten_typ, $eingrenzung = false, array $parameter = array()) + { + return $this->call('listezahl', array($node_guid, $knoten_typ, $eingrenzung, $parameter)); + } + + /** */ + public function moegliche($node_guid, $knoten_typ, $reihenfolge = false, $eingrenzung = false, array $parameter = array()) + { + return $this->call('moegliche', array($node_guid, $knoten_typ, $reihenfolge, $eingrenzung, $parameter)); + } + + /** */ + public function moeglicheattribute($node_guid, $knoten_typ, $attribute, $reihenfolge = false, $eingrenzung = false, array $parameter = array()) + { + return $this->call('moeglicheattribute', array($node_guid, $knoten_typ, $attribute, $reihenfolge, $eingrenzung, $parameter)); + } + + /** */ + public function moeglichezahl($node_guid, $knoten_typ, $eingrenzung = false, array $parameter = array()) + { + return $this->call('moeglichezahl', array($node_guid, $knoten_typ, $eingrenzung, $parameter)); + } + + /** */ + public function alle($knoten_typ, $reihenfolge = false, $eingrenzung = false, array $parameter = array()) + { + return $this->call('alle', array($knoten_typ, $reihenfolge, $eingrenzung, $parameter)); + } + + /** */ + public function alleattribute($knoten_typ, $attribute, $reihenfolge = false, $eingrenzung = false, array $parameter = array()) + { + return $this->call('alleattribute', array($knoten_typ, $attribute, $reihenfolge, $eingrenzung, $parameter)); + } + + /** */ + public function allezahl($knoten_typ, $eingrenzung = false, array $parameter = array()) + { + return $this->call('allezahl', array($knoten_typ, $eingrenzung, $parameter)); + } + + /** */ + public function aktion($node_guid, $aktionfunktion_name) + { + return $this->call('aktion', array($node_guid, $aktionfunktion_name)); + } + + /** */ + public function erzeugeknoten($knoten_typ) + { + return $this->call('erzeugeknoten', array($knoten_typ)); + } + + /** */ + public function vernichteknoten($node_guid) + { + return $this->call('vernichteknoten', array($node_guid)); + } + + /** */ + public function service($graphmodulservice_name, ...$parameter) + { + return $this->call('service', func_get_args()); + } + + /** */ + public function sessionattribut($schluessel, $default = null) + { + return $this->call('sessionattribut',[$schluessel, $default]); + } + + /** */ + public function sessionsetze($schluessel, $wert) + { + return $this->call('sessionsetze', [$schluessel, $wert]); + } + /* */ +} -- 2.34.1