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

@@ -6,6 +6,7 @@ namespace ZM\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use ZM\Config\ZMConfig;
class CheckConfigCommand extends Command
{
@@ -49,7 +50,10 @@ class CheckConfigCommand extends Command
* @noinspection PhpIncludeInspection
*/
private function check($remote, $local, OutputInterface $out) {
$local_file = include_once getcwd() . "/config/".$local;
$local_file = include_once WORKING_DIR . "/config/".$local;
if ($local_file === true) {
$local_file = ZMConfig::get("global");
}
foreach($remote as $k => $v) {
if (!isset($local_file[$k])) {
$out->writeln("<comment>配置文件 ".$local . " 需要更新!(当前配置文件缺少 `$k` 字段配置)</comment>");

View File

@@ -28,8 +28,8 @@ class ConsoleApplication extends Application
{
private static $obj = null;
const VERSION_ID = 409;
const VERSION = "2.5.0-b2";
const VERSION_ID = 410;
const VERSION = "2.5.0-b3";
/**
* @throws InitException

View File

@@ -15,6 +15,11 @@ use PDOStatement;
use Swoole\Database\PDOStatementProxy;
use ZM\Exception\DbException;
/**
* Class DB
* @package ZM\DB
* @deprecated This will delete in 2.6 or future version, use \ZM\MySQL\MySQLManager::getConnection() instead
*/
class DB
{
private static $table_list = [];
@@ -64,13 +69,13 @@ class DB
*/
public static function unprepared($line): bool {
try {
$conn = SqlPoolStorage::$sql_pool->get();
$conn = SqlPoolStorage::$sql_pool->getConnection();
if ($conn === false) {
SqlPoolStorage::$sql_pool->put(null);
SqlPoolStorage::$sql_pool->putConnection(null);
throw new DbException("无法连接SQL" . $line);
}
$result = $conn->query($line) === false ? false : true;
SqlPoolStorage::$sql_pool->put($conn);
SqlPoolStorage::$sql_pool->putConnection($conn);
return $result;
} catch (DBException $e) {
Console::warning($e->getMessage());
@@ -89,20 +94,20 @@ class DB
if (!is_array($params)) $params = [$params];
Console::debug("MySQL: " . $line . " | " . implode(", ", $params));
try {
$conn = SqlPoolStorage::$sql_pool->get();
$conn = SqlPoolStorage::$sql_pool->getConnection();
if ($conn === false) {
SqlPoolStorage::$sql_pool->put(null);
SqlPoolStorage::$sql_pool->putConnection(null);
throw new DbException("无法连接SQL" . $line);
}
$ps = $conn->prepare($line);
if ($ps === false) {
SqlPoolStorage::$sql_pool->put(null);
SqlPoolStorage::$sql_pool->putConnection(null);
/** @noinspection PhpUndefinedFieldInspection */
throw new DbException("SQL语句查询错误" . $line . ",错误信息:" . $conn->error);
} else {
if (!($ps instanceof PDOStatement) && !($ps instanceof PDOStatementProxy)) {
var_dump($ps);
SqlPoolStorage::$sql_pool->put(null);
SqlPoolStorage::$sql_pool->putConnection(null);
throw new DbException("语句查询错误!返回的不是 PDOStatement" . $line);
}
if ($params == []) $result = $ps->execute();
@@ -110,11 +115,11 @@ class DB
$result = $ps->execute([$params]);
} else $result = $ps->execute($params);
if ($result !== true) {
SqlPoolStorage::$sql_pool->put(null);
SqlPoolStorage::$sql_pool->putConnection(null);
throw new DBException("语句[$line]错误!" . $ps->errorInfo()[2]);
//echo json_encode(debug_backtrace(), 128 | 256);
}
SqlPoolStorage::$sql_pool->put($conn);
SqlPoolStorage::$sql_pool->putConnection($conn);
return $ps->fetchAll($fetch_mode);
}
} catch (DbException $e) {

View File

@@ -6,6 +6,11 @@ namespace ZM\DB;
use ZM\Exception\DbException;
/**
* Class DeleteBody
* @package ZM\DB
* @deprecated This will delete in 2.6 or future version, use \ZM\MySQL\MySQLManager::getConnection() instead
*/
class DeleteBody
{
use WhereBody;

View File

@@ -6,6 +6,11 @@ namespace ZM\DB;
use ZM\Exception\DbException;
/**
* Class InsertBody
* @package ZM\DB
* @deprecated This will delete in 2.6 or future version, use \ZM\MySQL\MySQLManager::getConnection() instead
*/
class InsertBody
{
/**

View File

@@ -6,6 +6,11 @@ namespace ZM\DB;
use ZM\Exception\DbException;
/**
* Class SelectBody
* @package ZM\DB
* @deprecated This will delete in 2.6 or future version, use \ZM\MySQL\MySQLManager::getConnection() instead
*/
class SelectBody
{
use WhereBody;

View File

@@ -5,7 +5,11 @@
namespace ZM\DB;
/**
* Class Table
* @package ZM\DB
* @deprecated This will delete in 2.6 or future version, use \ZM\MySQL\MySQLManager::getConnection() instead
*/
class Table
{
private $table_name;

View File

@@ -6,6 +6,11 @@ namespace ZM\DB;
use ZM\Exception\DbException;
/**
* Class UpdateBody
* @package ZM\DB
* @deprecated This will delete in 2.6 or future version, use \ZM\MySQL\MySQLManager::getConnection() instead
*/
class UpdateBody
{
use WhereBody;

View File

@@ -3,7 +3,11 @@
namespace ZM\DB;
/**
* Trait WhereBody
* @package ZM\DB
* @deprecated This will delete in 2.6 or future version, use \ZM\MySQL\MySQLManager::getConnection() instead
*/
trait WhereBody
{
protected $where_thing = [];

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));
}
}

View File

@@ -6,6 +6,7 @@ namespace ZM;
use Doctrine\Common\Annotations\AnnotationReader;
use Error;
use Exception;
use Phar;
use Swoole\Server\Port;
use Throwable;
use ZM\Config\ZMConfig;
@@ -111,8 +112,15 @@ class Framework
// 打印初始信息
$out["listen"] = ZMConfig::get("global", "host") . ":" . ZMConfig::get("global", "port");
if (!isset($this->server_set["worker_num"])) $out["worker"] = swoole_cpu_num() . " (auto)";
else $out["worker"] = $this->server_set["worker_num"];
if (!isset($this->server_set["worker_num"])) {
if ((ZMConfig::get("global", "runtime")["swoole_server_mode"]) == SWOOLE_PROCESS) {
$out["worker"] = swoole_cpu_num() . " (auto)";
} else {
$out["single_proc_mode"] = "true";
}
} else {
$out["worker"] = $this->server_set["worker_num"];
}
$out["environment"] = $args["env"] === null ? "default" : $args["env"];
$out["log_level"] = Console::getLevel();
$out["version"] = ZM_VERSION . (LOAD_MODE == 0 ? (" (build " . ZM_VERSION_ID . ")") : "");
@@ -128,6 +136,10 @@ class Framework
$conf = ZMConfig::get("global", "sql_config");
$out["mysql_pool"] = $conf["sql_database"] . "@" . $conf["sql_host"] . ":" . $conf["sql_port"];
}
if (ZMConfig::get("global", "mysql_config")["host"] !== "") {
$conf = ZMConfig::get("global", "mysql_config");
$out["mysql"] = $conf["dbname"] . "@" . $conf["host"] . ":" . $conf["port"];
}
if (ZMConfig::get("global", "redis_config")["host"] !== "") {
$conf = ZMConfig::get("global", "redis_config");
$out["redis_pool"] = $conf["host"] . ":" . $conf["port"];
@@ -151,7 +163,11 @@ class Framework
}
self::$server = new Server(ZMConfig::get("global", "host"), ZMConfig::get("global", "port"));
self::$server = new Server(
ZMConfig::get("global", "host"),
ZMConfig::get("global", "port"),
ZMConfig::get("global", "runtime")["swoole_server_mode"] ?? SWOOLE_PROCESS
);
if ($add_port) {
$conf = ZMConfig::get("global", "remote_terminal") ?? [
@@ -310,10 +326,13 @@ class Framework
}
}
/**
* @noinspection PhpIncludeInspection
*/
private function loadServerEvents() {
if (\Phar::running() !== "") {
if (Phar::running() !== "") {
ob_start();
$r = include_once DataProvider::getFrameworkRootDir() . "/src/ZM/script_setup_loader.php";
include_once DataProvider::getFrameworkRootDir() . "/src/ZM/script_setup_loader.php";
$r = ob_get_clean();
$result_code = 0;
} else {
@@ -440,7 +459,7 @@ class Framework
}
}
}
$global_hook = ZMConfig::get("global", 'runtime')['swoole_coroutine_hook_flags'] ?? SWOOLE_HOOK_ALL & (~SWOOLE_HOOK_CURL);
$global_hook = ZMConfig::get("global", 'runtime')['swoole_coroutine_hook_flags'] ?? (SWOOLE_HOOK_ALL & (~SWOOLE_HOOK_CURL));
if ($coroutine_mode && $global_hook === false) Runtime::enableCoroutine(true, $global_hook);
else Runtime::enableCoroutine(false, SWOOLE_HOOK_ALL);
}

View File

@@ -0,0 +1,94 @@
<?php /** @noinspection PhpComposerExtensionStubsInspection */
namespace ZM\MySQL;
use Doctrine\DBAL\Driver\Connection;
use Doctrine\DBAL\ParameterType;
use PDO;
use PDOException;
use PDOStatement;
use Swoole\Database\PDOProxy;
use Swoole\Database\PDOStatementProxy;
use ZM\Console\Console;
use ZM\Exception\DbException;
use ZM\Store\MySQL\SqlPoolStorage;
class MySQLConnection implements Connection
{
/** @var PDO|PDOProxy */
private $conn;
public function __construct() {
Console::info("Constructing...");
$this->conn = SqlPoolStorage::$sql_pool->getConnection();
}
public function prepare($sql, $options = []) {
try {
$statement = $this->conn->prepare($sql, $options);
assert(($statement instanceof PDOStatementProxy) || ($statement instanceof PDOStatement));
} catch (PDOException $exception) {
throw new DbException($exception->getMessage(), $exception->getCode(), $exception);
}
return new MySQLStatement($statement);
}
public function query(...$args) {
try {
$statement = $this->conn->query(...$args);
assert(($statement instanceof PDOStatementProxy) || ($statement instanceof PDOStatement));
} catch (PDOException $exception) {
throw new DbException($exception->getMessage(), $exception->getCode(), $exception);
}
return new MySQLStatement($statement);
}
public function quote($value, $type = ParameterType::STRING) {
return $this->conn->quote($value, $type);
}
public function exec($sql) {
try {
$statement = $this->conn->exec($sql);
assert($statement !== false);
return $statement;
} catch (PDOException $exception) {
throw new DbException($exception->getMessage(), $exception->getCode(), $exception);
}
}
public function lastInsertId($name = null) {
try {
return $name === null ? $this->conn->lastInsertId() : $this->conn->lastInsertId($name);
} catch (PDOException $exception) {
throw new DbException($exception->getMessage(), $exception->getCode(), $exception);
}
}
public function beginTransaction() {
return $this->conn->beginTransaction();
}
public function commit() {
return $this->conn->commit();
}
public function rollBack() {
return $this->conn->rollBack();
}
public function errorCode() {
return $this->conn->errorCode();
}
public function errorInfo() {
return $this->conn->errorInfo();
}
public function __destruct() {
Console::info("Destructing");
SqlPoolStorage::$sql_pool->putConnection($this->conn);
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace ZM\MySQL;
use Doctrine\DBAL\Driver;
use Doctrine\DBAL\Platforms\MySqlPlatform;
use Doctrine\DBAL\Schema\MySqlSchemaManager;
use ZM\Config\ZMConfig;
use ZM\Console\Console;
class MySQLDriver implements Driver
{
public function connect(array $params, $username = null, $password = null, array $driverOptions = []) {
Console::info("Requiring new connection");
return new MySQLConnection();
}
public function getDatabasePlatform(): MySqlPlatform {
return new MySqlPlatform();
}
public function getSchemaManager($conn) {
return new MySqlSchemaManager($conn);
}
public function getName() {
return 'pdo_mysql_pool';
}
public function getDatabase($conn) {
$params = ZMConfig::get("global", "mysql_config");
if (isset($params['dbname'])) {
return $params['dbname'];
}
return "";
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace ZM\MySQL;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Exception;
class MySQLManager
{
/**
* @return Connection
* @throws Exception
*/
public static function getConnection() {
return DriverManager::getConnection(["driverClass" => MySQLDriver::class]);
}
}

View File

@@ -0,0 +1,37 @@
<?php /** @noinspection PhpComposerExtensionStubsInspection */
/** @noinspection PhpReturnDocTypeMismatchInspection */
namespace ZM\MySQL;
use PDO;
use Swoole\Database\PDOConfig;
use Swoole\Database\PDOPool;
use Swoole\Database\PDOProxy;
class MySQLPool extends PDOPool
{
private $count = 0;
public function __construct(PDOConfig $config, int $size = self::DEFAULT_SIZE) {
parent::__construct($config, $size);
}
/**
* @return PDO|PDOProxy|void
*/
public function getConnection() {
$this->count++;
return parent::get();
}
/**
* @param PDO|PDOProxy $connection
*/
public function putConnection($connection) {
$this->count--;
parent::put($connection);
}
}

View File

@@ -0,0 +1,78 @@
<?php /** @noinspection PhpComposerExtensionStubsInspection */
namespace ZM\MySQL;
use Doctrine\DBAL\Driver\Statement;
use Doctrine\DBAL\Driver\StatementIterator;
use Doctrine\DBAL\ParameterType;
use PDO;
use PDOStatement;
use Swoole\Database\PDOStatementProxy;
class MySQLStatement implements Statement, \IteratorAggregate
{
/** @var PDOStatement|PDOStatementProxy */
private $statement;
public function __construct($obj) {
$this->statement = $obj;
}
public function closeCursor() {
return $this->statement->closeCursor();
}
public function columnCount() {
return $this->statement->columnCount();
}
public function setFetchMode($fetchMode, $arg2 = null, $arg3 = []) {
return $this->statement->setFetchMode($fetchMode, $arg2, $arg3);
}
public function fetch($fetchMode = PDO::FETCH_ASSOC, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) {
return $this->statement->fetch($fetchMode, $cursorOrientation, $cursorOffset);
}
public function fetchAll($fetchMode = PDO::FETCH_ASSOC, $fetchArgument = null, $ctorArgs = null) {
return $this->statement->fetchAll($fetchMode, $fetchArgument, $ctorArgs);
}
public function fetchColumn($columnIndex = 0) {
return $this->statement->fetchColumn($columnIndex);
}
public function bindValue($param, $value, $type = ParameterType::STRING) {
return $this->statement->bindValue($param, $value, $type);
}
public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null) {
return $this->statement->bindParam($param, $variable, $type, $length);
}
public function errorCode() {
return $this->statement->errorCode();
}
public function errorInfo() {
return $this->statement->errorInfo();
}
public function execute($params = null) {
return $this->statement->execute($params);
}
public function rowCount() {
return $this->statement->rowCount();
}
public function getIterator() {
return new StatementIterator($this);
}
public function current() {
return $this->statement->current();
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace ZM\MySQL;
class MySQLWrapper
{
public $connection;
public function __construct() {
$this->connection = MySQLManager::getConnection();
}
public function __destruct() {
$this->connection->close();
}
}

View File

@@ -4,10 +4,10 @@
namespace ZM\Store\MySQL;
use Swoole\Database\PDOPool;
use ZM\MySQL\MySQLPool;
class SqlPoolStorage
{
/** @var PDOPool */
/** @var MySQLPool */
public static $sql_pool = null;
}

View File

@@ -4,14 +4,9 @@
namespace ZM\Utils;
use Swoole\Event;
use Swoole\Process;
use Swoole\Server;
use Swoole\Timer;
use ZM\Console\Console;
use ZM\Framework;
use ZM\Store\ZMBuf;
use ZM\Utils\Manager\ProcessManager;
/**
* 炸毛框架的Linux signal管理类
@@ -26,6 +21,7 @@ class SignalListener
* @param Server $server
*/
public static function signalMaster(Server $server) {
Console::debug("Listening Master SIGINT");
Process::signal(SIGINT, function () use ($server) {
if (zm_atomic("_int_is_reload")->get() === 1) {
zm_atomic("_int_is_reload")->set(0);
@@ -33,10 +29,6 @@ class SignalListener
} else {
echo "\r";
Console::warning("Server interrupted(SIGINT) on Master.");
if ((Framework::$server->inotify ?? null) !== null)
/** @noinspection PhpUndefinedFieldInspection */ Event::del(Framework::$server->inotify);
if (ZMBuf::$terminal !== null)
Event::del(ZMBuf::$terminal);
Process::kill($server->master_pid, SIGTERM);
}
});
@@ -47,8 +39,17 @@ class SignalListener
*/
public static function signalManager() {
$func = function () {
Console::verbose("Interrupted in manager!");
if (\server()->master_pid == \server()->manager_pid) {
echo "\r";
Console::warning("Server interrupted(SIGINT) on Manager.");
swoole_timer_after(2, function() {
Process::kill(posix_getpid(), SIGTERM);
});
} else {
Console::verbose("Interrupted in manager!");
}
};
Console::debug("Listening Manager SIGINT");
if (version_compare(SWOOLE_VERSION, "4.6.7") >= 0) {
Process::signal(SIGINT, $func);
} elseif (extension_loaded("pcntl")) {
@@ -62,14 +63,17 @@ class SignalListener
* @param $worker_id
*/
public static function signalWorker(Server $server, $worker_id) {
Console::debug("Listening Worker #".$worker_id." SIGINT");
Process::signal(SIGINT, function () use ($worker_id, $server) {
if ($server->master_pid == $server->worker_pid) {
echo "\r";
Console::warning("Server interrupted(SIGINT) on Worker.");
swoole_timer_after(2, function() {
Process::kill(posix_getpid(), SIGTERM);
});
}
//Console::verbose("Interrupted in worker");
// do nothing
});
if ($server->taskworker === false) {
Process::signal(SIGUSR1, function () use ($worker_id) {
Timer::clearAll();
ProcessManager::resumeAllWorkerCoroutines();
});
}
}
}

View File

@@ -0,0 +1,18 @@
<?php
// TODO 配置 ORM
use Doctrine\ORM\Tools\Setup;
use Doctrine\ORM\EntityManager;
$paths = array();
$isDevMode = false;
// the connection configuration
$dbParams = array(
'driver' => 'pdo_mysql',
'user' => 'root',
'password' => '',
'dbname' => 'foo',
);
$config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode);
$entityManager = EntityManager::create($dbParams, $config);