You've already forked Php-Template
feat/grpc #25
9
.rr.yaml
9
.rr.yaml
@@ -10,8 +10,15 @@ grpc:
|
||||
listen: "tcp://0.0.0.0:9001"
|
||||
pool:
|
||||
command: "php grpc-worker.php"
|
||||
num_workers: ${GRPC_WORKERS:-4}
|
||||
allocate_timeout: 5s
|
||||
reset_timeout: 5s
|
||||
destroy_timeout: 5s
|
||||
stream_timeout: 5s
|
||||
reflection: ${GRPC_REFLECTION:-true}
|
||||
health_check: ${GRPC_HEALTH_CHECK:-true}
|
||||
proto:
|
||||
- "proto/helloworld.proto"
|
||||
- "protos/example.proto"
|
||||
|
||||
http:
|
||||
pool:
|
||||
|
||||
25
generated/GRPC/GPBMetadata/Example.php
Normal file
25
generated/GRPC/GPBMetadata/Example.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# NO CHECKED-IN PROTOBUF GENCODE
|
||||
# source: protos/example.proto
|
||||
|
||||
namespace GRPC\GPBMetadata;
|
||||
|
||||
class Example
|
||||
{
|
||||
public static $is_initialized = false;
|
||||
|
||||
public static function initOnce() {
|
||||
$pool = \Google\Protobuf\Internal\DescriptorPool::getGeneratedPool();
|
||||
|
||||
if (static::$is_initialized == true) {
|
||||
return;
|
||||
}
|
||||
$pool->internalAddGeneratedFile(
|
||||
"\x0A\xE5\x01\x0A\x14protos/example.proto\x12\x0Ahelloworld\"\x1C\x0A\x0CHelloRequest\x12\x0C\x0A\x04name\x18\x01 \x01(\x09\"\x1D\x0A\x0AHelloReply\x12\x0F\x0A\x07message\x18\x01 \x01(\x092I\x0A\x07Greeter\x12>\x0A\x08SayHello\x12\x18.helloworld.HelloRequest\x1A\x16.helloworld.HelloReply\"\x00B1Z\x0Dproto/greeter\xCA\x02\x0CGRPC\\Greeter\xE2\x02\x10GRPC\\GPBMetadatab\x06proto3"
|
||||
, true);
|
||||
|
||||
static::$is_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
22
generated/GRPC/Greeter/GreeterInterface.php
Normal file
22
generated/GRPC/Greeter/GreeterInterface.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
# Generated by the protocol buffer compiler (roadrunner-server/grpc). DO NOT EDIT!
|
||||
# source: protos/example.proto
|
||||
|
||||
namespace GRPC\Greeter;
|
||||
|
||||
use Spiral\RoadRunner\GRPC;
|
||||
|
||||
interface GreeterInterface extends GRPC\ServiceInterface
|
||||
{
|
||||
// GRPC specific service name.
|
||||
public const NAME = "helloworld.Greeter";
|
||||
|
||||
/**
|
||||
* @param GRPC\ContextInterface $ctx
|
||||
* @param HelloRequest $in
|
||||
* @return HelloReply
|
||||
*
|
||||
* @throws GRPC\Exception\InvokeException
|
||||
*/
|
||||
public function SayHello(GRPC\ContextInterface $ctx, HelloRequest $in): HelloReply;
|
||||
}
|
||||
61
generated/GRPC/Greeter/HelloReply.php
Normal file
61
generated/GRPC/Greeter/HelloReply.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# NO CHECKED-IN PROTOBUF GENCODE
|
||||
# source: protos/example.proto
|
||||
|
||||
namespace GRPC\Greeter;
|
||||
|
||||
use Google\Protobuf\Internal\GPBType;
|
||||
use Google\Protobuf\Internal\GPBUtil;
|
||||
use Google\Protobuf\RepeatedField;
|
||||
|
||||
/**
|
||||
* The response message containing the greetings
|
||||
*
|
||||
* Generated from protobuf message <code>helloworld.HelloReply</code>
|
||||
*/
|
||||
class HelloReply extends \Google\Protobuf\Internal\Message
|
||||
{
|
||||
/**
|
||||
* Generated from protobuf field <code>string message = 1;</code>
|
||||
*/
|
||||
protected $message = '';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $data {
|
||||
* Optional. Data for populating the Message object.
|
||||
*
|
||||
* @type string $message
|
||||
* }
|
||||
*/
|
||||
public function __construct($data = NULL) {
|
||||
\GRPC\GPBMetadata\Example::initOnce();
|
||||
parent::__construct($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>string message = 1;</code>
|
||||
* @return string
|
||||
*/
|
||||
public function getMessage()
|
||||
{
|
||||
return $this->message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>string message = 1;</code>
|
||||
* @param string $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setMessage($var)
|
||||
{
|
||||
GPBUtil::checkString($var, True);
|
||||
$this->message = $var;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
61
generated/GRPC/Greeter/HelloRequest.php
Normal file
61
generated/GRPC/Greeter/HelloRequest.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# NO CHECKED-IN PROTOBUF GENCODE
|
||||
# source: protos/example.proto
|
||||
|
||||
namespace GRPC\Greeter;
|
||||
|
||||
use Google\Protobuf\Internal\GPBType;
|
||||
use Google\Protobuf\Internal\GPBUtil;
|
||||
use Google\Protobuf\RepeatedField;
|
||||
|
||||
/**
|
||||
* The request message containing the user's name.
|
||||
*
|
||||
* Generated from protobuf message <code>helloworld.HelloRequest</code>
|
||||
*/
|
||||
class HelloRequest extends \Google\Protobuf\Internal\Message
|
||||
{
|
||||
/**
|
||||
* Generated from protobuf field <code>string name = 1;</code>
|
||||
*/
|
||||
protected $name = '';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $data {
|
||||
* Optional. Data for populating the Message object.
|
||||
*
|
||||
* @type string $name
|
||||
* }
|
||||
*/
|
||||
public function __construct($data = NULL) {
|
||||
\GRPC\GPBMetadata\Example::initOnce();
|
||||
parent::__construct($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>string name = 1;</code>
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>string name = 1;</code>
|
||||
* @param string $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setName($var)
|
||||
{
|
||||
GPBUtil::checkString($var, True);
|
||||
$this->name = $var;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
14
grpc-worker.php
Normal file
14
grpc-worker.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
use Siteworxpro\App\Grpc;
|
||||
|
||||
require __DIR__ . '/vendor/autoload.php';
|
||||
|
||||
try {
|
||||
$server = new Grpc();
|
||||
$server->start();
|
||||
} catch (\Exception $e) {
|
||||
echo $e->getMessage();
|
||||
|
||||
exit(1);
|
||||
}
|
||||
151
makefile
151
makefile
@@ -1,59 +1,120 @@
|
||||
help:
|
||||
# Makefile (enhanced)
|
||||
SHELL := /bin/sh
|
||||
.DEFAULT_GOAL := help
|
||||
|
||||
# Reusable vars
|
||||
DOCKER := docker compose
|
||||
COMPOSER_RUNTIME := composer-runtime
|
||||
DEV_RUNTIME := dev-runtime
|
||||
MIGRATION_CONTAINER := migration-container
|
||||
|
||||
PROTOC_GEN_DIR := ./protoc-gen-php-grpc-2025.1.5-darwin-arm64
|
||||
PROTOC_GEN := $(PROTOC_GEN_DIR)/protoc-gen-php-grpc
|
||||
PROTOC_URL := https://github.com/roadrunner-server/roadrunner/releases/download/v2025.1.5/protoc-gen-php-grpc-2025.1.5-darwin-arm64.tar.gz
|
||||
|
||||
COMPOSER := $(DOCKER) exec $(COMPOSER_RUNTIME) sh -c
|
||||
DEV := $(DOCKER) exec $(DEV_RUNTIME) sh -c
|
||||
|
||||
# Colors
|
||||
GREEN := \033[32m
|
||||
YELLOW := \033[33m
|
||||
RESET := \033[0m
|
||||
|
||||
# Align width for help display
|
||||
HELP_COL_WIDTH := 26
|
||||
|
||||
# Help: auto-generate from targets with "##" comments
|
||||
help: ## Show this help
|
||||
@echo "Available commands:"
|
||||
@echo " start - Start the development runtime container"
|
||||
@echo " sh - Open a shell in the development runtime container"
|
||||
@echo " run - Run the application server in the development runtime container"
|
||||
@echo " stop - Stop and remove the development runtime container"
|
||||
@echo " migrate - Run database migrations in the migration container"
|
||||
@echo " composer-install - Install PHP dependencies in the composer runtime container"
|
||||
@echo " composer-require - Require a PHP package in the composer runtime container (usage: make composer-require package=vendor/package)"
|
||||
@echo " composer-require-dev - Require a PHP package as dev in the composer runtime container (usage: make composer-require-dev package=vendor/package)"
|
||||
@echo " composer-update - Update PHP dependencies in the composer runtime container"
|
||||
@echo " enable-debug - Enable Xdebug in the development runtime container"
|
||||
@echo " enable-coverage - Enable PCOV code coverage in the composer runtime container"
|
||||
@echo " protoc - Generate PHP gRPC code from .proto files"
|
||||
@awk -F':|##' '/^[a-zA-Z0-9._-]+:.*##/ {printf " %-$(HELP_COL_WIDTH)s - %s\n", $$1, $$3}' $(MAKEFILE_LIST) | sort
|
||||
|
||||
composer-install:
|
||||
docker compose exec composer-runtime sh -c "composer install --no-interaction --prefer-dist --optimize-autoloader --ignore-platform-reqs"
|
||||
start: ## Start the development runtime container
|
||||
@printf "$(GREEN)Starting $(DEV_RUNTIME)$(RESET)\n"
|
||||
$(DOCKER) up $(DEV_RUNTIME) -d --no-recreate
|
||||
|
||||
composer-require:
|
||||
docker compose exec composer-runtime sh -c "composer require $(package) --ignore-platform-reqs"
|
||||
sh: ## Open a shell in the development runtime container
|
||||
@$(MAKE) start
|
||||
$(DOCKER) exec $(DEV_RUNTIME) sh
|
||||
|
||||
composer-require-dev:
|
||||
docker compose exec composer-runtime sh -c "composer require --dev $(package) --ignore-platform-reqs"
|
||||
run: ## Run the application server in the development runtime container
|
||||
@$(MAKE) start
|
||||
$(DEV) "rr serve"
|
||||
|
||||
composer-update:
|
||||
docker compose exec composer-runtime sh -c "composer update --no-interaction --prefer-dist --optimize-autoloader --ignore-platform-reqs"
|
||||
stop: ## Stop and remove the development runtime container
|
||||
@printf "$(YELLOW)Stopping all containers$(RESET)\n"
|
||||
$(DOCKER) down
|
||||
|
||||
migrate:
|
||||
docker compose up migration-container
|
||||
restart: ## Restart dev container (stop + start)
|
||||
@$(MAKE) stop
|
||||
@$(MAKE) start
|
||||
|
||||
enable-coverage:
|
||||
${MAKE} start
|
||||
docker compose exec composer-runtime sh -c "bin/pcov.sh"
|
||||
rebuild: ## Rebuild containers (useful after Dockerfile changes)
|
||||
@printf "$(YELLOW)Rebuilding containers$(RESET)\n"
|
||||
$(DOCKER) build
|
||||
$(DOCKER) up --force-recreate --build -d
|
||||
|
||||
start:
|
||||
docker compose up dev-runtime -d --no-recreate
|
||||
ps: ## Show docker compose ps
|
||||
$(DOCKER) ps
|
||||
|
||||
sh:
|
||||
${MAKE} start
|
||||
docker compose exec dev-runtime sh
|
||||
migrate: ## Run database migrations in the migration container
|
||||
$(DOCKER) up $(MIGRATION_CONTAINER)
|
||||
|
||||
run:
|
||||
${MAKE} start
|
||||
docker compose exec dev-runtime sh -c "rr serve"
|
||||
# Composer helpers
|
||||
composer-install: ## Install PHP dependencies in the composer runtime container
|
||||
$(COMPOSER) "composer install --no-interaction --prefer-dist --optimize-autoloader --ignore-platform-reqs"
|
||||
|
||||
enable-debug:
|
||||
${MAKE} start
|
||||
docker compose exec dev-runtime sh -c "bin/xdebug.sh"
|
||||
composer-require: ## Require a PHP package in the composer runtime container (usage: make composer-require package=vendor/package)
|
||||
ifndef package
|
||||
$(error package variable is required: make composer-require package=vendor/package)
|
||||
endif
|
||||
$(COMPOSER) "composer require $(package) --ignore-platform-reqs"
|
||||
|
||||
stop:
|
||||
docker compose down
|
||||
composer-require-dev: ## Require a PHP package as dev in the composer runtime container (usage: make composer-require-dev package=vendor/package)
|
||||
ifndef package
|
||||
$(error package variable is required: make composer-require-dev package=vendor/package)
|
||||
endif
|
||||
$(COMPOSER) "composer require --dev $(package) --ignore-platform-reqs"
|
||||
|
||||
protoc:
|
||||
protoc --plugin=protoc-gen-php-grpc \
|
||||
--php_out=./generated \
|
||||
--php-grpc_out=./generated \
|
||||
protos/example.proto
|
||||
composer-update: ## Update PHP dependencies in the composer runtime container
|
||||
$(COMPOSER) "composer update --no-interaction --prefer-dist --optimize-autoloader --ignore-platform-reqs"
|
||||
|
||||
.PHONY: help enable-coverage start sh run enable-debug stop protoc
|
||||
enable-debug: ## Enable Xdebug in the development runtime container
|
||||
@$(MAKE) start
|
||||
$(DEV) "bin/xdebug.sh"
|
||||
|
||||
enable-coverage: ## Enable PCOV code coverage in the composer runtime container
|
||||
@$(MAKE) start
|
||||
$(COMPOSER) "bin/pcov.sh"
|
||||
|
||||
protoc: ## Generate PHP gRPC code from .proto files
|
||||
@printf "$(GREEN)Setting up protoc-gen-php-grpc plugin$(RESET)\n"
|
||||
@curl -LOs $(PROTOC_URL)
|
||||
@tar -xzf protoc-gen-php-grpc-2025.1.5-darwin-arm64.tar.gz
|
||||
@printf "$(GREEN)Generating PHP gRPC code from .proto files$(RESET)\n"
|
||||
@protoc --plugin=./protoc-gen-php-grpc-2025.1.5-darwin-arm64/protoc-gen-php-grpc \
|
||||
--php_out=./generated \
|
||||
--php-grpc_out=./generated \
|
||||
protos/example.proto
|
||||
@printf "$(GREEN)Cleaning up protoc-gen-php-grpc plugin files$(RESET)\n"
|
||||
@rm -rf $(PROTOC_GEN_DIR) protoc-gen-php-grpc-2025.1.5-darwin-arm64.tar.gz
|
||||
|
||||
# Developer tasks
|
||||
lint: ## Run linting (phpcs/phpstan) in composer runtime
|
||||
@$(DOCKER) up $(COMPOSER_RUNTIME) -d --no-recreate
|
||||
$(COMPOSER) "composer run-script tests:lint || true"
|
||||
$(COMPOSER) "composer run-script tests:phpstan || true"
|
||||
|
||||
fmt: ## Format code (php-cs-fixer)
|
||||
@$(DOCKER) up $(COMPOSER_RUNTIME) -d --no-recreate
|
||||
$(COMPOSER) "composer run-script tests:lint:fix"
|
||||
|
||||
test: ## Run test suite (phpunit)
|
||||
$(COMPOSER) "composer run-script tests:unit || true"
|
||||
|
||||
# Convenience aliases
|
||||
dev: run ## Alias for start
|
||||
ci: composer-install test ## CI-like local flow
|
||||
down: stop ## Alias for stop
|
||||
up: start ## Alias for start
|
||||
|
||||
.PHONY: help start sh run stop restart rebuild ps logs migrate composer-install composer-require composer-require-dev composer-update enable-debug enable-coverage protoc lint fmt test check-lock dev ci
|
||||
@@ -5,10 +5,7 @@ use Siteworxpro\App\Api;
|
||||
require __DIR__ . '/vendor/autoload.php';
|
||||
|
||||
try {
|
||||
// Instantiate the ExternalServer class
|
||||
$server = new Api();
|
||||
|
||||
// Start the server
|
||||
$server->startServer();
|
||||
} catch (JsonException $e) {
|
||||
echo $e->getMessage();
|
||||
|
||||
17
src/Grpc.php
17
src/Grpc.php
@@ -4,11 +4,20 @@ declare(strict_types=1);
|
||||
|
||||
namespace Siteworxpro\App;
|
||||
|
||||
use GRPC\Greeter\GreeterInterface;
|
||||
use Siteworxpro\App\GrpcHandlers\GreeterHandler;
|
||||
use Siteworxpro\App\Services\Facades\Config;
|
||||
use Spiral\RoadRunner\GRPC\Invoker;
|
||||
use Spiral\RoadRunner\GRPC\Server;
|
||||
use Spiral\RoadRunner\Worker;
|
||||
|
||||
/**
|
||||
* Class Grpc
|
||||
*
|
||||
* starts a gRPC server using RoadRunner
|
||||
*
|
||||
* @package Siteworxpro\App
|
||||
*/
|
||||
class Grpc
|
||||
{
|
||||
/**
|
||||
@@ -19,14 +28,18 @@ class Grpc
|
||||
Kernel::boot();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the gRPC server
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function start(): int
|
||||
{
|
||||
$server = new Server(new Invoker(), [
|
||||
'debug' => (bool) Config::get('app.debug'),
|
||||
]);
|
||||
|
||||
$server->registerService(GreeterInterface::class, new Greeter());
|
||||
|
||||
$server->registerService(GreeterInterface::class, new GreeterHandler());
|
||||
$server->serve(Worker::create());
|
||||
|
||||
return 0;
|
||||
|
||||
21
src/GrpcHandlers/GreeterHandler.php
Normal file
21
src/GrpcHandlers/GreeterHandler.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Siteworxpro\App\GrpcHandlers;
|
||||
|
||||
use GRPC\Greeter\GreeterInterface;
|
||||
use GRPC\Greeter\HelloReply;
|
||||
use GRPC\Greeter\HelloRequest;
|
||||
use Spiral\RoadRunner\GRPC;
|
||||
|
||||
class GreeterHandler implements GreeterInterface
|
||||
{
|
||||
public function SayHello(GRPC\ContextInterface $ctx, HelloRequest $in): HelloReply // phpcs:ignore
|
||||
{
|
||||
$reply = new HelloReply();
|
||||
$reply->setMessage('Hello ' . $in->getName());
|
||||
|
||||
return $reply;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user