正在显示
28 个修改的文件
包含
2436 行增加
和
8 行删除
| @@ -2,15 +2,21 @@ | @@ -2,15 +2,21 @@ | ||
| 2 | 2 | ||
| 3 | namespace AukeySwrpc; | 3 | namespace AukeySwrpc; |
| 4 | 4 | ||
| 5 | +use AukeySwrpc\Commands\SwrpcGenCom; | ||
| 6 | +use AukeySwrpc\Commands\SwrcpTestCom; | ||
| 7 | +use AukeySwrpc\Commands\SwrpcServerCom; | ||
| 5 | use Illuminate\Support\ServiceProvider; | 8 | use Illuminate\Support\ServiceProvider; |
| 6 | 9 | ||
| 7 | -class SwrpcProvider extends ServiceProvider | 10 | +class AukeySwrpcProvider extends ServiceProvider |
| 8 | { | 11 | { |
| 9 | public function boot() | 12 | public function boot() |
| 10 | { | 13 | { |
| 11 | $this->loadMigrationsFrom(__DIR__ . '/database/migrations'); | 14 | $this->loadMigrationsFrom(__DIR__ . '/database/migrations'); |
| 12 | if ($this->app->runningInConsole()) { | 15 | if ($this->app->runningInConsole()) { |
| 13 | $this->commands([ | 16 | $this->commands([ |
| 17 | + SwrpcServerCom::class, | ||
| 18 | + SwrpcGenCom::class, | ||
| 19 | + SwrcpTestCom::class, | ||
| 14 | ]); | 20 | ]); |
| 15 | } | 21 | } |
| 16 | } | 22 | } |
src/BaseService.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace AukeySwrpc; | ||
| 4 | + | ||
| 5 | + | ||
| 6 | +use AukeySwrpc\Request\SyncRequest; | ||
| 7 | +use AukeySwrpc\Tracer\TracerContext; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * Class BaseService | ||
| 11 | + * | ||
| 12 | + * @package App\Clients | ||
| 13 | + * @author pengjch 2024314 11:26:45 | ||
| 14 | + */ | ||
| 15 | +class BaseService | ||
| 16 | +{ | ||
| 17 | + protected $serviceKey; | ||
| 18 | + protected $traceContext = null; | ||
| 19 | + | ||
| 20 | + /** | ||
| 21 | + * @return static | ||
| 22 | + * @author 2021-03-14 11:25:18 | ||
| 23 | + */ | ||
| 24 | + public static function factory() | ||
| 25 | + { | ||
| 26 | + return new static(); | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + /** | ||
| 30 | + * BaseService constructor. | ||
| 31 | + */ | ||
| 32 | + public function __construct() | ||
| 33 | + { | ||
| 34 | + $this->init(); | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + /** | ||
| 38 | + * @author pengjch 2024314 11:33:22 | ||
| 39 | + */ | ||
| 40 | + protected function init() | ||
| 41 | + { | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + /** | ||
| 45 | + * @param $serviceKey | ||
| 46 | + * @author pengjch 2024314 11:31:57 | ||
| 47 | + */ | ||
| 48 | + protected function setService($serviceKey) | ||
| 49 | + { | ||
| 50 | + $this->serviceKey = $serviceKey; | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + /** | ||
| 54 | + * 链路追踪上下文 | ||
| 55 | + * | ||
| 56 | + * @param TracerContext|null $context | ||
| 57 | + * @return $this | ||
| 58 | + * @author pengjch 2024314 11:27:45 | ||
| 59 | + */ | ||
| 60 | + public function trace(?TracerContext $context = null) | ||
| 61 | + { | ||
| 62 | + $this->traceContext = $context; | ||
| 63 | + return $this; | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + /** | ||
| 67 | + * 调用远程服务 | ||
| 68 | + * | ||
| 69 | + * @param $method | ||
| 70 | + * @param $args | ||
| 71 | + * @return mixed | ||
| 72 | + * @throws \Exception | ||
| 73 | + * @author pengjch 2024-03-14 11:25:18 | ||
| 74 | + */ | ||
| 75 | + protected function callRemoteService($method, $args) | ||
| 76 | + { | ||
| 77 | + $serviceNs = $this->getTargetServiceNamespace(); | ||
| 78 | + $method = $serviceNs . '_' . $method; | ||
| 79 | + $client = ClientManger::getInstance($this->serviceKey); | ||
| 80 | + $request = SyncRequest::create($method, $args, $this->traceContext); | ||
| 81 | + return $client->send($request); | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | + /** | ||
| 85 | + * 调用本地服务 | ||
| 86 | + * | ||
| 87 | + * @param $method | ||
| 88 | + * @param $args | ||
| 89 | + * @return string | ||
| 90 | + * @author pengjch 2024-03-14 11:25:18 | ||
| 91 | + */ | ||
| 92 | + protected function callLocalService($method, $args) | ||
| 93 | + { | ||
| 94 | + $serviceNs = $this->getTargetServiceNamespace(); | ||
| 95 | + return call_user_func_array([$serviceNs::factory(), $method], $args); | ||
| 96 | + } | ||
| 97 | + | ||
| 98 | + /** | ||
| 99 | + * 获取目标调用类命名空间 | ||
| 100 | + * | ||
| 101 | + * @return string | ||
| 102 | + * @author pengjch 2024314 12:6:8 | ||
| 103 | + */ | ||
| 104 | + protected function getTargetServiceNamespace(): string | ||
| 105 | + { | ||
| 106 | + $moduleName = $this->extractModuleName(); | ||
| 107 | + /** @var \Nwidart\Modules\Laravel\Module $module */ | ||
| 108 | + $module = \Nwidart\Modules\Facades\Module::find($moduleName); | ||
| 109 | + $moduleNs = ltrim(str_replace([base_path(), '/'], ['', '\\'], $module->getPath()), '\\'); | ||
| 110 | + return $moduleNs . '\\Services\\' . $this->extractServiceName(); | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | + /** | ||
| 114 | + * 根据调用类提前模块名称 | ||
| 115 | + * | ||
| 116 | + * @return false|string | ||
| 117 | + * @author pengjch 2024314 12:0:17 | ||
| 118 | + */ | ||
| 119 | + protected function extractModuleName() | ||
| 120 | + { | ||
| 121 | + $calledClass = get_called_class(); | ||
| 122 | + $module = str_replace(['App\Clients\\', '\\'], ['', '_'], $calledClass); | ||
| 123 | + return substr($module, 0, strrpos($module, '_')); | ||
| 124 | + } | ||
| 125 | + | ||
| 126 | + /** | ||
| 127 | + * 根据调用类提前service名称 | ||
| 128 | + * | ||
| 129 | + * @return false|string | ||
| 130 | + * @author pengjch 2024314 12:0:34 | ||
| 131 | + */ | ||
| 132 | + protected function extractServiceName() | ||
| 133 | + { | ||
| 134 | + $calledClass = get_called_class(); | ||
| 135 | + return substr($calledClass, strrpos($calledClass, '\\') + 1); | ||
| 136 | + } | ||
| 137 | + | ||
| 138 | + /** | ||
| 139 | + * __call | ||
| 140 | + * | ||
| 141 | + * @param $method | ||
| 142 | + * @param $args | ||
| 143 | + * @return false|mixed | ||
| 144 | + * @throws \Exception | ||
| 145 | + * @author 2021-03-14 11:25:18 | ||
| 146 | + */ | ||
| 147 | + public function __call($method, $args) | ||
| 148 | + { | ||
| 149 | + switch (env('SERVICE_CALL_STRATEGY', 'remote')) { | ||
| 150 | + case 'remote': | ||
| 151 | + return $this->callRemoteService($method, $args); | ||
| 152 | + case 'local': | ||
| 153 | + return $this->callLocalService($method, $args); | ||
| 154 | + default: | ||
| 155 | + throw new \Exception('error strategy'); | ||
| 156 | + } | ||
| 157 | + } | ||
| 158 | +} |
src/Client.php
0 → 100755
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace AukeySwrpc; | ||
| 4 | + | ||
| 5 | + | ||
| 6 | +use Swoole\Client as SwClient; | ||
| 7 | +use AukeySwrpc\Exceptions\RpcException; | ||
| 8 | +use AukeySwrpc\Packer\PackerInterface; | ||
| 9 | +use AukeySwrpc\Packer\SerializeLengthPacker; | ||
| 10 | +use AukeySwrpc\Register\RegisterInterface; | ||
| 11 | +use AukeySwrpc\Register\Service; | ||
| 12 | +use AukeySwrpc\Request\Request; | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * Class Client | ||
| 16 | + * | ||
| 17 | + * @package Swrpc | ||
| 18 | + * @author pengjch 202439 11:36:25 | ||
| 19 | + */ | ||
| 20 | +class Client | ||
| 21 | +{ | ||
| 22 | + protected $services = []; | ||
| 23 | + protected $connects = []; | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + const STRATEGY_RANDOM = 1; | ||
| 27 | + const STRATEGY_WEIGHT = 2; | ||
| 28 | + | ||
| 29 | + protected $mode; | ||
| 30 | + protected $timeout = 3; | ||
| 31 | + protected array $options; | ||
| 32 | + protected string $module; | ||
| 33 | + protected int $strategy; | ||
| 34 | + protected ?RegisterInterface $register = null; | ||
| 35 | + protected ?PackerInterface $packer = null; | ||
| 36 | + | ||
| 37 | + protected array $defaultOptions | ||
| 38 | + = [ | ||
| 39 | + 'open_length_check' => true, | ||
| 40 | + 'package_length_type' => 'N', | ||
| 41 | + 'package_length_offset' => 0, //第N个字节是包长度的值 | ||
| 42 | + 'package_body_offset' => 4, //第几个字节开始计算长度 | ||
| 43 | + 'package_max_length' => 81920, //协议最大长度 | ||
| 44 | + ]; | ||
| 45 | + | ||
| 46 | + /** | ||
| 47 | + * Client constructor. | ||
| 48 | + * | ||
| 49 | + * @param string $module | ||
| 50 | + * @param array $services | ||
| 51 | + * @param int $mode | ||
| 52 | + * @param int $timeout | ||
| 53 | + * @param array $options | ||
| 54 | + */ | ||
| 55 | + public function __construct(string $module, array $services, $mode = SWOOLE_SOCK_TCP, $timeout = 3, $options = []) | ||
| 56 | + { | ||
| 57 | + $this->module = $module; | ||
| 58 | + $this->services = $services; | ||
| 59 | + $this->mode = $mode; | ||
| 60 | + $this->timeout = $timeout; | ||
| 61 | + if (empty($options)) { | ||
| 62 | + $options = $this->defaultOptions; | ||
| 63 | + } | ||
| 64 | + $this->options = $options; | ||
| 65 | + | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + /** | ||
| 69 | + * @param string $module | ||
| 70 | + * @param string $host | ||
| 71 | + * @param int $port | ||
| 72 | + * @param int $mode | ||
| 73 | + * @param array $options | ||
| 74 | + * @return Client | ||
| 75 | + * @author pengjch 2024313 18:31:17 | ||
| 76 | + */ | ||
| 77 | + public static function create( | ||
| 78 | + string $module, | ||
| 79 | + string $host, | ||
| 80 | + int $port, | ||
| 81 | + $mode = SWOOLE_SOCK_TCP, | ||
| 82 | + $timeout = 3, | ||
| 83 | + $options = [] | ||
| 84 | + ): Client { | ||
| 85 | + $service = Service::build($host, $port, 1); | ||
| 86 | + return new static($module, [$service], $mode, $timeout, $options); | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + /** | ||
| 90 | + * @param string $module | ||
| 91 | + * @param RegisterInterface $register | ||
| 92 | + * @param int $strategy | ||
| 93 | + * @param int $mode | ||
| 94 | + * @param int $timeout | ||
| 95 | + * @param array $options | ||
| 96 | + * @return Client | ||
| 97 | + * @author pengjch 2024313 18:31:22 | ||
| 98 | + */ | ||
| 99 | + public static function createBalancer( | ||
| 100 | + string $module, | ||
| 101 | + RegisterInterface $register, | ||
| 102 | + $strategy = self::STRATEGY_RANDOM, | ||
| 103 | + $mode = SWOOLE_SOCK_TCP, | ||
| 104 | + $timeout = 3, | ||
| 105 | + $options = [] | ||
| 106 | + ): Client { | ||
| 107 | + $client = new static($module, [], $mode, $timeout, $options); | ||
| 108 | + $client->strategy = $strategy; | ||
| 109 | + $client->addRegister($register); | ||
| 110 | + return $client; | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | + /** | ||
| 114 | + * @param RegisterInterface $register | ||
| 115 | + * @return $this | ||
| 116 | + * @author pengjch 2024313 18:27:20 | ||
| 117 | + */ | ||
| 118 | + public function addRegister(RegisterInterface $register): Client | ||
| 119 | + { | ||
| 120 | + $this->register = $register; | ||
| 121 | + $this->services = $this->register->getServices($this->module); | ||
| 122 | + return $this; | ||
| 123 | + } | ||
| 124 | + | ||
| 125 | + /** | ||
| 126 | + * @param PackerInterface $packer | ||
| 127 | + * @return $this | ||
| 128 | + * @author pengjch 2024313 18:27:24 | ||
| 129 | + */ | ||
| 130 | + public function addPacker(PackerInterface $packer): Client | ||
| 131 | + { | ||
| 132 | + $this->packer = $packer; | ||
| 133 | + return $this; | ||
| 134 | + } | ||
| 135 | + | ||
| 136 | + /** | ||
| 137 | + * @return SwClient | ||
| 138 | + * @throws RpcException | ||
| 139 | + * @author pengjch 2024313 18:23:37 | ||
| 140 | + */ | ||
| 141 | + public function connect(): SwClient | ||
| 142 | + { | ||
| 143 | + $n = count($this->services); | ||
| 144 | + if ($n == 0) { | ||
| 145 | + throw new RpcException('No services available'); | ||
| 146 | + } | ||
| 147 | + | ||
| 148 | + /** @var Service $service */ | ||
| 149 | + if ($n == 1) { //单个服务节点 | ||
| 150 | + $service = $this->services[0]; | ||
| 151 | + $key = $service->getHost() . '_' . $service->getPort(); | ||
| 152 | + } else { //多个服务节点 | ||
| 153 | + $key = $this->getConnectKey(); | ||
| 154 | + } | ||
| 155 | + | ||
| 156 | + if (isset($this->connects[$key]) && $this->connects[$key]->isConnected()) { | ||
| 157 | + return $this->connects[$key]; | ||
| 158 | + } | ||
| 159 | + $client = new SwClient($this->mode ?: SWOOLE_SOCK_TCP); | ||
| 160 | + if (!$client->connect($service->getHost(), $service->getPort(), $this->timeout ?? 3)) { | ||
| 161 | + throw new RpcException("connect failed. Error: {$client->errCode}"); | ||
| 162 | + } | ||
| 163 | + $client->set($this->options); | ||
| 164 | + $this->connects[$key] = $client; | ||
| 165 | + return $this->connects[$key]; | ||
| 166 | + } | ||
| 167 | + | ||
| 168 | + /** | ||
| 169 | + * 发送请求 | ||
| 170 | + * | ||
| 171 | + * @param Request $request | ||
| 172 | + * @return mixed | ||
| 173 | + * @throws RpcException | ||
| 174 | + * @author pengjch 202439 13:35:25 | ||
| 175 | + */ | ||
| 176 | + public function send(Request $request) | ||
| 177 | + { | ||
| 178 | + /** @var \Swoole\Client $conn */ | ||
| 179 | + $conn = $this->connect(); | ||
| 180 | + | ||
| 181 | + if (!$this->packer) { | ||
| 182 | + $this->packer = new SerializeLengthPacker([ | ||
| 183 | + 'package_length_type' => $options['package_length_type'] ?? 'N', | ||
| 184 | + 'package_body_offset' => $options['package_body_offset'] ?? 4, | ||
| 185 | + ]); | ||
| 186 | + } | ||
| 187 | + | ||
| 188 | + $request->setModule($this->module); | ||
| 189 | + $conn->send($this->packer->pack($request)); | ||
| 190 | + | ||
| 191 | + /** @var Response $response */ | ||
| 192 | + $response = @unserialize($conn->recv()); | ||
| 193 | + if (!($response instanceof Response)) { | ||
| 194 | + throw new RpcException('The server return type is not a Swrpc\Response'); | ||
| 195 | + } | ||
| 196 | + if ($response->code == Response::RES_ERROR) { | ||
| 197 | + throw new RpcException($response->msg); | ||
| 198 | + } | ||
| 199 | + | ||
| 200 | + return $response->data['result'] ?? null; | ||
| 201 | + } | ||
| 202 | + | ||
| 203 | + /** | ||
| 204 | + * @return string | ||
| 205 | + * @author pengjch 2024313 18:20:38 | ||
| 206 | + */ | ||
| 207 | + public function getConnectKey(): string | ||
| 208 | + { | ||
| 209 | + /** @var Service $service */ | ||
| 210 | + if ($this->strategy == self::STRATEGY_RANDOM) { | ||
| 211 | + $service = array_rand($this->services); | ||
| 212 | + return $service->getHost() . '_' . $service->getPort(); | ||
| 213 | + } else { | ||
| 214 | + /** @var Service $service */ | ||
| 215 | + foreach ($this->services as $service) { | ||
| 216 | + $totalWeight += $service->getWeight(); | ||
| 217 | + $sort[] = $service->getWeight(); | ||
| 218 | + $serviceArr[] = $service->toArray(); | ||
| 219 | + } | ||
| 220 | + | ||
| 221 | + array_multisort($serviceArr, SORT_DESC, $sort); | ||
| 222 | + | ||
| 223 | + $start = 0; | ||
| 224 | + $rand = rand(1, $totalWeight); | ||
| 225 | + foreach ($serviceArr as $service) { | ||
| 226 | + if ($start + $service['weight'] >= $rand) { | ||
| 227 | + return $service['host'] . '_' . $service['port']; | ||
| 228 | + } | ||
| 229 | + $start = $start + $service['weight']; | ||
| 230 | + } | ||
| 231 | + } | ||
| 232 | + } | ||
| 233 | + | ||
| 234 | + /** | ||
| 235 | + * 关闭客户端连接 | ||
| 236 | + * | ||
| 237 | + * @return mixed | ||
| 238 | + * @author pengjch 2024310 9:16:46 | ||
| 239 | + */ | ||
| 240 | + public function close() | ||
| 241 | + { | ||
| 242 | + foreach ($this->connects as $connect) { | ||
| 243 | + $connect->close(true); | ||
| 244 | + } | ||
| 245 | + } | ||
| 246 | + | ||
| 247 | + /** | ||
| 248 | + * 刷新节点服务信息 | ||
| 249 | + * 客户端使用长连接的情况下,需要起一个定时器来定时更新节点服务信息 | ||
| 250 | + * | ||
| 251 | + * @author pengjch 2024313 18:24:23 | ||
| 252 | + */ | ||
| 253 | + public function refreshServices() | ||
| 254 | + { | ||
| 255 | + if ($this->register) { | ||
| 256 | + $this->services = $this->register->getServices($this->module); | ||
| 257 | + $this->connects = []; | ||
| 258 | + } | ||
| 259 | + } | ||
| 260 | +} |
src/ClientManger.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace AukeySwrpc; | ||
| 4 | + | ||
| 5 | +use AukeySwrpc\Client; | ||
| 6 | +use AukeySwrpc\Register\Consul; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * 客户端管理器 | ||
| 10 | + * Class ClientManger | ||
| 11 | + * | ||
| 12 | + * @package App\Clients | ||
| 13 | + * @author pengjch 202435 23:20:30 | ||
| 14 | + */ | ||
| 15 | +class ClientManger | ||
| 16 | +{ | ||
| 17 | + /** @var \Hprose\Client */ | ||
| 18 | + private static $clients; | ||
| 19 | + | ||
| 20 | + private function __sleep() | ||
| 21 | + { | ||
| 22 | + } | ||
| 23 | + | ||
| 24 | + private function __wakeup() | ||
| 25 | + { | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | + private function __construct() | ||
| 29 | + { | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + /** | ||
| 33 | + * @param $key | ||
| 34 | + * @return Client | ||
| 35 | + * @throws \Exception | ||
| 36 | + * @author pengjch 2024314 12:34:8 | ||
| 37 | + */ | ||
| 38 | + public static function getInstance($key): Client | ||
| 39 | + { | ||
| 40 | + if (!isset(self::$clients[$key])) { | ||
| 41 | + $registerUri = env('SWRPC_REGISTER_URI'); | ||
| 42 | + if ($registerUri) { //从注册中心获取连接地址 | ||
| 43 | + self::$clients[$key] = Client::createBalancer($key, new Consul($registerUri)); | ||
| 44 | + } else { //直连模式 | ||
| 45 | + $conf = explode(':', env($key)); | ||
| 46 | + if (!$conf || count($conf) != 2) { | ||
| 47 | + throw new \Exception('.env未配置' . $key); | ||
| 48 | + } | ||
| 49 | + self::$clients[$key] = Client::create($key, $conf[0], $conf[1]); | ||
| 50 | + } | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + return self::$clients[$key]; | ||
| 54 | + } | ||
| 55 | +} |
src/Commands/SwrpcGenCom.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace AukeySwrpc\Commands; | ||
| 4 | + | ||
| 5 | + | ||
| 6 | +use Illuminate\Console\Command; | ||
| 7 | +use Nwidart\Modules\Facades\Module; | ||
| 8 | +use AukeySwrpc\LogicService; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * Class SwrpcGenCom | ||
| 12 | + * | ||
| 13 | + * @package App\Console\Commands | ||
| 14 | + * @author pengjch 2024314 12:13:7 | ||
| 15 | + */ | ||
| 16 | +class SwrpcGenCom extends Command | ||
| 17 | +{ | ||
| 18 | + /** | ||
| 19 | + * The name and signature of the console command. | ||
| 20 | + * | ||
| 21 | + * @var string | ||
| 22 | + */ | ||
| 23 | + protected $signature = 'swrpc:gen {-m|--module=}'; | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * The console command description. | ||
| 27 | + * | ||
| 28 | + * @var string | ||
| 29 | + */ | ||
| 30 | + protected $description = 'swrpc客户端代码生成器'; | ||
| 31 | + | ||
| 32 | + /** | ||
| 33 | + * Create a new command instance. | ||
| 34 | + * | ||
| 35 | + * @return void | ||
| 36 | + */ | ||
| 37 | + public function __construct() | ||
| 38 | + { | ||
| 39 | + parent::__construct(); | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | + /** | ||
| 43 | + * Execute the console command. | ||
| 44 | + * | ||
| 45 | + * @return int | ||
| 46 | + * @throws \ReflectionException | ||
| 47 | + */ | ||
| 48 | + public function handle() | ||
| 49 | + { | ||
| 50 | +// $serviceKey = env('SWRPC_SERVER_NAME'); | ||
| 51 | +// if (!$serviceKey) { | ||
| 52 | +// $this->error('SWRPC_SERVER_NAME未设置'); | ||
| 53 | +// return -1; | ||
| 54 | +// } | ||
| 55 | + | ||
| 56 | + $filters = []; | ||
| 57 | + $specifyModules = $this->option('module') ? explode(',', $this->option('module')) : []; | ||
| 58 | + $modules = Module::all(); | ||
| 59 | + print_r($modules);exit(); | ||
| 60 | + /** @var \Nwidart\Modules\Laravel\Module $module */ | ||
| 61 | + foreach ($modules as $module) { | ||
| 62 | + if ($module->getName() == 'Common') { | ||
| 63 | + continue; | ||
| 64 | + } | ||
| 65 | + //如果有指定moudle,则只有指定的moudle会生成,否则会生成全部 | ||
| 66 | + if (count($specifyModules) > 0 && !in_array($module->getName(), $specifyModules)) { | ||
| 67 | + continue; | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + $moduleName = $module->getName(); | ||
| 71 | + $modulePath = str_replace('_', '/', $moduleName); | ||
| 72 | + | ||
| 73 | + //create module dir | ||
| 74 | + $basePath = base_path('app/Clients/' . $modulePath); | ||
| 75 | + if (!is_dir($basePath)) { | ||
| 76 | + $this->mkdir($basePath); | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + //target service namespace | ||
| 80 | + $namespace = ltrim(str_replace([base_path(), '/'], ['', '\\'], $module->getPath()), '\\') . '\\Services'; | ||
| 81 | + | ||
| 82 | + //fetch file | ||
| 83 | + $servicePath = $module->getPath() . '/Services'; | ||
| 84 | + if (!is_dir($servicePath)) { | ||
| 85 | + continue; | ||
| 86 | + } | ||
| 87 | + $queues = scandir($servicePath); | ||
| 88 | + while (count($queues) > 0) { | ||
| 89 | + $file = array_shift($queues); | ||
| 90 | + if ($file == '.' || $file == '..' || in_array($file, $filters)) { | ||
| 91 | + continue; | ||
| 92 | + } | ||
| 93 | + //支持嵌套多层service目录 | ||
| 94 | + if (is_dir($servicePath . '/' . $file)) { | ||
| 95 | + $childrenFiles = scandir($servicePath . '/' . $file); | ||
| 96 | + foreach ($childrenFiles as $f) { | ||
| 97 | + if ($f == '.' || $f == '..' || in_array($f, $filters)) { | ||
| 98 | + continue; | ||
| 99 | + } | ||
| 100 | + array_push($queues, $file . '/' . $f); | ||
| 101 | + } | ||
| 102 | + continue; | ||
| 103 | + } | ||
| 104 | + $class = substr($file, 0, strrpos($file, '.')); | ||
| 105 | + $funcs = $this->parseFunc($namespace, $class); | ||
| 106 | + if (empty($funcs)) { | ||
| 107 | + continue; | ||
| 108 | + } | ||
| 109 | + | ||
| 110 | + //generate proxy file | ||
| 111 | + $proxyPath = $basePath . '/' . $file; | ||
| 112 | + ob_start(); | ||
| 113 | + ob_implicit_flush(false); | ||
| 114 | + include(base_path('app/Clients/client.template.php')); | ||
| 115 | + $content = ob_get_clean(); | ||
| 116 | + if (!file_put_contents($proxyPath, $content)) { | ||
| 117 | + $this->error($proxyPath . ' import failure.'); | ||
| 118 | + } else { | ||
| 119 | + $this->info($proxyPath . ' import success.'); | ||
| 120 | + } | ||
| 121 | + } | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + $this->info('完成.'); | ||
| 125 | + return 0; | ||
| 126 | + } | ||
| 127 | + | ||
| 128 | + /** | ||
| 129 | + * @param $path | ||
| 130 | + * @return bool | ||
| 131 | + * @author pengjch 2024314 12:54:6 | ||
| 132 | + */ | ||
| 133 | + protected function mkdir($path) | ||
| 134 | + { | ||
| 135 | + if (!is_dir($path)) { | ||
| 136 | + $this->mkdir(dirname($path)); | ||
| 137 | + if (!mkdir($path, 0777)) { | ||
| 138 | + return false; | ||
| 139 | + } | ||
| 140 | + } | ||
| 141 | + return true; | ||
| 142 | + } | ||
| 143 | + | ||
| 144 | + /** | ||
| 145 | + * parseFunc | ||
| 146 | + * | ||
| 147 | + * @param $namespace | ||
| 148 | + * @param $class | ||
| 149 | + * @return array | ||
| 150 | + * @throws \ReflectionException | ||
| 151 | + * @author pengjch 202435 16:3:16 | ||
| 152 | + */ | ||
| 153 | + protected function parseFunc($namespace, $class): array | ||
| 154 | + { | ||
| 155 | + $serviceClass = str_replace('/', '\\', $namespace . '\\' . $class); | ||
| 156 | + if (!class_exists($serviceClass)) { | ||
| 157 | + $this->error($serviceClass . '类不存在'); | ||
| 158 | + return []; | ||
| 159 | + } | ||
| 160 | + | ||
| 161 | + try { | ||
| 162 | + $rc = new \ReflectionClass($serviceClass); | ||
| 163 | + } catch (\ReflectionException $e) { | ||
| 164 | + $this->error($serviceClass . $e->getMessage()); | ||
| 165 | + return []; | ||
| 166 | + } | ||
| 167 | + | ||
| 168 | + $serviceObj = $rc->newInstance(); | ||
| 169 | + if (!($serviceObj instanceof LogicService)) { | ||
| 170 | + $this->warn('没有继承\Swrpc\LogicService类,跳过'.get_class($serviceObj)); | ||
| 171 | + return []; | ||
| 172 | + } | ||
| 173 | + | ||
| 174 | + $funcs = []; | ||
| 175 | + foreach ($rc->getMethods() as $method) { | ||
| 176 | + if (in_array($method->getName(), [ | ||
| 177 | + 'factory', | ||
| 178 | + 'initTracer', | ||
| 179 | + 'setModule', | ||
| 180 | + 'setTracerUrl', | ||
| 181 | + 'setParams', | ||
| 182 | + 'setTracerContext', | ||
| 183 | + 'getTracerContext' | ||
| 184 | + ]) | ||
| 185 | + ) { | ||
| 186 | + continue; | ||
| 187 | + } | ||
| 188 | + if (false === $method->isPublic()) { | ||
| 189 | + continue; | ||
| 190 | + } | ||
| 191 | + $line = ''; | ||
| 192 | + if ($returnType = $method->getReturnType()) { | ||
| 193 | + $line .= $returnType->getName(); | ||
| 194 | + } | ||
| 195 | + $line .= ' ' . $method->getName() . '('; | ||
| 196 | + $params = ''; | ||
| 197 | + foreach ($method->getParameters() as $parameter) { | ||
| 198 | + $params .= '$' . $parameter->getName(); | ||
| 199 | + if ($parameter->isOptional() && $value = $parameter->getDefaultValue()) { | ||
| 200 | + if (is_string($value)) { | ||
| 201 | + $params .= '="' . $value . '"'; | ||
| 202 | + } else { | ||
| 203 | + $params .= '=' . $value; | ||
| 204 | + } | ||
| 205 | + } | ||
| 206 | + $params .= ','; | ||
| 207 | + } | ||
| 208 | + $line .= rtrim($params, ','); | ||
| 209 | + $line .= ")\r\n"; | ||
| 210 | + $funcs[] = $line; | ||
| 211 | + } | ||
| 212 | + | ||
| 213 | + if (count($funcs) == 0) { | ||
| 214 | + $this->warn('没有可用的方法', ['service' => $serviceObj->getName()]); | ||
| 215 | + } | ||
| 216 | + | ||
| 217 | + return $funcs; | ||
| 218 | + } | ||
| 219 | +} |
src/Commands/SwrpcServerCom.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace AukeySwrpc\Commands; | ||
| 4 | + | ||
| 5 | + | ||
| 6 | +use AukeySwrpc\ClientManger; | ||
| 7 | +use Illuminate\Console\Command; | ||
| 8 | +use Monolog\Handler\StreamHandler; | ||
| 9 | +use Monolog\Logger; | ||
| 10 | +use Nwidart\Modules\Facades\Module; | ||
| 11 | +use AukeySwrpc\Client; | ||
| 12 | +use AukeySwrpc\LogicService; | ||
| 13 | +use AukeySwrpc\Register\Consul; | ||
| 14 | +use AukeySwrpc\Request\SystemRequest; | ||
| 15 | +use AukeySwrpc\Server; | ||
| 16 | + | ||
| 17 | +/** | ||
| 18 | + * Class SwrpcServerCom | ||
| 19 | + * | ||
| 20 | + * @package App\Console\Commands | ||
| 21 | + * @author pengjch 2024314 12:13:15 | ||
| 22 | + */ | ||
| 23 | +class SwrpcServerCom extends Command | ||
| 24 | +{ | ||
| 25 | + /** | ||
| 26 | + * The name and signature of the console command. | ||
| 27 | + * | ||
| 28 | + * @var string | ||
| 29 | + */ | ||
| 30 | + protected $signature = 'swrpc:server {action=start} {--module=}'; | ||
| 31 | + | ||
| 32 | + /** | ||
| 33 | + * The console command description. | ||
| 34 | + * | ||
| 35 | + * @var string | ||
| 36 | + */ | ||
| 37 | + protected $description = 'swrpc服务端'; | ||
| 38 | + | ||
| 39 | + /** | ||
| 40 | + * Create a new command instance. | ||
| 41 | + * | ||
| 42 | + * @return void | ||
| 43 | + */ | ||
| 44 | + public function __construct() | ||
| 45 | + { | ||
| 46 | + parent::__construct(); | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + protected $pidFile = __DIR__ . '/swrpc.pid'; | ||
| 50 | + | ||
| 51 | + /** | ||
| 52 | + * Execute the console command. | ||
| 53 | + * | ||
| 54 | + * @return int | ||
| 55 | + */ | ||
| 56 | + public function handle() | ||
| 57 | + { | ||
| 58 | + $action = $this->argument('action'); | ||
| 59 | + if ($action == 'start') { | ||
| 60 | + $this->start(); | ||
| 61 | + } elseif ($action == 'stop') { | ||
| 62 | + $this->stop(); | ||
| 63 | + } elseif ($action == 'status') { | ||
| 64 | + $this->status(); | ||
| 65 | + } elseif ($action == 'restart') { | ||
| 66 | + $this->stop(); | ||
| 67 | + sleep(2); | ||
| 68 | + $this->start(); | ||
| 69 | + } | ||
| 70 | + return 0; | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + protected function status() | ||
| 74 | + { | ||
| 75 | + $pid = @file_get_contents($this->pidFile); | ||
| 76 | + if (!$pid) { | ||
| 77 | + $this->error('swrpc未启动'); | ||
| 78 | + return; | ||
| 79 | + } | ||
| 80 | + $res = posix_kill($pid, 0); | ||
| 81 | + if (!$res) { | ||
| 82 | + $this->error('swrpc未启动或已退出'); | ||
| 83 | + return; | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + $client = ClientManger::getInstance(env('SWRPC_SERVER_NAME')); | ||
| 87 | + $records = $client->send(SystemRequest::create('stats', [])); | ||
| 88 | + $this->info('----------swrpc服务端状态---------'); | ||
| 89 | + foreach ((array)$records as $key => $value) { | ||
| 90 | + $this->info($key . ': ' . $value); | ||
| 91 | + } | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + protected function stop() | ||
| 95 | + { | ||
| 96 | + $pid = @file_get_contents($this->pidFile); | ||
| 97 | + if (!$pid) { | ||
| 98 | + $this->error('swrpc未启动'); | ||
| 99 | + return; | ||
| 100 | + } | ||
| 101 | + | ||
| 102 | + $res = posix_kill($pid, SIGTERM); | ||
| 103 | + $res ? $this->info('swrpc停止成功') : $this->info('swrpc停止失败'); | ||
| 104 | + } | ||
| 105 | + | ||
| 106 | + protected function start() | ||
| 107 | + { | ||
| 108 | + $pid = @file_get_contents($this->pidFile); | ||
| 109 | + if ($pid && posix_kill($pid, 0)) { | ||
| 110 | + $this->error('swrpc已启动,请不要重复启动'); | ||
| 111 | + return -1; | ||
| 112 | + } | ||
| 113 | + | ||
| 114 | + $name = env('SWRPC_SERVER_NAME'); | ||
| 115 | + if (!$name) { | ||
| 116 | + $this->error('SWRPC_SERVER_NAME未设置'); | ||
| 117 | + return -1; | ||
| 118 | + } | ||
| 119 | + $host = env('SWRPC_SERVER_HOST'); | ||
| 120 | + if (!$host) { | ||
| 121 | + $this->error('SWRPC_SERVER_HOST未设置'); | ||
| 122 | + return -1; | ||
| 123 | + } | ||
| 124 | + $port = env('SWRPC_SERVER_PORT'); | ||
| 125 | + if (!$port) { | ||
| 126 | + $this->error('SWRPC_SERVER_PORT未设置'); | ||
| 127 | + return -1; | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + $logger = new Logger('swrpc'); | ||
| 131 | + $logger->pushHandler(new StreamHandler(STDOUT, Logger::INFO)); | ||
| 132 | + $server = new Server($name, $host, $port, [ | ||
| 133 | + 'worker_num' => swoole_cpu_num(), | ||
| 134 | + 'pid_file' => $this->pidFile, | ||
| 135 | + ], SWOOLE_PROCESS, SWOOLE_SOCK_TCP, $logger); | ||
| 136 | + | ||
| 137 | + if ($regiserUri = env('SWRPC_REGISTER_URI')) { | ||
| 138 | + $server->addRegister(new Consul($regiserUri)); | ||
| 139 | + } | ||
| 140 | + | ||
| 141 | + $filters = []; | ||
| 142 | + $specifyModules = $this->option('module') ? explode(',', $this->option('module')) : []; | ||
| 143 | + $modules = Module::all(); | ||
| 144 | + /** @var \Nwidart\Modules\Laravel\Module $module */ | ||
| 145 | + foreach ($modules as $module) { | ||
| 146 | + if ($module->getName() == 'Common') { | ||
| 147 | + continue; | ||
| 148 | + } | ||
| 149 | + //如果有指定moudle,则只有指定的moudle会生成,否则会生成全部 | ||
| 150 | + if (count($specifyModules) > 0 && !in_array($module->getName(), $specifyModules)) { | ||
| 151 | + continue; | ||
| 152 | + } | ||
| 153 | + $namespace = ltrim(str_replace([base_path(), '/'], ['', '\\'], $module->getPath()), '\\') . '\\Services\\'; | ||
| 154 | + $servicePath = $module->getPath() . '/Services'; | ||
| 155 | + if (!is_dir($servicePath)) { | ||
| 156 | + continue; | ||
| 157 | + } | ||
| 158 | + $queues = scandir($servicePath); | ||
| 159 | + while (count($queues) > 0) { | ||
| 160 | + $file = array_shift($queues); | ||
| 161 | + if ($file == '.' || $file == '..' || in_array($file, $filters)) { | ||
| 162 | + continue; | ||
| 163 | + } | ||
| 164 | + //支持嵌套多层service目录 | ||
| 165 | + if (is_dir($servicePath . '/' . $file)) { | ||
| 166 | + $childrenFiles = scandir($servicePath . '/' . $file); | ||
| 167 | + foreach ($childrenFiles as $f) { | ||
| 168 | + if ($f == '.' || $f == '..' || in_array($f, $filters)) { | ||
| 169 | + continue; | ||
| 170 | + } | ||
| 171 | + array_push($queues, $file . '/' . $f); | ||
| 172 | + } | ||
| 173 | + continue; | ||
| 174 | + } | ||
| 175 | + $class = substr($file, 0, strrpos($file, '.')); | ||
| 176 | + $serviceObj = $this->build($namespace, $class); | ||
| 177 | + if (!$serviceObj) { | ||
| 178 | + continue; | ||
| 179 | + } | ||
| 180 | + if (!($serviceObj instanceof LogicService)) { | ||
| 181 | + $this->warn('没有继承\Swrpc\LogicService类,跳过' . get_class($serviceObj)); | ||
| 182 | + continue; | ||
| 183 | + } | ||
| 184 | + | ||
| 185 | + $server->addService($serviceObj); | ||
| 186 | + } | ||
| 187 | + } | ||
| 188 | + | ||
| 189 | + $server->start(); | ||
| 190 | + } | ||
| 191 | + | ||
| 192 | + /** | ||
| 193 | + * build | ||
| 194 | + * | ||
| 195 | + * @param $namespace | ||
| 196 | + * @param $class | ||
| 197 | + * @return object|null | ||
| 198 | + * @author pengjch 202435 16:51:18 | ||
| 199 | + */ | ||
| 200 | + protected function build($namespace, $class): ?object | ||
| 201 | + { | ||
| 202 | + $serviceClass = str_replace('/', '\\', $namespace . $class); | ||
| 203 | + if (!class_exists($serviceClass)) { | ||
| 204 | + $this->error($serviceClass . '类不存在'); | ||
| 205 | + return null; | ||
| 206 | + } | ||
| 207 | + | ||
| 208 | + try { | ||
| 209 | + $rf = new \ReflectionClass($serviceClass); | ||
| 210 | + } catch (\ReflectionException $e) { | ||
| 211 | + $this->error($serviceClass . $e->getMessage()); | ||
| 212 | + return null; | ||
| 213 | + } | ||
| 214 | + | ||
| 215 | + try { | ||
| 216 | + return $rf->newInstance(); | ||
| 217 | + } catch (\ReflectionException $e) { | ||
| 218 | + $this->error($serviceClass . $e->getMessage()); | ||
| 219 | + return null; | ||
| 220 | + } | ||
| 221 | + } | ||
| 222 | +} |
src/Event.php
0 → 100755
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace AukeySwrpc; | ||
| 4 | + | ||
| 5 | +trait Event | ||
| 6 | +{ | ||
| 7 | + public function OnWorkerStart(\Swoole\Server $server, int $workerId) | ||
| 8 | + { | ||
| 9 | + } | ||
| 10 | + | ||
| 11 | + public function onStart(\Swoole\Server $server) | ||
| 12 | + { | ||
| 13 | + } | ||
| 14 | + | ||
| 15 | + public function onShutdown(\Swoole\Server $server) | ||
| 16 | + { | ||
| 17 | + | ||
| 18 | + } | ||
| 19 | +} |
src/Exceptions/RequestException.php
0 → 100755
src/Exceptions/RpcException.php
0 → 100755
src/Exceptions/TypeException.php
0 → 100755
| @@ -19,18 +19,18 @@ class RouteServiceProvider extends ServiceProvider{ | @@ -19,18 +19,18 @@ class RouteServiceProvider extends ServiceProvider{ | ||
| 19 | * web路由设置 | 19 | * web路由设置 |
| 20 | */ | 20 | */ |
| 21 | protected function mapWebRoutes(){ | 21 | protected function mapWebRoutes(){ |
| 22 | - Route::middleware('web') | ||
| 23 | - ->namespace('Swrpc\Http\Controllers') | ||
| 24 | - ->group(__DIR__ . '/Controllers/routes.php'); | 22 | +// Route::middleware('web') |
| 23 | +// ->namespace('AukeySwrpc\Http\Controllers') | ||
| 24 | +// ->group(__DIR__ . '/Controllers/routes.php'); | ||
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | /** | 27 | /** |
| 28 | * api路由设置 | 28 | * api路由设置 |
| 29 | */ | 29 | */ |
| 30 | protected function mapApiRoutes(){ | 30 | protected function mapApiRoutes(){ |
| 31 | - Route::prefix('api') | ||
| 32 | - ->middleware('api') | ||
| 33 | - ->namespace('Swrpc\Http\Controllers') | ||
| 34 | - ->group(__DIR__ . '/Controllers/routes.php'); | 31 | +// Route::prefix('api') |
| 32 | +// ->middleware('api') | ||
| 33 | +// ->namespace('AukeySwrpc\Http\Controllers') | ||
| 34 | +// ->group(__DIR__ . '/Controllers/routes.php'); | ||
| 35 | } | 35 | } |
| 36 | } | 36 | } |
src/LogicService.php
0 → 100755
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace AukeySwrpc; | ||
| 4 | + | ||
| 5 | + | ||
| 6 | +use AukeySwrpc\Tracer\TracerContext; | ||
| 7 | +use Zipkin\Endpoint; | ||
| 8 | +use Zipkin\Reporters\Http; | ||
| 9 | +use Zipkin\Samplers\BinarySampler; | ||
| 10 | +use Zipkin\TracingBuilder; | ||
| 11 | + | ||
| 12 | +/** | ||
| 13 | + * Class LogicService | ||
| 14 | + * | ||
| 15 | + * @package Swrpc | ||
| 16 | + * @author pengjch 2024311 11:10:18 | ||
| 17 | + */ | ||
| 18 | +class LogicService | ||
| 19 | +{ | ||
| 20 | + protected $params; | ||
| 21 | + protected $module; | ||
| 22 | + protected $tracerUrl; | ||
| 23 | + protected $tracerContext; | ||
| 24 | + protected $clients = []; | ||
| 25 | + | ||
| 26 | + /** | ||
| 27 | + * @return static | ||
| 28 | + * @author pengjch 2024311 11:4:5 | ||
| 29 | + */ | ||
| 30 | + public static function factory() | ||
| 31 | + { | ||
| 32 | + return new static(); | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + /** | ||
| 36 | + * 初始化链路追踪器 | ||
| 37 | + * | ||
| 38 | + * @param $func | ||
| 39 | + * @author pengjch 2024311 11:3:36 | ||
| 40 | + */ | ||
| 41 | + public function initTracer($func) | ||
| 42 | + { | ||
| 43 | + $reporterUrl = $this->tracerUrl ?: 'http://127.0.0.1:9411/api/v2/spans'; | ||
| 44 | + $endpoint = Endpoint::create($this->module); | ||
| 45 | + $reporter = new Http(['endpoint_url' => $reporterUrl]); | ||
| 46 | + $sampler = BinarySampler::createAsAlwaysSample(); | ||
| 47 | + $tracing = TracingBuilder::create() | ||
| 48 | + ->havingLocalEndpoint($endpoint) | ||
| 49 | + ->havingSampler($sampler) | ||
| 50 | + ->havingReporter($reporter) | ||
| 51 | + ->build(); | ||
| 52 | + $tracer = $tracing->getTracer(); | ||
| 53 | + $span = $tracer->newTrace(); | ||
| 54 | + $span->setName($func); | ||
| 55 | + $span->start(); | ||
| 56 | + $span->finish(); | ||
| 57 | + $tracer->flush(); | ||
| 58 | + | ||
| 59 | + $ctx = $span->getContext(); | ||
| 60 | + if ($this->tracerContext) { | ||
| 61 | + $this->tracerContext->setTraceID($ctx->getTraceId()); | ||
| 62 | + $this->tracerContext->setParentID($ctx->getSpanId()); | ||
| 63 | + $this->tracerContext->setReporterUrl($reporterUrl); | ||
| 64 | + } else { | ||
| 65 | + $this->tracerContext = TracerContext::create($ctx->getTraceId(), $ctx->getSpanId(), $reporterUrl); | ||
| 66 | + } | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + /** | ||
| 70 | + * @param $context | ||
| 71 | + * @return $this | ||
| 72 | + * @author pengjch 2024311 11:18:43 | ||
| 73 | + */ | ||
| 74 | + public function setTracerContext($context) | ||
| 75 | + { | ||
| 76 | + $this->tracerContext = $context; | ||
| 77 | + return $this; | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | + /** | ||
| 81 | + * @param $func | ||
| 82 | + * @return null | ||
| 83 | + * @author pengjch 2024311 11:4:1 | ||
| 84 | + */ | ||
| 85 | + public function getTracerContext($func) | ||
| 86 | + { | ||
| 87 | + if (empty($this->tracerUrl)) { | ||
| 88 | + return null; | ||
| 89 | + } | ||
| 90 | + if (empty($this->tracerContext)) { | ||
| 91 | + $this->initTracer($func); | ||
| 92 | + } | ||
| 93 | + return $this->tracerContext; | ||
| 94 | + } | ||
| 95 | + | ||
| 96 | + /** | ||
| 97 | + * @param array $params | ||
| 98 | + * @return $this | ||
| 99 | + * @author pengjch 2024311 11:15:47 | ||
| 100 | + */ | ||
| 101 | + public function setParams(array $params) | ||
| 102 | + { | ||
| 103 | + $this->params = $params; | ||
| 104 | + return $this; | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + /** | ||
| 108 | + * @param string $url | ||
| 109 | + * @return static $this | ||
| 110 | + * @author pengjch 2024311 11:15:35 | ||
| 111 | + */ | ||
| 112 | + public function setTracerUrl(string $url) | ||
| 113 | + { | ||
| 114 | + $this->tracerUrl = $url; | ||
| 115 | + return $this; | ||
| 116 | + } | ||
| 117 | + | ||
| 118 | + /** | ||
| 119 | + * @param string $name | ||
| 120 | + * @return $this | ||
| 121 | + * @author pengjch 2024311 11:59:4 | ||
| 122 | + */ | ||
| 123 | + public function setModule(string $name) | ||
| 124 | + { | ||
| 125 | + $this->module = $name; | ||
| 126 | + return $this; | ||
| 127 | + } | ||
| 128 | +} |
src/Middlewares/MiddlewareInterface.php
0 → 100755
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace AukeySwrpc\Middlewares; | ||
| 4 | + | ||
| 5 | + | ||
| 6 | +use Closure; | ||
| 7 | +use AukeySwrpc\Request\Request; | ||
| 8 | +use AukeySwrpc\Response; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * Interface MiddlewareInterface | ||
| 12 | + * | ||
| 13 | + * @package AukeySwrpc\Middlewares | ||
| 14 | + * @author pengjch 202439 11:37:39 | ||
| 15 | + */ | ||
| 16 | +interface MiddlewareInterface | ||
| 17 | +{ | ||
| 18 | + function handle(Request $request, Closure $next): Response; | ||
| 19 | +} |
src/Middlewares/TraceMiddleware.php
0 → 100755
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace AukeySwrpc\Middlewares; | ||
| 4 | + | ||
| 5 | + | ||
| 6 | +use Closure; | ||
| 7 | +use AukeySwrpc\Request\Request; | ||
| 8 | +use AukeySwrpc\Response; | ||
| 9 | +use Zipkin\Endpoint; | ||
| 10 | +use Zipkin\Propagation\TraceContext; | ||
| 11 | +use Zipkin\Reporters\Http; | ||
| 12 | +use Zipkin\Samplers\BinarySampler; | ||
| 13 | +use Zipkin\TracingBuilder; | ||
| 14 | + | ||
| 15 | +/** | ||
| 16 | + * 链路追踪中间件 | ||
| 17 | + * Class TraceMiddleware | ||
| 18 | + * | ||
| 19 | + * @package AukeySwrpc\Middlewares | ||
| 20 | + * @author pengjch 2024310 16:41:6 | ||
| 21 | + */ | ||
| 22 | +class TraceMiddleware implements MiddlewareInterface | ||
| 23 | +{ | ||
| 24 | + function handle(Request $request, Closure $next): Response | ||
| 25 | + { | ||
| 26 | + $context = $request->getTraceContext(); | ||
| 27 | + if (!$context) { | ||
| 28 | + return $next($request); | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + $traceContext = TraceContext::create($context->getTraceID(), $context->getParentID(), null, true); | ||
| 32 | + $endpoint = Endpoint::create($request->getModule()); | ||
| 33 | + $reporter = new Http(['endpoint_url' => $context->getReporterUrl()]); | ||
| 34 | + $sampler = BinarySampler::createAsAlwaysSample(); | ||
| 35 | + $tracing = TracingBuilder::create() | ||
| 36 | + ->havingLocalEndpoint($endpoint) | ||
| 37 | + ->havingSampler($sampler) | ||
| 38 | + ->havingReporter($reporter) | ||
| 39 | + ->build(); | ||
| 40 | + | ||
| 41 | + $tracer = $tracing->getTracer(); | ||
| 42 | + $span = $tracer->newChild($traceContext); | ||
| 43 | + $span->setName($request->getMethod()); | ||
| 44 | + $span->start(); | ||
| 45 | + $span->tag('请求参数', serialize($request->getParams())); | ||
| 46 | + $request->setTraceContext($span->getContext()->getTraceId(), $span->getContext() | ||
| 47 | + ->getSpanId(), $context->getReporterUrl()); | ||
| 48 | + | ||
| 49 | + $start = microtime(true); | ||
| 50 | + $result = $next($request); | ||
| 51 | + $end = microtime(true); | ||
| 52 | + | ||
| 53 | + $span->tag('响应状态码code', $result->code); | ||
| 54 | + $span->tag('响应提示语msg', $result->msg); | ||
| 55 | + $span->tag('响应耗时', $end - $start); | ||
| 56 | + $span->finish(); | ||
| 57 | + $tracer->flush(); | ||
| 58 | + | ||
| 59 | + return $result; | ||
| 60 | + } | ||
| 61 | +} |
src/Packer/PackerInterface.php
0 → 100755
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace AukeySwrpc\Packer; | ||
| 4 | + | ||
| 5 | + | ||
| 6 | +use AukeySwrpc\Request\Request; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * Interface PackerInterface | ||
| 10 | + * | ||
| 11 | + * @package AukeySwrpc\Packer | ||
| 12 | + * @author pengjch 202439 11:37:10 | ||
| 13 | + */ | ||
| 14 | +interface PackerInterface | ||
| 15 | +{ | ||
| 16 | + function pack(Request $data):string; | ||
| 17 | + function unpack(string $data); | ||
| 18 | +} |
src/Packer/SerializeEofPacker.php
0 → 100755
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace AukeySwrpc\Packer; | ||
| 4 | + | ||
| 5 | + | ||
| 6 | +use AukeySwrpc\Request\Request; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * Class SerializeEofPacker | ||
| 10 | + * | ||
| 11 | + * @package AukeySwrpc\Packer | ||
| 12 | + * @author pengjch 202439 11:37:17 | ||
| 13 | + */ | ||
| 14 | +class SerializeEofPacker implements PackerInterface | ||
| 15 | +{ | ||
| 16 | + /** | ||
| 17 | + * @var string | ||
| 18 | + */ | ||
| 19 | + protected $eof; | ||
| 20 | + | ||
| 21 | + public function __construct(array $options = []) | ||
| 22 | + { | ||
| 23 | + $this->eof = $options['settings']['package_eof'] ?? "\r\n"; | ||
| 24 | + } | ||
| 25 | + | ||
| 26 | + public function pack(Request $data): string | ||
| 27 | + { | ||
| 28 | + return serialize($data); | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + public function unpack(string $data) | ||
| 32 | + { | ||
| 33 | + return unserialize($data); | ||
| 34 | + } | ||
| 35 | +} |
src/Packer/SerializeLengthPacker.php
0 → 100755
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace AukeySwrpc\Packer; | ||
| 4 | + | ||
| 5 | + | ||
| 6 | +use AukeySwrpc\Request\Request; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * Class SerializeLengthPacker | ||
| 10 | + * | ||
| 11 | + * @package AukeySwrpc\Packer | ||
| 12 | + * @author pengjch 202439 11:37:27 | ||
| 13 | + */ | ||
| 14 | +class SerializeLengthPacker implements PackerInterface | ||
| 15 | +{ | ||
| 16 | + /** | ||
| 17 | + * @var string | ||
| 18 | + */ | ||
| 19 | + protected $type; | ||
| 20 | + | ||
| 21 | + /** | ||
| 22 | + * @var int | ||
| 23 | + */ | ||
| 24 | + protected $length; | ||
| 25 | + | ||
| 26 | + protected $defaultOptions | ||
| 27 | + = [ | ||
| 28 | + 'package_length_type' => 'N', | ||
| 29 | + 'package_body_offset' => 4, | ||
| 30 | + ]; | ||
| 31 | + | ||
| 32 | + public function __construct(array $options = []) | ||
| 33 | + { | ||
| 34 | + $options = array_merge($this->defaultOptions, $options['settings'] ?? []); | ||
| 35 | + | ||
| 36 | + $this->type = $options['package_length_type']; | ||
| 37 | + $this->length = $options['package_body_offset']; | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + public function pack(Request $data): string | ||
| 41 | + { | ||
| 42 | + $data = serialize($data); | ||
| 43 | + return pack($this->type, strlen($data)) . $data; | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + public function unpack(string $data) | ||
| 47 | + { | ||
| 48 | + $package = unpack('N', $data); | ||
| 49 | + $len = $package[1]; | ||
| 50 | + | ||
| 51 | + //合并unserialize和substr,以减少内存拷贝 https://wenda.swoole.com/detail/107587 | ||
| 52 | + if (function_exists('swoole_substr_unserialize')) { | ||
| 53 | + return swoole_substr_unserialize($data, $this->length, $len); | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + $data = substr($data, $this->length, $len); | ||
| 57 | + return unserialize($data); | ||
| 58 | + } | ||
| 59 | +} |
src/Register/Consul.php
0 → 100755
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace AukeySwrpc\Register; | ||
| 4 | + | ||
| 5 | + | ||
| 6 | +use SensioLabs\Consul\ServiceFactory; | ||
| 7 | +use SensioLabs\Consul\Services\Agent; | ||
| 8 | +use SensioLabs\Consul\Services\AgentInterface as AgentInterfaceAlias; | ||
| 9 | +use SensioLabs\Consul\Services\Catalog; | ||
| 10 | +use SensioLabs\Consul\Services\CatalogInterface; | ||
| 11 | +use SensioLabs\Consul\Services\Health; | ||
| 12 | +use AukeySwrpc\Exceptions\RpcException; | ||
| 13 | + | ||
| 14 | +class Consul implements RegisterInterface | ||
| 15 | +{ | ||
| 16 | + protected $sf; | ||
| 17 | + protected array $options; | ||
| 18 | + protected array $serviceCache | ||
| 19 | + = [ | ||
| 20 | + 'ttl' => 10, | ||
| 21 | + 'services' => [], | ||
| 22 | + 'lastUpdateTime' => 0, | ||
| 23 | + ]; | ||
| 24 | + | ||
| 25 | + public function __construct($uri = 'http://127.0.0.1:8500', $options = []) | ||
| 26 | + { | ||
| 27 | + $this->options = $options; | ||
| 28 | + $this->sf = new ServiceFactory([ | ||
| 29 | + 'base_uri' => $uri | ||
| 30 | + ]); | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + public function getName(): string | ||
| 34 | + { | ||
| 35 | + return 'Consul'; | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + /** | ||
| 39 | + * 注册节点 | ||
| 40 | + * | ||
| 41 | + * @param string $module | ||
| 42 | + * @param string $host | ||
| 43 | + * @param $port | ||
| 44 | + * @param int $weight | ||
| 45 | + * @author pengjch 202439 23:17:5 | ||
| 46 | + */ | ||
| 47 | + public function register($module, $host, $port, $weight = 1) | ||
| 48 | + { | ||
| 49 | + $id = $host . '_' . $port; | ||
| 50 | + /** @var Agent $agent */ | ||
| 51 | + $agent = $this->sf->get(AgentInterfaceAlias::class); | ||
| 52 | + $agent->registerService([ | ||
| 53 | + 'ID' => $id, | ||
| 54 | + 'Name' => $module, | ||
| 55 | + 'Port' => $port, | ||
| 56 | + 'Address' => $host, | ||
| 57 | + 'Tags' => [ | ||
| 58 | + 'port_' . $port, | ||
| 59 | + ], | ||
| 60 | + 'Weights' => [ | ||
| 61 | + 'Passing' => $weight, | ||
| 62 | + 'Warning' => 1, | ||
| 63 | + ], | ||
| 64 | + 'Check' => [ | ||
| 65 | + 'TCP' => $host . ':' . $port, | ||
| 66 | + 'Interval' => $this->options['interval'] ?? '10s', | ||
| 67 | + 'Timeout' => $this->options['timeout'] ?? '5s', | ||
| 68 | + 'DeregisterCriticalServiceAfter' => $this->options['deregisterCriticalServiceAfter'] ?? '30s', | ||
| 69 | + ], | ||
| 70 | + ]); | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + /** | ||
| 74 | + * 注销节点 | ||
| 75 | + * http://127.0.0.1:8500/v1/agent/service/deregister/service_id | ||
| 76 | + * | ||
| 77 | + * @param $host | ||
| 78 | + * @param $port | ||
| 79 | + * @author pengjch 202439 23:16:51 | ||
| 80 | + */ | ||
| 81 | + public function unRegister($host, $port) | ||
| 82 | + { | ||
| 83 | + $id = $host . '_' . $port; | ||
| 84 | + /** @var Agent $agent */ | ||
| 85 | + $agent = $this->sf->get(AgentInterfaceAlias::class); | ||
| 86 | + $agent->deregisterService($id); | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + /** | ||
| 90 | + * 获取模块下所有的服务 | ||
| 91 | + * | ||
| 92 | + * @param string $module | ||
| 93 | + * @return array | ||
| 94 | + * @author pengjch 2024310 9:44:16 | ||
| 95 | + */ | ||
| 96 | + public function getServices(string $module): array | ||
| 97 | + { | ||
| 98 | + $cache = $this->serviceCache; | ||
| 99 | + $ttl = $this->options['ttl'] ?? $cache['ttl']; | ||
| 100 | + | ||
| 101 | + //本地缓存所有节点信息,避免每次请求都要从consul拉一遍数据 | ||
| 102 | + if ($cache['lastUpdateTime'] + $ttl < time()) { | ||
| 103 | + $health = new Health(); | ||
| 104 | + $servers = $health->service($module)->json(); | ||
| 105 | + if (empty($servers)) { | ||
| 106 | + return []; | ||
| 107 | + } | ||
| 108 | + $result = []; | ||
| 109 | + foreach ($servers as $server) { | ||
| 110 | + $result[] = Service::build($server['Service']['Address'], $server['Service']['Port'], $server['Service']['Weights']['Passing']); | ||
| 111 | + } | ||
| 112 | + $cache['service'] = $result; | ||
| 113 | + $cache['lastUpdateTime'] = time(); | ||
| 114 | + } | ||
| 115 | + | ||
| 116 | + return $cache['service']; | ||
| 117 | + } | ||
| 118 | + | ||
| 119 | + /** | ||
| 120 | + * 随机获取一个服务 | ||
| 121 | + * | ||
| 122 | + * @param string $module | ||
| 123 | + * @return Service | ||
| 124 | + * @author pengjch 2024310 9:44:27 | ||
| 125 | + */ | ||
| 126 | + public function getRandomService(string $module): Service | ||
| 127 | + { | ||
| 128 | + $services = $this->getServices($module); | ||
| 129 | + if (!$services) { | ||
| 130 | + throw new RpcException('It has not register module'); | ||
| 131 | + } | ||
| 132 | + | ||
| 133 | + return $services[rand(0, count($services) - 1)]; | ||
| 134 | + } | ||
| 135 | + | ||
| 136 | + /** | ||
| 137 | + * 获取权重服务 | ||
| 138 | + * | ||
| 139 | + * @param string $module | ||
| 140 | + * @return Service | ||
| 141 | + * @author pengjch 2024310 9:44:38 | ||
| 142 | + */ | ||
| 143 | + public function getWeightService(string $module): Service | ||
| 144 | + { | ||
| 145 | + $serviceArr = []; | ||
| 146 | + $totalWeight = 0; | ||
| 147 | + $services = $this->getServices($module); | ||
| 148 | + if (!$services) { | ||
| 149 | + throw new RpcException('It has not register module'); | ||
| 150 | + } | ||
| 151 | + | ||
| 152 | + /** @var Service $service */ | ||
| 153 | + foreach ($services as $service) { | ||
| 154 | + $totalWeight += $service->getWeight(); | ||
| 155 | + $sort[] = $service->getWeight(); | ||
| 156 | + $serviceArr[] = $service->toArray(); | ||
| 157 | + } | ||
| 158 | + | ||
| 159 | + array_multisort($serviceArr, SORT_DESC, $sort); | ||
| 160 | + | ||
| 161 | + $start = 0; | ||
| 162 | + $rand = rand(1, $totalWeight); | ||
| 163 | + foreach ($serviceArr as $service) { | ||
| 164 | + if ($start + $service['weight'] >= $rand) { | ||
| 165 | + return Service::build($service['host'], $service['port'], $service['weight']); | ||
| 166 | + } | ||
| 167 | + $start = $start + $service['weight']; | ||
| 168 | + } | ||
| 169 | + } | ||
| 170 | +} |
src/Register/RegisterInterface.php
0 → 100755
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace AukeySwrpc\Register; | ||
| 4 | + | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * Interface RegisterInterface | ||
| 8 | + * | ||
| 9 | + * @package AukeySwrpc\Register | ||
| 10 | + * @author pengjch 202439 16:23:35 | ||
| 11 | + */ | ||
| 12 | +interface RegisterInterface | ||
| 13 | +{ | ||
| 14 | + function getName(): string; | ||
| 15 | + | ||
| 16 | + function register($module, $host, $port, $weight = 1); | ||
| 17 | + | ||
| 18 | + function unRegister($host, $port); | ||
| 19 | + | ||
| 20 | + function getServices(string $module): array; | ||
| 21 | + | ||
| 22 | + function getRandomService(string $module): Service; | ||
| 23 | + | ||
| 24 | + function getWeightService(string $module): Service; | ||
| 25 | +} |
src/Register/Service.php
0 → 100755
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace AukeySwrpc\Register; | ||
| 4 | + | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * 注册中心服务 | ||
| 8 | + * Class Service | ||
| 9 | + * | ||
| 10 | + * @package AukeySwrpc\Register | ||
| 11 | + * @author pengjch 2024311 10:25:46 | ||
| 12 | + */ | ||
| 13 | +class Service | ||
| 14 | +{ | ||
| 15 | + protected $host; | ||
| 16 | + protected $port; | ||
| 17 | + protected $weight; | ||
| 18 | + | ||
| 19 | + public function __construct($host, $port, $weight) | ||
| 20 | + { | ||
| 21 | + $this->host = $host; | ||
| 22 | + $this->port = $port; | ||
| 23 | + $this->weight = $weight; | ||
| 24 | + } | ||
| 25 | + | ||
| 26 | + public static function build($host, $port, $weight) | ||
| 27 | + { | ||
| 28 | + return new static($host, $port, $weight); | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + public function getHost() | ||
| 32 | + { | ||
| 33 | + return $this->host; | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + public function getPort() | ||
| 37 | + { | ||
| 38 | + return $this->port; | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + public function getWeight() | ||
| 42 | + { | ||
| 43 | + return $this->weight; | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + public function toArray(): array | ||
| 47 | + { | ||
| 48 | + return [ | ||
| 49 | + 'host' => $this->host, | ||
| 50 | + 'port' => $this->port, | ||
| 51 | + 'weight' => $this->weight | ||
| 52 | + ]; | ||
| 53 | + } | ||
| 54 | +} |
src/Request/AsyncRequest.php
0 → 100755
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace AukeySwrpc\Request; | ||
| 4 | + | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * Class AsyncRequest | ||
| 8 | + * | ||
| 9 | + * @package AukeySwrpc\Request | ||
| 10 | + * @author pengjch 2024313 9:10:2 | ||
| 11 | + */ | ||
| 12 | +class AsyncRequest extends Request | ||
| 13 | +{ | ||
| 14 | + public function init() | ||
| 15 | + { | ||
| 16 | + $this->setSync(false); | ||
| 17 | + $this->setSystem(false); | ||
| 18 | + } | ||
| 19 | +} |
src/Request/Request.php
0 → 100755
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace AukeySwrpc\Request; | ||
| 4 | + | ||
| 5 | + | ||
| 6 | +use AukeySwrpc\Tracer\TracerContext; | ||
| 7 | + | ||
| 8 | +abstract class Request | ||
| 9 | +{ | ||
| 10 | + protected string $module; | ||
| 11 | + protected string $method; | ||
| 12 | + protected array $params; | ||
| 13 | + protected bool $isSync = true; //是否同步请求,默认是 | ||
| 14 | + protected bool $isSystem = false; //是否系统请求,默认否 | ||
| 15 | + protected $error; | ||
| 16 | + protected ?TracerContext $traceContext; | ||
| 17 | + | ||
| 18 | + public static function create($method, $params, ?TracerContext $traceContext = null) | ||
| 19 | + { | ||
| 20 | + return new static ($method, $params, $traceContext); | ||
| 21 | + } | ||
| 22 | + | ||
| 23 | + public function __construct($method, $params, ?TracerContext $traceContext = null) | ||
| 24 | + { | ||
| 25 | + $this->method = $method; | ||
| 26 | + $this->params = $params; | ||
| 27 | + $this->traceContext = $traceContext; | ||
| 28 | + $this->init(); | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + abstract public function init(); | ||
| 32 | + | ||
| 33 | + public function getModule(): string | ||
| 34 | + { | ||
| 35 | + return $this->module; | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + public function getMethod(): string | ||
| 39 | + { | ||
| 40 | + return $this->method; | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + public function getParams(): array | ||
| 44 | + { | ||
| 45 | + return $this->params; | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + public function setParams(array $params) | ||
| 49 | + { | ||
| 50 | + $this->params = $params; | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + public function setModule(string $name) | ||
| 54 | + { | ||
| 55 | + $this->module = $name; | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + public function mergeParams(array $params) | ||
| 59 | + { | ||
| 60 | + $this->params = array_merge($this->params, $params); | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + public function getTraceContext(): ?TracerContext | ||
| 64 | + { | ||
| 65 | + return $this->traceContext; | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + public function setTraceContext($traceID, $parentID, $url) | ||
| 69 | + { | ||
| 70 | + $this->traceContext = TracerContext::create($traceID, $parentID, $url); | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + public function setSync(bool $value) | ||
| 74 | + { | ||
| 75 | + $this->isSync = $value; | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + public function isSync(): bool | ||
| 79 | + { | ||
| 80 | + return $this->isSync; | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + public function setSystem(bool $value) | ||
| 84 | + { | ||
| 85 | + $this->isSystem = $value; | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + public function isSystem(): bool | ||
| 89 | + { | ||
| 90 | + return $this->isSystem; | ||
| 91 | + } | ||
| 92 | + | ||
| 93 | + public function getError() | ||
| 94 | + { | ||
| 95 | + return $this->error; | ||
| 96 | + } | ||
| 97 | + | ||
| 98 | + public function setError($err) | ||
| 99 | + { | ||
| 100 | + $this->error = $err; | ||
| 101 | + } | ||
| 102 | +} |
src/Request/SyncRequest.php
0 → 100755
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace AukeySwrpc\Request; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * Class SyncRequest | ||
| 7 | + * | ||
| 8 | + * @package AukeySwrpc\Request | ||
| 9 | + * @author pengjch 2024313 9:9:54 | ||
| 10 | + */ | ||
| 11 | +class SyncRequest extends Request | ||
| 12 | +{ | ||
| 13 | + public function init() | ||
| 14 | + { | ||
| 15 | + $this->setSync(true); | ||
| 16 | + $this->setSystem(false); | ||
| 17 | + } | ||
| 18 | +} |
src/Request/SystemRequest.php
0 → 100755
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace AukeySwrpc\Request; | ||
| 4 | + | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * Class AsyncRequest | ||
| 8 | + * | ||
| 9 | + * @package AukeySwrpc\Request | ||
| 10 | + * @author pengjch 2024313 9:10:2 | ||
| 11 | + */ | ||
| 12 | +class SystemRequest extends Request | ||
| 13 | +{ | ||
| 14 | + public function init() | ||
| 15 | + { | ||
| 16 | + $this->setSync(true); | ||
| 17 | + $this->setSystem(true); | ||
| 18 | + } | ||
| 19 | +} |
src/Response.php
0 → 100755
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace AukeySwrpc; | ||
| 4 | + | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * Class Response | ||
| 8 | + * | ||
| 9 | + * @package Swrpc | ||
| 10 | + * @author pengjch 202439 11:36:9 | ||
| 11 | + */ | ||
| 12 | +class Response | ||
| 13 | +{ | ||
| 14 | + const RES_ERROR = 0; | ||
| 15 | + const RES_SUCCESS = 1; | ||
| 16 | + | ||
| 17 | + public string $msg; | ||
| 18 | + public int $code; | ||
| 19 | + public array $data; | ||
| 20 | + | ||
| 21 | + public function __construct($code, $msg, $data) | ||
| 22 | + { | ||
| 23 | + $this->data = $data; | ||
| 24 | + $this->code = $code; | ||
| 25 | + $this->msg = $msg; | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | + public static function error($msg, $code = self::RES_ERROR, $data = []): Response | ||
| 29 | + { | ||
| 30 | + return new static($code, $msg, $data); | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + public static function success($data = [], $msg = 'success', $code = self::RES_SUCCESS): Response | ||
| 34 | + { | ||
| 35 | + return new static($code, $msg, $data); | ||
| 36 | + } | ||
| 37 | +} |
src/Server.php
0 → 100755
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace AukeySwrpc; | ||
| 4 | + | ||
| 5 | + | ||
| 6 | +use Monolog\Handler\StreamHandler; | ||
| 7 | +use Monolog\Logger; | ||
| 8 | +use Psr\Log\LoggerInterface; | ||
| 9 | +use AukeySwrpc\Middlewares\TraceMiddleware; | ||
| 10 | +use AukeySwrpc\Packer\SerializeLengthPacker; | ||
| 11 | +use AukeySwrpc\Register\RegisterInterface; | ||
| 12 | +use AukeySwrpc\Middlewares\MiddlewareInterface; | ||
| 13 | +use AukeySwrpc\Packer\PackerInterface; | ||
| 14 | +use AukeySwrpc\Request\Request; | ||
| 15 | + | ||
| 16 | +/** | ||
| 17 | + * Class Server | ||
| 18 | + * | ||
| 19 | + * @package Swrpc | ||
| 20 | + * @author pengjch 202439 11:35:52 | ||
| 21 | + */ | ||
| 22 | +class Server | ||
| 23 | +{ | ||
| 24 | + use Event; | ||
| 25 | + | ||
| 26 | + protected string $module; | ||
| 27 | + protected string $host; | ||
| 28 | + protected int $port; | ||
| 29 | + protected int $weight = 1; | ||
| 30 | + protected array $options; | ||
| 31 | + protected array $defaultOptions | ||
| 32 | + = [ | ||
| 33 | + 'open_length_check' => true, | ||
| 34 | + 'package_length_type' => 'N', | ||
| 35 | + 'package_length_offset' => 0, //第N个字节是包长度的值 | ||
| 36 | + 'package_body_offset' => 4, //第几个字节开始计算长度 | ||
| 37 | + 'package_max_length' => 81920, //协议最大长度 | ||
| 38 | + ]; | ||
| 39 | + | ||
| 40 | + /** @var PackerInterface $packer */ | ||
| 41 | + protected $packer; | ||
| 42 | + | ||
| 43 | + /** @var Service $service */ | ||
| 44 | + protected $service; | ||
| 45 | + | ||
| 46 | + /** @var LoggerInterface $logger */ | ||
| 47 | + protected $logger; | ||
| 48 | + | ||
| 49 | + /** @var RegisterInterface $register */ | ||
| 50 | + protected $register; | ||
| 51 | + | ||
| 52 | + /** @var \Swoole\Server $server */ | ||
| 53 | + protected \Swoole\Server $server; | ||
| 54 | + | ||
| 55 | + private array $middlewares; | ||
| 56 | + | ||
| 57 | + public function __construct( | ||
| 58 | + string $module, | ||
| 59 | + string $host, | ||
| 60 | + int $port, | ||
| 61 | + array $options = [], | ||
| 62 | + $mode = SWOOLE_PROCESS, | ||
| 63 | + $socketType = SWOOLE_SOCK_TCP, | ||
| 64 | + LoggerInterface $logger = null | ||
| 65 | + ) { | ||
| 66 | + $this->module = $module; | ||
| 67 | + $this->host = $host; | ||
| 68 | + $this->port = $port; | ||
| 69 | + | ||
| 70 | + $this->setDefaultOptions($options); | ||
| 71 | + $this->setDefaultLogger($logger); | ||
| 72 | + $this->setCoreMiddleware(); | ||
| 73 | + | ||
| 74 | + $this->service = new Service($this->logger); | ||
| 75 | + | ||
| 76 | + $server = new \Swoole\Server($host, $port, $mode ?: SWOOLE_PROCESS, $socketType ?: SWOOLE_SOCK_TCP); | ||
| 77 | + $server->set($this->options); | ||
| 78 | + $server->on('Start', [$this, 'onStart']); | ||
| 79 | + $server->on('Shutdown', [$this, 'onShutdown']); | ||
| 80 | + $server->on('WorkerStart', [$this, 'onWorkerStart']); | ||
| 81 | + $server->on('Connect', [$this, 'OnConnect']); | ||
| 82 | + $server->on('Receive', [$this, 'OnReceive']); | ||
| 83 | + $server->on('Close', [$this, 'OnClose']); | ||
| 84 | + $server->on('Task', [$this, 'OnTask']); | ||
| 85 | + $server->on('Finish', [$this, 'OnFinish']); | ||
| 86 | + $this->server = $server; | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + /** | ||
| 90 | + * 设置节点权重 | ||
| 91 | + * | ||
| 92 | + * @param int $weight | ||
| 93 | + * @return Server | ||
| 94 | + * @author pengjch 2024313 10:55:39 | ||
| 95 | + */ | ||
| 96 | + public function weight(int $weight): Server | ||
| 97 | + { | ||
| 98 | + $this->weight = $weight; | ||
| 99 | + return $this; | ||
| 100 | + } | ||
| 101 | + | ||
| 102 | + /** | ||
| 103 | + * 设置默认选项 | ||
| 104 | + * | ||
| 105 | + * @param $options | ||
| 106 | + * @author pengjch 2024311 10:35:3 | ||
| 107 | + */ | ||
| 108 | + protected function setDefaultOptions($options) | ||
| 109 | + { | ||
| 110 | + if (empty($options)) { | ||
| 111 | + $options = $this->defaultOptions; | ||
| 112 | + } | ||
| 113 | + | ||
| 114 | + $this->options = $options; | ||
| 115 | + | ||
| 116 | + //请求数量超过10000重启 | ||
| 117 | + if (empty($this->options['max_request'])) { | ||
| 118 | + $this->options['max_request'] = 10000; | ||
| 119 | + } | ||
| 120 | + //默认task数量 | ||
| 121 | + if (empty($this->options['task_worker_num'])) { | ||
| 122 | + $this->options['task_worker_num'] = swoole_cpu_num() * 2; | ||
| 123 | + } | ||
| 124 | + //task请求数超过10000则重启 | ||
| 125 | + if (empty($this->options['task_max_request'])) { | ||
| 126 | + $this->options['task_max_request'] = 10000; | ||
| 127 | + } | ||
| 128 | + //10s没有数据传输就进行检测 | ||
| 129 | + if (empty($this->options['tcp_keepidle'])) { | ||
| 130 | + $this->options['tcp_keepidle'] = 10; | ||
| 131 | + } | ||
| 132 | + //3s探测一次 | ||
| 133 | + if (empty($this->options['tcp_keepinterval'])) { | ||
| 134 | + $this->options['tcp_keepinterval'] = 3; | ||
| 135 | + } | ||
| 136 | + //探测的次数,超过5次后还没回包close此连接 | ||
| 137 | + if (empty($this->options['tcp_keepcount'])) { | ||
| 138 | + $this->options['tcp_keepcount'] = 5; | ||
| 139 | + } | ||
| 140 | + } | ||
| 141 | + | ||
| 142 | + /** | ||
| 143 | + * 设置默认日志处理器 | ||
| 144 | + * | ||
| 145 | + * @param LoggerInterface|null $logger | ||
| 146 | + * @author pengjch 2024311 10:34:19 | ||
| 147 | + */ | ||
| 148 | + protected function setDefaultLogger(LoggerInterface $logger = null) | ||
| 149 | + { | ||
| 150 | + if (empty($logger)) { | ||
| 151 | + $logger = new Logger('swrpc'); | ||
| 152 | + $logger->pushHandler(new StreamHandler(STDOUT, Logger::DEBUG)); | ||
| 153 | + } | ||
| 154 | + $this->logger = $logger; | ||
| 155 | + } | ||
| 156 | + | ||
| 157 | + /** | ||
| 158 | + * 设置核心中间件 | ||
| 159 | + * | ||
| 160 | + * @author pengjch 2024311 10:34:5 | ||
| 161 | + */ | ||
| 162 | + protected function setCoreMiddleware() | ||
| 163 | + { | ||
| 164 | + $this->middlewares[] = TraceMiddleware::class; | ||
| 165 | + } | ||
| 166 | + | ||
| 167 | + /** | ||
| 168 | + * 添加中间件,支持匿名函数和实现类 | ||
| 169 | + * addMiddleware | ||
| 170 | + * | ||
| 171 | + * @param mixed ...$middlewares | ||
| 172 | + * @author pengjch 202439 11:35:11 | ||
| 173 | + */ | ||
| 174 | + public function addMiddleware(...$middlewares) | ||
| 175 | + { | ||
| 176 | + foreach ($middlewares as $middleware) { | ||
| 177 | + if (is_string($middleware) && class_exists($middleware)) { | ||
| 178 | + $middleware = new $middleware(); | ||
| 179 | + } | ||
| 180 | + if (!($middleware instanceof \Closure) && !($middleware instanceof MiddlewareInterface)) { | ||
| 181 | + $this->logger->warning('Skip illegal Middleware.'); | ||
| 182 | + continue; | ||
| 183 | + } | ||
| 184 | + $this->middlewares[] = $middleware; | ||
| 185 | + } | ||
| 186 | + } | ||
| 187 | + | ||
| 188 | + /** | ||
| 189 | + * 添加服务 | ||
| 190 | + * addService | ||
| 191 | + * | ||
| 192 | + * @param $service | ||
| 193 | + * @param string $prefix | ||
| 194 | + * @return Server | ||
| 195 | + * @author pengjch 202439 11:35:2 | ||
| 196 | + */ | ||
| 197 | + public function addService($service, $prefix = ''): Server | ||
| 198 | + { | ||
| 199 | + $this->service->addInstance($service, $prefix); | ||
| 200 | + return $this; | ||
| 201 | + } | ||
| 202 | + | ||
| 203 | + /** | ||
| 204 | + * @param $key | ||
| 205 | + * @return mixed|null | ||
| 206 | + * @author pengjch 2024312 16:11:12 | ||
| 207 | + */ | ||
| 208 | + public function getService($key) | ||
| 209 | + { | ||
| 210 | + return $this->service->getService($key); | ||
| 211 | + } | ||
| 212 | + | ||
| 213 | + /** | ||
| 214 | + * 注册发现中心 | ||
| 215 | + * | ||
| 216 | + * @param $register | ||
| 217 | + * @return Server | ||
| 218 | + * @author pengjch 202439 16:38:51 | ||
| 219 | + */ | ||
| 220 | + public function addRegister($register): Server | ||
| 221 | + { | ||
| 222 | + $this->register = $register; | ||
| 223 | + return $this; | ||
| 224 | + } | ||
| 225 | + | ||
| 226 | + /** | ||
| 227 | + * 添加日志处理器 | ||
| 228 | + * | ||
| 229 | + * @param $logger | ||
| 230 | + * @author pengjch 202439 12:20:57 | ||
| 231 | + */ | ||
| 232 | + public function addLogger($logger) | ||
| 233 | + { | ||
| 234 | + $this->logger = $logger; | ||
| 235 | + } | ||
| 236 | + | ||
| 237 | + /** | ||
| 238 | + * 添加包解析器 | ||
| 239 | + * | ||
| 240 | + * @param $packer | ||
| 241 | + * @author pengjch 202439 12:45:53 | ||
| 242 | + */ | ||
| 243 | + public function addPacker($packer) | ||
| 244 | + { | ||
| 245 | + $this->packer = $packer; | ||
| 246 | + } | ||
| 247 | + | ||
| 248 | + /** | ||
| 249 | + * 注册服务到consul | ||
| 250 | + * onWorkerStart 和 onStart 回调是在不同进程中并行执行的,不存在先后顺序 | ||
| 251 | + * | ||
| 252 | + * @param \Swoole\Server $server | ||
| 253 | + * @author pengjch 202439 23:11:10 | ||
| 254 | + */ | ||
| 255 | + public function onStart(\Swoole\Server $server) | ||
| 256 | + { | ||
| 257 | + if ($this->register) { | ||
| 258 | + $this->logger->info(sprintf('Register server[%s:%d] to %s.', $this->host, $this->port, $this->register->getName())); | ||
| 259 | + $this->register->register($this->module, $this->host, $this->port, $this->weight); | ||
| 260 | + } | ||
| 261 | + } | ||
| 262 | + | ||
| 263 | + /** | ||
| 264 | + * 注销服务 | ||
| 265 | + * 强制 kill 进程不会回调 onShutdown | ||
| 266 | + * 需要使用 kill -15 来发送 SIGTERM 信号到主进程才能按照正常的流程终止 | ||
| 267 | + * | ||
| 268 | + * @param \Swoole\Server $server | ||
| 269 | + * @author pengjch 202439 23:14:40 | ||
| 270 | + */ | ||
| 271 | + public function onShutdown(\Swoole\Server $server) | ||
| 272 | + { | ||
| 273 | + if ($this->register) { | ||
| 274 | + $this->logger->info(sprintf('UnRegister server[%s:%d] from register.', $this->host, $this->port)); | ||
| 275 | + $this->register->unRegister($this->host, $this->port); | ||
| 276 | + } | ||
| 277 | + } | ||
| 278 | + | ||
| 279 | + /** | ||
| 280 | + * server接收请求 | ||
| 281 | + * | ||
| 282 | + * @param \Swoole\Server $server | ||
| 283 | + * @param $fd | ||
| 284 | + * @param $reactor_id | ||
| 285 | + * @param $data | ||
| 286 | + * @return mixed | ||
| 287 | + * @author pengjch 202439 11:34:0 | ||
| 288 | + */ | ||
| 289 | + public function onReceive(\Swoole\Server $server, $fd, $reactor_id, $data) | ||
| 290 | + { | ||
| 291 | + /** @var Request $request */ | ||
| 292 | + $request = $this->packer->unpack($data); | ||
| 293 | + //系统请求 | ||
| 294 | + if ($request->isSystem()) { | ||
| 295 | + return $server->send($fd, serialize($this->doSystemRequest($request))); | ||
| 296 | + } | ||
| 297 | + //同步请求 | ||
| 298 | + if ($request->isSync()) { | ||
| 299 | + return $server->send($fd, serialize($this->doRequest($request))); | ||
| 300 | + } | ||
| 301 | + //异步请求 | ||
| 302 | + $server->task($request); | ||
| 303 | + return $server->send($fd, serialize(Response::success(['result' => 'success']))); | ||
| 304 | + } | ||
| 305 | + | ||
| 306 | + /** | ||
| 307 | + * 执行请求 | ||
| 308 | + * | ||
| 309 | + * @param Request $request | ||
| 310 | + * @return Response | ||
| 311 | + * @author pengjch 2024313 9:37:20 | ||
| 312 | + */ | ||
| 313 | + public function doRequest(Request $request): Response | ||
| 314 | + { | ||
| 315 | + try { | ||
| 316 | + $handler = $this->getRequestHandler(); | ||
| 317 | + } catch (\ReflectionException $e) { | ||
| 318 | + return Response::error($e->getMessage()); | ||
| 319 | + } | ||
| 320 | + | ||
| 321 | + $response = $handler($request); | ||
| 322 | + if (!($response instanceof Response)) { | ||
| 323 | + $msg = 'The middleware must return the response type'; | ||
| 324 | + $this->logger->error($msg); | ||
| 325 | + $response = Response::error($msg); | ||
| 326 | + } | ||
| 327 | + | ||
| 328 | + return $response; | ||
| 329 | + } | ||
| 330 | + | ||
| 331 | + /** | ||
| 332 | + * 系统请求 | ||
| 333 | + * | ||
| 334 | + * @param Request $request | ||
| 335 | + * @return Response | ||
| 336 | + * @author pengjch 2024323 10:46:55 | ||
| 337 | + */ | ||
| 338 | + public function doSystemRequest(Request $request): Response | ||
| 339 | + { | ||
| 340 | + if ($request->getMethod() == 'stats') { | ||
| 341 | + return Response::success(['result' => $this->server->stats()]); | ||
| 342 | + } else { | ||
| 343 | + return Response::error($request->getMethod() . ' is not supported'); | ||
| 344 | + } | ||
| 345 | + } | ||
| 346 | + | ||
| 347 | + /** | ||
| 348 | + * @return mixed | ||
| 349 | + * @throws \ReflectionException | ||
| 350 | + * @author pengjch 2024312 16:36:52 | ||
| 351 | + */ | ||
| 352 | + public function getRequestHandler() | ||
| 353 | + { | ||
| 354 | + return array_reduce(array_reverse($this->middlewares), function ($stack, $next) { | ||
| 355 | + return function ($request) use ($stack, $next) { | ||
| 356 | + if ($next instanceof \Closure) { | ||
| 357 | + return $next($request, $stack); | ||
| 358 | + } elseif (is_string($next) && class_exists($next)) { | ||
| 359 | + return (new $next())->handle($request, $stack); | ||
| 360 | + } else { | ||
| 361 | + return $next->handle($request, $stack); | ||
| 362 | + } | ||
| 363 | + }; | ||
| 364 | + }, function ($request) { | ||
| 365 | + return $this->service->call($request); | ||
| 366 | + }); | ||
| 367 | + } | ||
| 368 | + | ||
| 369 | + /** | ||
| 370 | + * 异步处理请求 | ||
| 371 | + * | ||
| 372 | + * @param $server | ||
| 373 | + * @param $taskID | ||
| 374 | + * @param $reactorID | ||
| 375 | + * @param $data | ||
| 376 | + * @return Response | ||
| 377 | + * @author pengjch 2024313 9:40:37 | ||
| 378 | + */ | ||
| 379 | + public function OnTask($server, $taskID, $reactorID, $data): Response | ||
| 380 | + { | ||
| 381 | + $this->logger->debug('AsyncTask: Start', ['taskID' => $taskID]); | ||
| 382 | + return $this->doRequest($data); | ||
| 383 | + } | ||
| 384 | + | ||
| 385 | + /** | ||
| 386 | + * 完成异步任务回调 | ||
| 387 | + * | ||
| 388 | + * @param $server | ||
| 389 | + * @param $taskID | ||
| 390 | + * @param $data | ||
| 391 | + * @author pengjch 2024313 9:49:44 | ||
| 392 | + */ | ||
| 393 | + public function OnFinish($server, $taskID, $data) | ||
| 394 | + { | ||
| 395 | + $this->logger->debug('AsyncTask: Finish', ['taskID' => $taskID, 'data' => $data]); | ||
| 396 | + } | ||
| 397 | + | ||
| 398 | + /** | ||
| 399 | + * OnClose | ||
| 400 | + * | ||
| 401 | + * @param $server | ||
| 402 | + * @param $fd | ||
| 403 | + * @author pengjch 202439 11:34:48 | ||
| 404 | + */ | ||
| 405 | + public function OnClose($server, $fd) | ||
| 406 | + { | ||
| 407 | + $this->logger->debug('Client: Close'); | ||
| 408 | + } | ||
| 409 | + | ||
| 410 | + /** | ||
| 411 | + * OnConnect | ||
| 412 | + * | ||
| 413 | + * @param $server | ||
| 414 | + * @param $fd | ||
| 415 | + * @author pengjch 202439 11:34:52 | ||
| 416 | + */ | ||
| 417 | + public function OnConnect($server, $fd) | ||
| 418 | + { | ||
| 419 | + $this->logger->debug('Client: Connect.'); | ||
| 420 | + } | ||
| 421 | + | ||
| 422 | + /** | ||
| 423 | + * start | ||
| 424 | + * | ||
| 425 | + * @author pengjch 202439 11:34:56 | ||
| 426 | + */ | ||
| 427 | + public function start(): bool | ||
| 428 | + { | ||
| 429 | + //可用服务数量 | ||
| 430 | + if ($this->service->count() == 0) { | ||
| 431 | + $this->logger->error('There is no service available.'); | ||
| 432 | + return false; | ||
| 433 | + } | ||
| 434 | + //默认使用固定包头+包体方式解决粘包问题 | ||
| 435 | + if (empty($this->packer)) { | ||
| 436 | + $this->packer = new SerializeLengthPacker([ | ||
| 437 | + 'package_length_type' => $this->options['package_length_type'] ?? 'N', | ||
| 438 | + 'package_body_offset' => $this->options['package_body_offset'] ?? 4, | ||
| 439 | + ]); | ||
| 440 | + } | ||
| 441 | + | ||
| 442 | + $this->logger->info(sprintf('Rpc server[%s:%s] start.', $this->host, $this->port)); | ||
| 443 | + $this->server->start(); | ||
| 444 | + return true; | ||
| 445 | + } | ||
| 446 | +} |
src/Service.php
0 → 100755
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace AukeySwrpc; | ||
| 4 | + | ||
| 5 | + | ||
| 6 | +use Psr\Log\LoggerInterface; | ||
| 7 | +use ReflectionClass; | ||
| 8 | +use ReflectionMethod; | ||
| 9 | +use AukeySwrpc\Request\Request; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * Class Service | ||
| 13 | + * | ||
| 14 | + * @package Swrpc | ||
| 15 | + * @author pengjch 202439 11:39:41 | ||
| 16 | + */ | ||
| 17 | +class Service | ||
| 18 | +{ | ||
| 19 | + private array $services = []; | ||
| 20 | + protected array $filers | ||
| 21 | + = [ | ||
| 22 | + 'factory', | ||
| 23 | + 'initTracer', | ||
| 24 | + 'setModule', | ||
| 25 | + 'setTracerUrl', | ||
| 26 | + 'setParams', | ||
| 27 | + 'setTracerContext', | ||
| 28 | + 'getTracerContext' | ||
| 29 | + ]; | ||
| 30 | + | ||
| 31 | + /** @var LoggerInterface $logger */ | ||
| 32 | + private $logger; | ||
| 33 | + | ||
| 34 | + public function __construct($logger) | ||
| 35 | + { | ||
| 36 | + $this->logger = $logger; | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + /** | ||
| 40 | + * 注册服务实例 | ||
| 41 | + * | ||
| 42 | + * @param $obj | ||
| 43 | + * @param $prefix | ||
| 44 | + * @return bool | ||
| 45 | + * @author pengjch 202438 13:43:21 | ||
| 46 | + */ | ||
| 47 | + public function addInstance($obj, $prefix = ''): bool | ||
| 48 | + { | ||
| 49 | + if (is_string($obj)) { | ||
| 50 | + $obj = new $obj(); | ||
| 51 | + } | ||
| 52 | + if (!is_object($obj)) { | ||
| 53 | + $this->logger->error('Service is not an object.', ['service' => $obj]); | ||
| 54 | + return false; | ||
| 55 | + } | ||
| 56 | + if (!($obj instanceof LogicService)) { | ||
| 57 | + $this->logger->error('The Service does not inherit LogicService', ['service' => get_class($obj)]); | ||
| 58 | + return false; | ||
| 59 | + } | ||
| 60 | + $className = get_class($obj); | ||
| 61 | + $methods = get_class_methods($obj); | ||
| 62 | + foreach ($methods as $method) { | ||
| 63 | + if (in_array($method, $this->filers)) { | ||
| 64 | + continue; | ||
| 65 | + } | ||
| 66 | + if (strlen($prefix) > 0) { | ||
| 67 | + $key = $prefix . '_' . $className . '_' . $method; | ||
| 68 | + } else { | ||
| 69 | + $key = $className . '_' . $method; | ||
| 70 | + } | ||
| 71 | + $this->services[$key] = $className; | ||
| 72 | + $this->logger->info(sprintf('import %s => %s.', $key, $className)); | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + return true; | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + /** | ||
| 79 | + * 获取服务 | ||
| 80 | + * | ||
| 81 | + * @param $key | ||
| 82 | + * @return mixed|null | ||
| 83 | + * @author pengjch 202438 13:43:17 | ||
| 84 | + */ | ||
| 85 | + public function getService($key) | ||
| 86 | + { | ||
| 87 | + return $this->services[$key] ?? null; | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + /** | ||
| 91 | + * 获取所有服务 | ||
| 92 | + * getServices | ||
| 93 | + * | ||
| 94 | + * @return array | ||
| 95 | + * @author pengjch 202438 15:23:58 | ||
| 96 | + */ | ||
| 97 | + public function getServices(): array | ||
| 98 | + { | ||
| 99 | + return $this->services; | ||
| 100 | + } | ||
| 101 | + | ||
| 102 | + /** | ||
| 103 | + * count | ||
| 104 | + * | ||
| 105 | + * @return int | ||
| 106 | + * @author pengjch 202439 12:56:46 | ||
| 107 | + */ | ||
| 108 | + public function count(): int | ||
| 109 | + { | ||
| 110 | + return count($this->services); | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | + /** | ||
| 114 | + * @param $key | ||
| 115 | + * @return bool | ||
| 116 | + * @author pengjch 202438 14:32:50 | ||
| 117 | + */ | ||
| 118 | + public function isExist($key): bool | ||
| 119 | + { | ||
| 120 | + return isset($this->services[$key]); | ||
| 121 | + } | ||
| 122 | + | ||
| 123 | + /** | ||
| 124 | + * 调用服务 | ||
| 125 | + * | ||
| 126 | + * @param Request $request | ||
| 127 | + * @return Response | ||
| 128 | + * @throws \ReflectionException | ||
| 129 | + * @author pengjch 202439 10:17:59 | ||
| 130 | + */ | ||
| 131 | + public function call(Request $request): Response | ||
| 132 | + { | ||
| 133 | + if ($err = $request->getError()) { | ||
| 134 | + return Response::error($err); | ||
| 135 | + } | ||
| 136 | + | ||
| 137 | + $service = $this->getService($request->getMethod()); | ||
| 138 | + if (!$service) { | ||
| 139 | + $this->logger->debug('service is not exist.', ['method' => $request->getMethod()]); | ||
| 140 | + return Response::error('service is not exist.'); | ||
| 141 | + } | ||
| 142 | + | ||
| 143 | + $methodArr = explode('_', $request->getMethod()); | ||
| 144 | + $methodName = array_pop($methodArr); | ||
| 145 | + $reflect = new ReflectionClass($service); | ||
| 146 | + $instance = $reflect->newInstanceArgs(); | ||
| 147 | + if (!method_exists($instance, $methodName)) { | ||
| 148 | + $this->logger->debug('method is not exist.', ['method' => $request->getMethod()]); | ||
| 149 | + return Response::error(sprintf('%s method[%s] is not exist.', $service, $methodName)); | ||
| 150 | + } | ||
| 151 | + | ||
| 152 | + $ctx = $request->getTraceContext(); | ||
| 153 | + if ($ctx && method_exists($instance, 'setTracerContext')) { | ||
| 154 | + $instance->setTracerUrl($ctx->getReporterUrl())->setTracerContext($ctx); | ||
| 155 | + } | ||
| 156 | + | ||
| 157 | + try { | ||
| 158 | + $methodObj = new ReflectionMethod($reflect->getName(), $methodName); | ||
| 159 | + $result = $methodObj->invokeArgs($instance, $request->getParams()); | ||
| 160 | + } catch (\Throwable $e) { | ||
| 161 | + return Response::error($e->getMessage()); | ||
| 162 | + } | ||
| 163 | + | ||
| 164 | + return Response::success([ | ||
| 165 | + 'result' => $result | ||
| 166 | + ]); | ||
| 167 | + } | ||
| 168 | +} |
src/Tracer/TracerContext.php
0 → 100755
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace AukeySwrpc\Tracer; | ||
| 4 | + | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * 链路追踪上下文 | ||
| 8 | + * Class TracerContext | ||
| 9 | + * | ||
| 10 | + * @package AukeySwrpc\Tracer | ||
| 11 | + * @author pengjch 2024311 10:21:34 | ||
| 12 | + */ | ||
| 13 | +class TracerContext | ||
| 14 | +{ | ||
| 15 | + protected $traceID; | ||
| 16 | + protected $parentID; | ||
| 17 | + protected $reporterUrl; | ||
| 18 | + | ||
| 19 | + public function __construct($traceID, $parentID, $reporterUrl) | ||
| 20 | + { | ||
| 21 | + $this->traceID = $traceID; | ||
| 22 | + $this->parentID = $parentID; | ||
| 23 | + $this->reporterUrl = $reporterUrl; | ||
| 24 | + } | ||
| 25 | + | ||
| 26 | + public static function create($traceID, $parentID, $reporterUrl) | ||
| 27 | + { | ||
| 28 | + return new static($traceID, $parentID, $reporterUrl); | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + public function setTraceID($traceID) | ||
| 32 | + { | ||
| 33 | + $this->traceID = $traceID; | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + public function setParentID($parentID) | ||
| 37 | + { | ||
| 38 | + $this->parentID = $parentID; | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + public function setReporterUrl($url) | ||
| 42 | + { | ||
| 43 | + $this->reporterUrl = $url; | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + public function getTraceID() | ||
| 47 | + { | ||
| 48 | + return $this->traceID; | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + public function getParentID() | ||
| 52 | + { | ||
| 53 | + return $this->parentID; | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + public function getReporterUrl() | ||
| 57 | + { | ||
| 58 | + return $this->reporterUrl; | ||
| 59 | + } | ||
| 60 | +} |
-
请 注册 或 登录 后发表评论