diff --git a/Annotation/Annotation.php b/Annotation/Annotation.php index 0eb9e1c9..99e0445c 100644 --- a/Annotation/Annotation.php +++ b/Annotation/Annotation.php @@ -5,6 +5,7 @@ namespace Annotation; use DirectoryIterator; +use Exception; use Snowflake\Abstracts\Component; use Snowflake\Exception\ComponentException; @@ -51,7 +52,7 @@ class Annotation extends Component * @param string $namespace * @param string $alias * @return void - * @throws ComponentException + * @throws Exception */ public function read(string $path, string $namespace, string $alias = 'root'): void { diff --git a/Annotation/Loader.php b/Annotation/Loader.php index c3900dfd..f8594e3c 100644 --- a/Annotation/Loader.php +++ b/Annotation/Loader.php @@ -6,6 +6,7 @@ namespace Annotation; use Attribute; use DirectoryIterator; +use Exception; use ReflectionClass; use ReflectionMethod; use ReflectionProperty; @@ -121,7 +122,7 @@ class Loader extends BaseObject /** * @param DirectoryIterator $paths * @param $namespace - * @throws ComponentException + * @throws Exception */ public function _scanDir(DirectoryIterator $paths, $namespace) { @@ -216,6 +217,11 @@ class Loader extends BaseObject } $annotations = $this->_classes[$className]; + if (isset($_array['target']) && !empty($_array['target'])) { + foreach ($_array['target'] as $value) { + $value->execute([$annotations['handler']]); + } + } foreach ($annotations['methods'] as $name => $attribute) { foreach ($attribute as $value) { diff --git a/Annotation/Rpc/RpcService.php b/Annotation/Rpc/RpcService.php index f8bca780..cd3e8dd3 100644 --- a/Annotation/Rpc/RpcService.php +++ b/Annotation/Rpc/RpcService.php @@ -6,6 +6,7 @@ namespace Annotation\Rpc; use Annotation\Attribute; use ReflectionException; +use Rpc\IProducer; use Snowflake\Exception\ComponentException; use Snowflake\Exception\NotFindClassException; use Snowflake\Snowflake; @@ -18,6 +19,8 @@ use Snowflake\Snowflake; #[\Attribute(\Attribute::TARGET_CLASS)] class RpcService extends Attribute { + private array $config; + /** * RpcClient constructor. @@ -33,6 +36,7 @@ use Snowflake\Snowflake; public int $mode = SWOOLE_SOCK_TCP6 ) { + $this->config = ['host' => $this->host, 'port' => $this->port, 'mode' => $this->mode]; } @@ -45,13 +49,15 @@ use Snowflake\Snowflake; */ public function execute(array $handler): mixed { + // TODO: Change the autogenerated stub + if ($handler[0] instanceof IProducer) { + call_user_func([$handler[0], 'instance']); + } + $rpc = Snowflake::app()->getRpc(); - $rpc->addProducer($this->cmd, $handler, [ - 'host' => $this->host, - 'port' => $this->port, - 'mode' => $this->mode - ]); - return parent::execute($handler); // TODO: Change the autogenerated stub + $rpc->addProducer($this->cmd, $handler, $this->config); + + return parent::execute($handler); } diff --git a/HttpServer/Http/HttpParams.php b/HttpServer/Http/HttpParams.php index 9fce4ab2..128056f0 100644 --- a/HttpServer/Http/HttpParams.php +++ b/HttpServer/Http/HttpParams.php @@ -26,394 +26,433 @@ use Snowflake\Snowflake; class HttpParams { - private ?array $body = []; + private ?array $body = []; - /** @var array */ - private array $gets = []; + /** @var array */ + private array $gets = []; - /** @var array */ - private array $files = []; - private array $socket = []; + /** @var array */ + private array $files = []; + private array $socket = []; - /** - * HttpParams constructor. - * @param $body - * @param $get - * @param $files - * @param array $socket - */ - public function __construct($body, $get, $files, $socket = []) - { - $this->gets = $get ?? []; - $this->files = $files ?? []; - $this->socket = $socket ?? []; - if (!is_array($body)) { - $this->body = Help::toArray($body); - } else { - $this->body = $body ?? []; - } - } + /** + * HttpParams constructor. + * @param $body + * @param $get + * @param $files + * @param array $socket + */ + public function __construct($body, $get, $files, $socket = []) + { + $this->gets = $get ?? []; + $this->files = $files ?? []; + $this->socket = $socket ?? []; + if (!is_array($body)) { + $this->body = Help::toArray($body); + } else { + $this->body = $body ?? []; + } + } - /** - * @return int - */ - public function offset(): int - { - return ($this->page() - 1) * $this->size(); - } + /** + * @return int + */ + public function offset(): int + { + return ($this->page() - 1) * $this->size(); + } - /** - * @param array $data - * 批量添加数据 - */ - public function setPosts(array $data) - { - if (!is_array($data)) { - return; - } - foreach ($data as $key => $vla) { - $this->body[$key] = $vla; - } - } + /** + * @param array $data + * 批量添加数据 + */ + public function setPosts(array $data) + { + if (!is_array($data)) { + return; + } + foreach ($data as $key => $vla) { + $this->body[$key] = $vla; + } + } - /** - * @return mixed - */ - public function getBody(): mixed - { - return $this->body; - } + /** + * 删除参数 + */ + public function clearBody() + { + $this->body = []; + } - /** - * @param string $key - * @param string $value - */ - public function addGetParam(string $key, string $value) - { - $this->gets[$key] = $value; - } - - /** - * @return int - */ - private function page(): int - { - return (int)$this->get('page', 1); - } - - /** - * @return int - */ - public function size(): int - { - return (int)$this->get('size', 20); - } + /** + * 删除参数 + */ + public function clearGet() + { + $this->gets = []; + } - /** - * @param $name - * @param null $defaultValue - * @param null $call - * @return mixed - */ - public function get($name, $defaultValue = null, $call = null): mixed - { - return $this->gets[$name] ?? $defaultValue; - } - - /** - * @param $name - * @param null $defaultValue - * @param null $call - * @return mixed - */ - public function post($name, $defaultValue = null, $call = null): mixed - { - $data = $this->body[$name] ?? $defaultValue; - if ($call !== null) { - $data = call_user_func($call, $data); - } - return $data; - } - - /** - * @param $name - * @return bool|string - * @throws Exception - */ - public function json($name): bool|string - { - $data = $this->array($name); - if (empty($data)) { - return Json::encode([]); - } else if (!is_array($data)) { - return Json::encode([]); - } - return Json::encode($data); - } - - /** - * @return array - */ - public function gets(): array - { - return $this->gets; - } - - /** - * @return array - */ - #[Pure] public function params(): array - { - return array_merge($this->body ?? [], $this->files ?? []); - } - - /** - * @return array - */ - #[Pure] public function load(): array - { - return array_merge($this->files ?? [], $this->body ?? [], $this->gets ?? [], $this->socket ?? []); - } - - /** - * @param $name - * @param array $defaultValue - * @return mixed - */ - public function array($name, $defaultValue = []): mixed - { - return $this->body[$name] ?? $defaultValue; - } - - /** - * @param $name - * @return File|null - * @throws ReflectionException - * @throws NotFindClassException - */ - public function file($name): File|null - { - if (!isset($this->files[$name])) { - return null; - } - $param = $this->files[$name]; - $param['class'] = File::class; - return Snowflake::createObject($param); - } - - /** - * @param $name - * @param bool $isNeed - * @return mixed - * @throws RequestException - */ - private function required(string $name, bool $isNeed = false): mixed - { - $body = array_merge($this->body ?? [], $this->socket ?? []); - - $int = $body[$name] ?? NULL; - if (is_null($int) && $isNeed === true) { - throw new RequestException("You need to add request parameter $name"); - } - return $int; - } - - /** - * @param $name - * @param bool $isNeed - * @param null $min - * @param null $max - * @return int|null - * @throws RequestException - */ - public function int(string $name, bool $isNeed = FALSE, array|int|null $min = NULL, int|null $max = NULL): ?int - { - $int = $this->required($name, $isNeed); - if (is_null($int)) return null; - if (is_array($min)) { - list($min, $max) = $min; - } - $length = strlen((string)$int); - if (!is_numeric($int) || intval($int) != $int) { - throw new RequestException("The request parameter $name must integer."); - } - $this->between($length, $min, $max); - return (int)$int; - } - - /** - * @param $name - * @param bool $isNeed - * @param int $round - * @return float|null - * @throws RequestException - */ - public function float(string $name, bool $isNeed = FALSE, $round = 0): ?float - { - $int = $this->required($name, $isNeed); - if ($int === null) { - return null; - } - if ($round > 0) { - return round(floatval($int), $round); - } else { - return floatval($int); - } - } - - /** - * @param $name - * @param bool $isNeed - * @param null $length - * - * @return string - * @throws - */ - public function string(string $name, bool $isNeed = FALSE, int|array|null $length = NULL): ?string - { - $string = $this->required($name, $isNeed); - if ($string === null || $length === null) { - return $string; - } - if (is_numeric($length)) { - $length = [$length, $length]; - } - return $this->between($string, $length[0], $length[1] ?? $length[0]); - } - - /** - * @param $_length - * @param $min - * @param $max - * @throws RequestException - */ - private function between($string, $min, $max): mixed - { - $_length = mb_strlen($string); - if ($min !== NULL && $_length < $min) { - throw new RequestException("The minimum value cannot be lower than $min, has length $_length"); - } - if ($max !== NULL && $_length > $max) { - throw new RequestException("Maximum cannot exceed $max, has length " . $_length); - } - return $string; - } - - /** - * @param $name - * @param bool $isNeed - * - * @return string|null - * @throws RequestException - */ - public function email(string $name, bool $isNeed = FALSE): ?string - { - $email = $this->required($name, $isNeed); - if ($email === null) { - return null; - } - if (!preg_match('/^\w+([.-_]\w+)+@\w+(\.\w+)+$/', $email)) { - throw new RequestException("Request parameter $name is in the wrong format", 4001); - } - return $email; - } + /** + * 清空文件上传信息 + */ + public function clearFile() + { + $this->files = []; + } - /** - * @param $name - * @param bool $isNeed - * - * @return bool|string - * @throws RequestException - */ - public function bool(string $name, bool $isNeed = FALSE): bool - { - $email = $this->required($name, $isNeed); - if ($email === null) { - return false; - } - return (bool)$email; - } - - /** - * @param $name - * @param null $default - * - * @return int|string|null - * @throws RequestException - */ - public function timestamp(string $name, int|null $default = NULL): null|int|string - { - $value = $this->required($name, false); - if ($value === null) { - return $default; - } - if (!is_numeric($value)) { - throw new RequestException('The request param :attribute not is a timestamp value'); - } - if (strlen((string)$value) != 10) { - throw new RequestException('The request param :attribute not is a timestamp value'); - } - if (!date('YmdHis', $value)) { - throw new RequestException('The request param :attribute format error', 4001); - } - return $value; - } - - /** - * @param $name - * @param null $default - * - * @return mixed - * @throws RequestException - */ - public function datetime(string $name, string $default = NULL): string|null - { - $value = $this->required($name, false); - if ($value === null) { - return $default; - } - $match = '/^\d{4}.*?([1-12]).*([1-31]).*?[0-23].*?[0-59].*?[0-59].*?$/'; - $match = preg_match($match, $value, $result); - if (!$match || $result[0] != $value) { - throw new RequestException('The request param :attribute format error', 4001); - } - return $value; - } + /** + * @return mixed + */ + public function getBody(): mixed + { + return $this->body; + } - /** - * @param $name - * @param null $default - * @return mixed - * @throws RequestException - */ - public function ip(string $name, string $default = NULL): string|null - { - $value = $this->required($name, false); - if ($value == NULL) { - return $default; - } - $match = preg_match('/^\d{1,3}(\.\d{1,3}){3}$/', $value, $result); - if (!$match || $result[0] != $value) { - throw new RequestException('The request param :attribute format error', 4001); - } - return $value; - } + /** + * @return mixed + */ + public function getBodyAndClear(): mixed + { + $data = $this->body; + $this->clearBody(); + return $data; + } - /** - * @param $name - * @return mixed - */ - #[Pure] public function __get($name): mixed - { - $load = $this->load(); + /** + * @param string $key + * @param string $value + */ + public function addGetParam(string $key, string $value) + { + $this->gets[$key] = $value; + } - return $load[$name] ?? null; - } + /** + * @return int + */ + private function page(): int + { + return (int)$this->get('page', 1); + } + + /** + * @return int + */ + public function size(): int + { + return (int)$this->get('size', 20); + } + + + /** + * @param $name + * @param null $defaultValue + * @param null $call + * @return mixed + */ + public function get($name, $defaultValue = null, $call = null): mixed + { + return $this->gets[$name] ?? $defaultValue; + } + + /** + * @param $name + * @param null $defaultValue + * @param null $call + * @return mixed + */ + public function post($name, $defaultValue = null, $call = null): mixed + { + $data = $this->body[$name] ?? $defaultValue; + if ($call !== null) { + $data = call_user_func($call, $data); + } + return $data; + } + + /** + * @param $name + * @return bool|string + * @throws Exception + */ + public function json($name): bool|string + { + $data = $this->array($name); + if (empty($data)) { + return Json::encode([]); + } else if (!is_array($data)) { + return Json::encode([]); + } + return Json::encode($data); + } + + /** + * @return array + */ + public function gets(): array + { + return $this->gets; + } + + /** + * @return array + */ + #[Pure] public function params(): array + { + return array_merge($this->body ?? [], $this->files ?? []); + } + + /** + * @return array + */ + #[Pure] public function load(): array + { + return array_merge($this->files ?? [], $this->body ?? [], $this->gets ?? [], $this->socket ?? []); + } + + /** + * @param $name + * @param array $defaultValue + * @return mixed + */ + public function array($name, $defaultValue = []): mixed + { + return $this->body[$name] ?? $defaultValue; + } + + /** + * @param $name + * @return File|null + * @throws ReflectionException + * @throws NotFindClassException + */ + public function file($name): File|null + { + if (!isset($this->files[$name])) { + return null; + } + $param = $this->files[$name]; + $param['class'] = File::class; + return Snowflake::createObject($param); + } + + /** + * @param $name + * @param bool $isNeed + * @return mixed + * @throws RequestException + */ + private function required(string $name, bool $isNeed = false): mixed + { + $body = array_merge($this->body ?? [], $this->socket ?? []); + + $int = $body[$name] ?? NULL; + if (is_null($int) && $isNeed === true) { + throw new RequestException("You need to add request parameter $name"); + } + return $int; + } + + /** + * @param string $name + * @param bool $isNeed + * @param array|int|null $min + * @param int|null $max + * @return int|null + * @throws RequestException + */ + public function int(string $name, bool $isNeed = FALSE, array|int|null $min = NULL, int|null $max = NULL): ?int + { + $int = $this->required($name, $isNeed); + if (is_null($int)) return null; + if (is_array($min)) { + list($min, $max) = $min; + } + $length = strlen((string)$int); + if (!is_numeric($int) || intval($int) != $int) { + throw new RequestException("The request parameter $name must integer."); + } + $this->between($length, $min, $max); + return (int)$int; + } + + /** + * @param $name + * @param bool $isNeed + * @param int $round + * @return float|null + * @throws RequestException + */ + public function float(string $name, bool $isNeed = FALSE, $round = 0): ?float + { + $int = $this->required($name, $isNeed); + if ($int === null) { + return null; + } + if ($round > 0) { + return round(floatval($int), $round); + } else { + return floatval($int); + } + } + + /** + * @param string $name + * @param bool $isNeed + * @param int|array|null $length + * + * @return string|null + * @throws RequestException + */ + public function string(string $name, bool $isNeed = FALSE, int|array|null $length = NULL): ?string + { + $string = $this->required($name, $isNeed); + if ($string === null || $length === null) { + return $string; + } + if (is_numeric($length)) { + $length = [$length, $length]; + } + return $this->between($string, $length[0], $length[1] ?? $length[0]); + } + + /** + * @param $string + * @param $min + * @param $max + * @return mixed + * @throws RequestException + */ + private function between($string, $min, $max): mixed + { + $_length = mb_strlen($string); + if ($min !== NULL && $_length < $min) { + throw new RequestException("The minimum value cannot be lower than $min, has length $_length"); + } + if ($max !== NULL && $_length > $max) { + throw new RequestException("Maximum cannot exceed $max, has length " . $_length); + } + return $string; + } + + /** + * @param $name + * @param bool $isNeed + * + * @return string|null + * @throws RequestException + */ + public function email(string $name, bool $isNeed = FALSE): ?string + { + $email = $this->required($name, $isNeed); + if ($email === null) { + return null; + } + if (!preg_match('/^\w+([.-_]\w+)+@\w+(\.\w+)+$/', $email)) { + throw new RequestException("Request parameter $name is in the wrong format", 4001); + } + return $email; + } + + + /** + * @param string $name + * @param bool $isNeed + * + * @return bool + * @throws RequestException + */ + public function bool(string $name, bool $isNeed = FALSE): bool + { + $email = $this->required($name, $isNeed); + if ($email === null) { + return false; + } + return (bool)$email; + } + + /** + * @param string $name + * @param int|null $default + * + * @return int|string|null + * @throws RequestException + */ + public function timestamp(string $name, int|null $default = NULL): null|int|string + { + $value = $this->required($name, false); + if ($value === null) { + return $default; + } + if (!is_numeric($value)) { + throw new RequestException('The request param :attribute not is a timestamp value'); + } + if (strlen((string)$value) != 10) { + throw new RequestException('The request param :attribute not is a timestamp value'); + } + if (!date('YmdHis', $value)) { + throw new RequestException('The request param :attribute format error', 4001); + } + return $value; + } + + /** + * @param string $name + * @param string|null $default + * + * @return string|null + * @throws RequestException + */ + public function datetime(string $name, string $default = NULL): string|null + { + $value = $this->required($name, false); + if ($value === null) { + return $default; + } + $match = '/^\d{4}.*?([1-12]).*([1-31]).*?[0-23].*?[0-59].*?[0-59].*?$/'; + $match = preg_match($match, $value, $result); + if (!$match || $result[0] != $value) { + throw new RequestException('The request param :attribute format error', 4001); + } + return $value; + } + + + /** + * @param string $name + * @param string|null $default + * @return string|null + * @throws RequestException + */ + public function ip(string $name, string $default = NULL): string|null + { + $value = $this->required($name, false); + if ($value == NULL) { + return $default; + } + $match = preg_match('/^\d{1,3}(\.\d{1,3}){3}$/', $value, $result); + if (!$match || $result[0] != $value) { + throw new RequestException('The request param :attribute format error', 4001); + } + return $value; + } + + + /** + * @param $name + * @return mixed + */ + #[Pure] public function __get($name): mixed + { + $load = $this->load(); + + return $load[$name] ?? null; + } } diff --git a/HttpServer/Server.php b/HttpServer/Server.php index 31c730c9..8eed443e 100644 --- a/HttpServer/Server.php +++ b/HttpServer/Server.php @@ -476,6 +476,8 @@ class Server extends HttpService $annotation = Snowflake::app()->getAttributes(); $annotation->instanceDirectoryFiles(CONTROLLER_PATH); + $annotation->instanceDirectoryFiles(RPC_SERVICE_PATH); + $annotation->instanceDirectoryFiles(RPC_CLIENT_PATH); }); } diff --git a/Rpc/Client.php b/Rpc/Client.php index eaecb7cf..e57b27f8 100644 --- a/Rpc/Client.php +++ b/Rpc/Client.php @@ -18,66 +18,78 @@ use Swoole\Coroutine\Client as CClient; class Client extends Component { - private array $config = []; + private array $config = []; - private CClient $client; + private string $service = ''; - /** - * @param $name - */ - public function setConfig($name) - { - $this->config = $name; - } + private CClient $client; /** - * @param string $route + * @param $name + */ + public function setConfig($name) + { + $this->config = $name; + } + + + /** + * @param $value + */ + public function setService($value) + { + $this->service = $value; + } + + + /** + * @param string $cmd * @param array $param * @return mixed * @throws Exception */ - public function request(string $route, array $param): mixed - { - $service = $this->config; - if (empty($service)) { - return null; - } - if (!($this->client instanceof CClient)) { - $this->client = $this->getClient(); - } - if (!$this->client->isConnected()) { - if (!$this->client->connect($service['host'], $service['port'], $service['timeout'])) { - return $this->client->errCode . ':' . $this->client->errMsg; - } - } - $isSend = $this->client->send(serialize(['route' => $route, 'body' => $param])); - if ($isSend === false) { - return $this->client->errCode . ':' . $this->client->errMsg; - } - return unserialize($this->client->recv()); - } + public function dispatch(string $cmd, array $param): mixed + { + $service = $this->config; + if (empty($service)) { + return null; + } + if (!($this->client instanceof CClient)) { + $this->client = $this->getClient(); + } + if (!$this->client->isConnected()) { + if (!$this->client->connect($service['host'], $service['port'], $service['timeout'])) { + return $this->client->errCode . ':' . $this->client->errMsg; + } + } + $isSend = $this->client->send(serialize(['cmd' => $cmd, 'body' => $param])); + if ($isSend === false) { + return $this->client->errCode . ':' . $this->client->errMsg; + } + return unserialize($this->client->recv()); + } - /** - * @return mixed - * @throws Exception - */ - public function getClient(): CClient - { - return objectPool(CClient::class, function () { - $client = new CClient(SWOOLE_SOCK_TCP6); - $client->set([ - 'timeout' => 0.5, - 'connect_timeout' => 1.0, - 'write_timeout' => 10.0, - 'read_timeout' => 0.5, - 'open_tcp_keepalive' => true, - ]); - }); - } + /** + * @return mixed + * @throws Exception + */ + public function getClient(): CClient + { + return objectPool(CClient::class, function () { + $client = new CClient(SWOOLE_SOCK_TCP6); + $client->set([ + 'timeout' => 0.5, + 'connect_timeout' => 1.0, + 'write_timeout' => 10.0, + 'read_timeout' => 0.5, + 'open_tcp_keepalive' => true, + ]); + }); + } } diff --git a/Rpc/IProducer.php b/Rpc/IProducer.php index 3677e0ee..cc8af696 100644 --- a/Rpc/IProducer.php +++ b/Rpc/IProducer.php @@ -8,7 +8,7 @@ interface IProducer { - public function getConfig(): array; + public function initClient(): array; } diff --git a/Rpc/Producer.php b/Rpc/Producer.php index 53dd70b1..a89392a2 100644 --- a/Rpc/Producer.php +++ b/Rpc/Producer.php @@ -21,63 +21,84 @@ use Snowflake\Snowflake; class Producer extends Component { - private array $producers = []; + private array $producers = []; + + + private array $classAlias = []; + + + private array $consumers = []; + + + /** + * @param string $name + * @param array $handler + * @param array $node + */ + public function addProducer(string $name, array $handler, array $node) + { + $this->classAlias[get_class($handler[0])] = $name; + + $this->consumers[$name] = $handler[0]; + + $this->producers[$name] = $node; + } /** * @param $name - * @return Producer|bool - * @throws ReflectionException - * @throws ComponentException - * @throws ConfigException - * @throws NotFindClassException + * @return mixed * @throws Exception */ - public function get($name): Client|bool - { - if (empty($this->producers)) { - $this->producers = Config::get('rpc.producers'); - } - if (empty($this->producers)) { - return $this->addError('Empty by rpc service'); - } - if (!isset($this->producers[$name])) { - return $this->addError('Unknown rpc service'); - } - $rand = $this->producers[$name][array_rand($this->producers[$name])]; - - if (Snowflake::app()->has($this->getName($name, $rand))) { - return Snowflake::app()->get($this->getName($name, $rand)); - } - return Snowflake::app()->set($this->getName($name, $rand), [ - 'class' => Client::class, - 'config' => $rand - ]); - } + public function get($name): mixed + { + if (!isset($this->consumers[$name])) { + throw new Exception('Unknown rpc client.'); + } + return $this->consumers[$name]; + } - /** - * @param $name - * @return Client|bool - * @throws ReflectionException - * @throws ComponentException - * @throws ConfigException - * @throws NotFindClassException - */ - public function __get($name): Client|bool - { - return $this->get($name); // TODO: Change the autogenerated stub - } + /** + * @param string $name + * @return mixed + * @throws Exception + */ + public function getClient(string $name): Client + { + if (!is_array($producer = $this->producers[$name] ?? null)) { + throw new Exception('Unknown rpc client config.'); + } + $producerName = $this->getName($name, $producer); + + $snowflake = Snowflake::app(); + if (!$snowflake->has($producerName)) { + return $snowflake->set($producerName, ['class' => Client::class, 'config' => $producer]); + } else { + return $snowflake->get($producerName); + } + } - /** - * @param $name - * @param $rand - * @return string - */ - private function getName($name, $rand): string - { - return 'rpc.client.' . $name . '.' . $rand['host']; - } + /** + * @param $name + * @return Client|bool + * @throws Exception + */ + public function __get($name): Client|bool + { + return $this->get($name); // TODO: Change the autogenerated stub + } + + + /** + * @param $name + * @param $rand + * @return string + */ + private function getName($name, $rand): string + { + return 'rpc.client.' . $name . '.' . $rand['host']; + } } diff --git a/Rpc/Service.php b/Rpc/Service.php index e9843c82..08a06dca 100644 --- a/Rpc/Service.php +++ b/Rpc/Service.php @@ -68,11 +68,9 @@ class Service extends Component ]); $router->addPortListen($service['port'], function () use ($service, $mode) { try { + /** @var Request $request */ $request = Context::getContext('request'); - $request->headers->replace('request_method', Request::HTTP_CMD); - - $router = Snowflake::app()->getRouter(); - if (($node = $router->find_path($request)) === null) { + if (($node = router()->find_path($this->replace($request, $service))) === null) { throw new Exception('Cmd not find.'); } return $node->dispatch(); @@ -86,4 +84,31 @@ class Service extends Component } + /** + * @param Request $request + * @param array $service + * @return Request + * @throws Exception + */ + public function replace(Request $request, array $service): Request + { + $body = $request->params->getBodyAndClear(); + if (is_null($serialize = unserialize($body))) { + throw new Exception('Protocol format error.'); + } + if (!isset($serialize['cmd'])) { + throw new Exception('Protocol format error.'); + } + $request->params->setPosts($serialize); + + $serialize['cmd'] = ltrim($serialize['cmd'], '/'); + + $header = $request->headers; + $header->replace('request_uri', 'rpc/' . $service['port'] . '/' . $serialize['cmd']); + $header->replace('request_method', Request::HTTP_CMD); + + return $request; + } + + } diff --git a/System/Abstracts/BaseApplication.php b/System/Abstracts/BaseApplication.php index ae2ee314..351b7071 100644 --- a/System/Abstracts/BaseApplication.php +++ b/System/Abstracts/BaseApplication.php @@ -50,406 +50,418 @@ use Swoole\Table; abstract class BaseApplication extends Service { - use TraitApplication; + use TraitApplication; - /** - * @var string - */ - public string $storage = APP_PATH . '/storage'; + /** + * @var string + */ + public string $storage = APP_PATH . '/storage'; - public string $envPath = APP_PATH . '/.env'; + public string $envPath = APP_PATH . '/.env'; - /** - * Init constructor. - * - * @param array $config - * - * @throws - */ - public function __construct(array $config = []) - { - Snowflake::init($this); + /** + * Init constructor. + * + * @param array $config + * + * @throws + */ + public function __construct(array $config = []) + { + Snowflake::init($this); - $this->moreComponents(); - $this->parseInt($config); - $this->parseEvents($config); - $this->initErrorHandler(); - $this->enableEnvConfig(); + $this->moreComponents(); + $this->parseInt($config); + $this->parseEvents($config); + $this->initErrorHandler(); + $this->enableEnvConfig(); - parent::__construct($config); - } + parent::__construct($config); + } - /** - * @return array - */ - public function enableEnvConfig(): array - { - if (!file_exists($this->envPath)) { - return []; - } - $lines = $this->readLinesFromFile($this->envPath); - foreach ($lines as $line) { - if (!$this->isComment($line) && $this->looksLikeSetter($line)) { - [$key, $value] = explode('=', $line); - putenv(trim($key) . '=' . trim($value)); - } - } - return $lines; - } + /** + * @return array + */ + public function enableEnvConfig(): array + { + if (!file_exists($this->envPath)) { + return []; + } + $lines = $this->readLinesFromFile($this->envPath); + foreach ($lines as $line) { + if (!$this->isComment($line) && $this->looksLikeSetter($line)) { + [$key, $value] = explode('=', $line); + putenv(trim($key) . '=' . trim($value)); + } + } + return $lines; + } - /** - * Read lines from the file, auto detecting line endings. - * - * @param string $filePath - * - * @return array - */ - protected function readLinesFromFile(string $filePath): array - { - // Read file into an array of lines with auto-detected line endings - $autodetect = ini_get('auto_detect_line_endings'); - ini_set('auto_detect_line_endings', '1'); - $lines = file($filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - ini_set('auto_detect_line_endings', $autodetect); + /** + * Read lines from the file, auto detecting line endings. + * + * @param string $filePath + * + * @return array + */ + protected function readLinesFromFile(string $filePath): array + { + // Read file into an array of lines with auto-detected line endings + $autodetect = ini_get('auto_detect_line_endings'); + ini_set('auto_detect_line_endings', '1'); + $lines = file($filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + ini_set('auto_detect_line_endings', $autodetect); - return $lines; - } + return $lines; + } - /** - * Determine if the line in the file is a comment, e.g. begins with a #. - * - * @param string $line - * - * @return bool - */ - protected function isComment(string $line): bool - { - $line = ltrim($line); + /** + * Determine if the line in the file is a comment, e.g. begins with a #. + * + * @param string $line + * + * @return bool + */ + protected function isComment(string $line): bool + { + $line = ltrim($line); - return isset($line[0]) && $line[0] === '#'; - } + return isset($line[0]) && $line[0] === '#'; + } - /** - * Determine if the given line looks like it's setting a variable. - * - * @param string $line - * - * @return bool - */ - #[Pure] protected function looksLikeSetter(string $line): bool - { - return str_contains($line, '='); - } + /** + * Determine if the given line looks like it's setting a variable. + * + * @param string $line + * + * @return bool + */ + #[Pure] protected function looksLikeSetter(string $line): bool + { + return str_contains($line, '='); + } - /** - * @param $config - * - * @throws - */ - public function parseInt($config) - { - foreach ($config as $key => $value) { - Config::set($key, $value); - } - if ($storage = Config::get('storage', false, 'storage')) { - if (!str_contains($storage, APP_PATH)) { - $storage = APP_PATH . $storage . '/'; - } - if (!is_dir($storage)) { - mkdir($storage); - } - if (!is_dir($storage) || !is_writeable($storage)) { - throw new InitException("Directory {$storage} does not have write permission"); - } - } - } + /** + * @param $config + * + * @throws + */ + public function parseInt($config) + { + foreach ($config as $key => $value) { + Config::set($key, $value); + } + if ($storage = Config::get('storage', false, 'storage')) { + if (!str_contains($storage, APP_PATH)) { + $storage = APP_PATH . $storage . '/'; + } + if (!is_dir($storage)) { + mkdir($storage); + } + if (!is_dir($storage) || !is_writeable($storage)) { + throw new InitException("Directory {$storage} does not have write permission"); + } + } + } - /** - * @param $config - * - * @throws - */ - public function parseEvents($config) - { - if (!isset($config['events']) || !is_array($config['events'])) { - return; - } - $event = Snowflake::app()->getEvent(); - foreach ($config['events'] as $key => $value) { - if (is_string($value)) { - if (!class_exists($value)) { - throw new InitException("Class {$value} does not exists."); - } - $value = Snowflake::createObject($value); - } else if (is_array($value) && !is_callable($value, true)) { - throw new InitException("Class does not hav callback."); - } - $event->on($key, $value); - } - } + /** + * @param $config + * + * @throws + */ + public function parseEvents($config) + { + if (!isset($config['events']) || !is_array($config['events'])) { + return; + } + $event = Snowflake::app()->getEvent(); + foreach ($config['events'] as $key => $value) { + if (is_string($value)) { + if (!class_exists($value)) { + throw new InitException("Class {$value} does not exists."); + } + $value = Snowflake::createObject($value); + } else if (is_array($value) && !is_callable($value, true)) { + throw new InitException("Class does not hav callback."); + } + $event->on($key, $value); + } + } - /** - * @param $name - * @return mixed - * @throws Exception - */ - public function clone($name): mixed - { - return clone $this->get($name); - } + /** + * @param $name + * @return mixed + * @throws Exception + */ + public function clone($name): mixed + { + return clone $this->get($name); + } - /** - * - * @throws Exception - */ - public function initErrorHandler() - { - $this->get('error')->register(); - } + /** + * + * @throws Exception + */ + public function initErrorHandler() + { + $this->get('error')->register(); + } - /** - * @return mixed - */ - public function getLocalIps(): mixed - { - return swoole_get_local_ip(); - } + /** + * @return mixed + */ + public function getLocalIps(): mixed + { + return swoole_get_local_ip(); + } - /** - * @return mixed - */ - public function getFirstLocal(): mixed - { - return current($this->getLocalIps()); - } + /** + * @return mixed + */ + public function getFirstLocal(): mixed + { + return current($this->getLocalIps()); + } - /** - * @return Logger - * @throws Exception - */ - public function getLogger(): Logger - { - return $this->get('logger'); - } + /** + * @return Logger + * @throws Exception + */ + public function getLogger(): Logger + { + return $this->get('logger'); + } - /** - * @return Producer - * @throws Exception - */ - public function getKafka(): Producer - { - return $this->get('kafka'); - } + /** + * @return Producer + * @throws Exception + */ + public function getKafka(): Producer + { + return $this->get('kafka'); + } - /** - * @return \Redis|Redis - * @throws Exception - */ - public function getRedis(): Redis|\Redis - { - return $this->get('redis'); - } + /** + * @return \Redis|Redis + * @throws Exception + */ + public function getRedis(): Redis|\Redis + { + return $this->get('redis'); + } - /** - * @param $ip - * @return bool - */ - public function isLocal($ip): bool - { - return $this->getFirstLocal() == $ip; - } + /** + * @param $ip + * @return bool + */ + public function isLocal($ip): bool + { + return $this->getFirstLocal() == $ip; + } - /** - * @return ErrorHandler - * @throws Exception - */ - public function getError(): ErrorHandler - { - return $this->get('error'); - } + /** + * @return ErrorHandler + * @throws Exception + */ + public function getError(): ErrorHandler + { + return $this->get('error'); + } - /** - * @return Connection - * @throws ComponentException - * @throws NotFindClassException - * @throws ReflectionException - */ - public function getMysqlFromPool(): Connection - { - return $this->get('pool')->getDb(); - } + /** + * @return Connection + * @throws ComponentException + * @throws NotFindClassException + * @throws ReflectionException + */ + public function getMysqlFromPool(): Connection + { + return $this->get('pool')->getDb(); + } - /** - * @return SRedis - * @throws NotFindClassException - * @throws ReflectionException - * @throws ComponentException - */ - public function getRedisFromPool(): SRedis - { - return $this->get('pool')->getRedis(); - } + /** + * @return SRedis + * @throws NotFindClassException + * @throws ReflectionException + * @throws ComponentException + */ + public function getRedisFromPool(): SRedis + { + return $this->get('pool')->getRedis(); + } - /** - * @return Response - * @throws Exception - */ - public function getResponse(): Response - { - return $this->get('response'); - } + /** + * @return Response + * @throws Exception + */ + public function getResponse(): Response + { + return $this->get('response'); + } - /** - * @return Request - * @throws Exception - */ - public function getRequest(): Request - { - return $this->get('request'); - } + /** + * @return Request + * @throws Exception + */ + public function getRequest(): Request + { + return $this->get('request'); + } - /** - * @param $name - * @return Table - * @throws Exception - */ - public function getTable($name): Table - { - return $this->get($name); - } + /** + * @param $name + * @return Table + * @throws Exception + */ + public function getTable($name): Table + { + return $this->get($name); + } - /** - * @return Config - * @throws Exception - */ - public function getConfig(): Config - { - return $this->get('config'); - } + /** + * @return Config + * @throws Exception + */ + public function getConfig(): Config + { + return $this->get('config'); + } - /** - * @return Router - * @throws Exception - */ - public function getRouter(): Router - { - return $this->get('router'); - } + /** + * @return Router + * @throws Exception + */ + public function getRouter(): Router + { + return $this->get('router'); + } - /** - * @return Event - * @throws Exception - */ - public function getEvent(): Event - { - return $this->get('event'); - } + /** + * @return Event + * @throws Exception + */ + public function getEvent(): Event + { + return $this->get('event'); + } - /** - * @return Jwt - * @throws Exception - */ - public function getJwt(): Jwt - { - return $this->get('jwt'); - } + /** + * @return Jwt + * @throws Exception + */ + public function getJwt(): Jwt + { + return $this->get('jwt'); + } - /** - * @return Server - * @throws Exception - */ - public function getServer(): Server - { - return $this->get('server'); - } + /** + * @return Server + * @throws Exception + */ + public function getServer(): Server + { + return $this->get('server'); + } - /** - * @return Http|Packet|Receive|Websocket|null - * @throws Exception - */ - public function getSwoole(): Packet|Websocket|Receive|Http|null - { - return $this->getServer()->getServer(); - } + /** + * @return Http|Packet|Receive|Websocket|null + * @throws Exception + */ + public function getSwoole(): Packet|Websocket|Receive|Http|null + { + return $this->getServer()->getServer(); + } - /** - * @return SAnnotation - * @throws Exception - */ - public function getAttributes(): SAnnotation - { - return $this->get('attributes'); - } + /** + * @return SAnnotation + * @throws Exception + */ + public function getAttributes(): SAnnotation + { + return $this->get('attributes'); + } - /** - * @return Async - * @throws Exception - */ - public function getAsync(): Async - { - return $this->get('async'); - } + /** + * @return Async + * @throws Exception + */ + public function getAsync(): Async + { + return $this->get('async'); + } - /** - * @return ObjectPool - * @throws Exception - */ - public function getObject(): ObjectPool - { - return $this->get('object'); - } + /** + * @return ObjectPool + * @throws Exception + */ + public function getObject(): ObjectPool + { + return $this->get('object'); + } - /** - * @throws Exception - */ - protected function moreComponents(): void - { - $this->setComponents([ - 'error' => ['class' => ErrorHandler::class], - 'event' => ['class' => Event::class], - 'connections' => ['class' => Connection::class], - 'redis_connections' => ['class' => SRedis::class], - 'pool' => ['class' => SPool::class], - 'response' => ['class' => Response::class], - 'request' => ['class' => Request::class], - 'config' => ['class' => Config::class], - 'logger' => ['class' => Logger::class], - 'attributes' => ['class' => SAnnotation::class], - 'router' => ['class' => Router::class], - 'redis' => ['class' => Redis::class], - 'jwt' => ['class' => Jwt::class], - 'async' => ['class' => Async::class], - 'filter' => ['class' => HttpFilter::class], - 'crontab' => ['class' => Crontab::class], - 'object' => ['class' => ObjectPool::class], - 'goto' => ['class' => BaseGoto::class], - 'rpc' => ['class' => \Rpc\Producer::class], - 'rpc-service' => ['class' => \Rpc\Service::class], - 'http2' => ['class' => Http2::class], - ]); - } + /** + * @return \Rpc\Producer + * @throws ComponentException + * @throws NotFindClassException + * @throws ReflectionException + */ + public function getRpc(): \Rpc\Producer + { + return $this->get('rpc'); + } + + + /** + * @throws Exception + */ + protected function moreComponents(): void + { + $this->setComponents([ + 'error' => ['class' => ErrorHandler::class], + 'event' => ['class' => Event::class], + 'connections' => ['class' => Connection::class], + 'redis_connections' => ['class' => SRedis::class], + 'pool' => ['class' => SPool::class], + 'response' => ['class' => Response::class], + 'request' => ['class' => Request::class], + 'config' => ['class' => Config::class], + 'logger' => ['class' => Logger::class], + 'attributes' => ['class' => SAnnotation::class], + 'router' => ['class' => Router::class], + 'redis' => ['class' => Redis::class], + 'jwt' => ['class' => Jwt::class], + 'async' => ['class' => Async::class], + 'filter' => ['class' => HttpFilter::class], + 'crontab' => ['class' => Crontab::class], + 'object' => ['class' => ObjectPool::class], + 'goto' => ['class' => BaseGoto::class], + 'rpc' => ['class' => \Rpc\Producer::class], + 'rpc-service' => ['class' => \Rpc\Service::class], + 'http2' => ['class' => Http2::class], + ]); + } } diff --git a/System/Snowflake.php b/System/Snowflake.php index c1f147d9..5fb60ed7 100644 --- a/System/Snowflake.php +++ b/System/Snowflake.php @@ -24,6 +24,8 @@ defined('DB_ERROR_BUSY') or define('DB_ERROR', 'The database is busy. Please try defined('SELECT_IS_NULL') or define('SELECT_IS_NULL', 'Query data does not exist, please check the relevant conditions.'); defined('PARAMS_IS_NULL') or define('PARAMS_IS_NULL', 'Required items cannot be empty, please add.'); defined('CONTROLLER_PATH') or define('CONTROLLER_PATH', APP_PATH . 'app/Http/Controllers/'); +defined('RPC_SERVICE_PATH') or define('RPC_SERVICE_PATH', APP_PATH . 'app/Http/Rpc/'); +defined('RPC_CLIENT_PATH') or define('RPC_CLIENT_PATH', APP_PATH . 'app/Client/Rpc/'); defined('MODEL_PATH') or define('MODEL_PATH', APP_PATH . 'app/Models/'); defined('SOCKET_PATH') or define('SOCKET_PATH', APP_PATH . 'app/Websocket/');