作者 pengjch

dev: composer test

1 { 1 {
2 - "name": "aukey/aukeySwrpc", 2 + "name": "aukey/swrpc",
3 "description": "基于swoole的rpc库", 3 "description": "基于swoole的rpc库",
4 "license": "MIT", 4 "license": "MIT",
5 "authors": [ 5 "authors": [
@@ -20,8 +20,8 @@ @@ -20,8 +20,8 @@
20 }, 20 },
21 "autoload": { 21 "autoload": {
22 "psr-4": { 22 "psr-4": {
23 - "AukeySwrpc\\": "src/",  
24 - "AukeySwrpcTests\\": "tests/" 23 + "Swrpc\\": "src/",
  24 + "SwrpcTests\\": "tests/"
25 }, 25 },
26 "classmap": [ 26 "classmap": [
27 "src/" 27 "src/"
1 -<?php  
2 -  
3 -namespace AukeySwrpc;  
4 -  
5 -use Illuminate\Support\ServiceProvider;  
6 -  
7 -class AukeyAukeySwrpcProvider extends ServiceProvider  
8 -{  
9 - public function boot()  
10 - {  
11 - $this->loadMigrationsFrom(__DIR__ . '/database/migrations');  
12 - if ($this->app->runningInConsole()) {  
13 - $this->commands([  
14 - \AukeyDataCenter\Commands\CreateBaseCode::class,  
15 - \AukeyDataCenter\Commands\SheinReturnOrderCom::class,  
16 - \AukeyDataCenter\Commands\SheinProductCom::class,  
17 - \AukeyDataCenter\Commands\SheinBrandCom::class,  
18 - ]);  
19 - }  
20 - }  
21 -  
22 - public function register()  
23 - {  
24 - $provides = [  
25 - 'AukeyDataCenter\Http\RouteServiceProvider',  
26 - ];  
27 - foreach ($provides as $provider) {  
28 - $this->app->register($provider);  
29 - }  
30 - }  
31 -}  
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 AukeySwrpc  
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 AukeySwrpc\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 -}  
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 -}  
1 -<?php  
2 -  
3 -namespace AukeySwrpc\Exceptions;  
4 -  
5 -  
6 -use Exception;  
7 -  
8 -/**  
9 - * Class RequestException  
10 - *  
11 - * @package AukeySwrpc\Exceptions  
12 - * @author pengjch 202439 11:38:5  
13 - */  
14 -class RequestException extends Exception  
15 -{  
16 -  
17 -}  
1 -<?php  
2 -  
3 -namespace AukeySwrpc\Exceptions;  
4 -  
5 -  
6 -use Exception;  
7 -  
8 -/**  
9 - * Class RpcException  
10 - *  
11 - * @package AukeySwrpc\Exceptions  
12 - * @author pengjch 202439 11:38:5  
13 - */  
14 -class RpcException extends Exception  
15 -{  
16 -  
17 -}  
1 -<?php  
2 -  
3 -namespace AukeySwrpc\Exceptions;  
4 -  
5 -  
6 -use Exception;  
7 -  
8 -/**  
9 - * Class TypeException  
10 - *  
11 - * @package AukeySwrpc\Exceptions  
12 - * @author pengjch 202439 11:38:5  
13 - */  
14 -class TypeException extends Exception  
15 -{  
16 -  
17 -}  
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 AukeySwrpc  
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 -}  
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 -}  
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 -}  
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 -}  
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 -}  
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 -}  
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 -}  
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 -}  
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 -}  
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 -}  
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 -}  
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 -}  
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 -}  
1 -<?php  
2 -  
3 -namespace AukeySwrpc;  
4 -  
5 -  
6 -/**  
7 - * Class Response  
8 - *  
9 - * @package AukeySwrpc  
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 -}  
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 AukeySwrpc  
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('AukeySwrpc');  
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 -}  
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 AukeySwrpc  
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 -}  
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 -}  
1 -<?php  
2 -  
3 -namespace AukeySwrpcTests;  
4 -  
5 -  
6 -use PHPUnit\Framework\TestCase;  
7 -  
8 -/**  
9 - * Class BootTest  
10 - *  
11 - * @author wuzhc  
12 - * @internal  
13 - */  
14 -abstract class BootTest extends TestCase  
15 -{  
16 - const PID_FILE = __DIR__ . '/AukeySwrpc.pid';  
17 - const SERVER_LOG = __DIR__ . '/AukeySwrpc.log';  
18 - const SERVER_SCRIPT = __DIR__ . '/server.sh';  
19 -  
20 - public static function setUpBeforeClass(): void  
21 - {  
22 - // fwrite(STDOUT, 'Starting rpc server...' . PHP_EOL);  
23 - $cmd = 'nohup ' . self::SERVER_SCRIPT . ' > ' . self::SERVER_LOG . ' 2>&1 &';  
24 - shell_exec($cmd);  
25 - sleep(5);  
26 -  
27 - self::assertFileExists(self::PID_FILE, 'Run rpc server failed: ' . $cmd . '');  
28 - $pid = file_get_contents(self::PID_FILE);  
29 - self::assertNotEmpty($pid, 'Failed to start the rpc server.');  
30 -  
31 - $res = shell_exec('ps aux | grep ' . $pid . ' | wc -l');  
32 - self::assertGreaterThanOrEqual(1, intval($res), 'Failed to start the rpc server.');  
33 -  
34 - // fwrite(STDOUT, 'Rpc server started successfully.' . PHP_EOL);  
35 - }  
36 -  
37 - public static function tearDownAfterClass(): void  
38 - {  
39 - if (\file_exists(self::PID_FILE)) {  
40 - $pid = file_get_contents(self::PID_FILE);  
41 - \shell_exec('kill -15 ' . $pid);  
42 - if (\file_exists(self::PID_FILE)) {  
43 - \unlink(self::PID_FILE);  
44 - }  
45 - \sleep(1);  
46 - }  
47 - }  
48 -}  
1 -<?php  
2 -  
3 -namespace AukeySwrpcTests;  
4 -  
5 -  
6 -use AukeySwrpc\Register\Consul;  
7 -use AukeySwrpc\Register\Service;  
8 -use AukeySwrpc\Request;  
9 -use AukeySwrpc\Client;  
10 -  
11 -/**  
12 - * 客户端单元测试  
13 - * php74 ../phpunit.phar tests/ClientTest.php --debug  
14 - * Class ClientTest  
15 - *  
16 - * @link http://www.phpunit.cn/manual/7.0/zh_cn/index.html  
17 - * @author pengjch 2024312 9:39:22  
18 - */  
19 -class ClientTest extends BootTest  
20 -{  
21 - /**  
22 - * @return Client Client  
23 - * @author pengjch 2024312 14:29:28  
24 - */  
25 - public function testClientConnect(): Client  
26 - {  
27 - $client = Client::create('School_Module', getenv('RPC_SERVER_HOST'), getenv('RPC_SERVER_PORT'));  
28 - $conn = $client->connect();  
29 - $this->assertIsBool($conn->isConnected(), 'Client connect failure.');  
30 - return $client;  
31 - }  
32 -  
33 - /**  
34 - * @depends testClientConnect  
35 - * @param Client $client  
36 - * @author pengjch 2024312 14:29:20  
37 - */  
38 - public function testClientSyncRequest($client)  
39 - {  
40 - $request = Request\SyncRequest::create('AukeySwrpcTests\services\SchoolService_getUserSchool', [1, 1]);  
41 - $res = $client->send($request);  
42 - $this->assertEquals('未来学校1', $res);  
43 - }  
44 -  
45 - /**  
46 - * @depends testClientConnect  
47 - * @param $client  
48 - * @author pengjch 2024313 10:3:43  
49 - */  
50 - public function testClientAsyncRequest($client)  
51 - {  
52 - $request = Request\AsyncRequest::create('AukeySwrpcTests\services\SchoolService_saveUserName', ['tony']);  
53 - $res = $client->send($request);  
54 - $this->assertEquals('success', $res);  
55 - sleep(3);  
56 - $this->assertFileExists('xxx.log', 'Async request failure.');  
57 - $value = file_get_contents('xxx.log');  
58 - $this->assertEquals('tony', $value);  
59 - @unlink('xxx.log');  
60 - }  
61 -}  
1 -<?php  
2 -  
3 -namespace AukeySwrpcTests;  
4 -  
5 -  
6 -use PHPUnit\Framework\TestCase;  
7 -use AukeySwrpc\Request\SyncRequest;  
8 -  
9 -/**  
10 - * Class PackerTest  
11 - * php74 ../phpunit.phar tests/ClientTest.php  
12 - *  
13 - * @package AukeySwrpcTests  
14 - * @author pengjch 2024312 16:5:14  
15 - */  
16 -class PackerTest extends TestCase  
17 -{  
18 - /**  
19 - * 注意:Request类属性和方法发生变化时,这个测试案例就没有意义了  
20 - * @return string  
21 - * @author pengjch 2024312 14:57:32  
22 - */  
23 - public function testSerializeLengthPack()  
24 - {  
25 - $packer = new \AukeySwrpc\Packer\SerializeLengthPacker();  
26 - $result = $packer->pack(SyncRequest::create('SchoolService_getName', [1, 1]));  
27 - $this->assertEquals('AAAAzU86MjU6IlN3cnBjXFJlcXVlc3RcU3luY1JlcXVlc3QiOjY6e3M6OToiACoAbWV0aG9kIjtzOjIxOiJTY2hvb2xTZXJ2aWNlX2dldE5hbWUiO3M6OToiACoAcGFyYW1zIjthOjI6e2k6MDtpOjE7aToxO2k6MTt9czo5OiIAKgBpc1N5bmMiO2I6MTtzOjExOiIAKgBpc1N5c3RlbSI7YjowO3M6ODoiACoAZXJyb3IiO047czoxNToiACoAdHJhY2VDb250ZXh0IjtOO30=', base64_encode($result));  
28 - return base64_encode($result);  
29 - }  
30 -  
31 - /**  
32 - * @depends testSerializeLengthPack  
33 - * @author pengjch 2024312 14:57:23  
34 - */  
35 - public function testSerializeLenghtUnpack($value)  
36 - {  
37 - $expect = SyncRequest::create('SchoolService_getName', [1, 1]);  
38 - $packer = new \AukeySwrpc\Packer\SerializeLengthPacker();  
39 - $result = $packer->unpack(base64_decode($value));  
40 - $this->assertSame(serialize($expect), serialize($result));  
41 - }  
42 -  
43 - /**  
44 - * 注意:Request类属性和方法发生变化时,这个测试案例就没有意义了  
45 - * @return string  
46 - * @author pengjch 2024312 14:57:32  
47 - */  
48 - public function testSerializeEofPack()  
49 - {  
50 - $packer = new \AukeySwrpc\Packer\SerializeEofPacker();  
51 - $result = $packer->pack(SyncRequest::create('SchoolService_getName', [1, 1]));  
52 - $this->assertEquals('TzoyNToiU3dycGNcUmVxdWVzdFxTeW5jUmVxdWVzdCI6Njp7czo5OiIAKgBtZXRob2QiO3M6MjE6IlNjaG9vbFNlcnZpY2VfZ2V0TmFtZSI7czo5OiIAKgBwYXJhbXMiO2E6Mjp7aTowO2k6MTtpOjE7aToxO31zOjk6IgAqAGlzU3luYyI7YjoxO3M6MTE6IgAqAGlzU3lzdGVtIjtiOjA7czo4OiIAKgBlcnJvciI7TjtzOjE1OiIAKgB0cmFjZUNvbnRleHQiO047fQ==', base64_encode($result));  
53 - return base64_encode($result);  
54 - }  
55 -  
56 - /**  
57 - * @depends testSerializeEofPack  
58 - * @author pengjch 2024312 14:57:23  
59 - */  
60 - public function testSerializeEofUnpack($value)  
61 - {  
62 - $expect = SyncRequest::create('SchoolService_getName', [1, 1]);  
63 - $packer = new \AukeySwrpc\Packer\SerializeEofPacker();  
64 - $result = $packer->unpack(base64_decode($value));  
65 - $this->assertSame(serialize($expect), serialize($result));  
66 - }  
67 -}  
1 -<?php  
2 -  
3 -namespace AukeySwrpcTests;  
4 -  
5 -  
6 -use Monolog\Logger;  
7 -use AukeySwrpc\Register\Consul;  
8 -use AukeySwrpc\Register\Service;  
9 -use AukeySwrpc\Request\Request;  
10 -use AukeySwrpc\Request\SyncRequest;  
11 -use AukeySwrpc\Server;  
12 -use AukeySwrpcTests\services\UserService;  
13 -  
14 -/**  
15 - * Class ServerTest  
16 - * php74 ../phpunit.phar tests/ClientTest.php  
17 - *  
18 - * @package AukeySwrpcTests  
19 - * @author pengjch 2024312 16:5:7  
20 - */  
21 -class ServerTest extends \PHPUnit\Framework\TestCase  
22 -{  
23 - /**  
24 - * @author pengjch 2024312 17:8:31  
25 - */  
26 - public function testServerRegisterToConsul()  
27 - {  
28 - $res = shell_exec('netstat anp | grep ' . getenv('CONSUL_PORT') . ' | wc -l');  
29 - $this->assertGreaterThanOrEqual(1, intval($res), 'Warning: Consul not started.');  
30 -  
31 - $consul = new Consul('http://' . getenv('CONSUL_HOST') . ':' . getenv('CONSUL_PORT'));  
32 - $consul->register('test_module', '127.0.0.1', 8080);  
33 -  
34 - $isSuccess = false;  
35 - $services = $consul->getServices('test_module');  
36 - /** @var Service $service */  
37 - foreach ($services as $service) {  
38 - if ($service->getHost() == '127.0.0.1' && $service->getPort() == 8080) {  
39 - $isSuccess = true;  
40 - break;  
41 - }  
42 - }  
43 -  
44 - $this->assertIsBool($isSuccess);  
45 - return $consul;  
46 - }  
47 -  
48 - /**  
49 - * @depends testServerRegisterToConsul  
50 - * @param Consul $consul  
51 - * @author pengjch 2024312 17:12:17  
52 - */  
53 - public function testServerUnregisterFromConsul($consul)  
54 - {  
55 - $consul->unRegister('127.0.0.1', 8080);  
56 - $isSuccess = true;  
57 - $services = $consul->getServices('test_module');  
58 - /** @var Service $service */  
59 - foreach ($services as $service) {  
60 - if ($service->getHost() == '127.0.0.1' && $service->getPort() == 8080) {  
61 - $isSuccess = false;  
62 - break;  
63 - }  
64 - }  
65 - $this->assertIsBool($isSuccess);  
66 - }  
67 -  
68 - /**  
69 - * @return Server  
70 - * @author pengjch 2024312 17:8:17  
71 - */  
72 - public function testServerAddService()  
73 - {  
74 - $logger = new Logger('swprc');  
75 - $server = new Server('School_Module', getenv('RPC_SERVER_HOST'), getenv('RPC_SERVER_PORT'), [], null, null, $logger);  
76 - $server->addService(UserService::class);  
77 - $key = UserService::class . '_getName';  
78 - $value = $server->getService($key);  
79 - $this->assertEquals(UserService::class, $value);  
80 - return $server;  
81 - }  
82 -  
83 - /**  
84 - * @depends testServerAddService  
85 - * @param $server  
86 - * @author pengjch 2024312 16:40:0  
87 - */  
88 - public function testServerAddMiddleware($server)  
89 - {  
90 - $request = SyncRequest::create('AukeySwrpcTests\services\UserService_getFavoriteFood', ['肥胖']);  
91 - $server->addMiddleware(function (Request $request, $next) {  
92 - $request->setParams(['帅气']);  
93 - return $next($request);  
94 - });  
95 - $func = $server->getRequestHandler();  
96 - $result = $func($request);  
97 - $this->assertEquals('帅气的我喜欢吃苹果', $result->data['result']);  
98 - }  
99 -}  
1 -#!/usr/bin/env /opt/php74/bin/php  
2 -<?php  
3 -  
4 -use AukeySwrpc\Register\Consul;  
5 -use AukeySwrpc\Server;  
6 -  
7 -$basePath = dirname(dirname(__FILE__));  
8 -require_once $basePath . "/vendor/autoload.php";  
9 -  
10 -$options = [  
11 - 'enable_coroutine' => true,  
12 - 'pid_file' => __DIR__ . '/AukeySwrpc.pid',  
13 -];  
14 -$server = new Server('School_Module', getenv('RPC_SERVER_HOST'), getenv('RPC_SERVER_PORT'), $options);  
15 -$server->addRegister(new Consul())  
16 - ->addService(\AukeySwrpcTests\services\UserService::class)  
17 - ->addService(\AukeySwrpcTests\services\SchoolService::class)  
18 - ->addService(\AukeySwrpcTests\services\ClassService::class)  
19 - ->start();  
1 -<?php  
2 -  
3 -namespace AukeySwrpcTests\services;  
4 -  
5 -  
6 -use AukeySwrpc\Exceptions\RpcException;  
7 -use AukeySwrpc\LogicService;  
8 -use AukeySwrpc\Register\Consul;  
9 -use AukeySwrpc\Request\SyncRequest;  
10 -  
11 -/**  
12 - * Class ClassService  
13 - *  
14 - * @package AukeySwrpcTests\services  
15 - * @author pengjch 2024313 9:15:21  
16 - */  
17 -class ClassService extends LogicService  
18 -{  
19 - public function getUserClass($userID = 1): string  
20 - {  
21 - $register = new Consul();  
22 - try {  
23 - $classID = 111;  
24 - $client = \AukeySwrpc\Client::createBalancer('School_Module', $register, \AukeySwrpc\Client::STRATEGY_WEIGHT);  
25 - $result = $client->send(SyncRequest::create('SchoolService_getUserSchool', [  
26 - $userID,  
27 - $classID,  
28 - ], $this->getTracerContext(__FUNCTION__)));  
29 - } catch (RpcException $e) {  
30 - return $e->getMessage() . PHP_EOL;  
31 - }  
32 -  
33 - return '高一2班, school:' . $result;  
34 - }  
35 -}  
1 -<?php  
2 -  
3 -namespace AukeySwrpcTests\services;  
4 -  
5 -  
6 -use AukeySwrpc\LogicService;  
7 -  
8 -/**  
9 - * Class SchoolService  
10 - *  
11 - * @package AukeySwrpcTests\services  
12 - * @author pengjch 2024313 9:15:30  
13 - */  
14 -class SchoolService extends LogicService  
15 -{  
16 - public function getUserSchool($userID, $classID): string  
17 - {  
18 - return '未来学校' . $userID;  
19 - }  
20 -  
21 - public function saveUserName($name)  
22 - {  
23 - file_put_contents('xxx.log', $name);  
24 - }  
25 -}  
1 -<?php  
2 -  
3 -namespace AukeySwrpcTests\services;  
4 -  
5 -  
6 -use AukeySwrpc\Exceptions\RpcException;  
7 -use AukeySwrpc\LogicService;  
8 -use AukeySwrpc\Register\Consul;  
9 -use AukeySwrpc\Request\SyncRequest;  
10 -  
11 -/**  
12 - * Class UserService  
13 - *  
14 - * @package AukeySwrpcTests\services  
15 - * @author pengjch 2024313 9:15:52  
16 - */  
17 -class UserService extends LogicService  
18 -{  
19 - /**  
20 - * @return UserService  
21 - * @author pengjch 2024311 11:32:35  
22 - */  
23 - public static function factory()  
24 - {  
25 - return parent::factory();  
26 - }  
27 -  
28 - public function getName(): string  
29 - {  
30 - $register = new Consul();  
31 - try {  
32 - $userID = 1;  
33 - $client = \AukeySwrpc\Client::createBalancer('Class_Module', $register, \AukeySwrpc\Client::STRATEGY_WEIGHT);  
34 - $result = $client->send(SyncRequest::create('ClassService_getUserClass', [$userID], $this->getTracerContext(__FUNCTION__)));  
35 - } catch (RpcException $e) {  
36 - return $e->getMessage() . PHP_EOL;  
37 - }  
38 -  
39 - return 'user:wuzhc, class:' . $result;  
40 - }  
41 -  
42 - public function getAge(): int  
43 - {  
44 - return 30;  
45 - }  
46 -  
47 - public function getFavoriteFood($prefix)  
48 - {  
49 - return $prefix . '的我喜欢吃苹果';  
50 - }  
51 -}