├── .gitignore ├── README.md ├── README.zh-cn.md ├── composer.json ├── phpunit.xml └── src ├── Contracts ├── ThriftClient.php └── ThriftServer.php ├── Facades └── ThriftClient.php ├── Middleware └── ThriftServerMiddleware.php ├── ThriftClientImpl.php ├── ThriftServerImpl.php └── ThriftServiceProvider.php /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | composer.lock 3 | vendor/ 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # thrift-laravel 2 | 3 | use Thrift in Laravel 4 | 5 | # How to use 6 | 7 | ## Server side 8 | 9 | 1. `composer require angejia/thrift-laravel` 10 | 2. add provider to `app.providers`: 11 | ```` 12 | \Angejia\Thrift\ThriftServiceProvider::class 13 | ```` 14 | 3. setting `thrift.providers` in file `config/thrift.php`: 15 | ```` 16 | // first is service name, defined in thrift file 17 | // second in Service implement reference, e.g. 18 | // class ImageServcie implement \Angejia\ImageServiceIf 19 | ['Angejia.ImageService', \Angejia\ImageService::class], 20 | ```` 21 | 4. add Middleware `\Angejia\Thrift\Middleware\ThriftServerMiddleware::class` to `app\Http\Kernel` 22 | 23 | in default, the request to `/rpc` will be process by Middleware, 24 | if you want to change this, please extend `ThriftServerMiddleware` and overwrite `process` method 25 | 26 | ## Client side 27 | 28 | 1. `composer require angejia/thrift-laravel` 29 | 2. add provider in `app.providers`: 30 | ```` 31 | \Angejia\Thrift\ThriftServiceProvider::class 32 | ```` 33 | 3. setting `thrift.depends` in file `config/thrift.php`: 34 | ```` 35 | // key is url 36 | // value is array of service name 37 | "http://localhost/rpc" => [ 38 | 'Angejia.ImageService', 39 | ] 40 | ```` 41 | 4. usage: 42 | ```` 43 | /** @var \Angejia\Thrift\Contracts\ThriftClient $thriftClient */ 44 | $thriftClient = app(\Angejia\Thrift\Contracts\ThriftClient::class); 45 | /** @var \Angejia\ImageServiceIf $imageService */ 46 | $imageService = $thriftClient->with('Angejia.ImageService'); 47 | 48 | $result = $imageService->foo(); 49 | ```` 50 | 51 | # TODO 52 | 53 | * Unittest 54 | -------------------------------------------------------------------------------- /README.zh-cn.md: -------------------------------------------------------------------------------- 1 | # thrift-laravel 2 | 3 | 在Laravel中使用Thrift 4 | 5 | # 如何使用 6 | 7 | ## 服务端 8 | 9 | 1. `composer require angejia/thrift-laravel` 10 | 2. 在配置`app.providers`中添加一行: 11 | ```` 12 | \Angejia\Thrift\ThriftServiceProvider::class 13 | ```` 14 | 3. 在配置文件`config/thrift.php`中,设置`thrift.providers`: 15 | ```` 16 | // 第一个是 service name, 在thrift中定义 17 | // 第二个是实现该service的类全名,实现了thrift生成的接口 18 | // class ImageServcie implement \Angejia\ImageServiceIf 19 | ['Angejia.ImageService', \Angejia\ImageService::class], 20 | ```` 21 | 4. 在`app\Http\Kernel`中添加 Middleware `\Angejia\Thrift\Middleware\ThriftServerMiddleware::class` 22 | 23 | 默认会处理`/rpc`上的请求,如果需要更改此规则,请继承此类并覆盖`process`方法 24 | 25 | ## 客户端 26 | 27 | 1. `composer require angejia/thrift-laravel` 28 | 2. 在配置`app.providers`中添加一行: 29 | ```` 30 | \Angejia\Thrift\ThriftServiceProvider::class 31 | ```` 32 | 3. 在配置文件`config/thrift.php`中,设置`thrift.depends`: 33 | ```` 34 | // key 为url 35 | // value 为 service name 的数组 36 | "http://localhost/rpc" => [ 37 | 'Angejia.ImageService', 38 | ] 39 | ```` 40 | 4. 使用: 41 | ```` 42 | /** @var \Angejia\Thrift\Contracts\ThriftClient $thriftClient */ 43 | $thriftClient = app(\Angejia\Thrift\Contracts\ThriftClient::class); 44 | /** @var \Angejia\ImageServiceIf $imageService */ 45 | $imageService = $thriftClient->with('Angejia.ImageService'); 46 | 47 | $result = $imageService->foo(); 48 | ```` 49 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angejia/thrift-laravel", 3 | "description": "use Thrift in Laravel", 4 | "keywords": [ 5 | "thrift", 6 | "laravel" 7 | ], 8 | "license": "MIT", 9 | "require": { 10 | "php": ">=7.0.0", 11 | "illuminate/http": "5.1.*|5.2.*", 12 | "illuminate/support": "5.1.*|5.2.*", 13 | "symfony/http-foundation": "2.7.*|2.8.*|3.0.*", 14 | "angejia/thrift": "^0.9.3.4" 15 | }, 16 | "require-dev": { 17 | "mockery/mockery": "~0.9", 18 | "phpunit/phpunit": "~4.0" 19 | }, 20 | "autoload": { 21 | "psr-4": { 22 | "Angejia\\Thrift\\": "src/" 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | ./tests/ 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/Contracts/ThriftClient.php: -------------------------------------------------------------------------------- 1 | thrift_server = $thrift_server; 19 | } 20 | 21 | /** 22 | * @param \Illuminate\Http\Request $request 23 | * @return Response 24 | */ 25 | protected function process($request) 26 | { 27 | $input_trans = new TMemoryBuffer($request->getContent()); 28 | $output_trans = new TMemoryBuffer(); 29 | 30 | $input_trans->open(); 31 | $this->thrift_server->process($input_trans, $output_trans); 32 | $buffer = $output_trans->getBuffer(); 33 | $output_trans->close(); 34 | return (new Response($buffer, 200)) 35 | ->header('Content-Type', 'application/x-thrift'); 36 | } 37 | 38 | /** 39 | * Handle an incoming request. 40 | * 41 | * @param \Illuminate\Http\Request $request 42 | * @param \Closure $next 43 | * @return mixed 44 | */ 45 | public function handle($request, Closure $next) 46 | { 47 | if ($request->is('rpc') && 'application/x-thrift' == $request->header('CONTENT_TYPE')) { 48 | return $this->process($request); 49 | } else { 50 | return $next($request); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/ThriftClientImpl.php: -------------------------------------------------------------------------------- 1 | config = $config; 27 | 28 | $this->protocol_class = $this->config->get("thrift.protocol", TBinaryProtocolAccelerated::class); 29 | $this->transport_class = $this->config->get("thrift.transport", TCurlClient::class); 30 | 31 | $arr = $this->config->get('thrift.depends'); 32 | foreach ($arr as $endpoint => $name) { 33 | if (empty($endpoint)) { 34 | throw new \InvalidArgumentException( 35 | 'The endpoint of ' 36 | . (is_array($name) ? implode($name, ', ') : $name) 37 | . ' doesn\'t exist!' 38 | ); 39 | } 40 | $info = parse_url($endpoint); 41 | $info = [ 42 | 'host' => $info['host'], 43 | 'port' => $info['port']??80, 44 | 'uri' => $info['path']??'/', 45 | 'scheme' => $info['scheme']??'http', 46 | ]; 47 | $info['port'] = intval($info['port']); 48 | 49 | if (is_string($name)) { 50 | $this->providers[$name] = $info; 51 | } elseif (is_array($name)) { 52 | foreach ($name as $name_) { 53 | /** @var string $name_ */ 54 | $this->providers[$name_] = $info; 55 | } 56 | } 57 | } 58 | } 59 | 60 | /** 61 | * @param string $name 62 | * @return mixed 63 | */ 64 | public function with($name) 65 | { 66 | $info = $this->providers[$name]; 67 | $transport = new $this->transport_class($info['host'], $info['port'], $info['uri'], $info['scheme']); 68 | 69 | /** @var TProtocol $protocol */ 70 | $protocol = new $this->protocol_class($transport); 71 | $protocol = new TMultiplexedProtocol($protocol, $name); 72 | 73 | $client_class = str_replace(".", "\\", $name) . "Client"; 74 | $client = new $client_class($protocol); 75 | 76 | return $client; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/ThriftServerImpl.php: -------------------------------------------------------------------------------- 1 | config = $config; 41 | 42 | $this->protocol_class = $this->config->get("thrift.protocol", TBinaryProtocolAccelerated::class); 43 | } 44 | 45 | /** 46 | * 向 $mprocessor注册所有配置文件中的服务 47 | */ 48 | protected function registerAll() 49 | { 50 | if (is_null($this->mprocessor)) { 51 | $providers = $this->config->get("thrift.providers"); 52 | $this->mprocessor = new TMultiplexedProcessor(); 53 | foreach ($providers as $provider) { 54 | if (is_string($provider)) { 55 | $this->register($provider); 56 | } elseif (is_array($provider)) { 57 | $this->register($provider[0], $provider[1]); 58 | } else { 59 | throw new \InvalidArgumentException("provider must be name or array. now it's " . var_export($provider)); 60 | } 61 | } 62 | } 63 | } 64 | 65 | /** 66 | * 注册 name 的 handler 和 processor 67 | * 68 | * @param $name 69 | * @param string|null $handler_class 70 | * @param string|null $processor_class 71 | */ 72 | public function register($name, $handler_class = null, $processor_class = null) 73 | { 74 | $class_name = str_replace(".", "\\", $name); 75 | if ($handler_class === null) { 76 | $handler_class = $class_name . "Handler"; 77 | } 78 | if ($processor_class === null) { 79 | $processor_class = $class_name . "Processor"; 80 | } 81 | 82 | $handler = new $handler_class(); 83 | $processor = new $processor_class($handler); 84 | $this->mprocessor->registerProcessor($name, $processor); 85 | } 86 | 87 | /** 88 | * 处理 RPC 请求 89 | * @param TTransport $input_trans 90 | * @param TTransport $output_trans 91 | */ 92 | public function process(TTransport $input_trans, TTransport $output_trans) 93 | { 94 | /* @var TProtocol $input_proto */ 95 | $input_proto = new $this->protocol_class($input_trans); 96 | /* @var TProtocol $output_proto */ 97 | $output_proto = new $this->protocol_class($output_trans); 98 | if (!$input_trans->isOpen()) { 99 | $input_trans->open(); 100 | } 101 | if (!$output_trans->isOpen()) { 102 | $output_trans->open(); 103 | } 104 | 105 | try { 106 | $this->registerAll(); 107 | 108 | $this->mprocessor->process($input_proto, $output_proto); 109 | } catch (\Exception $e) { 110 | $app_exception = new TApplicationException( 111 | $e->getMessage() . PHP_EOL . $e->getFile() . ':' . $e->getLine(), 112 | TApplicationException::UNKNOWN 113 | ); 114 | $output_proto->writeMessageBegin(__METHOD__, TMessageType::EXCEPTION, 0); 115 | $app_exception->write($output_proto); 116 | $output_proto->writeMessageEnd(); 117 | $output_proto->getTransport()->flush(); 118 | \Log::error($e); 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/ThriftServiceProvider.php: -------------------------------------------------------------------------------- 1 | app->singleton('Angejia\Thrift\Contracts\ThriftServer', 'Angejia\Thrift\ThriftServerImpl'); 24 | $this->app->singleton('Angejia\Thrift\Contracts\ThriftClient', 'Angejia\Thrift\ThriftClientImpl'); 25 | } 26 | 27 | /** 28 | * Get the services provided by the provider. 29 | * 30 | * @return array 31 | */ 32 | public function provides() 33 | { 34 | return ['Angejia\Thrift\Contracts\ThriftServer', 'Angejia\Thrift\Contracts\ThriftClient']; 35 | } 36 | } 37 | --------------------------------------------------------------------------------