Compare commits
193 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 73cb94f657 | |||
| b3ea8978b1 | |||
| 008a0914eb | |||
| 01f8e16b38 | |||
| c095b69f67 | |||
| 4c8c5ac239 | |||
| cfc847133e | |||
| 30b430f1cf | |||
| 516c7612a5 | |||
| 3bb3d5a1d7 | |||
| fb48a0b508 | |||
| a3964faa72 | |||
| 0fea7ac770 | |||
| 7eccee5d16 | |||
| 565943b76f | |||
| adb95af124 | |||
| b554b53cfd | |||
| 0e0caaf8a9 | |||
| c37c11a768 | |||
| 51a2f448fd | |||
| eb6aaf3509 | |||
| 12766a3b74 | |||
| ec00c2d104 | |||
| 40a2331626 | |||
| d528e4d603 | |||
| 39865db17a | |||
| 04434f72d4 | |||
| f95f576a52 | |||
| 7fde689244 | |||
| b083984efd | |||
| f83538b687 | |||
| d0c579455d | |||
| 5aae1f0ba4 | |||
| ca874beaaf | |||
| 15e8d7a5a7 | |||
| 2959115a23 | |||
| b661581baf | |||
| ab8a7d7fff | |||
| 31a5053bed | |||
| be9c469a0f | |||
| 3c3ba68aba | |||
| 4d2b462676 | |||
| c075662c59 | |||
| 35ce80c19b | |||
| 3345ff697b | |||
| 2ea7289c43 | |||
| 3e53f8d3c2 | |||
| af3b482c1f | |||
| cf8b25d7db | |||
| 0ba9fc0ce7 | |||
| a03c28d7e5 | |||
| ab32584cf2 | |||
| 423d406f3e | |||
| c545686b8f | |||
| 7246d88e44 | |||
| 1aef68902b | |||
| 41ee154c90 | |||
| 37b745b659 | |||
| 88cdf3a547 | |||
| 1a012150ce | |||
| 74bcdf257e | |||
| d3fd4385e6 | |||
| e94b3ca1d9 | |||
| 2ca845a65c | |||
| ee23b78872 | |||
| bccf0e2a1e | |||
| d98392b6af | |||
| c17e829f75 | |||
| 216bc1d894 | |||
| 77b457b620 | |||
| 6cdf8052e6 | |||
| 9ea0b9d34b | |||
| f91194b5c8 | |||
| a671719896 | |||
| 6612040b3a | |||
| 4c2068482a | |||
| d762d392e8 | |||
| 3399c31e70 | |||
| 5e8676b844 | |||
| 9b9a6233dc | |||
| a233ff72ab | |||
| 8999b7ad3f | |||
| 36db8aa4a8 | |||
| d47e1309a9 | |||
| a77d138898 | |||
| 0466268ac8 | |||
| 2c37c5c494 | |||
| 42db5c83dc | |||
| c439e9949c | |||
| d0f3469997 | |||
| 1fad90e1e7 | |||
| 968be07fbb | |||
| f0fe2c1c11 | |||
| b66b2867ab | |||
| 956a68bbff | |||
| bcf865ff34 | |||
| de475736ba | |||
| 7a39375657 | |||
| 8e700e4086 | |||
| 19bd6882d1 | |||
| 40f315f4d9 | |||
| 632d96a197 | |||
| 2e32dea501 | |||
| 4df34aac0b | |||
| 3dff8272ea | |||
| 5c3a197b52 | |||
| 8ebfb295ab | |||
| 49892feff4 | |||
| 7fcf535617 | |||
| ccc9f9bbf1 | |||
| e2e43959a8 | |||
| 382a6ff1b5 | |||
| 9feebc2b73 | |||
| 3f9a7b98e8 | |||
| 1f9116c9c0 | |||
| c0f9506dc6 | |||
| 65ff89e3ed | |||
| 058beb2c26 | |||
| 2036d4ebd9 | |||
| 1f7403b8c0 | |||
| d7b84a804d | |||
| 4096050303 | |||
| b23cf6187c | |||
| 6f0e423773 | |||
| f8a28967d5 | |||
| a3f02701ca | |||
| 2e6ca9b4fa | |||
| c3d8a92b33 | |||
| ba9086b56b | |||
| d34eb2bf53 | |||
| c4c6d9a58e | |||
| ee255c02f9 | |||
| e4c65484fe | |||
| a70e080153 | |||
| b5bd2d12f8 | |||
| c4cf051139 | |||
| 2f17c40444 | |||
| 84d120de92 | |||
| 89e7f2d7bc | |||
| 0db42d3a38 | |||
| aa72ac2eb9 | |||
| fbe83aff27 | |||
| 7e7652795d | |||
| 15da06a63d | |||
| db65cb46c2 | |||
| f3f29c1342 | |||
| 0436076614 | |||
| 53cbc714ed | |||
| 5e9df58276 | |||
| b76c262397 | |||
| e31a66686f | |||
| a8244921ae | |||
| 164ce98990 | |||
| 7e25c361bf | |||
| 557d0fd583 | |||
| 9b7e6e1396 | |||
| 56df262e56 | |||
| 6d49e73ec2 | |||
| f7fb56fc06 | |||
| add59693c1 | |||
| 84071fecde | |||
| 4e5787b20d | |||
| 52823100af | |||
| 2b9d09f835 | |||
| e576af2071 | |||
| 07c2b3f6cf | |||
| aed5e9469d | |||
| 9da5d5a332 | |||
| 1c48f27e4a | |||
| 760192d63a | |||
| c786999fe1 | |||
| cd133a8ec7 | |||
| d40d3cc282 | |||
| 33508652ad | |||
| 8286e27407 | |||
| 188f53d3b0 | |||
| d353e019df | |||
| e0b3954909 | |||
| b6ac2c75ee | |||
| 558008ad08 | |||
| 10805c1022 | |||
| 3d9266dc16 | |||
| b80b2c18db | |||
| a7630df003 | |||
| 2cea45051b | |||
| da703055b3 | |||
| 78bc474f2b | |||
| 1622986699 | |||
| 0935f54f06 | |||
| 894feb3506 | |||
| 04ef4473cc | |||
| ed4051171c | |||
| 6fb5bb1d41 |
@@ -7,10 +7,6 @@ namespace Annotation\Route;
|
||||
use Annotation\Attribute;
|
||||
use Exception;
|
||||
use HttpServer\Route\Router;
|
||||
use ReflectionException;
|
||||
use Snowflake\Exception\ComponentException;
|
||||
use Snowflake\Exception\ConfigException;
|
||||
use Snowflake\Exception\NotFindClassException;
|
||||
use Snowflake\Snowflake;
|
||||
|
||||
/**
|
||||
@@ -30,21 +26,18 @@ use Snowflake\Snowflake;
|
||||
* @param string|null $uri
|
||||
* @param string $version
|
||||
*/
|
||||
public function __construct(
|
||||
public string $event,
|
||||
public ?string $uri = null,
|
||||
public string $version = 'v.1.0'
|
||||
)
|
||||
public function __construct(public string $event, public ?string $uri = null, public string $version = 'v.1.0')
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $handler
|
||||
* @param mixed $class
|
||||
* @param mixed|null $method
|
||||
* @return Router
|
||||
* @throws Exception
|
||||
*/
|
||||
public function execute(mixed $class, mixed $method = null): Router
|
||||
public function execute(mixed $class, mixed $method = null): Router
|
||||
{
|
||||
// TODO: Implement setHandler() method.
|
||||
$router = Snowflake::app()->getRouter();
|
||||
|
||||
@@ -132,7 +132,7 @@ class ActiveQuery extends Component implements ISqlBuilder
|
||||
*/
|
||||
public function execute($sql, $params = []): Command
|
||||
{
|
||||
return $this->modelClass::getDb()->createCommand($sql, $params);
|
||||
return $this->modelClass::getDb()->createCommand($sql, $this->modelClass::getDbName(), $params);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ use Database\Traits\HasBase;
|
||||
use Exception;
|
||||
use ReflectionException;
|
||||
use Snowflake\Channel;
|
||||
use Snowflake\Event;
|
||||
use Snowflake\Exception\NotFindClassException;
|
||||
use Snowflake\Snowflake;
|
||||
|
||||
@@ -195,7 +196,7 @@ class ActiveRecord extends BaseActiveRecord
|
||||
if (is_bool($create)) {
|
||||
return false;
|
||||
}
|
||||
return static::getDb()->createCommand($create[0], $create[1])->exec();
|
||||
return static::getDb()->createCommand($create[0], static::getDbName(), $create[1])->exec();
|
||||
}
|
||||
|
||||
|
||||
|
||||
+965
-945
File diff suppressed because it is too large
Load Diff
+256
-252
@@ -14,7 +14,7 @@ use Exception;
|
||||
use PDO;
|
||||
use PDOStatement;
|
||||
use Snowflake\Abstracts\Component;
|
||||
use Swoole\Coroutine;
|
||||
use Snowflake\Core\Json;
|
||||
|
||||
/**
|
||||
* Class Command
|
||||
@@ -22,291 +22,295 @@ use Swoole\Coroutine;
|
||||
*/
|
||||
class Command extends Component
|
||||
{
|
||||
const ROW_COUNT = 'ROW_COUNT';
|
||||
const FETCH = 'FETCH';
|
||||
const FETCH_ALL = 'FETCH_ALL';
|
||||
const EXECUTE = 'EXECUTE';
|
||||
const FETCH_COLUMN = 'FETCH_COLUMN';
|
||||
const ROW_COUNT = 'ROW_COUNT';
|
||||
const FETCH = 'FETCH';
|
||||
const FETCH_ALL = 'FETCH_ALL';
|
||||
const EXECUTE = 'EXECUTE';
|
||||
const FETCH_COLUMN = 'FETCH_COLUMN';
|
||||
|
||||
const DB_ERROR_MESSAGE = 'The system is busy, please try again later.';
|
||||
const DB_ERROR_MESSAGE = 'The system is busy, please try again later.';
|
||||
|
||||
/** @var Connection */
|
||||
public Connection $db;
|
||||
/** @var Connection */
|
||||
public Connection $db;
|
||||
|
||||
/** @var ?string */
|
||||
public ?string $sql = '';
|
||||
/** @var ?string */
|
||||
public ?string $sql = '';
|
||||
|
||||
/** @var array */
|
||||
public array $params = [];
|
||||
/** @var array */
|
||||
public array $params = [];
|
||||
|
||||
/** @var string */
|
||||
private string $_modelName;
|
||||
/** @var string */
|
||||
private string $_modelName;
|
||||
|
||||
private ?PDOStatement $prepare = null;
|
||||
private ?PDOStatement $prepare = null;
|
||||
|
||||
|
||||
/**
|
||||
* @return array|bool|int|string|PDOStatement|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public function incrOrDecr(): array|bool|int|string|PDOStatement|null
|
||||
{
|
||||
return $this->execute(static::EXECUTE);
|
||||
}
|
||||
/**
|
||||
* @return array|bool|int|string|PDOStatement|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public function incrOrDecr(): array|bool|int|string|PDOStatement|null
|
||||
{
|
||||
return $this->execute(static::EXECUTE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $isInsert
|
||||
* @param bool $hasAutoIncrement
|
||||
* @return int|bool|array|string|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public function save($isInsert = TRUE, $hasAutoIncrement = null): int|bool|array|string|null
|
||||
{
|
||||
return $this->execute(static::EXECUTE, $isInsert, $hasAutoIncrement);
|
||||
}
|
||||
/**
|
||||
* @param bool $isInsert
|
||||
* @param mixed $hasAutoIncrement
|
||||
* @return int|bool|array|string|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public function save(bool $isInsert = TRUE, mixed $hasAutoIncrement = null): int|bool|array|string|null
|
||||
{
|
||||
return $this->execute(static::EXECUTE, $isInsert, $hasAutoIncrement);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return int|bool|array|string|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public function all(): int|bool|array|string|null
|
||||
{
|
||||
return $this->execute(static::FETCH_ALL);
|
||||
}
|
||||
/**
|
||||
* @return int|bool|array|string|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public function all(): int|bool|array|string|null
|
||||
{
|
||||
return $this->execute(static::FETCH_ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|bool|int|string|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public function one(): null|array|bool|int|string
|
||||
{
|
||||
return $this->execute(static::FETCH);
|
||||
}
|
||||
/**
|
||||
* @return array|bool|int|string|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public function one(): null|array|bool|int|string
|
||||
{
|
||||
return $this->execute(static::FETCH);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|bool|array|string|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public function fetchColumn(): int|bool|array|string|null
|
||||
{
|
||||
return $this->execute(static::FETCH_COLUMN);
|
||||
}
|
||||
/**
|
||||
* @return int|bool|array|string|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public function fetchColumn(): int|bool|array|string|null
|
||||
{
|
||||
return $this->execute(static::FETCH_COLUMN);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|bool|array|string|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public function rowCount(): int|bool|array|string|null
|
||||
{
|
||||
return $this->execute(static::ROW_COUNT);
|
||||
}
|
||||
/**
|
||||
* @return int|bool|array|string|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public function rowCount(): int|bool|array|string|null
|
||||
{
|
||||
return $this->execute(static::ROW_COUNT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|bool|array|string|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public function flush(): int|bool|array|string|null
|
||||
{
|
||||
return $this->execute(static::EXECUTE);
|
||||
}
|
||||
/**
|
||||
* @return int|bool|array|string|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public function flush(): int|bool|array|string|null
|
||||
{
|
||||
return $this->execute(static::EXECUTE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $type
|
||||
* @param null $isInsert
|
||||
* @param bool $hasAutoIncrement
|
||||
* @return int|bool|array|string|null
|
||||
* @throws Exception
|
||||
*/
|
||||
private function execute($type, $isInsert = null, $hasAutoIncrement = null): int|bool|array|string|null
|
||||
{
|
||||
try {
|
||||
if ($type === static::EXECUTE) {
|
||||
$result = $this->insert_or_change($isInsert, $hasAutoIncrement);
|
||||
} else {
|
||||
$result = $this->search($type);
|
||||
}
|
||||
if ($this->prepare) {
|
||||
$this->prepare->closeCursor();
|
||||
}
|
||||
return $result;
|
||||
} catch (\Throwable $exception) {
|
||||
return $this->addError($this->sql . '. error: ' . $exception->getMessage(), 'mysql');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param $type
|
||||
* @param null $isInsert
|
||||
* @param bool|null $hasAutoIncrement
|
||||
* @return int|bool|array|string|null
|
||||
* @throws Exception
|
||||
*/
|
||||
private function execute($type, $isInsert = null, mixed $hasAutoIncrement = null): int|bool|array|string|null
|
||||
{
|
||||
try {
|
||||
$time = microtime(true);
|
||||
if ($type === static::EXECUTE) {
|
||||
$result = $this->insert_or_change($isInsert, $hasAutoIncrement);
|
||||
} else {
|
||||
$result = $this->search($type);
|
||||
}
|
||||
if (microtime(true) - $time >= 0.02) {
|
||||
$this->warning('Mysql:' . Json::encode([$this->sql, $this->params]) . (microtime(true) - $time));
|
||||
}
|
||||
if ($this->prepare) {
|
||||
$this->prepare->closeCursor();
|
||||
}
|
||||
return $result;
|
||||
} catch (\Throwable $exception) {
|
||||
return $this->addError($this->sql . '. error: ' . $exception->getMessage(), 'mysql');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $type
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
private function search($type): mixed
|
||||
{
|
||||
if (($prepare = $this->prepare()) == false) {
|
||||
return false;
|
||||
}
|
||||
if ($type === static::FETCH_COLUMN) {
|
||||
$data = $prepare->fetchAll(PDO::FETCH_ASSOC);
|
||||
} else if ($type === static::ROW_COUNT) {
|
||||
$data = $prepare->rowCount();
|
||||
} else if ($type === static::FETCH_ALL) {
|
||||
$data = $prepare->fetchAll(PDO::FETCH_ASSOC);
|
||||
} else {
|
||||
$data = $prepare->fetch(PDO::FETCH_ASSOC);
|
||||
}
|
||||
$prepare->closeCursor();
|
||||
return $data;
|
||||
}
|
||||
/**
|
||||
* @param $type
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
private function search($type): mixed
|
||||
{
|
||||
if (($prepare = $this->prepare()) == false) {
|
||||
return false;
|
||||
}
|
||||
if ($type === static::FETCH_COLUMN) {
|
||||
$data = $prepare->fetchAll(PDO::FETCH_ASSOC);
|
||||
} else if ($type === static::ROW_COUNT) {
|
||||
$data = $prepare->rowCount();
|
||||
} else if ($type === static::FETCH_ALL) {
|
||||
$data = $prepare->fetchAll(PDO::FETCH_ASSOC);
|
||||
} else {
|
||||
$data = $prepare->fetch(PDO::FETCH_ASSOC);
|
||||
}
|
||||
$prepare->closeCursor();
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $isInsert
|
||||
* @param $hasAutoIncrement
|
||||
* @return bool|string|int
|
||||
* @throws Exception
|
||||
*/
|
||||
private function insert_or_change($isInsert, $hasAutoIncrement): bool|string|int
|
||||
{
|
||||
if (($result = $this->getPdoStatement()) === false) {
|
||||
return $result;
|
||||
}
|
||||
if ($isInsert === false || !$hasAutoIncrement) {
|
||||
return true;
|
||||
}
|
||||
if ($result == 0 && $hasAutoIncrement->isAutoIncrement()) {
|
||||
return $this->addError(static::DB_ERROR_MESSAGE, 'mysql');
|
||||
}
|
||||
return $result == 0 ? true : $result;
|
||||
}
|
||||
/**
|
||||
* @param $isInsert
|
||||
* @param $hasAutoIncrement
|
||||
* @return bool|string|int
|
||||
* @throws Exception
|
||||
*/
|
||||
private function insert_or_change($isInsert, $hasAutoIncrement): bool|string|int
|
||||
{
|
||||
if (($result = $this->getPdoStatement()) === false) {
|
||||
return $result;
|
||||
}
|
||||
if ($isInsert === false || !$hasAutoIncrement) {
|
||||
return true;
|
||||
}
|
||||
if ($result == 0 && $hasAutoIncrement->isAutoIncrement()) {
|
||||
return $this->addError(static::DB_ERROR_MESSAGE, 'mysql');
|
||||
}
|
||||
return $result == 0 ? true : $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 重新构建
|
||||
* @throws
|
||||
*/
|
||||
private function getPdoStatement(): bool|int
|
||||
{
|
||||
if (empty($this->sql)) {
|
||||
return $this->addError('no sql.', 'mysql');
|
||||
}
|
||||
if (!(($connect = $this->db->getConnect($this->sql)) instanceof PDO)) {
|
||||
return $this->addError('get client error.', 'mysql');
|
||||
}
|
||||
if (!(($prepare = $connect->prepare($this->sql)) instanceof PDOStatement)) {
|
||||
return $this->addError($this->errorMessage($prepare), 'mysql');
|
||||
}
|
||||
$result = $this->checkResponse($prepare, $connect);
|
||||
$prepare->closeCursor();
|
||||
return $result;
|
||||
}
|
||||
/**
|
||||
* 重新构建
|
||||
* @throws
|
||||
*/
|
||||
private function getPdoStatement(): bool|int
|
||||
{
|
||||
if (empty($this->sql)) {
|
||||
return $this->addError('no sql.', 'mysql');
|
||||
}
|
||||
if (!(($connect = $this->db->getConnect($this->sql)) instanceof PDO)) {
|
||||
return $this->addError('get client error.', 'mysql');
|
||||
}
|
||||
if (!(($prepare = $connect->prepare($this->sql)) instanceof PDOStatement)) {
|
||||
return $this->addError($this->errorMessage($prepare), 'mysql');
|
||||
}
|
||||
$result = $this->checkResponse($prepare, $connect);
|
||||
$prepare->closeCursor();
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $prepare
|
||||
* @return string
|
||||
*/
|
||||
private function errorMessage($prepare)
|
||||
{
|
||||
return $this->sql . ':' . ($prepare->errorInfo()[2] ?? static::DB_ERROR_MESSAGE);
|
||||
}
|
||||
/**
|
||||
* @param $prepare
|
||||
* @return string
|
||||
*/
|
||||
private function errorMessage($prepare): string
|
||||
{
|
||||
return $this->sql . ':' . ($prepare->errorInfo()[2] ?? static::DB_ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool|\PDOStatement
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function prepare(): bool|PDOStatement
|
||||
{
|
||||
if (!(($connect = $this->db->getConnect($this->sql)) instanceof PDO)) {
|
||||
return $this->addError('get client error.', 'mysql');
|
||||
}
|
||||
if (!(($prepare = $connect->query($this->sql)) instanceof PDOStatement)) {
|
||||
$error = $prepare->errorInfo()[2] ?? static::DB_ERROR_MESSAGE;
|
||||
return $this->addError($this->sql . ':' . $error, 'mysql');
|
||||
}
|
||||
return $prepare;
|
||||
}
|
||||
/**
|
||||
* @return bool|\PDOStatement
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function prepare(): bool|PDOStatement
|
||||
{
|
||||
if (!(($connect = $this->db->getConnect($this->sql)) instanceof PDO)) {
|
||||
return $this->addError('get client error.', 'mysql');
|
||||
}
|
||||
if (!(($prepare = $connect->query($this->sql)) instanceof PDOStatement)) {
|
||||
$error = $prepare->errorInfo()[2] ?? static::DB_ERROR_MESSAGE;
|
||||
return $this->addError($this->sql . ':' . $error, 'mysql');
|
||||
}
|
||||
return $prepare;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $prepare
|
||||
* @param $connect
|
||||
* @return bool|int
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function checkResponse($prepare, $connect)
|
||||
{
|
||||
$result = $prepare->execute($this->params);
|
||||
if ($result === false) {
|
||||
return $this->addError($connect->errorInfo()[2], 'mysql');
|
||||
}
|
||||
return (int)$connect->lastInsertId();
|
||||
}
|
||||
/**
|
||||
* @param $prepare
|
||||
* @param $connect
|
||||
* @return bool|int
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function checkResponse($prepare, $connect): bool|int
|
||||
{
|
||||
$result = $prepare->execute($this->params);
|
||||
if ($result === false) {
|
||||
return $this->addError($connect->errorInfo()[2], 'mysql');
|
||||
}
|
||||
return (int)$connect->lastInsertId();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $modelName
|
||||
* @return $this
|
||||
*/
|
||||
public function setModelName($modelName): static
|
||||
{
|
||||
$this->_modelName = $modelName;
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* @param $modelName
|
||||
* @return $this
|
||||
*/
|
||||
public function setModelName($modelName): static
|
||||
{
|
||||
$this->_modelName = $modelName;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getModelName(): string
|
||||
{
|
||||
return $this->_modelName;
|
||||
}
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getModelName(): string
|
||||
{
|
||||
return $this->_modelName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|bool|array|string|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public function delete(): int|bool|array|string|null
|
||||
{
|
||||
return $this->execute(static::EXECUTE);
|
||||
}
|
||||
/**
|
||||
* @return int|bool|array|string|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public function delete(): int|bool|array|string|null
|
||||
{
|
||||
return $this->execute(static::EXECUTE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null $scope
|
||||
* @param bool $insert
|
||||
* @return int|bool|array|string|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public function exec($scope = null, $insert = false): int|bool|array|string|null
|
||||
{
|
||||
return $this->execute(static::EXECUTE, $insert, $scope);
|
||||
}
|
||||
/**
|
||||
* @param null $scope
|
||||
* @param bool $insert
|
||||
* @return int|bool|array|string|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public function exec($scope = null, bool $insert = false): int|bool|array|string|null
|
||||
{
|
||||
return $this->execute(static::EXECUTE, $insert, $scope);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return $this
|
||||
*/
|
||||
public function bindValues(array $data = []): static
|
||||
{
|
||||
if (!is_array($this->params)) {
|
||||
$this->params = [];
|
||||
}
|
||||
if (!empty($data)) {
|
||||
$this->params = array_merge($this->params, $data);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* @param array $data
|
||||
* @return $this
|
||||
*/
|
||||
public function bindValues(array $data = []): static
|
||||
{
|
||||
if (!is_array($this->params)) {
|
||||
$this->params = [];
|
||||
}
|
||||
if (!empty($data)) {
|
||||
$this->params = array_merge($this->params, $data);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sql
|
||||
* @return $this
|
||||
* @throws Exception
|
||||
*/
|
||||
public function setSql($sql): static
|
||||
{
|
||||
$this->sql = $sql;
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* @param $sql
|
||||
* @return $this
|
||||
* @throws Exception
|
||||
*/
|
||||
public function setSql($sql): static
|
||||
{
|
||||
$this->sql = $sql;
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+258
-245
@@ -17,6 +17,7 @@ use JetBrains\PhpStorm\Pure;
|
||||
use PDO;
|
||||
use ReflectionException;
|
||||
use Snowflake\Abstracts\Component;
|
||||
use Snowflake\Abstracts\Config;
|
||||
use Snowflake\Event;
|
||||
use Snowflake\Exception\NotFindClassException;
|
||||
use Snowflake\Snowflake;
|
||||
@@ -27,290 +28,302 @@ use Snowflake\Snowflake;
|
||||
*/
|
||||
class Connection extends Component
|
||||
{
|
||||
const TRANSACTION_COMMIT = 'transaction::commit';
|
||||
const TRANSACTION_ROLLBACK = 'transaction::rollback';
|
||||
const TRANSACTION_COMMIT = 'transaction::commit';
|
||||
const TRANSACTION_ROLLBACK = 'transaction::rollback';
|
||||
|
||||
public string $id = 'db';
|
||||
public string $cds = '';
|
||||
public string $password = '';
|
||||
public string $username = '';
|
||||
public string $charset = 'utf-8';
|
||||
public string $tablePrefix = '';
|
||||
public string $id = 'db';
|
||||
public string $cds = '';
|
||||
public string $password = '';
|
||||
public string $username = '';
|
||||
public string $charset = 'utf-8';
|
||||
public string $tablePrefix = '';
|
||||
|
||||
public int $timeout = 1900;
|
||||
public string $database = '';
|
||||
|
||||
public int $maxNumber = 200;
|
||||
public int $timeout = 1900;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
* enable database cache
|
||||
*/
|
||||
public bool $enableCache = false;
|
||||
public string $cacheDriver = 'redis';
|
||||
public int $maxNumber = 30;
|
||||
public int $minNumber = 10;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*
|
||||
* @example [
|
||||
* 'cds' => 'mysql:dbname=dbname;host=127.0.0.1',
|
||||
* 'username' => 'root',
|
||||
* 'password' => 'root'
|
||||
* ]
|
||||
*/
|
||||
public array $slaveConfig = [];
|
||||
/**
|
||||
* @var bool
|
||||
* enable database cache
|
||||
*/
|
||||
public bool $enableCache = false;
|
||||
public string $cacheDriver = 'redis';
|
||||
|
||||
private ?Schema $_schema = null;
|
||||
/**
|
||||
* @var array
|
||||
*
|
||||
* @example [
|
||||
* 'cds' => 'mysql:dbname=dbname;host=127.0.0.1',
|
||||
* 'username' => 'root',
|
||||
* 'password' => 'root'
|
||||
* ]
|
||||
*/
|
||||
public array $slaveConfig = [];
|
||||
|
||||
private ?Schema $_schema = null;
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
Event::on(Event::SYSTEM_RESOURCE_CLEAN, [$this, 'disconnect']);
|
||||
Event::on(Event::SYSTEM_RESOURCE_RELEASES, [$this, 'clear_connection']);
|
||||
}
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
Event::on(Event::SYSTEM_RESOURCE_CLEAN, [$this, 'disconnect']);
|
||||
Event::on(Event::SYSTEM_RESOURCE_RELEASES, [$this, 'clear_connection']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function enablingTransactions()
|
||||
{
|
||||
if (!Db::transactionsActive()) {
|
||||
return;
|
||||
}
|
||||
$this->beginTransaction();
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function enablingTransactions()
|
||||
{
|
||||
if (!Db::transactionsActive()) {
|
||||
return;
|
||||
}
|
||||
$this->beginTransaction();
|
||||
|
||||
Event::on(Connection::TRANSACTION_COMMIT, [$this, 'commit'], false, true);
|
||||
Event::on(Connection::TRANSACTION_ROLLBACK, [$this, 'rollback'], false, true);
|
||||
}
|
||||
Event::on(Connection::TRANSACTION_COMMIT, [$this, 'commit'], false, true);
|
||||
Event::on(Connection::TRANSACTION_ROLLBACK, [$this, 'rollback'], false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null $sql
|
||||
* @return PDO
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getConnect($sql = NULL): PDO
|
||||
{
|
||||
return $this->getPdo($sql);
|
||||
}
|
||||
/**
|
||||
* @param null $sql
|
||||
* @return PDO
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getConnect($sql = NULL): PDO
|
||||
{
|
||||
return $this->getPdo($sql);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function fill()
|
||||
{
|
||||
$connections = $this->connections();
|
||||
$connections->initConnections('mysql', $this->cds, true, $this->maxNumber);
|
||||
if (!empty($this->slaveConfig)) {
|
||||
$connections->initConnections('mysql', $this->slaveConfig['cds'], false, $this->maxNumber);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function fill()
|
||||
{
|
||||
$connections = $this->connections();
|
||||
$pool = Config::get('databases.pool.max', 10);
|
||||
|
||||
$connections->initConnections('Mysql:' . $this->cds, true, $pool);
|
||||
if (!empty($this->slaveConfig) && $this->cds != $this->slaveConfig['cds']) {
|
||||
$connections->initConnections('Mysql:' . $this->slaveConfig['cds'], false, $pool);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $sql
|
||||
* @return PDO
|
||||
* @throws Exception
|
||||
*/
|
||||
private function getPdo($sql): PDO
|
||||
{
|
||||
if ($this->isWrite($sql)) {
|
||||
return $this->masterInstance();
|
||||
} else {
|
||||
return $this->slaveInstance();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param $sql
|
||||
* @return PDO
|
||||
* @throws Exception
|
||||
*/
|
||||
private function getPdo($sql): PDO
|
||||
{
|
||||
if ($this->isWrite($sql)) {
|
||||
return $this->masterInstance();
|
||||
} else {
|
||||
return $this->slaveInstance();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @throws ReflectionException
|
||||
* @throws NotFindClassException
|
||||
*/
|
||||
public function getSchema(): Schema
|
||||
{
|
||||
if ($this->_schema === null) {
|
||||
$this->_schema = Snowflake::createObject([
|
||||
'class' => Schema::class,
|
||||
'db' => $this
|
||||
]);
|
||||
}
|
||||
return $this->_schema;
|
||||
}
|
||||
/**
|
||||
* @return mixed
|
||||
* @throws ReflectionException
|
||||
* @throws NotFindClassException
|
||||
*/
|
||||
public function getSchema(): Schema
|
||||
{
|
||||
if ($this->_schema === null) {
|
||||
$this->_schema = Snowflake::createObject([
|
||||
'class' => Schema::class,
|
||||
'db' => $this
|
||||
]);
|
||||
}
|
||||
return $this->_schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sql
|
||||
* @return bool
|
||||
*/
|
||||
#[Pure] public function isWrite($sql): bool
|
||||
{
|
||||
if (empty($sql)) return false;
|
||||
if (str_starts_with(strtolower($sql), 'select')) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* @param $sql
|
||||
* @return bool
|
||||
*/
|
||||
#[Pure] public function isWrite($sql): bool
|
||||
{
|
||||
if (empty($sql)) return false;
|
||||
if (str_starts_with(strtolower($sql), 'select')) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getCacheDriver(): mixed
|
||||
{
|
||||
if (!$this->enableCache) {
|
||||
return null;
|
||||
}
|
||||
return Snowflake::app()->get($this->cacheDriver);
|
||||
}
|
||||
/**
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getCacheDriver(): mixed
|
||||
{
|
||||
if (!$this->enableCache) {
|
||||
return null;
|
||||
}
|
||||
return Snowflake::app()->get($this->cacheDriver);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return PDO
|
||||
* @throws Exception
|
||||
*/
|
||||
public function masterInstance(): PDO
|
||||
{
|
||||
return $this->connections()->get([
|
||||
'cds' => $this->cds, 'username' => $this->username, 'password' => $this->password
|
||||
], true);
|
||||
}
|
||||
/**
|
||||
* @return PDO
|
||||
* @throws Exception
|
||||
*/
|
||||
public function masterInstance(): PDO
|
||||
{
|
||||
return $this->connections()->get([
|
||||
'cds' => $this->cds,
|
||||
'username' => $this->username,
|
||||
'password' => $this->password,
|
||||
'database' => $this->database
|
||||
], true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return PDO
|
||||
* @throws Exception
|
||||
*/
|
||||
public function slaveInstance(): PDO
|
||||
{
|
||||
if (empty($this->slaveConfig) || Db::transactionsActive()) {
|
||||
return $this->masterInstance();
|
||||
}
|
||||
return $this->connections()->get($this->slaveConfig, false);
|
||||
}
|
||||
/**
|
||||
* @return PDO
|
||||
* @throws Exception
|
||||
*/
|
||||
public function slaveInstance(): PDO
|
||||
{
|
||||
if (empty($this->slaveConfig) || Db::transactionsActive()) {
|
||||
return $this->masterInstance();
|
||||
}
|
||||
if ($this->slaveConfig['cds'] == $this->cds) {
|
||||
return $this->masterInstance();
|
||||
}
|
||||
return $this->connections()->get($this->slaveConfig, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return \Snowflake\Pool\Connection
|
||||
* @throws Exception
|
||||
*/
|
||||
private function connections(): \Snowflake\Pool\Connection
|
||||
{
|
||||
return Snowflake::app()->getMysqlFromPool();
|
||||
}
|
||||
/**
|
||||
* @return \Snowflake\Pool\Connection
|
||||
* @throws Exception
|
||||
*/
|
||||
private function connections(): \Snowflake\Pool\Connection
|
||||
{
|
||||
return Snowflake::app()->getMysqlFromPool();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
* @throws Exception
|
||||
*/
|
||||
public function beginTransaction(): static
|
||||
{
|
||||
$this->connections()->beginTransaction($this->cds);
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* @return $this
|
||||
* @throws Exception
|
||||
*/
|
||||
public function beginTransaction(): static
|
||||
{
|
||||
$this->connections()->beginTransaction($this->cds);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this|bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function inTransaction(): bool|static
|
||||
{
|
||||
return $this->connections()->inTransaction($this->cds);
|
||||
}
|
||||
/**
|
||||
* @return $this|bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function inTransaction(): bool|static
|
||||
{
|
||||
return $this->connections()->inTransaction($this->cds);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
* 事务回滚
|
||||
*/
|
||||
public function rollback()
|
||||
{
|
||||
$this->connections()->rollback($this->cds);
|
||||
}
|
||||
/**
|
||||
* @throws Exception
|
||||
* 事务回滚
|
||||
*/
|
||||
public function rollback()
|
||||
{
|
||||
$this->connections()->rollback($this->cds);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
* 事务提交
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
$this->connections()->commit($this->cds);
|
||||
}
|
||||
/**
|
||||
* @throws Exception
|
||||
* 事务提交
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
$this->connections()->commit($this->cds);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sql
|
||||
* @return PDO
|
||||
* @throws Exception
|
||||
*/
|
||||
public function refresh($sql): PDO
|
||||
{
|
||||
if ($this->isWrite($sql)) {
|
||||
$instance = $this->masterInstance();
|
||||
} else {
|
||||
$instance = $this->slaveInstance();
|
||||
}
|
||||
return $instance;
|
||||
}
|
||||
/**
|
||||
* @param $sql
|
||||
* @return PDO
|
||||
* @throws Exception
|
||||
*/
|
||||
public function refresh($sql): PDO
|
||||
{
|
||||
if ($this->isWrite($sql)) {
|
||||
$instance = $this->masterInstance();
|
||||
} else {
|
||||
$instance = $this->slaveInstance();
|
||||
}
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sql
|
||||
* @param array $attributes
|
||||
* @return Command
|
||||
* @throws
|
||||
*/
|
||||
public function createCommand($sql = null, $attributes = []): Command
|
||||
{
|
||||
$command = new Command(['db' => $this, 'sql' => $sql]);
|
||||
return $command->bindValues($attributes);
|
||||
}
|
||||
/**
|
||||
* @param null $sql
|
||||
* @param string $dbname
|
||||
* @param array $attributes
|
||||
* @return Command
|
||||
* @throws Exception
|
||||
*/
|
||||
public function createCommand($sql = null, string $dbname = '', array $attributes = []): Command
|
||||
{
|
||||
$command = new Command(['db' => $this, 'sql' => $sql]);
|
||||
return $command->bindValues($attributes);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* 回收链接
|
||||
* @throws
|
||||
*/
|
||||
public function release()
|
||||
{
|
||||
$connections = $this->connections();
|
||||
/**
|
||||
*
|
||||
* 回收链接
|
||||
* @throws
|
||||
*/
|
||||
public function release()
|
||||
{
|
||||
$connections = $this->connections();
|
||||
|
||||
$connections->release($this->cds, true);
|
||||
$connections->release($this->slaveConfig['cds'], false);
|
||||
}
|
||||
$connections->release($this->cds, true);
|
||||
$connections->release($this->slaveConfig['cds'], false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function recovery()
|
||||
{
|
||||
$connections = $this->connections();
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function recovery()
|
||||
{
|
||||
$connections = $this->connections();
|
||||
|
||||
$connections->release($this->cds, true);
|
||||
$connections->release($this->slaveConfig['cds'], false);
|
||||
}
|
||||
$connections->release($this->cds, true);
|
||||
$connections->release($this->slaveConfig['cds'], false);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 回收链接
|
||||
* @throws
|
||||
*/
|
||||
public function clear_connection()
|
||||
{
|
||||
$connections = $this->connections();
|
||||
/**
|
||||
*
|
||||
* 回收链接
|
||||
* @throws
|
||||
*/
|
||||
public function clear_connection()
|
||||
{
|
||||
$connections = $this->connections();
|
||||
|
||||
$connections->release($this->cds, true);
|
||||
$connections->release($this->slaveConfig['cds'], false);
|
||||
}
|
||||
$connections->release($this->cds, true);
|
||||
$connections->release($this->slaveConfig['cds'], false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
$connections = $this->connections();
|
||||
$connections->disconnect($this->cds, true);
|
||||
$connections->disconnect($this->slaveConfig['cds'], false);
|
||||
}
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
$connections = $this->connections();
|
||||
$connections->disconnect($this->cds, true);
|
||||
$connections->disconnect($this->slaveConfig['cds'], false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,84 +25,92 @@ class DatabasesProviders extends Providers
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param Application $application
|
||||
* @throws Exception
|
||||
*/
|
||||
public function onImport(Application $application)
|
||||
{
|
||||
$application->set('db', $this);
|
||||
/**
|
||||
* @param Application $application
|
||||
* @throws Exception
|
||||
*/
|
||||
public function onImport(Application $application)
|
||||
{
|
||||
$application->set('db', $this);
|
||||
|
||||
Event::on(Event::SERVER_TASK_START, [$this, 'createPool']);
|
||||
Event::on(Event::SERVER_WORKER_START, [$this, 'createPool']);
|
||||
}
|
||||
Event::on(Event::SERVER_TASK_START, [$this, 'createPool']);
|
||||
Event::on(Event::SERVER_WORKER_START, [$this, 'createPool']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return Connection
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function get($name): Connection
|
||||
{
|
||||
$application = Snowflake::app();
|
||||
if ($application->has('databases.' . $name)) {
|
||||
return $application->get('databases.' . $name);
|
||||
}
|
||||
$config = $this->getConfig($name);
|
||||
return $application->set('databases.' . $name, [
|
||||
'class' => Connection::class,
|
||||
'id' => $config['id'],
|
||||
'cds' => $config['cds'],
|
||||
'username' => $config['username'],
|
||||
'password' => $config['password'],
|
||||
'tablePrefix' => $config['tablePrefix'],
|
||||
'maxNumber' => $config['maxNumber'],
|
||||
'charset' => $config['charset'] ?? 'utf8mb4',
|
||||
'slaveConfig' => $config['slaveConfig']
|
||||
]);
|
||||
}
|
||||
/**
|
||||
* @param $name
|
||||
* @return Connection
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function get($name): Connection
|
||||
{
|
||||
$application = Snowflake::app();
|
||||
if ($application->has('databases.' . $name)) {
|
||||
return $application->get('databases.' . $name);
|
||||
}
|
||||
$config = $this->getConfig($name);
|
||||
|
||||
$max = Config::get('databases.pool.max', 30);
|
||||
return $application->set('databases.' . $name, [
|
||||
'class' => Connection::class,
|
||||
'id' => $config['id'],
|
||||
'cds' => $config['cds'],
|
||||
'username' => $config['username'],
|
||||
'password' => $config['password'],
|
||||
'tablePrefix' => $config['tablePrefix'],
|
||||
'maxNumber' => $max,
|
||||
'database' => $config['database'],
|
||||
'charset' => $config['charset'] ?? 'utf8mb4',
|
||||
'slaveConfig' => $config['slaveConfig']
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function createPool()
|
||||
{
|
||||
$databases = Config::get('databases', []);
|
||||
if (empty($databases)) {
|
||||
return;
|
||||
}
|
||||
$application = Snowflake::app();
|
||||
foreach ($databases as $name => $database) {
|
||||
/** @var Connection $connection */
|
||||
$connection = $application->set('databases.' . $name, [
|
||||
'class' => Connection::class,
|
||||
'id' => $database['id'],
|
||||
'cds' => $database['cds'],
|
||||
'username' => $database['username'],
|
||||
'password' => $database['password'],
|
||||
'tablePrefix' => $database['tablePrefix'],
|
||||
'maxNumber' => $database['maxNumber'],
|
||||
'charset' => $database['charset'] ?? 'utf8mb4',
|
||||
'slaveConfig' => $database['slaveConfig']
|
||||
]);
|
||||
$connection->fill();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function createPool()
|
||||
{
|
||||
$databases = Config::get('databases.connections', []);
|
||||
if (empty($databases)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$max = Config::get('databases.pool', ['max' => 10, 'min' => 10]);
|
||||
|
||||
$application = Snowflake::app();
|
||||
foreach ($databases as $name => $database) {
|
||||
/** @var Connection $connection */
|
||||
$connection = $application->set('databases.' . $name, [
|
||||
'class' => Connection::class,
|
||||
'id' => $database['id'],
|
||||
'cds' => $database['cds'],
|
||||
'username' => $database['username'],
|
||||
'password' => $database['password'],
|
||||
'tablePrefix' => $database['tablePrefix'],
|
||||
'database' => $database['database'],
|
||||
'maxNumber' => $max['max'],
|
||||
'minNumber' => $max['min'],
|
||||
'charset' => $database['charset'] ?? 'utf8mb4',
|
||||
'slaveConfig' => $database['slaveConfig']
|
||||
]);
|
||||
$connection->fill();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return mixed
|
||||
* @throws ConfigException
|
||||
*/
|
||||
public function getConfig($name): mixed
|
||||
{
|
||||
return Config::get('databases.' . $name,null, true);
|
||||
}
|
||||
/**
|
||||
* @param $name
|
||||
* @return mixed
|
||||
* @throws ConfigException
|
||||
*/
|
||||
public function getConfig($name): mixed
|
||||
{
|
||||
return Config::get('databases.connections.' . $name, null, true);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+310
-290
@@ -11,7 +11,6 @@ namespace Database;
|
||||
|
||||
use Database\Traits\QueryTrait;
|
||||
use Exception;
|
||||
use HttpServer\Http\Context;
|
||||
use Snowflake\Event;
|
||||
use Snowflake\Snowflake;
|
||||
|
||||
@@ -21,309 +20,330 @@ use Snowflake\Snowflake;
|
||||
*/
|
||||
class Db implements ISqlBuilder
|
||||
{
|
||||
use QueryTrait;
|
||||
use QueryTrait;
|
||||
|
||||
|
||||
private static bool $_inTransaction = false;
|
||||
private static bool $_inTransaction = false;
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function transactionsActive(): bool
|
||||
{
|
||||
return static::$_inTransaction === true;
|
||||
}
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function transactionsActive(): bool
|
||||
{
|
||||
return static::$_inTransaction === true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function beginTransaction()
|
||||
{
|
||||
static::$_inTransaction = true;
|
||||
}
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function beginTransaction()
|
||||
{
|
||||
static::$_inTransaction = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function commit()
|
||||
{
|
||||
if (!static::transactionsActive()) {
|
||||
return;
|
||||
}
|
||||
Event::trigger(Connection::TRANSACTION_COMMIT);
|
||||
Event::offName(Connection::TRANSACTION_COMMIT);
|
||||
static::$_inTransaction = false;
|
||||
}
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function commit()
|
||||
{
|
||||
if (!static::transactionsActive()) {
|
||||
return;
|
||||
}
|
||||
Event::trigger(Connection::TRANSACTION_COMMIT);
|
||||
Event::offName(Connection::TRANSACTION_COMMIT);
|
||||
static::$_inTransaction = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function rollback()
|
||||
{
|
||||
if (!static::transactionsActive()) {
|
||||
return;
|
||||
}
|
||||
Event::trigger(Connection::TRANSACTION_ROLLBACK);
|
||||
Event::offName(Connection::TRANSACTION_ROLLBACK);
|
||||
static::$_inTransaction = false;
|
||||
}
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function rollback()
|
||||
{
|
||||
if (!static::transactionsActive()) {
|
||||
return;
|
||||
}
|
||||
Event::trigger(Connection::TRANSACTION_ROLLBACK);
|
||||
Event::offName(Connection::TRANSACTION_ROLLBACK);
|
||||
static::$_inTransaction = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $table
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function table($table): Db|static
|
||||
{
|
||||
$db = new Db();
|
||||
$db->from($table);
|
||||
return $db;
|
||||
}
|
||||
/**
|
||||
* @param $table
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function table($table): Db|static
|
||||
{
|
||||
$db = new Db();
|
||||
$db->from($table);
|
||||
return $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
* @param string $alias
|
||||
* @return string
|
||||
*/
|
||||
public static function any_value(string $column, string $alias = ''): string
|
||||
{
|
||||
if (empty($alias)) {
|
||||
$alias = $column . '_any_value';
|
||||
}
|
||||
return 'ANY_VALUE(' . $column . ') as ' . $alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Connection|null $db
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function get(Connection $db = NULL): mixed
|
||||
{
|
||||
if (empty($db)) {
|
||||
$db = Snowflake::app()->get('db');
|
||||
}
|
||||
return $db->createCommand(SqlBuilder::builder($this)->one())
|
||||
->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $column
|
||||
* @return string
|
||||
*/
|
||||
public static function raw($column): string
|
||||
{
|
||||
return '`' . $column . '`';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Connection|null $db
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function find(Connection $db = NULL): mixed
|
||||
{
|
||||
if (empty($db)) {
|
||||
$db = Snowflake::app()->get('db');
|
||||
}
|
||||
return $db->createCommand(SqlBuilder::builder($this)->all())
|
||||
->one();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Connection|NULL $db
|
||||
* @return bool|int
|
||||
* @throws Exception
|
||||
*/
|
||||
public function count(Connection $db = NULL): bool|int
|
||||
{
|
||||
if (empty($db)) {
|
||||
$db = Snowflake::app()->get('db');
|
||||
}
|
||||
return $db->createCommand(SqlBuilder::builder($this)->count())
|
||||
->exec();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Connection|NULL $db
|
||||
* @return bool|int
|
||||
* @throws Exception
|
||||
*/
|
||||
public function exists(Connection $db = NULL): bool|int
|
||||
{
|
||||
if (empty($db)) {
|
||||
$db = Snowflake::app()->get('db');
|
||||
}
|
||||
return $db->createCommand(SqlBuilder::builder($this)->one())
|
||||
->fetchColumn();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sql
|
||||
* @param array $attributes
|
||||
* @param Connection|null $db
|
||||
* @return array|bool|int|string|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function findAllBySql(string $sql, array $attributes = [], Connection $db = NULL): int|bool|array|string|null
|
||||
{
|
||||
return $db->createCommand($sql, $attributes)->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sql
|
||||
* @param array $attributes
|
||||
* @param Connection|NULL $db
|
||||
* @return array|mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function findBySql(string $sql, array $attributes = [], Connection $db = NULL): mixed
|
||||
{
|
||||
return $db->createCommand($sql, $attributes)->one();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
* @return array|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public function values(string $field): ?array
|
||||
{
|
||||
$data = $this->get();
|
||||
if (empty($data) || empty($field)) {
|
||||
return NULL;
|
||||
}
|
||||
$first = current($data);
|
||||
if (!isset($first[$field])) {
|
||||
return NULL;
|
||||
}
|
||||
return array_column($data, $field);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $field
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function value($field): mixed
|
||||
{
|
||||
$data = $this->find();
|
||||
if (!empty($field) && isset($data[$field])) {
|
||||
return $data[$field];
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null $db
|
||||
* @return bool|int
|
||||
* @throws Exception
|
||||
*/
|
||||
public function delete($db = null): bool|int
|
||||
{
|
||||
if (empty($db)) {
|
||||
$db = Snowflake::app()->get('db');
|
||||
}
|
||||
|
||||
$query = $db->getBuild()->builder($this);
|
||||
|
||||
return $db->createCommand($query)->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $table
|
||||
* @param null $db
|
||||
* @return bool|int
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function drop($table, $db = null): bool|int
|
||||
{
|
||||
if (empty($db)) {
|
||||
$db = Snowflake::app()->get('db');
|
||||
}
|
||||
return $db->createCommand('DROP TABLE ' . $table)->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $table
|
||||
* @param null $db
|
||||
* @return bool|int
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function truncate($table, $db = null): bool|int
|
||||
{
|
||||
|
||||
if (empty($db)) {
|
||||
$db = Snowflake::app()->get('db');
|
||||
}
|
||||
|
||||
return $db->createCommand('TRUNCATE ' . $table)->exec();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $table
|
||||
* @param Connection|NULL $db
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function showCreateSql($table, Connection $db = NULL): mixed
|
||||
{
|
||||
|
||||
if (empty($db)) {
|
||||
$db = Snowflake::app()->get('db');
|
||||
}
|
||||
/**
|
||||
* @param string $column
|
||||
* @param string $alias
|
||||
* @return string
|
||||
*/
|
||||
public static function any_value(string $column, string $alias = ''): string
|
||||
{
|
||||
if (empty($alias)) {
|
||||
$alias = $column . '_any_value';
|
||||
}
|
||||
return 'ANY_VALUE(' . $column . ') as ' . $alias;
|
||||
}
|
||||
|
||||
|
||||
if (empty($table)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $db->createCommand('SHOW CREATE TABLE ' . $table)->one();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $table
|
||||
* @param Connection|NULL $db
|
||||
* @return bool|int|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function desc($table, Connection $db = NULL): bool|int|null
|
||||
{
|
||||
if (empty($db)) {
|
||||
$db = Snowflake::app()->get('db');
|
||||
}
|
||||
|
||||
if (empty($table)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $db->createCommand('SHOW FULL FIELDS FROM ' . $table)->all();
|
||||
}
|
||||
/**
|
||||
* @param string $column
|
||||
* @return string
|
||||
*/
|
||||
public static function increment(string $column): string
|
||||
{
|
||||
return '+ ' . $column;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $table
|
||||
* @param Connection|NULL $db
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function show(string $table, Connection $db = NULL): mixed
|
||||
{
|
||||
if (empty($table)) {
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* @param string $column
|
||||
* @return string
|
||||
*/
|
||||
public static function decrement(string $column): string
|
||||
{
|
||||
return '- ' . $column;
|
||||
}
|
||||
|
||||
if (empty($db)) {
|
||||
$db = Snowflake::app()->get('db');
|
||||
}
|
||||
|
||||
$table = [' const TABLE = \'select * from %s where REFERENCED_TABLE_NAME=%s\';'];
|
||||
/**
|
||||
* @param Connection|null $db
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function get(Connection $db = NULL): mixed
|
||||
{
|
||||
if (empty($db)) {
|
||||
$db = Snowflake::app()->get('db');
|
||||
}
|
||||
return $db->createCommand(SqlBuilder::builder($this)->one())
|
||||
->all();
|
||||
}
|
||||
|
||||
return $db->createCommand((new Query())
|
||||
->select('*')
|
||||
->from('INFORMATION_SCHEMA.KEY_COLUMN_USAGE')
|
||||
->where(['REFERENCED_TABLE_NAME' => $table])
|
||||
->getSql())->one();
|
||||
}
|
||||
/**
|
||||
* @param $column
|
||||
* @return string
|
||||
*/
|
||||
public static function raw($column): string
|
||||
{
|
||||
return '`' . $column . '`';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Connection|null $db
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function find(Connection $db = NULL): mixed
|
||||
{
|
||||
if (empty($db)) {
|
||||
$db = Snowflake::app()->get('db');
|
||||
}
|
||||
return $db->createCommand(SqlBuilder::builder($this)->all())
|
||||
->one();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Connection|NULL $db
|
||||
* @return bool|int
|
||||
* @throws Exception
|
||||
*/
|
||||
public function count(Connection $db = NULL): bool|int
|
||||
{
|
||||
if (empty($db)) {
|
||||
$db = Snowflake::app()->get('db');
|
||||
}
|
||||
return $db->createCommand(SqlBuilder::builder($this)->count())
|
||||
->exec();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Connection|NULL $db
|
||||
* @return bool|int
|
||||
* @throws Exception
|
||||
*/
|
||||
public function exists(Connection $db = NULL): bool|int
|
||||
{
|
||||
if (empty($db)) {
|
||||
$db = Snowflake::app()->get('db');
|
||||
}
|
||||
return $db->createCommand(SqlBuilder::builder($this)->one())
|
||||
->fetchColumn();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sql
|
||||
* @param array $attributes
|
||||
* @param Connection|null $db
|
||||
* @return array|bool|int|string|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function findAllBySql(string $sql, array $attributes = [], Connection $db = NULL): int|bool|array|string|null
|
||||
{
|
||||
return $db->createCommand($sql, $db?->database, $attributes)->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sql
|
||||
* @param array $attributes
|
||||
* @param Connection|NULL $db
|
||||
* @return string|array|bool|int|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function findBySql(string $sql, array $attributes = [], Connection $db = NULL): string|array|bool|int|null
|
||||
{
|
||||
return $db->createCommand($sql, $db?->database, $attributes)->one();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
* @return array|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public function values(string $field): ?array
|
||||
{
|
||||
$data = $this->get();
|
||||
if (empty($data) || empty($field)) {
|
||||
return NULL;
|
||||
}
|
||||
$first = current($data);
|
||||
if (!isset($first[$field])) {
|
||||
return NULL;
|
||||
}
|
||||
return array_column($data, $field);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $field
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function value($field): mixed
|
||||
{
|
||||
$data = $this->find();
|
||||
if (!empty($field) && isset($data[$field])) {
|
||||
return $data[$field];
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null $db
|
||||
* @return bool|int
|
||||
* @throws Exception
|
||||
*/
|
||||
public function delete($db = null): bool|int
|
||||
{
|
||||
if (empty($db)) {
|
||||
$db = Snowflake::app()->get('db');
|
||||
}
|
||||
|
||||
$query = $db->getBuild()->builder($this);
|
||||
|
||||
return $db->createCommand($query)->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $table
|
||||
* @param null $db
|
||||
* @return bool|int
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function drop($table, $db = null): bool|int
|
||||
{
|
||||
if (empty($db)) {
|
||||
$db = Snowflake::app()->get('db');
|
||||
}
|
||||
return $db->createCommand('DROP TABLE `' . $db->database . '`.' . $table)->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $table
|
||||
* @param null $db
|
||||
* @return bool|int
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function truncate($table, $db = null): bool|int
|
||||
{
|
||||
|
||||
if (empty($db)) {
|
||||
$db = Snowflake::app()->get('db');
|
||||
}
|
||||
|
||||
return $db->createCommand('TRUNCATE `' . $db->database . '`.' . $table)->exec();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $table
|
||||
* @param Connection|NULL $db
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function showCreateSql($table, Connection $db = NULL): mixed
|
||||
{
|
||||
|
||||
if (empty($db)) {
|
||||
$db = Snowflake::app()->get('db');
|
||||
}
|
||||
|
||||
|
||||
if (empty($table)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $db->createCommand('SHOW CREATE TABLE `' . $db->database . '`.' . $table)->one();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $table
|
||||
* @param Connection|NULL $db
|
||||
* @return bool|int|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function desc($table, Connection $db = NULL): bool|int|null
|
||||
{
|
||||
if (empty($db)) {
|
||||
$db = Snowflake::app()->get('db');
|
||||
}
|
||||
|
||||
if (empty($table)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $db->createCommand('SHOW FULL FIELDS FROM `' . $db->database . '`.' . $table)->all();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $table
|
||||
* @param Connection|NULL $db
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function show(string $table, Connection $db = NULL): mixed
|
||||
{
|
||||
if (empty($table)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (empty($db)) {
|
||||
$db = Snowflake::app()->get('db');
|
||||
}
|
||||
|
||||
$table = [' const TABLE = \'select * from %s where REFERENCED_TABLE_NAME=%s\';'];
|
||||
|
||||
return $db->createCommand((new Query())
|
||||
->select('*')
|
||||
->from('INFORMATION_SCHEMA.KEY_COLUMN_USAGE')
|
||||
->where(['REFERENCED_TABLE_NAME' => $table])
|
||||
->getSql())->one();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+150
-152
@@ -7,8 +7,6 @@ namespace Database;
|
||||
use Closure;
|
||||
use Exception;
|
||||
use Snowflake\Abstracts\Component;
|
||||
use Snowflake\Event;
|
||||
use Swoole\Coroutine;
|
||||
|
||||
/**
|
||||
* Class Pagination
|
||||
@@ -17,186 +15,186 @@ use Swoole\Coroutine;
|
||||
class Pagination extends Component
|
||||
{
|
||||
|
||||
/** @var ActiveQuery */
|
||||
private ActiveQuery $activeQuery;
|
||||
/** @var ActiveQuery */
|
||||
private ActiveQuery $activeQuery;
|
||||
|
||||
/** @var int 从第几个开始查 */
|
||||
private int $_offset = 0;
|
||||
/** @var int 从第几个开始查 */
|
||||
private int $_offset = 0;
|
||||
|
||||
/** @var int 每页数量 */
|
||||
private int $_limit = 100;
|
||||
/** @var int 每页数量 */
|
||||
private int $_limit = 100;
|
||||
|
||||
/** @var int 最大查询数量 */
|
||||
private int $_max = 0;
|
||||
/** @var int 最大查询数量 */
|
||||
private int $_max = 0;
|
||||
|
||||
/** @var int 当前已查询数量 */
|
||||
private int $_length = 0;
|
||||
/** @var int 当前已查询数量 */
|
||||
private int $_length = 0;
|
||||
|
||||
/** @var Closure */
|
||||
private Closure $_callback;
|
||||
/** @var Closure */
|
||||
private Closure $_callback;
|
||||
|
||||
|
||||
/**
|
||||
* PaginationIteration constructor.
|
||||
* @param ActiveQuery $activeQuery
|
||||
* @param array $config
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct(ActiveQuery $activeQuery, array $config = [])
|
||||
{
|
||||
parent::__construct($config);
|
||||
$this->activeQuery = $activeQuery;
|
||||
}
|
||||
/**
|
||||
* PaginationIteration constructor.
|
||||
* @param ActiveQuery $activeQuery
|
||||
* @param array $config
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct(ActiveQuery $activeQuery, array $config = [])
|
||||
{
|
||||
parent::__construct($config);
|
||||
$this->activeQuery = $activeQuery;
|
||||
}
|
||||
|
||||
|
||||
public function clean()
|
||||
{
|
||||
unset($this->activeQuery, $this->_callback, $this->_group);
|
||||
$this->_offset = 0;
|
||||
$this->_limit = 100;
|
||||
$this->_max = 0;
|
||||
$this->_length = 0;;
|
||||
}
|
||||
public function clean()
|
||||
{
|
||||
unset($this->activeQuery, $this->_callback, $this->_group);
|
||||
$this->_offset = 0;
|
||||
$this->_limit = 100;
|
||||
$this->_max = 0;
|
||||
$this->_length = 0;;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* recover class by clone
|
||||
*/
|
||||
public function __clone()
|
||||
{
|
||||
$this->clean();
|
||||
}
|
||||
/**
|
||||
* recover class by clone
|
||||
*/
|
||||
public function __clone()
|
||||
{
|
||||
$this->clean();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array|Closure $callback
|
||||
* @throws Exception
|
||||
*/
|
||||
public function setCallback(array|Closure $callback)
|
||||
{
|
||||
if (!is_callable($callback, true)) {
|
||||
throw new Exception('非法回调函数~');
|
||||
}
|
||||
$this->_callback = $callback;
|
||||
}
|
||||
/**
|
||||
* @param array|Closure $callback
|
||||
* @throws Exception
|
||||
*/
|
||||
public function setCallback(array|Closure $callback)
|
||||
{
|
||||
if (!is_callable($callback, true)) {
|
||||
throw new Exception('非法回调函数~');
|
||||
}
|
||||
$this->_callback = $callback;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $number
|
||||
* @return Pagination
|
||||
*/
|
||||
public function setOffset(int $number): static
|
||||
{
|
||||
if ($number < 0) {
|
||||
$number = 0;
|
||||
}
|
||||
$this->_offset = $number;
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* @param int $number
|
||||
* @return Pagination
|
||||
*/
|
||||
public function setOffset(int $number): static
|
||||
{
|
||||
if ($number < 0) {
|
||||
$number = 0;
|
||||
}
|
||||
$this->_offset = $number;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $number
|
||||
* @return Pagination
|
||||
*/
|
||||
public function setLimit(int $number): static
|
||||
{
|
||||
if ($number < 1) {
|
||||
$number = 100;
|
||||
} else if ($number > 5000) {
|
||||
$number = 5000;
|
||||
}
|
||||
$this->_limit = $number;
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* @param int $number
|
||||
* @return Pagination
|
||||
*/
|
||||
public function setLimit(int $number): static
|
||||
{
|
||||
if ($number < 1) {
|
||||
$number = 100;
|
||||
} else if ($number > 5000) {
|
||||
$number = 5000;
|
||||
}
|
||||
$this->_limit = $number;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $number
|
||||
* @return Pagination
|
||||
*/
|
||||
public function setMax(int $number): static
|
||||
{
|
||||
if ($number < 0) {
|
||||
return $this;
|
||||
}
|
||||
$this->_max = $number;
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* @param int $number
|
||||
* @return Pagination
|
||||
*/
|
||||
public function setMax(int $number): static
|
||||
{
|
||||
if ($number < 0) {
|
||||
return $this;
|
||||
}
|
||||
$this->_max = $number;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $param
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function plunk($param = [])
|
||||
{
|
||||
$this->loop($param);
|
||||
}
|
||||
/**
|
||||
* @param array $param
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function plunk($param = [])
|
||||
{
|
||||
$this->loop($param);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 轮训
|
||||
* @param $param
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function loop($param): array
|
||||
{
|
||||
if ($this->_max > 0 && $this->_length >= $this->_max) {
|
||||
return $this->output();
|
||||
}
|
||||
[$length, $data] = $this->get();
|
||||
/**
|
||||
* 轮训
|
||||
* @param $param
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function loop($param): array
|
||||
{
|
||||
if ($this->_max > 0 && $this->_length >= $this->_max) {
|
||||
return $this->output();
|
||||
}
|
||||
[$length, $data] = $this->get();
|
||||
|
||||
$this->executed($data, $param);
|
||||
$this->executed($data, $param);
|
||||
|
||||
unset($data);
|
||||
if ($length < $this->_limit) {
|
||||
return $this->output();
|
||||
}
|
||||
return $this->loop($param);
|
||||
}
|
||||
unset($data);
|
||||
if ($length < $this->_limit) {
|
||||
return $this->output();
|
||||
}
|
||||
return $this->loop($param);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function output(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function output(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
* @param $param
|
||||
* @throws Exception
|
||||
*/
|
||||
private function executed($data, $param): void
|
||||
{
|
||||
try {
|
||||
call_user_func($this->_callback, $data, $param);
|
||||
} catch (\Throwable $exception) {
|
||||
$this->addError($exception, 'throwable');
|
||||
} finally {
|
||||
logger()->insert();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param $data
|
||||
* @param $param
|
||||
* @throws Exception
|
||||
*/
|
||||
private function executed($data, $param): void
|
||||
{
|
||||
try {
|
||||
call_user_func($this->_callback, $data, $param);
|
||||
} catch (\Throwable $exception) {
|
||||
$this->addError($exception, 'throwable');
|
||||
} finally {
|
||||
logger()->insert();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array|Collection
|
||||
*/
|
||||
private function get(): Collection|array
|
||||
{
|
||||
if ($this->_length + $this->_limit > $this->_max) {
|
||||
$this->_limit = $this->_length + $this->_limit - $this->_max;
|
||||
}
|
||||
$data = $this->activeQuery->limit($this->_offset, $this->_limit)->get();
|
||||
$this->_offset += $this->_limit;
|
||||
$this->_length += $data->size();
|
||||
return [$data->size(), $data];
|
||||
}
|
||||
/**
|
||||
* @return array|Collection
|
||||
*/
|
||||
private function get(): Collection|array
|
||||
{
|
||||
if ($this->_max > 0 && $this->_length + $this->_limit > $this->_max) {
|
||||
$this->_limit = $this->_length + $this->_limit - $this->_max;
|
||||
}
|
||||
$data = $this->activeQuery->limit($this->_offset, $this->_limit)->get();
|
||||
$this->_offset += $this->_limit;
|
||||
$this->_length += $data->size();
|
||||
return [$data->size(), $data];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+44
-22
@@ -52,19 +52,8 @@ class SqlBuilder extends Component
|
||||
public function update(array $attributes): bool|array
|
||||
{
|
||||
[$string, $array] = $this->builderParams($attributes);
|
||||
if (empty($string) || empty($array)) {
|
||||
return $this->addError('None data update.');
|
||||
}
|
||||
|
||||
$condition = $this->conditionToString();
|
||||
if (!empty($condition)) {
|
||||
$condition = ' WHERE ' . $condition;
|
||||
}
|
||||
|
||||
$update = 'UPDATE ' . $this->tableName() . ' SET ' . implode(',', $string) . $condition;
|
||||
$update .= $this->builderLimit($this->query);
|
||||
|
||||
return [$update, $array];
|
||||
return $this->__updateBuilder($string, $array);
|
||||
}
|
||||
|
||||
|
||||
@@ -74,14 +63,24 @@ class SqlBuilder extends Component
|
||||
* @return bool|array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function mathematics(array $attributes, $opera = '+'): bool|array
|
||||
public function mathematics(array $attributes, string $opera = '+'): bool|array
|
||||
{
|
||||
$string = $array = [];
|
||||
|
||||
$string = [];
|
||||
foreach ($attributes as $attribute => $value) {
|
||||
$string[] = $attribute . '=' . $attribute . $opera . $value;
|
||||
}
|
||||
return $this->__updateBuilder($string, []);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $string
|
||||
* @param array $params
|
||||
* @return array|bool
|
||||
* @throws Exception
|
||||
*/
|
||||
private function __updateBuilder(array $string, array $params): array|bool
|
||||
{
|
||||
if (empty($string)) {
|
||||
return $this->addError('None data update.');
|
||||
}
|
||||
@@ -92,9 +91,9 @@ class SqlBuilder extends Component
|
||||
}
|
||||
|
||||
$update = 'UPDATE ' . $this->tableName() . ' SET ' . implode(',', $string) . $condition;
|
||||
$update .= $this->builderLimit($this->query);
|
||||
$update .= $this->builderLimit($this->query, false);
|
||||
|
||||
return [$update, []];
|
||||
return [$update, $params];
|
||||
}
|
||||
|
||||
|
||||
@@ -104,7 +103,7 @@ class SqlBuilder extends Component
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function insert(array $attributes, $isBatch = false): array
|
||||
public function insert(array $attributes, bool $isBatch = false): array
|
||||
{
|
||||
$update = sprintf('INSERT INTO %s', $this->tableName());
|
||||
if ($isBatch === false) {
|
||||
@@ -156,16 +155,39 @@ class SqlBuilder extends Component
|
||||
* @return array[]
|
||||
* a=:b,
|
||||
*/
|
||||
private function builderParams(array $attributes, bool $isInsert = false, $params = [], $order = 0): array
|
||||
#[Pure] private function builderParams(array $attributes, bool $isInsert = false, array $params = [], int $order = 0): array
|
||||
{
|
||||
$keys = [];
|
||||
foreach ($attributes as $key => $value) {
|
||||
if ($isInsert === true) {
|
||||
$keys[] = ':' . $key . $order;
|
||||
$params[$key . $order] = $value;
|
||||
} else {
|
||||
$keys[] = $key . '=:' . $key . $order;
|
||||
[$keys, $params] = $this->resolveParams($key, $value, $order, $params, $keys);
|
||||
}
|
||||
}
|
||||
return [$keys, $params];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param int $order
|
||||
* @param array $params
|
||||
* @param array $keys
|
||||
* @return array
|
||||
*/
|
||||
private function resolveParams(string $key, mixed $value, int $order, array $params, array $keys): array
|
||||
{
|
||||
if (
|
||||
str_starts_with($value, '+ ') ||
|
||||
str_starts_with($value, '- ')
|
||||
) {
|
||||
$keys[] = $key . '=' . $key . ' ' . $value;
|
||||
} else {
|
||||
$params[$key . $order] = $value;
|
||||
$keys[] = $key . '=:' . $key . $order;
|
||||
}
|
||||
return [$keys, $params];
|
||||
}
|
||||
@@ -226,7 +248,7 @@ class SqlBuilder extends Component
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
private function _prefix($hasOrder = false): string
|
||||
private function _prefix(bool $hasOrder = false): string
|
||||
{
|
||||
$select = '';
|
||||
if (!empty($this->query->from)) {
|
||||
@@ -286,7 +308,7 @@ class SqlBuilder extends Component
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
public function get($isCount = false): string
|
||||
public function get(bool $isCount = false): string
|
||||
{
|
||||
if ($isCount === false) {
|
||||
return $this->all();
|
||||
|
||||
@@ -104,14 +104,15 @@ trait Builder
|
||||
|
||||
/**
|
||||
* @param ActiveQuery|Query $query
|
||||
* @param bool $hasLimit
|
||||
* @return string
|
||||
*/
|
||||
#[Pure] private function builderLimit(ActiveQuery|Query $query): string
|
||||
#[Pure] private function builderLimit(ActiveQuery|Query $query, bool $hasLimit = true): string
|
||||
{
|
||||
if (!is_numeric($query->limit) || $query->limit < 1) {
|
||||
return "";
|
||||
}
|
||||
if ($query->offset !== null) {
|
||||
if ($query->offset !== null && $hasLimit) {
|
||||
return ' LIMIT ' . $query->offset . ',' . $query->limit;
|
||||
}
|
||||
return ' LIMIT ' . $query->limit;
|
||||
|
||||
@@ -16,7 +16,6 @@ use Database\ActiveRecord;
|
||||
use Database\Condition\MathematicsCondition;
|
||||
use Database\Query;
|
||||
use Exception;
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use ReflectionException;
|
||||
use Snowflake\Exception\NotFindClassException;
|
||||
use Snowflake\Snowflake;
|
||||
|
||||
+3
-3
@@ -12,9 +12,6 @@ namespace Gii;
|
||||
use Database\Connection;
|
||||
use Database\Db;
|
||||
use Exception;
|
||||
use JetBrains\PhpStorm\ArrayShape;
|
||||
|
||||
use Snowflake\Abstracts\Config;
|
||||
use Snowflake\Abstracts\Input;
|
||||
use Snowflake\Exception\ComponentException;
|
||||
use Snowflake\Exception\ConfigException;
|
||||
@@ -42,6 +39,9 @@ class Gii
|
||||
public string $controllerNamespace = 'App\\Http\\Controllers\\';
|
||||
|
||||
|
||||
public static array $createSqls = [];
|
||||
|
||||
|
||||
public array $keyword = [
|
||||
'ADD', 'ALL', 'ALTER', 'AND', 'AS', 'ASC', 'ASENSITIVE', 'BEFORE', 'BETWEEN', 'BIGINT', 'BINARY', 'BLOB', 'BOTH', 'BY', 'CALL', 'CASCADE', 'CASE', 'CHANGE', 'CHAR', 'CHARACTER', 'CHECK', 'COLLATE', 'COLUMN', 'CONDITION', 'CONNECTION', 'CONSTRAINT', 'CONTINUE', 'CONVERT', 'CREATE', 'CROSS', 'CURRENT_DATE', 'CURRENT_TIME', 'CURRENT_TIMESTAMP', 'CURRENT_USER', 'CURSOR', 'DATABASE', 'DATABASES', 'DAY_HOUR', 'DAY_MICROSECOND', 'DAY_MINUTE', 'DAY_SECOND', 'DEC', 'DECIMAL', 'DECLARE', 'DEFAULT', 'DELAYED', 'DELETE', 'DESC', 'DESCRIBE', 'DETERMINISTIC', 'DISTINCT', 'DISTINCTROW', 'DIV', 'DOUBLE', 'DROP', 'DUAL', 'EACH', 'ELSE', 'ELSEIF', 'ENCLOSED', 'ESCAPED', 'EXISTS', 'EXIT', 'EXPLAIN', 'FALSE', 'FETCH', 'FLOAT', 'FLOAT4', 'FLOAT8', 'FOR', 'FORCE', 'FOREIGN', 'FROM', 'FULLTEXT', 'GOTO', 'GRANT', 'GROUP', 'HAVING', 'HIGH_PRIORITY', 'HOUR_MICROSECOND', 'HOUR_MINUTE', 'HOUR_SECOND', 'IF', 'IGNORE', 'IN', 'INDEX', 'INFILE', 'INNER', 'INOUT', 'INSENSITIVE', 'INSERT', 'INT', 'INT1', 'INT2', 'INT3', 'INT4', 'INT8', 'INTEGER', 'INTERVAL', 'INTO', 'IS', 'ITERATE', 'JOIN', 'KEY', 'KEYS', 'KILL', 'LABEL', 'LEADING', 'LEAVE', 'LEFT', 'LIKE', 'LIMIT', 'LINEAR', 'LINES', 'LOAD', 'LOCALTIME', 'LOCALTIMESTAMP', 'LOCK', 'LONG', 'LONGBLOB', 'LONGTEXT', 'LOOP', 'LOW_PRIORITY', 'MATCH', 'MEDIUMBLOB', 'MEDIUMINT', 'MEDIUMTEXT', 'MIDDLEINT', 'MINUTE_MICROSECOND', 'MINUTE_SECOND', 'MOD', 'MODIFIES', 'NATURAL', 'NOT', 'NO_WRITE_TO_BINLOG', 'NULL', 'NUMERIC', 'ON', 'OPTIMIZE', 'OPTION', 'OPTIONALLY', 'OR', 'ORDER', 'OUT', 'OUTER', 'OUTFILE', 'PRECISION', 'PRIMARY', 'PROCEDURE', 'PURGE', 'RAID0', 'RANGE', 'READ', 'READS', 'REAL', 'REFERENCES', 'REGEXP', 'RELEASE', 'RENAME', 'REPEAT', 'REPLACE', 'REQUIRE', 'RESTRICT', 'RETURN', 'REVOKE', 'RIGHT', 'RLIKE', 'SCHEMA', 'SCHEMAS', 'SECOND_MICROSECOND', 'SELECT', 'SENSITIVE', 'SEPARATOR', 'SET', 'SHOW', 'SMALLINT', 'SPATIAL', 'SPECIFIC', 'SQL', 'SQLEXCEPTION', 'SQLSTATE', 'SQLWARNING', 'SQL_BIG_RESULT', 'SQL_CALC_FOUND_ROWS', 'SQL_SMALL_RESULT', 'SSL', 'STARTING', 'STRAIGHT_JOIN', 'TABLE', 'TERMINATED', 'THEN', 'TINYBLOB', 'TINYINT', 'TINYTEXT', 'TO', 'TRAILING', 'TRIGGER', 'TRUE', 'UNDO', 'UNION', 'UNIQUE', 'UNLOCK', 'UNSIGNED', 'UPDATE', 'USAGE', 'USE', 'USING', 'UTC_DATE', 'UTC_TIME', 'UTC_TIMESTAMP', 'VALUES', 'VARBINARY', 'VARCHAR', 'VARCHARACTER', 'VARYING', 'WHEN', 'WHERE', 'WHILE', 'WITH', 'WRITE', 'X509', 'XOR', 'YEAR_MONTH', 'ZEROFILL'
|
||||
];
|
||||
|
||||
+20
-12
@@ -22,12 +22,12 @@ class GiiModel extends GiiBase
|
||||
public ?array $fields;
|
||||
|
||||
/**
|
||||
* ModelFile constructor.
|
||||
* @param $classFileName
|
||||
* @param $tableName
|
||||
* @param $visible
|
||||
* @param $res
|
||||
* @param $fields
|
||||
* GiiModel constructor.
|
||||
* @param string $classFileName
|
||||
* @param string $tableName
|
||||
* @param array $visible
|
||||
* @param array $res
|
||||
* @param array $fields
|
||||
*/
|
||||
public function __construct(string $classFileName, string $tableName, array $visible, array $res, array $fields)
|
||||
{
|
||||
@@ -308,16 +308,20 @@ use Database\ActiveRecord;
|
||||
if (empty($data)) return '';
|
||||
$string = [];
|
||||
foreach ($data as $key => $_val) {
|
||||
if (is_string($key) && str_contains($key, ',')) {
|
||||
$key = '[' . $key . ']';
|
||||
if (in_array($_val[0][1], $this->type['float'])) {
|
||||
$e_x = explode(',', $key);
|
||||
$key = '\'round\' => ' . $e_x[1] . ', \'maxLength\' => ' . ((int)$e_x[0] + 1);
|
||||
} else if (is_string($key) && str_contains($key, ',')) {
|
||||
$key = '\'between\' => [' . $key . ']';
|
||||
} else {
|
||||
$key = '\'maxLength\' => ' . $key;
|
||||
}
|
||||
if (count($_val) == 1) {
|
||||
[$typeRule, $type, $rule, $field] = current($_val);
|
||||
$_tmp = '
|
||||
[\'' . $field . '\', \'' . ($type == 'enum' ? 'enum' : 'maxLength') . '\' => ' . $key . ']';
|
||||
[\'' . $_val[0][3] . '\', ' . ($_val[0][1] == 'enum' ? '\'enum\' => ' . $key : $key) . ']';
|
||||
} else {
|
||||
$_tmp = '
|
||||
[[\'' . implode('\', \'', array_column($_val, 3)) . '\'], \'maxLength\' => ' . $key . ']';
|
||||
[[\'' . implode('\', \'', array_column($_val, 3)) . '\'], ' . $key . ']';
|
||||
}
|
||||
$string[] = $_tmp;
|
||||
}
|
||||
@@ -412,6 +416,10 @@ use Database\ActiveRecord;
|
||||
*/
|
||||
private function setCreateSql($table): string
|
||||
{
|
||||
if (isset(Gii::$createSqls[$table])) {
|
||||
return Gii::$createSqls[$table];
|
||||
}
|
||||
|
||||
$text = Db::showCreateSql($table, $this->db)['Create Table'] ?? '';
|
||||
|
||||
$_tmp = [];
|
||||
@@ -419,7 +427,7 @@ use Database\ActiveRecord;
|
||||
$_tmp[] = '// ' . $val;
|
||||
}
|
||||
|
||||
return implode(PHP_EOL, $_tmp);
|
||||
return Gii::$createSqls[$table] = implode(PHP_EOL, $_tmp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -6,20 +6,10 @@ namespace HttpServer\Abstracts;
|
||||
|
||||
use Database\Connection;
|
||||
use Exception;
|
||||
use HttpServer\Http\Request;
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
use PHPMailer\PHPMailer\SMTP;
|
||||
use ReflectionException;
|
||||
use Snowflake\Abstracts\Config;
|
||||
use Snowflake\Core\Json;
|
||||
use Snowflake\Error\LoggerProcess;
|
||||
use Snowflake\Event;
|
||||
use Snowflake\Exception\ComponentException;
|
||||
use Snowflake\Exception\ConfigException;
|
||||
use Snowflake\Exception\NotFindClassException;
|
||||
use Snowflake\Snowflake;
|
||||
use Swoole\Process;
|
||||
use Swoole\Server;
|
||||
|
||||
|
||||
/**
|
||||
@@ -30,116 +20,89 @@ abstract class Callback extends HttpService
|
||||
{
|
||||
|
||||
|
||||
|
||||
const EVENT_ERROR = 'WORKER:ERROR';
|
||||
const EVENT_STOP = 'WORKER:STOP';
|
||||
const EVENT_EXIT = 'WORKER:EXIT';
|
||||
const EVENT_ERROR = 'WORKER:ERROR';
|
||||
const EVENT_STOP = 'WORKER:STOP';
|
||||
const EVENT_EXIT = 'WORKER:EXIT';
|
||||
|
||||
|
||||
private array $_MESSAGE = [
|
||||
self::EVENT_ERROR => 'The server error. at No.',
|
||||
self::EVENT_STOP => 'The server stop. at No.',
|
||||
self::EVENT_EXIT => 'The server exit. at No.',
|
||||
];
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return PHPMailer
|
||||
* @throws \PHPMailer\PHPMailer\Exception
|
||||
* @throws ConfigException
|
||||
*/
|
||||
private function createEmail(): PHPMailer
|
||||
{
|
||||
$mail = new PHPMailer(true);
|
||||
$mail->SMTPDebug = SMTP::DEBUG_SERVER; // Enable verbose debug output
|
||||
$mail->isSMTP(); // Send using SMTP
|
||||
$mail->Host = Config::get('email.host'); // Set the SMTP server to send through
|
||||
$mail->SMTPAuth = true; // Enable SMTP authentication
|
||||
$mail->Debugoutput = false; // Enable SMTP authentication
|
||||
$mail->CharSet = "UTF8"; // Enable SMTP authentication
|
||||
$mail->Username = Config::get('email.username'); // SMTP username
|
||||
$mail->Password = Config::get('email.password'); // SMTP password
|
||||
$mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS; // Enable TLS encryption; `PHPMailer::ENCRYPTION_SMTPS` encouraged
|
||||
$mail->Port = Config::get('email.port'); // TCP port to connect to, use 465 for `PHPMailer::ENCRYPTION_SMTPS` above
|
||||
$mail->setFrom(Config::get('email.send.address'), Config::get('email.send.nickname'));
|
||||
return $mail;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $fd
|
||||
* @param $data
|
||||
* @param $reID
|
||||
* @return Request
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function _request($fd, $data, $reID): Request
|
||||
{
|
||||
return Request::createListenRequest($fd, $data, $reID);
|
||||
}
|
||||
private array $_MESSAGE = [
|
||||
self::EVENT_ERROR => 'The server error. at No.',
|
||||
self::EVENT_STOP => 'The server stop. at No.',
|
||||
self::EVENT_EXIT => 'The server exit. at No.',
|
||||
];
|
||||
|
||||
/**
|
||||
* @param $messageContent
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function system_mail($messageContent)
|
||||
{
|
||||
try {
|
||||
$email = Config::get('email');
|
||||
if (empty($email) || !$email['enable']) {
|
||||
return;
|
||||
}
|
||||
$transport = (new \Swift_SmtpTransport($email['host'], $email['465']))
|
||||
->setUsername($email['username'])
|
||||
->setPassword($email['password']);
|
||||
$mailer = new \Swift_Mailer($transport);
|
||||
protected function system_mail($messageContent)
|
||||
{
|
||||
try {
|
||||
$email = Config::get('email');
|
||||
if (empty($email) || !$email['enable']) {
|
||||
return;
|
||||
}
|
||||
$transport = (new \Swift_SmtpTransport($email['host'], $email['465']))
|
||||
->setUsername($email['username'])
|
||||
->setPassword($email['password']);
|
||||
$mailer = new \Swift_Mailer($transport);
|
||||
|
||||
// Create a message
|
||||
$message = (new \Swift_Message('Wonderful Subject'))
|
||||
->setFrom([$email['send']['address'] => $email['send']['nickname']])
|
||||
->setBody('Here is the message itself');
|
||||
// Create a message
|
||||
$message = (new \Swift_Message('Wonderful Subject'))
|
||||
->setFrom([$email['send']['address'] => $email['send']['nickname']])
|
||||
->setBody('Here is the message itself');
|
||||
|
||||
foreach ($email['receive'] as $item) {
|
||||
$message->setTo([$item['address'], $item['address'] => $item['nickname']]);
|
||||
}
|
||||
$mailer->send($messageContent);
|
||||
} catch (\Throwable $e) {
|
||||
$this->addError($e, 'email');
|
||||
}
|
||||
}
|
||||
foreach ($email['receive'] as $item) {
|
||||
$message->setTo([$item['address'], $item['address'] => $item['nickname']]);
|
||||
}
|
||||
$mailer->send($messageContent);
|
||||
} catch (\Throwable $e) {
|
||||
$this->addError($e, 'email');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function clearMysqlClient()
|
||||
{
|
||||
$databases = Config::get('databases', []);
|
||||
if (empty($databases)) {
|
||||
return;
|
||||
}
|
||||
$application = Snowflake::app();
|
||||
foreach ($databases as $name => $database) {
|
||||
/** @var Connection $connection */
|
||||
$connection = $application->get('databases.' . $name, false);
|
||||
if (empty($connection)) {
|
||||
continue;
|
||||
}
|
||||
$connection->disconnect();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function clearMysqlClient()
|
||||
{
|
||||
$databases = Config::get('databases', []);
|
||||
if (empty($databases)) {
|
||||
return;
|
||||
}
|
||||
$application = Snowflake::app();
|
||||
foreach ($databases as $name => $database) {
|
||||
/** @var Connection $connection */
|
||||
$connection = $application->get('databases.' . $name, false);
|
||||
if (empty($connection)) {
|
||||
continue;
|
||||
}
|
||||
$connection->disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function clearRedisClient()
|
||||
{
|
||||
$redis = Snowflake::app()->getRedis();
|
||||
$redis->destroy();
|
||||
}
|
||||
/**
|
||||
* @param array $clientInfo
|
||||
* @param string $event
|
||||
* @return string
|
||||
*/
|
||||
protected function getName(array $clientInfo, string $event): string
|
||||
{
|
||||
return 'listen ' . $clientInfo['server_port'] . ' ' . Event::SERVER_CONNECT;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function clearRedisClient()
|
||||
{
|
||||
$redis = Snowflake::app()->getRedis();
|
||||
$redis->destroy();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ abstract class HttpService extends Component
|
||||
* @param string $category
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function write($message, $category = 'app')
|
||||
protected function write($message, string $category = 'app')
|
||||
{
|
||||
$logger = Snowflake::app()->getLogger();
|
||||
$logger->write($message, $category);
|
||||
|
||||
@@ -7,7 +7,6 @@ namespace HttpServer\Events;
|
||||
use Exception;
|
||||
use HttpServer\Abstracts\Callback;
|
||||
use Snowflake\Event;
|
||||
use Snowflake\Snowflake;
|
||||
use Swoole\Server;
|
||||
|
||||
/**
|
||||
@@ -19,33 +18,20 @@ class OnClose extends Callback
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param Server $server
|
||||
* @param int $fd
|
||||
* @throws Exception
|
||||
*/
|
||||
public function onHandler(Server $server, int $fd)
|
||||
{
|
||||
try {
|
||||
defer(fn() => fire(Event::SYSTEM_RESOURCE_RELEASES));
|
||||
$clientInfo = $server->getClientInfo($fd);
|
||||
if (!Event::exists(($name = $this->getName($clientInfo)))) {
|
||||
return;
|
||||
}
|
||||
Event::trigger($name, [$server, $fd]);
|
||||
} catch (\Throwable $exception) {
|
||||
$this->addError($exception, 'throwable');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param Server $server
|
||||
* @param int $fd
|
||||
* @throws Exception
|
||||
*/
|
||||
public function onHandler(Server $server, int $fd)
|
||||
{
|
||||
try {
|
||||
defer(fn() => fire(Event::SYSTEM_RESOURCE_RELEASES));
|
||||
|
||||
|
||||
/**
|
||||
* @param $server_port
|
||||
* @return string
|
||||
*/
|
||||
private function getName($server_port): string
|
||||
{
|
||||
return 'listen ' . $server_port['server_port'] . ' ' . Event::SERVER_CLIENT_CLOSE;
|
||||
}
|
||||
Event::trigger(Event::SERVER_CLIENT_CLOSE, [$server, $fd]);
|
||||
} catch (\Throwable $exception) {
|
||||
$this->addError($exception, 'throwable');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,26 +26,18 @@ class OnConnect extends Callback
|
||||
public function onHandler(Server $server, int $fd, int $reactorId)
|
||||
{
|
||||
try {
|
||||
defer(fn() => fire(Event::SYSTEM_RESOURCE_RELEASES));
|
||||
|
||||
defer(fn() => fire(Event::SYSTEM_RESOURCE_RELEASES));
|
||||
if (($clientInfo = $server->getClientInfo($fd, $reactorId)) === false) {
|
||||
return;
|
||||
}
|
||||
fire($this->getName($clientInfo), [$server, $fd, $reactorId]);
|
||||
if (isset($clientInfo['websocket_status'])) {
|
||||
return;
|
||||
}
|
||||
fire($this->getName($clientInfo, Event::SERVER_CONNECT), [$server, $fd, $reactorId]);
|
||||
} catch (\Throwable $throwable) {
|
||||
$this->addError($throwable, 'connect');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $clientInfo
|
||||
* @return string
|
||||
*/
|
||||
private function getName(array $clientInfo): string
|
||||
{
|
||||
return 'listen ' . $clientInfo['server_port'] . ' ' . Event::SERVER_CONNECT;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ use HttpServer\Http\HttpHeaders;
|
||||
use HttpServer\Http\HttpParams;
|
||||
use HttpServer\Http\Request;
|
||||
use HttpServer\Http\Response;
|
||||
use HttpServer\Route\Router;
|
||||
use ReflectionException;
|
||||
use Snowflake\Core\ArrayAccess;
|
||||
use Snowflake\Event;
|
||||
@@ -29,130 +30,106 @@ class OnHandshake extends Callback
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param $request
|
||||
* @param $response
|
||||
* @throws Exception
|
||||
*/
|
||||
private function resolveParse($request, $response)
|
||||
{
|
||||
/** @var Server $server */
|
||||
$secWebSocketKey = $request->header['sec-websocket-key'];
|
||||
$patten = '#^[+/0-9A-Za-z]{21}[AQgw]==$#';
|
||||
if (0 === preg_match($patten, $secWebSocketKey) || 16 !== strlen(base64_decode($secWebSocketKey))) {
|
||||
throw new Exception('protocol error.', 500);
|
||||
}
|
||||
$key = base64_encode(sha1($request->header['sec-websocket-key'] . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', TRUE));
|
||||
$headers = [
|
||||
'Upgrade' => 'websocket',
|
||||
'Connection' => 'Upgrade',
|
||||
'Sec-websocket-Accept' => $key,
|
||||
'Sec-websocket-Version' => '13',
|
||||
];
|
||||
if (isset($request->header['sec-websocket-protocol'])) {
|
||||
$headers['Sec-websocket-Protocol'] = $request->header['sec-websocket-protocol'];
|
||||
}
|
||||
foreach ($headers as $key => $val) {
|
||||
$response->header($key, $val);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param $request
|
||||
* @param $response
|
||||
* @return Router
|
||||
* @throws Exception
|
||||
*/
|
||||
private function _protocol($request, $response): Router
|
||||
{
|
||||
/** @var Server $server */
|
||||
$secWebSocketKey = $request->header['sec-websocket-key'];
|
||||
$patten = '#^[+/0-9A-Za-z]{21}[AQgw]==$#';
|
||||
if (0 === preg_match($patten, $secWebSocketKey) || 16 !== strlen(base64_decode($secWebSocketKey))) {
|
||||
throw new Exception('protocol error.', 500);
|
||||
}
|
||||
$key = base64_encode(sha1($request->header['sec-websocket-key'] . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', TRUE));
|
||||
$headers = [
|
||||
'Upgrade' => 'websocket',
|
||||
'Connection' => 'Upgrade',
|
||||
'Sec-websocket-Accept' => $key,
|
||||
'Sec-websocket-Version' => '13',
|
||||
];
|
||||
if (isset($request->header['sec-websocket-protocol'])) {
|
||||
$headers['Sec-websocket-Protocol'] = $request->header['sec-websocket-protocol'];
|
||||
}
|
||||
foreach ($headers as $key => $val) {
|
||||
$response->header($key, $val);
|
||||
}
|
||||
return Snowflake::app()->getRouter();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param SResponse $response
|
||||
* @param int $code
|
||||
* @return false
|
||||
*/
|
||||
private function disconnect(SResponse $response, $code = 500): bool
|
||||
{
|
||||
$server = Snowflake::getWebSocket();
|
||||
if (!$server->exist($response->fd)) {
|
||||
return false;
|
||||
}
|
||||
$response->status($code);
|
||||
$response->end();
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* @param SResponse $response
|
||||
* @param int $code
|
||||
* @return void
|
||||
*/
|
||||
private function disconnect(SResponse $response, int $code = 500): void
|
||||
{
|
||||
$server = Snowflake::getWebSocket();
|
||||
if (!$server->isEstablished($response->fd)) {
|
||||
return;
|
||||
}
|
||||
$response->status($code);
|
||||
$response->end();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $response
|
||||
* @param int $code
|
||||
* @return false
|
||||
*/
|
||||
private function connect($response, $code = 101): bool
|
||||
{
|
||||
$response->status($code);
|
||||
$response->end();
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* @param SRequest $request
|
||||
* @param SResponse $response
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function onHandler(SRequest $request, SResponse $response): void
|
||||
{
|
||||
try {
|
||||
defer(fn() => fire(Event::SYSTEM_RESOURCE_RELEASES));
|
||||
|
||||
$router = $this->_protocol($request, $response);
|
||||
|
||||
[$sRequest, $sResponse] = $this->sRequest($request, $response);
|
||||
|
||||
if (($node = $router->find_path($sRequest)) !== null) {
|
||||
$node->dispatch($sRequest, $sResponse);
|
||||
} else {
|
||||
$this->disconnect($response, 404);
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
$this->addError($exception, 'throwable');
|
||||
$response->status(500);
|
||||
$response->end($exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param SRequest $request
|
||||
* @param SResponse $response
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function onHandler(SRequest $request, SResponse $response): void
|
||||
{
|
||||
try {
|
||||
defer(fn() => fire(Event::SYSTEM_RESOURCE_RELEASES));
|
||||
/**
|
||||
* @param $request
|
||||
* @param SResponse $response
|
||||
* @return array
|
||||
* @throws NotFindClassException
|
||||
* @throws ReflectionException
|
||||
* @throws Exception
|
||||
*/
|
||||
private function sRequest($request, SResponse $response): array
|
||||
{
|
||||
/** @var Request $sRequest */
|
||||
$sRequest = Request::create($request);
|
||||
$sRequest->uri = '/' . Socket::HANDSHAKE . '::event';
|
||||
|
||||
$this->execute($request, $response);
|
||||
} catch (\Throwable $exception) {
|
||||
$this->addError($exception, 'throwable');
|
||||
$response->status(500);
|
||||
$response->end($exception->getMessage());
|
||||
}
|
||||
}
|
||||
$sRequest->headers = new HttpHeaders(ArrayAccess::merge($request->server, $request->header));
|
||||
|
||||
$sRequest->headers->replace('request_method', 'sw::socket');
|
||||
$sRequest->headers->replace('request_uri', $sRequest->uri);
|
||||
|
||||
/**
|
||||
* @param SRequest $request
|
||||
* @param SResponse $response
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
private function execute(SRequest $request, SResponse $response): mixed
|
||||
{
|
||||
$this->resolveParse($request, $response);
|
||||
$sRequest->params = new HttpParams([], $request->get, []);
|
||||
|
||||
$router = Snowflake::app()->getRouter();
|
||||
$sRequest->parseUri();
|
||||
|
||||
[$sRequest, $sResponse] = $this->sRequest($request, $response);
|
||||
|
||||
if (($node = $router->find_path($sRequest)) !== null) {
|
||||
return $node->dispatch($sRequest, $sResponse);
|
||||
}
|
||||
return $this->disconnect($response, 404);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $request
|
||||
* @param SResponse $response
|
||||
* @return array
|
||||
* @throws NotFindClassException
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
private function sRequest($request, SResponse $response): array
|
||||
{
|
||||
/** @var Request $sRequest */
|
||||
$sRequest = Request::create($request);
|
||||
$sRequest->uri = '/' . Socket::HANDSHAKE . '::event';
|
||||
|
||||
$sRequest->headers = new HttpHeaders(ArrayAccess::merge($request->server, $request->header));
|
||||
|
||||
$sRequest->headers->replace('request_method', 'sw::socket');
|
||||
$sRequest->headers->replace('request_uri', $sRequest->uri);
|
||||
|
||||
$sRequest->params = new HttpParams([], $request->get, []);
|
||||
|
||||
$sRequest->parseUri();
|
||||
|
||||
return [$sRequest, Response::create($response)];
|
||||
}
|
||||
return [$sRequest, Response::create($response)];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ class OnManagerStop extends Callback
|
||||
{
|
||||
|
||||
/**
|
||||
* @param $server
|
||||
* @param Server $server
|
||||
* @throws Exception
|
||||
*/
|
||||
public function onHandler(Server $server)
|
||||
|
||||
@@ -4,22 +4,8 @@ declare(strict_types=1);
|
||||
namespace HttpServer\Events;
|
||||
|
||||
|
||||
use Annotation\Route\Socket;
|
||||
use Exception;
|
||||
use HttpServer\Abstracts\Callback;
|
||||
use HttpServer\Http\Context;
|
||||
use HttpServer\Http\HttpHeaders;
|
||||
use HttpServer\Http\HttpParams;
|
||||
use HttpServer\Http\Request;
|
||||
use ReflectionException;
|
||||
use Snowflake\Abstracts\Config;
|
||||
use Snowflake\Core\Json;
|
||||
use Snowflake\Event;
|
||||
use Snowflake\Exception\ComponentException;
|
||||
use Snowflake\Exception\ConfigException;
|
||||
use Snowflake\Exception\NotFindClassException;
|
||||
use Snowflake\Snowflake;
|
||||
use Swoole\Coroutine;
|
||||
use Swoole\WebSocket\Frame;
|
||||
use Swoole\WebSocket\Server;
|
||||
|
||||
@@ -30,38 +16,29 @@ use Swoole\WebSocket\Server;
|
||||
class OnMessage extends Callback
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Server $server
|
||||
* @param Frame $frame
|
||||
* @throws
|
||||
*/
|
||||
public function onHandler(Server $server, Frame $frame)
|
||||
{
|
||||
try {
|
||||
defer(fn() => fire(Event::SYSTEM_RESOURCE_RELEASES));
|
||||
if ($frame->opcode === 0x08) {
|
||||
return;
|
||||
}
|
||||
Event::trigger($this->getName($server, $frame), [$frame, $server]);
|
||||
} catch (\Throwable $exception) {
|
||||
$this->addError($exception, 'websocket');
|
||||
if (!swoole()->isEstablished($frame->fd)) {
|
||||
return;
|
||||
}
|
||||
$server->send($frame->fd, $exception->getMessage());
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param Server $server
|
||||
* @param Frame $frame
|
||||
* @throws
|
||||
*/
|
||||
public function onHandler(Server $server, Frame $frame)
|
||||
{
|
||||
try {
|
||||
defer(fn() => fire(Event::SYSTEM_RESOURCE_RELEASES));
|
||||
if ($frame->opcode === 0x08) {
|
||||
return;
|
||||
}
|
||||
|
||||
$clientInfo = $this->getName($server->getClientInfo($frame->fd), Event::SERVER_MESSAGE);
|
||||
|
||||
/**
|
||||
* @param $clientInfo
|
||||
* @return string
|
||||
*/
|
||||
private function getName(Server $server, Frame $frame): string
|
||||
{
|
||||
$clientInfo = $server->getClientInfo($frame->fd);
|
||||
|
||||
return 'listen ' . $clientInfo['server_port'] . ' ' . Event::SERVER_MESSAGE;
|
||||
}
|
||||
Event::trigger($clientInfo, [$frame, $server]);
|
||||
} catch (\Throwable $exception) {
|
||||
$this->addError($exception, 'websocket');
|
||||
if (!swoole()->isEstablished($frame->fd)) {
|
||||
return;
|
||||
}
|
||||
$server->send($frame->fd, $exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ use Exception;
|
||||
use HttpServer\Abstracts\Callback;
|
||||
use Snowflake\Core\Json;
|
||||
use Snowflake\Event;
|
||||
use Snowflake\Snowflake;
|
||||
use Swoole\Server;
|
||||
|
||||
/**
|
||||
@@ -18,45 +17,30 @@ use Swoole\Server;
|
||||
class OnPacket extends Callback
|
||||
{
|
||||
|
||||
|
||||
public int $port = 0;
|
||||
|
||||
|
||||
public string $host = '';
|
||||
|
||||
|
||||
/**
|
||||
* @param Server $server
|
||||
* @param $data
|
||||
* @param $clientInfo
|
||||
* @param string $data
|
||||
* @param array $client
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function onHandler(Server $server, string $data, array $clientInfo): mixed
|
||||
public function onHandler(Server $server, string $data, array $client): mixed
|
||||
{
|
||||
[$host, $port] = [$clientInfo['address'], $clientInfo['port']];
|
||||
try {
|
||||
defer(fn() => fire(Event::SYSTEM_RESOURCE_RELEASES));
|
||||
defer(fn() => fire(Event::SYSTEM_RESOURCE_RELEASES));
|
||||
|
||||
$request = $this->_request($clientInfo, $server, $data);
|
||||
$client['server_port'] = $client['port'];
|
||||
$name = $this->getName($client, Event::SERVER_RECEIVE);
|
||||
|
||||
$router = Snowflake::app()->getRouter();
|
||||
if (($node = $router->find_path($request)) === null) {
|
||||
return $server->sendto($host, $port, Json::encode(['state' => 404]));
|
||||
}
|
||||
|
||||
$dispatch = $node->dispatch();
|
||||
if (!is_string($dispatch)) $dispatch = Json::encode($dispatch);
|
||||
if (empty($dispatch)) {
|
||||
$dispatch = Json::encode(['state' => 0, 'message' => 'ok']);
|
||||
}
|
||||
return $server->sendto($host, $port, $dispatch);
|
||||
$result = Event::trigger($name, [$server, $data, $client]);
|
||||
} catch (\Throwable $exception) {
|
||||
$this->addError($exception, 'packet');
|
||||
|
||||
$response = Json::encode(['state' => 500, 'message' => $exception->getMessage()]);
|
||||
|
||||
return $server->sendto($host, $port, $response);
|
||||
$result = logger()->exception($exception);
|
||||
} finally {
|
||||
if (is_array($result) || is_object($result)) {
|
||||
$result = Json::encode($result);
|
||||
}
|
||||
$sendData = [$client['address'], $client['port'], $result];
|
||||
return $server->sendto(...$sendData);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,12 +7,9 @@ namespace HttpServer\Events;
|
||||
use Exception;
|
||||
use HttpServer\Abstracts\Callback;
|
||||
use HttpServer\Http\Request;
|
||||
use HttpServer\Route\Router;
|
||||
use ReflectionException;
|
||||
use Snowflake\Abstracts\Config;
|
||||
use Snowflake\Core\Json;
|
||||
use Snowflake\Event;
|
||||
use Snowflake\Exception\NotFindClassException;
|
||||
use Snowflake\Snowflake;
|
||||
use Swoole\Server;
|
||||
|
||||
/**
|
||||
@@ -22,56 +19,36 @@ use Swoole\Server;
|
||||
class OnReceive extends Callback
|
||||
{
|
||||
|
||||
public int $port = 0;
|
||||
/**
|
||||
* @param Server $server
|
||||
* @param int $fd
|
||||
* @param int $reID
|
||||
* @param string $data
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function onHandler(Server $server, int $fd, int $reID, string $data): mixed
|
||||
{
|
||||
try {
|
||||
defer(fn() => fire(Event::SYSTEM_RESOURCE_RELEASES));
|
||||
|
||||
$client = $server->getClientInfo($fd, $reID);
|
||||
$name = $this->getName($client, Event::SERVER_RECEIVE);
|
||||
|
||||
public string $host = '';
|
||||
|
||||
|
||||
private Router $router;
|
||||
|
||||
|
||||
public function init()
|
||||
{
|
||||
$this->router = Snowflake::app()->getRouter();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Server $server
|
||||
* @param int $fd
|
||||
* @param int $reID
|
||||
* @param string $data
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function onHandler(Server $server, int $fd, int $reID, string $data): mixed
|
||||
{
|
||||
try {
|
||||
defer(fn() => fire(Event::SYSTEM_RESOURCE_RELEASES));
|
||||
|
||||
$request = $this->_request($fd, $data, $reID);
|
||||
if (($node = $this->router->find_path($request)) === null) {
|
||||
return $server->send($fd, Json::encode(['state' => 404]));
|
||||
}
|
||||
$dispatch = $node->dispatch();
|
||||
if (!is_string($dispatch)) $dispatch = Json::encode($dispatch);
|
||||
if (empty($dispatch)) {
|
||||
$dispatch = Json::encode(['state' => 0, 'message' => 'ok']);
|
||||
}
|
||||
if ($server->exist($fd)) {
|
||||
return $server->send($fd, $dispatch);
|
||||
}
|
||||
return $dispatch;
|
||||
} catch (\Throwable $exception) {
|
||||
$this->addError($exception, 'receive');
|
||||
$error = ['state' => 500, 'message' => $exception->getMessage()];
|
||||
if ($server->exist($fd)) {
|
||||
return $server->send($fd, Json::encode($error));
|
||||
}
|
||||
return Json::encode($error);
|
||||
}
|
||||
}
|
||||
if (Config::get('rpc.port', 0) == $client['server_port']) {
|
||||
$result = router()->find_path(Request::rpcRequest($fd, $data, $reID))?->dispatch();
|
||||
} else {
|
||||
$result = Event::trigger($name, [$server, $data, $client]);
|
||||
}
|
||||
if (is_array($result) || is_object($result)) {
|
||||
$result = Json::encode($result);
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
$result = logger()->exception($exception);
|
||||
} finally {
|
||||
return $server->send($fd, $result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ use Snowflake\Snowflake;
|
||||
use Swoole\Error;
|
||||
use Swoole\Http\Request;
|
||||
use Swoole\Http\Response;
|
||||
use Swoole\Http\Status;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Class OnRequest
|
||||
@@ -50,7 +52,7 @@ class OnRequest extends Callback
|
||||
public function onHandler(Request $request, Response $response): mixed
|
||||
{
|
||||
try {
|
||||
defer(fn() => fire(Event::SYSTEM_RESOURCE_RELEASES));
|
||||
defer(fn() => fire(Event::SYSTEM_RESOURCE_RELEASES));
|
||||
|
||||
/** @var HResponse $response */
|
||||
[$request, $response] = OnRequest::createContext($request, $response);
|
||||
@@ -59,7 +61,7 @@ class OnRequest extends Callback
|
||||
return $response->close(404);
|
||||
}
|
||||
return $this->router->dispatch();
|
||||
} catch (ExitException | Error | \Throwable $exception) {
|
||||
} catch (ExitException | Error | Throwable $exception) {
|
||||
$this->addError($exception, 'throwable');
|
||||
return $this->sendErrorMessage($request, $response, $exception);
|
||||
}
|
||||
@@ -81,11 +83,11 @@ class OnRequest extends Callback
|
||||
/**
|
||||
* @param $sRequest
|
||||
* @param $sResponse
|
||||
* @param $exception
|
||||
* @param Throwable $exception
|
||||
* @return bool|string
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function sendErrorMessage($sRequest, $sResponse, $exception): bool|string
|
||||
protected function sendErrorMessage($sRequest, $sResponse, Throwable $exception): bool|string
|
||||
{
|
||||
$this->addError($exception, 'throwable');
|
||||
if ($sResponse instanceof Response) {
|
||||
@@ -95,6 +97,7 @@ class OnRequest extends Callback
|
||||
$headers = $sRequest->headers->get('access-control-request-headers');
|
||||
$methods = $sRequest->headers->get('access-control-request-method');
|
||||
|
||||
/** @var HResponse $sResponse */
|
||||
$sResponse->addHeader('Access-Control-Allow-Origin', '*');
|
||||
$sResponse->addHeader('Access-Control-Allow-Headers', $headers);
|
||||
$sResponse->addHeader('Access-Control-Request-Method', $methods);
|
||||
|
||||
@@ -102,7 +102,7 @@ class OnTask extends Callback
|
||||
private function runTaskHandler($data): ?array
|
||||
{
|
||||
try {
|
||||
defer(fn() => fire(Event::SYSTEM_RESOURCE_RELEASES));
|
||||
defer(fn() => fire(Event::SYSTEM_RESOURCE_CLEAN));
|
||||
|
||||
$serialize = $this->before($data);
|
||||
if ($serialize === null) {
|
||||
|
||||
@@ -6,9 +6,7 @@ namespace HttpServer\Events;
|
||||
|
||||
use Exception;
|
||||
use HttpServer\Abstracts\Callback;
|
||||
use Snowflake\Error\Logger;
|
||||
use Snowflake\Event;
|
||||
use Snowflake\Snowflake;
|
||||
use Swoole\Timer;
|
||||
|
||||
/**
|
||||
|
||||
@@ -23,7 +23,7 @@ use HttpServer\IInterface\IFormatter;
|
||||
class HtmlFormatter extends HttpService implements IFormatter
|
||||
{
|
||||
|
||||
public $data;
|
||||
public mixed $data;
|
||||
|
||||
/** @var Response */
|
||||
public Response $status;
|
||||
|
||||
+17
-32
@@ -415,10 +415,10 @@ class Request extends HttpService
|
||||
{
|
||||
$mainstay = sprintf("%.6f", microtime(true)); // 带毫秒的时间戳
|
||||
|
||||
$timestamp = floor($mainstay); // 时间戳
|
||||
$milliseconds = round(($mainstay - $timestamp) * 1000); // 毫秒
|
||||
$timestamp = floatval($mainstay); // 时间戳
|
||||
$milliseconds = round(($mainstay - $timestamp) * 1000); // 毫秒
|
||||
|
||||
$datetime = date("Y-m-d H:i:s", $timestamp) . '.' . $milliseconds;
|
||||
$datetime = date("Y-m-d H:i:s", (int)$timestamp) . '.' . $milliseconds;
|
||||
|
||||
$tmp = [
|
||||
'[Debug ' . $datetime . '] ',
|
||||
@@ -427,7 +427,6 @@ class Request extends HttpService
|
||||
'`' . $this->headers->getHeader('user-agent') . '`',
|
||||
$this->getRuntime()
|
||||
];
|
||||
|
||||
return implode(' ', $tmp);
|
||||
}
|
||||
|
||||
@@ -466,7 +465,7 @@ class Request extends HttpService
|
||||
$sRequest->params->setPosts($request->post ?? []);
|
||||
}
|
||||
|
||||
$sRequest->headers = new HttpHeaders(ArrayAccess::merge($request->server, $request->header));
|
||||
$sRequest->headers = new HttpHeaders(array_merge($request->server, $request->header));
|
||||
$sRequest->uri = $sRequest->headers->get('request_uri');
|
||||
|
||||
$sRequest->parseUri();
|
||||
@@ -476,11 +475,11 @@ class Request extends HttpService
|
||||
|
||||
/**
|
||||
* @param $frame
|
||||
* @param $route
|
||||
* @param string $route
|
||||
* @param string $event
|
||||
* @return Request
|
||||
*/
|
||||
public static function socketQuery($frame, $event = Socket::MESSAGE, $route = 'event'): Request
|
||||
public static function socketQuery($frame, string $event = Socket::MESSAGE, string $route = 'event'): Request
|
||||
{
|
||||
$sRequest = new Request();
|
||||
$sRequest->fd = $frame->fd;
|
||||
@@ -500,10 +499,11 @@ class Request extends HttpService
|
||||
* @param $fd
|
||||
* @param $data
|
||||
* @param int $reID
|
||||
* @return Request
|
||||
* @return mixed|null
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function createListenRequest($fd, $data, $reID = 0): Request
|
||||
public static function rpcRequest($fd, $data, int $reID = 0): Request|null
|
||||
{
|
||||
$sRequest = new Request();
|
||||
|
||||
@@ -514,28 +514,11 @@ class Request extends HttpService
|
||||
$sRequest->params = new HttpParams($data, [], []);
|
||||
|
||||
$port = $sRequest->clientInfo['server_port'];
|
||||
|
||||
$sRequest->headers->setRequestUri('add-port-listen/port_' . $port);
|
||||
$sRequest->headers->setRequestMethod(self::HTTP_LISTEN);
|
||||
|
||||
$sRequest->checkIsRpcClient()->parseUri();
|
||||
|
||||
return Context::setContext('request', $sRequest);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
private function checkIsRpcClient(): static
|
||||
{
|
||||
$port = $this->clientInfo['server_port'];
|
||||
if (($rpc = Config::get('rpc.port', 0)) !== $port) {
|
||||
return $this;
|
||||
return null;
|
||||
}
|
||||
|
||||
[$cmd, $repeat, $body] = explode("\n", $this->params->getBody());
|
||||
[$cmd, $repeat, $body] = explode("\n", $sRequest->params->getBody());
|
||||
if (is_null($body) || is_null($cmd) || !empty($repeat)) {
|
||||
throw new Exception('Protocol format error.');
|
||||
}
|
||||
@@ -543,10 +526,12 @@ class Request extends HttpService
|
||||
if (is_string($body) && is_null($data = Json::decode($body))) {
|
||||
throw new Exception('Protocol format error.');
|
||||
}
|
||||
$this->headers->setRequestUri('rpc/p' . $rpc . '/' . ltrim($cmd, '/'));
|
||||
$this->headers->setRequestMethod(Request::HTTP_CMD);
|
||||
|
||||
return $this;
|
||||
$sRequest->params->setPosts($data);
|
||||
$sRequest->headers->setRequestUri('rpc/p' . $rpc . '/' . ltrim($cmd, '/'));
|
||||
$sRequest->headers->setRequestMethod(Request::HTTP_CMD);
|
||||
|
||||
return Context::setContext('request', $sRequest);
|
||||
}
|
||||
|
||||
|
||||
@@ -556,7 +541,7 @@ class Request extends HttpService
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
private static function getClientInfo($fd, $re = 0): mixed
|
||||
private static function getClientInfo($fd, int $re = 0): mixed
|
||||
{
|
||||
$server = Snowflake::app()->getSwoole();
|
||||
if (!is_array($fd)) {
|
||||
|
||||
+299
-300
@@ -20,6 +20,7 @@ use Snowflake\Core\Json;
|
||||
use Snowflake\Snowflake;
|
||||
use Swoole\Http\Response as SResponse;
|
||||
use Swoole\Http2\Response as S2Response;
|
||||
use Swoole\WebSocket\Server;
|
||||
|
||||
/**
|
||||
* Class Response
|
||||
@@ -28,340 +29,338 @@ use Swoole\Http2\Response as S2Response;
|
||||
class Response extends HttpService
|
||||
{
|
||||
|
||||
const JSON = 'json';
|
||||
const XML = 'xml';
|
||||
const HTML = 'html';
|
||||
const JSON = 'json';
|
||||
const XML = 'xml';
|
||||
const HTML = 'html';
|
||||
|
||||
/** @var ?string */
|
||||
public ?string $format = null;
|
||||
/** @var ?string */
|
||||
public ?string $format = null;
|
||||
|
||||
/** @var int */
|
||||
public int $statusCode = 200;
|
||||
/** @var int */
|
||||
public int $statusCode = 200;
|
||||
|
||||
public ?SResponse $response = null;
|
||||
public bool $isWebSocket = false;
|
||||
public array $headers = [];
|
||||
public ?SResponse $response = null;
|
||||
public bool $isWebSocket = false;
|
||||
public array $headers = [];
|
||||
|
||||
private float $startTime = 0;
|
||||
private float $startTime = 0;
|
||||
|
||||
private array $_format_maps = [
|
||||
self::JSON => JsonFormatter::class,
|
||||
self::XML => XmlFormatter::class,
|
||||
self::HTML => HtmlFormatter::class
|
||||
];
|
||||
private array $_format_maps = [
|
||||
self::JSON => JsonFormatter::class,
|
||||
self::XML => XmlFormatter::class,
|
||||
self::HTML => HtmlFormatter::class
|
||||
];
|
||||
|
||||
public int $fd = 0;
|
||||
public int $fd = 0;
|
||||
|
||||
/**
|
||||
* @param $format
|
||||
* @return $this
|
||||
*/
|
||||
public function setFormat($format): static
|
||||
{
|
||||
$this->format = $format;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理无用数据
|
||||
*/
|
||||
public function clear(): void
|
||||
{
|
||||
$this->fd = 0;
|
||||
$this->isWebSocket = false;
|
||||
$this->format = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getContentType(): string
|
||||
{
|
||||
if ($this->format == null || $this->format == static::JSON) {
|
||||
return 'application/json;charset=utf-8';
|
||||
} else if ($this->format == static::XML) {
|
||||
return 'application/xml;charset=utf-8';
|
||||
} else {
|
||||
return 'text/html;charset=utf-8';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $content
|
||||
* @return mixed
|
||||
*/
|
||||
public function toHtml($content): mixed
|
||||
{
|
||||
$this->format = self::HTML;
|
||||
return $content;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $content
|
||||
* @return mixed
|
||||
*/
|
||||
public function toJson($content): mixed
|
||||
{
|
||||
$this->format = self::JSON;
|
||||
return $content;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $content
|
||||
* @return mixed
|
||||
*/
|
||||
public function toXml($content): mixed
|
||||
{
|
||||
$this->format = self::XML;
|
||||
return $content;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function sender(): mixed
|
||||
{
|
||||
return $this->send(func_get_args());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param $value
|
||||
* @return Response
|
||||
*/
|
||||
public function addHeader($key, $value): static
|
||||
{
|
||||
$this->headers[$key] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function isClient(): bool
|
||||
{
|
||||
return !($this->response instanceof SResponse) && !($this->response instanceof S2Response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $format
|
||||
* @return $this
|
||||
*/
|
||||
public function setFormat($format): static
|
||||
{
|
||||
$this->format = $format;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理无用数据
|
||||
*/
|
||||
public function clear(): void
|
||||
{
|
||||
$this->fd = 0;
|
||||
$this->isWebSocket = false;
|
||||
$this->format = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getContentType(): string
|
||||
{
|
||||
if ($this->format == null || $this->format == static::JSON) {
|
||||
return 'application/json;charset=utf-8';
|
||||
} else if ($this->format == static::XML) {
|
||||
return 'application/xml;charset=utf-8';
|
||||
} else {
|
||||
return 'text/html;charset=utf-8';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $content
|
||||
* @return mixed
|
||||
*/
|
||||
public function toHtml($content): mixed
|
||||
{
|
||||
$this->format = self::HTML;
|
||||
return $content;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $content
|
||||
* @return mixed
|
||||
*/
|
||||
public function toJson($content): mixed
|
||||
{
|
||||
$this->format = self::JSON;
|
||||
return $content;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $content
|
||||
* @return mixed
|
||||
*/
|
||||
public function toXml($content): mixed
|
||||
{
|
||||
$this->format = self::XML;
|
||||
return $content;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function sender(): mixed
|
||||
{
|
||||
return $this->send(func_get_args());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param $value
|
||||
* @return Response
|
||||
*/
|
||||
public function addHeader($key, $value): static
|
||||
{
|
||||
$this->headers[$key] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function isClient(): bool
|
||||
{
|
||||
return !($this->response instanceof SResponse) && !($this->response instanceof S2Response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $context
|
||||
* @param mixed $context
|
||||
* @param int $statusCode
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function send($context = '', $statusCode = 200): mixed
|
||||
{
|
||||
$sendData = $this->parseData($context);
|
||||
public function send(mixed $context = '', int $statusCode = 200): mixed
|
||||
{
|
||||
$sendData = $this->parseData($context);
|
||||
|
||||
$response = Context::getContext('response');
|
||||
if ($response instanceof SResponse) {
|
||||
$this->sendData($response, $sendData, $statusCode);
|
||||
} else {
|
||||
if (!empty(request()->fd)) {
|
||||
return '';
|
||||
}
|
||||
$this->printResult($sendData);
|
||||
}
|
||||
return $sendData;
|
||||
}
|
||||
$response = Context::getContext('response');
|
||||
if ($response instanceof SResponse) {
|
||||
$this->sendData($response, $sendData, $statusCode);
|
||||
} else {
|
||||
if (!empty(request()->fd)) {
|
||||
return '';
|
||||
}
|
||||
$this->printResult($sendData);
|
||||
}
|
||||
return $sendData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $context
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
private function parseData($context): mixed
|
||||
{
|
||||
if (empty($context)) {
|
||||
return $context;
|
||||
}
|
||||
if (isset($this->_format_maps[$this->format])) {
|
||||
$class['class'] = $this->_format_maps[$this->format];
|
||||
} else {
|
||||
$class['class'] = HtmlFormatter::class;
|
||||
}
|
||||
$format = Snowflake::createObject($class);
|
||||
return $format->send($context)->getData();
|
||||
}
|
||||
/**
|
||||
* @param $context
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
private function parseData($context): mixed
|
||||
{
|
||||
if (empty($context)) {
|
||||
return $context;
|
||||
}
|
||||
if (isset($this->_format_maps[$this->format])) {
|
||||
$class['class'] = $this->_format_maps[$this->format];
|
||||
} else {
|
||||
$class['class'] = HtmlFormatter::class;
|
||||
}
|
||||
$format = Snowflake::createObject($class);
|
||||
return $format->send($context)->getData();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $result
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
private function printResult($result): string
|
||||
{
|
||||
$result = Help::toString($result);
|
||||
$string = PHP_EOL . 'Command Result: ' . PHP_EOL . PHP_EOL;
|
||||
/**
|
||||
* @param $result
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
private function printResult($result): void
|
||||
{
|
||||
$result = Help::toString($result);
|
||||
$string = PHP_EOL . 'Command Result: ' . PHP_EOL . PHP_EOL;
|
||||
|
||||
fire('CONSOLE_END');
|
||||
if (str_contains((string)$result, 'Event::rshutdown(): Event::wait()')) {
|
||||
return (string)$result;
|
||||
}
|
||||
fire('CONSOLE_END');
|
||||
if (str_contains((string)$result, 'Event::rshutdown(): Event::wait()')) {
|
||||
return;
|
||||
}
|
||||
if (empty($result)) {
|
||||
$string .= 'success!' . PHP_EOL . PHP_EOL;
|
||||
} else {
|
||||
$string .= $result . PHP_EOL . PHP_EOL;
|
||||
}
|
||||
$string .= 'Command End!' . PHP_EOL . PHP_EOL;
|
||||
print_r($string);
|
||||
}
|
||||
|
||||
if (empty($result)) {
|
||||
$string .= 'success!' . PHP_EOL . PHP_EOL;
|
||||
} else {
|
||||
$string .= $result . PHP_EOL . PHP_EOL;
|
||||
}
|
||||
$string .= 'Command End!' . PHP_EOL . PHP_EOL;
|
||||
print_r($string);
|
||||
|
||||
return (string)$result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $response
|
||||
* @param $sendData
|
||||
* @param $status
|
||||
* @throws Exception
|
||||
*/
|
||||
private function sendData($response, $sendData, $status): void
|
||||
{
|
||||
if (!Snowflake::getWebSocket()->exist($response->fd)) {
|
||||
return;
|
||||
}
|
||||
if (is_array($sendData)) {
|
||||
$sendData = Json::encode($sendData);
|
||||
}
|
||||
$this->setHeaders($response, $status)->end($sendData);
|
||||
}
|
||||
/**
|
||||
* @param $response
|
||||
* @param $sendData
|
||||
* @param $status
|
||||
* @throws Exception
|
||||
*/
|
||||
private function sendData($response, $sendData, $status): void
|
||||
{
|
||||
$server = Snowflake::app()->getSwoole();
|
||||
if (!$server->exist($response->fd)) {
|
||||
return;
|
||||
}
|
||||
if (is_array($sendData)) {
|
||||
$sendData = Json::encode($sendData);
|
||||
}
|
||||
$this->setHeaders($response, $status)->end($sendData);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param SResponse $response
|
||||
* @param $status
|
||||
* @return SResponse
|
||||
*/
|
||||
private function setHeaders(SResponse $response, $status): SResponse
|
||||
{
|
||||
$response->status($status);
|
||||
$response->header('Content-Type', $this->getContentType());
|
||||
$response->header('Run-Time', $this->getRuntime());
|
||||
/**
|
||||
* @param SResponse $response
|
||||
* @param $status
|
||||
* @return SResponse
|
||||
*/
|
||||
private function setHeaders(SResponse $response, $status): SResponse
|
||||
{
|
||||
$response->status($status);
|
||||
$response->header('Content-Type', $this->getContentType());
|
||||
$response->header('Run-Time', $this->getRuntime());
|
||||
|
||||
if (empty($this->headers) || !is_array($this->headers)) {
|
||||
return $response;
|
||||
}
|
||||
foreach ($this->headers as $key => $header) {
|
||||
$response->header($key, $header, true);
|
||||
}
|
||||
$this->headers = [];
|
||||
return $response;
|
||||
}
|
||||
if (empty($this->headers) || !is_array($this->headers)) {
|
||||
return $response;
|
||||
}
|
||||
foreach ($this->headers as $key => $header) {
|
||||
$response->header($key, $header);
|
||||
}
|
||||
$this->headers = [];
|
||||
return $response;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $url
|
||||
* @param array $param
|
||||
* @return int
|
||||
*/
|
||||
public function redirect($url, array $param = []): int
|
||||
{
|
||||
if (!empty($param)) {
|
||||
$url .= '?' . http_build_query($param);
|
||||
}
|
||||
$url = ltrim($url, '/');
|
||||
if (!preg_match('/^http/', $url)) {
|
||||
$url = '/' . $url;
|
||||
}
|
||||
return $this->response->redirect($url);
|
||||
}
|
||||
/**
|
||||
* @param $url
|
||||
* @param array $param
|
||||
* @return int
|
||||
*/
|
||||
public function redirect($url, array $param = []): int
|
||||
{
|
||||
if (!empty($param)) {
|
||||
$url .= '?' . http_build_query($param);
|
||||
}
|
||||
$url = ltrim($url, '/');
|
||||
if (!preg_match('/^http/', $url)) {
|
||||
$url = '/' . $url;
|
||||
}
|
||||
return $this->response->redirect($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null $response
|
||||
* @return static
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function create($response = null): static
|
||||
{
|
||||
Context::setContext('response', $response);
|
||||
/**
|
||||
* @param null $response
|
||||
* @return static
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function create($response = null): static
|
||||
{
|
||||
Context::setContext('response', $response);
|
||||
|
||||
$ciResponse = Snowflake::getApp('response');
|
||||
$ciResponse->response = $response;
|
||||
$ciResponse->startTime = microtime(true);
|
||||
$ciResponse->format = self::JSON;
|
||||
return $ciResponse;
|
||||
}
|
||||
$ciResponse = Snowflake::getApp('response');
|
||||
$ciResponse->response = $response;
|
||||
$ciResponse->startTime = microtime(true);
|
||||
$ciResponse->format = self::JSON;
|
||||
return $ciResponse;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $statusCode
|
||||
* @param string $message
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function close($statusCode = 200, $message = ''): mixed
|
||||
{
|
||||
return $this->send($message, $statusCode);
|
||||
}
|
||||
/**
|
||||
* @param int $statusCode
|
||||
* @param string $message
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function close(int $statusCode = 200, string $message = ''): mixed
|
||||
{
|
||||
return $this->send($message, $statusCode);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $clientId
|
||||
* @param int $statusCode
|
||||
* @param string $message
|
||||
* @return mixed
|
||||
*/
|
||||
public function closeClient($clientId, $statusCode = 200, $message = ''): mixed
|
||||
{
|
||||
$socket = Snowflake::getWebSocket();
|
||||
if (!$socket->exist($clientId)) {
|
||||
return true;
|
||||
}
|
||||
return $socket->close($clientId, true);
|
||||
}
|
||||
/**
|
||||
* @param $clientId
|
||||
* @param int $statusCode
|
||||
* @param string $message
|
||||
* @return mixed
|
||||
*/
|
||||
public function closeClient($clientId,int $statusCode = 200,string $message = ''): mixed
|
||||
{
|
||||
$socket = Snowflake::getWebSocket();
|
||||
if (!$socket->exist($clientId)) {
|
||||
return true;
|
||||
}
|
||||
return $socket->close($clientId, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param int $offset
|
||||
* @param int $limit
|
||||
* @param int $sleep
|
||||
* @return string
|
||||
*/
|
||||
public function sendFile(string $path, $offset = 0, $limit = 1024000, $sleep = 0): string
|
||||
{
|
||||
$open = fopen($path, 'r');
|
||||
/**
|
||||
* @param string $path
|
||||
* @param int $offset
|
||||
* @param int $limit
|
||||
* @param int $sleep
|
||||
* @return string
|
||||
*/
|
||||
public function sendFile(string $path, int $offset = 0, int $limit = 1024000, int $sleep = 0): string
|
||||
{
|
||||
$open = fopen($path, 'r');
|
||||
|
||||
$stat = fstat($open);
|
||||
$stat = fstat($open);
|
||||
|
||||
while ($file = fread($open, $limit)) {
|
||||
$this->response->write($file);
|
||||
fseek($open, $offset);
|
||||
if ($sleep > 0) {
|
||||
sleep($sleep);
|
||||
}
|
||||
if ($offset >= $stat['size']) {
|
||||
break;
|
||||
}
|
||||
$offset += $limit;
|
||||
}
|
||||
$this->response->end();
|
||||
$this->response = null;
|
||||
return '';
|
||||
}
|
||||
while ($file = fread($open, $limit)) {
|
||||
$this->response->write($file);
|
||||
fseek($open, $offset);
|
||||
if ($sleep > 0) {
|
||||
sleep($sleep);
|
||||
}
|
||||
if ($offset >= $stat['size']) {
|
||||
break;
|
||||
}
|
||||
$offset += $limit;
|
||||
}
|
||||
$this->response->end();
|
||||
$this->response = null;
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function sendNotFind()
|
||||
{
|
||||
$this->format = static::HTML;
|
||||
$this->send('', 404);
|
||||
}
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function sendNotFind()
|
||||
{
|
||||
$this->format = static::HTML;
|
||||
$this->send('', 404);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
#[Pure] public function getRuntime(): string
|
||||
{
|
||||
return sprintf('%.5f', microtime(TRUE) - $this->startTime);
|
||||
}
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
#[Pure] public function getRuntime(): string
|
||||
{
|
||||
return sprintf('%.5f', microtime(TRUE) - $this->startTime);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+499
-505
File diff suppressed because it is too large
Load Diff
@@ -7,6 +7,7 @@ use Closure;
|
||||
use Exception;
|
||||
use HttpServer\Abstracts\HttpService;
|
||||
use HttpServer\Controller;
|
||||
use HttpServer\Exception\RequestException;
|
||||
use HttpServer\Http\Request;
|
||||
use HttpServer\IInterface\Middleware;
|
||||
use HttpServer\IInterface\RouterInterface;
|
||||
@@ -34,7 +35,7 @@ class Router extends HttpService implements RouterInterface
|
||||
const NOT_FOUND = 'Page not found or method not allowed.';
|
||||
|
||||
/** @var string[] */
|
||||
public array $methods = ['get', 'post', 'options', 'put', 'delete', 'receive'];
|
||||
public array $methods = ['get', 'post', 'options', 'put', 'delete', 'receive', 'head'];
|
||||
|
||||
|
||||
public ?Closure $middleware = null;
|
||||
@@ -261,7 +262,7 @@ class Router extends HttpService implements RouterInterface
|
||||
public function any($route, $handler): Any
|
||||
{
|
||||
$nodes = [];
|
||||
foreach (['get', 'post', 'options', 'put', 'delete'] as $method) {
|
||||
foreach (['get', 'post', 'options', 'put', 'delete', 'head'] as $method) {
|
||||
$nodes[] = $this->addRoute($route, $handler, $method);
|
||||
}
|
||||
return new Any($nodes);
|
||||
@@ -278,6 +279,19 @@ class Router extends HttpService implements RouterInterface
|
||||
return $this->addRoute($route, $handler, 'delete');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
* @param $handler
|
||||
* @return \HttpServer\Route\Node|null
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function head($route, $handler): ?Node
|
||||
{
|
||||
return $this->addRoute($route, $handler, 'head');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
* @param $handler
|
||||
@@ -490,7 +504,7 @@ class Router extends HttpService implements RouterInterface
|
||||
{
|
||||
$node = $this->find_path(\request());
|
||||
if (!($node instanceof Node)) {
|
||||
return send(self::NOT_FOUND);
|
||||
throw new RequestException(\request()->getUri() . ' -> ' . self::NOT_FOUND, 404);
|
||||
}
|
||||
send(($response = $node->dispatch()), 200);
|
||||
if (!$node->hasAfter()) {
|
||||
|
||||
+386
-382
@@ -33,87 +33,87 @@ defined('PID_PATH') or define('PID_PATH', APP_PATH . 'storage/server.pid');
|
||||
class Server extends HttpService
|
||||
{
|
||||
|
||||
const HTTP = 'HTTP';
|
||||
const TCP = 'TCP';
|
||||
const PACKAGE = 'PACKAGE';
|
||||
const WEBSOCKET = 'WEBSOCKET';
|
||||
const HTTP = 'HTTP';
|
||||
const TCP = 'TCP';
|
||||
const PACKAGE = 'PACKAGE';
|
||||
const WEBSOCKET = 'WEBSOCKET';
|
||||
|
||||
private array $server = [
|
||||
'HTTP' => [SWOOLE_TCP, Http::class],
|
||||
'TCP' => [SWOOLE_TCP, Receive::class],
|
||||
'PACKAGE' => [SWOOLE_UDP, Packet::class],
|
||||
'WEBSOCKET' => [SWOOLE_SOCK_TCP, Websocket::class],
|
||||
];
|
||||
private array $server = [
|
||||
'HTTP' => [SWOOLE_TCP, Http::class],
|
||||
'TCP' => [SWOOLE_TCP, Receive::class],
|
||||
'PACKAGE' => [SWOOLE_UDP, Packet::class],
|
||||
'WEBSOCKET' => [SWOOLE_SOCK_TCP, Websocket::class],
|
||||
];
|
||||
|
||||
private Packet|Websocket|Receive|null|Http $swoole = null;
|
||||
private Packet|Websocket|Receive|null|Http $swoole = null;
|
||||
|
||||
public int $daemon = 0;
|
||||
public int $daemon = 0;
|
||||
|
||||
|
||||
private array $process = [
|
||||
'biomonitoring' => Biomonitoring::class,
|
||||
'logger_process' => LoggerProcess::class
|
||||
];
|
||||
private array $process = [
|
||||
'biomonitoring' => Biomonitoring::class,
|
||||
'logger_process' => LoggerProcess::class
|
||||
];
|
||||
|
||||
private array $params = [];
|
||||
private array $params = [];
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $process
|
||||
* @param array $params
|
||||
*/
|
||||
public function addProcess($name, $process, $params = [])
|
||||
{
|
||||
$this->process[$name] = $process;
|
||||
$this->params[$name] = $params;
|
||||
}
|
||||
/**
|
||||
* @param $name
|
||||
* @param $process
|
||||
* @param array $params
|
||||
*/
|
||||
public function addProcess($name, $process, $params = [])
|
||||
{
|
||||
$this->process[$name] = $process;
|
||||
$this->params[$name] = $params;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getProcesses(): array
|
||||
{
|
||||
return $this->process ?? [];
|
||||
}
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getProcesses(): array
|
||||
{
|
||||
return $this->process ?? [];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $configs
|
||||
* @return Packet|Websocket|Receive|Http|null
|
||||
* @throws Exception
|
||||
*/
|
||||
private function initCore($configs): Packet|Websocket|Receive|Http|null
|
||||
{
|
||||
$servers = $this->sortServers($configs);
|
||||
foreach ($servers as $server) {
|
||||
$this->create($server);
|
||||
if (!$this->swoole) {
|
||||
throw new Exception('Base service create fail.');
|
||||
}
|
||||
}
|
||||
return $this->startRpcService();
|
||||
}
|
||||
/**
|
||||
* @param $configs
|
||||
* @return Packet|Websocket|Receive|Http|null
|
||||
* @throws Exception
|
||||
*/
|
||||
private function initCore($configs): Packet|Websocket|Receive|Http|null
|
||||
{
|
||||
$servers = $this->sortServers($configs);
|
||||
foreach ($servers as $server) {
|
||||
$this->create($server);
|
||||
if (!$this->swoole) {
|
||||
throw new Exception('Base service create fail.');
|
||||
}
|
||||
}
|
||||
return $this->startRpcService();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string start server
|
||||
*
|
||||
* start server
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function start(): string
|
||||
{
|
||||
$configs = Config::get('servers', [], true);
|
||||
/**
|
||||
* @return string start server
|
||||
*
|
||||
* start server
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function start(): string
|
||||
{
|
||||
$configs = Config::get('servers', [], true);
|
||||
|
||||
$baseServer = $this->initCore($configs);
|
||||
if (!$baseServer) {
|
||||
return 'ok';
|
||||
}
|
||||
$baseServer = $this->initCore($configs);
|
||||
if (!$baseServer) {
|
||||
return 'ok';
|
||||
}
|
||||
|
||||
Runtime::enableCoroutine(true, SWOOLE_HOOK_ALL ^ SWOOLE_HOOK_BLOCKING_FUNCTION);
|
||||
Runtime::enableCoroutine(true, SWOOLE_HOOK_ALL ^ SWOOLE_HOOK_BLOCKING_FUNCTION);
|
||||
|
||||
$settings['enable_deadlock_check'] = false;
|
||||
$settings['exit_condition'] = function () {
|
||||
@@ -121,368 +121,372 @@ class Server extends HttpService
|
||||
};
|
||||
Coroutine::set($settings);
|
||||
|
||||
return $this->execute($baseServer);
|
||||
}
|
||||
return $this->execute($baseServer);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $baseServer
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
private function execute($baseServer): mixed
|
||||
{
|
||||
$app = Snowflake::app();
|
||||
$app->set('base-server', $baseServer);
|
||||
return $baseServer->start();
|
||||
}
|
||||
/**
|
||||
* @param $baseServer
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
private function execute($baseServer): mixed
|
||||
{
|
||||
$app = Snowflake::app();
|
||||
$app->set('base-server', $baseServer);
|
||||
return $baseServer->start();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $host
|
||||
* @param $Port
|
||||
* @return Packet|Websocket|Receive|Http|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public function error_stop($host, $Port): Packet|Websocket|Receive|Http|null
|
||||
{
|
||||
$this->error(sprintf('Port %s::%d is already.', $host, $Port));
|
||||
if ($this->swoole) {
|
||||
$this->swoole->shutdown();
|
||||
} else {
|
||||
$this->shutdown();
|
||||
}
|
||||
return $this->swoole;
|
||||
}
|
||||
/**
|
||||
* @param $host
|
||||
* @param $Port
|
||||
* @return Packet|Websocket|Receive|Http|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public function error_stop($host, $Port): Packet|Websocket|Receive|Http|null
|
||||
{
|
||||
$this->error(sprintf('Port %s::%d is already.', $host, $Port));
|
||||
if ($this->swoole) {
|
||||
$this->swoole->shutdown();
|
||||
} else {
|
||||
$this->shutdown();
|
||||
}
|
||||
return $this->swoole;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function isRunner(): bool
|
||||
{
|
||||
$port = $this->sortServers(Config::get('servers'));
|
||||
if (empty($port)) {
|
||||
return false;
|
||||
}
|
||||
foreach ($port as $value) {
|
||||
if ($this->checkPort($value['port'])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* @return bool
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function isRunner(): bool
|
||||
{
|
||||
$port = $this->sortServers(Config::get('servers'));
|
||||
if (empty($port)) {
|
||||
return false;
|
||||
}
|
||||
foreach ($port as $value) {
|
||||
if ($this->checkPort($value['port'])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $port
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
private function checkPort($port): bool
|
||||
{
|
||||
if (Snowflake::getPlatform()->isLinux()) {
|
||||
exec('netstat -tunlp | grep ' . $port, $output);
|
||||
} else {
|
||||
exec('lsof -i :' . $port . ' | grep -i "LISTEN"', $output);
|
||||
}
|
||||
return !empty($output);
|
||||
}
|
||||
/**
|
||||
* @param $port
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
private function checkPort($port): bool
|
||||
{
|
||||
if (Snowflake::getPlatform()->isLinux()) {
|
||||
exec('netstat -tunlp | grep ' . $port, $output);
|
||||
} else {
|
||||
exec('lsof -i :' . $port . ' | grep -i "LISTEN"', $output);
|
||||
}
|
||||
return !empty($output);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*
|
||||
* start server
|
||||
* @throws Exception
|
||||
*/
|
||||
public function shutdown()
|
||||
{
|
||||
/** @var Shutdown $shutdown */
|
||||
$shutdown = Snowflake::app()->get('shutdown');
|
||||
$shutdown->shutdown();
|
||||
}
|
||||
/**
|
||||
* @return void
|
||||
*
|
||||
* start server
|
||||
* @throws Exception
|
||||
*/
|
||||
public function shutdown()
|
||||
{
|
||||
/** @var Shutdown $shutdown */
|
||||
$shutdown = Snowflake::app()->get('shutdown');
|
||||
$shutdown->shutdown();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function onProcessListener(): \Swoole\Server|null|Packet|Receive|Http|Websocket
|
||||
{
|
||||
if (!($this->swoole instanceof \Swoole\Server)) {
|
||||
return $this->swoole;
|
||||
}
|
||||
/**
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function onProcessListener(): \Swoole\Server|null|Packet|Receive|Http|Websocket
|
||||
{
|
||||
if (!($this->swoole instanceof \Swoole\Server)) {
|
||||
return $this->swoole;
|
||||
}
|
||||
|
||||
$processes = Config::get('processes');
|
||||
if (!empty($processes) && is_array($processes)) {
|
||||
$this->deliveryProcess(merge($processes, $this->process));
|
||||
} else {
|
||||
$this->deliveryProcess($this->process);
|
||||
}
|
||||
return $this->swoole;
|
||||
}
|
||||
$processes = Config::get('processes');
|
||||
if (!empty($processes) && is_array($processes)) {
|
||||
$this->deliveryProcess(merge($processes, $this->process));
|
||||
} else {
|
||||
$this->deliveryProcess($this->process);
|
||||
}
|
||||
return $this->swoole;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $processes
|
||||
* @throws Exception
|
||||
*/
|
||||
private function deliveryProcess($processes)
|
||||
{
|
||||
$application = Snowflake::app();
|
||||
if (empty($processes) || !is_array($processes)) {
|
||||
return;
|
||||
}
|
||||
foreach ($processes as $name => $process) {
|
||||
$this->debug(sprintf('Process %s', $process));
|
||||
if (!is_string($process)) {
|
||||
continue;
|
||||
}
|
||||
$system = Snowflake::createObject($process, [Snowflake::app(), $name, true]);
|
||||
if (isset($this->params[$name]) && !empty($this->params[$name])) {
|
||||
$system->write(swoole_serialize($this->params[$name]));
|
||||
}
|
||||
$this->swoole->addProcess($system);
|
||||
$application->set($process, $system);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param $processes
|
||||
* @throws Exception
|
||||
*/
|
||||
private function deliveryProcess($processes)
|
||||
{
|
||||
$application = Snowflake::app();
|
||||
if (empty($processes) || !is_array($processes)) {
|
||||
return;
|
||||
}
|
||||
foreach ($processes as $name => $process) {
|
||||
$this->debug(sprintf('Process %s', $process));
|
||||
if (!is_string($process)) {
|
||||
continue;
|
||||
}
|
||||
$system = Snowflake::createObject($process, [Snowflake::app(), $name, true]);
|
||||
if (isset($this->params[$name]) && !empty($this->params[$name])) {
|
||||
$system->write(swoole_serialize($this->params[$name]));
|
||||
}
|
||||
$this->swoole->addProcess($system);
|
||||
$application->set($process, $system);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $daemon
|
||||
* @return Server
|
||||
*/
|
||||
public function setDaemon($daemon): static
|
||||
{
|
||||
if (!in_array($daemon, [0, 1])) {
|
||||
return $this;
|
||||
}
|
||||
$this->daemon = $daemon;
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* @param $daemon
|
||||
* @return Server
|
||||
*/
|
||||
public function setDaemon($daemon): static
|
||||
{
|
||||
if (!in_array($daemon, [0, 1])) {
|
||||
return $this;
|
||||
}
|
||||
$this->daemon = $daemon;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Packet|Websocket|Receive|Http|null
|
||||
*/
|
||||
public function getServer(): Packet|Websocket|Receive|Http|null
|
||||
{
|
||||
return $this->swoole;
|
||||
}
|
||||
/**
|
||||
* @return Packet|Websocket|Receive|Http|null
|
||||
*/
|
||||
public function getServer(): Packet|Websocket|Receive|Http|null
|
||||
{
|
||||
return $this->swoole;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $config
|
||||
* @return \Swoole\Server|Packet|Receive|Http|Websocket|null
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
private function create($config): \Swoole\Server|null|Packet|Receive|Http|Websocket
|
||||
{
|
||||
$settings = Config::get('settings', []);
|
||||
if (!isset($this->server[$config['type']])) {
|
||||
throw new Exception('Unknown server type(' . $config['type'] . ').');
|
||||
}
|
||||
$server = $this->dispatchCreate($config, $settings);
|
||||
if (isset($config['events'])) {
|
||||
$this->createEventListen($config);
|
||||
}
|
||||
return $server;
|
||||
}
|
||||
/**
|
||||
* @param $config
|
||||
* @return \Swoole\Server|Packet|Receive|Http|Websocket|null
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
private function create($config): \Swoole\Server|null|Packet|Receive|Http|Websocket
|
||||
{
|
||||
$settings = Config::get('settings', []);
|
||||
if (!isset($this->server[$config['type']])) {
|
||||
throw new Exception('Unknown server type(' . $config['type'] . ').');
|
||||
}
|
||||
$server = $this->dispatchCreate($config, $settings);
|
||||
if (isset($config['events'])) {
|
||||
$this->createEventListen($config);
|
||||
}
|
||||
return $server;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $config
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function createEventListen($config)
|
||||
{
|
||||
if (!is_array($config['events'])) {
|
||||
return;
|
||||
}
|
||||
foreach ($config['events'] as $name => $_event) {
|
||||
Event::on('listen ' . $config['port'] . ' ' . $name, $_event);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param $config
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function createEventListen($config)
|
||||
{
|
||||
if (!is_array($config['events'])) {
|
||||
return;
|
||||
}
|
||||
foreach ($config['events'] as $name => $_event) {
|
||||
if ($name === Event::SERVER_CLIENT_CLOSE) {
|
||||
Event::on($name, $_event);
|
||||
}else{
|
||||
Event::on('listen ' . $config['port'] . ' ' . $name, $_event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $config
|
||||
* @param $settings
|
||||
* @return \Swoole\Server|Packet|Receive|Http|Websocket|null
|
||||
* @throws Exception
|
||||
*/
|
||||
private function dispatchCreate($config, $settings): \Swoole\Server|Packet|Receive|Http|Websocket|null
|
||||
{
|
||||
if (Snowflake::port_already($config['port'])) {
|
||||
return $this->error_stop($config['host'], $config['port']);
|
||||
}
|
||||
if (!($this->swoole instanceof \Swoole\Server)) {
|
||||
return $this->parseServer($config, $settings);
|
||||
}
|
||||
return $this->addListener($config);
|
||||
}
|
||||
/**
|
||||
* @param $config
|
||||
* @param $settings
|
||||
* @return \Swoole\Server|Packet|Receive|Http|Websocket|null
|
||||
* @throws Exception
|
||||
*/
|
||||
private function dispatchCreate($config, $settings): \Swoole\Server|Packet|Receive|Http|Websocket|null
|
||||
{
|
||||
if (Snowflake::port_already($config['port'])) {
|
||||
return $this->error_stop($config['host'], $config['port']);
|
||||
}
|
||||
if (!($this->swoole instanceof \Swoole\Server)) {
|
||||
return $this->parseServer($config, $settings);
|
||||
}
|
||||
return $this->addListener($config);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $config
|
||||
* @return Http|Packet|Receive|Websocket|null
|
||||
* @throws Exception
|
||||
*/
|
||||
private function addListener($config): Packet|Websocket|Receive|Http|null
|
||||
{
|
||||
$newListener = $this->swoole->addlistener($config['host'], $config['port'], $config['mode']);
|
||||
if (!$newListener) {
|
||||
exit($this->addError(sprintf('Listen %s::%d fail.', $config['host'], $config['port'])));
|
||||
}
|
||||
/**
|
||||
* @param $config
|
||||
* @return Http|Packet|Receive|Websocket|null
|
||||
* @throws Exception
|
||||
*/
|
||||
private function addListener($config): Packet|Websocket|Receive|Http|null
|
||||
{
|
||||
$newListener = $this->swoole->addlistener($config['host'], $config['port'], $config['mode']);
|
||||
if (!$newListener) {
|
||||
exit($this->addError(sprintf('Listen %s::%d fail.', $config['host'], $config['port'])));
|
||||
}
|
||||
|
||||
if (isset($config['settings']) && is_array($config['settings'])) {
|
||||
$newListener->set($config['settings']);
|
||||
}
|
||||
$this->onListenerBind($config);
|
||||
if (isset($config['settings']) && is_array($config['settings'])) {
|
||||
$newListener->set($config['settings']);
|
||||
}
|
||||
$this->onListenerBind($config);
|
||||
|
||||
return $this->swoole;
|
||||
}
|
||||
return $this->swoole;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Packet|Websocket|Receive|Http|null
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
private function startRpcService(): Packet|Websocket|Receive|Http|null
|
||||
{
|
||||
$rpcService = Config::get('rpc', []);
|
||||
if (empty($rpcService)) {
|
||||
return $this->swoole;
|
||||
}
|
||||
$this->addListener($rpcService);
|
||||
return $this->swoole;
|
||||
}
|
||||
/**
|
||||
* @return Packet|Websocket|Receive|Http|null
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
private function startRpcService(): Packet|Websocket|Receive|Http|null
|
||||
{
|
||||
$rpcService = Config::get('rpc', []);
|
||||
if (empty($rpcService)) {
|
||||
return $this->swoole;
|
||||
}
|
||||
$this->addListener($rpcService);
|
||||
return $this->swoole;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $config
|
||||
* @param $settings
|
||||
* @return Packet|Websocket|Receive|Http|null
|
||||
* @throws Exception
|
||||
*/
|
||||
private function parseServer($config, $settings): Packet|Websocket|Receive|Http|null
|
||||
{
|
||||
$class = $this->dispatch($config['type']);
|
||||
if (is_array($config['settings'] ?? null)) {
|
||||
$settings = array_merge($settings, $config['settings']);
|
||||
}
|
||||
$this->debug(Snowflake::listen($config));
|
||||
$this->swoole = $this->createServer($class, $config);
|
||||
$this->swoole->set(array_merge($settings, [
|
||||
'daemonize' => $this->daemon,
|
||||
'pid_file' => $settings['pid_file'] ?? PID_PATH
|
||||
]));
|
||||
return $this->onProcessListener();
|
||||
}
|
||||
/**
|
||||
* @param $config
|
||||
* @param $settings
|
||||
* @return Packet|Websocket|Receive|Http|null
|
||||
* @throws Exception
|
||||
*/
|
||||
private function parseServer($config, $settings): Packet|Websocket|Receive|Http|null
|
||||
{
|
||||
$class = $this->dispatch($config['type']);
|
||||
if (is_array($config['settings'] ?? null)) {
|
||||
$settings = array_merge($settings, $config['settings']);
|
||||
}
|
||||
$this->debug(Snowflake::listen($config));
|
||||
$this->swoole = $this->createServer($class, $config);
|
||||
$this->swoole->set(array_merge($settings, [
|
||||
'daemonize' => $this->daemon,
|
||||
'pid_file' => $settings['pid_file'] ?? PID_PATH
|
||||
]));
|
||||
return $this->onProcessListener();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
* @param $config
|
||||
* @return mixed
|
||||
*/
|
||||
private function createServer($class, $config): mixed
|
||||
{
|
||||
return new $class($config['host'], $config['port'], SWOOLE_PROCESS, $config['mode']);
|
||||
}
|
||||
/**
|
||||
* @param $class
|
||||
* @param $config
|
||||
* @return mixed
|
||||
*/
|
||||
private function createServer($class, $config): mixed
|
||||
{
|
||||
return new $class($config['host'], $config['port'], SWOOLE_PROCESS, $config['mode']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $config
|
||||
* @return Packet|Websocket|Receive|Http|null
|
||||
* @throws Exception
|
||||
*/
|
||||
private function onListenerBind($config): Packet|Websocket|Receive|Http|null
|
||||
{
|
||||
$this->bindServerEvent($config['type']);
|
||||
/**
|
||||
* @param $config
|
||||
* @return Packet|Websocket|Receive|Http|null
|
||||
* @throws Exception
|
||||
*/
|
||||
private function onListenerBind($config): Packet|Websocket|Receive|Http|null
|
||||
{
|
||||
$this->bindServerEvent($config['type']);
|
||||
|
||||
$this->debug(sprintf('Check listen %s::%d -> ok', $config['host'], $config['port']));
|
||||
$this->debug(sprintf('Check listen %s::%d -> ok', $config['host'], $config['port']));
|
||||
|
||||
return $this->swoole;
|
||||
}
|
||||
return $this->swoole;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
* @throws Exception
|
||||
*/
|
||||
private function bindServerEvent($type = self::TCP)
|
||||
{
|
||||
if (in_array($type, [self::PACKAGE, self::TCP])) {
|
||||
$this->onBindCallback('connect', [make(OnConnect::class), 'onHandler']);
|
||||
$this->onBindCallback('close', [make(OnClose::class), 'onHandler']);
|
||||
if ($type == self::PACKAGE) {
|
||||
$this->onBindCallback('packet', [make(OnPacket::class), 'onHandler']);
|
||||
} else if ($type == self::TCP) {
|
||||
$this->onBindCallback('receive', [make(OnReceive::class), 'onHandler']);
|
||||
}
|
||||
} else if ($type === self::HTTP) {
|
||||
$this->onBindCallback('request', [make(OnRequest::class), 'onHandler']);
|
||||
} else {
|
||||
throw new Exception('Unknown server type(' . $type . ').');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param string $type
|
||||
* @throws Exception
|
||||
*/
|
||||
private function bindServerEvent($type = self::TCP)
|
||||
{
|
||||
if (in_array($type, [self::PACKAGE, self::TCP])) {
|
||||
$this->onBindCallback('connect', [make(OnConnect::class), 'onHandler']);
|
||||
$this->onBindCallback('close', [make(OnClose::class), 'onHandler']);
|
||||
if ($type == self::PACKAGE) {
|
||||
$this->onBindCallback('packet', [make(OnPacket::class), 'onHandler']);
|
||||
} else if ($type == self::TCP) {
|
||||
$this->onBindCallback('receive', [make(OnReceive::class), 'onHandler']);
|
||||
}
|
||||
} else if ($type === self::HTTP) {
|
||||
$this->onBindCallback('request', [make(OnRequest::class), 'onHandler']);
|
||||
} else {
|
||||
throw new Exception('Unknown server type(' . $type . ').');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $callback
|
||||
* @throws Exception
|
||||
*/
|
||||
public function onBindCallback($name, $callback)
|
||||
{
|
||||
if ($this->swoole->getCallback($name) !== null) {
|
||||
return;
|
||||
}
|
||||
$this->swoole->on($name, $callback);
|
||||
}
|
||||
/**
|
||||
* @param $name
|
||||
* @param $callback
|
||||
* @throws Exception
|
||||
*/
|
||||
public function onBindCallback($name, $callback)
|
||||
{
|
||||
if ($this->swoole->getCallback($name) !== null) {
|
||||
return;
|
||||
}
|
||||
$this->swoole->on($name, $callback);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $type
|
||||
* @return string
|
||||
*/
|
||||
private function dispatch($type): string
|
||||
{
|
||||
return match ($type) {
|
||||
self::HTTP => Http::class,
|
||||
self::WEBSOCKET => Websocket::class,
|
||||
self::PACKAGE => Packet::class,
|
||||
default => Receive::class
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @param $type
|
||||
* @return string
|
||||
*/
|
||||
private function dispatch($type): string
|
||||
{
|
||||
return match ($type) {
|
||||
self::HTTP => Http::class,
|
||||
self::WEBSOCKET => Websocket::class,
|
||||
self::PACKAGE => Packet::class,
|
||||
default => Receive::class
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $servers
|
||||
* @return array
|
||||
*/
|
||||
private function sortServers($servers): array
|
||||
{
|
||||
$array = [];
|
||||
foreach ($servers as $server) {
|
||||
switch ($server['type']) {
|
||||
case self::WEBSOCKET:
|
||||
array_unshift($array, $server);
|
||||
break;
|
||||
case self::HTTP:
|
||||
case self::PACKAGE | self::TCP:
|
||||
$array[] = $server;
|
||||
break;
|
||||
default:
|
||||
$array[] = $server;
|
||||
}
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
/**
|
||||
* @param $servers
|
||||
* @return array
|
||||
*/
|
||||
private function sortServers($servers): array
|
||||
{
|
||||
$array = [];
|
||||
foreach ($servers as $server) {
|
||||
switch ($server['type']) {
|
||||
case self::WEBSOCKET:
|
||||
array_unshift($array, $server);
|
||||
break;
|
||||
case self::HTTP:
|
||||
case self::PACKAGE | self::TCP:
|
||||
$array[] = $server;
|
||||
break;
|
||||
default:
|
||||
$array[] = $server;
|
||||
}
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+50
-18
@@ -6,7 +6,6 @@ namespace HttpServer;
|
||||
|
||||
use Exception;
|
||||
use Snowflake\Abstracts\Component;
|
||||
use Snowflake\Exception\ConfigException;
|
||||
|
||||
|
||||
/**
|
||||
@@ -51,7 +50,7 @@ class Shutdown extends Component
|
||||
|
||||
$master_pid = Server()->setting['pid_file'] ?? PID_PATH;
|
||||
if (file_exists($master_pid)) {
|
||||
$this->close($master_pid);
|
||||
$this->close(file_get_contents($master_pid));
|
||||
}
|
||||
$this->closeOther();
|
||||
}
|
||||
@@ -109,33 +108,66 @@ class Shutdown extends Component
|
||||
*/
|
||||
public function directoryCheck(string $path): bool
|
||||
{
|
||||
$dir = new \DirectoryIterator($path);
|
||||
if ($dir->getSize() < 1) {
|
||||
return true;
|
||||
}
|
||||
foreach ($dir as $value) {
|
||||
if ($value->isDot()) continue;
|
||||
$values = $this->getProcessPidS($path);
|
||||
if (empty($values)) return false;
|
||||
|
||||
if (!$value->valid()) continue;
|
||||
|
||||
$this->close($value->getRealPath());
|
||||
$diff = array_diff($values, $this->getPidS());
|
||||
foreach ($diff as $value) {
|
||||
$this->pidIsExists($value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $path
|
||||
* @return array|bool
|
||||
*/
|
||||
private function getProcessPidS($path): bool|array
|
||||
{
|
||||
$values = [];
|
||||
$dir = new \DirectoryIterator($path);
|
||||
if ($dir->getSize() < 1) {
|
||||
return $values;
|
||||
}
|
||||
foreach ($dir as $value) {
|
||||
if ($value->isDot()) continue;
|
||||
|
||||
if (!$value->valid()) continue;
|
||||
|
||||
$_value = file_get_contents($value->getRealPath());
|
||||
if (empty($_value)) {
|
||||
continue;
|
||||
}
|
||||
$values[] = intval($_value);
|
||||
|
||||
@unlink($value->getRealPath());
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getPidS(): array
|
||||
{
|
||||
exec('ps -eo pid', $output);
|
||||
return array_filter($output, function ($value) {
|
||||
return intval($value);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
*/
|
||||
public function close(string $value)
|
||||
public function close(mixed $value)
|
||||
{
|
||||
$content = file_get_contents($value);
|
||||
|
||||
while ($this->pidIsExists($content)) {
|
||||
exec('kill -15 ' . $content);
|
||||
sleep(1);
|
||||
while ($this->pidIsExists($value)) {
|
||||
exec('kill -15 ' . $value);
|
||||
usleep(100);
|
||||
}
|
||||
|
||||
clearstatcache($value);
|
||||
if (file_exists($value)) {
|
||||
@unlink($value);
|
||||
|
||||
@@ -38,6 +38,7 @@ use Snowflake\Event;
|
||||
use Snowflake\Exception\InitException;
|
||||
use Snowflake\Exception\NotFindClassException;
|
||||
use Snowflake\Jwt\Jwt;
|
||||
use Snowflake\Pool\ClientsPool;
|
||||
use Snowflake\Pool\Connection;
|
||||
use Snowflake\Pool\Pool as SPool;
|
||||
use Snowflake\Pool\Redis as SRedis;
|
||||
@@ -434,6 +435,16 @@ abstract class BaseApplication extends Service
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return ClientsPool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getClientsPool(): ClientsPool
|
||||
{
|
||||
return $this->get('clientsPool');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
@@ -444,6 +455,7 @@ abstract class BaseApplication extends Service
|
||||
'connections' => ['class' => Connection::class],
|
||||
'redis_connections' => ['class' => SRedis::class],
|
||||
'pool' => ['class' => SPool::class],
|
||||
'clientsPool' => ['class' => ClientsPool::class],
|
||||
'config' => ['class' => Config::class],
|
||||
'logger' => ['class' => Logger::class],
|
||||
'annotation' => ['class' => SAnnotation::class],
|
||||
|
||||
@@ -11,7 +11,6 @@ namespace Snowflake\Abstracts;
|
||||
|
||||
use Exception;
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use Snowflake\Core\Json;
|
||||
use Snowflake\Snowflake;
|
||||
use Swoole\Coroutine;
|
||||
|
||||
@@ -104,7 +103,7 @@ class BaseObject implements Configure
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function addError($message, $model = 'app'): bool
|
||||
public function addError($message, string $model = 'app'): bool
|
||||
{
|
||||
if ($message instanceof \Throwable) {
|
||||
$Throwable = $message;
|
||||
@@ -218,10 +217,10 @@ class BaseObject implements Configure
|
||||
}
|
||||
$content = (empty($method) ? '' : $method . ': ') . $message;
|
||||
|
||||
$message = "\033[41;37m" . PHP_EOL . "[" . date('Y-m-d H:i:s') . '][ERROR]: ' . $content . PHP_EOL . "\033[0m";
|
||||
$message = "\033[41;37m[" . date('Y-m-d H:i:s') . '][ERROR]: ' . $content . "\033[0m";
|
||||
|
||||
if (!empty($file)) {
|
||||
$message .= "\033[41;37m[" . date('Y-m-d H:i:s') . '][ERROR]: ' . $file . "\033[0m";
|
||||
$message .= PHP_EOL . "\033[41;37m[" . date('Y-m-d H:i:s') . '][ERROR]: ' . $file . "\033[0m";
|
||||
}
|
||||
$socket->output($message . PHP_EOL);
|
||||
}
|
||||
|
||||
@@ -57,11 +57,7 @@ class Config extends Component
|
||||
if (empty($configs)) {
|
||||
return;
|
||||
}
|
||||
if (!empty($config->data)) {
|
||||
$config->data = ArrayAccess::merge($config->data, $configs);
|
||||
} else {
|
||||
$config->data = $configs;
|
||||
}
|
||||
$config->data = $configs;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+50
-59
@@ -73,17 +73,15 @@ abstract class Pool extends Component
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function Heartbeat_detection()
|
||||
public function Heartbeat_detection($ticker, string $name)
|
||||
{
|
||||
if (env('state') == 'exit') {
|
||||
Timer::clear($this->creates);
|
||||
$this->creates = -1;
|
||||
} else if ($this->lastTime != 0) {
|
||||
[$firstClear, $lastClear] = $this->getClearTime();
|
||||
if ($this->lastTime + $firstClear < time()) {
|
||||
$this->flush(0);
|
||||
} else if ($this->lastTime + $lastClear < time()) {
|
||||
$this->flush(2);
|
||||
} else {
|
||||
$min = Config::get('databases.pool.min', 1);
|
||||
if (($length = $this->getChannel($name)->length()) > $min) {
|
||||
$this->flush($min);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,12 +119,12 @@ abstract class Pool extends Component
|
||||
|
||||
|
||||
/**
|
||||
* @param $channel
|
||||
* @param Channel $channel
|
||||
* @param $name
|
||||
* @param $retain_number
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function pop($channel, $name, $retain_number): void
|
||||
protected function pop(Channel $channel, $name, $retain_number): void
|
||||
{
|
||||
if (Coroutine::getCid() === -1) {
|
||||
return;
|
||||
@@ -147,7 +145,7 @@ abstract class Pool extends Component
|
||||
* @param false $isMaster
|
||||
* @param int $max
|
||||
*/
|
||||
public function initConnections($driver, $name, $isMaster = false, $max = 60)
|
||||
public function initConnections($driver, $name, bool $isMaster = false, int $max = 60)
|
||||
{
|
||||
$name = $this->name($driver, $name, $isMaster);
|
||||
if (isset(static::$_items[$name]) && static::$_items[$name] instanceof Channel) {
|
||||
@@ -156,8 +154,28 @@ abstract class Pool extends Component
|
||||
if (Coroutine::getCid() === -1) {
|
||||
return;
|
||||
}
|
||||
static::$_items[$name] = new Channel((int)$max);
|
||||
$this->max = (int)$max;
|
||||
if ($this->creates === -1) {
|
||||
$this->creates = Timer::tick(1000, [$this, 'Heartbeat_detection'], $name);
|
||||
}
|
||||
static::$_items[$name] = new Channel($max);
|
||||
$this->max = $max;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return Channel
|
||||
* @throws ConfigException
|
||||
*/
|
||||
private function getChannel($name): Channel
|
||||
{
|
||||
if (!isset(static::$_items[$name])) {
|
||||
static::$_items[$name] = new Channel(Config::get('databases.pool.max', 10));
|
||||
if ($this->creates === -1) {
|
||||
$this->creates = Timer::tick(1000, [$this, 'Heartbeat_detection'], $name);
|
||||
}
|
||||
}
|
||||
return static::$_items[$name];
|
||||
}
|
||||
|
||||
|
||||
@@ -172,36 +190,23 @@ abstract class Pool extends Component
|
||||
if (Coroutine::getCid() === -1) {
|
||||
return $this->createClient($name, $callback);
|
||||
}
|
||||
$channel = static::$_items[$name] ?? new Channel($this->max);
|
||||
if (!((static::$_items[$name] ?? null) instanceof Channel)) {
|
||||
static::$_items[$name] = $channel;
|
||||
}
|
||||
if ($channel->isEmpty()) {
|
||||
$this->createByCallback($channel, $name, $callback);
|
||||
}
|
||||
$connection = $channel->pop();
|
||||
if (!$this->checkCanUse($name, $connection)) {
|
||||
return $this->createClient($name, $callback);
|
||||
} else {
|
||||
return $connection;
|
||||
|
||||
$channel = $this->getChannel($name);
|
||||
if (!$channel->isEmpty()) {
|
||||
$connection = $channel->pop();
|
||||
if ($this->checkCanUse($name, $connection)) {
|
||||
return $connection;
|
||||
}
|
||||
}
|
||||
return $this->createClient($name, $callback);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $channel
|
||||
* @param $name
|
||||
* @param mixed $callback
|
||||
* @param string $name
|
||||
* @param mixed $config
|
||||
* @return mixed
|
||||
*/
|
||||
private function createByCallback(Channel $channel, $name, mixed $callback): void
|
||||
{
|
||||
if ($this->creates === -1 && !is_callable($callback)) {
|
||||
$this->creates = Timer::tick(1000, [$this, 'Heartbeat_detection']);
|
||||
}
|
||||
$channel->push($this->createClient($name, $callback));
|
||||
}
|
||||
|
||||
|
||||
abstract public function createClient(string $name, mixed $config): mixed;
|
||||
|
||||
|
||||
@@ -211,7 +216,7 @@ abstract class Pool extends Component
|
||||
* @param false $isMaster
|
||||
* @return string
|
||||
*/
|
||||
#[Pure] public function name($driver, $cds, $isMaster = false): string
|
||||
#[Pure] public function name($driver, $cds, bool $isMaster = false): string
|
||||
{
|
||||
if ($isMaster === true) {
|
||||
return $cds . '_master';
|
||||
@@ -223,7 +228,7 @@ abstract class Pool extends Component
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param $client
|
||||
* @param mixed $client
|
||||
* @return bool
|
||||
* 检查连接可靠性
|
||||
*/
|
||||
@@ -235,7 +240,7 @@ abstract class Pool extends Component
|
||||
|
||||
/**
|
||||
* @param array $config
|
||||
* @param $isMaster
|
||||
* @param bool $isMaster
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
@@ -249,19 +254,6 @@ abstract class Pool extends Component
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function canCreate(string $name): bool
|
||||
{
|
||||
if (!isset(static::$hasCreate[$name])) {
|
||||
static::$hasCreate[$name] = 0;
|
||||
}
|
||||
return static::$hasCreate[$name] < $this->max;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return bool
|
||||
*/
|
||||
public function hasItem(string $name): bool
|
||||
{
|
||||
if (isset(static::$_items[$name])) {
|
||||
@@ -272,7 +264,7 @@ abstract class Pool extends Component
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
*/
|
||||
public function size(string $name): mixed
|
||||
@@ -288,18 +280,16 @@ abstract class Pool extends Component
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $client
|
||||
* @param string $name
|
||||
* @param mixed $client
|
||||
* @throws ConfigException
|
||||
*/
|
||||
public function push(string $name, mixed $client)
|
||||
{
|
||||
if (Coroutine::getCid() === -1) {
|
||||
return;
|
||||
}
|
||||
$channel = static::$_items[$name] ?? new Channel($this->max);
|
||||
if (!isset(static::$_items[$name])) {
|
||||
static::$_items[$name] = $channel;
|
||||
}
|
||||
$channel = $this->getChannel($name);
|
||||
if (!$channel->isFull()) {
|
||||
$channel->push($client);
|
||||
}
|
||||
@@ -321,6 +311,7 @@ abstract class Pool extends Component
|
||||
if ($this->creates > -1) {
|
||||
Timer::clear($this->creates);
|
||||
}
|
||||
$channel->close();
|
||||
static::$_items[$name] = null;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ use Snowflake\Channel;
|
||||
use Snowflake\Error\Logger;
|
||||
use Snowflake\Event;
|
||||
use Snowflake\Jwt\Jwt;
|
||||
use Snowflake\Pool\ClientsPool;
|
||||
use Snowflake\Pool\Connection;
|
||||
use Snowflake\Pool\Pool as SPool;
|
||||
use Rpc\Producer as RPCProducer;
|
||||
@@ -54,6 +55,7 @@ use Rpc\Producer as RPCProducer;
|
||||
* @property Channel $channel
|
||||
* @property Shutdown $shutdown
|
||||
* @property Emit $emit
|
||||
* @property ClientsPool $clientsPool
|
||||
*/
|
||||
trait TraitApplication
|
||||
{
|
||||
|
||||
@@ -35,7 +35,6 @@ use function Co\run;
|
||||
* @package Snowflake
|
||||
*
|
||||
* @property-read Config $config
|
||||
* @property-read WchatProviders $wchat
|
||||
*/
|
||||
class Application extends BaseApplication
|
||||
{
|
||||
@@ -62,6 +61,9 @@ class Application extends BaseApplication
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param Closure|array $closure
|
||||
* @return $this
|
||||
|
||||
+17
-16
@@ -12,6 +12,7 @@ namespace Snowflake\Cache;
|
||||
use Exception;
|
||||
use Snowflake\Abstracts\Component;
|
||||
use Snowflake\Abstracts\Config;
|
||||
use Snowflake\Core\Json;
|
||||
use Snowflake\Event;
|
||||
use Snowflake\Exception\ConfigException;
|
||||
use Snowflake\Snowflake;
|
||||
@@ -20,6 +21,7 @@ use Snowflake\Snowflake;
|
||||
* Class Redis
|
||||
* @package Snowflake\Snowflake\Cache
|
||||
* @see \Redis
|
||||
*
|
||||
*/
|
||||
class Redis extends Component
|
||||
{
|
||||
@@ -51,11 +53,10 @@ class Redis extends Component
|
||||
$connections = Snowflake::app()->getRedisFromPool();
|
||||
|
||||
$config = $this->get_config();
|
||||
$name = $config['host'] . ':' . $config['prefix'] . ':' . $config['databases'];
|
||||
|
||||
$length = env('REDIS.POOL_LENGTH', 100);
|
||||
$length = (int)env('REDIS.POOL_LENGTH', 100);
|
||||
|
||||
$connections->initConnections('redis', 'redis:' . $name, true, $length);
|
||||
$connections->initConnections('Redis:' . $config['host'], true, $length);
|
||||
}
|
||||
|
||||
|
||||
@@ -67,11 +68,17 @@ class Redis extends Component
|
||||
*/
|
||||
public function __call($name, $arguments): mixed
|
||||
{
|
||||
$time = microtime(true);
|
||||
if (method_exists($this, $name)) {
|
||||
$data = $this->{$name}(...$arguments);
|
||||
} else {
|
||||
$data = $this->proxy()->{$name}(...$arguments);
|
||||
}
|
||||
|
||||
if (microtime(true) - $time >= 0.02) {
|
||||
$this->warning('Redis:' . Json::encode([$name, $arguments]) . (microtime(true) - $time));
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
@@ -82,7 +89,7 @@ class Redis extends Component
|
||||
* @return bool|int
|
||||
* @throws Exception
|
||||
*/
|
||||
public function lock($key, $timeout = 5): bool|int
|
||||
public function lock($key, int $timeout = 5): bool|int
|
||||
{
|
||||
$script = <<<SCRIPT
|
||||
local _nx = redis.call('setnx',KEYS[1], ARGV[1])
|
||||
@@ -92,7 +99,7 @@ if (_nx ~= 0) then
|
||||
end
|
||||
return 0
|
||||
SCRIPT;
|
||||
return $this->proxy()->eval($script, [$key, $timeout], 1);
|
||||
return $this->proxy()->eval($script, ['{lock}:' . $key, $timeout], 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -104,7 +111,7 @@ SCRIPT;
|
||||
public function unlock($key): int
|
||||
{
|
||||
$redis = $this->proxy();
|
||||
return $redis->del($key);
|
||||
return $redis->del('{lock}:' . $key);
|
||||
}
|
||||
|
||||
|
||||
@@ -137,7 +144,9 @@ SCRIPT;
|
||||
{
|
||||
$connections = Snowflake::app()->getRedisFromPool();
|
||||
|
||||
$client = $connections->get($this->get_config(), true);
|
||||
$config = $this->get_config();
|
||||
|
||||
$client = $connections->get($config, true);
|
||||
if (!($client instanceof \Redis)) {
|
||||
throw new Exception('Redis connections more.');
|
||||
}
|
||||
@@ -150,15 +159,7 @@ SCRIPT;
|
||||
*/
|
||||
public function get_config(): array
|
||||
{
|
||||
return Config::get('cache.redis', false, [
|
||||
'host' => '127.0.0.1',
|
||||
'port' => '6379',
|
||||
'prefix' => Config::get('id'),
|
||||
'auth' => '',
|
||||
'databases' => '0',
|
||||
'read_timeout' => -1,
|
||||
'timeout' => -1,
|
||||
]);
|
||||
return Config::get('cache.redis', null, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+79
-50
@@ -18,54 +18,83 @@ class Channel extends Component
|
||||
{
|
||||
|
||||
|
||||
private static array $_channels = [];
|
||||
private static array $_channels = [];
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
* @param string $name
|
||||
* @throws Exception
|
||||
*/
|
||||
public function push(mixed $value, string $name = ''): void
|
||||
{
|
||||
$channel = $this->channelInit($name);
|
||||
if ($channel->count() >= 100) {
|
||||
return;
|
||||
}
|
||||
$channel->enqueue($value);
|
||||
}
|
||||
private static array $_waitRecover = [];
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return bool|SplQueue
|
||||
*/
|
||||
private function channelInit(string $name = ''): bool|SplQueue
|
||||
{
|
||||
if (!isset(static::$_channels[$name]) || !(static::$_channels[$name] instanceof SplQueue)) {
|
||||
static::$_channels[$name] = new SplQueue();
|
||||
}
|
||||
return static::$_channels[$name];
|
||||
}
|
||||
public function init()
|
||||
{
|
||||
Event::on(Event::SYSTEM_RESOURCE_RELEASES, [$this, 'recover']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* 清空缓存
|
||||
*/
|
||||
public function cleanAll()
|
||||
{
|
||||
/** @var SplQueue $channel */
|
||||
foreach (static::$_channels as $channel) {
|
||||
if (!($channel instanceof SplQueue)) {
|
||||
continue;
|
||||
}
|
||||
while ($channel->count() > 0) {
|
||||
$channel->dequeue();
|
||||
}
|
||||
}
|
||||
static::$_channels = [];
|
||||
}
|
||||
/**
|
||||
* 回收对象
|
||||
*/
|
||||
public function recover()
|
||||
{
|
||||
foreach (Channel::$_waitRecover as $key => $value) {
|
||||
if (empty($value)) {
|
||||
continue;
|
||||
}
|
||||
$channel = $this->channelInit($key);
|
||||
if ($channel->count() >= 100) {
|
||||
continue;
|
||||
}
|
||||
foreach ($value as $item) {
|
||||
$channel->enqueue($item);
|
||||
}
|
||||
}
|
||||
Channel::$_waitRecover = [];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
* @param string $name
|
||||
* @throws Exception
|
||||
*/
|
||||
public function push(mixed $value, string $name = ''): void
|
||||
{
|
||||
if (!isset(Channel::$_waitRecover[$name])) {
|
||||
Channel::$_waitRecover[$name] = [];
|
||||
}
|
||||
Channel::$_waitRecover[$name][] = $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return bool|SplQueue
|
||||
*/
|
||||
private function channelInit(string $name = ''): bool|SplQueue
|
||||
{
|
||||
if (!isset(static::$_channels[$name]) || !(static::$_channels[$name] instanceof SplQueue)) {
|
||||
static::$_channels[$name] = new SplQueue();
|
||||
}
|
||||
return static::$_channels[$name];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* 清空缓存
|
||||
*/
|
||||
public function cleanAll()
|
||||
{
|
||||
/** @var SplQueue $channel */
|
||||
foreach (static::$_channels as $channel) {
|
||||
if (!($channel instanceof SplQueue)) {
|
||||
continue;
|
||||
}
|
||||
while ($channel->count() > 0) {
|
||||
$channel->dequeue();
|
||||
}
|
||||
}
|
||||
static::$_channels = [];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -73,14 +102,14 @@ class Channel extends Component
|
||||
* @param Closure $closure
|
||||
* @return mixed
|
||||
*/
|
||||
public function pop(string $name, Closure $closure): mixed
|
||||
{
|
||||
$channel = $this->channelInit($name);
|
||||
if ($channel->isEmpty()) {
|
||||
return call_user_func($closure);
|
||||
}
|
||||
return $channel->dequeue();
|
||||
}
|
||||
public function pop(string $name, Closure $closure): mixed
|
||||
{
|
||||
$channel = $this->channelInit($name);
|
||||
if ($channel->isEmpty()) {
|
||||
return call_user_func($closure);
|
||||
}
|
||||
return $channel->dequeue();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+233
-220
@@ -18,278 +18,291 @@ use Swoole\Timer;
|
||||
abstract class Crontab extends BaseObject
|
||||
{
|
||||
|
||||
const WAIT_END = 'crontab:wait:execute';
|
||||
const WAIT_END = 'crontab:wait:execute';
|
||||
|
||||
|
||||
private string $name = '';
|
||||
private string $name = '';
|
||||
|
||||
|
||||
private mixed $params = [];
|
||||
private mixed $params = [];
|
||||
|
||||
|
||||
private int $tickTime = 1;
|
||||
private int $tickTime = 1;
|
||||
|
||||
|
||||
private bool $isLoop = false;
|
||||
private bool $isLoop = false;
|
||||
|
||||
|
||||
private int $timerId = -1;
|
||||
private int $timerId = -1;
|
||||
|
||||
|
||||
private int $max_execute_number = -1;
|
||||
private int $max_execute_number = -1;
|
||||
|
||||
|
||||
private int $execute_number = 0;
|
||||
private int $execute_number = 0;
|
||||
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function increment(): static
|
||||
{
|
||||
$this->execute_number += 1;
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function increment(): static
|
||||
{
|
||||
$this->execute_number += 1;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
#[Pure] public function getName(): string
|
||||
{
|
||||
return md5($this->name);
|
||||
}
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
#[Pure] public function getName(): string
|
||||
{
|
||||
return md5($this->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getParams(): mixed
|
||||
{
|
||||
return $this->params;
|
||||
}
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getParams(): mixed
|
||||
{
|
||||
return $this->params;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getTickTime(): int
|
||||
{
|
||||
return $this->tickTime;
|
||||
}
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getTickTime(): int
|
||||
{
|
||||
return $this->tickTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isLoop(): bool
|
||||
{
|
||||
return $this->isLoop;
|
||||
}
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isLoop(): bool
|
||||
{
|
||||
return $this->isLoop;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getMaxExecuteNumber(): int
|
||||
{
|
||||
return $this->max_execute_number;
|
||||
}
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getMaxExecuteNumber(): int
|
||||
{
|
||||
return $this->max_execute_number;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getExecuteNumber(): int
|
||||
{
|
||||
return $this->execute_number;
|
||||
}
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getExecuteNumber(): int
|
||||
{
|
||||
return $this->execute_number;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*/
|
||||
public function setName(string $name): void
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
/**
|
||||
* @param string $name
|
||||
*/
|
||||
public function setName(string $name): void
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
|
||||
public function setParams(): void
|
||||
{
|
||||
$this->params = func_get_args();
|
||||
}
|
||||
public function setParams(): void
|
||||
{
|
||||
$this->params = func_get_args();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $tickTime
|
||||
*/
|
||||
public function setTickTime(int $tickTime): void
|
||||
{
|
||||
$this->tickTime = $tickTime;
|
||||
}
|
||||
/**
|
||||
* @param int $tickTime
|
||||
*/
|
||||
public function setTickTime(int $tickTime): void
|
||||
{
|
||||
$this->tickTime = $tickTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $isLoop
|
||||
*/
|
||||
public function setIsLoop(bool $isLoop): void
|
||||
{
|
||||
$this->isLoop = $isLoop;
|
||||
}
|
||||
/**
|
||||
* @param bool $isLoop
|
||||
*/
|
||||
public function setIsLoop(bool $isLoop): void
|
||||
{
|
||||
$this->isLoop = $isLoop;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $max_execute_number
|
||||
*/
|
||||
public function setMaxExecuteNumber(int $max_execute_number): void
|
||||
{
|
||||
$this->max_execute_number = $max_execute_number;
|
||||
}
|
||||
/**
|
||||
* @param int $max_execute_number
|
||||
*/
|
||||
public function setMaxExecuteNumber(int $max_execute_number): void
|
||||
{
|
||||
$this->max_execute_number = $max_execute_number;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $execute_number
|
||||
*/
|
||||
public function setExecuteNumber(int $execute_number): void
|
||||
{
|
||||
$this->execute_number = $execute_number;
|
||||
}
|
||||
/**
|
||||
* @param int $execute_number
|
||||
*/
|
||||
public function setExecuteNumber(int $execute_number): void
|
||||
{
|
||||
$this->execute_number = $execute_number;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getTimerId(): int
|
||||
{
|
||||
return $this->timerId;
|
||||
}
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getTimerId(): int
|
||||
{
|
||||
return $this->timerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $timerId
|
||||
*/
|
||||
public function setTimerId(int $timerId): void
|
||||
{
|
||||
$this->timerId = $timerId;
|
||||
}
|
||||
/**
|
||||
* @param int $timerId
|
||||
*/
|
||||
public function setTimerId(int $timerId): void
|
||||
{
|
||||
$this->timerId = $timerId;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function clearTimer()
|
||||
{
|
||||
$this->warning('crontab timer clear.');
|
||||
if (Timer::exists($this->timerId)) {
|
||||
Timer::clear($this->timerId);
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function clearTimer()
|
||||
{
|
||||
$this->warning('crontab timer clear.');
|
||||
if (Timer::exists($this->timerId)) {
|
||||
Timer::clear($this->timerId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
abstract public function process(): mixed;
|
||||
abstract public function process(): mixed;
|
||||
|
||||
abstract public function max_execute(): mixed;
|
||||
abstract public function max_execute(): mixed;
|
||||
|
||||
abstract public function isStop(): bool;
|
||||
abstract public function isStop(): bool;
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function execute(): void
|
||||
{
|
||||
defer(fn() => $this->afterExecute());
|
||||
try {
|
||||
$redis = Snowflake::app()->getRedis();
|
||||
|
||||
$name_md5 = $this->getName();
|
||||
|
||||
$redis->hSet(self::WAIT_END, $name_md5, static::getSerialize($this));
|
||||
|
||||
$params = call_user_func([$this, 'process'], ...$this->params);
|
||||
$redis->hDel(self::WAIT_END, $name_md5);
|
||||
if ($params === null) {
|
||||
return;
|
||||
}
|
||||
write(Json::encode(['name' => $this->name, 'response' => serialize($params)]), 'crontab');
|
||||
} catch (\Throwable $throwable) {
|
||||
logger()->addError($throwable, 'throwable');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param $name
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($name): mixed
|
||||
{
|
||||
if (!isset($this->params[$name])) {
|
||||
return null;
|
||||
}
|
||||
return $this->params[$name];
|
||||
}
|
||||
|
||||
|
||||
public function afterExecute()
|
||||
{
|
||||
if ($this->isRecover() !== 999) {
|
||||
return;
|
||||
}
|
||||
$redis = Snowflake::app()->getRedis();
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function execute(): void
|
||||
{
|
||||
defer(fn() => $this->afterExecute());
|
||||
try {
|
||||
$redis = Snowflake::app()->getRedis();
|
||||
|
||||
$name = $this->getName();
|
||||
if (!$redis->exists('stop:crontab:' . $name)) {
|
||||
$redis->set('crontab:' . $name, swoole_serialize($this));
|
||||
$tickTime = time() + $this->getTickTime();
|
||||
$redis->zAdd(Producer::CRONTAB_KEY, $tickTime, $name);
|
||||
} else {
|
||||
$redis->del('crontab:' . $name);
|
||||
$redis->del('stop:crontab:' . $name);
|
||||
}
|
||||
}
|
||||
$name_md5 = $this->getName();
|
||||
|
||||
$redis->hSet(self::WAIT_END, $name_md5, static::getSerialize($this));
|
||||
|
||||
$params = call_user_func([$this, 'process'], ...$this->params);
|
||||
$redis->hDel(self::WAIT_END, $name_md5);
|
||||
if ($params === null) {
|
||||
return;
|
||||
}
|
||||
write(Json::encode(['name' => $this->name, 'response' => serialize($params)]), 'crontab');
|
||||
} catch (\Throwable $throwable) {
|
||||
logger()->addError($throwable, 'throwable');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool|int
|
||||
* @throws Exception
|
||||
*/
|
||||
public function isRecover(): bool|int
|
||||
{
|
||||
try {
|
||||
$redis = Snowflake::app()->getRedis();
|
||||
if ($redis->exists('stop:crontab:' . $this->getName())) {
|
||||
$redis->del('stop:crontab:' . $this->getName());
|
||||
return true;
|
||||
}
|
||||
if ($this->isExit()) {
|
||||
return $redis->del('crontab:' . $this->getName());
|
||||
}
|
||||
if ($this->isMaxExecute()) {
|
||||
call_user_func([$this, 'max_execute'], ...$this->getParams());
|
||||
return $redis->del('crontab:' . $this->getName());
|
||||
} else {
|
||||
return 999;
|
||||
}
|
||||
} catch (\Throwable $throwable) {
|
||||
return logger()->addError($throwable, 'throwable');
|
||||
}
|
||||
}
|
||||
public function afterExecute()
|
||||
{
|
||||
if ($this->isRecover() !== 999) {
|
||||
return;
|
||||
}
|
||||
$redis = Snowflake::app()->getRedis();
|
||||
|
||||
$name = $this->getName();
|
||||
if (!$redis->exists('stop:crontab:' . $name)) {
|
||||
$redis->set('crontab:' . $name, swoole_serialize($this));
|
||||
$tickTime = time() + $this->getTickTime();
|
||||
$redis->zAdd(Producer::CRONTAB_KEY, $tickTime, $name);
|
||||
} else {
|
||||
$redis->del('crontab:' . $name);
|
||||
$redis->del('stop:crontab:' . $name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
* @return string
|
||||
*/
|
||||
public static function getSerialize($class): string
|
||||
{
|
||||
return serialize($class);
|
||||
}
|
||||
/**
|
||||
* @return bool|int
|
||||
* @throws Exception
|
||||
*/
|
||||
public function isRecover(): bool|int
|
||||
{
|
||||
try {
|
||||
$redis = Snowflake::app()->getRedis();
|
||||
if ($redis->exists('stop:crontab:' . $this->getName())) {
|
||||
$redis->del('stop:crontab:' . $this->getName());
|
||||
return true;
|
||||
}
|
||||
if ($this->isExit()) {
|
||||
return $redis->del('crontab:' . $this->getName());
|
||||
}
|
||||
if ($this->isMaxExecute()) {
|
||||
call_user_func([$this, 'max_execute'], ...$this->getParams());
|
||||
return $redis->del('crontab:' . $this->getName());
|
||||
} else {
|
||||
return 999;
|
||||
}
|
||||
} catch (\Throwable $throwable) {
|
||||
return logger()->addError($throwable, 'throwable');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function isExit(): bool
|
||||
{
|
||||
if ($this->isStop()) {
|
||||
return true;
|
||||
}
|
||||
if (!$this->isLoop) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* @param $class
|
||||
* @return string
|
||||
*/
|
||||
public static function getSerialize($class): string
|
||||
{
|
||||
return serialize($class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function isMaxExecute(): bool
|
||||
{
|
||||
if ($this->max_execute_number !== -1) {
|
||||
return $this->execute_number >= $this->max_execute_number;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function isExit(): bool
|
||||
{
|
||||
if ($this->isStop()) {
|
||||
return true;
|
||||
}
|
||||
if (!$this->isLoop) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function isMaxExecute(): bool
|
||||
{
|
||||
if ($this->max_execute_number !== -1) {
|
||||
return $this->execute_number >= $this->max_execute_number;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ use Snowflake\Snowflake;
|
||||
class Producer extends Component
|
||||
{
|
||||
|
||||
const CRONTAB_KEY = '_application:system:crontab';
|
||||
const CRONTAB_KEY = '_application:{crontab}:system:crontab';
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -118,11 +118,16 @@ class Zookeeper extends Process
|
||||
*/
|
||||
private function loadCarobTask(Redis|\Redis $redis): array
|
||||
{
|
||||
$range = $redis->zRangeByScore(Producer::CRONTAB_KEY, '0', (string)time());
|
||||
$script = <<<SCRIPT
|
||||
local _two = redis.call('zRangeByScore', KEYS[1], '0', ARGV[1])
|
||||
|
||||
$redis->zRem(Producer::CRONTAB_KEY, ...$range);
|
||||
if (table.getn(_two) > 0) then
|
||||
redis.call('ZREM', KEYS[1], unpack(_two))
|
||||
end
|
||||
|
||||
return $range;
|
||||
return _two
|
||||
SCRIPT;
|
||||
return $redis->eval($script, [Producer::CRONTAB_KEY, (string)time()], 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+115
-115
@@ -23,140 +23,140 @@ use Snowflake\Snowflake;
|
||||
class Service extends Component
|
||||
{
|
||||
|
||||
private array $_components = [];
|
||||
private array $_components = [];
|
||||
|
||||
|
||||
private array $_definition = [];
|
||||
private array $_definition = [];
|
||||
|
||||
|
||||
private array $_ids = [];
|
||||
private array $_ids = [];
|
||||
|
||||
|
||||
protected array $_alias = [];
|
||||
protected array $_alias = [];
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @param bool $try
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function get($id, $try = true): mixed
|
||||
{
|
||||
if (isset($this->_components[$id])) {
|
||||
return $this->_components[$id];
|
||||
}
|
||||
if (!isset($this->_definition[$id]) && !isset($this->_alias[$id])) {
|
||||
if ($try === false) {
|
||||
return null;
|
||||
}
|
||||
throw new ComponentException("Unknown component ID: $id");
|
||||
}
|
||||
if (isset($this->_definition[$id])) {
|
||||
$config = $this->_definition[$id];
|
||||
if (is_object($config)) {
|
||||
return $this->_components[$id] = $config;
|
||||
}
|
||||
$object = Snowflake::createObject($config);
|
||||
} else {
|
||||
$config = $this->_alias[$id];
|
||||
/**
|
||||
* @param $id
|
||||
* @param bool $try
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function get($id, $try = true): mixed
|
||||
{
|
||||
if (isset($this->_components[$id])) {
|
||||
return $this->_components[$id];
|
||||
}
|
||||
if (!isset($this->_definition[$id]) && !isset($this->_alias[$id])) {
|
||||
if ($try === false) {
|
||||
return null;
|
||||
}
|
||||
throw new ComponentException("Unknown component ID: $id");
|
||||
}
|
||||
if (isset($this->_definition[$id])) {
|
||||
$config = $this->_definition[$id];
|
||||
if (is_object($config)) {
|
||||
return $this->_components[$id] = $config;
|
||||
}
|
||||
$object = Snowflake::createObject($config);
|
||||
} else {
|
||||
$config = $this->_alias[$id];
|
||||
|
||||
$object = Snowflake::createObject($config);
|
||||
}
|
||||
return $this->_components[$id] = $object;
|
||||
}
|
||||
$object = Snowflake::createObject($config);
|
||||
}
|
||||
return $this->_components[$id] = $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $className
|
||||
* @param string $alias
|
||||
*/
|
||||
public function setAlias(string $className, string $alias)
|
||||
{
|
||||
$this->_alias[$className] = $alias;
|
||||
}
|
||||
/**
|
||||
* @param string $className
|
||||
* @param string $alias
|
||||
*/
|
||||
public function setAlias(string $className, string $alias)
|
||||
{
|
||||
$this->_alias[$className] = $alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @param $definition
|
||||
*
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function set($id, $definition): mixed
|
||||
{
|
||||
if ($definition === NULL) {
|
||||
return $this->remove($id);
|
||||
}
|
||||
/**
|
||||
* @param $id
|
||||
* @param $definition
|
||||
*
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function set($id, $definition): mixed
|
||||
{
|
||||
if ($definition === NULL) {
|
||||
return $this->remove($id);
|
||||
}
|
||||
|
||||
$this->_ids[] = $id;
|
||||
$this->_ids[] = $id;
|
||||
|
||||
unset($this->_components[$id]);
|
||||
if (is_object($definition) || is_callable($definition, TRUE)) {
|
||||
return $this->_definition[$id] = $definition;
|
||||
} else if (!is_array($definition)) {
|
||||
throw new ComponentException("Unexpected configuration type for the \"$id\" component: " . gettype($definition));
|
||||
}
|
||||
if (!isset($definition['class'])) {
|
||||
throw new ComponentException("The configuration for the \"$id\" component must contain a \"class\" element.");
|
||||
} else {
|
||||
$this->_definition[$id] = $definition;
|
||||
}
|
||||
return $this->get($id);
|
||||
}
|
||||
unset($this->_components[$id]);
|
||||
if (is_object($definition) || is_callable($definition, TRUE)) {
|
||||
return $this->_definition[$id] = $definition;
|
||||
} else if (!is_array($definition)) {
|
||||
throw new ComponentException("Unexpected configuration type for the \"$id\" component: " . gettype($definition));
|
||||
}
|
||||
if (!isset($definition['class'])) {
|
||||
throw new ComponentException("The configuration for the \"$id\" component must contain a \"class\" element.");
|
||||
} else {
|
||||
$this->_definition[$id] = $definition;
|
||||
}
|
||||
return $this->get($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @return bool
|
||||
*/
|
||||
#[Pure] public function has($id): bool
|
||||
{
|
||||
return in_array($id, $this->_ids);
|
||||
}
|
||||
/**
|
||||
* @param $id
|
||||
* @return bool
|
||||
*/
|
||||
#[Pure] public function has($id): bool
|
||||
{
|
||||
return in_array($id, $this->_ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @throws Exception
|
||||
*/
|
||||
public function setComponents(array $data)
|
||||
{
|
||||
foreach ($data as $key => $val) {
|
||||
$this->set($key, $val);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param array $data
|
||||
* @throws Exception
|
||||
*/
|
||||
public function setComponents(array $data)
|
||||
{
|
||||
foreach ($data as $key => $val) {
|
||||
$this->set($key, $val);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __get($name): mixed
|
||||
{
|
||||
if ($this->has($name)) {
|
||||
return $this->get($name);
|
||||
}
|
||||
/**
|
||||
* @param $name
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __get($name): mixed
|
||||
{
|
||||
if ($this->has($name)) {
|
||||
return $this->get($name);
|
||||
}
|
||||
|
||||
return parent::__get($name);
|
||||
}
|
||||
return parent::__get($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @return bool
|
||||
*/
|
||||
public function remove($id): bool
|
||||
{
|
||||
$component = $this->_components[$id];
|
||||
$className = $component::class;
|
||||
/**
|
||||
* @param $id
|
||||
* @return bool
|
||||
*/
|
||||
public function remove($id): bool
|
||||
{
|
||||
$component = $this->_components[$id];
|
||||
$className = $component::class;
|
||||
|
||||
unset($component, $this->_components[$id]);
|
||||
unset($this->_definition[$id]);
|
||||
if (isset($this->_alias[$id])) {
|
||||
unset($this->_components[$this->_alias[$id]]);
|
||||
unset($this->_definition[$this->_alias[$id]]);
|
||||
unset($this->_alias[$id]);
|
||||
}
|
||||
unset($component, $this->_components[$id]);
|
||||
unset($this->_definition[$id]);
|
||||
if (isset($this->_alias[$id])) {
|
||||
unset($this->_components[$this->_alias[$id]]);
|
||||
unset($this->_definition[$this->_alias[$id]]);
|
||||
unset($this->_alias[$id]);
|
||||
}
|
||||
|
||||
Snowflake::getDi()->unset($className);
|
||||
Snowflake::getDi()->unset($className);
|
||||
|
||||
return $this->has($id);
|
||||
}
|
||||
return $this->has($id);
|
||||
}
|
||||
}
|
||||
|
||||
+23
-23
@@ -39,7 +39,7 @@ class Logger extends Component
|
||||
|
||||
|
||||
/**
|
||||
* @param $message
|
||||
* @param mixed $message
|
||||
* @param string $method
|
||||
* @param null $file
|
||||
* @throws Exception
|
||||
@@ -51,18 +51,18 @@ class Logger extends Component
|
||||
|
||||
|
||||
/**
|
||||
* @param $message
|
||||
* @param mixed $message
|
||||
* @param string $method
|
||||
* @throws Exception
|
||||
*/
|
||||
public function trance($message, $method = 'app')
|
||||
public function trance(mixed $message, string $method = 'app')
|
||||
{
|
||||
$this->writer($message, $method);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $message
|
||||
* @param mixed $message
|
||||
* @param string $method
|
||||
* @param null $file
|
||||
* @throws Exception
|
||||
@@ -72,13 +72,13 @@ class Logger extends Component
|
||||
$this->writer($message, $method);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $message
|
||||
* @param string $method
|
||||
* @param null $file
|
||||
* @throws Exception
|
||||
*/
|
||||
public function success(mixed $message, $method = 'app', $file = null)
|
||||
/**
|
||||
* @param mixed $message
|
||||
* @param string $method
|
||||
* @param null $file
|
||||
* @throws Exception
|
||||
*/
|
||||
public function success(mixed $message, string $method = 'app', $file = null)
|
||||
{
|
||||
$this->writer($message, $method);
|
||||
}
|
||||
@@ -89,7 +89,7 @@ class Logger extends Component
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
private function writer($message, $method = 'app'): string
|
||||
private function writer($message, string $method = 'app'): string
|
||||
{
|
||||
$this->print_r($message, $method);
|
||||
if ($message instanceof Throwable) {
|
||||
@@ -114,10 +114,10 @@ class Logger extends Component
|
||||
|
||||
/**
|
||||
* @param $message
|
||||
* @param $method
|
||||
* @param string $method
|
||||
* @throws Exception
|
||||
*/
|
||||
public function print_r($message, $method = '')
|
||||
public function print_r($message, string $method = '')
|
||||
{
|
||||
$debug = Config::get('debug', ['enable' => false]);
|
||||
if ((bool)$debug['enable'] === true) {
|
||||
@@ -145,7 +145,7 @@ class Logger extends Component
|
||||
* @param string $application
|
||||
* @return mixed
|
||||
*/
|
||||
public function getLastError($application = 'app'): mixed
|
||||
public function getLastError(string $application = 'app'): mixed
|
||||
{
|
||||
$filetype = [];
|
||||
foreach ($this->logs as $key => $val) {
|
||||
@@ -160,15 +160,15 @@ class Logger extends Component
|
||||
return end($filetype);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $messages
|
||||
* @param string $method
|
||||
* @throws
|
||||
*/
|
||||
public function write(string $messages, $method = 'app')
|
||||
/**
|
||||
* @param string $messages
|
||||
* @param string $method
|
||||
* @throws Exception
|
||||
*/
|
||||
public function write(string $messages, string $method = 'app')
|
||||
{
|
||||
if (empty($messages)) {
|
||||
return;
|
||||
return;
|
||||
if (empty($messages)) {
|
||||
}
|
||||
|
||||
$fileName = 'server-' . date('Y-m-d') . '.log';
|
||||
|
||||
+414
-394
@@ -5,11 +5,12 @@ namespace Snowflake\Jwt;
|
||||
|
||||
use Exception;
|
||||
use HttpServer\Http\HttpHeaders;
|
||||
use Snowflake\Cache\Redis;
|
||||
use Snowflake\Abstracts\Component;
|
||||
use Snowflake\Abstracts\Config;
|
||||
use Snowflake\Cache\Redis;
|
||||
use Snowflake\Core\Json;
|
||||
use Snowflake\Core\Str;
|
||||
use Snowflake\Exception\AuthException;
|
||||
use Snowflake\Abstracts\Component;
|
||||
use Snowflake\Exception\ConfigException;
|
||||
use Snowflake\Snowflake;
|
||||
|
||||
@@ -21,20 +22,20 @@ use Snowflake\Snowflake;
|
||||
class Jwt extends Component
|
||||
{
|
||||
|
||||
/** @var int $user */
|
||||
private int $user;
|
||||
/** @var int $user */
|
||||
private int $user;
|
||||
|
||||
private array $data;
|
||||
private array $data;
|
||||
|
||||
private array $source = ['browser', 'android', 'iphone', 'pc', 'mingame'];
|
||||
private array $source = ['browser', 'android', 'iphone', 'pc', 'mingame'];
|
||||
|
||||
private array $config = ['token' => ''];
|
||||
private array $config = ['token' => ''];
|
||||
|
||||
private ?int $timeout = 7200;
|
||||
private ?int $timeout = 7200;
|
||||
|
||||
private string $key = 'www.xshucai.com';
|
||||
private string $key = 'www.xshucai.com';
|
||||
|
||||
private ?string $public = '-----BEGIN PUBLIC KEY-----
|
||||
private ?string $public = '-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6BuML3gtLGde7QKNuNST
|
||||
UCB9gdHC7XIpOc7Wx2I64Esj3UxWHTgp3URj0ge8zpy7A3FfBdppR7d1nwoD6Xad
|
||||
jqfjEWpTy4WwGYsOfH0tFl3wAmse0lebF4NFsS9pzrikQT6c9qsVm88pCjvg4i5t
|
||||
@@ -44,7 +45,7 @@ WlQhpQrA5/wKd76dCzjvqw9M32OiZl2lCKT73cV8GUvt7BNsM1SiPhqfY7nhO6y3
|
||||
cwIDAQAB
|
||||
-----END PUBLIC KEY-----';
|
||||
|
||||
private ?string $private = '-----BEGIN RSA PRIVATE KEY-----
|
||||
private ?string $private = '-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpQIBAAKCAQEA6BuML3gtLGde7QKNuNSTUCB9gdHC7XIpOc7Wx2I64Esj3UxW
|
||||
HTgp3URj0ge8zpy7A3FfBdppR7d1nwoD6XadjqfjEWpTy4WwGYsOfH0tFl3wAmse
|
||||
0lebF4NFsS9pzrikQT6c9qsVm88pCjvg4i5tWhTMEnpTFDYoDR0KXlLXltQMudBB
|
||||
@@ -73,419 +74,438 @@ mlAZUEjsoaT9vjvjGTxl3uCm0TX5KTgtSJIt2kA1tYVjQef+/iZTHxY=
|
||||
-----END RSA PRIVATE KEY-----';
|
||||
|
||||
|
||||
/**
|
||||
* @throws ConfigException
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
if (!Config::has('ssl.public') || !Config::has('ssl.private')) {
|
||||
return;
|
||||
}
|
||||
$this->public = Config::get('ssl.public', $this->public);
|
||||
$this->private = Config::get('ssl.private', $this->private);
|
||||
$this->timeout = Config::get('ssl.timeout', 7200);
|
||||
}
|
||||
/**
|
||||
* @throws ConfigException
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
if (!Config::has('ssl.public') || !Config::has('ssl.private')) {
|
||||
return;
|
||||
}
|
||||
$this->public = Config::get('ssl.public', $this->public);
|
||||
$this->private = Config::get('ssl.private', $this->private);
|
||||
$this->timeout = Config::get('ssl.timeout', 7200);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $publicKey
|
||||
*/
|
||||
public function setPublic(string $publicKey)
|
||||
{
|
||||
$this->public = $publicKey;
|
||||
}
|
||||
/**
|
||||
* @param string $publicKey
|
||||
*/
|
||||
public function setPublic(string $publicKey)
|
||||
{
|
||||
$this->public = $publicKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $timeout
|
||||
*/
|
||||
public function setTimeout(int $timeout)
|
||||
{
|
||||
$this->timeout = $timeout;
|
||||
}
|
||||
/**
|
||||
* @param int $timeout
|
||||
*/
|
||||
public function setTimeout(int $timeout)
|
||||
{
|
||||
$this->timeout = $timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $timeout
|
||||
*/
|
||||
public function setKey(string $timeout)
|
||||
{
|
||||
$this->key = $timeout;
|
||||
}
|
||||
/**
|
||||
* @param string $timeout
|
||||
*/
|
||||
public function setKey(string $timeout)
|
||||
{
|
||||
$this->key = $timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $privateKey
|
||||
*/
|
||||
public function setPrivate(string $privateKey)
|
||||
{
|
||||
$this->private = $privateKey;
|
||||
}
|
||||
/**
|
||||
* @param string $privateKey
|
||||
*/
|
||||
public function setPrivate(string $privateKey)
|
||||
{
|
||||
$this->private = $privateKey;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $unionId
|
||||
* @param array $headers
|
||||
*
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function create(int $unionId, $headers = []): array
|
||||
{
|
||||
$this->user = $unionId;
|
||||
$this->config['time'] = time();
|
||||
if (empty($headers)) {
|
||||
$headers = request()->headers->getHeaders();
|
||||
} else if ($headers instanceof HttpHeaders) {
|
||||
$headers = $headers->getHeaders();
|
||||
}
|
||||
$this->data = $headers;
|
||||
if (!isset($this->data['source'])) {
|
||||
$this->data['source'] = 'browser';
|
||||
}
|
||||
return $this->createEncrypt($unionId);
|
||||
}
|
||||
/**
|
||||
* @param int $unionId
|
||||
* @param array $headers
|
||||
*
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function create(int $unionId, array $headers = []): array
|
||||
{
|
||||
$this->user = $unionId;
|
||||
$this->config['time'] = time();
|
||||
if (empty($headers)) {
|
||||
$headers = request()->headers->getHeaders();
|
||||
} else if ($headers instanceof HttpHeaders) {
|
||||
$headers = $headers->getHeaders();
|
||||
}
|
||||
$this->data = $headers;
|
||||
if (!isset($this->data['source'])) {
|
||||
$this->data['source'] = 'browser';
|
||||
}
|
||||
return $this->createEncrypt($unionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $unionId
|
||||
* @return array
|
||||
* @throws Exception
|
||||
* 对相关信息进行加密
|
||||
*/
|
||||
private function createEncrypt($unionId): array
|
||||
{
|
||||
$caches = $this->clear($unionId);
|
||||
$param = $this->assembly(array_merge($this->config, [
|
||||
'user' => $unionId,
|
||||
'token' => $this->token($unionId, [
|
||||
'device' => Str::rand(128),
|
||||
], $this->config['time']),
|
||||
]), TRUE);
|
||||
$refresh = array_intersect_key($param, $this->config);
|
||||
/**
|
||||
* @param $unionId
|
||||
* @return array
|
||||
* @throws Exception
|
||||
* 对相关信息进行加密
|
||||
*/
|
||||
private function createEncrypt($unionId): array
|
||||
{
|
||||
$caches = $this->clear($unionId);
|
||||
$param = $this->assembly(array_merge($this->config, [
|
||||
'user' => $unionId,
|
||||
'token' => $this->token($unionId, [
|
||||
'device' => Str::rand(128),
|
||||
], $this->config['time']),
|
||||
]), TRUE);
|
||||
$refresh = array_intersect_key($param, $this->config);
|
||||
|
||||
$params['user'] = $this->user;
|
||||
$params['token'] = $refresh['token'];
|
||||
$json = json_encode($params, JSON_NUMERIC_CHECK | JSON_UNESCAPED_UNICODE);
|
||||
$params['user'] = $this->user;
|
||||
$params['token'] = $refresh['token'];
|
||||
$json = json_encode($params, JSON_NUMERIC_CHECK | JSON_UNESCAPED_UNICODE);
|
||||
|
||||
openssl_private_encrypt($json, $encode, $this->private);
|
||||
$refresh['refresh'] = base64_encode($encode);
|
||||
$this->setRefresh($refresh['refresh']);
|
||||
openssl_private_encrypt($json, $encode, $this->private);
|
||||
$refresh['refresh'] = base64_encode($encode);
|
||||
$this->setRefresh($refresh['refresh']);
|
||||
|
||||
$redis = $this->getRedis();
|
||||
foreach ($caches as $cache) {
|
||||
$redis->del($cache);
|
||||
}
|
||||
return $refresh;
|
||||
}
|
||||
$redis = $this->getRedis();
|
||||
foreach ($caches as $cache) {
|
||||
$redis->del($cache);
|
||||
}
|
||||
return $refresh;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $update
|
||||
* @param array $param
|
||||
* @return array
|
||||
* @throws
|
||||
*/
|
||||
private function assembly(array $param, $update = FALSE): array
|
||||
{
|
||||
if (isset($param['sign'])) {
|
||||
unset($param['sign']);
|
||||
}
|
||||
$param = $this->initialize($param);
|
||||
asort($param, SORT_STRING);
|
||||
$_tmp = [];
|
||||
foreach ($param as $key => $val) {
|
||||
$_tmp[] = trim($key) . '=>' . trim((string)$val);
|
||||
}
|
||||
$param['sign'] = md5(implode(':', $_tmp));
|
||||
if ($update) {
|
||||
$this->setCache($param);
|
||||
}
|
||||
return $param;
|
||||
}
|
||||
/**
|
||||
* @param bool $update
|
||||
* @param array $param
|
||||
* @return array
|
||||
* @throws
|
||||
*/
|
||||
private function assembly(array $param, bool $update = FALSE): array
|
||||
{
|
||||
if (isset($param['sign'])) {
|
||||
unset($param['sign']);
|
||||
}
|
||||
$param = $this->initialize($param);
|
||||
asort($param, SORT_STRING);
|
||||
$_tmp = [];
|
||||
foreach ($param as $key => $val) {
|
||||
$_tmp[] = trim($key) . '=>' . trim((string)$val);
|
||||
}
|
||||
$param['sign'] = md5(implode(':', $_tmp));
|
||||
if ($update) {
|
||||
$this->setCache($param);
|
||||
}
|
||||
return $param;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $headers
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function refresh($headers = []): array
|
||||
{
|
||||
$this->data = $headers;
|
||||
if (!openssl_public_decrypt(base64_decode($headers['refresh']), $data, $this->public)) {
|
||||
throw new AuthException('信息解码失败.');
|
||||
}
|
||||
/**
|
||||
* @param array $headers
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function refresh(array $headers = []): array
|
||||
{
|
||||
$this->data = $headers;
|
||||
if (!openssl_public_decrypt(base64_decode($headers['refresh']), $data, $this->public)) {
|
||||
throw new AuthException('信息解码失败.');
|
||||
}
|
||||
|
||||
$this->user = $data['user'];
|
||||
$this->user = $data['user'];
|
||||
|
||||
if (!$this->getRedis()->exists('refresh:' . $this->user)) {
|
||||
throw new AuthException('refresh data error.');
|
||||
}
|
||||
if (!$this->getRedis()->exists('refresh:' . $this->user)) {
|
||||
throw new AuthException('refresh data error.');
|
||||
}
|
||||
|
||||
$this->getRedis()->del('refresh:' . $this->user);
|
||||
$this->getRedis()->del('refresh:' . $this->user);
|
||||
|
||||
return $this->create($this->user, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $param
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function initialize(array $param): array
|
||||
{
|
||||
$_param = [
|
||||
'version' => '1',
|
||||
'source' => $this->getSource(),
|
||||
];
|
||||
if (!isset($param['device'])) {
|
||||
$param['device'] = Str::rand(128);
|
||||
}
|
||||
return array_merge($_param, $param);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @throws Exception
|
||||
*/
|
||||
private function setCache(array $data)
|
||||
{
|
||||
$redis = $this->getRedis();
|
||||
$redis->hMset($this->authKey($this->getSource(), $data['token']), $data);
|
||||
$redis->expire($this->authKey($this->getSource(), $data['token']), $this->timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refresh
|
||||
* @throws Exception
|
||||
*/
|
||||
private function setRefresh(string $refresh)
|
||||
{
|
||||
$redis = $this->getRedis();
|
||||
|
||||
$redis->set('refresh:' . $this->user, $refresh);
|
||||
$redis->expire('refresh:' . $this->user, $this->timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $_source
|
||||
* @param string $token
|
||||
*
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
private function authKey(string $_source, string $token): string
|
||||
{
|
||||
$source = $this->getSource();
|
||||
if (!empty($_source)) $source = $_source;
|
||||
|
||||
return 'Tmp_Token:' . strtoupper($source) . ':' . $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSource(): string
|
||||
{
|
||||
return $this->data['source'] ?? 'browser';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $user
|
||||
* @param array $param
|
||||
* @param null $requestTime
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function token(int $user, $param = [], $requestTime = NULL): string
|
||||
{
|
||||
$str = '';
|
||||
|
||||
$user = (string)$user;
|
||||
$_user = str_split(md5($user . md5($user)));
|
||||
ksort($_user);
|
||||
foreach ($_user as $key => $val) {
|
||||
$str .= md5(sha1($key . $val . $this->key));
|
||||
}
|
||||
foreach ($param as $key => $val) {
|
||||
$str .= md5($str . sha1($key . md5($val)));
|
||||
}
|
||||
$str .= sha1(base64_encode((string)$requestTime));
|
||||
return $this->preg(md5($str . $user));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $str
|
||||
*
|
||||
* @return array|string|null 将字符串替换成指定格式
|
||||
*/
|
||||
private function preg(string $str): null|array|string
|
||||
{
|
||||
return preg_replace('/(\w{10})(\w{3})(\w{4})(\w{9})(\w{6})/', '$1-$2-$3-$4-$5', $str);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $user
|
||||
* @return string[]
|
||||
* @throws Exception
|
||||
*/
|
||||
public function clear(int $user): array
|
||||
{
|
||||
$this->user = $user;
|
||||
$redis = $this->getRedis();
|
||||
if (is_bool($refresh = $redis->get('refresh:' . $this->user))) {
|
||||
return [];
|
||||
};
|
||||
openssl_public_decrypt(base64_decode($refresh), $info, $this->public);
|
||||
|
||||
$_tmp = [];
|
||||
if (!empty($info) && $json = json_decode($info, true)) {
|
||||
if (!isset($json['token'])) {
|
||||
return [];
|
||||
}
|
||||
foreach ($this->source as $value) {
|
||||
$_tmp[] = $this->authKey($value, $json['token']);
|
||||
}
|
||||
}
|
||||
return $_tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param int $user
|
||||
* @return bool
|
||||
* @throws AuthException
|
||||
*/
|
||||
public function check(array $data, int $user): bool
|
||||
{
|
||||
$this->data = $data;
|
||||
$this->user = $user;
|
||||
|
||||
if (empty($this->user)) return FALSE;
|
||||
$cache = $this->getUserModel();
|
||||
if (empty($cache)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$merge = $this->assembly(array_merge($cache, [
|
||||
'token' => $data['token'],
|
||||
]));
|
||||
$check = array_diff_assoc($this->initialize($cache), $merge);
|
||||
return !((bool)count($check));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @throws
|
||||
*/
|
||||
public function getCurrentOnlineUser(): int
|
||||
{
|
||||
$this->data = request()->headers->getHeaders();
|
||||
|
||||
return $this->loadByCache();
|
||||
}
|
||||
return $this->create($this->user, $headers);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $token
|
||||
* @param string $source
|
||||
* @return mixed
|
||||
* @throws AuthException
|
||||
*/
|
||||
public function getOnlineUserByToken(string $token, string $source = 'BROWSER'): int
|
||||
{
|
||||
$this->data['token'] = $token;
|
||||
$this->data['source'] = $source;
|
||||
/**
|
||||
* @param array $headers
|
||||
* @return mixed
|
||||
* @throws AuthException
|
||||
*/
|
||||
public function getTokenUser(array $headers = []): int
|
||||
{
|
||||
$this->data = $headers;
|
||||
if (!openssl_public_decrypt(base64_decode($headers['refresh']), $data, $this->public)) {
|
||||
throw new AuthException('信息解码失败.');
|
||||
}
|
||||
|
||||
return $this->loadByCache();
|
||||
}
|
||||
$data = Json::decode($data, true);
|
||||
|
||||
return (int)$data['user'];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return int
|
||||
* @throws AuthException
|
||||
* @throws Exception
|
||||
*/
|
||||
private function loadByCache(): int
|
||||
{
|
||||
$model = $this->getUserModel();
|
||||
if (empty($model)) {
|
||||
return (int)$this->addError('授权信息已过期!');
|
||||
}
|
||||
if (!isset($model['user'])) {
|
||||
return (int)$this->addError('授权信息错误!');
|
||||
}
|
||||
if (!$this->check($this->data, (int)$model['user'])) {
|
||||
return (int)$this->addError('授权信息不合法!');
|
||||
}
|
||||
/**
|
||||
* @param array $param
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function initialize(array $param): array
|
||||
{
|
||||
$_param = [
|
||||
'version' => '1',
|
||||
'source' => $this->getSource(),
|
||||
];
|
||||
if (!isset($param['device'])) {
|
||||
$param['device'] = Str::rand(128);
|
||||
}
|
||||
return array_merge($_param, $param);
|
||||
}
|
||||
|
||||
$this->expireRefresh();
|
||||
/**
|
||||
* @param array $data
|
||||
* @throws Exception
|
||||
*/
|
||||
private function setCache(array $data)
|
||||
{
|
||||
$redis = $this->getRedis();
|
||||
$redis->hMset($this->authKey($this->getSource(), $data['token']), $data);
|
||||
$redis->expire($this->authKey($this->getSource(), $data['token']), $this->timeout);
|
||||
}
|
||||
|
||||
return (int)$model['user'];
|
||||
}
|
||||
/**
|
||||
* @param string $refresh
|
||||
* @throws Exception
|
||||
*/
|
||||
private function setRefresh(string $refresh)
|
||||
{
|
||||
$redis = $this->getRedis();
|
||||
|
||||
$redis->set('refresh:' . $this->user, $refresh);
|
||||
$redis->expire('refresh:' . $this->user, $this->timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $_source
|
||||
* @param string $token
|
||||
*
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
private function authKey(string $_source, string $token): string
|
||||
{
|
||||
$source = $this->getSource();
|
||||
if (!empty($_source)) $source = $_source;
|
||||
|
||||
return 'Tmp_Token:' . strtoupper($source) . ':' . $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSource(): string
|
||||
{
|
||||
return $this->data['source'] ?? 'browser';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $user
|
||||
* @param array $param
|
||||
* @param null $requestTime
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function token(int $user, array $param = [], $requestTime = NULL): string
|
||||
{
|
||||
$str = '';
|
||||
|
||||
$user = (string)$user;
|
||||
$_user = str_split(md5($user . md5($user)));
|
||||
ksort($_user);
|
||||
foreach ($_user as $key => $val) {
|
||||
$str .= md5(sha1($key . $val . $this->key));
|
||||
}
|
||||
foreach ($param as $key => $val) {
|
||||
$str .= md5($str . sha1($key . md5($val)));
|
||||
}
|
||||
$str .= sha1(base64_encode((string)$requestTime));
|
||||
return $this->preg(md5($str . $user));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $str
|
||||
*
|
||||
* @return array|string|null 将字符串替换成指定格式
|
||||
*/
|
||||
private function preg(string $str): null|array|string
|
||||
{
|
||||
return preg_replace('/(\w{10})(\w{3})(\w{4})(\w{9})(\w{6})/', '$1-$2-$3-$4-$5', $str);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $user
|
||||
* @return string[]
|
||||
* @throws Exception
|
||||
*/
|
||||
public function clear(int $user): array
|
||||
{
|
||||
$this->user = $user;
|
||||
$redis = $this->getRedis();
|
||||
if (is_bool($refresh = $redis->get('refresh:' . $this->user))) {
|
||||
return [];
|
||||
};
|
||||
openssl_public_decrypt(base64_decode($refresh), $info, $this->public);
|
||||
|
||||
$_tmp = [];
|
||||
if (!empty($info) && $json = json_decode($info, true)) {
|
||||
if (!isset($json['token'])) {
|
||||
return [];
|
||||
}
|
||||
foreach ($this->source as $value) {
|
||||
$_tmp[] = $this->authKey($value, $json['token']);
|
||||
}
|
||||
}
|
||||
return $_tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param int $user
|
||||
* @return bool
|
||||
* @throws AuthException|Exception
|
||||
*/
|
||||
public function check(array $data, int $user): bool
|
||||
{
|
||||
$this->data = $data;
|
||||
$this->user = $user;
|
||||
|
||||
if (empty($this->user)) return FALSE;
|
||||
$cache = $this->getUserModel();
|
||||
if (empty($cache)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$merge = $this->assembly(array_merge($cache, [
|
||||
'token' => $data['token'],
|
||||
]));
|
||||
$check = array_diff_assoc($this->initialize($cache), $merge);
|
||||
return !((bool)count($check));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @throws
|
||||
*/
|
||||
public function getCurrentOnlineUser(): int
|
||||
{
|
||||
$this->data = request()->headers->getHeaders();
|
||||
|
||||
return $this->loadByCache();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $header
|
||||
* @return mixed
|
||||
* @throws AuthException
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function checkAuth(array $header = []): mixed
|
||||
{
|
||||
$instance = Snowflake::app()->getJwt();
|
||||
if (empty($header)) {
|
||||
$header = request()->headers->getHeaders();
|
||||
}
|
||||
/**
|
||||
* @param string $token
|
||||
* @param string $source
|
||||
* @return mixed
|
||||
* @throws AuthException
|
||||
*/
|
||||
public function getOnlineUserByToken(string $token, string $source = 'BROWSER'): int
|
||||
{
|
||||
$this->data['token'] = $token;
|
||||
$this->data['source'] = $source;
|
||||
|
||||
$instance->data = $header;
|
||||
$model = $instance->getUserModel();
|
||||
if (empty($model) || !isset($model['user'])) {
|
||||
return false;
|
||||
}
|
||||
return $this->loadByCache();
|
||||
}
|
||||
|
||||
if (!$instance->check($header, (int)$model['user'])) {
|
||||
return false;
|
||||
}
|
||||
$instance->expireRefresh();
|
||||
return $model['user'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null $token
|
||||
* @param null $source
|
||||
* @throws Exception
|
||||
*/
|
||||
public function expireRefresh($token = null, $source = null)
|
||||
{
|
||||
if (!empty($token)) {
|
||||
$this->data['token'] = $token;
|
||||
}
|
||||
if (!empty($source)) {
|
||||
$this->data['source'] = $source;
|
||||
}
|
||||
if (!isset($this->data['token'])) {
|
||||
return;
|
||||
}
|
||||
$key = $this->authKey($this->getSource(), $this->data['token']);
|
||||
$this->getRedis()->expire($key, $this->timeout);
|
||||
}
|
||||
/**
|
||||
* @return int
|
||||
* @throws AuthException
|
||||
* @throws Exception
|
||||
*/
|
||||
private function loadByCache(): int
|
||||
{
|
||||
$model = $this->getUserModel();
|
||||
if (empty($model)) {
|
||||
return (int)$this->addError('授权信息已过期!');
|
||||
}
|
||||
if (!isset($model['user'])) {
|
||||
return (int)$this->addError('授权信息错误!');
|
||||
}
|
||||
if (!$this->check($this->data, (int)$model['user'])) {
|
||||
return (int)$this->addError('授权信息不合法!');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool|array
|
||||
* @throws Exception
|
||||
*/
|
||||
private function getUserModel(): bool|array
|
||||
{
|
||||
if (!isset($this->data['token'])) {
|
||||
return $this->addError('暂无访问权限!');
|
||||
}
|
||||
$key = $this->authKey($this->getSource(), $this->data['token']);
|
||||
return $this->getRedis()->hGetAll($key);
|
||||
}
|
||||
$this->expireRefresh();
|
||||
|
||||
/**
|
||||
* @return Redis|\Redis
|
||||
* @throws
|
||||
*/
|
||||
private function getRedis(): Redis|\Redis
|
||||
{
|
||||
return Snowflake::app()->getRedis();
|
||||
}
|
||||
return (int)$model['user'];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $header
|
||||
* @return mixed
|
||||
* @throws AuthException
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function checkAuth(array $header = []): mixed
|
||||
{
|
||||
$instance = Snowflake::app()->getJwt();
|
||||
if (empty($header)) {
|
||||
$header = request()->headers->getHeaders();
|
||||
}
|
||||
|
||||
$instance->data = $header;
|
||||
$model = $instance->getUserModel();
|
||||
if (empty($model) || !isset($model['user'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$instance->check($header, (int)$model['user'])) {
|
||||
return false;
|
||||
}
|
||||
$instance->expireRefresh();
|
||||
return $model['user'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null $token
|
||||
* @param null $source
|
||||
* @throws Exception
|
||||
*/
|
||||
public function expireRefresh($token = null, $source = null)
|
||||
{
|
||||
if (!empty($token)) {
|
||||
$this->data['token'] = $token;
|
||||
}
|
||||
if (!empty($source)) {
|
||||
$this->data['source'] = $source;
|
||||
}
|
||||
if (!isset($this->data['token'])) {
|
||||
return;
|
||||
}
|
||||
$key = $this->authKey($this->getSource(), $this->data['token']);
|
||||
$this->getRedis()->expire($key, $this->timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool|array
|
||||
* @throws Exception
|
||||
*/
|
||||
private function getUserModel(): bool|array
|
||||
{
|
||||
if (!isset($this->data['token'])) {
|
||||
return $this->addError('暂无访问权限!');
|
||||
}
|
||||
$key = $this->authKey($this->getSource(), $this->data['token']);
|
||||
return $this->getRedis()->hGetAll($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Redis|\Redis
|
||||
* @throws
|
||||
*/
|
||||
private function getRedis(): Redis|\Redis
|
||||
{
|
||||
return Snowflake::app()->getRedis();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,332 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Snowflake\Pool;
|
||||
|
||||
|
||||
use Exception;
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use Snowflake\Abstracts\Component;
|
||||
use Snowflake\Abstracts\Config;
|
||||
use Snowflake\Exception\ConfigException;
|
||||
use Snowflake\Snowflake;
|
||||
use Swoole\Coroutine;
|
||||
use Swoole\Coroutine\Channel;
|
||||
use Swoole\Timer;
|
||||
|
||||
|
||||
/**
|
||||
* Class ClientsPool
|
||||
* @package Snowflake\Pool
|
||||
*/
|
||||
class ClientsPool extends Component
|
||||
{
|
||||
|
||||
/** @var Channel[] */
|
||||
private static array $_connections = [];
|
||||
|
||||
public int $max = 60;
|
||||
|
||||
public int $creates = -1;
|
||||
|
||||
|
||||
private array $_times = [];
|
||||
|
||||
protected static array $hasCreate = [];
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*/
|
||||
public function increment(string $name)
|
||||
{
|
||||
if (!isset(static::$hasCreate[$name])) {
|
||||
static::$hasCreate[$name] = 0;
|
||||
}
|
||||
static::$hasCreate[$name] += 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*/
|
||||
public function decrement(string $name)
|
||||
{
|
||||
if (!isset(static::$hasCreate[$name])) {
|
||||
return;
|
||||
}
|
||||
if (static::$hasCreate[$name] <= 0) {
|
||||
return;
|
||||
}
|
||||
static::$hasCreate[$name] -= 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @throws ConfigException
|
||||
*/
|
||||
private function getClearTime(): array
|
||||
{
|
||||
$firstClear = Config::get('pool.clear.start', 600);
|
||||
$lastClear = Config::get('pool.clear.end', 300);
|
||||
return [$firstClear, $lastClear];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function Heartbeat_detection($ticker)
|
||||
{
|
||||
if (env('state') == 'exit') {
|
||||
Timer::clear($this->creates);
|
||||
foreach (static::$_connections as $channel) {
|
||||
$this->flush($channel, 0);
|
||||
$channel->close();
|
||||
}
|
||||
static::$_connections = [];
|
||||
$this->creates = -1;
|
||||
} else {
|
||||
$this->heartbeat_flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
private function heartbeat_flush()
|
||||
{
|
||||
$num = [];
|
||||
$total = 0;
|
||||
$min = Config::get('databases.pool.min', 1);
|
||||
foreach (static::$_connections as $key => $channel) {
|
||||
if (!isset($num[$key])) {
|
||||
$num[$key] = 0;
|
||||
}
|
||||
if (time() - ($this->_times[$key] ?? time()) > 120) {
|
||||
$this->flush($channel, 0);
|
||||
} else if ($channel->length() > $min) {
|
||||
$this->flush($channel, $min);
|
||||
}
|
||||
$num[$key] += ($length = $channel->length());
|
||||
if (str_starts_with($key, 'Mysql') && (Snowflake::isWorker() || Snowflake::isTask()) && $length > 0) {
|
||||
$this->debug('Worker #' . env('worker') . ' use client -> ' . $key . ':' . $length);
|
||||
}
|
||||
$total += $length;
|
||||
}
|
||||
write(var_export($num, true), 'connections');
|
||||
if ($total < 1) {
|
||||
Timer::clear($this->creates);
|
||||
if (Snowflake::isWorker() || Snowflake::isTask()) {
|
||||
$this->debug('Worker #' . env('worker') . ' clear time tick.');
|
||||
}
|
||||
$this->creates = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $channel
|
||||
* @param $retain_number
|
||||
* @throws Exception
|
||||
*/
|
||||
public function flush($channel, $retain_number)
|
||||
{
|
||||
$this->pop($channel, $retain_number);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Channel $channel
|
||||
* @param $retain_number
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function pop(Channel $channel, $retain_number): void
|
||||
{
|
||||
if (Coroutine::getCid() === -1) {
|
||||
return;
|
||||
}
|
||||
while ($channel->length() > $retain_number) {
|
||||
$connection = $channel->pop();
|
||||
if ($connection) {
|
||||
unset($connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param false $isMaster
|
||||
* @param int $max
|
||||
*/
|
||||
public function initConnections($name, bool $isMaster = false, int $max = 60)
|
||||
{
|
||||
$name = $this->name($name, $isMaster);
|
||||
if (isset(static::$_connections[$name]) && static::$_connections[$name] instanceof Channel) {
|
||||
return;
|
||||
}
|
||||
if (Coroutine::getCid() === -1) {
|
||||
return;
|
||||
}
|
||||
if ($this->creates === -1) {
|
||||
$this->creates = Timer::tick(60000, [$this, 'Heartbeat_detection']);
|
||||
}
|
||||
static::$_connections[$name] = new Channel($max);
|
||||
$this->max = $max;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return Channel
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
private function getChannel($name): Channel
|
||||
{
|
||||
if (!isset(static::$_connections[$name])) {
|
||||
static::$_connections[$name] = new Channel(Config::get('databases.pool.max', 10));
|
||||
}
|
||||
if (static::$_connections[$name]->errCode == SWOOLE_CHANNEL_CLOSED){
|
||||
throw new Exception('Channel is Close.');
|
||||
}
|
||||
if ($this->creates === -1) {
|
||||
$this->creates = Timer::tick(60000, [$this, 'Heartbeat_detection']);
|
||||
}
|
||||
return static::$_connections[$name];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getFromChannel($name): mixed
|
||||
{
|
||||
$this->_times[$name] = time();
|
||||
$channel = $this->getChannel($name);
|
||||
if (!$channel->isEmpty()) {
|
||||
$connection = $channel->pop();
|
||||
if ($this->checkCanUse($name, $connection)) {
|
||||
return $connection;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $cds
|
||||
* @param false $isMaster
|
||||
* @return string
|
||||
*/
|
||||
#[Pure] public function name($cds, bool $isMaster = false): string
|
||||
{
|
||||
if ($isMaster === true) {
|
||||
return $cds . '_master';
|
||||
} else {
|
||||
return $cds . '_slave';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param mixed $client
|
||||
* @return bool
|
||||
* 检查连接可靠性
|
||||
*/
|
||||
public function checkCanUse(string $name, mixed $client): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $config
|
||||
* @param bool $isMaster
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function get(mixed $config, bool $isMaster): mixed
|
||||
{
|
||||
throw new Exception('Undefined system processing function.');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function hasItem(string $name): bool
|
||||
{
|
||||
if (isset(static::$_connections[$name])) {
|
||||
return !static::$_connections[$name]->isEmpty();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
*/
|
||||
public function size(string $name): mixed
|
||||
{
|
||||
if (Coroutine::getCid() === -1) {
|
||||
return 0;
|
||||
}
|
||||
if (!isset(static::$_connections[$name])) {
|
||||
return 0;
|
||||
}
|
||||
return static::$_connections[$name]->length();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param mixed $client
|
||||
* @throws ConfigException
|
||||
*/
|
||||
public function push(string $name, mixed $client)
|
||||
{
|
||||
if (Coroutine::getCid() === -1) {
|
||||
return;
|
||||
}
|
||||
$channel = $this->getChannel($name);
|
||||
if (!$channel->isFull()) {
|
||||
$channel->push($client);
|
||||
}
|
||||
unset($client);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @throws Exception
|
||||
*/
|
||||
public function clean(string $name)
|
||||
{
|
||||
if (Coroutine::getCid() === -1 || !isset(static::$_connections[$name])) {
|
||||
return;
|
||||
}
|
||||
$channel = static::$_connections[$name];
|
||||
$this->pop($channel, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Channel[]
|
||||
*/
|
||||
protected function getChannels(): array
|
||||
{
|
||||
return static::$_connections;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+63
-50
@@ -6,7 +6,8 @@ namespace Snowflake\Pool;
|
||||
use Exception;
|
||||
use HttpServer\Http\Context;
|
||||
use PDO;
|
||||
use Snowflake\Abstracts\Pool;
|
||||
use Snowflake\Abstracts\Component;
|
||||
use Snowflake\Snowflake;
|
||||
use Swoole\Coroutine;
|
||||
use Swoole\Error;
|
||||
use Swoole\Runtime;
|
||||
@@ -16,51 +17,36 @@ use Throwable;
|
||||
* Class Connection
|
||||
* @package Snowflake\Pool
|
||||
*/
|
||||
class Connection extends Pool
|
||||
class Connection extends Component
|
||||
{
|
||||
|
||||
private ?ClientsPool $clientsPool = null;
|
||||
|
||||
public int $timeout = 1900;
|
||||
|
||||
/**
|
||||
* @param $timeout
|
||||
*/
|
||||
public function setTimeout($timeout)
|
||||
{
|
||||
$this->timeout = $timeout;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
*/
|
||||
public function setLength($value)
|
||||
{
|
||||
$this->max = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $cds
|
||||
* @return bool
|
||||
*
|
||||
* db is in transaction
|
||||
* @throws Exception
|
||||
*/
|
||||
public function inTransaction($cds): bool
|
||||
{
|
||||
return Context::getContext('begin_' . $this->name('mysql', $cds, true)) == 0;
|
||||
return Context::getContext('begin_' . $this->getPool()->name('Mysql:' . $cds, true)) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $coroutineName
|
||||
* @throws Exception
|
||||
*/
|
||||
public function beginTransaction($coroutineName)
|
||||
{
|
||||
$coroutineName = $this->name('mysql', $coroutineName, true);
|
||||
$coroutineName = $this->getPool()->name('Mysql:' . $coroutineName, true);
|
||||
if (!Context::hasContext('begin_' . $coroutineName)) {
|
||||
Context::setContext('begin_' . $coroutineName, 0);
|
||||
}
|
||||
Context::increment('begin_' . $coroutineName);
|
||||
if (!Context::getContext('begin_' . $coroutineName) !== 0) {
|
||||
if (Context::getContext('begin_' . $coroutineName) != 0) {
|
||||
return;
|
||||
}
|
||||
$connection = Context::getContext($coroutineName);
|
||||
@@ -71,10 +57,11 @@ class Connection extends Pool
|
||||
|
||||
/**
|
||||
* @param $coroutineName
|
||||
* @throws Exception
|
||||
*/
|
||||
public function commit($coroutineName)
|
||||
{
|
||||
$coroutineName = $this->name('mysql', $coroutineName, true);
|
||||
$coroutineName = $this->getPool()->name('Mysql:' . $coroutineName, true);
|
||||
if (!Context::hasContext('begin_' . $coroutineName)) {
|
||||
return;
|
||||
}
|
||||
@@ -92,22 +79,13 @@ class Connection extends Pool
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param false $isMaster
|
||||
* @return array
|
||||
*/
|
||||
private function getIndex($name, $isMaster = false): array
|
||||
{
|
||||
return [Coroutine::getCid(), $this->name('mysql', $name, $isMaster)];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $coroutineName
|
||||
* @throws Exception
|
||||
*/
|
||||
public function rollback($coroutineName)
|
||||
{
|
||||
$coroutineName = $this->name('mysql', $coroutineName, true);
|
||||
$coroutineName = $this->getPool()->name('Mysql:' . $coroutineName, true);
|
||||
if (!Context::hasContext('begin_' . $coroutineName)) {
|
||||
return;
|
||||
}
|
||||
@@ -129,13 +107,21 @@ class Connection extends Pool
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function get(mixed $config, $isMaster = false): mixed
|
||||
public function get(mixed $config, bool $isMaster = false): mixed
|
||||
{
|
||||
$coroutineName = $this->name('mysql', $config['cds'], $isMaster);
|
||||
$coroutineName = $this->getPool()->name('Mysql:' . $config['cds'], $isMaster);
|
||||
if (($pdo = Context::getContext($coroutineName)) instanceof PDO) {
|
||||
return $pdo;
|
||||
}
|
||||
$connections = $this->getFromChannel($coroutineName, $config);
|
||||
if (Coroutine::getCid() === -1) {
|
||||
$connections = $this->createClient($coroutineName, $config);
|
||||
} else {
|
||||
/** @var PDO $connections */
|
||||
$connections = $this->getPool()->getFromChannel($coroutineName);
|
||||
if (empty($connections)) {
|
||||
$connections = $this->createClient($coroutineName, $config);
|
||||
}
|
||||
}
|
||||
if ($number = Context::getContext('begin_' . $coroutineName, Coroutine::getCid())) {
|
||||
$number > 0 && $connections->beginTransaction();
|
||||
}
|
||||
@@ -143,6 +129,18 @@ class Connection extends Pool
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $isMaster
|
||||
* @param $max
|
||||
* @throws Exception
|
||||
*/
|
||||
public function initConnections($name, $isMaster, $max)
|
||||
{
|
||||
$this->getPool()->initConnections($name, $isMaster, $max);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param mixed $config
|
||||
@@ -152,12 +150,13 @@ class Connection extends Pool
|
||||
public function createClient(string $name, mixed $config): PDO
|
||||
{
|
||||
if (Coroutine::getCid() === -1) {
|
||||
Runtime::enableCoroutine(false);
|
||||
Runtime::enableCoroutine(false);
|
||||
}
|
||||
$link = new PDO($config['cds'], $config['username'], $config['password'], [
|
||||
$cds = 'mysql:dbname=' . $config['database'] . ';host=' . $config['cds'];
|
||||
$link = new PDO($cds, $config['username'], $config['password'], [
|
||||
PDO::ATTR_EMULATE_PREPARES => false,
|
||||
PDO::ATTR_CASE => PDO::CASE_NATURAL,
|
||||
PDO::ATTR_TIMEOUT => $this->timeout,
|
||||
PDO::ATTR_TIMEOUT => 60,
|
||||
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
|
||||
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES ' . ($config['charset'] ?? 'utf8mb4')
|
||||
]);
|
||||
@@ -175,7 +174,7 @@ class Connection extends Pool
|
||||
*/
|
||||
public function release($coroutineName, $isMaster)
|
||||
{
|
||||
$coroutineName = $this->name('mysql', $coroutineName, $isMaster);
|
||||
$coroutineName = $this->getPool()->name('Mysql:' . $coroutineName, $isMaster);
|
||||
|
||||
/** @var PDO $client */
|
||||
if (!($client = Context::getContext($coroutineName)) instanceof PDO) {
|
||||
@@ -184,8 +183,8 @@ class Connection extends Pool
|
||||
if ($client->inTransaction()) {
|
||||
$client->commit();
|
||||
}
|
||||
$this->push($coroutineName, $client);
|
||||
$this->lastTime = time();
|
||||
$this->getPool()->push($coroutineName, $client);
|
||||
Context::remove($coroutineName);
|
||||
}
|
||||
|
||||
|
||||
@@ -203,9 +202,9 @@ class Connection extends Pool
|
||||
* batch release
|
||||
* @throws Exception
|
||||
*/
|
||||
public function connection_clear()
|
||||
public function connection_clear($name, $isMaster)
|
||||
{
|
||||
$this->flush(0);
|
||||
$this->getPool()->clean($this->getPool()->name($name, $isMaster));
|
||||
}
|
||||
|
||||
|
||||
@@ -227,7 +226,7 @@ class Connection extends Pool
|
||||
$result = $this->addError($exception, 'mysql');
|
||||
} finally {
|
||||
if (!$result) {
|
||||
$this->decrement($name);
|
||||
$this->getPool()->decrement($name);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
@@ -239,10 +238,24 @@ class Connection extends Pool
|
||||
* @param bool $isMaster
|
||||
* @throws Exception
|
||||
*/
|
||||
public function disconnect($coroutineName, $isMaster = false)
|
||||
public function disconnect($coroutineName, bool $isMaster = false)
|
||||
{
|
||||
$coroutineName = $this->name($coroutineName, $isMaster);
|
||||
$this->clean($coroutineName);
|
||||
Context::remove($coroutineName);
|
||||
$coroutineName = $this->getPool()->name('Mysql:' . $coroutineName, $isMaster);
|
||||
$this->getPool()->clean($coroutineName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return ClientsPool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getPool(): ClientsPool
|
||||
{
|
||||
if (!$this->clientsPool) {
|
||||
$this->clientsPool = Snowflake::app()->getClientsPool();
|
||||
}
|
||||
return $this->clientsPool;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+46
-62
@@ -8,8 +8,10 @@ namespace Snowflake\Pool;
|
||||
use Exception;
|
||||
use HttpServer\Http\Context;
|
||||
use Redis as SRedis;
|
||||
use Snowflake\Abstracts\Pool;
|
||||
use Snowflake\Abstracts\Component;
|
||||
use Snowflake\Exception\ConfigException;
|
||||
use Snowflake\Exception\RedisConnectException;
|
||||
use Snowflake\Snowflake;
|
||||
use Swoole\Coroutine;
|
||||
use Swoole\Runtime;
|
||||
|
||||
@@ -17,32 +19,10 @@ use Swoole\Runtime;
|
||||
* Class RedisClient
|
||||
* @package Snowflake\Snowflake\Pool
|
||||
*/
|
||||
class Redis extends Pool
|
||||
class Redis extends Component
|
||||
{
|
||||
|
||||
|
||||
public int $_create = 0;
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
*/
|
||||
public function setLength($value)
|
||||
{
|
||||
$this->max = $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function canCreate(string $name): bool
|
||||
{
|
||||
if (!isset(static::$hasCreate[$name])) {
|
||||
static::$hasCreate[$name] = 0;
|
||||
}
|
||||
return static::$hasCreate[$name] >= $this->max;
|
||||
}
|
||||
private ?ClientsPool $clientsPool = null;
|
||||
|
||||
|
||||
/**
|
||||
@@ -51,14 +31,20 @@ class Redis extends Pool
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function get(mixed $config, $isMaster = false): mixed
|
||||
public function get(mixed $config, bool $isMaster = false): mixed
|
||||
{
|
||||
$name = $config['host'] . ':' . $config['prefix'] . ':' . $config['databases'];
|
||||
$coroutineName = $this->name('redis', 'redis:' . $name, $isMaster);
|
||||
if (!Context::hasContext($coroutineName)) {
|
||||
return Context::setContext($coroutineName, $this->getFromChannel($coroutineName, $config));
|
||||
$coroutineName = $this->getPool()->name('Redis:' . $config['host'], $isMaster);
|
||||
if (Context::hasContext($coroutineName)) {
|
||||
return Context::getContext($coroutineName);
|
||||
}
|
||||
return Context::getContext($coroutineName);
|
||||
if (Coroutine::getCid() === -1) {
|
||||
return Context::setContext($coroutineName, $this->createClient($coroutineName, $config));
|
||||
}
|
||||
$clients = $this->getPool()->getFromChannel($coroutineName);
|
||||
if (empty($clients)) {
|
||||
return Context::setContext($coroutineName, $this->createClient($coroutineName, $config));
|
||||
}
|
||||
return Context::setContext($coroutineName, $clients);
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +74,7 @@ class Redis extends Pool
|
||||
$redis->setOption(SRedis::OPT_READ_TIMEOUT, $config['read_timeout']);
|
||||
$redis->setOption(SRedis::OPT_PREFIX, $config['prefix']);
|
||||
|
||||
$this->increment($name);
|
||||
$this->getPool()->increment($name);
|
||||
|
||||
return $redis;
|
||||
}
|
||||
@@ -97,18 +83,18 @@ class Redis extends Pool
|
||||
/**
|
||||
* @param array $config
|
||||
* @param bool $isMaster
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function release(array $config, $isMaster = false)
|
||||
public function release(array $config, bool $isMaster = false)
|
||||
{
|
||||
$name = $config['host'] . ':' . $config['prefix'] . ':' . $config['databases'];
|
||||
$coroutineName = $this->name('redis', 'redis:' . $name, $isMaster);
|
||||
$coroutineName = $this->getPool()->name('Redis:' . $config['host'], $isMaster);
|
||||
if (!Context::hasContext($coroutineName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->push($coroutineName, Context::getContext($coroutineName));
|
||||
Context::remove($coroutineName);
|
||||
$this->lastTime = time();
|
||||
$this->getPool()->push($coroutineName, Context::getContext($coroutineName));
|
||||
Context::remove($coroutineName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -116,42 +102,40 @@ class Redis extends Pool
|
||||
* @param bool $isMaster
|
||||
* @throws Exception
|
||||
*/
|
||||
public function destroy(array $config, $isMaster = false)
|
||||
public function destroy(array $config, bool $isMaster = false)
|
||||
{
|
||||
$name = $config['host'] . ':' . $config['prefix'] . ':' . $config['databases'];
|
||||
$coroutineName = $this->name('redis', 'redis:' . $name, $isMaster);
|
||||
$coroutineName = $this->getPool()->name('Redis:' . $config['host'], $isMaster);
|
||||
if (Context::hasContext($coroutineName)) {
|
||||
$this->decrement($coroutineName);
|
||||
$this->getPool()->decrement($coroutineName);
|
||||
}
|
||||
Context::remove($coroutineName);
|
||||
$this->flush(0);
|
||||
$this->getPool()->clean($coroutineName);
|
||||
Context::remove($coroutineName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param mixed $client
|
||||
* @return bool
|
||||
* @return ClientsPool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function checkCanUse(string $name, mixed $client): bool
|
||||
public function getPool(): ClientsPool
|
||||
{
|
||||
try {
|
||||
if (!($client instanceof SRedis)) {
|
||||
$result = false;
|
||||
} else {
|
||||
$result = true;
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
$this->addError($exception, 'redis');
|
||||
$result = false;
|
||||
} finally {
|
||||
if (!$result) {
|
||||
$this->decrement($name);
|
||||
}
|
||||
return $result;
|
||||
if (!$this->clientsPool) {
|
||||
$this->clientsPool = Snowflake::app()->getClientsPool();
|
||||
}
|
||||
return $this->clientsPool;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $isMaster
|
||||
* @param $max
|
||||
* @throws Exception
|
||||
*/
|
||||
public function initConnections($name, $isMaster, $max)
|
||||
{
|
||||
$this->getPool()->initConnections($name, $isMaster, $max);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ abstract class Process extends \Swoole\Process implements SProcess
|
||||
public function __construct($application, $name, $enable_coroutine = true)
|
||||
{
|
||||
parent::__construct([$this, '_load'], false, 1, $enable_coroutine);
|
||||
Snowflake::setProcessId($this->pid);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -37,11 +36,13 @@ abstract class Process extends \Swoole\Process implements SProcess
|
||||
*/
|
||||
public function _load(Process $process)
|
||||
{
|
||||
Snowflake::setProcessId($this->pid);
|
||||
|
||||
putenv('environmental=' . Snowflake::PROCESS);
|
||||
|
||||
fire(Event::SERVER_WORKER_START);
|
||||
if (Snowflake::getPlatform()->isLinux()) {
|
||||
swoole_set_process_name($this->getProcessName());
|
||||
if (Snowflake::getPlatform()->isLinux()) {
|
||||
name($this->pid, $this->getProcessName());
|
||||
}
|
||||
if (method_exists($this, 'before')) {
|
||||
$this->before($process);
|
||||
|
||||
@@ -46,7 +46,7 @@ abstract class BaseValidator
|
||||
* BaseValidator constructor.
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct($config = [])
|
||||
public function __construct(array $config = [])
|
||||
{
|
||||
$this->regConfig($config);
|
||||
}
|
||||
|
||||
@@ -37,14 +37,11 @@ class LengthValidator extends BaseValidator
|
||||
if (is_null($value)) {
|
||||
return $this->addError('The param :attribute is null');
|
||||
}
|
||||
switch (strtolower($this->method)) {
|
||||
case self::MAX_LENGTH:
|
||||
return $this->maxLength($value);
|
||||
case self::MIN_LENGTH:
|
||||
return $this->minLength($value);
|
||||
default:
|
||||
return $this->defaultLength($value);
|
||||
}
|
||||
return match (strtolower($this->method)) {
|
||||
self::MAX_LENGTH => $this->maxLength($value),
|
||||
self::MIN_LENGTH => $this->minLength($value),
|
||||
default => $this->defaultLength($value),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace validator;
|
||||
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Class RoundValidator
|
||||
* @package validator
|
||||
*/
|
||||
class RoundValidator extends BaseValidator
|
||||
{
|
||||
|
||||
|
||||
public ?int $value = null;
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function trigger(): bool
|
||||
{
|
||||
$value = $this->model->getAttribute($this->field);
|
||||
if ($value == null || round($value, $this->value) != $value) {
|
||||
return $this->addError('The param :attribute length error');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -102,6 +102,9 @@ class Validator extends BaseValidator
|
||||
'class' => 'validator\LengthValidator',
|
||||
'method' => 'default',
|
||||
],
|
||||
'round' => [
|
||||
'class' => 'validator\RoundValidator',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
+34
-2
@@ -17,6 +17,7 @@ use JetBrains\PhpStorm\Pure;
|
||||
use Snowflake\Abstracts\Config;
|
||||
use Snowflake\Application;
|
||||
use Snowflake\Core\ArrayAccess;
|
||||
use Snowflake\Core\Json;
|
||||
use Snowflake\Error\Logger;
|
||||
use Snowflake\Event;
|
||||
use Snowflake\Exception\ConfigException;
|
||||
@@ -375,6 +376,35 @@ if (!function_exists('logger')) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!function_exists('trim_blank')) {
|
||||
|
||||
|
||||
/**
|
||||
* 空白字符替换
|
||||
* @param string $content 内容
|
||||
* @param int $len 截取长度
|
||||
* @param string $encode 编码
|
||||
* @param bool $htmlTags
|
||||
* @return array|string|null
|
||||
*/
|
||||
function trim_blank(string $content, $len = 0, $encode = 'utf-8', $htmlTags = true): array|string|null
|
||||
{
|
||||
$str = trim($content);
|
||||
if ($htmlTags) {
|
||||
$str = strip_tags($str);
|
||||
}
|
||||
$str = preg_replace('/[\n|\r|\t]+/', '', $str);
|
||||
$str = preg_replace("/(\s|\ \;| |\xc2\xa0)/", '', $str);
|
||||
if ($len > 0) {
|
||||
return mb_substr($str, 0, $len, $encode);
|
||||
} else {
|
||||
return $str;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!function_exists('get_file_extension')) {
|
||||
|
||||
function get_file_extension($filename)
|
||||
@@ -615,12 +645,14 @@ if (!function_exists('send')) {
|
||||
|
||||
/**
|
||||
* @param $context
|
||||
* @param $statusCode
|
||||
* @param int $statusCode
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
function send($context, $statusCode = 404): mixed
|
||||
function send($context, int $statusCode = 404): mixed
|
||||
{
|
||||
if (is_array($context)) $context = Json::encode($context);
|
||||
|
||||
return \response()->send($context, $statusCode);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user