diff --git a/README.md b/README.md index a654077..03c9d9e 100644 --- a/README.md +++ b/README.md @@ -49,9 +49,14 @@ use Spiral\Goridge; require "vendor/autoload.php"; $rpc = new Goridge\RPC(new Goridge\SocketRelay("127.0.0.1", 6001)); +//or, using factory: +$tcpRPC = Goridge\Relay::create('tcp://127.0.0.1:6001'); +$unixRPC = Goridge\Relay::create('unix:///tmp/rpc.sock'); +$streamRPC = Goridge\Relay::create('pipes://stdin:stdout'); echo $rpc->call("App.Hi", "Antony"); ``` +> Factory applies the next format: `://:` ```go package main diff --git a/php-src/Exceptions/RelayFactoryException.php b/php-src/Exceptions/RelayFactoryException.php new file mode 100644 index 0000000..d5968eb --- /dev/null +++ b/php-src/Exceptions/RelayFactoryException.php @@ -0,0 +1,12 @@ +[^:\/]+):\/\/(?P[^:]+)(:(?P[^:]+))?/'; + + public static function create(string $connection): RelayInterface + { + if (!preg_match(self::CONNECTION, strtolower($connection), $match)) { + throw new Exceptions\RelayFactoryException('unsupported connection format'); + } + + switch ($match['protocol']) { + case self::TCP_SOCKET: + //fall through + case self::UNIX_SOCKET: + return new SocketRelay( + $match['arg1'], + isset($match['arg2']) ? (int)$match['arg2'] : null, + $match['protocol'] === self::TCP_SOCKET ? SocketRelay::SOCK_TCP : SocketRelay::SOCK_UNIX + ); + + case self::STREAM: + if (!isset($match['arg2'])) { + throw new Exceptions\RelayFactoryException('unsupported stream connection format'); + } + + return new StreamRelay( + fopen("php://{$match['arg1']}", 'rb'), + fopen("php://{$match['arg2']}", 'wb') + ); + default: + throw new Exceptions\RelayFactoryException('unknown connection protocol'); + } + } +} diff --git a/tests/Cases/RelayFactoryTest.php b/tests/Cases/RelayFactoryTest.php new file mode 100644 index 0000000..36bf9ff --- /dev/null +++ b/tests/Cases/RelayFactoryTest.php @@ -0,0 +1,93 @@ +assertTrue(true); + if ($expectedException) { + $this->expectException(Exceptions\RelayFactoryException::class); + } + + try { + Relay::create($connection); + } catch (Exceptions\RelayFactoryException $exception) { + throw $exception; + } catch (Throwable $exception) { + //do nothing, that's not a factory issue + } + } + + /** + * @return iterable + */ + public function formatProvider(): iterable + { + return [ + //format invalid + ['tcp:localhost:', true], + ['tcp:/localhost:', true], + ['tcp//localhost:', true], + ['tcp//localhost', true], + //unknown provider + ['test://localhost', true], + //pipes require 2 args + ['pipes://localhost:', true], + ['pipes://localhost', true], + //valid format + ['tcp://localhost'], + ['tcp://localhost:123'], + ['unix://localhost:123'], + ['unix://rpc.sock'], + ['unix:///tmp/rpc.sock'], + ['tcp://localhost:abc'], + ['pipes://stdin:stdout'], + ]; + } + + public function testTCP(): void + { + /** @var SocketRelay $relay */ + $relay = Relay::create('tcp://localhost:0'); + $this->assertInstanceOf(SocketRelay::class, $relay); + $this->assertSame('localhost', $relay->getAddress()); + $this->assertSame(0, $relay->getPort()); + $this->assertSame(SocketRelay::SOCK_TCP, $relay->getType()); + } + + public function testUnix(): void + { + /** @var SocketRelay $relay */ + $relay = Relay::create('unix:///tmp/rpc.sock'); + $this->assertInstanceOf(SocketRelay::class, $relay); + $this->assertSame('/tmp/rpc.sock', $relay->getAddress()); + $this->assertSame(SocketRelay::SOCK_UNIX, $relay->getType()); + } + + public function testPipes(): void + { + /** @var StreamRelay $relay */ + $relay = Relay::create('pipes://stdin:stdout'); + $this->assertInstanceOf(StreamRelay::class, $relay); + } +}