"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "8819b656c8da858aeee741066f00c123",
+ "content-hash": "3d65b77f5f76008c32a22709c5d58d73",
"packages": [
{
"name": "graphit/graph-common",
- "version": "v0.1.1",
+ "version": "v0.1.8",
"source": {
"type": "git",
"url": "ssh://git@git.graph-it.com:44022/graphit/graph-common",
- "reference": "fae80afcb63233232c0bf4824e599bc101293225"
+ "reference": "93d05c2c9492c8302d94bf6766db9cb8819467c8"
},
"require": {
- "php": ">=5.6.0",
- "twig/twig": "^1.26.0"
+ "php": ">=8.3.0",
+ "twig/twig": "^1.44.7 || ^3.4.3"
},
"type": "library",
"autoload": {
"psr-4": {
"Graphit\\Graph\\Common\\": "src/"
- }
+ },
+ "files": [
+ "bootstrap.php"
+ ]
},
"authors": [
{
}
],
"description": "Vom Graphserver und -Client geteilte Sourcen.",
- "time": "2022-05-04T16:06:22+00:00"
+ "time": "2025-04-09T12:47:01+00:00"
+ },
+ {
+ "name": "symfony/deprecation-contracts",
+ "version": "v3.5.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/deprecation-contracts.git",
+ "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6",
+ "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
+ "branch-alias": {
+ "dev-main": "3.5-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "function.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "A generic function and convention to trigger deprecation notices",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-09-25T14:20:29+00:00"
},
{
"name": "symfony/polyfill-ctype",
- "version": "v1.25.0",
+ "version": "v1.32.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
- "reference": "30885182c981ab175d4d034db0f6f469898070ab"
+ "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab",
- "reference": "30885182c981ab175d4d034db0f6f469898070ab",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
+ "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
"shasum": ""
},
"require": {
- "php": ">=7.1"
+ "php": ">=7.2"
},
"provide": {
"ext-ctype": "*"
},
"type": "library",
"extra": {
- "branch-alias": {
- "dev-main": "1.23-dev"
- },
"thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
"portable"
],
"support": {
- "source": "https://github.com/symfony/polyfill-ctype/tree/v1.25.0"
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2021-10-20T20:35:02+00:00"
+ "time": "2024-09-09T11:45:10+00:00"
},
{
- "name": "twig/twig",
- "version": "v1.44.6",
+ "name": "symfony/polyfill-mbstring",
+ "version": "v1.32.0",
"source": {
"type": "git",
- "url": "https://github.com/twigphp/Twig.git",
- "reference": "ae39480f010ef88adc7938503c9b02d3baf2f3b3"
+ "url": "https://github.com/symfony/polyfill-mbstring.git",
+ "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/twigphp/Twig/zipball/ae39480f010ef88adc7938503c9b02d3baf2f3b3",
- "reference": "ae39480f010ef88adc7938503c9b02d3baf2f3b3",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
+ "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
"shasum": ""
},
"require": {
- "php": ">=7.2.5",
- "symfony/polyfill-ctype": "^1.8"
+ "ext-iconv": "*",
+ "php": ">=7.2"
},
- "require-dev": {
- "psr/container": "^1.0",
- "symfony/phpunit-bridge": "^4.4.9|^5.0.9"
+ "provide": {
+ "ext-mbstring": "*"
+ },
+ "suggest": {
+ "ext-mbstring": "For best performance"
},
"type": "library",
"extra": {
- "branch-alias": {
- "dev-master": "1.44-dev"
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
- "psr-0": {
- "Twig_": "lib/"
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Mbstring\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for the Mbstring extension",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "mbstring",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
},
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-12-23T08:48:59+00:00"
+ },
+ {
+ "name": "twig/twig",
+ "version": "v3.21.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/twigphp/Twig.git",
+ "reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/twigphp/Twig/zipball/285123877d4dd97dd7c11842ac5fb7e86e60d81d",
+ "reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1.0",
+ "symfony/deprecation-contracts": "^2.5|^3",
+ "symfony/polyfill-ctype": "^1.8",
+ "symfony/polyfill-mbstring": "^1.3"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "^2.0",
+ "psr/container": "^1.0|^2.0",
+ "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/Resources/core.php",
+ "src/Resources/debug.php",
+ "src/Resources/escaper.php",
+ "src/Resources/string_loader.php"
+ ],
"psr-4": {
"Twig\\": "src/"
}
],
"support": {
"issues": "https://github.com/twigphp/Twig/issues",
- "source": "https://github.com/twigphp/Twig/tree/v1.44.6"
+ "source": "https://github.com/twigphp/Twig/tree/v3.21.1"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2021-11-25T13:31:46+00:00"
+ "time": "2025-05-03T07:21:55+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
- "stability-flags": [],
+ "stability-flags": {},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
- "php": ">=5.6.0"
+ "php": ">=8.3.0",
+ "ext-msgpack": "^2.0.0 | ^3.0.0"
},
- "platform-dev": [],
- "plugin-api-version": "2.2.0"
+ "platform-dev": {},
+ "plugin-api-version": "2.6.0"
}
namespace Graphit\Graph\Client;
use Graphit\Graph\Common\RemoteConnection;
-use Graphit\Graph\Common\ConnectionInterface;
+use RuntimeException;
+use LogicException;
-class Connection extends RemoteConnection implements ConnectionInterface {
+/** @api */
+class Connection extends RemoteConnection {
- const STREAM_SELECT_TIMEOUT = 2;
-
- /** @var string */
- private $url;
+ const int STREAM_SELECT_TIMEOUT = 2;
/** @var resource|false */
private $socket = false;
- /** @var array */
- private $options;
-
- /** @var string */
- private $protocoll;
-
- /** @var int|false */
- private $cryptoType;
-
- /** @var int */
- private $messageId = 0;
-
- /**
- * @param string $url
- */
- public function __construct($url, array $options = [])
- {
- $this->url = $url;
- $this->options = $options;
+ private int $messageId = 0;
- $matches = [];
- $pattern = '/^(?<protocoll>[^:]+):\/\//';
- 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];
- }
- }
+ /** @param array{cafile?: string, lofile?: string } $options */
+ public function __construct(
+ private readonly string $url,
+ private readonly array $options = []
+ ) { }
public function __destruct()
{
}
}
- /** @return void */
- private function _connect()
+ private function _connect(): void
{
$context = stream_context_create();
- if ($this->cryptoType !== false) {
- stream_context_set_option($context, [
+ if (substr($this->url, 0, 6) === 'tls://') {
+ stream_context_set_options($context, [
'ssl' => [
'verify_peer' => true,
'verify_peer_name' => false,
'ciphers' => 'HIGH',
- 'cafile' => $this->options['cafile'],
- 'local_cert' => $this->options['lofile'],
+ 'cafile' => $this->options['cafile'] ?? '',
+ 'local_cert' => $this->options['lofile'] ?? '',
],
]);
}
$timeout = (float)ini_get('default_socket_timeout');
$this->socket = stream_socket_client($this->url, $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $context);
if ($this->socket === false) {
- throw new \Exception("stream_socket_server() failed: $errstr");
+ throw new RuntimeException("stream_socket_server() failed: $errstr");
}
if ( !stream_set_blocking($this->socket, false)) {
- throw new \Exception("stream_set_blocking(false) failed!");
+ throw new RuntimeException("stream_set_blocking(false) failed!");
}
$this->_readMessage();
}
- /**
- * @param int $size
- * @return string
- */
- private function _readBytes($size) {
+ private function _readBytes(int $size): string {
if ( !$this->socket) {
- throw new \Exception("Socket not initialized");
+ throw new RuntimeException("Socket not initialized");
}
$bytes = '';
$rs = [$this->socket];
$ws = NULL;
$es = NULL;
- if (@stream_select($rs, $ws, $es, self::STREAM_SELECT_TIMEOUT)) {
+ if (@stream_select($rs, $ws, $es, self::STREAM_SELECT_TIMEOUT) > 0) {
if (feof($this->socket)) {
break;
}
}
if (strlen($bytes) != $size) {
- throw new \Exception("Unable to read $size Bytes from the socket");
+ throw new RuntimeException("Unable to read $size Bytes from the socket");
}
return $bytes;
}
- /** @return mixed */
- private function _readMessage() {
+ private function parseUnpackSize(mixed $value): int {
+ if ( !is_array($value))
+ throw new LogicException('array expected');
+
+ if ( !array_key_exists('size', $value))
+ throw new LogicException('key "size" expected');
+
+ if ( !is_int($value['size']))
+ throw new LogicException('int expected');
+
+ return $value['size'];
+ }
+
+ private function _readMessage(): mixed {
$size = $this->_readBytes(4);
- /** @var int $size */
- $size = unpack('Vsize', $size)['size'];
+ $size = $this->parseUnpackSize(unpack('Vsize', $size));
$message = $this->_readBytes($size);
- return msgpack_unpack($message);
+ return \msgpack_unpack($message);
}
/**
*/
private function _writeBytes($bytes) {
if ( !$this->socket) {
- throw new \Exception("Socket not initialized");
+ throw new RuntimeException("Socket not initialized");
}
$size = strlen($bytes);
}
if ($written != $size) {
- throw new \Exception("Unable to write $size Bytes to socket");
+ throw new RuntimeException("Unable to write $size Bytes to socket");
}
}
- /**
- * @param mixed $message
- * @return void
- */
- private function _writeMessage($message) {
+ private function _writeMessage(mixed $message): void {
/** @var string $message */
$message = msgpack_pack($message);
$message = pack('V', strlen($message)).$message;
$this->_writeBytes($message);
}
- /** */
+ #[\Override]
protected function call($method, array $params)
{
if ( !$this->socket) {
$response = $this->_readMessage();
if ( !isset($response['jsonrpc']) || $response['jsonrpc'] != $request['jsonrpc']) {
- throw new \Exception('Not a JSON-RPC 2.0 response!');
+ throw new RuntimeException('Not a JSON-RPC 2.0 response!');
}
if (isset($response['error'])) {
$error = json_encode($response['error']);
- throw new \Exception("JSON-RPC: Remote error: {$error}");
+ throw new RuntimeException("JSON-RPC: Remote error: {$error}");
}
if ( !isset($response['id']) || $response['id'] != $request['id']) {
- throw new \Exception('JSON-RPC id missing or invalid');
+ throw new RuntimeException('JSON-RPC id missing or invalid');
}
return $response['result'];