Skip to content

Commit

Permalink
Improves Scaffolder for Centrifugo handler (#95)
Browse files Browse the repository at this point in the history
  • Loading branch information
butschster committed Dec 21, 2023
1 parent 9206d2a commit feb0aab
Show file tree
Hide file tree
Showing 3 changed files with 491 additions and 19 deletions.
135 changes: 134 additions & 1 deletion src/Console/Command/Scaffolder/CentrifugoHandlerCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,145 @@ final class CentrifugoHandlerCommand extends AbstractCommand
#[Option(description: 'Optional, specify a custom namespace')]
private ?string $namespace = null;

#[Option(shortcut: 't', description: 'Service type [connect, subscribe, rpc, refresh, publish]')]
private string $type = 'connect';

#[Option(name: 'with-api', shortcut: 'a', description: 'With API dependency')]
private bool $withApi = false;

public function perform(): int
{
$declaration = $this->createDeclaration(CentrifugoHandlerDeclaration::class);
$declaration = $this->createDeclaration(CentrifugoHandlerDeclaration::class, [
'withApi' => $this->withApi,
]);

$type = match ($this->type) {
'connect' => [
'request' => \RoadRunner\Centrifugo\Request\Connect::class,
'use' => [
\RoadRunner\Centrifugo\Payload\ConnectResponse::class,
],
'body' => $this->createConnectHandlerBody(),
],
'subscribe' => [
'request' => \RoadRunner\Centrifugo\Request\Subscribe::class,
'use' => [
\RoadRunner\Centrifugo\Payload\SubscribeResponse::class,
],
'body' => $this->createSubscribeHandlerBody(),
],
'rpc' => [
'request' => \RoadRunner\Centrifugo\Request\RPC::class,
'use' => [
\RoadRunner\Centrifugo\Payload\RPCResponse::class,
],
'body' => $this->createRpcHandlerBody(),
],
'refresh' => [
'request' => \RoadRunner\Centrifugo\Request\Refresh::class,
'use' => [
\RoadRunner\Centrifugo\Payload\RefreshResponse::class,
],
'body' => $this->createRefreshHandlerBody(),
],
'publish' => [
'request' => \RoadRunner\Centrifugo\Request\Publish::class,
'use' => [
\RoadRunner\Centrifugo\Payload\PublishResponse::class,
],
'body' => $this->createPublishHandlerBody(),
],
default => throw new \InvalidArgumentException('Invalid service type'),
};

$declaration->setType($type);

$this->writeDeclaration($declaration);

return self::SUCCESS;
}

private function createConnectHandlerBody(): string
{
return <<<'PHP'
try {
$request->respond(
new ConnectResponse(
user: '', // User ID
channels: [
// List of channels to subscribe to on connect to Centrifugo
// 'public',
],
)
);
} catch (\Throwable $e) {
$request->error($e->getCode(), $e->getMessage());
}
PHP;
}

private function createSubscribeHandlerBody(): string
{
return <<<'PHP'
try {
// Here you can check if user is allowed to subscribe to requested channel
if ($request->channel !== 'public') {
$request->disconnect('403', 'Channel is not allowed.');
return;
}
$request->respond(
new SubscribeResponse()
);
} catch (\Throwable $e) {
$request->error($e->getCode(), $e->getMessage());
}
PHP;
}

private function createRpcHandlerBody(): string
{
return <<<'PHP'
$result = match ($request->method) {
'ping' => ['pong' => 'pong', 'code' => 200],
default => ['error' => 'Not found', 'code' => 404]
};
try {
$request->respond(
new RPCResponse(
data: $result
)
);
} catch (\Throwable $e) {
$request->error($e->getCode(), $e->getMessage());
}
PHP;
}

private function createRefreshHandlerBody(): string
{
return <<<'PHP'
try {
$request->respond(
new RefreshResponse(...)
);
} catch (\Throwable $e) {
$request->error($e->getCode(), $e->getMessage());
}
PHP;
}

private function createPublishHandlerBody(): string
{
return <<<'PHP'
try {
$request->respond(
new PublishResponse(...)
);
} catch (\Throwable $e) {
$request->error($e->getCode(), $e->getMessage());
}
PHP;
}
}
64 changes: 54 additions & 10 deletions src/Scaffolder/Declaration/CentrifugoHandlerDeclaration.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,70 @@
namespace Spiral\RoadRunnerBridge\Scaffolder\Declaration;

use RoadRunner\Centrifugo\CentrifugoApiInterface;
use RoadRunner\Centrifugo\Request\RequestInterface;
use Spiral\RoadRunnerBridge\Centrifugo\ServiceInterface;
use Spiral\Scaffolder\Config\ScaffolderConfig;
use Spiral\Scaffolder\Declaration\AbstractDeclaration;
use Spiral\Scaffolder\Declaration\HasInstructions;

class CentrifugoHandlerDeclaration extends AbstractDeclaration
class CentrifugoHandlerDeclaration extends AbstractDeclaration implements HasInstructions
{
public const TYPE = 'centrifugo-handler';

public function __construct(
ScaffolderConfig $config,
string $name,
?string $comment = null,
?string $namespace = null,
private bool $withApi = false,
) {
parent::__construct($config, $name, $comment, $namespace);
}

public function declare(): void
{
$this->namespace->addUse(CentrifugoApiInterface::class);

$this->class->setFinal();

$this->class->addMethod('__construct')
if ($this->withApi) {
$this->namespace->addUse(CentrifugoApiInterface::class);

$this->class->addMethod('__construct')
->setPublic()
->addPromotedParameter('api')
->setPrivate()
->setReadOnly()
->setType(CentrifugoApiInterface::class);
}
}

public function setType(array $data): void
{
$this->namespace->addUse($data['request']);
$this->namespace->addUse(RequestInterface::class);
$this->namespace->addUse(ServiceInterface::class);

foreach ($data['use'] as $use) {
$this->namespace->addUse($use);
}

$className = (new \ReflectionClass($data['request']))->getShortName();

$this->class
->addImplement(ServiceInterface::class)
->addMethod('handle')
->setPublic()
->addPromotedParameter('api')
->setPrivate()
->setReadOnly()
->setType(CentrifugoApiInterface::class)
;
->setBody($data['body'] ?? '// Put your code here')
->setReturnType('void')
->setComment("\n@param {$className} \$request")
->addParameter('request')
->setType(RequestInterface::class);
}

$this->class->addMethod('handle')->setPublic()->setReturnType('void');
public function getInstructions(): array
{
return [
'Register your handler in `app/config/centrifugo.php` file. Read more in the documentation: https://spiral.dev/docs/websockets-services#service-registration',
'Read more about Centrifugo handlers: https://spiral.dev/docs/websockets-services',
];
}
}
Loading

0 comments on commit feb0aab

Please sign in to comment.