137 Commits

Author SHA1 Message Date
as2252258 6418b3288b eee 2024-04-24 14:31:06 +08:00
as2252258 a761bb3428 eee 2023-11-30 17:03:17 +08:00
as2252258 2ecb13c453 eee 2023-11-30 17:02:20 +08:00
as2252258 0a705b27bc eee 2023-10-24 17:22:31 +08:00
as2252258 10a64ee646 qqq 2023-07-31 23:09:00 +08:00
as2252258 493a58281f qqq 2023-05-26 09:20:30 +08:00
as2252258 18a9b29bbd qqq 2023-05-25 16:59:19 +08:00
as2252258 d72ff2f82c qqq 2023-05-20 23:05:38 +08:00
as2252258 de2698ee12 qqq 2023-05-16 15:21:50 +08:00
as2252258 b1bc0ff23c 变更 2022-12-12 17:31:12 +08:00
as2252258 7f28443d99 变更 2022-10-11 18:41:58 +08:00
as2252258 7ea28f47e1 变更 2022-09-23 19:02:26 +08:00
as2252258 c01dc5f41a 变更 2022-09-23 18:55:46 +08:00
as2252258 c190c749f4 modify plugin name 2022-06-17 13:44:40 +08:00
as2252258 45315dcbb2 modify plugin name 2022-06-17 13:44:24 +08:00
as2252258 8d20f56660 modify plugin name 2022-06-16 18:49:33 +08:00
as2252258 348f0129e8 modify plugin name 2022-06-16 18:07:27 +08:00
as2252258 6371d5271e modify plugin name 2022-06-16 17:38:23 +08:00
as2252258 8f9de7a508 modify plugin name 2022-06-08 17:19:32 +08:00
as2252258 2a6b2a1979 modify plugin name 2022-06-08 15:08:07 +08:00
as2252258 b79513757b modify plugin name 2022-06-08 14:32:20 +08:00
as2252258 b495927099 modify plugin name 2022-06-08 14:27:49 +08:00
as2252258 188742360e 变更 2022-05-31 20:41:31 +08:00
as2252258 6715743843 变更 2022-05-31 11:54:06 +08:00
as2252258 f94a8a3792 变更 2022-05-31 11:43:06 +08:00
as2252258 0ad17ae4c5 变更 2022-05-31 11:11:12 +08:00
as2252258 95772e794b 变更 2022-05-31 11:03:52 +08:00
as2252258 9473384c18 变更 2022-05-31 11:02:15 +08:00
as2252258 152049fdae 变更 2022-05-31 10:59:22 +08:00
as2252258 4c6739a83b 变更 2022-05-31 10:53:48 +08:00
as2252258 5f81fd5ff9 变更 2022-05-31 10:53:33 +08:00
as2252258 cf8208bd12 变更 2022-05-31 10:02:47 +08:00
as2252258 0d2989171e 变更 2022-05-04 03:53:37 +08:00
as2252258 4b50c3fc18 变更 2022-05-04 03:32:10 +08:00
as2252258 ad346d01d1 变更 2022-05-04 03:29:14 +08:00
as2252258 c108de48af 变更 2022-05-04 03:25:37 +08:00
as2252258 3192b5940e 变更 2022-05-04 03:22:31 +08:00
as2252258 1d3b71b023 变更 2022-05-04 03:19:28 +08:00
as2252258 abaa2547f7 变更 2022-05-04 03:16:52 +08:00
as2252258 c982e44631 变更 2022-05-04 03:12:41 +08:00
as2252258 87d47e0971 变更 2022-05-04 03:11:10 +08:00
as2252258 072db59b9f 变更 2022-05-04 03:08:46 +08:00
as2252258 2620e88447 变更 2022-05-04 02:55:14 +08:00
as2252258 f3cd9b4b7c modify plugin name 2022-03-03 18:30:59 +08:00
as2252258 e270f9c588 modify plugin name 2022-03-03 16:39:46 +08:00
as2252258 f2cf841573 modify plugin name 2022-03-02 16:47:02 +08:00
as2252258 7a3299cb10 modify plugin name 2022-03-02 16:45:12 +08:00
as2252258 2ad3809736 modify plugin name 2022-03-02 16:27:15 +08:00
as2252258 219d246d4a modify plugin name 2022-03-02 15:15:36 +08:00
as2252258 a3dfcf02e6 modify plugin name 2022-02-28 14:59:34 +08:00
as2252258 688b2381da modify plugin name 2022-02-23 16:32:08 +08:00
as2252258 8824f711bb Revert "改名"
This reverts commit fdf58326
2022-01-20 19:04:16 +08:00
as2252258 f2d97832b5 Revert "改名"
This reverts commit fdf58326
2022-01-19 17:27:47 +08:00
as2252258 855e57a651 Revert "改名"
This reverts commit fdf58326
2022-01-19 16:39:29 +08:00
as2252258 0b3310b82e Revert "改名"
This reverts commit fdf58326
2022-01-14 11:29:16 +08:00
as2252258 e8cf7f29f0 Revert "改名"
This reverts commit fdf58326
2022-01-13 19:02:07 +08:00
as2252258 62e3b001f0 Revert "改名"
This reverts commit fdf58326
2022-01-13 19:00:01 +08:00
as2252258 f655cebdf3 Revert "改名"
This reverts commit fdf58326
2022-01-13 18:58:40 +08:00
as2252258 ee492d97ad Revert "改名"
This reverts commit fdf58326
2022-01-13 18:57:53 +08:00
as2252258 a16d841d98 Revert "改名"
This reverts commit fdf58326
2022-01-13 18:56:41 +08:00
as2252258 f015662fd6 Revert "改名"
This reverts commit fdf58326
2022-01-13 18:52:42 +08:00
as2252258 021dcae59b Revert "改名"
This reverts commit fdf58326
2022-01-13 18:50:19 +08:00
as2252258 c6dc34c821 Revert "改名"
This reverts commit fdf58326
2022-01-13 18:47:34 +08:00
as2252258 88c3958aba Revert "改名"
This reverts commit fdf58326
2022-01-13 18:42:42 +08:00
as2252258 24ebfac360 Revert "改名"
This reverts commit fdf58326
2022-01-13 18:41:16 +08:00
as2252258 b3c200b443 Revert "改名"
This reverts commit fdf58326
2022-01-13 18:34:23 +08:00
as2252258 3e2b50bf60 Revert "改名"
This reverts commit fdf58326
2022-01-13 18:33:56 +08:00
as2252258 89c142930e Revert "改名"
This reverts commit fdf58326
2022-01-13 18:29:51 +08:00
as2252258 1515d9695c Revert "改名"
This reverts commit fdf58326
2022-01-13 18:28:22 +08:00
as2252258 f1f7b1081d Revert "改名"
This reverts commit fdf58326
2022-01-13 18:27:36 +08:00
as2252258 07533e29f9 Revert "改名"
This reverts commit fdf58326
2022-01-13 18:25:29 +08:00
as2252258 4d60a24fac Revert "改名"
This reverts commit fdf58326
2022-01-12 14:10:33 +08:00
as2252258 4dc6bc661a Revert "改名"
This reverts commit fdf58326
2022-01-11 17:56:16 +08:00
as2252258 0d7fd5e356 Revert "改名"
This reverts commit fdf58326
2022-01-11 14:53:41 +08:00
as2252258 da16b0685d Revert "改名"
This reverts commit fdf58326
2022-01-11 14:51:50 +08:00
as2252258 febbdea8c8 Revert "改名"
This reverts commit fdf58326
2022-01-11 14:44:02 +08:00
as2252258 a45c3d875c Revert "改名"
This reverts commit fdf58326
2022-01-11 14:42:04 +08:00
as2252258 64d01c0a80 Revert "改名"
This reverts commit fdf58326
2022-01-11 14:41:06 +08:00
as2252258 bf5fe594e4 Revert "改名"
This reverts commit fdf58326
2022-01-11 14:30:58 +08:00
as2252258 5cfe3c6d6d Revert "改名"
This reverts commit fdf58326
2022-01-11 14:30:05 +08:00
as2252258 773e3c0f57 Revert "改名"
This reverts commit fdf58326
2022-01-11 14:26:57 +08:00
as2252258 b1c91343ef Revert "改名"
This reverts commit fdf58326
2022-01-11 14:25:24 +08:00
as2252258 3f821ca9d0 Revert "改名"
This reverts commit fdf58326
2022-01-11 14:23:48 +08:00
as2252258 d296b3107e Revert "改名"
This reverts commit fdf58326
2022-01-11 14:15:51 +08:00
as2252258 f606c58204 Revert "改名"
This reverts commit fdf58326
2022-01-11 14:13:51 +08:00
as2252258 6c1d986814 Revert "改名"
This reverts commit fdf58326
2022-01-10 11:39:56 +08:00
as2252258 da056b09c7 1 2022-01-09 16:07:57 +08:00
as2252258 4eefe54be0 e 2022-01-09 14:00:32 +08:00
as2252258 b0ed7650c5 Revert "改名"
This reverts commit fdf58326
2022-01-08 18:49:07 +08:00
as2252258 3d89cbd4c6 Revert "改名"
This reverts commit fdf58326
2022-01-05 15:22:29 +08:00
as2252258 0f2d19f3c7 Revert "改名"
This reverts commit fdf58326
2022-01-05 15:21:48 +08:00
as2252258 9001dd041e Revert "改名"
This reverts commit fdf58326
2022-01-04 15:56:37 +08:00
as2252258 1bb26b4680 改名 2021-12-24 14:53:59 +08:00
as2252258 a6d825ef9b 改名 2021-12-24 14:16:07 +08:00
as2252258 6cc0334b9b 改名 2021-12-24 11:55:09 +08:00
as2252258 d6cb6e40a8 改名 2021-12-24 11:53:24 +08:00
as2252258 fb10622960 改名 2021-12-24 11:34:29 +08:00
as2252258 2a9c36babb 改名 2021-12-24 11:31:48 +08:00
as2252258 bc4e506ea8 改名 2021-12-23 18:22:26 +08:00
as2252258 59089462e7 改名 2021-12-08 11:32:32 +08:00
as2252258 845b8b36d1 改名 2021-12-06 17:10:45 +08:00
as2252258 07436f7035 改名 2021-12-06 17:08:03 +08:00
as2252258 4d93fcaff2 改名 2021-12-03 15:42:05 +08:00
as2252258 2e01b60e1e 改名 2021-12-03 15:09:05 +08:00
as2252258 8d2ce1d45c 改名 2021-12-03 15:07:21 +08:00
as2252258 8a3ed5aea5 改名 2021-12-03 14:56:13 +08:00
as2252258 d50b6e6ec7 改名 2021-12-03 14:46:38 +08:00
as2252258 8f3bea7738 改名 2021-12-02 16:22:44 +08:00
as2252258 eec4ad8a8b 改名 2021-12-02 16:18:10 +08:00
as2252258 18d2ce66e6 改名 2021-12-02 16:13:57 +08:00
as2252258 a66de3f016 改名 2021-12-02 15:57:36 +08:00
as2252258 6fcd26f80f 改名 2021-12-02 15:53:25 +08:00
as2252258 3538393620 改名 2021-12-02 15:52:49 +08:00
as2252258 9a6575b438 改名 2021-12-02 15:48:32 +08:00
as2252258 7293e24f9d 改名 2021-12-02 15:41:39 +08:00
as2252258 646f6b1258 改名 2021-12-02 15:41:16 +08:00
as2252258 1189ab7b0c 改名 2021-12-02 15:40:45 +08:00
as2252258 7c36c32c65 改名 2021-12-02 15:39:47 +08:00
as2252258 f2d60f6982 改名 2021-12-02 15:38:49 +08:00
as2252258 6d242d42b0 改名 2021-12-02 15:36:54 +08:00
as2252258 5991ea9d3f 改名 2021-12-02 15:33:57 +08:00
as2252258 9af46754e7 改名 2021-12-02 15:32:54 +08:00
as2252258 23206bc683 改名 2021-12-02 15:26:43 +08:00
as2252258 439e3c566e 改名 2021-12-02 15:25:41 +08:00
as2252258 14d395be5e 改名 2021-12-02 14:40:10 +08:00
as2252258 a8a202ad6b 改名 2021-12-02 14:38:07 +08:00
as2252258 a8d3d1472f 改名 2021-12-02 14:25:50 +08:00
as2252258 f374fad591 改名 2021-12-02 14:24:26 +08:00
as2252258 4e2c4633c1 改名 2021-12-02 14:22:23 +08:00
as2252258 31a086e338 改名 2021-12-02 14:21:32 +08:00
as2252258 87d0d28847 改名 2021-12-02 14:20:19 +08:00
as2252258 c41bdd9c8e 改名 2021-12-02 14:17:52 +08:00
as2252258 e6ae1acd14 改名 2021-12-02 14:14:32 +08:00
as2252258 d2ec972c69 改名 2021-12-02 14:13:44 +08:00
as2252258 ce3647b5b7 改名 2021-12-02 14:12:27 +08:00
as2252258 19c9b692d4 改名 2021-12-02 14:06:57 +08:00
as2252258 7fef63fa39 改名 2021-12-01 19:04:59 +08:00
32 changed files with 1431 additions and 1319 deletions
+37 -37
View File
@@ -1,37 +1,37 @@
# Created by .ignore support plugin (hsz.mobi)
### Yii template
assets/*
!assets/.gitignore
protected/runtime/*
!protected/runtime/.gitignore
protected/data/*.db
themes/classic/views/
### Example user template template
### Example user template
# IntelliJ project files
.idea
*.iml
out
gen
db/
async-queue/
composer.lock
*.log
commands/result
config/setting.php
tests/
vendor/
runtime/
*.xml
*.lock
oot
d
composer.lock
# Created by .ignore support plugin (hsz.mobi)
### Yii template
assets/*
!assets/.gitignore
protected/runtime/*
!protected/runtime/.gitignore
protected/data/*.db
themes/classic/views/
### Example user template template
### Example user template
# IntelliJ project files
.idea
*.iml
out
gen
db/
async-queue/
composer.lock
*.log
commands/result
config/setting.php
tests/
vendor/
runtime/
*.xml
*.lock
oot
d
composer.lock
+18 -18
View File
@@ -1,18 +1,18 @@
<?php
namespace PHPSTORM_META {
// Reflect
use Kiri\Di\Container;
use Psr\Container\ContainerInterface;
override(ContainerInterface::get(0), map('@'));
override(Container::get(0), map('@'));
override(Container::make(0), map('@'));
override(Container::create(0), map('@'));
// override(\Hyperf\Utils\Context::get(0), map('@'));
// override(\make(0), map('@'));
override(\di(0), map('@'));
override(\duplicate(0), map('@'));
}
<?php
namespace PHPSTORM_META {
// Reflect
use Kiri\Di\Container;
use Kiri\Di\ContainerInterface;
override(ContainerInterface::get(0), map('@'));
override(Container::get(0), map('@'));
override(Container::make(0), map('@'));
override(Container::create(0), map('@'));
// override(\Hyperf\Utils\Context::get(0), map('@'));
// override(\make(0), map('@'));
override(\di(0), map('@'));
override(\duplicate(0), map('@'));
}
+68
View File
@@ -0,0 +1,68 @@
<?php
namespace Kiri\Rpc;
use Kiri\Core\Json;
use Kiri\Core\Number;
use Kiri\Di\Inject\Container;
abstract class AbstractRpcClient
{
public string $service = '';
public string $version = '';
/**
* @var JsonRpcTransporterInterface
*/
#[Container(JsonRpcTransporterInterface::class)]
private JsonRpcTransporterInterface $transporter;
/**
* @param JsonRpcTransporterInterface $transporter
*/
public function setTransporter(JsonRpcTransporterInterface $transporter): void
{
$this->transporter = $transporter;
}
/**
* @return string
*/
public function getService(): string
{
if (empty($this->service)) {
return get_called_class();
}
return $this->service;
}
/**
* @param string $method
* @param ...$args
* @return string|bool
*/
protected function send(string $method, ...$args): string|bool
{
$result = $this->transporter->push(Json::encode([
'jsonrpc' => $this->version,
'service' => $this->getService(),
'method' => $method,
'params' => $args,
'id' => Number::create(time())
]), $this->getService());
if (is_string($result)) {
return json_decode($result, true);
} else {
return $result;
}
}
}
+114
View File
@@ -0,0 +1,114 @@
<?php
namespace Kiri\Rpc;
use Exception;
use Kiri;
use Kiri\Abstracts\Component;
use Kiri\Pool\Pool;
use Kiri\Server\Events\OnBeforeShutdown;
use ReflectionException;
use Swoole\Coroutine\Client as CoroutineClient;
use Swoole\Client as AsyncClient;
/**
*
*/
class ClientPool extends Component
{
public int $max;
public int $min;
private array $names = [];
/**
* @return void
*/
public function init(): void
{
on(OnBeforeShutdown::class, [$this, 'onBeforeShutdown']);
}
/**
* @return void
* @throws Exception
*/
public function onBeforeShutdown(): void
{
$pool = Kiri::getDi()->get(Pool::class);
foreach ($this->names as $name) {
$pool->clean($name);
}
}
/**
* @param $config
* @return resource
* @throws Exception
*/
public function get($config): mixed
{
$coroutineName = $config['Address'] . '::' . $config['Port'];
if (!in_array($coroutineName, $this->names)) {
$this->names[] = $coroutineName;
}
return $this->getPool($config['Address'], $config['Port'])->get($coroutineName);
}
/**
* @param CoroutineClient|AsyncClient $client
* @param $host
* @param $port
* @throws Exception
*/
public function push(CoroutineClient|AsyncClient $client, $host, $port)
{
$this->getPool($host, $port)->push($host . '::' . $port, $client);
}
/**
* @param string $host
* @param int $port
* @return Pool
* @throws ReflectionException
*/
public function getPool(string $host, int $port): Pool
{
$pool = Kiri::getDi()->get(Pool::class);
$pool->created($host . '::' . $port, 10, [$this, 'connect']);
return $pool;
}
/**
* @param $host
* @param $port
* @return CoroutineClient|AsyncClient
* @throws Exception
*/
public function connect($host, $port): CoroutineClient|AsyncClient
{
if (Kiri\Di\Context::inCoroutine()) {
$client = new CoroutineClient(SWOOLE_SOCK_TCP);
} else {
$client = new AsyncClient(SWOOLE_SOCK_TCP);
}
if (!$client->connect($host, $port, 3)) {
throw new Exception('Connect ' . $host . '::' . $port . ' fail');
}
return $client;
}
}
+90
View File
@@ -0,0 +1,90 @@
<?php
use Etcd\Client;
use GuzzleHttp\Exception\BadResponseException;
use Kiri\Abstracts\Component;
use Kiri\Core\Str;
/**
*
*/
class Etcd extends Component
{
private Client $client;
private bool $isEnd = false;
private array $config = [];
private array|BadResponseException $grant;
/**
* @return void
* @throws Exception
*/
public function init(): void
{
$this->client = new Client('47.92.194.207:' . 2379, 'v3');
$this->grant = $this->client->grant(60);
if ($this->grant instanceof BadResponseException) {
throw new Exception($this->grant->getMessage());
}
$key = 'center.service.' . gethostbyname(gethostname());
\pcntl_signal(SIGINT, function () use ($key) {
$this->isEnd = true;
$this->client->del($key);
});
$this->client->put($key, json_encode([
'address' => gethostbyname(gethostname()) . ':10240',
'nodeId' => Str::rand(32)
]), ['lease' => (int)$this->grant["ID"]]);
}
/**
* @param string $key
* @return mixed
*/
public function get(string $key): mixed
{
return $this->config[$key] ?? null;
}
/**
* @param string $key
* @param mixed $value
* @return void
* @throws Exception
*/
public function put(string $key, mixed $value): void
{
$result = $this->client->put($key, $value);
if ($result instanceof BadResponseException) {
throw new Exception($result->getMessage());
}
$this->config[$key] = $value;
}
/**
* @return void
*/
public function waite(): void
{
while ($this->isEnd == false) {
$this->client->keepAlive((int)$this->grant["ID"]);
sleep(1);
}
}
}
@@ -1,23 +1,24 @@
<?php
namespace Kiri\Rpc;
use Throwable;
class InvalidRpcParamsException extends \Exception
{
/**
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
public function __construct($message = "", $code = 0, Throwable $previous = null)
{
parent::__construct($message, -32602, $previous);
}
}
<?php
namespace Kiri\Rpc;
use JetBrains\PhpStorm\Pure;
use Throwable;
class InvalidRpcParamsException extends \Exception
{
/**
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
#[Pure] public function __construct(string $message = "", int $code = 0, Throwable $previous = null)
{
parent::__construct($message, -32602, $previous);
}
}
+49
View File
@@ -0,0 +1,49 @@
<?php
namespace Kiri\Rpc;
use Exception;
use Kiri\Di\Inject\Container;
use Kiri\Exception\ConfigException;
use ReflectionException;
class JsonRpcPoolTransporter implements JsonRpcTransporterInterface
{
use TraitTransporter;
#[Container(ClientPool::class)]
public ClientPool $pool;
/**
* @param string $content
* @param string $service
* @return string|bool
* @throws RpcServiceException
* @throws ReflectionException
*/
public function push(string $content, string $service): string|bool
{
$client = $this->get_consul($service)->getClient();
$response = $this->request($client, $content);
$this->pool->push($client, $this->config['Address'], $this->config['Port']);
return $response;
}
/**
* @throws Exception
*/
private function getClient()
{
return $this->pool->get($this->config);
}
}
+37
View File
@@ -0,0 +1,37 @@
<?php
namespace Kiri\Rpc;
use Exception;
/**
*
*/
class JsonRpcTransporter implements JsonRpcTransporterInterface
{
use TraitTransporter;
/**
* @param string $content
* @param string $service
* @return string|bool
* @throws RpcServiceException
* @throws Exception
*/
public function push(string $content, string $service): string|bool
{
$client = $this->get_consul($service)->newClient();
$body = $this->request($client, $content);
$client->close();
return $body;
}
}
+15
View File
@@ -0,0 +1,15 @@
<?php
namespace Kiri\Rpc;
interface JsonRpcTransporterInterface
{
/**
* @param string $content
* @param string $service
* @return string|bool
*/
public function push(string $content, string $service): string|bool;
}
+201 -201
View File
@@ -1,201 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+185
View File
@@ -0,0 +1,185 @@
<?php
namespace Kiri\Rpc;
class LotteryDraw
{
/**
* @param array $goods
* @param string $wight
* @return mixed
* @uses $reward = Lucked::luck($data);
*/
public static function luck(array $goods, string $wight = 'probability'): mixed
{
static $class = null;
if ($class === null) $class = new LotteryDraw();
if (count($goods) < 1) return null;
$prob = $alias = [];
$class->ket($array = $class->init($goods, $wight), $prob, $alias);
$result = $class->generation($array, $prob, $alias);
if (!isset($goods[$result])) {
return null;
}
return $goods[$result];
}
/**
* @param array $goods
* @param string $wight
* @return array
*/
protected function init(array $goods, string $wight): array
{
$defaultIndex = -1;
$array = [];
foreach ($goods as $key => $val) {
if ($val[$wight] == 0) $defaultIndex = $key;
$array[] = (float)$val[$wight];
}
$total = array_sum($array);
if ($total > 1) {
$array = $this->reset($array, $total);
$total = array_sum($array);
}
if (1 - $total !== floatval(0)) {
if ($defaultIndex == -1) {
$defaultIndex = count($goods);
}
$array[$defaultIndex] = 1 - array_sum($array);
}
return $array;
}
/**
* @param array $data
* @param float $total
* @return array
*/
protected function reset(array $data, float $total): array
{
$length = $this->getMin($data);
foreach ($data as $key => $val) {
$data[$key] = ($val * $length - ($val * $length) / ($total * $length)) / $length;
}
return $data;
}
/**
* @param $data
* @param $prob
* @param $alias
* @return mixed
*/
private function generation($data, $prob, $alias): mixed
{
$nums = count($prob) - 1;
$MAX_P = $this->getMin($data); // 假设最小的几率是万分之一
$coin_toss = mt_rand(1, $MAX_P) / $MAX_P; // 抛出硬币
$col = mt_rand(0, $nums); // 随机落在一列
$b_head = $coin_toss > $prob[$col]; // 判断是否落在原色
return $b_head ? $alias[$col] : $col;
}
/**
* @param $num
* @return int
*/
private function getMin($num): int
{
$length = $this->getFloatLength($this->mini($num));
return (int)sprintf('1%0' . $length . 'd', 0);
}
/**
* @param $num
* @return int|float
*/
protected function mini($num): int|float
{
$def = current($num);
foreach ($num as $val) {
if ($val < $def) {
$def = $val;
}
}
return $def;
}
/**
* @param $float
* @return int
*/
private function getFloatLength($float): int
{
$ex = explode('.', $float);
return strlen(end($ex));
}
/**
* @param array $data
* @param array $prob
* @param array $alias
*/
private function ket(array $data, array &$prob, array &$alias): void
{
$nums = count($data);
$small = $large = [];
for ($i = 0; $i < $nums; ++$i) {
$data[$i] = $data[$i] * $nums; // 扩大倍数,使每列高度可为1
/** 分到两个数组,便于组合 */
if ($data[$i] < 1) {
$small[] = $i;
} else {
$large[] = $i;
}
}
/** 将超过1的色块与原色拼凑成1 */
while (!empty($small) && !empty($large)) {
$n_index = array_shift($small);
$a_index = array_shift($large);
$prob[$n_index] = $data[$n_index];
$alias[$n_index] = $a_index;
// 重新调整大色块
$data[$a_index] = ($data[$a_index] + $data[$n_index]) - 1;
if ($data[$a_index] < 1) {
$small[] = $a_index;
} else {
$large[] = $a_index;
}
}
/** 剩下大色块都设为1 */
while (!empty($large)) {
$n_index = array_shift($large);
$prob[$n_index] = 1;
}
/** 一般是精度问题才会执行这一步 */
while (!empty($small)) {
$n_index = array_shift($small);
$prob[$n_index] = 1;
}
}
}
@@ -1,12 +1,12 @@
<?php
namespace Kiri\Rpc;
interface OnJsonRpcInterface
{
// public function execute();
}
<?php
namespace Kiri\Rpc;
interface OnJsonRpcInterface
{
// public function execute();
}
@@ -1,8 +1,8 @@
<?php
namespace Kiri\Rpc;
interface OnRpcConsumerInterface
{
}
<?php
namespace Kiri\Rpc;
interface OnRpcConsumerInterface
{
}
+251
View File
@@ -0,0 +1,251 @@
<?php
namespace Kiri\Rpc;
use Exception;
use JetBrains\PhpStorm\ArrayShape;
use Kiri;
use Kiri\Abstracts\Component;
use Kiri\Core\Json;
use Kiri\Events\EventProvider;
use Kiri\Server\Contract\OnCloseInterface;
use Kiri\Server\Contract\OnConnectInterface;
use Kiri\Server\Contract\OnReceiveInterface;
use Kiri\Server\Events\OnBeforeShutdown;
use Kiri\Server\Events\OnServerBeforeStart;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use ReflectionException;
use Swoole\Coroutine;
use Kiri\Router\RouterCollector;
use Psr\Container\ContainerInterface;
use Swoole\Coroutine\Channel;
use Swoole\Server;
use Kiri\Router\DataGrip;
/**
*
*/
class RpcJsonp extends Component implements OnConnectInterface, OnReceiveInterface, OnCloseInterface
{
public RouterCollector $collector;
/**
* @param ContainerInterface $container
* @param DataGrip $dataGrip
* @param RpcManager $manager
* @param EventProvider $eventProvider
* @throws Exception
*/
public function __construct(public ContainerInterface $container,
public DataGrip $dataGrip,
public RpcManager $manager,
public EventProvider $eventProvider)
{
parent::__construct();
}
/**
* @return void
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws ReflectionException
* @throws Exception
*/
public function init(): void
{
$this->eventProvider->on(OnBeforeShutdown::class, [$this, 'onBeforeShutdown']);
$this->collector = $this->dataGrip->get('rpc');
}
/**
* @param OnBeforeShutdown $beforeShutdown
* @return void
*/
public function onBeforeShutdown(OnBeforeShutdown $beforeShutdown): void
{
if (env('environmental') != Kiri::WORKER && env('environmental_workerId') != 0) {
return;
}
}
/**
* @param OnServerBeforeStart $server
*/
public function register(OnServerBeforeStart $server)
{
}
/**
* @param Server $server
* @param int $fd
*/
public function onConnect(Server $server, int $fd): void
{
// TODO: Implement onConnect() method.
}
/**
* @param Server $server
* @param int $fd
* @param int $reactor_id
* @param string $data
* @return bool
*/
public function onReceive(Server $server, int $fd, int $reactor_id, string $data): bool
{
try {
$data = json_decode($data, true);
if (is_null($data)) return $server->send($fd, 'success', $reactor_id);
$data = json_decode($data, true);
if (!is_array($data)) {
throw new Exception('Parse error语法解析错误', -32700);
}
if (!isset($data['jsonrpc']) || !isset($data['method']) || $data['jsonrpc'] != '2.0') {
throw new Exception('Invalid Request无效请求', -32600);
}
return $server->send($fd, $this->batchDispatch($data), $reactor_id);
} catch (\Throwable $throwable) {
$response = Json::encode($this->failure(-32700, $throwable->getMessage()));
return $server->send($fd, $response, $reactor_id);
}
}
/**
* @param array $data
* @return string|bool
*/
private function batchDispatch(array $data): string|bool
{
if (isset($data['jsonrpc'])) {
$result = $this->dispatch($data);
if (!isset($data['id'])) {
$result = [1];
}
} else {
$channel = new Channel($total = count($data));
foreach ($data as $datum) {
$this->_execute($channel, $datum);
}
$result = [];
for ($i = 0; $i < $total; $i++) {
$result[] = $channel->pop();
}
}
return json_encode($result, JSON_UNESCAPED_UNICODE);
}
/**
* @param $channel
* @param $datum
*/
private function _execute($channel, $datum)
{
Coroutine::create(function () use ($channel, $datum) {
if (empty($datum) || !isset($datum['jsonrpc'])) {
$channel->push($this->failure(-32700, 'Parse error语法解析错误'));
} else if (!isset($datum['method'])) {
$channel->push($this->failure(-32700, 'Parse error语法解析错误'));
} else {
$dispatch = $this->dispatch($datum);
if (!isset($dispatch['id'])) {
$dispatch = [1];
}
$channel->push($dispatch);
}
});
}
/**
* @param $data
* @return array
*/
private function dispatch($data): array
{
// try {
// $class = $this->collector->query($data['service'], 'tcp');
// if (!$this->container->has($class)) {
// throw new Exception('Handler not found', -32601);
// }
// $controller = $this->container->get($class);
// if (!method_exists($controller, $data['method'])) {
// throw new Exception('Method not found', -32601);
// }
// if (!isset($data['params']) || !is_array($data['params'])) {
// $data['params'] = [];
// }
// return $this->handler($controller, $data['method'], $data['params']);
// } catch (\Throwable $throwable) {
// $code = $throwable->getCode() == 0 ? -32603 : $throwable->getCode();
// return $this->failure($code, jTraceEx($throwable), [], $data['id'] ?? null);
// }
return $this->failure(404, 'Not found.');
}
/**
* @param $controller
* @param string $method
* @param $params
* @return array
*/
#[ArrayShape([])]
private function handler($controller, string $method, $params): array
{
$result = call_user_func([$controller, $method], ...$params);
return [
'jsonrpc' => '2.0',
'result' => $result,
'id' => $data['id'] ?? null
];
}
/**
* @param $code
* @param $message
* @param array $data
* @param null $id
* @return array
*/
#[ArrayShape([])]
protected function failure($code, $message, array $data = [], $id = null): array
{
$error = [
'jsonrpc' => '2.0',
'error' => [
'code' => $code,
'message' => $message,
'data' => $data
]
];
if (!is_null($id)) {
$error['id'] = $id;
}
return $error;
}
/**
* @param Server $server
* @param int $fd
* @return void
*/
public function OnClose(Server $server, int $fd): void
{
// TODO: Implement onClose() method.
}
}
+39
View File
@@ -0,0 +1,39 @@
<?php
namespace Kiri\Rpc;
use Etcd\Client;
use Kiri;
use Kiri\Abstracts\Component;
use PhpParser\Node\Stmt\Return_;
/**
* class RpcManager
*/
class RpcManager extends Component
{
protected array $services = [];
/**
* @return void
*/
public function watch(): void
{
$data = new Client('','');
}
/**
* @param $service
* @return mixed
*/
public function getServices($service): mixed
{
return $this->services[$service] ?? null;
}
}
+47
View File
@@ -0,0 +1,47 @@
<?php
namespace Kiri\Rpc;
use Kiri\Di\Context;
use Kiri\Server\Abstracts\BaseProcess;
use Swoole\Coroutine;
use Swoole\Process;
class RpcProcess extends BaseProcess
{
/**
* @return string
*/
public function getName(): string
{
return "Rpc Manager";
}
/**
* @param Process|null $process
* @return void
*/
public function process(?Process $process): void
{
}
/**
* @return $this
*/
public function onSigterm(): static
{
// TODO: Implement onSigterm() method.
if (Context::inCoroutine()) {
Coroutine::create(fn() => $this->onShutdown(Coroutine::waitSignal(SIGTERM | SIGINT)));
} else {
\pcntl_signal(SIGTERM, [$this, 'onStop']);
\pcntl_signal(SIGINT, [$this, 'onStop']);
}
return $this;
}
}
+8
View File
@@ -0,0 +1,8 @@
<?php
namespace Kiri\Rpc;
class RpcServiceException extends \Exception
{
}
+25
View File
@@ -0,0 +1,25 @@
<?php
use Kiri\Rpc\AbstractRpcClient;
class TestRpc extends AbstractRpcClient
{
public string $service = '';
/**
* @param $data
* @param $nba
* @return mixed
*/
public function test($data, $nba): mixed
{
$resp = $this->send(__FUNCTION__, $data, $nba);
return json_decode($resp, true);
}
}
+103
View File
@@ -0,0 +1,103 @@
<?php
namespace Kiri\Rpc;
use Exception;
use JetBrains\PhpStorm\ArrayShape;
use Kiri\Di\Context;
use Kiri\Di\Inject\Container;
use Swoole\Client;
use Swoole\Coroutine;
trait TraitTransporter
{
/**
* @var RpcManager
*/
#[Container(RpcManager::class)]
public RpcManager $manager;
protected array $config;
/**
* @param resource $client
* @param $content
* @return string|bool
*/
protected function request(mixed $client, $content): string|bool
{
socket_write($client, \msgpack_pack($content), mb_strlen($content));
socket_read($client, 1024);
return \msgpack_unpack($client->recv());
}
/**
* @param string $service
* @return $this
* @throws RpcServiceException
*/
protected function get_consul(string $service): static
{
if (empty($service)) {
throw new RpcServiceException('You need set rpc service name if used.');
}
$sf = $this->manager->getServices($service);
if (empty($sf) || !is_array($sf)) {
throw new RpcServiceException('You need set rpc service name if used.');
}
$this->config = $this->_loadRand($sf);
return $this;
}
/**
* @param $services
* @return array
*/
#[ArrayShape(['Address' => "mixed", 'Port' => "mixed"])]
protected function _loadRand($services): array
{
$array = [];
foreach ($services as $value) {
$value['Weight'] = $value['Weights']['Passing'];
$array[] = $value;
}
if (count($array) < 2) {
$luck = $array[0];
} else {
$luck = LotteryDraw::luck($array, 'Weight');
}
return [
'Address' => $luck['TaggedAddresses']['wan_ipv4']['Address'],
'Port' => $luck['TaggedAddresses']['wan_ipv4']['Port']
];
}
/**
* @return Client|Coroutine\Client
* @throws Exception
*/
protected function newClient(): Coroutine\Client|Client
{
if (Context::inCoroutine()) {
$client = new Coroutine\Client(SWOOLE_SOCK_TCP);
} else {
$client = new Client(SWOOLE_SOCK_TCP);
}
[$host, $port] = [$this->config['Address'], $this->config['Port']];
if (!$client->isConnected() && !$client->connect($host, $port, 60)) {
throw new Exception('connect fail.');
}
return $client;
}
}
+33 -24
View File
@@ -1,24 +1,33 @@
{
"name": "game-worker/kiri-rpc",
"description": "kiri-rpc",
"authors": [
{
"name": "XiangLin",
"email": "as2252258@163.com"
}
],
"license": "MIT",
"require": {
"php": ">=8.0",
"ext-json": "*",
"psr/http-client": "^1.0",
"psr/http-message": "^1.0"
},
"autoload": {
"psr-4": {
"Kiri\\Rpc\\": "src/"
}
},
"require-dev": {
}
}
{
"name": "game-worker/kiri-rpc",
"description": "kiri-rpc",
"authors": [
{
"name": "XiangLin",
"email": "as2252258@163.com"
}
],
"license": "MIT",
"require": {
"php": ">=8.0",
"ext-json": "*",
"ext-msgpack": "*",
"start-point/etcd-php": "^1.1",
"game-worker/kiri-pool": "~v1.0",
"linkorb/etcd-php": "^1.6"
},
"replace": {
"symfony/polyfill-apcu": "*",
"symfony/polyfill-php80": "*",
"symfony/polyfill-mbstring": "*",
"symfony/polyfill-ctype": "*",
"symfony/polyfill-php73": "*",
"symfony/polyfill-php72": "*",
"symfony/polyfill-php81": "*"
},
"autoload": {
"psr-4": {
"Kiri\\Rpc\\": "./"
}
}
}
+67
View File
@@ -0,0 +1,67 @@
<?php
use Kiri\Rpc\RpcJsonp;
use Kiri\Rpc\TestRpcService;
use Kiri\Server\Constant;
return [
'rpc' => [
'name' => 'json-rpc',
'type' => Constant::SERVER_TYPE_BASE,
'mode' => SWOOLE_SOCK_TCP,
'host' => '0.0.0.0',
'port' => 9526,
'settings' => [
],
'events' => [
Constant::RECEIVE => [RpcJsonp::class, 'onReceive']
]
],
'service' => [
[
"datacenter" => "dc1",
"id" => "40e4a748-2192-161a-0510-9bf59fe950b5",
"node" => "FriendRpcService",
'class' => TestRpc::class,
"skipNodeUpdate" => false,
"service" => [
"id" => "redis1",
"service" => "FriendRpcService",
"address" => "172.26.221.211",
"taggedAddresses" => [
"lan" => [
"address" => "127.0.0.1",
"port" => 8000
],
"wan" => [
"address" => "172.26.221.211",
"port" => 80
]
],
"meta" => [
"redis_version" => "4.0"
],
"port" => 8000
],
"check" => [
"node" => "t2.320",
"checkId" => "service:redis1",
"name" => "Redis health check",
"Annotations" => "Script based health check",
"status" => "passing",
"serviceID" => "redis1",
"definition" => [
"http" => "172.26.221.211:9527",
"interval" => "5s",
"timeout" => "1s",
"deregisterCriticalServiceAfter" => "30s"
],
],
]
]
];
-76
View File
@@ -1,76 +0,0 @@
<?php
namespace Kiri\Rpc;
use Exception;
use Kiri\Abstracts\Component;
use Kiri\Context;
use Kiri\Exception\ConfigException;
use Kiri\Kiri;
use Kiri\Pool\Alias;
use Kiri\Pool\Pool;
use Swoole\Client;
/**
*
*/
class ClientPool extends Component
{
const POOL_NAME = 'rpc.client.pool';
use Alias;
public int $max;
public int $min;
public int $waite;
/**
* @param $config
* @param callable $callback
* @return mixed
* @throws ConfigException
* @throws Exception
*/
public function get($config, callable $callback): mixed
{
$coroutineName = $this->name(self::POOL_NAME . '::' . $config['ServiceAddress'] . '::' . $config['ServicePort'], true);
$pool = $config['pool'] ?? ['min' => 1, 'max' => 100];
return $this->getPool()->get($coroutineName, $callback, $pool['min'] ?? 1);
}
/**
* @param \Swoole\Coroutine\Client|Client $client
* @param $host
* @param $port
* @throws ConfigException
* @throws Exception
*/
public function push(\Swoole\Coroutine\Client|Client $client, $host, $port)
{
$coroutineName = $this->name(self::POOL_NAME . '::' . $host . '::' . $port, true);
$this->getPool()->push($coroutineName, $client);
}
/**
* @return Pool
* @throws Exception
*/
public function getPool(): Pool
{
return Kiri::getDi()->get(Pool::class);
}
}
-140
View File
@@ -1,140 +0,0 @@
<?php
namespace Kiri\Rpc;
use Exception;
use Http\Message\ServerRequest;
use Http\Message\Stream;
use Kiri\Consul\Agent;
use Kiri\Core\Number;
use Kiri\Kiri;
use Kiri\Pool\Pool;
use Psr\Http\Client\ClientExceptionInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
/**
*
*/
abstract class JsonRpcConsumers implements OnRpcConsumerInterface
{
/**
* @var Pool
*/
public Pool $pool;
protected string $name = '';
/**
* @param string $method
* @param mixed $data
* @param string $version
* @throws Exception
* @throws ClientExceptionInterface
*/
public function notify(string $method, mixed $data, string $version = '2.0'): void
{
$config = $this->get_consul($this->name);
$transporter = Kiri::getDi()->get(RpcClientInterface::class);
$transporter->withConfig($config)->sendRequest(
$this->requestBody([
'jsonrpc' => $version,
'service' => $this->name,
'method' => $method,
'params' => $data,
])
);
}
/**
* @param array $data
* @return ServerRequestInterface
*/
private function requestBody(array $data): ServerRequestInterface
{
$server = Kiri::getDi()->get(ServerRequest::class);
return $server->withBody(new Stream(json_encode($data)));
}
/**
* @param string $method
* @param mixed $data
* @param string $version
* @param string $id
* @return mixed
* @throws Exception
* @throws ClientExceptionInterface
*/
public function get(string $method, mixed $data, string $version = '2.0', string $id = ''): ResponseInterface
{
if (empty($id)) $id = Number::create(time());
$config = $this->get_consul($this->name);
$transporter = Kiri::getDi()->get(RpcClientInterface::class);
return $transporter->withConfig($config)->sendRequest(
$this->requestBody([
'jsonrpc' => $version,
'service' => $this->name,
'method' => $method,
'params' => $data,
'id' => $id
])
);
}
/**
* @param array $data
* @return mixed
* @throws ClientExceptionInterface
* @throws Exception
*/
public function batch(array $data): mixed
{
$config = $this->get_consul($this->name);
$transporter = Kiri::getDi()->get(RpcClientInterface::class);
return $transporter->withConfig($config)->sendRequest(
$this->requestBody($data)
);
}
/**
* @param $service
* @return array
* @throws Exception
*/
private function get_consul($service): array
{
if (empty($service)) {
throw new Exception('You need set rpc service name if used.');
}
$sf = Kiri::getDi()->get(Agent::class);
$response = $sf->service->setQuery('filter=Service == ' . $service)->list();
if ($response->getStatusCode() != 200 || $response->getBody()->getSize() <= 2) {
throw new Exception('No microservices found [' . $service . '].');
}
$array = [];
$content = json_decode($response->getBody()->getContents(), true);
foreach ($content as $value) {
$array[] = ['id' => $value['ID'], 'Weights' => $value['Weights']['Passing']];
}
if (count($array) < 2) {
$luck = $array[0];
} else {
$luck = Luckdraw::luck($array, 'Weights');
}
return ['Address' => $luck['Address'], 'Port' => $luck['Port']];
}
}
-68
View File
@@ -1,68 +0,0 @@
<?php
namespace Kiri\Rpc;
use Note\Inject;
use Exception;
use Http\Message\Response;
use Http\Message\Stream;
use Kiri\Abstracts\Config;
use Kiri\Exception\ConfigException;
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Swoole\Coroutine\Client;
class JsonRpcPoolTransporter implements ClientInterface
{
use TraitTransporter;
#[Inject(ClientPool::class)]
public ClientPool $pool;
const POOL_NAME = 'rpc.client.pool';
/**
*/
public function init()
{
}
/**
* @param RequestInterface $request
* @return ResponseInterface
* @throws Exception
*/
public function sendRequest(RequestInterface $request): ResponseInterface
{
$content = $request->getBody()->getContents();
$response = $this->request($client = $this->getClient(), $content, false);
$this->pool->push($client, $this->config['ServiceAddress'], $this->config['ServicePort']);
return (new Response())->withBody(new Stream($response));
}
/**
* @return Client|\Swoole\Client
* @throws ConfigException
* @throws Exception
*/
private function getClient(): Client|\Swoole\Client
{
$this->config['pool'] = Config::get('rpc.pool', ['max' => 10, 'min' => 1, 'waite' => 60]);
return $this->pool->get($this->config, function () {
return $this->newClient();
});
}
}
-37
View File
@@ -1,37 +0,0 @@
<?php
namespace Kiri\Rpc;
use Http\Message\Response;
use Http\Message\Stream;
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
/**
*
*/
class JsonRpcTransporter implements ClientInterface
{
use TraitTransporter;
/**
* @param RequestInterface $request
* @return ResponseInterface
* @throws \Exception
*/
public function sendRequest(RequestInterface $request): ResponseInterface
{
$content = $request->getBody()->getContents();
$response = $this->request($this->newClient(), $content, true);
return (new Response())->withBody(new Stream($response));
}
}
-151
View File
@@ -1,151 +0,0 @@
<?php
namespace Kiri\Rpc;
use Exception;
class Luckdraw
{
/**
* @param array $goods
* @param string $wight
* @return mixed
* @array = [
* ['name'=> '商品名称', 'probability'=> '概率', 'total'=> '库存'],
* ['name'=> '商品名称', 'probability'=> '概率', 'total'=> '库存'],
* ['name'=> '商品名称', 'probability'=> '概率', 'total'=> '库存'],
* ['name'=> '商品名称', 'probability'=> '概率', 'total'=> '库存'],
* ['name'=> '商品名称', 'probability'=> '概率', 'total'=> '库存'],
* ['name'=> '商品名称', 'probability'=> '概率', 'total'=> '库存'],
* ['name'=> '商品名称', 'probability'=> '概率', 'total'=> '库存'],
* ['name'=> '商品名称', 'probability'=> '概率', 'total'=> '库存'],
* ]
*
* @uses $reward = Lucked::luck($data);
*/
public static function luck(array $goods, string $wight = 'probability'): mixed
{
static $class = null;
if ($class === null) $class = new Luckdraw();
if (empty($goods)) return null;
$array = $prob = $alias = [];
$defaultIndex = 0;
foreach ($goods as $key => $val) {
if ($val[$wight] == 0) $defaultIndex = $key;
$array[] = (float)$val[$wight];
}
$array[$defaultIndex] = 1 - array_sum($array);
$class->ket($array, $prob, $alias);
$result = $class->generation($array, $prob, $alias);
if (!isset($goods[$result])) {
return null;
}
return $goods[$result];
}
/**
* @param $data
* @param $prob
* @param $alias
* @return mixed
*/
private function generation($data, $prob, $alias): mixed
{
$nums = count($prob) - 1;
$MAX_P = $this->getMin($data); // 假设最小的几率是万分之一
$coin_toss = rand(1, $MAX_P) / $MAX_P; // 抛出硬币
$col = rand(0, $nums); // 随机落在一列
$b_head = $coin_toss < $prob[$col]; // 判断是否落在原色
return $b_head ? $col : @$alias[$col];
}
/**
* @param $num
* @return string
*/
private function getMin($num): string
{
$def = current($num);
foreach ($num as $val) {
if ($val < $def) {
$def = $val;
}
}
$length = $this->getFloatLength($def) + 1;
return sprintf('1%0' . $length . 'd', 0);
}
/**
* @param $float
* @return int
*/
private function getFloatLength($float): int
{
$ex = explode('.', 1 - $float);
return strlen(end($ex));
}
/**
* @param array $data
* @param array $prob
* @param array $alias
*/
private function ket(array $data, array &$prob, array &$alias)
{
$nums = count($data);
$small = $large = [];
for ($i = 0; $i < $nums; ++$i) {
$data[$i] = $data[$i] * $nums; // 扩大倍数,使每列高度可为1
/** 分到两个数组,便于组合 */
if ($data[$i] < 1) {
$small[] = $i;
} else {
$large[] = $i;
}
}
/** 将超过1的色块与原色拼凑成1 */
while (!empty($small) && !empty($large)) {
$n_index = array_shift($small);
$a_index = array_shift($large);
$prob[$n_index] = $data[$n_index];
$alias[$n_index] = $a_index;
// 重新调整大色块
$data[$a_index] = ($data[$a_index] + $data[$n_index]) - 1;
if ($data[$a_index] < 1) {
$small[] = $a_index;
} else {
$large[] = $a_index;
}
}
/** 剩下大色块都设为1 */
while (!empty($large)) {
$n_index = array_shift($large);
$prob[$n_index] = 1;
}
/** 一般是精度问题才会执行这一步 */
while (!empty($small)) {
$n_index = array_shift($small);
$prob[$n_index] = 1;
}
}
}
-74
View File
@@ -1,74 +0,0 @@
<?php
namespace Kiri\Rpc\Note;
use Note\Attribute;
use Kiri\Abstracts\Config;
use Kiri\Consul\Agent;
use Kiri\Exception\ConfigException;
use Kiri\Kiri;
use Kiri\Rpc\RpcManager;
use ReflectionException;
#[\Attribute(\Attribute::TARGET_CLASS)] class JsonRpc extends Attribute
{
/**
* @param string $service
* @param string $driver
* @param array $checkOptions
*/
public function __construct(public string $service, public string $driver, public array $checkOptions = [
"DeregisterCriticalServiceAfter" => "1m",
"Http" => "http://127.0.0.1:9527",
"Interval" => "1s",
"Timeout" => "1s"
])
{
}
/**
* @param mixed $class
* @param mixed|string $method
* @return mixed
* @throws ReflectionException
* @throws ConfigException
*/
public function execute(mixed $class, mixed $method = ''): bool
{
$default = $this->create();
$agent = Kiri::getDi()->get(Agent::class);
$data = $agent->service->register($default);
if ($data->getStatusCode() != 200) {
exit($data->getBody()->getContents());
}
return RpcManager::add($this->service, $class, $default['id']);
}
/**
* @throws ConfigException
*/
protected function create(): array
{
$content = current(swoole_get_local_ip());
return [
"id" => "rpc.json.{$this->service}." . md5(__DIR__ . '.' . md5($content)),
"name" => $this->service,
"address" => $content,
"port" => 9526,
"enableTagOverride" => true,
"check" => [
"DeregisterCriticalServiceAfter" => "1m",
"TCP" => $content . ":" . Config::get('rpc.port'),
"Interval" => "1s",
"Timeout" => "1s"
]
];
}
}
-14
View File
@@ -1,14 +0,0 @@
<?php
namespace Kiri\Rpc;
use Psr\Http\Client\ClientInterface;
/**
* @mixin JsonRpcTransporter
*/
interface RpcClientInterface extends ClientInterface
{
}
-261
View File
@@ -1,261 +0,0 @@
<?php
namespace Kiri\Rpc;
use Note\Note;
use Note\Inject;
use Http\Constrict\RequestInterface;
use Http\Handler\Router;
use Http\Message\ServerRequest;
use Kiri\Abstracts\Component;
use Kiri\Abstracts\Config;
use Kiri\Consul\Agent;
use Kiri\Context;
use Kiri\Core\Json;
use Kiri\Events\EventProvider;
use Kiri\Exception\ConfigException;
use Kiri\Kiri;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\ContainerInterface;
use Psr\Container\NotFoundExceptionInterface;
use Psr\Http\Message\ServerRequestInterface;
use Server\Contract\OnCloseInterface;
use Server\Contract\OnConnectInterface;
use Server\Contract\OnReceiveInterface;
use Server\Events\OnBeforeShutdown;
use Server\Events\OnStart;
use Swoole\Coroutine;
use Swoole\Coroutine\Channel;
use Swoole\Server;
/**
*
*/
class RpcJsonp extends Component implements OnConnectInterface, OnReceiveInterface, OnCloseInterface
{
#[Inject(Router::class)]
public Router $router;
#[Inject(Note::class)]
public Note $annotation;
#[Inject(EventProvider::class)]
public EventProvider $eventProvider;
#[Inject(ContainerInterface::class)]
public ContainerInterface $container;
/**
*
* @throws \Exception
*/
public function init(): void
{
$this->eventProvider->on(OnBeforeShutdown::class, [$this, 'onBeforeShutdown']);
scan_directory(APP_PATH . 'rpc', 'Rpc');
}
/**
* @param OnBeforeShutdown $beforeShutdown
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function onBeforeShutdown(OnBeforeShutdown $beforeShutdown)
{
$doneList = RpcManager::doneList();
$agent = $this->container->get(Agent::class);
foreach ($doneList as $value) {
$agent->service->deregister($value);
}
}
/**
* @param OnStart $server
* @throws ConfigException
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function register(OnStart $server)
{
$config = Config::get('rpc');
$agent = $this->container->get(Agent::class);
$data = $agent->service->register($config['registry']['config']);
if ($data->getStatusCode() != 200) {
$server->server->shutdown();
}
}
/**
* @param Server $server
* @param int $fd
*/
public function onConnect(Server $server, int $fd): void
{
// TODO: Implement onConnect() method.
}
/**
* @param Server $server
* @param int $fd
* @param int $reactor_id
* @param string $data
*/
public function onReceive(Server $server, int $fd, int $reactor_id, string $data): void
{
$data = json_decode($data, true);
if (is_null($data)) {
$this->failure(-32700, 'Parse error语法解析错误');
} else if (!isset($data['jsonrpc']) || !isset($data['method']) || $data['jsonrpc'] != '2.0') {
$this->failure(-32600, 'Invalid Request无效请求');
} else {
$this->batchDispatch($server, $fd, $data);
}
}
/**
* @param Server $server
* @param int $fd
* @param array $data
* @return void
*/
private function batchDispatch(Server $server, int $fd, array $data): void
{
if (isset($data['jsonrpc'])) {
$dispatch = $this->dispatch($data);
if (!isset($data['id'])) {
$dispatch = [1];
}
$result = json_encode($dispatch, JSON_UNESCAPED_UNICODE);
} else {
$channel = new Channel($total = count($data));
foreach ($data as $datum) {
$this->_execute($channel, $datum);
}
$result = [];
for ($i = 0; $i < $total; $i++) {
$result[] = $channel->pop();
}
}
$server->send($fd, json_encode($result, JSON_UNESCAPED_UNICODE));
}
/**
* @param $channel
* @param $datum
*/
private function _execute($channel, $datum)
{
Coroutine::create(function () use ($channel, $datum) {
if (empty($datum) || !isset($datum['jsonrpc'])) {
$channel->push($this->failure(-32700, 'Parse error语法解析错误'));
} else if (!isset($datum['method'])) {
$channel->push($this->failure(-32700, 'Parse error语法解析错误'));
} else {
$dispatch = $this->dispatch($datum);
if (!isset($dispatch['id'])) {
$dispatch = [1];
}
$channel->push($dispatch);
}
});
}
/**
* @param $data
* @return array
*/
private function dispatch($data): array
{
try {
[$handler, $params, $_] = RpcManager::get($data['service'], $data['method']);
if (is_null($handler)) {
throw new \Exception('Method not found', -32601);
} else {
$PsrRequest = Context::setContext(RequestInterface::class, $this->createServerRequest($params));
return $this->handler($handler, $PsrRequest);
}
} catch (\Throwable $throwable) {
$code = $throwable->getCode() == 0 ? -32603 : $throwable->getCode();
return $this->failure($code, jTraceEx($throwable), [], $data['id'] ?? null);
}
}
/**
* @param $params
* @return ServerRequestInterface
* @throws \Exception
*/
private function createServerRequest($params): ServerRequestInterface
{
return (new ServerRequest())->withParsedBody($params);
}
/**
* @param array $handler
* @param $request
* @return array
* @throws \ReflectionException
*/
private function handler(array $handler, $request): array
{
$controller = Kiri::getDi()->get($handler[0]);
$dispatcher = $controller->{$handler[1]}($request);
return [
'jsonrpc' => '2.0',
'result' => $dispatcher,
'id' => $data['id'] ?? null
];
}
/**
* @param $code
* @param $message
* @param array $data
* @param null $id
* @return array
*/
protected function failure($code, $message, array $data = [], $id = null): array
{
$error = [
'jsonrpc' => '2.0',
'error' => [
'code' => $code,
'message' => $message,
'data' => $data
]
];
if (!is_null($id)) {
$error['id'] = $id;
}
return $error;
}
/**
* @param Server $server
* @param int $fd
*/
public function onClose(Server $server, int $fd): void
{
// TODO: Implement onClose() method.
}
}
-64
View File
@@ -1,64 +0,0 @@
<?php
namespace Kiri\Rpc;
use Kiri\Kiri;
use ReflectionException;
class RpcManager
{
/**
* @var array
*/
private static array $_rpc = [];
/**
* @param string $name
* @param string $class
* @param string $serviceId
* @return bool
* @throws ReflectionException
*/
public static function add(string $name, string $class, string $serviceId): bool
{
$methods = Kiri::getDi()->getReflect($class);
$lists = $methods->getMethods(\ReflectionMethod::IS_PUBLIC);
if (!isset(static::$_rpc[$name])) static::$_rpc[$name] = ['methods' => [], 'id' => $serviceId];
foreach ($lists as $reflection) {
$methodName = $reflection->getName();
static::$_rpc[$name]['methods'][$methodName] = [[$class, $methodName], null];
}
return true;
}
/**
* @return array
*/
public static function doneList(): array
{
$array = [];
foreach (static::$_rpc as $list) {
$array[] = $list['id'];
}
return $array;
}
/**
* @param string $name
* @param string $method
* @return mixed
*/
public static function get(string $name, string $method): array
{
return static::$_rpc[$name]['methods'][$method] ?? [null, null];
}
}
-78
View File
@@ -1,78 +0,0 @@
<?php
namespace Kiri\Rpc;
use Exception;
use Kiri\Context;
use Swoole\Client;
use Swoole\Coroutine;
trait TraitTransporter
{
protected array $config;
protected array $clients = [];
/**
* @param $config
* @return $this
*/
public function withConfig($config): static
{
$this->config = $config;
return $this;
}
/**
* @param Client|Coroutine\Client $client
* @param $content
* @param bool $isClose
* @return mixed
*/
private function request(Client|Coroutine\Client $client, $content, bool $isClose): mixed
{
$client->send($content);
$read = $client->recv();
if ($isClose) {
$client->close();
}
return $read;
}
/**
* @return Client|Coroutine\Client
* @throws Exception
*/
private function newClient(): Coroutine\Client|Client
{
$alias = $this->alias($this->config);
$client = $this->clients[$alias] ?? null;
if (is_null($client)) {
$client = Context::inCoroutine() ? new Coroutine\Client(SWOOLE_SOCK_TCP) : new Client(SWOOLE_SOCK_TCP);
$this->clients[$alias] = $client;
}
[$host, $port] = [$this->config['ServiceAddress'], $this->config['ServicePort']];
if (!$client->isConnected() && !$client->connect($host, $port, 60)) {
throw new Exception('connect fail.');
}
return $client;
}
/**
* @param array $config
* @return string
*/
private function alias(array $config): string
{
return $config['ServiceAddress'] . '::' . $config['ServicePort'];
}
}
-33
View File
@@ -1,33 +0,0 @@
<?php
use Kiri\Rpc\RpcJsonp;
use Kiri\Rpc\TestRpcService;
use Server\Constant;
return [
'rpc' => [
'name' => 'json-rpc',
'type' => Constant::SERVER_TYPE_BASE,
'mode' => SWOOLE_SOCK_TCP,
'host' => '0.0.0.0',
'port' => 9526,
'settings' => [
],
'events' => [
Constant::RECEIVE => [RpcJsonp::class, 'onReceive']
],
'consumers' => [
'class' => TestRpcService::class,
'name' => 'test-rpc',
'package' => 'test',
'register' => [
'host' => '',
'port' => ''
]
]
]
];