Rename and a set of reworks.
- Aiwass -> RPCii - Swapped the meaning of "Procedure" and "Action" - IRpcActionHandler is now RpcHandler, abstract class no longer exists like Index - Anything suffixed by Trait is now suffixed by Common - All I prefixes on interfaces are gone - A PHP StreamWrapper implementation of HttpRequest added as a fallback for when cURL isnt installed - HttpRpcServer now hosts on /_rpcii instead of /_aiwass - Packagist package is now flashii/rpcii instead of flashwave/aiwass That's probably all of it but I probably forgor.
This commit is contained in:
parent
cf6653ed46
commit
93ec139171
41 changed files with 782 additions and 641 deletions
18
README.md
18
README.md
|
@ -1,29 +1,29 @@
|
|||
# Aiwass
|
||||
# RPCii (旧Aiwass)
|
||||
|
||||
Aiwass is an RPC client and server library.
|
||||
RPCii is an RPC client and server library.
|
||||
An Index compatible route handler is provided to make it really low effort to get a server going.
|
||||
|
||||
## Requirements and Dependencies
|
||||
|
||||
Aiwass currently targets **PHP 8.3** with the `msgpack` extension installed.
|
||||
RPCii currently targets **PHP 8.3** with the `msgpack` extension installed.
|
||||
|
||||
|
||||
## Versioning
|
||||
|
||||
Aiwass versioning will follows the [Semantic Versioning specification v2.0.0](https://semver.org/spec/v2.0.0.html).
|
||||
RPCii versioning will follows the [Semantic Versioning specification v2.0.0](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
Changes to minimum required PHP version other major overhauls to Aiwass itself that break compatibility will be reasons for incrementing the major version.
|
||||
Changes to minimum required PHP version other major overhauls to RPCii itself that break compatibility will be reasons for incrementing the major version.
|
||||
|
||||
Aiwass depends on Index, but its versioning depends on the minimum PHP version and should thus be fairly inconsequential.
|
||||
RPCii depends on Index, but its versioning depends on the minimum PHP version and should thus be fairly inconsequential.
|
||||
|
||||
Previous major versions may be supported for a time with backports depending on what projects of mine still target older versions of PHP.
|
||||
|
||||
The version is stored in the root of the repository in a file called `VERSION` and can be read out within Aiwass using `Aiwass\Aiwass::version()`.
|
||||
The version is stored in the root of the repository in a file called `VERSION` and can be read out within RPCii using `RPCii\RPCii::version()`.
|
||||
|
||||
|
||||
## Contribution
|
||||
|
||||
By submitting code for inclusion in the main Aiwass source tree you agree to transfer ownership of the code to the project owner.
|
||||
By submitting code for inclusion in the main RPCii source tree you agree to transfer ownership of the code to the project owner.
|
||||
The contributor will still be attributed for the contributed code, unless they ask for this attribution to be removed.
|
||||
This is to avoid intellectual property rights traps and drama that could lead to blackmail situations.
|
||||
If you do not agree with these terms, you are free to fork off.
|
||||
|
@ -31,4 +31,4 @@ If you do not agree with these terms, you are free to fork off.
|
|||
|
||||
## Licencing
|
||||
|
||||
Aiwass is available under the BSD 3-Clause Clear License, a full version of which is enclosed in the LICENCE file.
|
||||
RPCii is available under the BSD 3-Clause Clear License, a full version of which is enclosed in the LICENCE file.
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
1.1.0
|
||||
2.0.0
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "flashwave/aiwass",
|
||||
"description": "Shared HTTP RPC client/server library.",
|
||||
"name": "flashii/rpcii",
|
||||
"description": "HTTP RPC client/server library.",
|
||||
"type": "library",
|
||||
"homepage": "https://railgun.sh/aiwass",
|
||||
"homepage": "https://railgun.sh/rpcii",
|
||||
"license": "bsd-3-clause-clear",
|
||||
"require": {
|
||||
"php": ">=8.3",
|
||||
|
@ -10,8 +10,8 @@
|
|||
"flashwave/index": "^0.2410"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^11.2",
|
||||
"phpstan/phpstan": "^1.11"
|
||||
"phpunit/phpunit": "^11.4",
|
||||
"phpstan/phpstan": "^2.0"
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
|
@ -23,7 +23,7 @@
|
|||
],
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Aiwass\\": "src"
|
||||
"RPCii\\": "src"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
144
composer.lock
generated
144
composer.lock
generated
|
@ -4,15 +4,15 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "8d01741caad2805272e619b4aa3c3c5e",
|
||||
"content-hash": "f82764057cc610971b1823a40f95da29",
|
||||
"packages": [
|
||||
{
|
||||
"name": "flashwave/index",
|
||||
"version": "v0.2410.42339",
|
||||
"version": "v0.2410.191603",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://patchii.net/flash/index.git",
|
||||
"reference": "d3e4d0985a1189d15fb8ed9eb105830c9dc38c4d"
|
||||
"reference": "17cdb4d1c239241200d7e30968122a8cd8b26509"
|
||||
},
|
||||
"require": {
|
||||
"ext-mbstring": "*",
|
||||
|
@ -33,6 +33,14 @@
|
|||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/Cache/ArrayCache/_ndx.php",
|
||||
"src/Cache/Memcached/_ndx.php",
|
||||
"src/Cache/Valkey/_ndx.php",
|
||||
"src/Db/MariaDb/_ndx.php",
|
||||
"src/Db/NullDb/_ndx.php",
|
||||
"src/Db/Sqlite/_ndx.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Index\\": "src"
|
||||
}
|
||||
|
@ -51,7 +59,7 @@
|
|||
],
|
||||
"description": "Composer package for the common library for my projects.",
|
||||
"homepage": "https://railgun.sh/index",
|
||||
"time": "2024-10-04T23:39:32+00:00"
|
||||
"time": "2024-10-19T16:04:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/deprecation-contracts",
|
||||
|
@ -122,16 +130,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/mime",
|
||||
"version": "v7.1.5",
|
||||
"version": "v7.1.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/mime.git",
|
||||
"reference": "711d2e167e8ce65b05aea6b258c449671cdd38ff"
|
||||
"reference": "caa1e521edb2650b8470918dfe51708c237f0598"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/mime/zipball/711d2e167e8ce65b05aea6b258c449671cdd38ff",
|
||||
"reference": "711d2e167e8ce65b05aea6b258c449671cdd38ff",
|
||||
"url": "https://api.github.com/repos/symfony/mime/zipball/caa1e521edb2650b8470918dfe51708c237f0598",
|
||||
"reference": "caa1e521edb2650b8470918dfe51708c237f0598",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -186,7 +194,7 @@
|
|||
"mime-type"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/mime/tree/v7.1.5"
|
||||
"source": "https://github.com/symfony/mime/tree/v7.1.6"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -202,7 +210,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-09-20T08:28:38+00:00"
|
||||
"time": "2024-10-25T15:11:02+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
|
@ -673,16 +681,16 @@
|
|||
},
|
||||
{
|
||||
"name": "twig/twig",
|
||||
"version": "v3.14.0",
|
||||
"version": "v3.14.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/twigphp/Twig.git",
|
||||
"reference": "126b2c97818dbff0cdf3fbfc881aedb3d40aae72"
|
||||
"reference": "0b6f9d8370bb3b7f1ce5313ed8feb0fafd6e399a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/126b2c97818dbff0cdf3fbfc881aedb3d40aae72",
|
||||
"reference": "126b2c97818dbff0cdf3fbfc881aedb3d40aae72",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/0b6f9d8370bb3b7f1ce5313ed8feb0fafd6e399a",
|
||||
"reference": "0b6f9d8370bb3b7f1ce5313ed8feb0fafd6e399a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -736,7 +744,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/twigphp/Twig/issues",
|
||||
"source": "https://github.com/twigphp/Twig/tree/v3.14.0"
|
||||
"source": "https://github.com/twigphp/Twig/tree/v3.14.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -748,22 +756,22 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-09-09T17:55:12+00:00"
|
||||
"time": "2024-11-07T12:36:22+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "myclabs/deep-copy",
|
||||
"version": "1.12.0",
|
||||
"version": "1.12.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/myclabs/DeepCopy.git",
|
||||
"reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c"
|
||||
"reference": "123267b2c49fbf30d78a7b2d333f6be754b94845"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c",
|
||||
"reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c",
|
||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/123267b2c49fbf30d78a7b2d333f6be754b94845",
|
||||
"reference": "123267b2c49fbf30d78a7b2d333f6be754b94845",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -802,7 +810,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/myclabs/DeepCopy/issues",
|
||||
"source": "https://github.com/myclabs/DeepCopy/tree/1.12.0"
|
||||
"source": "https://github.com/myclabs/DeepCopy/tree/1.12.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -810,20 +818,20 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-06-12T14:39:25+00:00"
|
||||
"time": "2024-11-08T17:47:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
"version": "v5.3.0",
|
||||
"version": "v5.3.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nikic/PHP-Parser.git",
|
||||
"reference": "3abf7425cd284141dc5d8d14a9ee444de3345d1a"
|
||||
"reference": "8eea230464783aa9671db8eea6f8c6ac5285794b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3abf7425cd284141dc5d8d14a9ee444de3345d1a",
|
||||
"reference": "3abf7425cd284141dc5d8d14a9ee444de3345d1a",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/8eea230464783aa9671db8eea6f8c6ac5285794b",
|
||||
"reference": "8eea230464783aa9671db8eea6f8c6ac5285794b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -866,9 +874,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v5.3.0"
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v5.3.1"
|
||||
},
|
||||
"time": "2024-09-29T13:56:26+00:00"
|
||||
"time": "2024-10-08T18:51:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phar-io/manifest",
|
||||
|
@ -990,20 +998,20 @@
|
|||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "1.12.5",
|
||||
"version": "2.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "7e6c6cb7cecb0a6254009a1a8a7d54ec99812b17"
|
||||
"reference": "ab4e9b4415a5fc9e4d27f7fe16c8bc9d067dcd6d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/7e6c6cb7cecb0a6254009a1a8a7d54ec99812b17",
|
||||
"reference": "7e6c6cb7cecb0a6254009a1a8a7d54ec99812b17",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/ab4e9b4415a5fc9e4d27f7fe16c8bc9d067dcd6d",
|
||||
"reference": "ab4e9b4415a5fc9e4d27f7fe16c8bc9d067dcd6d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2|^8.0"
|
||||
"php": "^7.4|^8.0"
|
||||
},
|
||||
"conflict": {
|
||||
"phpstan/phpstan-shim": "*"
|
||||
|
@ -1044,39 +1052,39 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-09-26T12:45:22+00:00"
|
||||
"time": "2024-11-11T15:43:04+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
"version": "11.0.6",
|
||||
"version": "11.0.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "ebdffc9e09585dafa71b9bffcdb0a229d4704c45"
|
||||
"reference": "f7f08030e8811582cc459871d28d6f5a1a4d35ca"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ebdffc9e09585dafa71b9bffcdb0a229d4704c45",
|
||||
"reference": "ebdffc9e09585dafa71b9bffcdb0a229d4704c45",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f7f08030e8811582cc459871d28d6f5a1a4d35ca",
|
||||
"reference": "f7f08030e8811582cc459871d28d6f5a1a4d35ca",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-dom": "*",
|
||||
"ext-libxml": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"nikic/php-parser": "^5.1.0",
|
||||
"nikic/php-parser": "^5.3.1",
|
||||
"php": ">=8.2",
|
||||
"phpunit/php-file-iterator": "^5.0.1",
|
||||
"phpunit/php-file-iterator": "^5.1.0",
|
||||
"phpunit/php-text-template": "^4.0.1",
|
||||
"sebastian/code-unit-reverse-lookup": "^4.0.1",
|
||||
"sebastian/complexity": "^4.0.1",
|
||||
"sebastian/environment": "^7.2.0",
|
||||
"sebastian/lines-of-code": "^3.0.1",
|
||||
"sebastian/version": "^5.0.1",
|
||||
"sebastian/version": "^5.0.2",
|
||||
"theseer/tokenizer": "^1.2.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^11.0"
|
||||
"phpunit/phpunit": "^11.4.1"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-pcov": "PHP extension that provides line coverage",
|
||||
|
@ -1114,7 +1122,7 @@
|
|||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
||||
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.6"
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.7"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1122,7 +1130,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-08-22T04:37:56+00:00"
|
||||
"time": "2024-10-09T06:21:38+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
|
@ -1371,16 +1379,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "11.3.6",
|
||||
"version": "11.4.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "d62c45a19c665bb872c2a47023a0baf41a98bb2b"
|
||||
"reference": "e8e8ed1854de5d36c088ec1833beae40d2dedd76"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d62c45a19c665bb872c2a47023a0baf41a98bb2b",
|
||||
"reference": "d62c45a19c665bb872c2a47023a0baf41a98bb2b",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e8e8ed1854de5d36c088ec1833beae40d2dedd76",
|
||||
"reference": "e8e8ed1854de5d36c088ec1833beae40d2dedd76",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1394,21 +1402,21 @@
|
|||
"phar-io/manifest": "^2.0.4",
|
||||
"phar-io/version": "^3.2.1",
|
||||
"php": ">=8.2",
|
||||
"phpunit/php-code-coverage": "^11.0.6",
|
||||
"phpunit/php-code-coverage": "^11.0.7",
|
||||
"phpunit/php-file-iterator": "^5.1.0",
|
||||
"phpunit/php-invoker": "^5.0.1",
|
||||
"phpunit/php-text-template": "^4.0.1",
|
||||
"phpunit/php-timer": "^7.0.1",
|
||||
"sebastian/cli-parser": "^3.0.2",
|
||||
"sebastian/code-unit": "^3.0.1",
|
||||
"sebastian/comparator": "^6.1.0",
|
||||
"sebastian/comparator": "^6.1.1",
|
||||
"sebastian/diff": "^6.0.2",
|
||||
"sebastian/environment": "^7.2.0",
|
||||
"sebastian/exporter": "^6.1.3",
|
||||
"sebastian/global-state": "^7.0.2",
|
||||
"sebastian/object-enumerator": "^6.0.1",
|
||||
"sebastian/type": "^5.1.0",
|
||||
"sebastian/version": "^5.0.1"
|
||||
"sebastian/version": "^5.0.2"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-soap": "To be able to generate mocks based on WSDL files"
|
||||
|
@ -1419,7 +1427,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "11.3-dev"
|
||||
"dev-main": "11.4-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -1451,7 +1459,7 @@
|
|||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/11.3.6"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/11.4.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1467,7 +1475,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-09-19T10:54:28+00:00"
|
||||
"time": "2024-10-28T13:07:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/cli-parser",
|
||||
|
@ -1641,16 +1649,16 @@
|
|||
},
|
||||
{
|
||||
"name": "sebastian/comparator",
|
||||
"version": "6.1.0",
|
||||
"version": "6.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/comparator.git",
|
||||
"reference": "fa37b9e2ca618cb051d71b60120952ee8ca8b03d"
|
||||
"reference": "43d129d6a0f81c78bee378b46688293eb7ea3739"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa37b9e2ca618cb051d71b60120952ee8ca8b03d",
|
||||
"reference": "fa37b9e2ca618cb051d71b60120952ee8ca8b03d",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/43d129d6a0f81c78bee378b46688293eb7ea3739",
|
||||
"reference": "43d129d6a0f81c78bee378b46688293eb7ea3739",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1661,12 +1669,12 @@
|
|||
"sebastian/exporter": "^6.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^11.3"
|
||||
"phpunit/phpunit": "^11.4"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "6.1-dev"
|
||||
"dev-main": "6.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -1706,7 +1714,7 @@
|
|||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/comparator/issues",
|
||||
"security": "https://github.com/sebastianbergmann/comparator/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/comparator/tree/6.1.0"
|
||||
"source": "https://github.com/sebastianbergmann/comparator/tree/6.2.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1714,7 +1722,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-09-11T15:42:56+00:00"
|
||||
"time": "2024-10-31T05:30:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/complexity",
|
||||
|
@ -2340,16 +2348,16 @@
|
|||
},
|
||||
{
|
||||
"name": "sebastian/version",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/version.git",
|
||||
"reference": "45c9debb7d039ce9b97de2f749c2cf5832a06ac4"
|
||||
"reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/version/zipball/45c9debb7d039ce9b97de2f749c2cf5832a06ac4",
|
||||
"reference": "45c9debb7d039ce9b97de2f749c2cf5832a06ac4",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c687e3387b99f5b03b6caa64c74b63e2936ff874",
|
||||
"reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2382,7 +2390,7 @@
|
|||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/version/issues",
|
||||
"security": "https://github.com/sebastianbergmann/version/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/version/tree/5.0.1"
|
||||
"source": "https://github.com/sebastianbergmann/version/tree/5.0.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -2390,7 +2398,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-07-03T05:13:08+00:00"
|
||||
"time": "2024-10-09T05:16:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "theseer/tokenizer",
|
||||
|
|
|
@ -3,17 +3,17 @@
|
|||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="https://www.phpdoc.org"
|
||||
xsi:noNamespaceSchemaLocation="data/xsd/phpdoc.xsd">
|
||||
<title>Aiwass Documentation</title>
|
||||
<title>RPCii Documentation</title>
|
||||
<template name="default"/>
|
||||
<paths>
|
||||
<output>docs/html</output>
|
||||
</paths>
|
||||
<version number="0.1">
|
||||
<version number="2.0">
|
||||
<folder>latest</folder>
|
||||
<api format="php">
|
||||
<output>api</output>
|
||||
<visibility>public</visibility>
|
||||
<default-package-name>Aiwass</default-package-name>
|
||||
<default-package-name>RPCii</default-package-name>
|
||||
<source dsn=".">
|
||||
<path>src</path>
|
||||
</source>
|
||||
|
|
|
@ -3,5 +3,7 @@ parameters:
|
|||
checkUninitializedProperties: true
|
||||
checkImplicitMixed: true
|
||||
checkBenevolentUnionTypes: true
|
||||
treatPhpDocTypesAsCertain: false
|
||||
paths:
|
||||
- src
|
||||
- tests
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.2/phpunit.xsd"
|
||||
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/11.4/phpunit.xsd"
|
||||
colors="true"
|
||||
executionOrder="depends,defects"
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<?php
|
||||
// CurlHttpRequest.php
|
||||
// Created: 2024-08-13
|
||||
// Updated: 2024-10-05
|
||||
// Updated: 2024-11-13
|
||||
|
||||
namespace Aiwass\Client;
|
||||
namespace RPCii\Client;
|
||||
|
||||
use CurlHandle;
|
||||
use RuntimeException;
|
||||
|
@ -11,7 +11,7 @@ use RuntimeException;
|
|||
/**
|
||||
* Provides a cURL based HTTP request implementation.
|
||||
*/
|
||||
class CurlHttpRequest implements IHttpRequest {
|
||||
class CurlHttpRequest implements HttpRequest {
|
||||
private CurlHandle $handle;
|
||||
private bool $isPost = false;
|
||||
private ?string $url = null;
|
||||
|
@ -36,15 +36,11 @@ class CurlHttpRequest implements IHttpRequest {
|
|||
CURLOPT_MAXREDIRS => 2,
|
||||
CURLOPT_PROTOCOLS => CURLPROTO_HTTPS,
|
||||
CURLOPT_TIMEOUT => 5,
|
||||
CURLOPT_USERAGENT => 'Aiwass',
|
||||
CURLOPT_USERAGENT => 'RPCii',
|
||||
]);
|
||||
}
|
||||
|
||||
public function __destruct() {
|
||||
$this->close();
|
||||
}
|
||||
|
||||
public function close(): void {
|
||||
curl_close($this->handle);
|
||||
}
|
||||
|
||||
|
@ -87,7 +83,6 @@ class CurlHttpRequest implements IHttpRequest {
|
|||
if($response === false)
|
||||
throw new RuntimeException(curl_error($this->handle));
|
||||
|
||||
$this->close();
|
||||
if($response === true)
|
||||
return '';
|
||||
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
<?php
|
||||
// IHttpRequest.php
|
||||
// HttpRequest.php
|
||||
// Created: 2024-08-13
|
||||
// Updated: 2024-10-05
|
||||
// Updated: 2024-11-13
|
||||
|
||||
namespace Aiwass\Client;
|
||||
namespace RPCii\Client;
|
||||
|
||||
use RuntimeException;
|
||||
use Index\Closeable;
|
||||
|
||||
/**
|
||||
* Provides a common interface for making HTTP requests.
|
||||
*/
|
||||
interface IHttpRequest extends Closeable {
|
||||
interface HttpRequest {
|
||||
/**
|
||||
* Sets whether this is a POST request or a GET request.
|
||||
*
|
73
src/Client/HttpRpcClient.php
Normal file
73
src/Client/HttpRpcClient.php
Normal file
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
// HttpRpcClient.php
|
||||
// Created: 2024-08-13
|
||||
// Updated: 2024-11-13
|
||||
|
||||
namespace RPCii\Client;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use RPCii\{RpciiMsgPack,HmacVerificationProvider,VerificationProvider};
|
||||
|
||||
/**
|
||||
* Implements an RPC client.
|
||||
*/
|
||||
class HttpRpcClient implements RpcClient {
|
||||
/**
|
||||
* @param string $url Base RPC url, up to the /_rpcii part.
|
||||
* @param VerificationProvider $verify A verification provider.
|
||||
* @param callable(): HttpRequest $createRequest Creates a HTTP request.
|
||||
*/
|
||||
public function __construct(
|
||||
private string $url,
|
||||
private VerificationProvider $verify,
|
||||
private $createRequest
|
||||
) {
|
||||
if(!is_callable($createRequest))
|
||||
throw new InvalidArgumentException('$createRequest must be a callable');
|
||||
}
|
||||
|
||||
public function scopeTo(string $prefix): RpcClient {
|
||||
return new ScopedRpcClient($this, $prefix);
|
||||
}
|
||||
|
||||
/** @param array<string, mixed> $params */
|
||||
private function callProcedure(bool $isAction, string $action, array $params): mixed {
|
||||
$params = http_build_query($params, '', '&', PHP_QUERY_RFC3986);
|
||||
|
||||
$request = ($this->createRequest)();
|
||||
$request->setPost($isAction);
|
||||
$request->setUrl(sprintf('%s/_rpcii/%s', $this->url, $action));
|
||||
$request->setHeader('X-RPCii-Verify', $this->verify->sign($isAction, $action, $params));
|
||||
$request->setParams($params);
|
||||
|
||||
return RpciiMsgPack::decode($request->execute());
|
||||
}
|
||||
|
||||
public function query(string $action, array $params): mixed {
|
||||
return $this->callProcedure(false, $action, $params);
|
||||
}
|
||||
|
||||
public function action(string $action, array $params): mixed {
|
||||
return $this->callProcedure(true, $action, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an RPC client with HMAC verification and a suitable HTTP request implementation.
|
||||
*
|
||||
* @param string $url Base RPC url, up to the /_rpcii part.
|
||||
* @param callable(): string $getSecretKey A method that returns the secret key to use.
|
||||
* @return HttpRpcClient An HTTP RPC client!
|
||||
*/
|
||||
public static function createHmac(string $url, $getSecretKey): HttpRpcClient {
|
||||
if(extension_loaded('curl'))
|
||||
$createRequest = fn() => new CurlHttpRequest;
|
||||
else
|
||||
$createRequest = fn() => new StreamHttpRequest;
|
||||
|
||||
return new HttpRpcClient(
|
||||
$url,
|
||||
new HmacVerificationProvider($getSecretKey),
|
||||
$createRequest
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
<?php
|
||||
// IRpcClient.php
|
||||
// Created: 2024-08-16
|
||||
// Updated: 2024-08-16
|
||||
|
||||
namespace Aiwass\Client;
|
||||
|
||||
/**
|
||||
* Provides a common interface for RPC clients.
|
||||
*/
|
||||
interface IRpcClient {
|
||||
/**
|
||||
* Creates a proxy for this RPC client with a specified namespace.
|
||||
*
|
||||
* @param string $prefix Prefix to apply to the scoped RPC client.
|
||||
* @return IRpcClient A scoped RPC client instance.
|
||||
*/
|
||||
function scopeTo(string $prefix): IRpcClient;
|
||||
|
||||
/**
|
||||
* Makes an RPC query.
|
||||
*
|
||||
* @param string $action Name of the action.
|
||||
* @param array<string, mixed> $params Parameters to query with.
|
||||
* @return mixed Result of the query.
|
||||
*/
|
||||
function query(string $action, array $params): mixed;
|
||||
|
||||
/**
|
||||
* Makes an RPC procedure call.
|
||||
*
|
||||
* @param string $action Name of the action.
|
||||
* @param array<string, mixed> $params Parameters to query with.
|
||||
* @return mixed Result of the procedure call.
|
||||
*/
|
||||
function procedure(string $action, array $params): mixed;
|
||||
}
|
|
@ -1,68 +1,37 @@
|
|||
<?php
|
||||
// RpcClient.php
|
||||
// Created: 2024-08-13
|
||||
// Updated: 2024-08-16
|
||||
// Created: 2024-08-16
|
||||
// Updated: 2024-11-13
|
||||
|
||||
namespace Aiwass\Client;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Aiwass\{AiwassMsgPack,HmacVerificationProvider,IVerificationProvider};
|
||||
namespace RPCii\Client;
|
||||
|
||||
/**
|
||||
* Implemens an RPC client.
|
||||
* Provides a common interface for RPC clients.
|
||||
*/
|
||||
class RpcClient implements IRpcClient {
|
||||
interface RpcClient {
|
||||
/**
|
||||
* @param string $url Base RPC url, up to the /_aiwass part.
|
||||
* @param IVerificationProvider $verify A verification provider.
|
||||
* @param callable(): IHttpRequest $createRequest Creates a HTTP request.
|
||||
*/
|
||||
public function __construct(
|
||||
private string $url,
|
||||
private IVerificationProvider $verify,
|
||||
private $createRequest
|
||||
) {
|
||||
if(!is_callable($createRequest))
|
||||
throw new InvalidArgumentException('$createRequest must be a callable');
|
||||
}
|
||||
|
||||
public function scopeTo(string $prefix): IRpcClient {
|
||||
return new RpcClientScoped($this, $prefix);
|
||||
}
|
||||
|
||||
/** @param array<string, mixed> $params */
|
||||
private function callAction(bool $isProcedure, string $action, array $params): mixed {
|
||||
$params = http_build_query($params, '', '&', PHP_QUERY_RFC3986);
|
||||
|
||||
$request = ($this->createRequest)();
|
||||
$request->setPost($isProcedure);
|
||||
$request->setUrl(sprintf('%s/_aiwass/%s', $this->url, $action));
|
||||
$request->setHeader('X-Aiwass-Verify', $this->verify->sign($isProcedure, $action, $params));
|
||||
$request->setParams($params);
|
||||
|
||||
return AiwassMsgPack::decode($request->execute());
|
||||
}
|
||||
|
||||
public function query(string $action, array $params): mixed {
|
||||
return $this->callAction(false, $action, $params);
|
||||
}
|
||||
|
||||
public function procedure(string $action, array $params): mixed {
|
||||
return $this->callAction(true, $action, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an RPC client with HMAC verification and a suitable HTTP request implementation.
|
||||
* Creates a proxy for this RPC client with a specified namespace.
|
||||
*
|
||||
* @param string $url Base RPC url, up to the /_aiwass part.
|
||||
* @param callable(): string $getSecretKey A method that returns the secret key to use.
|
||||
* @return RpcClient An RPC client!
|
||||
* @param string $prefix Prefix to apply to the scoped RPC client.
|
||||
* @return RpcClient A scoped RPC client instance.
|
||||
*/
|
||||
public static function createHmac(string $url, $getSecretKey): RpcClient {
|
||||
return new RpcClient(
|
||||
$url,
|
||||
new HmacVerificationProvider($getSecretKey),
|
||||
fn() => new CurlHttpRequest,
|
||||
);
|
||||
}
|
||||
function scopeTo(string $prefix): RpcClient;
|
||||
|
||||
/**
|
||||
* Makes an RPC query.
|
||||
*
|
||||
* @param string $procedure Name of the procedure.
|
||||
* @param array<string, mixed> $params Parameters to query with.
|
||||
* @return mixed Result of the query.
|
||||
*/
|
||||
function query(string $procedure, array $params): mixed;
|
||||
|
||||
/**
|
||||
* Makes an RPC action call.
|
||||
*
|
||||
* @param string $procedure Name of the procedure.
|
||||
* @param array<string, mixed> $params Parameters to query with.
|
||||
* @return mixed Result of the procedure call.
|
||||
*/
|
||||
function action(string $procedure, array $params): mixed;
|
||||
}
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
<?php
|
||||
// RpcClientScoped.php
|
||||
// Created: 2024-08-16
|
||||
// Updated: 2024-08-16
|
||||
|
||||
namespace Aiwass\Client;
|
||||
|
||||
/**
|
||||
* Provides a scoped interface to an underlying RPC client.
|
||||
*/
|
||||
class RpcClientScoped implements IRpcClient {
|
||||
/**
|
||||
* @param IRpcClient $base RPC client instance to use as a base.
|
||||
* @param string $prefix Prefix to apply to action names passed.
|
||||
*/
|
||||
public function __construct(
|
||||
private IRpcClient $base,
|
||||
private string $prefix
|
||||
) {}
|
||||
|
||||
public function scopeTo(string $prefix): IRpcClient {
|
||||
return $this->base->scopeTo($this->prefix . $prefix);
|
||||
}
|
||||
|
||||
public function query(string $action, array $params): mixed {
|
||||
return $this->base->query($this->prefix . $action, $params);
|
||||
}
|
||||
|
||||
public function procedure(string $action, array $params): mixed {
|
||||
return $this->base->procedure($this->prefix . $action, $params);
|
||||
}
|
||||
}
|
32
src/Client/ScopedRpcClient.php
Normal file
32
src/Client/ScopedRpcClient.php
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
// ScopedRpcClient.php
|
||||
// Created: 2024-08-16
|
||||
// Updated: 2024-11-13
|
||||
|
||||
namespace RPCii\Client;
|
||||
|
||||
/**
|
||||
* Provides a scoped interface to an underlying RPC client.
|
||||
*/
|
||||
class ScopedRpcClient implements RpcClient {
|
||||
/**
|
||||
* @param RpcClient $base RPC client instance to use as a base.
|
||||
* @param string $prefix Prefix to apply to procedure names passed.
|
||||
*/
|
||||
public function __construct(
|
||||
private RpcClient $base,
|
||||
private string $prefix
|
||||
) {}
|
||||
|
||||
public function scopeTo(string $prefix): RpcClient {
|
||||
return $this->base->scopeTo($this->prefix . $prefix);
|
||||
}
|
||||
|
||||
public function query(string $procedure, array $params): mixed {
|
||||
return $this->base->query($this->prefix . $procedure, $params);
|
||||
}
|
||||
|
||||
public function action(string $procedure, array $params): mixed {
|
||||
return $this->base->action($this->prefix . $procedure, $params);
|
||||
}
|
||||
}
|
75
src/Client/StreamHttpRequest.php
Normal file
75
src/Client/StreamHttpRequest.php
Normal file
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
// StreamHttpRequest.php
|
||||
// Created: 2024-11-13
|
||||
// Updated: 2024-11-13
|
||||
|
||||
namespace RPCii\Client;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Provides a PHP Stream based HTTP request implementation.
|
||||
*/
|
||||
class StreamHttpRequest implements HttpRequest {
|
||||
private bool $isPost = false;
|
||||
private ?string $url = null;
|
||||
/** @var string[] */
|
||||
private array $headers = [];
|
||||
private string $paramString = '';
|
||||
|
||||
public function setPost(bool $state): void {
|
||||
$this->isPost = $state;
|
||||
}
|
||||
|
||||
public function setUrl(string $url): void {
|
||||
$this->url = $url;
|
||||
}
|
||||
|
||||
public function setHeader(string $name, string $value): void {
|
||||
$this->headers[] = sprintf('%s: %s', $name, $value);
|
||||
}
|
||||
|
||||
public function setParams(string $paramString): void {
|
||||
$this->paramString = $paramString;
|
||||
}
|
||||
|
||||
public function execute(): string {
|
||||
$url = $this->url;
|
||||
if($url === null)
|
||||
throw new RuntimeException('no target url specified');
|
||||
|
||||
$ctx = [];
|
||||
|
||||
if($this->isPost) {
|
||||
$ctx['method'] = 'POST';
|
||||
$this->setHeader('Content-Type', 'application/x-www-form-urlencoded');
|
||||
$ctx['content'] = $this->paramString;
|
||||
} else {
|
||||
$ctx['method'] = 'GET';
|
||||
$url .= str_contains($url, '?') ? '&' : '?';
|
||||
$url .= $this->paramString;
|
||||
}
|
||||
|
||||
$ctx['header'] = implode("\r\n", $this->headers);
|
||||
|
||||
$ctx = stream_context_create(['http' => $ctx]);
|
||||
$handle = fopen($url, 'rb', context: $ctx);
|
||||
if($handle === false)
|
||||
throw new RuntimeException('failed to create HTTP request');
|
||||
|
||||
$response = stream_get_contents($handle);
|
||||
if($response === false)
|
||||
throw new RuntimeException('failed to read response body');
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Stream HTTP Request instance.
|
||||
*
|
||||
* @return StreamHttpRequest File HTTP Request.
|
||||
*/
|
||||
public static function create(): StreamHttpRequest {
|
||||
return new StreamHttpRequest;
|
||||
}
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
<?php
|
||||
// HmacVerificationProvider.php
|
||||
// Created: 2024-08-13
|
||||
// Updated: 2024-08-13
|
||||
// Updated: 2024-11-13
|
||||
|
||||
namespace Aiwass;
|
||||
namespace RPCii;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Index\UriBase64;
|
||||
|
@ -11,7 +11,7 @@ use Index\UriBase64;
|
|||
/**
|
||||
* Implements an HMAC verification provider.
|
||||
*/
|
||||
class HmacVerificationProvider implements IVerificationProvider {
|
||||
class HmacVerificationProvider implements VerificationProvider {
|
||||
/**
|
||||
* Default list of allowed algorithms.
|
||||
*
|
||||
|
@ -49,15 +49,15 @@ class HmacVerificationProvider implements IVerificationProvider {
|
|||
throw new InvalidArgumentException('$timeValidPlusMinusSeconds must be greater than zero');
|
||||
}
|
||||
|
||||
public function sign(bool $isProcedure, string $action, string $paramString): string {
|
||||
return $this->signWith($this->algos[0], $isProcedure, $action, $paramString);
|
||||
public function sign(bool $isAction, string $action, string $paramString): string {
|
||||
return $this->signWith($this->algos[0], $isAction, $action, $paramString);
|
||||
}
|
||||
|
||||
private function signWith(string $algo, bool $isProcedure, string $action, string $paramString): string {
|
||||
private function signWith(string $algo, bool $isAction, string $action, string $paramString): string {
|
||||
$time = time();
|
||||
$hash = $this->createHash($algo, $time, $isProcedure, $action, $paramString);
|
||||
$hash = $this->createHash($algo, $time, $isAction, $action, $paramString);
|
||||
|
||||
return UriBase64::encode(AiwassMsgPack::encode([
|
||||
return UriBase64::encode(RpciiMsgPack::encode([
|
||||
'a' => $algo,
|
||||
't' => $time,
|
||||
'h' => $hash,
|
||||
|
@ -67,14 +67,14 @@ class HmacVerificationProvider implements IVerificationProvider {
|
|||
private function createHash(
|
||||
string $algo,
|
||||
int $timeStamp,
|
||||
bool $isProcedure,
|
||||
bool $isAction,
|
||||
string $action,
|
||||
string $paramString
|
||||
): string {
|
||||
$data = sprintf(
|
||||
'^<=>%d<=>%s<=>%s<=>%s<=>$',
|
||||
$timeStamp,
|
||||
$isProcedure ? 'p' : 'q',
|
||||
$isAction ? 'a' : 'q',
|
||||
$action,
|
||||
$paramString
|
||||
);
|
||||
|
@ -92,12 +92,12 @@ class HmacVerificationProvider implements IVerificationProvider {
|
|||
return in_array($algo, $this->algos);
|
||||
}
|
||||
|
||||
public function verify(string $userToken, bool $isProcedure, string $action, string $paramString): bool {
|
||||
public function verify(string $userToken, bool $isAction, string $action, string $paramString): bool {
|
||||
$userToken = UriBase64::decode($userToken);
|
||||
if($userToken === false)
|
||||
return false;
|
||||
|
||||
$userTokenInfo = AiwassMsgPack::decode($userToken);
|
||||
$userTokenInfo = RpciiMsgPack::decode($userToken);
|
||||
if(!is_array($userTokenInfo))
|
||||
return false;
|
||||
|
||||
|
@ -114,7 +114,7 @@ class HmacVerificationProvider implements IVerificationProvider {
|
|||
if(!is_string($userHash))
|
||||
return false;
|
||||
|
||||
$realHash = $this->createHash($userAlgo, $userTime, $isProcedure, $action, $paramString);
|
||||
$realHash = $this->createHash($userAlgo, $userTime, $isAction, $action, $paramString);
|
||||
return hash_equals($realHash, $userHash);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
<?php
|
||||
// Aiwass.php
|
||||
// RPCii.php
|
||||
// Created: 2024-08-13
|
||||
// Updated: 2024-08-13
|
||||
// Updated: 2024-11-13
|
||||
|
||||
namespace Aiwass;
|
||||
namespace RPCii;
|
||||
|
||||
/**
|
||||
* Provides information about the Aiwass library.
|
||||
* Provides information about the RPCii library.
|
||||
*/
|
||||
final class Aiwass {
|
||||
final class RPCii {
|
||||
public const PATH_SOURCE = __DIR__;
|
||||
public const PATH_ROOT = self::PATH_SOURCE . DIRECTORY_SEPARATOR . '..';
|
||||
public const PATH_VERSION = self::PATH_ROOT . DIRECTORY_SEPARATOR . 'VERSION';
|
||||
|
||||
/**
|
||||
* Gets the current version of the Aiwass library.
|
||||
* Gets the current version of the RPCii library.
|
||||
*
|
||||
* Reads the VERSION file in the root of the Aiwass directory.
|
||||
* Reads the VERSION file in the root of the RPCii directory.
|
||||
* Returns 0.0.0 if reading the file failed for any reason.
|
||||
*
|
||||
* @return string Current version string.
|
|
@ -1,9 +1,9 @@
|
|||
<?php
|
||||
// AiwassMsgPack.php
|
||||
// RpciiMsgPack.php
|
||||
// Created: 2024-08-13
|
||||
// Updated: 2024-08-13
|
||||
// Updated: 2024-11-13
|
||||
|
||||
namespace Aiwass;
|
||||
namespace RPCii;
|
||||
|
||||
use MessagePack;
|
||||
|
||||
|
@ -12,7 +12,7 @@ use MessagePack;
|
|||
*
|
||||
* @internal
|
||||
*/
|
||||
final class AiwassMsgPack {
|
||||
final class RpciiMsgPack {
|
||||
private static MessagePack $msgpack;
|
||||
|
||||
public static function encode(mixed $value): string {
|
||||
|
@ -29,4 +29,4 @@ final class AiwassMsgPack {
|
|||
}
|
||||
}
|
||||
|
||||
AiwassMsgPack::init();
|
||||
RpciiMsgPack::init();
|
45
src/Server/HttpRpcServer.php
Normal file
45
src/Server/HttpRpcServer.php
Normal file
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
// HttpRpcServer.php
|
||||
// Created: 2024-08-13
|
||||
// Updated: 2024-11-13
|
||||
|
||||
namespace RPCii\Server;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use RPCii\VerificationProvider;
|
||||
|
||||
/**
|
||||
* Implements an RPC server.
|
||||
*/
|
||||
class HttpRpcServer implements RpcServer {
|
||||
use RpcServerCommon;
|
||||
|
||||
/** @var array<string, RpcProcedureInfo> */
|
||||
private array $procedures = [];
|
||||
|
||||
/**
|
||||
* Creates an RPC route handler.
|
||||
*
|
||||
* @param VerificationProvider $verification A verification provider.
|
||||
* @return RpcRouteHandler RPC route handler.
|
||||
*/
|
||||
public function createRouteHandler(VerificationProvider $verification): RpcRouteHandler {
|
||||
return new RpcRouteHandler($this, $verification);
|
||||
}
|
||||
|
||||
public function scopeTo(string $prefix): RpcServer {
|
||||
return new ScopedRpcServer($this, $prefix);
|
||||
}
|
||||
|
||||
public function registerProcedure(bool $isAction, string $name, $handler): void {
|
||||
if(array_key_exists($name, $this->procedures))
|
||||
throw new RuntimeException('an procedure with that name has already been registered');
|
||||
|
||||
$this->procedures[$name] = new RpcProcedureInfo($isAction, $name, $handler);
|
||||
}
|
||||
|
||||
public function getProcedureInfo(string $name): ?RpcProcedureInfo {
|
||||
return $this->procedures[$name] ?? null;
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
<?php
|
||||
// IRpcActionHandler.php
|
||||
// Created: 2024-08-15
|
||||
// Updated: 2024-08-16
|
||||
|
||||
namespace Aiwass\Server;
|
||||
|
||||
/**
|
||||
* Provides the interface for IRpcServer::register().
|
||||
*/
|
||||
interface IRpcActionHandler {
|
||||
/**
|
||||
* Registers axctions on a given IRpcServer instance.
|
||||
*
|
||||
* @param IRpcServer $server Target RPC server.
|
||||
*/
|
||||
public function registerRpcActions(IRpcServer $server): void;
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
<?php
|
||||
// IRpcServer.php
|
||||
// Created: 2024-08-16
|
||||
// Updated: 2024-08-16
|
||||
|
||||
namespace Aiwass\Server;
|
||||
|
||||
use RuntimeException;
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Provides a common interface for RPC servers.
|
||||
*/
|
||||
interface IRpcServer {
|
||||
/**
|
||||
* Creates a proxy for this RPC server with a specified namespace.
|
||||
*
|
||||
* @param string $prefix Prefix to apply to the scoped RPC server.
|
||||
* @return IRpcServer A scoped RPC server instance.
|
||||
*/
|
||||
function scopeTo(string $prefix): IRpcServer;
|
||||
|
||||
/**
|
||||
* Registers a handler class.
|
||||
*
|
||||
* @param IRpcActionHandler $handler Handler to register.
|
||||
*/
|
||||
function register(IRpcActionHandler $handler): void;
|
||||
|
||||
/**
|
||||
* Registers an action.
|
||||
*
|
||||
* @param bool $isProcedure true if the action is a procedure (HTTP POST), false if it is a query (HTTP GET).
|
||||
* @param string $name Unique name of the action.
|
||||
* @param callable $handler Handler for the action.
|
||||
* @throws RuntimeException If a handler with the same name is already registered.
|
||||
* @throws InvalidArgumentException If $handler is not a callable type.
|
||||
*/
|
||||
function registerAction(bool $isProcedure, string $name, $handler): void;
|
||||
|
||||
/**
|
||||
* Registers a query action (HTTP GET).
|
||||
*
|
||||
* @param string $name Unique name of the action.
|
||||
* @param callable $handler Handler for the action.
|
||||
* @throws RuntimeException If a handler with the same name is already registered.
|
||||
* @throws InvalidArgumentException If $handler is not a callable type.
|
||||
*/
|
||||
function registerQueryAction(string $name, $handler): void;
|
||||
|
||||
/**
|
||||
* Registers a procedure action (HTTP POST).
|
||||
*
|
||||
* @param string $name Unique name of the action.
|
||||
* @param callable $handler Handler for the action.
|
||||
* @throws RuntimeException If a handler with the same name is already registered.
|
||||
* @throws InvalidArgumentException If $handler is not a callable type.
|
||||
*/
|
||||
function registerProcedureAction(string $name, $handler): void;
|
||||
|
||||
/**
|
||||
* Retrieves information about an action.
|
||||
*
|
||||
* @param string $name Name of the action.
|
||||
* @return ?RpcActionInfo An object containing information about the action, or null if it does not exist.
|
||||
*/
|
||||
function getActionInfo(string $name): ?RpcActionInfo;
|
||||
}
|
|
@ -1,67 +1,21 @@
|
|||
<?php
|
||||
// RpcAction.php
|
||||
// Created: 2024-08-15
|
||||
// Updated: 2024-08-16
|
||||
// Updated: 2024-11-13
|
||||
|
||||
namespace Aiwass\Server;
|
||||
namespace RPCii\Server;
|
||||
|
||||
use Attribute;
|
||||
use ReflectionAttribute;
|
||||
use ReflectionObject;
|
||||
|
||||
/**
|
||||
* Provides base for attributes that mark methods in a class as RPC action handlers.
|
||||
* Provides an attribute for marking methods in a class as an RPC Action procedure.
|
||||
*/
|
||||
#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
|
||||
class RpcAction {
|
||||
class RpcAction extends RpcProcedure {
|
||||
/**
|
||||
* @param bool $isProcedure true if the action is a procedure, false if query.
|
||||
* @param string $name Action name.
|
||||
* @param string $name Procedure name.
|
||||
*/
|
||||
public function __construct(
|
||||
private bool $isProcedure,
|
||||
private string $name
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Returns whether the action is a procedure.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isProcedure(): bool {
|
||||
return $this->isProcedure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the action name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads attributes from methods in a IRpcActionHandler instance and registers them to a given IRpcServer instance.
|
||||
*
|
||||
* @param IRpcServer $server RPC server instance.
|
||||
* @param IRpcActionHandler $handler Handler instance.
|
||||
*/
|
||||
public static function register(IRpcServer $server, IRpcActionHandler $handler): void {
|
||||
$objectInfo = new ReflectionObject($handler);
|
||||
$methodInfos = $objectInfo->getMethods();
|
||||
|
||||
foreach($methodInfos as $methodInfo) {
|
||||
$attrInfos = $methodInfo->getAttributes(RpcAction::class, ReflectionAttribute::IS_INSTANCEOF);
|
||||
|
||||
foreach($attrInfos as $attrInfo) {
|
||||
$handlerInfo = $attrInfo->newInstance();
|
||||
$server->registerAction(
|
||||
$handlerInfo->isProcedure(),
|
||||
$handlerInfo->getName(),
|
||||
$methodInfo->getClosure($methodInfo->isStatic() ? null : $handler)
|
||||
);
|
||||
}
|
||||
}
|
||||
public function __construct(string $name) {
|
||||
parent::__construct(true, $name);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
<?php
|
||||
// RpcActionHandler.php
|
||||
// Created: 2024-08-15
|
||||
// Updated: 2024-08-16
|
||||
|
||||
namespace Aiwass\Server;
|
||||
|
||||
/**
|
||||
* Provides an abstract class version of IRpcActionHandler that already includes the trait as well,
|
||||
* letting you only have to use one use statement rather than two!
|
||||
*/
|
||||
abstract class RpcActionHandler implements IRpcActionHandler {
|
||||
use RpcActionHandlerTrait;
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
<?php
|
||||
// RpcActionHandlerTrait.php
|
||||
// Created: 2024-08-15
|
||||
// Updated: 2024-08-16
|
||||
|
||||
namespace Aiwass\Server;
|
||||
|
||||
/**
|
||||
* Provides an implementation of IRpcActionHandler::registerRpcActions that uses the attributes.
|
||||
* For more advanced use, everything can be use'd separately and RpcActionAttribute::register called manually.
|
||||
*/
|
||||
trait RpcActionHandlerTrait {
|
||||
public function registerRpcActions(IRpcServer $server): void {
|
||||
RpcAction::register($server, $this);
|
||||
}
|
||||
}
|
18
src/Server/RpcHandler.php
Normal file
18
src/Server/RpcHandler.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
// RpcHandler.php
|
||||
// Created: 2024-08-15
|
||||
// Updated: 2024-11-13
|
||||
|
||||
namespace RPCii\Server;
|
||||
|
||||
/**
|
||||
* Provides the interface for RpcServer::register().
|
||||
*/
|
||||
interface RpcHandler {
|
||||
/**
|
||||
* Registers procedures to a given RpcServer instance.
|
||||
*
|
||||
* @param RpcServer $server Target RPC server.
|
||||
*/
|
||||
function registerProcedures(RpcServer $server): void;
|
||||
}
|
16
src/Server/RpcHandlerCommon.php
Normal file
16
src/Server/RpcHandlerCommon.php
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
// RpcHandlerCommon.php
|
||||
// Created: 2024-08-15
|
||||
// Updated: 2024-11-13
|
||||
|
||||
namespace RPCii\Server;
|
||||
|
||||
/**
|
||||
* Provides an implementation of RpcHandler::registerProcedures that uses the attributes.
|
||||
* For more advanced use, everything can be use'd separately and RpcProcedure::register called manually.
|
||||
*/
|
||||
trait RpcHandlerCommon {
|
||||
public function registerProcedures(RpcServer $server): void {
|
||||
RpcProcedure::register($server, $this);
|
||||
}
|
||||
}
|
|
@ -1,21 +1,67 @@
|
|||
<?php
|
||||
// RpcProcedure.php
|
||||
// Created: 2024-08-15
|
||||
// Updated: 2024-08-16
|
||||
// Updated: 2024-11-13
|
||||
|
||||
namespace Aiwass\Server;
|
||||
namespace RPCii\Server;
|
||||
|
||||
use Attribute;
|
||||
use ReflectionAttribute;
|
||||
use ReflectionObject;
|
||||
|
||||
/**
|
||||
* Provides an attribute for marking methods in a class as an RPC Query action.
|
||||
* Provides base for attributes that mark methods in a class as RPC procedure handlers.
|
||||
*/
|
||||
#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
|
||||
class RpcProcedure extends RpcAction {
|
||||
class RpcProcedure {
|
||||
/**
|
||||
* @param bool $isAction true if the procedure is an action, false if query.
|
||||
* @param string $name Action name.
|
||||
*/
|
||||
public function __construct(string $name) {
|
||||
parent::__construct(true, $name);
|
||||
public function __construct(
|
||||
private bool $isAction,
|
||||
private string $name
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Returns whether the procedure is an action.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isAction(): bool {
|
||||
return $this->isAction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the procedure name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads attributes from methods in a RpcHandler instance and registers them to a given RpcServer instance.
|
||||
*
|
||||
* @param RpcServer $server RPC server instance.
|
||||
* @param RpcHandler $handler Handler instance.
|
||||
*/
|
||||
public static function register(RpcServer $server, RpcHandler $handler): void {
|
||||
$objectInfo = new ReflectionObject($handler);
|
||||
$methodInfos = $objectInfo->getMethods();
|
||||
|
||||
foreach($methodInfos as $methodInfo) {
|
||||
$attrInfos = $methodInfo->getAttributes(RpcProcedure::class, ReflectionAttribute::IS_INSTANCEOF);
|
||||
|
||||
foreach($attrInfos as $attrInfo) {
|
||||
$handlerInfo = $attrInfo->newInstance();
|
||||
$server->registerProcedure(
|
||||
$handlerInfo->isAction(),
|
||||
$handlerInfo->getName(),
|
||||
$methodInfo->getClosure($methodInfo->isStatic() ? null : $handler)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<?php
|
||||
// RpcActionInfo.php
|
||||
// RpcProcedureInfo.php
|
||||
// Created: 2024-08-13
|
||||
// Updated: 2024-08-16
|
||||
// Updated: 2024-11-13
|
||||
|
||||
namespace Aiwass\Server;
|
||||
namespace RPCii\Server;
|
||||
|
||||
use Closure;
|
||||
use InvalidArgumentException;
|
||||
|
@ -11,17 +11,17 @@ use ReflectionFunction;
|
|||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Provides information about an RPC action.
|
||||
* Provides information about an RPC procedure.
|
||||
*/
|
||||
final class RpcActionInfo {
|
||||
final class RpcProcedureInfo {
|
||||
/**
|
||||
* @param bool $isProcedure Whether this action is a procedure (true) or a query (false).
|
||||
* @param string $name Name of the action.
|
||||
* @param callable $handler Handler for the action.
|
||||
* @param bool $isAction Whether this procedure is an action (true) or a query (false).
|
||||
* @param string $name Name of the procedure.
|
||||
* @param callable $handler Handler for the procedure.
|
||||
* @throws InvalidArgumentException If $handler is not a callable type.
|
||||
*/
|
||||
public function __construct(
|
||||
private bool $isProcedure,
|
||||
private bool $isAction,
|
||||
private string $name,
|
||||
private $handler
|
||||
) {
|
||||
|
@ -32,27 +32,27 @@ final class RpcActionInfo {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns whether the action is a procedure.
|
||||
* Returns whether the procedure is an action.
|
||||
*
|
||||
* @return bool true if the action is a procedure, false if it is a query.
|
||||
* @return bool true if the procedure is an action, false if it is a query.
|
||||
*/
|
||||
public function isProcedure(): bool {
|
||||
return $this->isProcedure;
|
||||
public function isAction(): bool {
|
||||
return $this->isAction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this action.
|
||||
* Returns the name of this procedure.
|
||||
*
|
||||
* @return string Name of the action.
|
||||
* @return string Name of the procedure.
|
||||
*/
|
||||
public function getName(): string {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the handler for this action.
|
||||
* Returns the handler for this procedure.
|
||||
*
|
||||
* @return Closure Handler for this action.
|
||||
* @return Closure Handler for this procedure.
|
||||
*/
|
||||
public function getHandler(): Closure {
|
||||
return Closure::fromCallable($this->handler);
|
|
@ -1,19 +1,19 @@
|
|||
<?php
|
||||
// RpcQuery.php
|
||||
// Created: 2024-08-15
|
||||
// Updated: 2024-08-16
|
||||
// Updated: 2024-11-13
|
||||
|
||||
namespace Aiwass\Server;
|
||||
namespace RPCii\Server;
|
||||
|
||||
use Attribute;
|
||||
|
||||
/**
|
||||
* Provides an attribute for marking methods in a class as an RPC Query action.
|
||||
* Provides an attribute for marking methods in a class as an RPC Query procedure.
|
||||
*/
|
||||
#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
|
||||
class RpcQuery extends RpcAction {
|
||||
class RpcQuery extends RpcProcedure {
|
||||
/**
|
||||
* @param string $name Action name.
|
||||
* @param string $name Procedure name.
|
||||
*/
|
||||
public function __construct(string $name) {
|
||||
parent::__construct(false, $name);
|
||||
|
|
|
@ -1,44 +1,44 @@
|
|||
<?php
|
||||
// RpcRouteHandler.php
|
||||
// Created: 2024-08-13
|
||||
// Updated: 2024-10-05
|
||||
// Updated: 2024-11-13
|
||||
|
||||
namespace Aiwass\Server;
|
||||
namespace RPCii\Server;
|
||||
|
||||
use Exception;
|
||||
use RuntimeException;
|
||||
use Aiwass\{AiwassMsgPack,IVerificationProvider};
|
||||
use RPCii\{RpciiMsgPack,VerificationProvider};
|
||||
use Index\Http\{HttpResponseBuilder,HttpRequest};
|
||||
use Index\Http\FormHttpContent;
|
||||
use Index\Http\Routing\{HttpGet,HttpPost,RouteHandler,RouteHandlerTrait};
|
||||
|
||||
/**
|
||||
* Provides a router implementation for an Aiwass RPC server.
|
||||
* Provides a router implementation for an RPCii RPC server.
|
||||
*/
|
||||
class RpcRouteHandler implements RouteHandler {
|
||||
use RouteHandlerTrait;
|
||||
|
||||
/**
|
||||
* @param IRpcServer $server An RPC server instance.
|
||||
* @param IVerificationProvider $verification A verification provider instance.
|
||||
* @param RpcServer $server An RPC server instance.
|
||||
* @param VerificationProvider $verification A verification provider instance.
|
||||
*/
|
||||
public function __construct(
|
||||
private IRpcServer $server,
|
||||
private IVerificationProvider $verification
|
||||
private RpcServer $server,
|
||||
private VerificationProvider $verification
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Handles an action request.
|
||||
* Handles a procedure request.
|
||||
*
|
||||
* @param HttpResponseBuilder $response Response that it being built.
|
||||
* @param HttpRequest $request Request that is being handled.
|
||||
* @param string $action Name of the action specified in the URL.
|
||||
* @param string $procedure Name of the procedure specified in the URL.
|
||||
* @return int|string Response to the request.
|
||||
*/
|
||||
#[HttpGet('/_aiwass/([A-Za-z0-9\-_\.:]+)')]
|
||||
#[HttpPost('/_aiwass/([A-Za-z0-9\-_\.:]+)')]
|
||||
public function handleAction(HttpResponseBuilder $response, HttpRequest $request, string $action) {
|
||||
if($action === '')
|
||||
#[HttpGet('/_rpcii/([A-Za-z0-9\-_\.:]+)')]
|
||||
#[HttpPost('/_rpcii/([A-Za-z0-9\-_\.:]+)')]
|
||||
public function handleProcedure(HttpResponseBuilder $response, HttpRequest $request, string $procedure) {
|
||||
if($procedure === '')
|
||||
return 404;
|
||||
|
||||
if($request->getMethod() === 'POST') {
|
||||
|
@ -46,11 +46,11 @@ class RpcRouteHandler implements RouteHandler {
|
|||
if(!($content instanceof FormHttpContent))
|
||||
return 400;
|
||||
|
||||
$expectProcedure = true;
|
||||
$expectAction = true;
|
||||
$paramString = $content->getParamString();
|
||||
$params = $content->getParams();
|
||||
} elseif($request->getMethod() === 'GET') {
|
||||
$expectProcedure = false;
|
||||
$expectAction = false;
|
||||
$paramString = $request->getParamString();
|
||||
$params = $request->getParams();
|
||||
} else {
|
||||
|
@ -60,32 +60,32 @@ class RpcRouteHandler implements RouteHandler {
|
|||
|
||||
$response->setContentType('application/vnd.msgpack');
|
||||
|
||||
$userToken = (string)$request->getHeaderLine('X-Aiwass-Verify');
|
||||
$userToken = (string)$request->getHeaderLine('X-RPCii-Verify');
|
||||
if($userToken === '') {
|
||||
$response->setStatusCode(403);
|
||||
return AiwassMsgPack::encode(['error' => 'aiwass:verify']);
|
||||
return RpciiMsgPack::encode(['error' => 'rpcii:verify']);
|
||||
}
|
||||
|
||||
$actInfo = $this->server->getActionInfo($action);
|
||||
if($actInfo === null) {
|
||||
$procInfo = $this->server->getProcedureInfo($procedure);
|
||||
if($procInfo === null) {
|
||||
$response->setStatusCode(404);
|
||||
return AiwassMsgPack::encode(['error' => 'aiwass:unknown']);
|
||||
return RpciiMsgPack::encode(['error' => 'rpcii:unknown']);
|
||||
}
|
||||
|
||||
if($actInfo->isProcedure() !== $expectProcedure) {
|
||||
if($procInfo->isAction() !== $expectAction) {
|
||||
$response->setStatusCode(405);
|
||||
$response->setHeader('Allow', $actInfo->isProcedure() ? 'POST' : 'GET');
|
||||
return AiwassMsgPack::encode(['error' => 'aiwass:method']);
|
||||
$response->setHeader('Allow', $procInfo->isAction() ? 'POST' : 'GET');
|
||||
return RpciiMsgPack::encode(['error' => 'rpcii:method']);
|
||||
}
|
||||
|
||||
if(!$this->verification->verify($userToken, $expectProcedure, $action, $paramString))
|
||||
return AiwassMsgPack::encode(['error' => 'aiwass:verify']);
|
||||
if(!$this->verification->verify($userToken, $expectAction, $procedure, $paramString))
|
||||
return RpciiMsgPack::encode(['error' => 'rpcii:verify']);
|
||||
|
||||
try {
|
||||
return AiwassMsgPack::encode($actInfo->invokeHandler($params));
|
||||
return RpciiMsgPack::encode($procInfo->invokeHandler($params));
|
||||
} catch(RuntimeException $ex) {
|
||||
$response->setStatusCode(400);
|
||||
return AiwassMsgPack::encode(['error' => sprintf('aiwass:%s', $ex->getMessage())]);
|
||||
return RpciiMsgPack::encode(['error' => sprintf('rpcii:%s', $ex->getMessage())]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,45 +1,68 @@
|
|||
<?php
|
||||
// RpcServer.php
|
||||
// Created: 2024-08-13
|
||||
// Updated: 2024-08-16
|
||||
// Created: 2024-08-16
|
||||
// Updated: 2024-11-13
|
||||
|
||||
namespace Aiwass\Server;
|
||||
namespace RPCii\Server;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use Aiwass\IVerificationProvider;
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Implements an RPC server.
|
||||
* Provides a common interface for RPC servers.
|
||||
*/
|
||||
class RpcServer implements IRpcServer {
|
||||
use RpcServerTrait;
|
||||
|
||||
/** @var array<string, RpcActionInfo> */
|
||||
private array $actions = [];
|
||||
|
||||
interface RpcServer {
|
||||
/**
|
||||
* Creates an RPC route handler.
|
||||
* Creates a proxy for this RPC server with a specified namespace.
|
||||
*
|
||||
* @param IVerificationProvider $verification A verification provider.
|
||||
* @return RpcRouteHandler RPC route handler.
|
||||
* @param string $prefix Prefix to apply to the scoped RPC server.
|
||||
* @return RpcServer A scoped RPC server instance.
|
||||
*/
|
||||
public function createRouteHandler(IVerificationProvider $verification): RpcRouteHandler {
|
||||
return new RpcRouteHandler($this, $verification);
|
||||
}
|
||||
function scopeTo(string $prefix): RpcServer;
|
||||
|
||||
public function scopeTo(string $prefix): IRpcServer {
|
||||
return new RpcServerScoped($this, $prefix);
|
||||
}
|
||||
/**
|
||||
* Registers a handler class.
|
||||
*
|
||||
* @param RpcHandler $handler Handler to register.
|
||||
*/
|
||||
function register(RpcHandler $handler): void;
|
||||
|
||||
public function registerAction(bool $isProcedure, string $name, $handler): void {
|
||||
if(array_key_exists($name, $this->actions))
|
||||
throw new RuntimeException('an action with that name has already been registered');
|
||||
/**
|
||||
* Registers a procedure.
|
||||
*
|
||||
* @param bool $isAction true if the procedure is an action (HTTP POST), false if it is a query (HTTP GET).
|
||||
* @param string $name Unique name of the procedure.
|
||||
* @param callable $handler Handler for the procedure.
|
||||
* @throws RuntimeException If a handler with the same name is already registered.
|
||||
* @throws InvalidArgumentException If $handler is not a callable type.
|
||||
*/
|
||||
function registerProcedure(bool $isAction, string $name, $handler): void;
|
||||
|
||||
$this->actions[$name] = new RpcActionInfo($isProcedure, $name, $handler);
|
||||
}
|
||||
/**
|
||||
* Registers a query procedure (HTTP GET).
|
||||
*
|
||||
* @param string $name Unique name of the procedure.
|
||||
* @param callable $handler Handler for the procedure.
|
||||
* @throws RuntimeException If a handler with the same name is already registered.
|
||||
* @throws InvalidArgumentException If $handler is not a callable type.
|
||||
*/
|
||||
function registerQueryProcedure(string $name, $handler): void;
|
||||
|
||||
public function getActionInfo(string $name): ?RpcActionInfo {
|
||||
return $this->actions[$name] ?? null;
|
||||
}
|
||||
/**
|
||||
* Registers an action procedure (HTTP POST).
|
||||
*
|
||||
* @param string $name Unique name of the procedure.
|
||||
* @param callable $handler Handler for the procedure.
|
||||
* @throws RuntimeException If a handler with the same name is already registered.
|
||||
* @throws InvalidArgumentException If $handler is not a callable type.
|
||||
*/
|
||||
function registerActionProcedure(string $name, $handler): void;
|
||||
|
||||
/**
|
||||
* Retrieves information about an procedure.
|
||||
*
|
||||
* @param string $name Name of the procedure.
|
||||
* @return ?RpcProcedureInfo An object containing information about the procedure, or null if it does not exist.
|
||||
*/
|
||||
function getProcedureInfo(string $name): ?RpcProcedureInfo;
|
||||
}
|
||||
|
|
23
src/Server/RpcServerCommon.php
Normal file
23
src/Server/RpcServerCommon.php
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
// RpcServerCommon.php
|
||||
// Created: 2024-08-16
|
||||
// Updated: 2024-11-13
|
||||
|
||||
namespace RPCii\Server;
|
||||
|
||||
/**
|
||||
* Provides implementations for RpcServer methods that are likely going to be identical across implementations.
|
||||
*/
|
||||
trait RpcServerCommon {
|
||||
public function register(RpcHandler $handler): void {
|
||||
$handler->registerProcedures($this);
|
||||
}
|
||||
|
||||
public function registerQueryProcedure(string $name, $handler): void {
|
||||
$this->registerProcedure(false, $name, $handler);
|
||||
}
|
||||
|
||||
public function registerActionProcedure(string $name, $handler): void {
|
||||
$this->registerProcedure(true, $name, $handler);
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
<?php
|
||||
// RpcServerScoped.php
|
||||
// Created: 2024-08-16
|
||||
// Updated: 2024-08-16
|
||||
|
||||
namespace Aiwass\Server;
|
||||
|
||||
/**
|
||||
* Provides a scoped RPC server implementation.
|
||||
*/
|
||||
class RpcServerScoped implements IRpcServer {
|
||||
use RpcServerTrait;
|
||||
|
||||
/**
|
||||
* @param IRpcServer $base RPC server instance to use as a base.
|
||||
* @param string $prefix Prefix to apply to action names passed.
|
||||
*/
|
||||
public function __construct(
|
||||
private IRpcServer $base,
|
||||
private string $prefix
|
||||
) {}
|
||||
|
||||
public function scopeTo(string $prefix): IRpcServer {
|
||||
return $this->base->scopeTo($this->prefix . $prefix);
|
||||
}
|
||||
|
||||
public function registerAction(bool $isProcedure, string $name, $handler): void {
|
||||
$this->base->registerAction($isProcedure, $this->prefix . $name, $handler);
|
||||
}
|
||||
|
||||
public function getActionInfo(string $name): ?RpcActionInfo {
|
||||
return $this->base->getActionInfo($this->prefix . $name);
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
<?php
|
||||
// RpcServerTrait.php
|
||||
// Created: 2024-08-16
|
||||
// Updated: 2024-08-16
|
||||
|
||||
namespace Aiwass\Server;
|
||||
|
||||
/**
|
||||
* Provides implementations for IRpcServer methods that are likely going to be identical across implementations.
|
||||
*/
|
||||
trait RpcServerTrait {
|
||||
public function register(IRpcActionHandler $handler): void {
|
||||
$handler->registerRpcActions($this);
|
||||
}
|
||||
|
||||
public function registerQueryAction(string $name, $handler): void {
|
||||
$this->registerAction(false, $name, $handler);
|
||||
}
|
||||
|
||||
public function registerProcedureAction(string $name, $handler): void {
|
||||
$this->registerAction(true, $name, $handler);
|
||||
}
|
||||
}
|
34
src/Server/ScopedRpcServer.php
Normal file
34
src/Server/ScopedRpcServer.php
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
// ScopedRpcServer.php
|
||||
// Created: 2024-08-16
|
||||
// Updated: 2024-11-13
|
||||
|
||||
namespace RPCii\Server;
|
||||
|
||||
/**
|
||||
* Provides a scoped RPC server implementation.
|
||||
*/
|
||||
class ScopedRpcServer implements RpcServer {
|
||||
use RpcServerCommon;
|
||||
|
||||
/**
|
||||
* @param RpcServer $base RPC server instance to use as a base.
|
||||
* @param string $prefix Prefix to apply to action names passed.
|
||||
*/
|
||||
public function __construct(
|
||||
private RpcServer $base,
|
||||
private string $prefix
|
||||
) {}
|
||||
|
||||
public function scopeTo(string $prefix): RpcServer {
|
||||
return $this->base->scopeTo($this->prefix . $prefix);
|
||||
}
|
||||
|
||||
public function registerProcedure(bool $isAction, string $name, $handler): void {
|
||||
$this->base->registerProcedure($isAction, $this->prefix . $name, $handler);
|
||||
}
|
||||
|
||||
public function getProcedureInfo(string $name): ?RpcProcedureInfo {
|
||||
return $this->base->getProcedureInfo($this->prefix . $name);
|
||||
}
|
||||
}
|
|
@ -1,24 +1,24 @@
|
|||
<?php
|
||||
// IVerificationProvider.php
|
||||
// VerificationProvider.php
|
||||
// Created: 2024-08-13
|
||||
// Updated: 2024-08-13
|
||||
// Updated: 2024-11-13
|
||||
|
||||
namespace Aiwass;
|
||||
namespace RPCii;
|
||||
|
||||
/**
|
||||
* Provides a common interface for verification providers for the route handler.
|
||||
*/
|
||||
interface IVerificationProvider {
|
||||
interface VerificationProvider {
|
||||
/**
|
||||
* Creates a signature.
|
||||
*
|
||||
* @param bool $isProcedure true if the request is a query or false if it is a procedure call.
|
||||
* @param bool $isAction true if the request is a query or false if it is an action.
|
||||
* @param string $action Name of the action.
|
||||
* @param string $paramString Query string value or body string value.
|
||||
* @return string A token string for the given arguments.
|
||||
*/
|
||||
function sign(
|
||||
bool $isProcedure,
|
||||
bool $isAction,
|
||||
string $action,
|
||||
string $paramString
|
||||
): string;
|
||||
|
@ -27,14 +27,14 @@ interface IVerificationProvider {
|
|||
* Verifies a signature.
|
||||
*
|
||||
* @param string $userToken A token provided by the user.
|
||||
* @param bool $isProcedure true if the request is a query or false if it is a procedure call.
|
||||
* @param bool $isAction true if the request is a query or false if it is a procedure call.
|
||||
* @param string $action Name of the action.
|
||||
* @param string $paramString Query string value or body string value.
|
||||
* @return bool true if the token verified successfully.
|
||||
*/
|
||||
function verify(
|
||||
string $userToken,
|
||||
bool $isProcedure,
|
||||
bool $isAction,
|
||||
string $action,
|
||||
string $paramString
|
||||
): bool;
|
|
@ -1,105 +1,107 @@
|
|||
<?php
|
||||
// AttributesTest.php
|
||||
// Created: 2024-08-16
|
||||
// Updated: 2024-08-16
|
||||
// Updated: 2024-11-13
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use PHPUnit\Framework\Attributes\{CoversClass,UsesClass};
|
||||
use Aiwass\Server\{RpcAction,RpcActionHandler,RpcProcedure,RpcQuery,RpcServer};
|
||||
use RPCii\Server\{RpcAction,RpcHandler,RpcHandlerCommon,RpcProcedure,RpcQuery,HttpRpcServer};
|
||||
|
||||
#[CoversClass(RpcAction::class)]
|
||||
#[CoversClass(RpcActionHandler::class)]
|
||||
#[CoversClass(RpcHandler::class)]
|
||||
#[CoversClass(RpcProcedure::class)]
|
||||
#[CoversClass(RpcQuery::class)]
|
||||
#[UsesClass(RpcServer::class)]
|
||||
#[UsesClass(HttpRpcServer::class)]
|
||||
final class AttributesTest extends TestCase {
|
||||
public function testAttributes(): void {
|
||||
$handler = new class($this) extends RpcActionHandler {
|
||||
private static $that;
|
||||
$handler = new class($this) implements RpcHandler {
|
||||
use RpcHandlerCommon;
|
||||
|
||||
public function __construct(private $self) {
|
||||
private static AttributesTest $that;
|
||||
|
||||
public function __construct(private AttributesTest $self) {
|
||||
self::$that = $self;
|
||||
}
|
||||
|
||||
#[RpcAction(true, 'aiwass:test:proc1')]
|
||||
public function procedureRegisteredUsingActionAttribute() {
|
||||
#[RpcProcedure(true, 'aiwass:test:proc1')]
|
||||
public function procedureRegisteredUsingActionAttribute(): string {
|
||||
return 'procedure registered using action attribute';
|
||||
}
|
||||
|
||||
#[RpcAction(false, 'aiwass:test:query1')]
|
||||
public function queryRegisteredUsingActionAttribute(string $beans) {
|
||||
#[RpcProcedure(false, 'aiwass:test:query1')]
|
||||
public function queryRegisteredUsingActionAttribute(string $beans): string {
|
||||
$this->self->assertEquals('it is beans', $beans);
|
||||
return 'query registered using action attribute';
|
||||
}
|
||||
|
||||
#[RpcQuery('aiwass:test:query2')]
|
||||
public static function staticQueryRegisteredUsingQueryAttribute(string $required, string $optional = 'the') {
|
||||
public static function staticQueryRegisteredUsingQueryAttribute(string $required, string $optional = 'the'): string {
|
||||
self::$that->assertEquals('internet', $required);
|
||||
self::$that->assertEquals('the', $optional);
|
||||
return 'static query registered using query attribute';
|
||||
}
|
||||
|
||||
#[RpcProcedure('aiwass:test:proc2')]
|
||||
public function dynamicProcedureRegisteredUsingProcedureAttribute(string $optional = 'meow') {
|
||||
#[RpcAction('aiwass:test:proc2')]
|
||||
public function dynamicProcedureRegisteredUsingProcedureAttribute(string $optional = 'meow'): string {
|
||||
$this->self->assertEquals('meow', $optional);
|
||||
return 'dynamic procedure registered using procedure attribute';
|
||||
}
|
||||
|
||||
#[RpcQuery('aiwass:test:query3')]
|
||||
#[RpcProcedure('aiwass:test:proc3')]
|
||||
public function multiple() {
|
||||
#[RpcAction('aiwass:test:proc3')]
|
||||
public function multiple(): string {
|
||||
return 'a dynamic method registered as both a query and a procedure';
|
||||
}
|
||||
|
||||
public function hasNoAttr() {
|
||||
public function hasNoAttr(): string {
|
||||
return 'not an action handler';
|
||||
}
|
||||
};
|
||||
|
||||
$server = new RpcServer;
|
||||
$server = new HttpRpcServer;
|
||||
$server->register($handler);
|
||||
|
||||
$this->assertNull($server->getActionInfo('aiwass:none'));
|
||||
$this->assertNull($server->getProcedureInfo('aiwass:none'));
|
||||
|
||||
$proc1 = $server->getActionInfo('aiwass:test:proc1');
|
||||
$this->assertNotNull($proc1);
|
||||
$this->assertTrue($proc1->isProcedure());
|
||||
$this->assertEquals('aiwass:test:proc1', $proc1->getName());
|
||||
$this->assertEquals('procedure registered using action attribute', $proc1->invokeHandler());
|
||||
$act1 = $server->getProcedureInfo('aiwass:test:proc1');
|
||||
$this->assertNotNull($act1);
|
||||
$this->assertTrue($act1->isAction());
|
||||
$this->assertEquals('aiwass:test:proc1', $act1->getName());
|
||||
$this->assertEquals('procedure registered using action attribute', $act1->invokeHandler());
|
||||
|
||||
$proc2 = $server->getActionInfo('aiwass:test:proc2');
|
||||
$this->assertNotNull($proc2);
|
||||
$this->assertTrue($proc2->isProcedure());
|
||||
$this->assertEquals('aiwass:test:proc2', $proc2->getName());
|
||||
$this->assertEquals('dynamic procedure registered using procedure attribute', $proc2->invokeHandler());
|
||||
$act2 = $server->getProcedureInfo('aiwass:test:proc2');
|
||||
$this->assertNotNull($act2);
|
||||
$this->assertTrue($act2->isAction());
|
||||
$this->assertEquals('aiwass:test:proc2', $act2->getName());
|
||||
$this->assertEquals('dynamic procedure registered using procedure attribute', $act2->invokeHandler());
|
||||
|
||||
$query1 = $server->getActionInfo('aiwass:test:query1');
|
||||
$query1 = $server->getProcedureInfo('aiwass:test:query1');
|
||||
$this->assertNotNull($query1);
|
||||
$this->assertFalse($query1->isProcedure());
|
||||
$this->assertFalse($query1->isAction());
|
||||
$this->assertEquals('aiwass:test:query1', $query1->getName());
|
||||
$this->assertEquals('query registered using action attribute', $query1->invokeHandler(['beans' => 'it is beans']));
|
||||
|
||||
$query2 = $server->getActionInfo('aiwass:test:query2');
|
||||
$query2 = $server->getProcedureInfo('aiwass:test:query2');
|
||||
$this->assertNotNull($query2);
|
||||
$this->assertFalse($query2->isProcedure());
|
||||
$this->assertFalse($query2->isAction());
|
||||
$this->assertEquals('aiwass:test:query2', $query2->getName());
|
||||
$this->assertEquals('static query registered using query attribute', $query2->invokeHandler(['required' => 'internet']));
|
||||
|
||||
$query3 = $server->getActionInfo('aiwass:test:query3');
|
||||
$proc3 = $server->getActionInfo('aiwass:test:proc3');
|
||||
$query3 = $server->getProcedureInfo('aiwass:test:query3');
|
||||
$proc3 = $server->getProcedureInfo('aiwass:test:proc3');
|
||||
$this->assertNotNull($query3);
|
||||
$this->assertNotNull($proc3);
|
||||
$this->assertFalse($query3->isProcedure());
|
||||
$this->asserttrue($proc3->isProcedure());
|
||||
$this->assertFalse($query3->isAction());
|
||||
$this->asserttrue($proc3->isAction());
|
||||
$this->assertEquals('aiwass:test:query3', $query3->getName());
|
||||
$this->assertEquals('aiwass:test:proc3', $proc3->getName());
|
||||
$this->assertEquals($query3->getHandler(), $proc3->getHandler());
|
||||
$this->assertEquals('a dynamic method registered as both a query and a procedure', $query3->invokeHandler());
|
||||
$this->assertEquals('a dynamic method registered as both a query and a procedure', $proc3->invokeHandler());
|
||||
|
||||
$this->assertNull($server->getActionInfo('doesnotexist'));
|
||||
$this->assertNull($server->getProcedureInfo('doesnotexist'));
|
||||
|
||||
$this->expectException(RuntimeException::class);
|
||||
$query1->invokeHandler(['notbeans' => 'it is not beans']);
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
<?php
|
||||
// CurlHttpTest.php
|
||||
// Created: 2024-08-13
|
||||
// Updated: 2024-08-16
|
||||
// Updated: 2024-11-13
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use Aiwass\Client\CurlHttpRequest;
|
||||
use RPCii\Client\CurlHttpRequest;
|
||||
|
||||
#[CoversClass(CurlHttpRequest::class)]
|
||||
final class CurlHttpTest extends TestCase {
|
||||
|
@ -19,13 +19,18 @@ final class CurlHttpTest extends TestCase {
|
|||
$request->setParams('soap=beans');
|
||||
$response = json_decode($request->execute(), true);
|
||||
|
||||
$this->assertTrue(array_key_exists('X-Test', $response['headers']));
|
||||
$this->assertIsArray($response);
|
||||
$this->assertArrayHasKey('headers', $response);
|
||||
$this->assertIsArray($response['headers']);
|
||||
$this->assertArrayHasKey('X-Test', $response['headers']);
|
||||
$this->assertEquals('teste', $response['headers']['X-Test']);
|
||||
|
||||
$this->assertTrue(array_key_exists('alreadyhere', $response['args']));
|
||||
$this->assertArrayHasKey('args', $response);
|
||||
$this->assertIsArray($response['args']);
|
||||
$this->assertArrayHasKey('alreadyhere', $response['args']);
|
||||
$this->assertEquals('true', $response['args']['alreadyhere']);
|
||||
|
||||
$this->assertTrue(array_key_exists('soap', $response['args']));
|
||||
$this->assertArrayHasKey('soap', $response['args']);
|
||||
$this->assertEquals('beans', $response['args']['soap']);
|
||||
}
|
||||
|
||||
|
@ -37,13 +42,18 @@ final class CurlHttpTest extends TestCase {
|
|||
$request->setParams('windows=xp&macos=leopard');
|
||||
$response = json_decode($request->execute(), true);
|
||||
|
||||
$this->assertTrue(array_key_exists('X-Meow', $response['headers']));
|
||||
$this->assertIsArray($response);
|
||||
$this->assertArrayHasKey('headers', $response);
|
||||
$this->assertIsArray($response['headers']);
|
||||
$this->assertArrayHasKey('X-Meow', $response['headers']);
|
||||
$this->assertEquals('soap', $response['headers']['X-Meow']);
|
||||
|
||||
$this->assertTrue(array_key_exists('windows', $response['form']));
|
||||
$this->assertArrayHasKey('form', $response);
|
||||
$this->assertIsArray($response['form']);
|
||||
$this->assertArrayHasKey('windows', $response['form']);
|
||||
$this->assertEquals('xp', $response['form']['windows']);
|
||||
|
||||
$this->assertTrue(array_key_exists('macos', $response['form']));
|
||||
$this->assertArrayHasKey('macos', $response['form']);
|
||||
$this->assertEquals('leopard', $response['form']['macos']);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
<?php
|
||||
// HmacVerificationTest.php
|
||||
// Created: 2024-08-13
|
||||
// Updated: 2024-08-13
|
||||
// Updated: 2024-11-13
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use Aiwass\HmacVerificationProvider;
|
||||
use RPCii\HmacVerificationProvider;
|
||||
|
||||
#[CoversClass(HmacVerificationProvider::class)]
|
||||
final class HmacVerificationTest extends TestCase {
|
||||
public function testProcedureEnforce(): void {
|
||||
public function testActionEnforce(): void {
|
||||
$provider = new HmacVerificationProvider(fn() => 'meow');
|
||||
$action = 'test';
|
||||
$procedure = 'test';
|
||||
$params = 'meow=cool&the=bean';
|
||||
|
||||
$queryToken = $provider->sign(false, $action, $params);
|
||||
$this->assertTrue($provider->verify($queryToken, false, $action, $params));
|
||||
$this->assertFalse($provider->verify($queryToken, true, $action, $params));
|
||||
$queryToken = $provider->sign(false, $procedure, $params);
|
||||
$this->assertTrue($provider->verify($queryToken, false, $procedure, $params));
|
||||
$this->assertFalse($provider->verify($queryToken, true, $procedure, $params));
|
||||
|
||||
$procedureToken = $provider->sign(true, $action, $params);
|
||||
$this->assertTrue($provider->verify($procedureToken, true, $action, $params));
|
||||
$this->assertFalse($provider->verify($procedureToken, false, $action, $params));
|
||||
$actionToken = $provider->sign(true, $procedure, $params);
|
||||
$this->assertTrue($provider->verify($actionToken, true, $procedure, $params));
|
||||
$this->assertFalse($provider->verify($actionToken, false, $procedure, $params));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,40 +1,40 @@
|
|||
<?php
|
||||
// ScopedServerTest.php
|
||||
// Created: 2024-08-16
|
||||
// Updated: 2024-08-16
|
||||
// Updated: 2024-11-13
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use PHPUnit\Framework\Attributes\{CoversClass,UsesClass};
|
||||
use Aiwass\Server\{RpcServer,RpcServerScoped};
|
||||
use RPCii\Server\{HttpRpcServer,ScopedRpcServer};
|
||||
|
||||
#[CoversClass(RpcServerScoped::class)]
|
||||
#[UsesClass(RpcServer::class)]
|
||||
#[CoversClass(ScopedRpcServer::class)]
|
||||
#[UsesClass(HttpRpcServer::class)]
|
||||
final class ScopedServerTest extends TestCase {
|
||||
public function testServerScoping(): void {
|
||||
$base = new RpcServer;
|
||||
$base->registerQueryAction('test', fn() => 'test');
|
||||
$base = new HttpRpcServer;
|
||||
$base->registerQueryProcedure('test', fn() => 'test');
|
||||
|
||||
$scopedToBeans = $base->scopeTo('beans:');
|
||||
$scopedToBeans->registerQueryAction('test', fn() => 'test in beans');
|
||||
$scopedToBeans->registerQueryProcedure('test', fn() => 'test in beans');
|
||||
|
||||
$scopedToGarf = $base->scopeTo('garf:');
|
||||
$scopedToGarfield = $scopedToGarf->scopeTo('ield:');
|
||||
$scopedToGarfield->registerQueryAction('test', fn() => 'test in garfield');
|
||||
$scopedToGarfield->registerQueryProcedure('test', fn() => 'test in garfield');
|
||||
|
||||
$baseTest = $base->getActionInfo('test');
|
||||
$baseTest = $base->getProcedureInfo('test');
|
||||
$this->assertNotNull($baseTest);
|
||||
$this->assertEquals('test', $baseTest->getName());
|
||||
|
||||
$baseBeansTest = $base->getActionInfo('beans:test');
|
||||
$scopedBeansTest = $scopedToBeans->getActionInfo('test');
|
||||
$baseBeansTest = $base->getProcedureInfo('beans:test');
|
||||
$scopedBeansTest = $scopedToBeans->getProcedureInfo('test');
|
||||
$this->assertNotNull($baseBeansTest);
|
||||
$this->assertSame($baseBeansTest, $scopedBeansTest);
|
||||
$this->assertEquals('beans:test', $scopedBeansTest->getName());
|
||||
|
||||
$baseGarfieldTest = $base->getActionInfo('garf:ield:test');
|
||||
$scopedGarfieldTest = $scopedToGarfield->getActionInfo('test');
|
||||
$baseGarfieldTest = $base->getProcedureInfo('garf:ield:test');
|
||||
$scopedGarfieldTest = $scopedToGarfield->getProcedureInfo('test');
|
||||
$this->assertNotNull($baseGarfieldTest);
|
||||
$this->assertSame($baseGarfieldTest, $scopedGarfieldTest);
|
||||
$this->assertEquals('garf:ield:test', $scopedGarfieldTest->getName());
|
||||
|
|
59
tests/StreamHttpTest.php
Normal file
59
tests/StreamHttpTest.php
Normal file
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
// StreamHttpTest.php
|
||||
// Created: 2024-11-13
|
||||
// Updated: 2024-11-13
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use RPCii\Client\StreamHttpRequest;
|
||||
|
||||
#[CoversClass(StreamHttpRequest::class)]
|
||||
final class StreamHttpTest extends TestCase {
|
||||
public function testGetRequest(): void {
|
||||
$request = new StreamHttpRequest;
|
||||
$request->setPost(false);
|
||||
$request->setUrl('https://httpbin.org/get?alreadyhere=true');
|
||||
$request->setHeader('X-Test', 'teste');
|
||||
$request->setParams('soap=beans');
|
||||
$response = json_decode($request->execute(), true);
|
||||
|
||||
$this->assertIsArray($response);
|
||||
$this->assertArrayHasKey('headers', $response);
|
||||
$this->assertIsArray($response['headers']);
|
||||
$this->assertArrayHasKey('X-Test', $response['headers']);
|
||||
$this->assertEquals('teste', $response['headers']['X-Test']);
|
||||
|
||||
$this->assertArrayHasKey('args', $response);
|
||||
$this->assertIsArray($response['args']);
|
||||
$this->assertArrayHasKey('alreadyhere', $response['args']);
|
||||
$this->assertEquals('true', $response['args']['alreadyhere']);
|
||||
|
||||
$this->assertArrayHasKey('soap', $response['args']);
|
||||
$this->assertEquals('beans', $response['args']['soap']);
|
||||
}
|
||||
|
||||
public function testPostRequest(): void {
|
||||
$request = new StreamHttpRequest;
|
||||
$request->setPost(true);
|
||||
$request->setUrl('https://httpbin.org/post');
|
||||
$request->setHeader('X-Meow', 'soap');
|
||||
$request->setParams('windows=xp&macos=leopard');
|
||||
$response = json_decode($request->execute(), true);
|
||||
|
||||
$this->assertIsArray($response);
|
||||
$this->assertArrayHasKey('headers', $response);
|
||||
$this->assertIsArray($response['headers']);
|
||||
$this->assertArrayHasKey('X-Meow', $response['headers']);
|
||||
$this->assertEquals('soap', $response['headers']['X-Meow']);
|
||||
|
||||
$this->assertArrayHasKey('form', $response);
|
||||
$this->assertIsArray($response['form']);
|
||||
$this->assertArrayHasKey('windows', $response['form']);
|
||||
$this->assertEquals('xp', $response['form']['windows']);
|
||||
|
||||
$this->assertArrayHasKey('macos', $response['form']);
|
||||
$this->assertEquals('leopard', $response['form']['macos']);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue