Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ phpstan: var vendor ## Analyze code using PHPStan
$(RUN) phpstan analyze --memory-limit=1G $(ARGS)
.PHONY: phpstan

test: var vendor ## Run tests using PHPUnit
test: var vendor compile-test-stub ## Run tests using PHPUnit
$(RUN) vendor/bin/phpunit $(ARGS) --colors
.PHONY: test

Expand All @@ -130,12 +130,12 @@ composer-normalize-check: ## Check that composer.json is normalized
fix: fixer rector composer-normalize ## Run all fixing recipes
.PHONY: fix

check: fixer-check rector-check composer-validate composer-normalize-check deps-analyze phpstan compile-test-stub test ## Run all project checks
check: fixer-check rector-check composer-validate composer-normalize-check deps-analyze phpstan test ## Run all project checks
.PHONY: check

compile-test-stub:
docker run --rm \
--user 1000:1000 \
--user $(CONTAINER_USER) \
-v $(PWD):/workspace \
-w /workspace \
ghcr.io/thesis-php/protoc-plugin:latest \
Expand Down
9 changes: 5 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,16 @@
"psr/log": "^3.0",
"revolt/event-loop": "1.0.8",
"thesis/endian": "^0.3.0",
"thesis/googleapis-rpc-types": "^0.1.2",
"thesis/googleapis-rpc-types": "^0.1.6",
"thesis/package-version": "^0.1.2",
"thesis/protobuf": "^0.1.5",
"thesis/protobuf-known-types": "^0.1.2"
"thesis/protobuf": "^0.1.8",
"thesis/protobuf-known-types": "^0.1.5"
},
"require-dev": {
"ext-bcmath": "*",
"phpunit/phpunit": "^12.4",
"symfony/var-dumper": "^8.0"
"symfony/var-dumper": "^8.0",
"thesis/protoregistry": "^0.1.2"
},
"autoload": {
"psr-4": {
Expand Down
2 changes: 1 addition & 1 deletion src/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
/**
* @api
*/
interface Server
interface Server extends ServiceRegistrar
{
/**
* The server can subscribe to the {@see Cancellation} to stop automatically when it is triggered, for example on a signal.
Expand Down
7 changes: 5 additions & 2 deletions src/Server/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -373,17 +373,20 @@ public function build(): Server
$server->expose($address, $bindContext);
}

return new Internal\AmphpHttpServer(
$grpc = new Internal\AmphpHttpServer(
server: $server,
requestHandler: new ServerRequestHandler(
encoderFactory: new MessageEncoderFactory(array_values($this->encoders)),
compressorFactory: new MessageCompressorFactory($compressors),
protobuf: $this->protobuf ?? Protobuf\Encoder\Builder::buildDefault(),
services: $this->services,
interceptors: $this->interceptors,
),
errorHandler: new ServerErrorHandler(),
);

$grpc->register(...$this->services);

return $grpc;
}

/**
Expand Down
17 changes: 17 additions & 0 deletions src/Server/Internal/AmphpHttpServer.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Amp\NullCancellation;
use Revolt\EventLoop;
use Thesis\Grpc\Server;
use Thesis\Grpc\Server\Service;
use function Amp\async;

/**
Expand Down Expand Up @@ -68,4 +69,20 @@ public function __destruct()
{
$this->stop();
}

#[\Override]
public function register(Service ...$services): void
{
if ($this->state === HttpServerState::Serve) {
throw new Server\ServerRunning();
}

$this->requestHandler->register(...$services);
}

#[\Override]
public function services(): array
{
return $this->requestHandler->services();
}
}
33 changes: 19 additions & 14 deletions src/Server/Internal/Http2/Router.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,25 @@

/**
* @internal
* @template-implements \IteratorAggregate<array-key, Service>
*/
final readonly class Router
final class Router implements \IteratorAggregate
{
/** @var array<non-empty-string, non-empty-array<non-empty-string, Rpc>> */
private array $services;
private array $index = [];

/**
* @param list<Service> $services
*/
public function __construct(array $services)
/** @var list<Service> */
private array $services = [];

public function addService(Service $service): void
{
$this->services = array_combine(
array_map(static fn(Service $service) => $service->name, $services),
$this->services[] = $service;
$this->index[$service->name] = array_combine(
array_map(
static fn(Service $service) => array_combine(
array_map(static fn(Rpc $rpc) => $rpc->handle->method, $service->handlers),
$service->handlers,
),
$services,
static fn(Rpc $rpc) => $rpc->handle->method,
$service->handlers,
),
$service->handlers,
);
}

Expand All @@ -47,8 +46,14 @@ public function route(Request $request): Rpc

$endpoint = Endpoint::parse($path);

$rpc = $this->services[$endpoint->service] ?? throw new InvalidRpcMethod("Unknown service {$endpoint->service}");
$rpc = $this->index[$endpoint->service] ?? throw new InvalidRpcMethod("Unknown service {$endpoint->service}");

return $rpc[$endpoint->method] ?? throw new InvalidRpcMethod("Unknown method {$endpoint->method} for service {$endpoint->service}");
}

#[\Override]
public function getIterator(): \Traversable
{
yield from $this->services;
}
}
21 changes: 17 additions & 4 deletions src/Server/Internal/Http2/ServerRequestHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
use Thesis\Grpc\Server\Service;
use Thesis\Grpc\Server\StreamInfo;
use Thesis\Grpc\ServerStream;
use Thesis\Grpc\ServiceRegistrar;
use Thesis\Grpc\UnimplementedException;
use Thesis\Protobuf;
use function Amp\async;
Expand All @@ -30,7 +31,9 @@
* @internal
* @phpstan-type HandlerEntry = object{future: Future<void>, cancellation: DeferredCancellation}
*/
final class ServerRequestHandler implements RequestHandler
final class ServerRequestHandler implements
RequestHandler,
ServiceRegistrar
{
private readonly Router $router;

Expand All @@ -40,24 +43,34 @@ final class ServerRequestHandler implements RequestHandler
private \WeakMap $pending;

/**
* @param list<Service> $services
* @param list<Interceptor> $interceptors
*/
public function __construct(
private readonly MessageEncoderFactory $encoderFactory,
private readonly MessageCompressorFactory $compressorFactory,
Protobuf\Encoder $protobuf,
array $services,
array $interceptors,
) {
$this->pending = new \WeakMap();
$this->router = new Router($services);
$this->router = new Router();
$this->interceptor = new InterceptorComposer([
new StreamHandleInterceptor($protobuf),
...$interceptors,
]);
}

#[\Override]
public function register(Service ...$services): void
{
array_walk($services, $this->router->addService(...));
}

#[\Override]
public function services(): array
{
return iterator_to_array($this->router, preserve_keys: false);
}

#[\Override]
public function handleRequest(Request $request): Response
{
Expand Down
12 changes: 12 additions & 0 deletions src/Server/ServerRunning.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace Thesis\Grpc\Server;

use Thesis\Grpc\GrpcException;

/**
* @api
*/
final class ServerRunning extends GrpcException {}
24 changes: 24 additions & 0 deletions src/ServiceRegistrar.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace Thesis\Grpc;

use Thesis\Grpc\Server\ServerRunning;
use Thesis\Grpc\Server\Service;

/**
* @api
*/
interface ServiceRegistrar
{
/**
* @throws ServerRunning
*/
public function register(Service ...$services): void;

/**
* @return list<Service>
*/
public function services(): array;
}
51 changes: 51 additions & 0 deletions tests/ServerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

declare(strict_types=1);

namespace Thesis\Grpc;

use Amp\Cancellation;
use Echos\Api\V1\EchoRequest;
use Echos\Api\V1\EchoResponse;
use Echos\Api\V1\EchoServiceClient;
use Echos\Api\V1\EchoServiceServer;
use Echos\Api\V1\EchoServiceServerRegistry;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\TestCase;
use Thesis\Grpc\Server\Internal\AmphpHttpServer;
use Thesis\Grpc\Server\ServerRunning;

#[CoversClass(AmphpHttpServer::class)]
final class ServerTest extends TestCase
{
public function testRegisterService(): void
{
$server = new Server\Builder()->build();
$server->register(...new EchoServiceServerRegistry(new class implements EchoServiceServer {
#[\Override]
public function echo(EchoRequest $request, Metadata $md, Cancellation $cancellation): EchoResponse
{
return new EchoResponse($request->sentence);
}
})->services());

$server->start();
$client = new EchoServiceClient(new Client\Builder()->build());
self::assertSame('Hello, gRPC', $client->echo(new EchoRequest('Hello, gRPC'))->sentence);
$server->stop();
}

public function testRegisterServiceInRunningServer(): void
{
$server = new Server\Builder()->build();
$server->start();
$this->expectExceptionObject(new ServerRunning());
$server->register(...new EchoServiceServerRegistry(new class implements EchoServiceServer {
#[\Override]
public function echo(EchoRequest $request, Metadata $md, Cancellation $cancellation): EchoResponse
{
return new EchoResponse($request->sentence);
}
})->services());
}
}
2 changes: 1 addition & 1 deletion tests/genproto/Chat/Api/V1/Message.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/**
* Code generated by thesis/protoc-plugin. DO NOT EDIT.
* Versions:
* thesis/protoc-plugin — v0.1.11
* thesis/protoc-plugin — v0.1.19
* protoc — v6.33.5
* Source: tests/protos/chat_v1.proto
*/
Expand Down
2 changes: 1 addition & 1 deletion tests/genproto/Chat/Api/V1/MessengerServiceClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/**
* Code generated by thesis/protoc-plugin. DO NOT EDIT.
* Versions:
* thesis/protoc-plugin — v0.1.11
* thesis/protoc-plugin — v0.1.19
* protoc — v6.33.5
* Source: tests/protos/chat_v1.proto
*/
Expand Down
2 changes: 1 addition & 1 deletion tests/genproto/Chat/Api/V1/MessengerServiceServer.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/**
* Code generated by thesis/protoc-plugin. DO NOT EDIT.
* Versions:
* thesis/protoc-plugin — v0.1.11
* thesis/protoc-plugin — v0.1.19
* protoc — v6.33.5
* Source: tests/protos/chat_v1.proto
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/**
* Code generated by thesis/protoc-plugin. DO NOT EDIT.
* Versions:
* thesis/protoc-plugin — v0.1.11
* thesis/protoc-plugin — v0.1.19
* protoc — v6.33.5
* Source: tests/protos/chat_v1.proto
*/
Expand Down
26 changes: 19 additions & 7 deletions tests/genproto/Chat/Api/V1/TestsProtosChatV1DescriptorRegistry.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/**
* Code generated by thesis/protoc-plugin. DO NOT EDIT.
* Versions:
* thesis/protoc-plugin — v0.1.11
* thesis/protoc-plugin — v0.1.19
* protoc — v6.33.5
* Source: tests/protos/chat_v1.proto
*/
Expand All @@ -13,20 +13,32 @@
namespace Chat\Api\V1;

use Override;
use Thesis\Protobuf\Pool;
use Thesis\Protobuf\Registry;
use Thesis\Protobuf\Registry\File;

/**
* @api
*/
final readonly class TestsProtosChatV1DescriptorRegistry implements Pool\Registrar
final readonly class TestsProtosChatV1DescriptorRegistry implements Registry\Registrar
{
private const string DESCRIPTOR_BUFFER = 'Chp0ZXN0cy9wcm90b3MvY2hhdF92MS5wcm90bxILY2hhdC5hcGkudjEiHQoHTWVzc2FnZRISCgR0ZXh0GAEgASgJUgR0ZXh0MkoKEE1lc3NlbmdlclNlcnZpY2USNgoEQ2hhdBIULmNoYXQuYXBpLnYxLk1lc3NhZ2UaFC5jaGF0LmFwaS52MS5NZXNzYWdlKAEwAUrWAQoGEgQAAAoBCggKAQwSAwAAEgoICgECEgMCABQKCgoCBAASBAQABgEKCgoDBAABEgMECA8KCwoEBAACABIDBQQUCgwKBQQAAgAFEgMFBAoKDAoFBAACAAESAwULDwoMCgUEAAIAAxIDBRITCgoKAgYAEgQIAAoBCgoKAwYAARIDCAgYCgsKBAYAAgASAwkENgoMCgUGAAIAARIDCQgMCgwKBQYAAgAFEgMJDRMKDAoFBgACAAISAwkUGwoMCgUGAAIABhIDCSYsCgwKBQYAAgADEgMJLTRiBnByb3RvMw==';

#[Override]
public function register(Pool\Registry $pool): void
public function register(Registry\Pool $pool): void
{
$pool->add(Pool\Descriptor::base64(self::DESCRIPTOR_BUFFER), [
'chat.api.v1.Message' => new Pool\MessageMetadata(\Chat\Api\V1\Message::class),
]);
$pool->add(Registry\Descriptor::base64(self::DESCRIPTOR_BUFFER), new File(
name: 'tests/protos/chat_v1.proto',
messages: [
new File\MessageDescriptor('chat.api.v1.Message', \Chat\Api\V1\Message::class),
],
services: [
new File\ServiceDescriptor(
name: 'chat.api.v1.MessengerService',
methods: [
new File\MethodDescriptor('Chat', true, true),
],
),
],
));
}
}
Loading