update to 2.5.0-b3 (build 410)

This commit is contained in:
crazywhalecc
2021-07-09 01:38:30 +08:00
parent c185d20a93
commit 7e0fc1528a
34 changed files with 692 additions and 157 deletions

View File

@@ -5,7 +5,9 @@ namespace ZM\Event\SwooleEvent;
use Swoole\Process;
use Swoole\WebSocket\Server;
use ZM\Annotation\Swoole\SwooleHandler;
use ZM\ConnectionManager\ManagerGM;
use ZM\Console\Console;
use ZM\Event\SwooleEvent;
@@ -16,11 +18,16 @@ use ZM\Event\SwooleEvent;
*/
class OnBeforeReload implements SwooleEvent
{
public function onCall() {
public function onCall(Server $server) {
Console::info(Console::setColor("Reloading server...", "gold"));
for ($i = 0; $i < ZM_WORKER_NUM; ++$i) {
Process::kill(zm_atomic("_#worker_".$i)->get(), SIGUSR1);
Process::kill(zm_atomic("_#worker_" . $i)->get(), SIGUSR1);
}
foreach ($server->connections as $fd) {
if (ManagerGM::get($fd) !== null) $server->disconnect($fd);
else $server->close($fd);
}
usleep(800 * 1000);
}
}

View File

@@ -6,12 +6,20 @@
namespace ZM\Event\SwooleEvent;
use Error;
use Exception;
use Swoole\Event;
use Swoole\Process;
use Swoole\Server;
use ZM\Annotation\Swoole\SwooleHandler;
use ZM\Console\Console;
use ZM\Event\SwooleEvent;
use ZM\Framework;
use ZM\Store\ZMBuf;
use ZM\Utils\DataProvider;
use ZM\Utils\SignalListener;
use ZM\Utils\Terminal;
use ZM\Utils\ZMUtil;
/**
* Class OnManagerStart
@@ -20,10 +28,68 @@ use ZM\Utils\SignalListener;
*/
class OnManagerStart implements SwooleEvent
{
/** @var null|Process */
public static $process = null;
public function onCall(Server $server) {
Console::debug("Calling onManagerStart event(1)");
if (!Framework::$argv["disable-safe-exit"]) {
SignalListener::signalManager();
}
self::$process = new Process(function() {
swoole_set_process_name($_SERVER["_"]." {ext-proc}");
if (Framework::$argv["watch"]) {
if (extension_loaded('inotify')) {
Console::info("Enabled File watcher, framework will reload automatically.");
/** @noinspection PhpUndefinedFieldInspection */
Framework::$server->inotify = $fd = inotify_init();
$this->addWatcher(DataProvider::getSourceRootDir() . "/src", $fd);
Event::add($fd, function () use ($fd) {
$r = inotify_read($fd);
Console::verbose("File updated: " . $r[0]["name"]);
ZMUtil::reload();
});
} else {
Console::warning(zm_internal_errcode("E00024") . "You have not loaded \"inotify\" extension, please install first.");
}
}
if (Framework::$argv["interact"]) {
Console::info("Interact mode");
ZMBuf::$terminal = $r = STDIN;
Event::add($r, function () use ($r) {
$fget = fgets($r);
if ($fget === false) {
Event::del($r);
return;
}
$var = trim($fget);
if ($var == "stop") Event::del($r);
try {
Terminal::executeCommand($var);
} catch (Exception $e) {
Console::error(zm_internal_errcode("E00025") . "Uncaught exception " . get_class($e) . ": " . $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")");
} catch (Error $e) {
Console::error(zm_internal_errcode("E00025") . "Uncaught error " . get_class($e) . ": " . $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")");
}
});
}
});
self::$process->set(['enable_coroutine' => true]);
self::$process->start();
Console::verbose("进程 Manager 已启动");
}
private function addWatcher($maindir, $fd) {
$dir = scandir($maindir);
if ($dir[0] == ".") {
unset($dir[0], $dir[1]);
}
foreach ($dir as $subdir) {
if (is_dir($maindir . "/" . $subdir)) {
Console::debug("添加监听目录:" . $maindir . "/" . $subdir);
inotify_add_watch($fd, $maindir . "/" . $subdir, IN_ATTRIB | IN_ISDIR);
$this->addWatcher($maindir . "/" . $subdir, $fd);
}
}
}
}

View File

@@ -4,6 +4,7 @@
namespace ZM\Event\SwooleEvent;
use Swoole\Process;
use ZM\Annotation\Swoole\SwooleHandler;
use ZM\Console\Console;
use ZM\Event\SwooleEvent;
@@ -16,6 +17,11 @@ use ZM\Event\SwooleEvent;
class OnManagerStop implements SwooleEvent
{
public function onCall() {
if (OnManagerStart::$process !== null) {
if (Process::kill(OnManagerStart::$process->pid, 0)) {
Process::kill(OnManagerStart::$process->pid, SIGTERM);
}
}
Console::verbose("进程 Manager 已停止!");
}
}

View File

@@ -26,55 +26,11 @@ use ZM\Utils\ZMUtil;
class OnStart implements SwooleEvent
{
public function onCall(Server $server) {
Console::debug("Calling onStart event(1)");
if (!Framework::$argv["disable-safe-exit"]) {
SignalListener::signalMaster($server);
}
if (Framework::$argv["watch"]) {
if (extension_loaded('inotify')) {
Console::info("Enabled File watcher, framework will reload automatically.");
/** @noinspection PhpUndefinedFieldInspection */
Framework::$server->inotify = $fd = inotify_init();
$this->addWatcher(DataProvider::getSourceRootDir() . "/src", $fd);
Event::add($fd, function () use ($fd) {
$r = inotify_read($fd);
Console::verbose("File updated: " . $r[0]["name"]);
ZMUtil::reload();
});
} else {
Console::warning(zm_internal_errcode("E00024") . "You have not loaded \"inotify\" extension, please install first.");
}
}
if (Framework::$argv["interact"]) {
ZMBuf::$terminal = $r = STDIN;
Event::add($r, function () use ($r) {
$fget = fgets($r);
if ($fget === false) {
Event::del($r);
return;
}
$var = trim($fget);
try {
Terminal::executeCommand($var);
} catch (Exception $e) {
Console::error(zm_internal_errcode("E00025") . "Uncaught exception " . get_class($e) . ": " . $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")");
} catch (Error $e) {
Console::error(zm_internal_errcode("E00025") . "Uncaught error " . get_class($e) . ": " . $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")");
}
});
}
}
private function addWatcher($maindir, $fd) {
$dir = scandir($maindir);
if ($dir[0] == ".") {
unset($dir[0], $dir[1]);
}
foreach ($dir as $subdir) {
if (is_dir($maindir . "/" . $subdir)) {
Console::debug("添加监听目录:" . $maindir . "/" . $subdir);
inotify_add_watch($fd, $maindir . "/" . $subdir, IN_ATTRIB | IN_ISDIR);
$this->addWatcher($maindir . "/" . $subdir, $fd);
}
}
}
}

View File

@@ -4,12 +4,13 @@
namespace ZM\Event\SwooleEvent;
use Swoole\Coroutine;
use Swoole\Server;
use Swoole\Timer;
use ZM\Annotation\Swoole\SwooleHandler;
use ZM\ConnectionManager\ManagerGM;
use ZM\Console\Console;
use ZM\Event\SwooleEvent;
use ZM\Store\LightCacheInside;
/**
* Class OnWorkerExit
@@ -20,9 +21,10 @@ class OnWorkerExit implements SwooleEvent
{
public function onCall(Server $server, $worker_id) {
Timer::clearAll();
foreach($server->connections as $v) {
$server->close($v);
Console::info("Closing connection #".$v);
foreach((LightCacheInside::get("wait_api", "wait_api") ?? []) as $v) {
if (($v["worker_id"] ?? -1) == $worker_id && isset($v["coroutine"])) {
Coroutine::resume($v["coroutine"]);
}
}
Console::info("正在结束 Worker #".$worker_id.",进程内可能有事务在运行...");
}

View File

@@ -9,7 +9,6 @@ use PDO;
use ReflectionException;
use Swoole\Coroutine;
use Swoole\Database\PDOConfig;
use Swoole\Database\PDOPool;
use Swoole\Process;
use Swoole\Server;
use ZM\Annotation\AnnotationParser;
@@ -28,6 +27,7 @@ use ZM\Exception\DbException;
use ZM\Exception\ZMException;
use ZM\Framework;
use ZM\Module\QQBot;
use ZM\MySQL\MySQLPool;
use ZM\Store\LightCacheInside;
use ZM\Store\MySQL\SqlPoolStorage;
use ZM\Store\Redis\ZMRedisPool;
@@ -42,11 +42,13 @@ use ZM\Utils\SignalListener;
class OnWorkerStart implements SwooleEvent
{
public function onCall(Server $server, $worker_id) {
Console::debug("Calling onWorkerStart event(1)");
if (!Framework::$argv["disable-safe-exit"]) {
SignalListener::signalWorker($server, $worker_id);
}
unset(Context::$context[Coroutine::getCid()]);
if ($server->taskworker === false) {
zm_atomic("_#worker_" . $worker_id)->set($server->worker_pid);
if (LightCacheInside::get("wait_api", "wait_api") !== null) {
LightCacheInside::unset("wait_api", "wait_api");
@@ -54,9 +56,11 @@ class OnWorkerStart implements SwooleEvent
try {
register_shutdown_function(function () use ($server) {
$error = error_get_last();
if (($error["type"] ?? -1) != 0) {
if (($error["type"] ?? 0) != 0) {
Console::error(zm_internal_errcode("E00027") . "Internal fatal error: " . $error["message"] . " at " . $error["file"] . "({$error["line"]})");
zm_dump($error);
} elseif (!isset($error["type"])) {
return;
}
//DataProvider::saveBuffer();
/** @var Server $server */
@@ -68,42 +72,9 @@ class OnWorkerStart implements SwooleEvent
Framework::$server = $server;
//ZMBuf::resetCache(); //清空变量缓存
//ZMBuf::set("wait_start", []); //添加队列在workerStart运行完成前先让其他协程等待执行
foreach ($server->connections as $v) {
$server->close($v);
}
//TODO: 单独抽出来MySQL和Redis连接池
if (ZMConfig::get("global", "sql_config")["sql_host"] != "") {
if (SqlPoolStorage::$sql_pool !== null) {
SqlPoolStorage::$sql_pool->close();
SqlPoolStorage::$sql_pool = null;
}
Console::info("新建SQL连接池中");
ob_start();
phpinfo(); //这个phpinfo是有用的不能删除
$str = ob_get_clean();
$str = explode("\n", $str);
foreach ($str as $v) {
$v = trim($v);
if ($v == "") continue;
if (mb_strpos($v, "API Extensions") === false) continue;
if (mb_strpos($v, "pdo_mysql") === false) {
throw new DbException(zm_internal_errcode("E00028") . "未安装 mysqlnd php-mysql扩展。");
}
}
$sql = ZMConfig::get("global", "sql_config");
SqlPoolStorage::$sql_pool = new PDOPool((new PDOConfig())
->withHost($sql["sql_host"])
->withPort($sql["sql_port"])
// ->withUnixSocket('/tmp/mysql.sock')
->withDbName($sql["sql_database"])
->withCharset('utf8mb4')
->withUsername($sql["sql_username"])
->withPassword($sql["sql_password"])
->withOptions($sql["sql_options"] ?? [PDO::ATTR_STRINGIFY_FETCHES => false])
);
DB::initTableList();
}
$this->initMySQLPool();
// 开箱即用的Redis
$redis = ZMConfig::get("global", "redis_config");
@@ -114,10 +85,7 @@ class OnWorkerStart implements SwooleEvent
$this->loadAnnotations(); //加载composer资源、phar外置包、注解解析注册等
//echo json_encode(debug_backtrace(), 128|256);
EventManager::registerTimerTick(); //启动计时器
//ZMBuf::unsetCache("wait_start");
set_coroutine_params(["server" => $server, "worker_id" => $worker_id]);
$dispatcher = new EventDispatcher(OnStart::class);
$dispatcher->setRuleFunction(function ($v) {
@@ -163,24 +131,9 @@ class OnWorkerStart implements SwooleEvent
* @throws Exception
*/
private function loadAnnotations() {
//加载phar包
/*Console::debug("加载外部phar包中");
$dir = DataProvider::getWorkingDir() . "/resources/package/";
if (version_compare(SWOOLE_VERSION, "4.4.0", ">=")) Timer::clearAll();
if (is_dir($dir)) {
$list = scandir($dir);
unset($list[0], $list[1]);
foreach ($list as $v) {
if (is_dir($dir . $v)) continue;
if (pathinfo($dir . $v, 4) == "phar") {
Console::debug("加载Phar: " . $dir . $v . " 中");
require_once($dir . $v);
}
}
}*/
//加载各个模块的注解类,以及反射
Console::debug("检索Module中");
Console::debug("Mapping annotations");
$parser = new AnnotationParser();
$composer = json_decode(file_get_contents(DataProvider::getSourceRootDir() . "/composer.json"), true);
foreach ($composer["autoload"]["psr-4"] as $k => $v) {
@@ -195,10 +148,10 @@ class OnWorkerStart implements SwooleEvent
EventManager::loadEventByParser($parser); //加载事件
//加载自定义的全局函数
Console::debug("加载自定义上下文中...");
Console::debug("Loading context class...");
$context_class = ZMConfig::get("global", "context_class");
if (!is_a($context_class, ContextInterface::class, true)) {
throw new ZMException(zm_internal_errcode("E00032") ."Context class must implemented from ContextInterface!");
throw new ZMException(zm_internal_errcode("E00032") . "Context class must implemented from ContextInterface!");
}
//加载插件
@@ -207,6 +160,7 @@ class OnWorkerStart implements SwooleEvent
["status" => true, "single_bot_mode" => false, "message_level" => 99999];
if ($obb_onebot["status"]) {
Console::debug("OneBot support enabled, listening OneBot event(3).");
$obj = new OnSwooleEvent();
$obj->class = QQBot::class;
$obj->method = 'handleByEvent';
@@ -223,4 +177,63 @@ class OnWorkerStart implements SwooleEvent
//TODO: 编写加载外部插件的方式
}
private function initMySQLPool() {
if (SqlPoolStorage::$sql_pool !== null) {
SqlPoolStorage::$sql_pool->close();
SqlPoolStorage::$sql_pool = null;
}
$real_conf = [];
if (isset(ZMConfig::get("global", "sql_config")["sql_host"])) {
if (ZMConfig::get("global", "sql_config")["sql_host"] != "") {
if (\server()->worker_id === 0) {
Console::warning("使用 'sql_config' 配置项和 DB 数据库查询构造器进行查询数据库可能会在下一个大版本中废弃,请使用 'mysql_config' 搭配 doctrine dbal 使用!");
Console::warning("详见: `https://framework.zhamao.xin/`");
}
$origin_conf = ZMConfig::get("global", "sql_config");
$real_conf = [
"host" => $origin_conf["sql_host"],
"port" => $origin_conf["sql_port"],
"username" => $origin_conf["sql_username"],
"password" => $origin_conf["sql_password"],
"dbname" => $origin_conf["sql_database"],
"options" => $origin_conf["sql_options"],
'unix_socket' => null,
'charset' => 'utf8mb4',
'pool_size' => 64
];
}
}
if (isset(ZMConfig::get("global", "mysql_config")["host"])) {
if (ZMConfig::get("global", "mysql_config")["host"] != "") {
$real_conf = ZMConfig::get("global", "mysql_config");
}
}
if (!empty($real_conf)) {
Console::info("Connecting to MySQL pool");
ob_start();
phpinfo(); //这个phpinfo是有用的不能删除
$str = ob_get_clean();
$str = explode("\n", $str);
foreach ($str as $v) {
$v = trim($v);
if ($v == "") continue;
if (mb_strpos($v, "API Extensions") === false) continue;
if (mb_strpos($v, "pdo_mysql") === false) {
throw new DbException(zm_internal_errcode("E00028") . "未安装 mysqlnd php-mysql扩展。");
}
}
SqlPoolStorage::$sql_pool = new MySQLPool((new PDOConfig())
->withHost($real_conf["host"])
->withPort($real_conf["port"])
// ->withUnixSocket('/tmp/mysql.sock')
->withDbName($real_conf["dbname"])
->withCharset($real_conf["charset"])
->withUsername($real_conf["username"])
->withPassword($real_conf["password"])
->withOptions($real_conf["options"] ?? [PDO::ATTR_STRINGIFY_FETCHES => false])
);
DB::initTableList();
}
}
}

View File

@@ -22,6 +22,6 @@ class OnWorkerStop implements SwooleEvent
if ($worker_id == (ZMConfig::get("worker_cache")["worker"] ?? 0)) {
LightCache::savePersistence();
}
Console::verbose(($server->taskworker ? "Task" : "") . "Worker #$worker_id 已停止");
Console::verbose(($server->taskworker ? "Task" : "") . "Worker #$worker_id 已停止: ".$server->getWorkerStatus($worker_id));
}
}