diff --git a/src/IRpcActionHandler.php b/src/IRpcActionHandler.php index 1b97e97..1b7845f 100644 --- a/src/IRpcActionHandler.php +++ b/src/IRpcActionHandler.php @@ -1,18 +1,18 @@ getMethods(); diff --git a/src/RpcActionHandlerTrait.php b/src/RpcActionHandlerTrait.php index 8d27ded..3a1cae1 100644 --- a/src/RpcActionHandlerTrait.php +++ b/src/RpcActionHandlerTrait.php @@ -10,7 +10,7 @@ namespace Aiwass; * For more advanced use, everything can be use'd separately and RpcActionAttribute::register called manually. */ trait RpcActionHandlerTrait { - public function registerRpcActions(RpcServer $server): void { + public function registerRpcActions(IRpcServer $server): void { RpcAction::register($server, $this); } } diff --git a/src/RpcRouteHandler.php b/src/RpcRouteHandler.php index 5e04925..c65d74f 100644 --- a/src/RpcRouteHandler.php +++ b/src/RpcRouteHandler.php @@ -16,10 +16,11 @@ use Index\Http\Routing\{HttpGet,HttpPost,RouteHandler}; */ class RpcRouteHandler extends RouteHandler { /** - * @param RpcServer $server An RPC server instance. + * @param IRpcServer $server An RPC server instance. */ public function __construct( - private RpcServer $server + private IVerificationProvider $verification, + private IRpcServer $server ) {} /** @@ -73,7 +74,7 @@ class RpcRouteHandler extends RouteHandler { return AiwassMsgPack::encode(['error' => 'aiwass:method']); } - if(!$this->server->getVerificationProvider()->verify($userToken, $expectProcedure, $action, $paramString)) + if(!$this->verification->verify($userToken, $expectProcedure, $action, $paramString)) return AiwassMsgPack::encode(['error' => 'aiwass:verify']); try { diff --git a/src/RpcServer.php b/src/RpcServer.php index 53d9b54..bbb4cf5 100644 --- a/src/RpcServer.php +++ b/src/RpcServer.php @@ -1,7 +1,7 @@ */ private array $actions = []; - /** - * @param IVerificationProvider $verify A verification provider. - */ - public function __construct( - private IVerificationProvider $verify - ) {} - - /** - * Retrieves this verification provider for this server. - * - * @return IVerificationProvider Verification provider implementation. - */ - public function getVerificationProvider(): IVerificationProvider { - return $this->verify; + public function scopeTo(string $prefix): IRpcServer { + return new RpcServerScoped($this, $prefix); } - /** - * Creates an RPC route handler. - * - * @return RpcRouteHandler RPC route handler. - */ - public function createRouteHandler(): RpcRouteHandler { - return new RpcRouteHandler($this); - } - - /** - * Registers a handler class. - * - * @param IRpcActionHandler $handler Handler to register. - */ - public function register(IRpcActionHandler $handler): void { - $handler->registerRpcActions($this); - } - - /** - * 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. - */ 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'); @@ -65,47 +28,7 @@ class RpcServer { $this->actions[$name] = new RpcActionInfo($isProcedure, $name, $handler); } - /** - * 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. - */ - public function registerQueryAction(string $name, $handler): void { - $this->registerAction(false, $name, $handler); - } - - /** - * 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. - */ - public function registerProcedureAction(string $name, $handler): void { - $this->registerAction(true, $name, $handler); - } - - /** - * 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. - */ public function getActionInfo(string $name): ?RpcActionInfo { return $this->actions[$name] ?? null; } - - /** - * Creates an RPC server with a Hmac verification provider. - * - * @param callable(): string $getSecretKey A method that returns the secret key to use. - * @return RpcServer The RPC server. - */ - public static function createHmac($getSecretKey): RpcServer { - return new RpcServer(new HmacVerificationProvider($getSecretKey)); - } } diff --git a/src/RpcServerScoped.php b/src/RpcServerScoped.php new file mode 100644 index 0000000..7a1c3ff --- /dev/null +++ b/src/RpcServerScoped.php @@ -0,0 +1,30 @@ +base, $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); + } +} diff --git a/src/RpcServerTrait.php b/src/RpcServerTrait.php new file mode 100644 index 0000000..b797720 --- /dev/null +++ b/src/RpcServerTrait.php @@ -0,0 +1,23 @@ +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); + } +} diff --git a/tests/AttributesTest.php b/tests/AttributesTest.php index 2acf87b..b1921ac 100644 --- a/tests/AttributesTest.php +++ b/tests/AttributesTest.php @@ -59,33 +59,39 @@ final class AttributesTest extends TestCase { } }; - $server = RpcServer::createHmac(fn() => 'test'); + $server = new RpcServer; $server->register($handler); $this->assertNull($server->getActionInfo('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()); $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()); $query1 = $server->getActionInfo('aiwass:test:query1'); + $this->assertNotNull($query1); $this->assertFalse($query1->isProcedure()); $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'); + $this->assertNotNull($query2); $this->assertFalse($query2->isProcedure()); $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'); + $this->assertNotNull($query3); + $this->assertNotNull($proc3); $this->assertFalse($query3->isProcedure()); $this->asserttrue($proc3->isProcedure()); $this->assertEquals('aiwass:test:query3', $query3->getName()); @@ -94,6 +100,8 @@ final class AttributesTest extends TestCase { $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->expectException(RuntimeException::class); $query1->invokeHandler(['notbeans' => 'it is not beans']); } diff --git a/tests/ScopedServerTest.php b/tests/ScopedServerTest.php new file mode 100644 index 0000000..893dd56 --- /dev/null +++ b/tests/ScopedServerTest.php @@ -0,0 +1,42 @@ +registerQueryAction('test', fn() => 'test'); + + $scopedToBeans = $base->scopeTo('beans:'); + $scopedToBeans->registerQueryAction('test', fn() => 'test in beans'); + + $scopedToGarf = $base->scopeTo('garf:'); + $scopedToGarfield = $scopedToGarf->scopeTo('ield:'); + $scopedToGarfield->registerQueryAction('test', fn() => 'test in garfield'); + + $baseTest = $base->getActionInfo('test'); + $this->assertNotNull($baseTest); + $this->assertEquals('test', $baseTest->getName()); + + $baseBeansTest = $base->getActionInfo('beans:test'); + $scopedBeansTest = $scopedToBeans->getActionInfo('test'); + $this->assertNotNull($baseBeansTest); + $this->assertSame($baseBeansTest, $scopedBeansTest); + $this->assertEquals('beans:test', $scopedBeansTest->getName()); + + $baseGarfieldTest = $base->getActionInfo('garf:ield:test'); + $scopedGarfieldTest = $scopedToGarfield->getActionInfo('test'); + $this->assertNotNull($baseGarfieldTest); + $this->assertSame($baseGarfieldTest, $scopedGarfieldTest); + $this->assertEquals('garf:ield:test', $scopedGarfieldTest->getName()); + } +}