增加 gRPC

This commit is contained in:
iVampireSP.com 2023-11-01 12:02:17 +08:00
parent 32ffc373ad
commit 48f8e35458
No known key found for this signature in database
GPG Key ID: 2F7B001CA27A8132
13 changed files with 1751 additions and 144 deletions

2
.gitignore vendored
View File

@ -17,3 +17,5 @@ yarn-error.log
/.fleet /.fleet
/.idea /.idea
/.vscode /.vscode
rr
.rr.yaml

View File

@ -1,66 +1,9 @@
<p align="center"><a href="https://laravel.com" target="_blank"><img src="https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg" width="400" alt="Laravel Logo"></a></p> # Install Protoc
<p align="center"> ```bash
<a href="https://github.com/laravel/framework/actions"><img src="https://github.com/laravel/framework/workflows/tests/badge.svg" alt="Build Status"></a> ./vendor/bin/rr download-protoc-binary
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/dt/laravel/framework" alt="Total Downloads"></a> ```
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/v/laravel/framework" alt="Latest Stable Version"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/l/laravel/framework" alt="License"></a>
</p>
## About Laravel ```bash
protoc --plugin=/Users/ivampiresp/.bin/protoc-gen-php-grpc --php_out=. --php-grpc_out=. resources/proto/pinger.proto
Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as: ```
- [Simple, fast routing engine](https://laravel.com/docs/routing).
- [Powerful dependency injection container](https://laravel.com/docs/container).
- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.
- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).
- Database agnostic [schema migrations](https://laravel.com/docs/migrations).
- [Robust background job processing](https://laravel.com/docs/queues).
- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).
Laravel is accessible, powerful, and provides tools required for large, robust applications.
## Learning Laravel
Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework.
You may also try the [Laravel Bootcamp](https://bootcamp.laravel.com), where you will be guided through building a modern Laravel application from scratch.
If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains over 2000 video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.
## Laravel Sponsors
We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the Laravel [Patreon page](https://patreon.com/taylorotwell).
### Premium Partners
- **[Vehikl](https://vehikl.com/)**
- **[Tighten Co.](https://tighten.co)**
- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**
- **[64 Robots](https://64robots.com)**
- **[Cubet Techno Labs](https://cubettech.com)**
- **[Cyber-Duck](https://cyber-duck.co.uk)**
- **[Many](https://www.many.co.uk)**
- **[Webdock, Fast VPS Hosting](https://www.webdock.io/en)**
- **[DevSquad](https://devsquad.com)**
- **[Curotec](https://www.curotec.com/services/technologies/laravel/)**
- **[OP.GG](https://op.gg)**
- **[WebReinvent](https://webreinvent.com/?utm_source=laravel&utm_medium=github&utm_campaign=patreon-sponsors)**
- **[Lendio](https://lendio.com)**
## Contributing
Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).
## Code of Conduct
In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).
## Security Vulnerabilities
If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed.
## License
The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).

View File

@ -0,0 +1,139 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class Init extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'app:init';
/**
* The console command description.
*
* @var string
*/
protected $description = '初始化应用程序(用于容器启动时)。';
/**
* Execute the console command.
*/
public function handle(): void
{
// 检查是否已经初始化
$lock = storage_path('init.lock');
if (file_exists($lock)) {
$this->warn("另一个初始化进程正在运行中。如果确定没有其他进程在运行,请手动删除 {$lock} 文件。");
// 如果有 --start 参数,则启动 Web 服务
if ($this->option('start')) {
$this->warn("正在等待另一个进程初始化完成。");
// 一直等待锁文件被删除
while (file_exists($lock)) {
sleep(1);
}
$this->call('serve');
}
return;
}
$this->info("上锁。");
// 加锁
file_put_contents($lock, '');
// 检测有无 .env
if (!file_exists(base_path('.env'))) {
// 复制 .env.example
$this->info("复制 .env.example 为 .env");
copy(base_path('.env.example'), base_path('.env'));
}
// 检测是否有 APP_KEY
$APP_KEY = env('APP_KEY');
if (empty($APP_KEY)) {
// 初始化
$this->info("生成应用程序密钥。");
$this->call('key:generate');
}
$this->info("初始化 storage 目录。");
// 初始化 storage 目录
$this->initStorageDir();
$this->info("初始化数据库。");
// force migrate
$this->call('migrate', [
'--force' => true,
]);
$this->info("生成缓存。");
$this->call('optimize');
$this->info("解锁");
// 解锁
unlink($lock);
// 输出
$this->info('应用程序初始化完成。');
if ($this->option('start')) {
$this->info('启动 Web 服务。');
$this->call('octane:start', [
'--host' => '0.0.0.0'
]);
}
}
private function initStorageDir(): void
{
// 检测 storage 下的目录是否正确
$storage = storage_path();
// 有无 app 目录
if (!is_dir($storage . '/app')) {
mkdir($storage . '/app');
// 有无 public 目录
if (!is_dir($storage . '/app/public')) {
mkdir($storage . '/app/public');
}
}
// 有无 framework 目录
if (!is_dir($storage . '/framework')) {
mkdir($storage . '/framework');
// 有无 cache 目录
if (!is_dir($storage . '/framework/cache')) {
mkdir($storage . '/framework/cache');
}
// 有无 sessions 目录
if (!is_dir($storage . '/framework/sessions')) {
mkdir($storage . '/framework/sessions');
}
// 有无 testing 目录
if (!is_dir($storage . '/framework/testing')) {
mkdir($storage . '/framework/testing');
}
// 有无 views 目录
if (!is_dir($storage . '/framework/views')) {
mkdir($storage . '/framework/views');
}
}
// 有无 logs 目录
if (!is_dir($storage . '/logs')) {
mkdir($storage . '/logs');
}
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace App\Console\Commands;
use App\Services\PingerService;
use Spiral\RoadRunner\Worker;
use Illuminate\Console\Command;
use Spiral\RoadRunner\GRPC\Server;
use Spiral\RoadRunner\GRPC\Invoker;
use App\Services\gRPC\Pinger\PingerInterface;
class Works extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'app:works';
/**
* The console command description.
*
* @var string
*/
protected $description = '启动 gRPC 服务';
/**
* Execute the console command.
*/
public function handle()
{
$server = new Server(new Invoker(), [
'debug' => false,
]);
$server->registerService(PingerInterface::class, new PingerService());
$server->serve(Worker::create());
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace App\Services;
use Spiral\RoadRunner\GRPC;
use App\Services\gRPC\Pinger\PingRequest;
use App\Services\gRPC\Pinger\PingResponse;
use App\Services\gRPC\Pinger\PingerInterface;
use Spiral\RoadRunner\GRPC\ContextInterface;
class PingerService implements PingerInterface
{
public function ping(ContextInterface $ctx, PingRequest $in): PingResponse
{
return new PingResponse([
'status_code' => rand(200, 500)
]);
}
}

Binary file not shown.

View File

@ -0,0 +1,58 @@
<?php
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: resources/proto/pinger.proto
namespace App\Services\gRPC\Pinger;
use Google\Protobuf\Internal\GPBType;
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\GPBUtil;
/**
* Generated from protobuf message <code>pinger.PingRequest</code>
*/
class PingRequest extends \Google\Protobuf\Internal\Message
{
/**
* Generated from protobuf field <code>string url = 1;</code>
*/
protected $url = '';
/**
* Constructor.
*
* @param array $data {
* Optional. Data for populating the Message object.
*
* @type string $url
* }
*/
public function __construct($data = NULL) {
\App\Services\gRPC\GPBMetadata\Pinger::initOnce();
parent::__construct($data);
}
/**
* Generated from protobuf field <code>string url = 1;</code>
* @return string
*/
public function getUrl()
{
return $this->url;
}
/**
* Generated from protobuf field <code>string url = 1;</code>
* @param string $var
* @return $this
*/
public function setUrl($var)
{
GPBUtil::checkString($var, True);
$this->url = $var;
return $this;
}
}

View File

@ -0,0 +1,58 @@
<?php
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: resources/proto/pinger.proto
namespace App\Services\gRPC\Pinger;
use Google\Protobuf\Internal\GPBType;
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\GPBUtil;
/**
* Generated from protobuf message <code>pinger.PingResponse</code>
*/
class PingResponse extends \Google\Protobuf\Internal\Message
{
/**
* Generated from protobuf field <code>int32 status_code = 1;</code>
*/
protected $status_code = 0;
/**
* Constructor.
*
* @param array $data {
* Optional. Data for populating the Message object.
*
* @type int $status_code
* }
*/
public function __construct($data = NULL) {
\App\Services\gRPC\GPBMetadata\Pinger::initOnce();
parent::__construct($data);
}
/**
* Generated from protobuf field <code>int32 status_code = 1;</code>
* @return int
*/
public function getStatusCode()
{
return $this->status_code;
}
/**
* Generated from protobuf field <code>int32 status_code = 1;</code>
* @param int $var
* @return $this
*/
public function setStatusCode($var)
{
GPBUtil::checkInt32($var);
$this->status_code = $var;
return $this;
}
}

View File

@ -0,0 +1,22 @@
<?php
# Generated by the protocol buffer compiler (roadrunner-server/grpc). DO NOT EDIT!
# source: resources/proto/pinger.proto
namespace App\Services\gRPC\Pinger;
use Spiral\RoadRunner\GRPC;
interface PingerInterface extends GRPC\ServiceInterface
{
// GRPC specific service name.
public const NAME = "pinger.Pinger";
/**
* @param GRPC\ContextInterface $ctx
* @param PingRequest $in
* @return PingResponse
*
* @throws GRPC\Exception\InvokeException
*/
public function ping(GRPC\ContextInterface $ctx, PingRequest $in): PingResponse;
}

View File

@ -8,10 +8,13 @@
"php": "^8.1", "php": "^8.1",
"guzzlehttp/guzzle": "^7.2", "guzzlehttp/guzzle": "^7.2",
"laravel/framework": "^10.10", "laravel/framework": "^10.10",
"laravel/octane": "*", "laravel/octane": "^2.1",
"laravel/sanctum": "^3.2", "laravel/sanctum": "^3.2",
"laravel/tinker": "^2.8", "laravel/tinker": "^2.8",
"pusher/pusher-php-server": "^7.2", "pusher/pusher-php-server": "^7.2",
"spiral/roadrunner-cli": "^2.5.0",
"spiral/roadrunner-grpc": "^3.1",
"spiral/roadrunner-http": "^3.0.1",
"tightenco/ziggy": "^1.8" "tightenco/ziggy": "^1.8"
}, },
"require-dev": { "require-dev": {

1240
composer.lock generated

File diff suppressed because it is too large Load Diff

221
config/octane.php Normal file
View File

@ -0,0 +1,221 @@
<?php
use Laravel\Octane\Contracts\OperationTerminated;
use Laravel\Octane\Events\RequestHandled;
use Laravel\Octane\Events\RequestReceived;
use Laravel\Octane\Events\RequestTerminated;
use Laravel\Octane\Events\TaskReceived;
use Laravel\Octane\Events\TaskTerminated;
use Laravel\Octane\Events\TickReceived;
use Laravel\Octane\Events\TickTerminated;
use Laravel\Octane\Events\WorkerErrorOccurred;
use Laravel\Octane\Events\WorkerStarting;
use Laravel\Octane\Events\WorkerStopping;
use Laravel\Octane\Listeners\CollectGarbage;
use Laravel\Octane\Listeners\DisconnectFromDatabases;
use Laravel\Octane\Listeners\EnsureUploadedFilesAreValid;
use Laravel\Octane\Listeners\EnsureUploadedFilesCanBeMoved;
use Laravel\Octane\Listeners\FlushTemporaryContainerInstances;
use Laravel\Octane\Listeners\FlushUploadedFiles;
use Laravel\Octane\Listeners\ReportException;
use Laravel\Octane\Listeners\StopWorkerIfNecessary;
use Laravel\Octane\Octane;
return [
/*
|--------------------------------------------------------------------------
| Octane Server
|--------------------------------------------------------------------------
|
| This value determines the default "server" that will be used by Octane
| when starting, restarting, or stopping your server via the CLI. You
| are free to change this to the supported server of your choosing.
|
| Supported: "roadrunner", "swoole"
|
*/
'server' => env('OCTANE_SERVER', 'roadrunner'),
/*
|--------------------------------------------------------------------------
| Force HTTPS
|--------------------------------------------------------------------------
|
| When this configuration value is set to "true", Octane will inform the
| framework that all absolute links must be generated using the HTTPS
| protocol. Otherwise your links may be generated using plain HTTP.
|
*/
'https' => env('OCTANE_HTTPS', false),
/*
|--------------------------------------------------------------------------
| Octane Listeners
|--------------------------------------------------------------------------
|
| All of the event listeners for Octane's events are defined below. These
| listeners are responsible for resetting your application's state for
| the next request. You may even add your own listeners to the list.
|
*/
'listeners' => [
WorkerStarting::class => [
EnsureUploadedFilesAreValid::class,
EnsureUploadedFilesCanBeMoved::class,
],
RequestReceived::class => [
...Octane::prepareApplicationForNextOperation(),
...Octane::prepareApplicationForNextRequest(),
//
],
RequestHandled::class => [
//
],
RequestTerminated::class => [
// FlushUploadedFiles::class,
],
TaskReceived::class => [
...Octane::prepareApplicationForNextOperation(),
//
],
TaskTerminated::class => [
//
],
TickReceived::class => [
...Octane::prepareApplicationForNextOperation(),
//
],
TickTerminated::class => [
//
],
OperationTerminated::class => [
FlushTemporaryContainerInstances::class,
// DisconnectFromDatabases::class,
// CollectGarbage::class,
],
WorkerErrorOccurred::class => [
ReportException::class,
StopWorkerIfNecessary::class,
],
WorkerStopping::class => [
//
],
],
/*
|--------------------------------------------------------------------------
| Warm / Flush Bindings
|--------------------------------------------------------------------------
|
| The bindings listed below will either be pre-warmed when a worker boots
| or they will be flushed before every new request. Flushing a binding
| will force the container to resolve that binding again when asked.
|
*/
'warm' => [
...Octane::defaultServicesToWarm(),
],
'flush' => [
//
],
/*
|--------------------------------------------------------------------------
| Octane Cache Table
|--------------------------------------------------------------------------
|
| While using Swoole, you may leverage the Octane cache, which is powered
| by a Swoole table. You may set the maximum number of rows as well as
| the number of bytes per row using the configuration options below.
|
*/
'cache' => [
'rows' => 1000,
'bytes' => 10000,
],
/*
|--------------------------------------------------------------------------
| Octane Swoole Tables
|--------------------------------------------------------------------------
|
| While using Swoole, you may define additional tables as required by the
| application. These tables can be used to store data that needs to be
| quickly accessed by other workers on the particular Swoole server.
|
*/
'tables' => [
'example:1000' => [
'name' => 'string:1000',
'votes' => 'int',
],
],
/*
|--------------------------------------------------------------------------
| File Watching
|--------------------------------------------------------------------------
|
| The following list of files and directories will be watched when using
| the --watch option offered by Octane. If any of the directories and
| files are changed, Octane will automatically reload your workers.
|
*/
'watch' => [
'app',
'bootstrap',
'config',
'database',
'public/**/*.php',
'resources/**/*.php',
'routes',
'composer.lock',
'.env',
],
/*
|--------------------------------------------------------------------------
| Garbage Collection Threshold
|--------------------------------------------------------------------------
|
| When executing long-lived PHP scripts such as Octane, memory can build
| up before being cleared by PHP. You can force Octane to run garbage
| collection if your application consumes this amount of megabytes.
|
*/
'garbage' => 50,
/*
|--------------------------------------------------------------------------
| Maximum Execution Time
|--------------------------------------------------------------------------
|
| The following setting configures the maximum execution time for requests
| being handled by Octane. You may set this value to 0 to indicate that
| there isn't a specific time limit on Octane request execution time.
|
*/
'max_execution_time' => 30,
];

View File

@ -0,0 +1,18 @@
syntax = "proto3";
option php_namespace = "App\\Services\\gRPC\\Pinger";
option php_metadata_namespace = "App\\Services\\gRPC\\GPBMetadata";
package pinger;
service Pinger {
rpc ping (PingRequest) returns (PingResponse) {}
}
message PingRequest {
string url = 1;
}
message PingResponse {
int32 status_code = 1;
}