From beb1f5f0631789b25e7034b4b66c85bc059fe2fd Mon Sep 17 00:00:00 2001 From: jerry Date: Mon, 31 Aug 2020 10:11:06 +0800 Subject: [PATCH] initial 2.0 commit --- bin/phar-build | 60 ---- bin/start | 144 ++------- composer.json | 18 +- config/console_color.json | 20 ++ config/global.php | 6 +- phar-starter.php | 85 ----- src/Custom/Annotation/Example.php | 5 +- src/Custom/Connection/CustomConnection.php | 14 - src/Framework/Console.php | 277 ----------------- src/Framework/FrameworkLoader.php | 186 ----------- src/Framework/GlobalConfig.php | 37 --- src/Module/Example/Hello.php | 18 +- src/Module/Middleware/TimerMiddleware.php | 2 +- src/Scheduler/MessageEvent.php | 29 -- src/Scheduler/Scheduler.php | 140 --------- src/ZM/API/CQ.php | 2 +- src/ZM/API/CQAPI.php | 143 +-------- src/ZM/{Utils => API}/ZMRobot.php | 97 +++--- src/ZM/{Utils => API}/ZMRobotExperiment.php | 24 +- src/ZM/Annotation/AnnotationParser.php | 288 ++++++++++------- src/ZM/Annotation/Http/Controller.php | 5 +- src/ZM/Annotation/Http/Middleware.php | 3 +- src/ZM/Annotation/Http/RequestMapping.php | 4 +- src/ZM/Annotation/Http/RequestMethod.php | 3 +- .../Interfaces/ErgodicAnnotation.php | 10 + .../Annotation/Swoole/OnTaskWorkerStart.php | 15 - src/ZM/Command/BuildCommand.php | 73 +++++ src/ZM/Command/InitCommand.php | 101 ++++++ src/ZM/Command/RunServerCommand.php | 51 +++ src/ZM/Command/SystemdCommand.php | 20 ++ src/ZM/Connection/CQConnection.php | 23 -- src/ZM/Connection/ConnectionManager.php | 76 ----- src/ZM/Connection/ProxyConnection.php | 13 - src/ZM/Connection/TerminalConnection.php | 13 - src/ZM/Connection/UnknownConnection.php | 13 - src/ZM/Connection/WCConnection.php | 10 - src/ZM/Connection/WSConnection.php | 51 --- src/ZM/ConsoleApplication.php | 42 +++ src/ZM/Context/Context.php | 30 +- src/ZM/Context/ContextInterface.php | 6 +- src/ZM/DB/DB.php | 11 +- src/ZM/DB/SelectBody.php | 2 +- src/ZM/Event/CQ/MessageEvent.php | 31 +- src/ZM/Event/CQ/MetaEvent.php | 12 +- src/ZM/Event/CQ/NoticeEvent.php | 12 +- src/ZM/Event/CQ/RequestEvent.php | 13 +- src/ZM/Event/EventHandler.php | 35 ++- .../Event}/ServerEventHandler.php | 16 +- src/ZM/Event/Swoole/MessageEvent.php | 22 +- src/ZM/Event/Swoole/RequestEvent.php | 13 +- src/ZM/Event/Swoole/WSCloseEvent.php | 12 +- src/ZM/Event/Swoole/WSOpenEvent.php | 56 ++-- src/ZM/Event/Swoole/WorkerStartEvent.php | 101 +++--- src/ZM/Exception/WaitTimeoutException.php | 4 +- src/ZM/Framework.php | 292 ++++++++++++++++++ src/ZM/Http/StaticFileHandler.php | 2 +- src/ZM/ModBase.php | 170 ---------- src/ZM/ModHandleType.php | 20 -- src/{Framework => ZM/Store}/ZMBuf.php | 17 +- src/{Framework => ZM/Utils}/DataProvider.php | 11 +- src/{Framework => ZM/Utils}/RemoteShell.php | 3 +- src/ZM/Utils/SQLPool.php | 122 -------- src/ZM/Utils/ScheduleManager.php | 10 - src/ZM/Utils/Terminal.php | 126 ++++++++ src/ZM/Utils/ZMRequest.php | 11 +- src/ZM/Utils/ZMUtil.php | 22 +- src/ZM/Utils/ZMWebSocket.php | 2 +- .../Utils}/terminal_listener.php | 0 src/{Framework => ZM}/global_functions.php | 22 +- 69 files changed, 1237 insertions(+), 2090 deletions(-) delete mode 100755 bin/phar-build create mode 100644 config/console_color.json delete mode 100644 phar-starter.php delete mode 100644 src/Custom/Connection/CustomConnection.php delete mode 100755 src/Framework/Console.php delete mode 100644 src/Framework/FrameworkLoader.php delete mode 100644 src/Framework/GlobalConfig.php delete mode 100644 src/Scheduler/MessageEvent.php delete mode 100644 src/Scheduler/Scheduler.php rename src/ZM/{Utils => API}/ZMRobot.php (81%) rename src/ZM/{Utils => API}/ZMRobotExperiment.php (82%) create mode 100644 src/ZM/Annotation/Interfaces/ErgodicAnnotation.php delete mode 100644 src/ZM/Annotation/Swoole/OnTaskWorkerStart.php create mode 100644 src/ZM/Command/BuildCommand.php create mode 100644 src/ZM/Command/InitCommand.php create mode 100644 src/ZM/Command/RunServerCommand.php create mode 100644 src/ZM/Command/SystemdCommand.php delete mode 100644 src/ZM/Connection/CQConnection.php delete mode 100644 src/ZM/Connection/ConnectionManager.php delete mode 100644 src/ZM/Connection/ProxyConnection.php delete mode 100644 src/ZM/Connection/TerminalConnection.php delete mode 100644 src/ZM/Connection/UnknownConnection.php delete mode 100644 src/ZM/Connection/WCConnection.php delete mode 100644 src/ZM/Connection/WSConnection.php create mode 100644 src/ZM/ConsoleApplication.php rename src/{Framework => ZM/Event}/ServerEventHandler.php (80%) create mode 100644 src/ZM/Framework.php delete mode 100644 src/ZM/ModBase.php delete mode 100644 src/ZM/ModHandleType.php rename src/{Framework => ZM/Store}/ZMBuf.php (87%) rename src/{Framework => ZM/Utils}/DataProvider.php (91%) rename src/{Framework => ZM/Utils}/RemoteShell.php (98%) delete mode 100644 src/ZM/Utils/SQLPool.php delete mode 100644 src/ZM/Utils/ScheduleManager.php create mode 100644 src/ZM/Utils/Terminal.php rename src/{Framework => ZM/Utils}/terminal_listener.php (100%) rename src/{Framework => ZM}/global_functions.php (94%) diff --git a/bin/phar-build b/bin/phar-build deleted file mode 100755 index 9a5e437c..00000000 --- a/bin/phar-build +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env php -startBuffering(); - $src = realpath(__DIR__ . '/../'); - $hello = file_get_contents($src . '/src/Module/Example/Hello.php'); - $middleware = file_get_contents($src . '/src/Module/Middleware/TimerMiddleware.php'); - unlink($src . '/src/Module/Example/Hello.php'); - unlink($src . '/src/Module/Middleware/TimerMiddleware.php'); - if ($with_wechat_patch) { - global $wechat_patch; - $wechat = base64_decode($wechat_patch); - } else { - $wechat = false; - } - if ($wechat !== false) { - echo "Using wechat patch.\n"; - $modbase = file_get_contents($src . '/src/ZM/ModBase.php'); - unlink($src . '/src/ZM/ModBase.php'); - } - $phar->buildFromDirectory($src); - $phar->addFromString('tmp/Hello.php.bak', $hello); - $phar->addFromString('tmp/TimerMiddleware.php.bak', $middleware); - if ($wechat !== false) { - $phar->addFromString('src/ZM/ModBase.php', $wechat); - file_put_contents($src . '/src/ZM/ModBase.php', $modbase); - } - //$phar->compressFiles(Phar::GZ); - $phar->setStub($phar->createDefaultStub('phar-starter.php')); - $phar->stopBuffering(); - file_put_contents($src . '/src/Module/Example/Hello.php', $hello); - file_put_contents($src . '/src/Module/Middleware/TimerMiddleware.php', $middleware); - echo "Successfully built. Location: " . $src . "/resources/$filename\n"; -} - diff --git a/bin/start b/bin/start index 1a8d310b..78c7a2b8 100755 --- a/bin/start +++ b/bin/start @@ -1,135 +1,29 @@ #!/usr/bin/env php 30000, -]); -global $vendor_mode; -$vendor_mode = false; -if (mb_strpos(__DIR__, getcwd()) !== false && substr(str_replace(getcwd(), "", __DIR__), 0, 8) == "/vendor/") { +$symbol = sha1(is_file("/flag") ? file_get_contents("/flag") : '1') == '6252c0ec7fcbd544c3d6f5f0a162f60407d7a896' || mb_strpos(getcwd(), "/private/tmp"); + +// 首先得判断是直接从library模式启动的框架还是从composer引入library启动的框架 +// 判断方法:判断当前目录上面有没有 /vendor 目录,如果没有 /vendor 目录说明是从 composer 引入的 +// 否则就是直接从 framework 项目启动的 +if (!is_dir(__DIR__ . '/../vendor') || $symbol) { define("LOAD_MODE", 1); //composer项目模式 define("LOAD_MODE_COMPOSER_PATH", getcwd()); + /** @noinspection PhpIncludeInspection */ + require_once LOAD_MODE_COMPOSER_PATH . "/vendor/autoload.php"; +} elseif (substr(__DIR__, 0, 7) != 'phar://') { + define("LOAD_MODE", 2); //phar模式 + // 会废弃phar启动的方式,在2.0 } else { - define("LOAD_MODE", 0); //正常模式 -} - -date_default_timezone_set("Asia/Shanghai"); - -switch ($argv[1] ?? '') { - case 'scheduler': - case 'timer': - go(function () { - try { - new Scheduler(Scheduler::REMOTE); - } catch (Exception $e) { - die($e->getMessage()); - } - }); - break; - case 'phar-build': - array_shift($argv); - require_once 'phar-build'; - break; - case 'systemd': - array_shift($argv); - require_once 'systemd'; - break; - case 'init': - array_shift($argv); - if (LOAD_MODE != 1) { - echo "initialization must be started with composer-project mode!\n"; - exit(1); - } - $cwd = LOAD_MODE_COMPOSER_PATH; - echo "Copying default module file ..."; - @mkdir($cwd . "/config"); - @mkdir($cwd . "/src"); - @mkdir($cwd . "/src/Custom"); - @mkdir($cwd . "/src/Module"); - @mkdir($cwd . "/src/Module/Example"); - @mkdir($cwd . "/src/Module/Middleware"); - $ls = [ - "/config/global.php", - "/.gitignore", - "/config/file_header.json", - "/config/motd.txt", - "/src/Module/Example/Hello.php", - "/src/Module/Middleware/TimerMiddleware.php", - "/src/Custom/global_function.php" - ]; - foreach($ls as $v) { - if(!file_exists($cwd.$v)) { - echo "Copying ".$v.PHP_EOL; - copy($cwd."/vendor/zhamao/framework".$v, $cwd.$v); - } - } - $autoload = [ - "psr-4" => [ - "Module\\" => "src/Module", - "Custom\\" => "src/Custom" - ], - "files" => [ - "src/Custom/global_function.php" - ] - ]; - $scripts = [ - "server" => "vendor/bin/start server", - "server:log-debug" => "vendor/bin/start server --log-debug", - "server:log-verbose" => "vendor/bin/start server --log-verbose", - "server:log-info" => "vendor/bin/start server --log-info", - "server:log-warning" => "vendor/bin/start server --log-warning", - "server:debug-mode" => "vendor/bin/start server --debug-mode", - "systemd" => "vendor/bin/start systemd" - ]; - echo PHP_EOL; - if (file_exists($cwd . "/composer.json")) { - echo "Updating composer.json ..."; - $composer = json_decode(file_get_contents($cwd . "/composer.json"), true); - if (!isset($composer["autoload"])) { - $composer["autoload"] = $autoload; - } - if (!isset($composer["scripts"])) { - $composer["scripts"] = $scripts; - } - file_put_contents($cwd . "/composer.json", json_encode($composer, 64 | 128 | 256)); - echo PHP_EOL; - } else { - echo("Error occurred. Please check your updates.\n"); - exit(1); - } - echo "success!\n"; - break; - case '': - case 'framework': - case 'server': - if (!is_dir(__DIR__ . '/../vendor/') && LOAD_MODE == 0) { - echo "Warning: you have not update composer!\n"; - exec("composer update", $out, $var); - if ($var != 0) { - echo "You need to run \"composer update\" at root of zhamao-framework!\n"; - die; - } - } - $loader = new FrameworkLoader($argv); - break; - case '--help': - case '-h': - echo "\nUsage: " . $argv[0] . " [OPTION]\n"; - echo "\nzhamao-framework start script, provides several startup arguments."; - echo "\n\n -h, --help\t\tShow this help menu"; - echo "\n framework, server\tstart main framework, this is default option"; - echo "\n phar-build\t\tbuild a new phar archive"; - echo "\n init\t\t\tinitialize framework structure in this directory"; - echo "\n systemd\t\tgenerate a new systemd \".service\" file to use\n\n"; - break; - default: - echo "Unknown option \"{$argv[1]}\"!\n\"--help\" for more information\n"; - break; + define("LOAD_MODE", 0); + require_once __DIR__ . "/../vendor/autoload.php"; } +// 终端的命令行功能启动!! +$application = new ConsoleApplication("zhamao-framework"); +$application->initEnv(); +$application->run(); diff --git a/composer.json b/composer.json index 7c47d87b..c63eeedc 100644 --- a/composer.json +++ b/composer.json @@ -3,7 +3,7 @@ "description": "High performance QQ robot and web server development framework", "minimum-stability": "stable", "license": "Apache-2.0", - "version": "1.6.2", + "version": "2.0.0-a1", "authors": [ { "name": "whale", @@ -28,14 +28,24 @@ "ext-posix": "*", "ext-ctype": "*", "ext-pdo": "*", - "psy/psysh": "@stable" + "psy/psysh": "@stable", + "symfony/console": "^5.1", + "symfony/polyfill-ctype": "^1.18", + "zhamao/connection-manager": "^1.0", + "zhamao/console": "^1.0", + "zhamao/config": "^1.0" }, "autoload": { "psr-4": { "Custom\\": "src/Custom", - "Framework\\": "src/Framework", "ZM\\": "src/ZM", "Module\\": "src/Module" - } + }, + "files": [ + "src/ZM/global_functions.php" + ] + }, + "require-dev": { + "phpunit/phpunit": "^9.3" } } diff --git a/config/console_color.json b/config/console_color.json new file mode 100644 index 00000000..e398759f --- /dev/null +++ b/config/console_color.json @@ -0,0 +1,20 @@ +{ + "default": { + "success": "green", + "info": "lightblue", + "warning": "yellow", + "error": "red", + "verbose": "blue", + "debug": "gray", + "trace": "gray" + }, + "white-term": { + "success": "green", + "info": "black", + "warning": "yellow", + "error": "red", + "verbose": "blue", + "debug": "gray", + "trace": "gray" + } +} diff --git a/config/global.php b/config/global.php index 2a3627ea..14ebf7cd 100644 --- a/config/global.php +++ b/config/global.php @@ -27,6 +27,7 @@ $config['swoole'] = [ 'log_file' => $config['crash_dir'] . 'swoole_error.log', 'worker_num' => 1, 'dispatch_mode' => 2, + 'max_coroutine' => 30000, //'task_worker_num' => 1, //'task_enable_coroutine' => true ]; @@ -68,9 +69,10 @@ $config['init_atomics'] = [ 'out_count' => 0, //消息发送(调用send_*_msg的统计数量) 'reload_time' => 0, //调用reload功能统计数量 'wait_msg_id' => 0, //协程挂起id自增 - 'info_level' => 2, //终端显示的log等级 ]; +$config["info_level"] = 2; + /** 自动保存的缓存保存时间(秒) */ $config['auto_save_interval'] = 900; @@ -88,7 +90,7 @@ $config['static_file_server'] = [ /** 注册 Swoole Server 事件注解的类列表 */ $config['server_event_handler_class'] = [ - \Framework\ServerEventHandler::class, + \ZM\Event\ServerEventHandler::class, ]; return $config; diff --git a/phar-starter.php b/phar-starter.php deleted file mode 100644 index ba2fc9a0..00000000 --- a/phar-starter.php +++ /dev/null @@ -1,85 +0,0 @@ - 30000, -]); - -date_default_timezone_set("Asia/Shanghai"); - -define('WORKING_DIR', __DIR__); -define('FRAMEWORK_DIR', __DIR__); -define('LOAD_MODE', 2); - -$s = new FrameworkLoader($argv); - -function loadPhp($dir) { - $dirs = scandir($dir); - foreach ($dirs as $v) { - $path = $dir . '/' . $v; - if (is_dir($path)) { - loadPhp($path); - } else { - if (pathinfo($dir . '/' . $v)['extension'] == 'php') { - if(pathinfo($dir . '/' . $v)['basename'] == 'terminal_listener.php') continue; - //echo 'loading '.$path.PHP_EOL; - require_once $path; - } - } - } -} - -function testEnvironment() { - $current_dir = realpath('.'); - @mkdir($current_dir . '/config/'); - if (!is_file($current_dir . '/config/global.php')) { - echo "Exporting default global config...\n"; - $global = file_get_contents(__DIR__ . '/config/global.php'); - $global = str_replace("WORKING_DIR", 'realpath(__DIR__ . "/../")', $global); - file_put_contents($current_dir . '/config/global.php', $global); - } - if (!is_file($current_dir . '/config/file_header.json')) { - echo "Exporting default file_header config...\n"; - $global = file_get_contents(__DIR__ . '/config/file_header.json'); - file_put_contents($current_dir . '/config/file_header.json', $global); - } - if (!is_dir($current_dir . '/resources')) mkdir($current_dir . '/resources'); - if (!is_dir($current_dir . '/src')) mkdir($current_dir . '/src'); - if (!is_dir($current_dir . '/src')) mkdir($current_dir . '/src'); - if (!is_dir($current_dir . '/src/Module')) { - mkdir($current_dir . '/src/Module'); - mkdir($current_dir . '/src/Module/Example'); - file_put_contents($current_dir . '/src/Module/Example/Hello.php', file_get_contents(__DIR__ . '/tmp/Hello.php.bak')); - mkdir($current_dir . '/src/Module/Middleware'); - file_put_contents($current_dir . '/src/Module/Middleware/TimerMiddleware.php', file_get_contents(__DIR__ . '/tmp/TimerMiddleware.php.bak')); - } - if (!is_dir($current_dir . '/src/Custom')) { - mkdir($current_dir . '/src/Custom'); - mkdir($current_dir . '/src/Custom/Annotation'); - mkdir($current_dir . '/src/Custom/Connection'); - file_put_contents($current_dir . '/src/Custom/global_function.php', "get(), [1, 2])) { - $trace = debug_backtrace()[1] ?? ['file' => '', 'function' => '']; - $trace = "[" . basename($trace["file"], ".php") . ":" . $trace["function"] . "] "; - } - if (!is_string($obj)) { - if (isset($trace)) { - var_dump($obj); - return; - } else $obj = "{Object}"; - } - echo(self::setColor($head . ($trace ?? "") . $obj, "red") . "\n"); - } - - static function warning($obj, $head = null) { - if ($head === null) $head = date("[H:i:s]") . " [W] "; - if (ZMBuf::$info_level !== null && in_array(ZMBuf::$info_level->get(), [1, 2])) { - $trace = debug_backtrace()[1] ?? ['file' => '', 'function' => '']; - $trace = "[" . basename($trace["file"], ".php") . ":" . $trace["function"] . "] "; - } - if (ZMBuf::$atomics["info_level"]->get() >= 1) { - if (!is_string($obj)) { - if (isset($trace)) { - var_dump($obj); - return; - } else $obj = "{Object}"; - } - echo(self::setColor($head . ($trace ?? "") . $obj, in_array("--white-term", FrameworkLoader::$argv) ? "blue" : "yellow") . "\n"); - } - } - - static function info($obj, $head = null) { - if ($head === null) $head = date("[H:i:s] ") . "[I] "; - if (ZMBuf::$info_level !== null && in_array(ZMBuf::$info_level->get(), [1, 2])) { - $trace = debug_backtrace()[1] ?? ['file' => '', 'function' => '']; - $trace = "[" . basename($trace["file"], ".php") . ":" . $trace["function"] . "] "; - } - if (ZMBuf::$atomics["info_level"]->get() >= 2) { - if (!is_string($obj)) { - if (isset($trace)) { - var_dump($obj); - return; - } else $obj = "{Object}"; - } - echo(self::setColor($head . ($trace ?? "") . $obj, in_array("--white-term", FrameworkLoader::$argv) ? "black" : "lightblue") . "\n"); - } - } - - static function success($obj, $head = null) { - if ($head === null) $head = date("[H:i:s] ") . "[S] "; - if (ZMBuf::$info_level !== null && in_array(ZMBuf::$info_level->get(), [1, 2])) { - $trace = debug_backtrace()[1] ?? ['file' => '', 'function' => '']; - $trace = "[" . basename($trace["file"], ".php") . ":" . $trace["function"] . "] "; - } - if (ZMBuf::$atomics["info_level"]->get() >= 2) { - if (!is_string($obj)) { - if (isset($trace)) { - var_dump($obj); - return; - } else $obj = "{Object}"; - } - echo(self::setColor($head . ($trace ?? "") . $obj, "green") . "\n"); - } - } - - static function verbose($obj, $head = null) { - if ($head === null) $head = date("[H:i:s] ") . "[V] "; - if (ZMBuf::$atomics["info_level"]->get() >= 3) { - if (!is_string($obj)) { - if (isset($trace)) { - var_dump($obj); - return; - } else $obj = "{Object}"; - } - echo(self::setColor($head . ($trace ?? "") . $obj, "blue") . "\n"); - } - } - - static function debug($msg) { - if (ZMBuf::$atomics["info_level"]->get() >= 4) Console::log(date("[H:i:s] ") . "[D] " . $msg, 'gray'); - } - - static function log($obj, $color = "") { - if (!is_string($obj)) var_dump($obj); - else echo(self::setColor($obj, $color) . "\n"); - } - - static function stackTrace() { - $log = "Stack trace:\n"; - $trace = debug_backtrace(); - //array_shift($trace); - foreach ($trace as $i => $t) { - if (!isset($t['file'])) { - $t['file'] = 'unknown'; - } - if (!isset($t['line'])) { - $t['line'] = 0; - } - if (!isset($t['function'])) { - $t['function'] = 'unknown'; - } - $log .= "#$i {$t['file']}({$t['line']}): "; - if (isset($t['object']) and is_object($t['object'])) { - $log .= get_class($t['object']) . '->'; - } - $log .= "{$t['function']}()\n"; - } - $log = Console::setColor($log, "gray"); - echo $log; - } - - static function listenConsole() { - if (in_array('--disable-console-input', FrameworkLoader::$argv) || in_array('--debug-mode', FrameworkLoader::$argv)) { - self::info("ConsoleCommand disabled."); - return; - } - global $terminal_id; - global $port; - $port = ZMBuf::globals("port"); - $vss = new SwooleEventAt(); - $vss->type = "open"; - $vss->level = 256; - $vss->rule = "connectType:terminal"; - $terminal_id = call_user_func(function () { - try { - $data = random_bytes(16); - } catch (Exception $e) { - return ""; - } - $data[6] = chr(ord($data[6]) & 0x0f | 0x40); - $data[8] = chr(ord($data[8]) & 0x3f | 0x80); - return strtoupper(vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4))); - }); - $vss->callback = function(?WSConnection $conn) use ($terminal_id){ - $req = ctx()->getRequest(); - if($conn->getType() != "terminal") return false; - Console::debug("Terminal fd: ".$conn->fd); - if(($req->header["x-terminal-id"] ?? "") != $terminal_id) { - $conn->close(); - return false; - } - return false; - }; - ZMBuf::$events[SwooleEventAt::class][] = $vss; - $vss2 = new SwooleEventAt(); - $vss2->type = "message"; - $vss2->rule = "connectType:terminal"; - $vss2->callback = function(?WSConnection $conn){ - if ($conn === null) return false; - if($conn->getType() != "terminal") return false; - $cmd = ctx()->getFrame()->data; - self::executeCommand($cmd); - return false; - }; - ZMBuf::$events[SwooleEventAt::class][] = $vss2; - go(function () { - global $terminal_id, $port; - $descriptorspec = array( - 0 => STDIN, - 1 => STDOUT, - 2 => STDERR - ); - self::$console_proc = proc_open('php -r \'$terminal_id = "'.$terminal_id.'";$port = '.$port.';require "'.__DIR__.'/terminal_listener.php";\'', $descriptorspec, $pipes); - }); - } - - /** - * @param string $cmd - * @return bool - */ - private static function executeCommand(string $cmd) { - $it = explodeMsg($cmd); - switch ($it[0] ?? '') { - case 'logtest': - Console::log(date("[H:i:s]") . " [L] This is normal msg. (0)"); - Console::error("This is error msg. (0)"); - Console::warning("This is warning msg. (1)"); - Console::info("This is info msg. (2)"); - Console::success("This is success msg. (2)"); - Console::verbose("This is verbose msg. (3)"); - Console::debug("This is debug msg. (4)"); - return true; - case 'call': - $class_name = $it[1]; - $function_name = $it[2]; - $class = new $class_name([]); - call_user_func_array([$class, $function_name], []); - return true; - case 'bc': - $code = base64_decode($it[1] ?? '', true); - try { - eval($code); - } catch (Exception $e) { - } - return true; - case 'echo': - Console::info($it[1]); - return true; - case 'color': - Console::log($it[2], $it[1]); - return true; - case 'stop': - ZMUtil::stop(); - return false; - case 'reload': - case 'r': - ZMUtil::reload(); - return false; - case 'save': - $origin = ZMBuf::$atomics["info_level"]->get(); - //ZMBuf::$atomics["info_level"]->set(3); - DataProvider::saveBuffer(); - //ZMBuf::$atomics["info_level"]->set($origin); - return true; - case '': - return true; - default: - Console::info("Command not found: " . $cmd); - return true; - } - } - - public static function withSleep(string $string, int $int) { - self::info($string); - sleep($int); - } -} diff --git a/src/Framework/FrameworkLoader.php b/src/Framework/FrameworkLoader.php deleted file mode 100644 index 3a93219d..00000000 --- a/src/Framework/FrameworkLoader.php +++ /dev/null @@ -1,186 +0,0 @@ -requireGlobalFunctions(); - if (LOAD_MODE == 0) define("WORKING_DIR", getcwd()); - elseif (LOAD_MODE == 1) define("WORKING_DIR", realpath(__DIR__ . "/../../")); - elseif (LOAD_MODE == 2) echo "Phar mode: " . WORKING_DIR . PHP_EOL; - //$this->registerAutoloader('classLoader'); - require_once "DataProvider.php"; - if (file_exists(DataProvider::getWorkingDir() . "/vendor/autoload.php")) { - /** @noinspection PhpIncludeInspection */ - require_once DataProvider::getWorkingDir() . "/vendor/autoload.php"; - } - if (LOAD_MODE == 2) { - require_once FRAMEWORK_DIR . "/vendor/autoload.php"; - spl_autoload_register('phar_classloader'); - } - - - self::$settings = new GlobalConfig(); - if (self::$settings->get("debug_mode") === true) { - $args[] = "--debug-mode"; - $args[] = "--disable-console-input"; - } - self::$argv = $args; - if (!in_array("--debug-mode", self::$argv)) { - Runtime::enableCoroutine(true, SWOOLE_HOOK_ALL); - } - self::$settings = new GlobalConfig(); - ZMBuf::$globals = self::$settings; - if (!self::$settings->success) die("Failed to load global config. Please check config/global.php file"); - $this->defineProperties(); - - //start swoole Framework - $this->selfCheck(); - try { - $this->server = new Server(self::$settings->get("host"), self::$settings->get("port")); - $settings = self::$settings->get("swoole"); - if (in_array("--daemon", $args)) { - $settings["daemonize"] = 1; - Console::log("已启用守护进程,输出重定向到 " . $settings["log_file"]); - self::$argv[] = "--disable-console-input"; - } - $this->server->set($settings); - $all_event_class = self::$settings->get("server_event_handler_class") ?? []; - if (!in_array(ServerEventHandler::class, $all_event_class)) { - $all_event_class[] = ServerEventHandler::class; - } - $event_list = []; - foreach ($all_event_class as $v) { - $reader = new AnnotationReader(); - $reflection_class = new ReflectionClass($v); - $methods = $reflection_class->getMethods(ReflectionMethod::IS_PUBLIC); - foreach ($methods as $vs) { - $method_annotations = $reader->getMethodAnnotations($vs); - if ($method_annotations != []) { - $annotation = $method_annotations[0]; - if ($annotation instanceof OnEvent) { - $annotation->class = $v; - $annotation->method = $vs->getName(); - $event_list[strtolower($annotation->event)] = $annotation; - } - } - } - } - foreach ($event_list as $k => $v) { - $this->server->on($k, function (...$param) use ($v) { - $c = $v->class; - //echo $c.PHP_EOL; - $c = new $c(); - call_user_func_array([$c, $v->method], $param); - }); - } - - ZMBuf::initAtomic(); - if (in_array("--remote-shell", $args)) RemoteShell::listen($this->server, "127.0.0.1"); - if (in_array("--log-error", $args)) ZMBuf::$atomics["info_level"]->set(0); - if (in_array("--log-warning", $args)) ZMBuf::$atomics["info_level"]->set(1); - if (in_array("--log-info", $args)) ZMBuf::$atomics["info_level"]->set(2); - if (in_array("--log-verbose", $args)) ZMBuf::$atomics["info_level"]->set(3); - if (in_array("--log-debug", $args)) ZMBuf::$atomics["info_level"]->set(4); - Console::log( - "host: " . self::$settings->get("host") . - ", port: " . self::$settings->get("port") . - ", log_level: " . ZMBuf::$atomics["info_level"]->get() . - ", version: " . ZM_VERSION . - "\nworking_dir: " . DataProvider::getWorkingDir() - ); - global $motd; - if (!file_exists(DataProvider::getWorkingDir() . "/config/motd.txt")) { - echo $motd; - } else { - echo file_get_contents(DataProvider::getWorkingDir() . "/config/motd.txt"); - } - if (in_array("--debug-mode", self::$argv)) - Console::warning("You are in debug mode, do not use in production!"); - $this->server->start(); - } catch (Exception $e) { - Console::error("Framework初始化出现错误,请检查!"); - Console::error($e->getMessage()); - die; - } - } - - private function requireGlobalFunctions() { - require_once __DIR__ . '/global_functions.php'; - } - - private function defineProperties() { - define("ZM_START_TIME", microtime(true)); - define("ZM_DATA", self::$settings->get("zm_data")); - define("ZM_VERSION", json_decode(file_get_contents(__DIR__ . "/../../composer.json"), true)["version"] ?? "unknown"); - define("CONFIG_DIR", self::$settings->get("config_dir")); - define("CRASH_DIR", self::$settings->get("crash_dir")); - @mkdir(ZM_DATA); - @mkdir(CONFIG_DIR); - @mkdir(CRASH_DIR); - define("ZM_MATCH_ALL", 0); - define("ZM_MATCH_FIRST", 1); - define("ZM_MATCH_NUMBER", 2); - define("ZM_MATCH_SECOND", 3); - define("ZM_BREAKPOINT", 'if(in_array("--debug-mode", \Framework\FrameworkLoader::$argv)) extract(\Psy\debug(get_defined_vars(), isset($this) ? $this : @get_called_class()));'); - define("BP", ZM_BREAKPOINT); - define("ZM_DEFAULT_FETCH_MODE", self::$settings->get("sql_config")["sql_default_fetch_mode"] ?? 4); - } - - private function selfCheck() { - if (!extension_loaded("swoole")) die("Can not find swoole extension.\n"); - if (version_compare(SWOOLE_VERSION, "4.4.13") == -1) die("You must install swoole version >= 4.4.13 !"); - //if (!extension_loaded("gd")) die("Can not find gd extension.\n"); - if (!extension_loaded("sockets")) die("Can not find sockets extension.\n"); - if (!extension_loaded("ctype")) die("Can not find ctype extension.\n"); - if (!function_exists("mb_substr")) die("Can not find mbstring extension.\n"); - if (substr(PHP_VERSION, 0, 1) != "7") die("PHP >=7 required.\n"); - //if (!function_exists("curl_exec")) die("Can not find curl extension.\n"); - //if (!class_exists("ZipArchive")) die("Can not find Zip extension.\n"); - //if (!file_exists(CRASH_DIR . "last_error.log")) die("Can not find log file.\n"); - return true; - } -} - -global $motd; -$motd = <<success = true; - $this->config = $config; - } - - public function get($key) { - $r = $this->config[$key] ?? null; - if ($r === null) return null; - return $r; - } - - public function getAll() { - return $this->config; - } -} diff --git a/src/Module/Example/Hello.php b/src/Module/Example/Hello.php index b87b350c..0539f93f 100644 --- a/src/Module/Example/Hello.php +++ b/src/Module/Example/Hello.php @@ -4,12 +4,12 @@ namespace Module\Example; -use Framework\Console; +use ZM\ConnectionManager\ConnectionObject; +use ZM\Console\Console; use ZM\Annotation\CQ\CQCommand; use ZM\Annotation\Http\Middleware; use ZM\Annotation\Http\RequestMapping; use ZM\Annotation\Swoole\SwooleEventAt; -use ZM\Connection\CQConnection; use ZM\Utils\ZMUtil; /** @@ -24,8 +24,8 @@ class Hello * @SwooleEventAt("open",rule="connectType:qq") * @param $conn */ - public function onConnect(CQConnection $conn) { - Console::info("机器人 " . $conn->getQQ() . " 已连接!"); + public function onConnect(ConnectionObject $conn) { + Console::info("机器人 " . $conn->getOption("connect_id") . " 已连接!"); } /** @@ -34,7 +34,7 @@ class Hello */ public function onDisconnect() { $conn = ctx()->getConnection(); - Console::info("机器人 " . $conn->getQQ() . " 已断开连接!"); + Console::info("机器人 " . $conn->getOption("connect_id") . " 已断开连接!"); } /** @@ -60,13 +60,13 @@ class Hello */ public function randNum($arg) { // 获取第一个数字类型的参数 - $num1 = context()->getArgs($arg, ZM_MATCH_NUMBER, "请输入第一个数字"); + $num1 = ctx()->getArgs($arg, ZM_MATCH_NUMBER, "请输入第一个数字"); // 获取第二个数字类型的参数 - $num2 = context()->getArgs($arg, ZM_MATCH_NUMBER, "请输入第二个数字"); + $num2 = ctx()->getArgs($arg, ZM_MATCH_NUMBER, "请输入第二个数字"); $a = min(intval($num1), intval($num2)); $b = max(intval($num1), intval($num2)); // 回复用户结果 - context()->reply("随机数是:".mt_rand($a, $b)); + ctx()->reply("随机数是:".mt_rand($a, $b)); } /** @@ -94,6 +94,6 @@ class Hello */ public function closeUnknownConn() { Console::info("Unknown connection , I will close it."); - context()->getConnection()->close(); + server()->close(ctx()->getConnection()->getFd()); } } diff --git a/src/Module/Middleware/TimerMiddleware.php b/src/Module/Middleware/TimerMiddleware.php index e78e8b67..8968c4ea 100644 --- a/src/Module/Middleware/TimerMiddleware.php +++ b/src/Module/Middleware/TimerMiddleware.php @@ -2,10 +2,10 @@ namespace Module\Middleware; -use Framework\Console; use ZM\Annotation\Http\After; use ZM\Annotation\Http\Before; use ZM\Annotation\Http\MiddlewareClass; +use ZM\Console\Console; use ZM\Http\MiddlewareInterface; /** diff --git a/src/Scheduler/MessageEvent.php b/src/Scheduler/MessageEvent.php deleted file mode 100644 index b3e67f6e..00000000 --- a/src/Scheduler/MessageEvent.php +++ /dev/null @@ -1,29 +0,0 @@ -client = $client; - $this->frame = $frame; - } - - public function onActivate() { - //TODO: 写Scheduler计时器内的处理逻辑 - } -} \ No newline at end of file diff --git a/src/Scheduler/Scheduler.php b/src/Scheduler/Scheduler.php deleted file mode 100644 index 3d8a1deb..00000000 --- a/src/Scheduler/Scheduler.php +++ /dev/null @@ -1,140 +0,0 @@ -initProcess(); - elseif ($method == self::REMOTE) $this->initRemote(); - } - - private function initProcess() { //TODO: 完成Process模式的代码 - $m_pid = posix_getpid(); - $this->process = new Process(function (Process $worker) use ($m_pid) { self::onWork($worker, $m_pid); }, false, 2, true); - $this->pid = $this->process->start(); - while (1) { - $ret = Process::wait(); - if ($ret) { - $this->process = new Process(function (Process $worker) use ($m_pid) { self::onWork($worker, $m_pid); }, false, 2, true); - $this->pid = $this->process->start(); - echo "Reboot done.\n"; - } - } - } - - private function initRemote() { - define('WORKING_DIR', __DIR__ . '../..'); - $this->requireGlobalFunctions(); - $this->registerAutoloader('classLoader'); - $this->settings = new GlobalConfig(); - if (!$this->settings->success) die("Failed to load global config. Please check config/global.php file"); - $this->defineProperties(); - - //start swoole Framework - $this->selfCheck(); - try { - $host = $this->settings->get("scheduler")["host"]; - $port = $this->settings->get("scheduler")["port"]; - $token = $this->settings->get("scheduler")["token"]; - $this->client = new Client($host, $port); - $path = "/" . ($token != "" ? ("?token=" . urlencode($token)) : ""); - while (true) { - if ($this->client->upgrade($path)) { - while (true) { - $recv = $this->client->recv(); - if ($recv instanceof Frame) { - (new MessageEvent($this->client, $recv))->onActivate(); - } else { - break; - } - } - } else { - Console::warning("无法连接Framework,将在5秒后重连..."); - Coroutine::sleep(5); - } - } - } catch (Exception $e) { - Console::error($e); - } - } - - private function requireGlobalFunctions() { - /** @noinspection PhpIncludeInspection */ - require WORKING_DIR . '/src/Framework/global_functions.php'; - } - - private function registerAutoloader(string $string) { - if (!spl_autoload_register($string)) die("Failed to register autoloader named \"$string\" !"); - } - - private function defineProperties() { - define("ZM_START_TIME", microtime(true)); - define("ZM_DATA", $this->settings->get("zm_data")); - //define("CONFIG_DIR", $this->settings->get("config_dir")); - define("CRASH_DIR", $this->settings->get("crash_dir")); - } - - private function selfCheck() { - if (!extension_loaded("swoole")) die("Can not find swoole extension.\n"); - if (!extension_loaded("sockets")) die("Can not find sockets extension.\n"); - if (!function_exists("mb_substr")) die("Can not find mbstring extension.\n"); - if (substr(PHP_VERSION, 0, 1) != "7") die("PHP >=7 required.\n"); - //if (!class_exists("ZipArchive")) die("Can not find Zip extension.\n"); - if (!file_exists(CRASH_DIR . "last_error.log")) die("Can not find log file.\n"); - return true; - } - - private static function onWork(Process $worker, $m_pid) { - swoole_set_process_name('php-scheduler'); - for ($j = 0; $j < 16000; $j++) { - self::checkMpid($worker, $m_pid); - echo "msg: {$j}\n"; - sleep(1); - } - } - - private static function checkMpid(Process $worker, $m_pid) { - if (!Process::kill($m_pid, 0)) { - $worker->exit(); //主进程死了我也死 - // 这句提示,实际是看不到的.需要写到日志中 - echo "Master process exited, I [{$worker['pid']}] also quit\n"; - } - } -} \ No newline at end of file diff --git a/src/ZM/API/CQ.php b/src/ZM/API/CQ.php index d8e172d4..346fa8ce 100644 --- a/src/ZM/API/CQ.php +++ b/src/ZM/API/CQ.php @@ -4,7 +4,7 @@ namespace ZM\API; -use Framework\Console; +use ZM\Console\Console; use ZM\Utils\ZMUtil; class CQ diff --git a/src/ZM/API/CQAPI.php b/src/ZM/API/CQAPI.php index b715a595..605c00b3 100644 --- a/src/ZM/API/CQAPI.php +++ b/src/ZM/API/CQAPI.php @@ -3,14 +3,11 @@ namespace ZM\API; - use Co; -use Framework\Console; -use Framework\ZMBuf; -use ZM\Connection\ConnectionManager; -use ZM\Connection\CQConnection; +use ZM\ConnectionManager\ConnectionObject; +use ZM\Console\Console; use ZM\Event\EventHandler; -use ZM\Utils\ZMRobot; +use ZM\Store\ZMBuf; /** * @method static send_private_msg($self_id, $params, $function = null) @@ -67,143 +64,15 @@ use ZM\Utils\ZMRobot; * @method static set_friend_add_request_async($self_id, $params, $function = null) * @method static set_group_add_request_async($self_id, $params, $function = null) */ -class CQAPI +trait CQAPI { - public static function quick_reply(CQConnection $conn, $data, $msg, $yield = null) { - switch ($data["message_type"]) { - case "group": - return (new ZMRobot($conn))->setCallback($yield)->sendGroupMsg($data["group_id"], $msg); - case "private": - return (new ZMRobot($conn))->setCallback($yield)->sendPrivateMsg($data["user_id"], $msg); - case "discuss": - return (new ZMRobot($conn))->setCallback($yield)->sendDiscussMsg($data["discuss_id"], $msg); - } - return null; - } - /** - * @param $name - * @param $arg - * @return bool - * @deprecated - */ - public static function __callStatic($name, $arg) { - trigger_error("This dynamic CQAPI calling method will be removed after 2.0 version.", E_USER_DEPRECATED); - $all = self::getSupportedAPIs(); - $find = null; - if (in_array($name, $all)) $find = $name; - else { - foreach ($all as $v) { - if (strtolower($name) == strtolower(str_replace("_", "", $v))) { - $find = $v; - break; - } - } - } - if ($find === null) { - Console::warning("Unknown API " . $name); - return false; - } - $reply = ["action" => $find]; - if (!is_array($arg[1])) { - Console::warning("Error when parsing params. Please make sure your params is an array."); - return false; - } - if ($arg[1] != []) { - $reply["params"] = $arg[1]; - } - if (!($arg[0] instanceof CQConnection)) { - $robot = ConnectionManager::getByType("qq", ["self_id" => $arg[0]]); - if ($robot == []) { - Console::warning("发送错误,机器人连接不存在!"); - return false; - } - $arg[0] = $robot[0]; - } - return self::processAPI($arg[0], $reply, $arg[2] ?? null); - } - - /********************** non-API Part **********************/ - - private static function getSupportedAPIs() { - return [ - "send_private_msg", - "send_group_msg", - "send_discuss_msg", - "send_msg", - "delete_msg", - "send_like", - "set_group_kick", - "set_group_ban", - "set_group_anonymous_ban", - "set_group_whole_ban", - "set_group_admin", - "set_group_anonymous", - "set_group_card", - "set_group_leave", - "set_group_special_title", - "set_discuss_leave", - "set_friend_add_request", - "set_group_add_request", - "get_login_info", - "get_stranger_info", - "get_group_list", - "get_group_member_info", - "get_group_member_list", - "get_cookies", - "get_csrf_token", - "get_credentials", - "get_record", - "get_status", - "get_version_info", - "set_restart", - "set_restart_plugin", - "clean_data_dir", - "clean_plugin_log", - "_get_friend_list", - "_get_group_info", - "_get_vip_info", - //异步API - "send_private_msg_async", - "send_group_msg_async", - "send_discuss_msg_async", - "send_msg_async", - "delete_msg_async", - "set_group_kick_async", - "set_group_ban_async", - "set_group_anonymous_ban_async", - "set_group_whole_ban_async", - "set_group_admin_async", - "set_group_anonymous_async", - "set_group_card_async", - "set_group_leave_async", - "set_group_special_title_async", - "set_discuss_leave_async", - "set_friend_add_request_async", - "set_group_add_request_async" - ]; - } - - public static function getLoggedAPIs() { - return [ - "send_private_msg", - "send_group_msg", - "send_discuss_msg", - "send_msg", - "send_private_msg_async", - "send_group_msg_async", - "send_discuss_msg_async", - "send_msg_async" - ]; - } - - /** - * @param CQConnection $connection + * @param ConnectionObject $connection * @param $reply * @param |null $function * @return bool|array */ - public static function processAPI($connection, $reply, $function = null) { + private function processAPI($connection, $reply, $function = null) { $api_id = ZMBuf::$atomics["wait_msg_id"]->get(); $reply["echo"] = $api_id; ZMBuf::$atomics["wait_msg_id"]->add(1); diff --git a/src/ZM/Utils/ZMRobot.php b/src/ZM/API/ZMRobot.php similarity index 81% rename from src/ZM/Utils/ZMRobot.php rename to src/ZM/API/ZMRobot.php index 13184072..ad823906 100644 --- a/src/ZM/Utils/ZMRobot.php +++ b/src/ZM/API/ZMRobot.php @@ -1,11 +1,10 @@ - $robot_id]); - if ($r == []) throw new RobotNotFoundException("机器人 " . $robot_id . " 未连接到框架!"); - return new ZMRobot($r[0]); + $r = ManagerGM::getAllByName('qq'); + foreach($r as $v) { + if($v->getOption('connect_id') == $robot_id) return new ZMRobot($v); + } + throw new RobotNotFoundException("机器人 " . $robot_id . " 未连接到框架!"); } /** @@ -40,12 +43,12 @@ class ZMRobot * @return ZMRobot */ public static function getRandom() { - $r = ConnectionManager::getByType("qq"); + $r = ManagerGM::getAllByName('qq'); if($r == []) throw new RobotNotFoundException("没有任何机器人连接到框架!"); return new ZMRobot($r[array_rand($r)]); } - public function __construct(CQConnection $connection) { + public function __construct(ConnectionObject $connection) { $this->connection = $connection; } @@ -60,7 +63,7 @@ class ZMRobot } public function sendPrivateMsg($user_id, $message, $auto_escape = false) { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__), 'params' => [ 'user_id' => $user_id, @@ -71,7 +74,7 @@ class ZMRobot } public function sendGroupMsg($group_id, $message, $auto_escape = false) { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__), 'params' => [ 'group_id' => $group_id, @@ -82,7 +85,7 @@ class ZMRobot } public function sendDiscussMsg($discuss_id, $message, $auto_escape = false) { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__), 'params' => [ 'discuss_id' => $discuss_id, @@ -93,7 +96,7 @@ class ZMRobot } public function sendMsg($message_type, $target_id, $message, $auto_escape = false) { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__), 'params' => [ 'message_type' => $message_type, @@ -105,7 +108,7 @@ class ZMRobot } public function deleteMsg($message_id) { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__), 'params' => [ 'message_id' => $message_id @@ -114,7 +117,7 @@ class ZMRobot } public function sendLike($user_id, $times = 1) { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__), 'params' => [ 'user_id' => $user_id, @@ -124,7 +127,7 @@ class ZMRobot } public function setGroupKick($group_id, $user_id, $reject_add_request = false) { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__), 'params' => [ 'group_id' => $group_id, @@ -135,7 +138,7 @@ class ZMRobot } public function setGroupBan($group_id, $user_id, $duration = 1800) { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__), 'params' => [ 'group_id' => $group_id, @@ -146,7 +149,7 @@ class ZMRobot } public function setGroupAnonymousBan($group_id, $anonymous_or_flag, $duration = 1800) { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__), 'params' => [ 'group_id' => $group_id, @@ -157,7 +160,7 @@ class ZMRobot } public function setGroupWholeBan($group_id, $enable = true) { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__), 'params' => [ 'group_id' => $group_id, @@ -167,7 +170,7 @@ class ZMRobot } public function setGroupAdmin($group_id, $user_id, $enable = true) { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__), 'params' => [ 'group_id' => $group_id, @@ -178,7 +181,7 @@ class ZMRobot } public function setGroupAnonymous($group_id, $enable = true) { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__), 'params' => [ 'group_id' => $group_id, @@ -188,7 +191,7 @@ class ZMRobot } public function setGroupCard($group_id, $user_id, $card = "") { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__), 'params' => [ 'group_id' => $group_id, @@ -199,7 +202,7 @@ class ZMRobot } public function setGroupLeave($group_id, $is_dismiss = false) { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__), 'params' => [ 'group_id' => $group_id, @@ -209,7 +212,7 @@ class ZMRobot } public function setGroupSpecialTitle($group_id, $user_id, $special_title = "", $duration = -1) { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__), 'params' => [ 'group_id' => $group_id, @@ -221,7 +224,7 @@ class ZMRobot } public function setDiscussLeave($discuss_id) { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__), 'params' => [ 'discuss_id' => $discuss_id @@ -230,7 +233,7 @@ class ZMRobot } public function setFriendAddRequest($flag, $approve = true, $remark = "") { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__), 'params' => [ 'flag' => $flag, @@ -241,7 +244,7 @@ class ZMRobot } public function setGroupAddRequest($flag, $sub_type, $approve = true, $reason = "") { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__), 'params' => [ 'flag' => $flag, @@ -253,11 +256,11 @@ class ZMRobot } public function getLoginInfo() { - return CQAPI::processAPI($this->connection, ['action' => $this->getActionName(__FUNCTION__)], $this->callback); + return $this->processAPI($this->connection, ['action' => $this->getActionName(__FUNCTION__)], $this->callback); } public function getStrangerInfo($user_id, $no_cache = false) { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__), 'params' => [ 'user_id' => $user_id, @@ -267,19 +270,19 @@ class ZMRobot } public function getFriendList() { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__) ], $this->callback); } public function getGroupList() { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__) ], $this->callback); } public function getGroupInfo($group_id, $no_cache = false) { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__), 'params' => [ 'group_id' => $group_id, @@ -289,7 +292,7 @@ class ZMRobot } public function getGroupMemberInfo($group_id, $user_id, $no_cache = false) { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__), 'params' => [ 'group_id' => $group_id, @@ -300,7 +303,7 @@ class ZMRobot } public function getGroupMemberList($group_id) { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__), 'params' => [ 'group_id' => $group_id @@ -309,7 +312,7 @@ class ZMRobot } public function getCookies($domain = "") { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__), 'params' => [ 'domain' => $domain @@ -318,13 +321,13 @@ class ZMRobot } public function getCsrfToken() { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__) ], $this->callback); } public function getCredentials($domain = "") { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__), 'params' => [ 'domain' => $domain @@ -333,7 +336,7 @@ class ZMRobot } public function getRecord($file, $out_format, $full_path = false) { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__), 'params' => [ 'file' => $file, @@ -344,7 +347,7 @@ class ZMRobot } public function getImage($file) { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__), 'params' => [ 'file' => $file @@ -353,31 +356,31 @@ class ZMRobot } public function canSendImage() { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__) ], $this->callback); } public function canSendRecord() { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__) ], $this->callback); } public function getStatus() { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__) ], $this->callback); } public function getVersionInfo() { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__) ], $this->callback); } public function setRestartPlugin($delay = 0) { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__), 'params' => [ 'delay' => $delay @@ -386,7 +389,7 @@ class ZMRobot } public function cleanDataDir($data_dir) { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__), 'params' => [ 'data_dir' => $data_dir @@ -395,7 +398,7 @@ class ZMRobot } public function cleanPluginLog() { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => $this->getActionName(__FUNCTION__) ], $this->callback); } diff --git a/src/ZM/Utils/ZMRobotExperiment.php b/src/ZM/API/ZMRobotExperiment.php similarity index 82% rename from src/ZM/Utils/ZMRobotExperiment.php rename to src/ZM/API/ZMRobotExperiment.php index 2043fc67..f7b6a565 100644 --- a/src/ZM/Utils/ZMRobotExperiment.php +++ b/src/ZM/API/ZMRobotExperiment.php @@ -1,11 +1,10 @@ connection = $connection; $this->callback = $callback; $this->prefix = $prefix; @@ -39,7 +37,7 @@ class ZMRobotExperiment } public function getFriendList($flat = false) { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => '_' . $this->getActionName(__FUNCTION__), 'params' => [ 'flat' => $flat @@ -48,7 +46,7 @@ class ZMRobotExperiment } public function getGroupInfo($group_id) { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => '_' . $this->getActionName(__FUNCTION__), 'params' => [ 'group_id' => $group_id @@ -57,7 +55,7 @@ class ZMRobotExperiment } public function getVipInfo($user_id) { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => '_' . $this->getActionName(__FUNCTION__), 'params' => [ 'user_id' => $user_id @@ -66,7 +64,7 @@ class ZMRobotExperiment } public function getGroupNotice($group_id) { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => '_' . $this->getActionName(__FUNCTION__), 'params' => [ 'group_id' => $group_id @@ -75,7 +73,7 @@ class ZMRobotExperiment } public function sendGroupNotice($group_id, $title, $content) { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => '_' . $this->getActionName(__FUNCTION__), 'params' => [ 'group_id' => $group_id, @@ -86,7 +84,7 @@ class ZMRobotExperiment } public function setRestart($clean_log = false, $clean_cache = false, $clean_event = false) { - return CQAPI::processAPI($this->connection, [ + return $this->processAPI($this->connection, [ 'action' => '_' . $this->getActionName(__FUNCTION__), 'params' => [ 'clean_log' => $clean_log, diff --git a/src/ZM/Annotation/AnnotationParser.php b/src/ZM/Annotation/AnnotationParser.php index e4b6dbce..af175e6f 100644 --- a/src/ZM/Annotation/AnnotationParser.php +++ b/src/ZM/Annotation/AnnotationParser.php @@ -3,144 +3,205 @@ namespace ZM\Annotation; -use Doctrine\Common\Annotations\{AnnotationException, AnnotationReader}; +use Doctrine\Common\Annotations\AnnotationReader; use Co; -use Framework\{Console, ZMBuf}; +use ZM\ConnectionManager\ConnectionObject; +use ZM\Console\Console; +use ZM\Store\ZMBuf; use Error; use Exception; use ReflectionClass; use ReflectionException; use ReflectionMethod; -use ZM\Annotation\CQ\{CQAfter, - CQAPIResponse, - CQAPISend, - CQBefore, - CQCommand, - CQMessage, - CQMetaEvent, - CQNotice, - CQRequest -}; -use ZM\Annotation\Http\{After, Before, Controller, HandleException, Middleware, MiddlewareClass, RequestMapping}; +use ZM\Annotation\CQ\CQAfter; +use ZM\Annotation\CQ\CQAPIResponse; +use ZM\Annotation\CQ\CQAPISend; +use ZM\Annotation\CQ\CQBefore; +use ZM\Annotation\CQ\CQCommand; +use ZM\Annotation\CQ\CQMessage; +use ZM\Annotation\CQ\CQMetaEvent; +use ZM\Annotation\CQ\CQNotice; +use ZM\Annotation\CQ\CQRequest; +use ZM\Annotation\Http\After; +use ZM\Annotation\Http\Before; +use ZM\Annotation\Http\Controller; +use ZM\Annotation\Http\HandleException; +use ZM\Annotation\Http\Middleware; +use ZM\Annotation\Http\MiddlewareClass; +use ZM\Annotation\Http\RequestMapping; use Swoole\Timer; use ZM\Annotation\Interfaces\CustomAnnotation; use ZM\Annotation\Interfaces\Level; -use ZM\Annotation\Module\{Closed, InitBuffer, LoadBuffer, SaveBuffer}; -use ZM\Annotation\Swoole\{OnSave, OnStart, OnTick, SwooleEventAfter, SwooleEventAt}; +use ZM\Annotation\Module\Closed; +use ZM\Annotation\Module\InitBuffer; +use ZM\Annotation\Module\LoadBuffer; +use ZM\Annotation\Module\SaveBuffer; +use ZM\Annotation\Swoole\OnSave; +use ZM\Annotation\Swoole\OnStart; +use ZM\Annotation\Swoole\OnTick; +use ZM\Annotation\Swoole\SwooleEventAfter; +use ZM\Annotation\Swoole\SwooleEventAt; use ZM\Annotation\Interfaces\Rule; -use ZM\Connection\WSConnection; use ZM\Event\EventHandler; use ZM\Http\MiddlewareInterface; -use Framework\DataProvider; +use ZM\Utils\DataProvider; use ZM\Utils\ZMUtil; class AnnotationParser { - /** - * 注册各个模块类的注解和模块level的排序 - * @throws ReflectionException - * @throws AnnotationException - */ - public static function registerMods() { - self::loadAnnotationClasses(); - $all_class = getAllClasses(DataProvider::getWorkingDir() . "/src/Module/", "Module"); + private $path_list = []; + + private $start_time; + + private $annotation_map = []; + + public function __construct() { + $this->start_time = microtime(true); + $this->loadAnnotationClasses(); + ZMBuf::$req_mapping = []; ZMBuf::$req_mapping[0] = [ 'id' => 0, 'pid' => -1, 'name' => '/' ]; - $reader = new AnnotationReader(); - foreach ($all_class as $v) { - Console::debug("正在检索 " . $v); - $reflection_class = new ReflectionClass($v); - $class_prefix = ''; - $methods = $reflection_class->getMethods(ReflectionMethod::IS_PUBLIC); - $class_annotations = $reader->getClassAnnotations($reflection_class); - $middleware_addon = []; - foreach ($class_annotations as $vs) { - if ($vs instanceof Closed) { - continue 2; - } elseif ($vs instanceof Controller) { - Console::debug("找到 Controller 中间件: " . $vs->class); - $class_prefix = $vs->prefix; - } elseif ($vs instanceof SaveBuffer) { - Console::debug("注册自动保存的缓存变量: " . $vs->buf_name . " (Dir:" . $vs->sub_folder . ")"); - DataProvider::addSaveBuffer($vs->buf_name, $vs->sub_folder); - } elseif ($vs instanceof LoadBuffer) { - Console::debug("注册到内存的缓存变量: " . $vs->buf_name . " (Dir:" . $vs->sub_folder . ")"); - ZMBuf::set($vs->buf_name, DataProvider::getJsonData(($vs->sub_folder ?? "") . "/" . $vs->buf_name . ".json")); - } elseif ($vs instanceof InitBuffer) { - ZMBuf::set($vs->buf_name, []); - } elseif ($vs instanceof MiddlewareClass) { - Console::verbose("正在注册中间件 " . $reflection_class->getName()); - $result = [ - "class" => "\\" . $reflection_class->getName() - ]; - foreach ($methods as $vss) { - if ($vss->getName() == "getName") { - /** @var MiddlewareInterface $tmp */ - $tmp = new $v(); - $result["name"] = $tmp->getName(); - continue; + } + + /** + * 注册各个模块类的注解和模块level的排序 + * @throws ReflectionException + */ + public function registerMods() { + foreach($this->path_list as $path) { + $all_class = getAllClasses($path[0], $path[1]); + $reader = new AnnotationReader(); + foreach ($all_class as $v) { + Console::debug("正在检索 " . $v); + $reflection_class = new ReflectionClass($v); + $methods = $reflection_class->getMethods(ReflectionMethod::IS_PUBLIC); + $class_annotations = $reader->getClassAnnotations($reflection_class); + + //这里将每个类里面所有的类注解、方法注解通通加到一颗大树上,后期解析 + /* + $annotation_map: { + Module\Example\Hello: { + class_annotations: [ + 注解对象1, 注解对象2, ... + ], + methods: [ + ReflectionMethod, ReflectionMethod, ... + ], + methods_annotations: { + foo: [ 注解对象1, 注解对象2, ... ], + bar: [ 注解对象1, 注解对象2, ... ], } - $method_annotations = $reader->getMethodAnnotations($vss); - foreach ($method_annotations as $vsss) { - if ($vss instanceof Rule) $vss = self::registerRuleEvent($vsss, $vss, $reflection_class); - else $vss = self::registerMethod($vsss, $vss, $reflection_class); - //echo get_class($vsss) . PHP_EOL; - if ($vsss instanceof Before) $result["before"] = $vsss->method; - if ($vsss instanceof After) $result["after"] = $vsss->method; - if ($vsss instanceof HandleException) { - $result["exceptions"][$vsss->class_name] = $vsss->method; + } + } + */ + $this->annotation_map[$v]["class_annotations"] = $class_annotations; + $this->annotation_map[$v]["methods"] = $methods; + foreach ($methods as $method) { + $this->annotation_map[$v]["methods_annotations"][$method->getName()] = $reader->getMethodAnnotations($method); + } + + /* + $middleware_addon = []; + foreach ($class_annotations as $vs) { + if ($vs instanceof Closed) { + continue 2; + } elseif ($vs instanceof Controller) { + Console::debug("找到 Controller 中间件: " . $vs->class); + $class_prefix = $vs->prefix; + } elseif ($vs instanceof SaveBuffer) { + Console::debug("注册自动保存的缓存变量: " . $vs->buf_name . " (Dir:" . $vs->sub_folder . ")"); + DataProvider::addSaveBuffer($vs->buf_name, $vs->sub_folder); + } elseif ($vs instanceof LoadBuffer) { + Console::debug("注册到内存的缓存变量: " . $vs->buf_name . " (Dir:" . $vs->sub_folder . ")"); + ZMBuf::set($vs->buf_name, DataProvider::getJsonData(($vs->sub_folder ?? "") . "/" . $vs->buf_name . ".json")); + } elseif ($vs instanceof InitBuffer) { + ZMBuf::set($vs->buf_name, []); + } elseif ($vs instanceof MiddlewareClass) { + Console::verbose("正在注册中间件 " . $reflection_class->getName()); + $result = [ + "class" => "\\" . $reflection_class->getName() + ]; + foreach ($methods as $vss) { + if ($vss->getName() == "getName") { + /** @var MiddlewareInterface $tmp * + $tmp = new $v(); + $result["name"] = $tmp->getName(); + continue; + } + $method_annotations = $reader->getMethodAnnotations($vss); + foreach ($method_annotations as $vsss) { + if ($vss instanceof Rule) $vss = self::registerRuleEvent($vsss, $vss, $reflection_class); + else $vss = self::registerMethod($vsss, $vss, $reflection_class); + //echo get_class($vsss) . PHP_EOL; + if ($vsss instanceof Before) $result["before"] = $vsss->method; + if ($vsss instanceof After) $result["after"] = $vsss->method; + if ($vsss instanceof HandleException) { + $result["exceptions"][$vsss->class_name] = $vsss->method; + } } } - } - ZMBuf::$events[MiddlewareClass::class][$result["name"]] = $result; - continue 2; - } elseif ($vs instanceof Middleware) { - $middleware_addon[] = $vs; - } elseif ($vs instanceof CustomAnnotation) { - $vs->class = $reflection_class->getName(); - ZMBuf::$events[get_class($vs)][] = $vs; - } - } - foreach ($methods as $vs) { - if ($middleware_addon !== []) { - foreach($middleware_addon as $value){ - Console::debug("Added middleware " . $value->middleware . " to $v -> " . $vs->getName()); - ZMBuf::$events[MiddlewareInterface::class][$v][$vs->getName()][] = $value->middleware; + ZMBuf::$events[MiddlewareClass::class][$result["name"]] = $result; + continue 2; + } elseif ($vs instanceof Middleware) { + $middleware_addon[] = $vs; + } elseif ($vs instanceof CustomAnnotation) { + $vs->class = $reflection_class->getName(); + ZMBuf::$events[get_class($vs)][] = $vs; } } - $method_annotations = $reader->getMethodAnnotations($vs); - foreach ($method_annotations as $vss) { - if ($vss instanceof Rule) $vss = self::registerRuleEvent($vss, $vs, $reflection_class); - else $vss = self::registerMethod($vss, $vs, $reflection_class); - Console::debug("寻找 " . $vs->getName() . " -> " . get_class($vss)); + foreach ($methods as $vs) { + if ($middleware_addon !== []) { + foreach ($middleware_addon as $value) { + Console::debug("Added middleware " . $value->middleware . " to $v -> " . $vs->getName()); + ZMBuf::$events[MiddlewareInterface::class][$v][$vs->getName()][] = $value->middleware; + } + } + $method_annotations = $reader->getMethodAnnotations($vs); + foreach ($method_annotations as $vss) { + if ($vss instanceof Rule) $vss = self::registerRuleEvent($vss, $vs, $reflection_class); + else $vss = self::registerMethod($vss, $vs, $reflection_class); + Console::debug("寻找 " . $vs->getName() . " -> " . get_class($vss)); - if ($vss instanceof SwooleEventAt) ZMBuf::$events[SwooleEventAt::class][] = $vss; - elseif ($vss instanceof SwooleEventAfter) ZMBuf::$events[SwooleEventAfter::class][] = $vss; - elseif ($vss instanceof CQMessage) ZMBuf::$events[CQMessage::class][] = $vss; - elseif ($vss instanceof CQNotice) ZMBuf::$events[CQNotice::class][] = $vss; - elseif ($vss instanceof CQRequest) ZMBuf::$events[CQRequest::class][] = $vss; - elseif ($vss instanceof CQMetaEvent) ZMBuf::$events[CQMetaEvent::class][] = $vss; - elseif ($vss instanceof CQCommand) ZMBuf::$events[CQCommand::class][] = $vss; - elseif ($vss instanceof RequestMapping) { - self::registerRequestMapping($vss, $vs, $reflection_class, $class_prefix); - } elseif ($vss instanceof CustomAnnotation) ZMBuf::$events[get_class($vss)][] = $vss; - elseif ($vss instanceof CQBefore) ZMBuf::$events[CQBefore::class][$vss->cq_event][] = $vss; - elseif ($vss instanceof CQAfter) ZMBuf::$events[CQAfter::class][$vss->cq_event][] = $vss; - elseif ($vss instanceof OnStart) ZMBuf::$events[OnStart::class][] = $vss; - elseif ($vss instanceof OnSave) ZMBuf::$events[OnSave::class][] = $vss; - elseif ($vss instanceof Middleware) ZMBuf::$events[MiddlewareInterface::class][$vss->class][$vss->method][] = $vss->middleware; - elseif ($vss instanceof OnTick) self::addTimerTick($vss); - elseif ($vss instanceof CQAPISend) ZMBuf::$events[CQAPISend::class][] = $vss; - elseif ($vss instanceof CQAPIResponse) ZMBuf::$events[CQAPIResponse::class][$vss->retcode] = [$vss->class, $vss->method]; - } + if ($vss instanceof SwooleEventAt) ZMBuf::$events[SwooleEventAt::class][] = $vss; + elseif ($vss instanceof SwooleEventAfter) ZMBuf::$events[SwooleEventAfter::class][] = $vss; + elseif ($vss instanceof CQMessage) ZMBuf::$events[CQMessage::class][] = $vss; + elseif ($vss instanceof CQNotice) ZMBuf::$events[CQNotice::class][] = $vss; + elseif ($vss instanceof CQRequest) ZMBuf::$events[CQRequest::class][] = $vss; + elseif ($vss instanceof CQMetaEvent) ZMBuf::$events[CQMetaEvent::class][] = $vss; + elseif ($vss instanceof CQCommand) ZMBuf::$events[CQCommand::class][] = $vss; + elseif ($vss instanceof RequestMapping) { + self::registerRequestMapping($vss, $vs, $reflection_class, $class_prefix); + } elseif ($vss instanceof CustomAnnotation) ZMBuf::$events[get_class($vss)][] = $vss; + elseif ($vss instanceof CQBefore) ZMBuf::$events[CQBefore::class][$vss->cq_event][] = $vss; + elseif ($vss instanceof CQAfter) ZMBuf::$events[CQAfter::class][$vss->cq_event][] = $vss; + elseif ($vss instanceof OnStart) ZMBuf::$events[OnStart::class][] = $vss; + elseif ($vss instanceof OnSave) ZMBuf::$events[OnSave::class][] = $vss; + elseif ($vss instanceof Middleware) ZMBuf::$events[MiddlewareInterface::class][$vss->class][$vss->method][] = $vss->middleware; + elseif ($vss instanceof OnTick) self::addTimerTick($vss); + elseif ($vss instanceof CQAPISend) ZMBuf::$events[CQAPISend::class][] = $vss; + elseif ($vss instanceof CQAPIResponse) ZMBuf::$events[CQAPIResponse::class][$vss->retcode] = [$vss->class, $vss->method]; + } + }*/ } } + + + $tree = self::genTree(ZMBuf::$req_mapping); ZMBuf::$req_mapping = $tree[0]; //给支持level的排个序 + + Console::debug("解析注解完毕!"); + if (ZMBuf::isset("timer_count")) { + Console::info("Added " . ZMBuf::get("timer_count") . " timer(s)!"); + ZMBuf::unsetCache("timer_count"); + } + } + + public function sortLevels() { foreach (ZMBuf::$events as $class_name => $v) { if (is_a($class_name, Level::class, true)) { for ($i = 0; $i < count(ZMBuf::$events[$class_name]) - 1; ++$i) { @@ -156,11 +217,6 @@ class AnnotationParser } } } - Console::debug("解析注解完毕!"); - if (ZMBuf::isset("timer_count")) { - Console::info("Added " . ZMBuf::get("timer_count") . " timer(s)!"); - ZMBuf::unsetCache("timer_count"); - } } public static function getRuleCallback($rule_str) { @@ -173,9 +229,9 @@ class AnnotationParser //Swoole 事件时走此switch switch ($asp_name) { case "connectType": //websocket连接类型 - $func = function (?WSConnection $connection) use ($rest) { + $func = function (?ConnectionObject $connection) use ($rest) { if ($connection === null) return false; - return $connection->getType() == $rest ? true : false; + return $connection->getName() == $rest ? true : false; }; break; case "containsGet": //handle http request事件时才能用 @@ -323,7 +379,7 @@ class AnnotationParser ZMBuf::$req_mapping = $array; } - private static function loadAnnotationClasses() { + private function loadAnnotationClasses() { $class = getAllClasses(WORKING_DIR . "/src/ZM/Annotation/", "ZM\\Annotation"); foreach ($class as $v) { $s = WORKING_DIR . '/src/' . str_replace("\\", "/", $v) . ".php"; @@ -387,4 +443,8 @@ class AnnotationParser }); ZMBuf::append("paused_tick", $cid); } + + public function addRegisterPath($path, $indoor_name) { + $this->path_list[] = [$path, $indoor_name]; + } } diff --git a/src/ZM/Annotation/Http/Controller.php b/src/ZM/Annotation/Http/Controller.php index 9556a6bd..347c1caf 100644 --- a/src/ZM/Annotation/Http/Controller.php +++ b/src/ZM/Annotation/Http/Controller.php @@ -6,6 +6,7 @@ namespace ZM\Annotation\Http; use Doctrine\Common\Annotations\Annotation\Required; use Doctrine\Common\Annotations\Annotation\Target; use ZM\Annotation\AnnotationBase; +use ZM\Annotation\Interfaces\ErgodicAnnotation; /** * Class Controller @@ -13,11 +14,11 @@ use ZM\Annotation\AnnotationBase; * @Target("CLASS") * @package ZM\Annotation\Http */ -class Controller extends AnnotationBase +class Controller extends AnnotationBase implements ErgodicAnnotation { /** * @var string * @Required() */ public $prefix = ''; -} \ No newline at end of file +} diff --git a/src/ZM/Annotation/Http/Middleware.php b/src/ZM/Annotation/Http/Middleware.php index 60a928c3..cb83ba63 100644 --- a/src/ZM/Annotation/Http/Middleware.php +++ b/src/ZM/Annotation/Http/Middleware.php @@ -7,6 +7,7 @@ namespace ZM\Annotation\Http; use Doctrine\Common\Annotations\Annotation\Required; use Doctrine\Common\Annotations\Annotation\Target; use ZM\Annotation\AnnotationBase; +use ZM\Annotation\Interfaces\ErgodicAnnotation; /** * Class Middleware @@ -14,7 +15,7 @@ use ZM\Annotation\AnnotationBase; * @Annotation * @Target("ALL") */ -class Middleware extends AnnotationBase +class Middleware extends AnnotationBase implements ErgodicAnnotation { /** * @var string diff --git a/src/ZM/Annotation/Http/RequestMapping.php b/src/ZM/Annotation/Http/RequestMapping.php index 966ad84d..7a8538dd 100644 --- a/src/ZM/Annotation/Http/RequestMapping.php +++ b/src/ZM/Annotation/Http/RequestMapping.php @@ -10,7 +10,7 @@ use ZM\Annotation\AnnotationBase; /** * Class RequestMapping * @Annotation - * @Target("ALL") + * @Target("METHOD") * @package ZM\Annotation\Http */ class RequestMapping extends AnnotationBase @@ -36,4 +36,4 @@ class RequestMapping extends AnnotationBase * @var array */ public $params = []; -} \ No newline at end of file +} diff --git a/src/ZM/Annotation/Http/RequestMethod.php b/src/ZM/Annotation/Http/RequestMethod.php index 2c54129e..6332b331 100644 --- a/src/ZM/Annotation/Http/RequestMethod.php +++ b/src/ZM/Annotation/Http/RequestMethod.php @@ -9,7 +9,6 @@ use ZM\Annotation\AnnotationBase; /** * Class RequestMethod * @Annotation - * * @package ZM\Annotation\Http */ class RequestMethod extends AnnotationBase @@ -27,4 +26,4 @@ class RequestMethod extends AnnotationBase public const DELETE = 'DELETE'; public const OPTIONS = 'OPTIONS'; public const HEAD = 'HEAD'; -} \ No newline at end of file +} diff --git a/src/ZM/Annotation/Interfaces/ErgodicAnnotation.php b/src/ZM/Annotation/Interfaces/ErgodicAnnotation.php new file mode 100644 index 00000000..b6b3be2f --- /dev/null +++ b/src/ZM/Annotation/Interfaces/ErgodicAnnotation.php @@ -0,0 +1,10 @@ +setDescription("Build an \".phar\" file | 将项目构建一个phar包"); + $this->setHelp("此功能将会把炸毛框架的模块打包为\".phar\",供发布和执行。"); + $this->addOption("target", "D", InputOption::VALUE_REQUIRED, "Output Directory | 指定输出目录"); + // ... + } + + protected function execute(InputInterface $input, OutputInterface $output) { + $this->output = $output; + $target_dir = $input->getOption("target") ?? (__DIR__ . '/../../../resources/'); + if (mb_strpos($target_dir, "../")) $target_dir = realpath($target_dir); + if ($target_dir === false) { + $output->writeln(TermColor::color8(31) . "Error: No such file or directory (".__DIR__ . '/../../../resources/'.")" . TermColor::RESET); + return Command::FAILURE; + } + $output->writeln("Target: " . $target_dir . " , Version: " . ($version = json_decode(file_get_contents(__DIR__ . "/../../../composer.json"), true)["version"])); + if (mb_substr($target_dir, -1, 1) !== '/') $target_dir .= "/"; + if (ini_get('phar.readonly') == 1) { + $output->writeln(TermColor::color8(31) . "You need to set \"phar.readonly\" to \"Off\"!"); + $output->writeln(TermColor::color8(31) . "See: https://stackoverflow.com/questions/34667606/cant-enable-phar-writing"); + return Command::FAILURE; + } + if (!is_dir($target_dir)) { + $output->writeln(TermColor::color8(31) . "Error: No such file or directory ($target_dir)" . TermColor::RESET); + return Command::FAILURE; + } + $filename = "server.phar"; + $this->build($target_dir, $filename); + + return Command::SUCCESS; + } + + private function build ($target_dir, $filename) { + @unlink($target_dir . $filename); + $phar = new Phar($target_dir . $filename); + $phar->startBuffering(); + $src = realpath(__DIR__ . '/../../zhamao-framework/'); + $hello = file_get_contents($src . '/src/Module/Example/Hello.php'); + $middleware = file_get_contents($src . '/src/Module/Middleware/TimerMiddleware.php'); + unlink($src . '/src/Module/Example/Hello.php'); + unlink($src . '/src/Module/Middleware/TimerMiddleware.php'); + $phar->buildFromDirectory($src); + $phar->addFromString('tmp/Hello.php.bak', $hello); + $phar->addFromString('tmp/TimerMiddleware.php.bak', $middleware); + //$phar->compressFiles(Phar::GZ); + $phar->setStub($phar->createDefaultStub('phar-starter.php')); + $phar->stopBuffering(); + file_put_contents($src . '/src/Module/Example/Hello.php', $hello); + file_put_contents($src . '/src/Module/Middleware/TimerMiddleware.php', $middleware); + $this->output->writeln("Successfully built. Location: " . $target_dir . "$filename"); + } +} diff --git a/src/ZM/Command/InitCommand.php b/src/ZM/Command/InitCommand.php new file mode 100644 index 00000000..19090668 --- /dev/null +++ b/src/ZM/Command/InitCommand.php @@ -0,0 +1,101 @@ +setDescription("Initialize framework starter | 初始化框架运行的基础文件"); + $this->setHelp("此命令将会解压以下文件到项目的根目录:\n" . implode("\n", $this->getExtractFiles())); + // ... + } + + protected function execute(InputInterface $input, OutputInterface $output) { + if (LOAD_MODE === 1) { // 从composer依赖而来的项目模式,最基本的需要初始化的模式 + $output->writeln("Initializing files"); + $base_path = LOAD_MODE_COMPOSER_PATH; + foreach ($this->extract_files as $file) { + if (!file_exists($base_path . $file)) { + $info = pathinfo($file); + @mkdir($base_path . $info["dirname"], 0777, true); + echo "Copying " . $file . PHP_EOL; + $package_name = ($version = json_decode(file_get_contents(__DIR__ . "/../../../composer.json"), true)["name"]); + copy($base_path . "/vendor/" . $package_name . $file, $base_path . $file); + } else { + echo "Skipping " . $file . " , file exists." . PHP_EOL; + } + } + $autoload = [ + "psr-4" => [ + "Module\\" => "src/Module", + "Custom\\" => "src/Custom" + ], + "files" => [ + "src/Custom/global_function.php" + ] + ]; + if (file_exists($base_path . "/composer.json")) { + $composer = json_decode(file_get_contents($base_path . "/composer.json"), true); + if (!isset($composer["autoload"])) { + $composer["autoload"] = $autoload; + } else { + foreach ($autoload["psr-4"] as $k => $v) { + if (!isset($composer["autoload"]["psr-4"][$k])) $composer["autoload"]["psr-4"][$k] = $v; + } + foreach ($autoload["files"] as $k => $v) { + if (!in_array($v, $composer["autoload"]["files"])) $composer["autoload"]["files"][] = $v; + } + } + file_put_contents($base_path . "/composer.json", json_encode($composer, 64 | 128 | 256)); + $output->writeln("Executing composer update command"); + exec("composer update"); + echo PHP_EOL; + } else { + echo("Error occurred. Please check your updates.\n"); + return Command::FAILURE; + } + return Command::SUCCESS; + } elseif (LOAD_MODE === 2) { //从phar启动的框架包,初始化的模式 + $phar_link = new Phar(__DIR__); + $current_dir = pathinfo($phar_link->getPath())["dirname"]; + chdir($current_dir); + $phar_link = "phar://" . $phar_link->getPath(); + foreach ($this->extract_files as $file) { + if (!file_exists($current_dir . $file)) { + $info = pathinfo($file); + @mkdir($current_dir . $info["dirname"], 0777, true); + echo "Copying " . $file . PHP_EOL; + file_put_contents($current_dir . $file, file_get_contents($phar_link . $file)); + } else { + echo "Skipping " . $file . " , file exists." . PHP_EOL; + } + } + } + $output->writeln("initialization must be started with composer-project mode!"); + return Command::FAILURE; + } + + private function getExtractFiles() { + return $this->extract_files; + } +} diff --git a/src/ZM/Command/RunServerCommand.php b/src/ZM/Command/RunServerCommand.php new file mode 100644 index 00000000..2dac62fe --- /dev/null +++ b/src/ZM/Command/RunServerCommand.php @@ -0,0 +1,51 @@ +setDescription("Run zhamao-framework | 启动框架"); + $this->setHelp("直接运行可以启动"); + $this->addOption("debug-mode", "D", null, "开启调试模式 (这将关闭协程化)"); + $this->addOption("log-debug", null, null, "调整消息等级到debug (log-level=4)"); + $this->addOption("log-verbose", null, null, "调整消息等级到verbose (log-level=3)"); + $this->addOption("log-info", null, null, "调整消息等级到info (log-level=2)"); + $this->addOption("log-warning", null, null, "调整消息等级到warning (log-level=1)"); + $this->addOption("log-error", null, null, "调整消息等级到error (log-level=0)"); + $this->addOption("log-theme", null, InputOption::VALUE_REQUIRED, "改变终端的主题配色"); + $this->addOption("disable-console-input", null, null, "禁止终端输入内容 (后台服务时需要)"); + $this->addOption("env", null, InputOption::VALUE_REQUIRED, "设置环境类型 (production, development, staging)"); + // ... + } + + protected function execute(InputInterface $input, OutputInterface $output) { + if(($opt = $input->getOption("env")) !== null) { + if(!in_array($opt, ["production", "staging", "development"])) { + $output->writeln(" \"--env\" option only accept production, development and staging ! "); + } + } + // ... put here the code to run in your command + // this method must return an integer number with the "exit status code" + // of the command. You can also use these constants to make code more readable + new Framework($input->getOptions()); + // return this if there was no problem running the command + // (it's equivalent to returning int(0)) + return Command::SUCCESS; + + // or return this if some error happened during the execution + // (it's equivalent to returning int(1)) + // return Command::FAILURE; + } +} diff --git a/src/ZM/Command/SystemdCommand.php b/src/ZM/Command/SystemdCommand.php new file mode 100644 index 00000000..8cea8607 --- /dev/null +++ b/src/ZM/Command/SystemdCommand.php @@ -0,0 +1,20 @@ +self_id = $self_id; - } - - public function getQQ(){ - return $this->self_id; - } - - public function getType() { - return "qq"; - } -} diff --git a/src/ZM/Connection/ConnectionManager.php b/src/ZM/Connection/ConnectionManager.php deleted file mode 100644 index 16e01fb4..00000000 --- a/src/ZM/Connection/ConnectionManager.php +++ /dev/null @@ -1,76 +0,0 @@ -fd == $fd) return $v; - } - return null; - } - - /** - * @param string $type - * @param array $option - * @return WSConnection[]|CQConnection[] - */ - public static function getByType(string $type, $option = []) { - $conn = []; - foreach (ZMBuf::$connect as $v) { - foreach ($option as $ks => $vs) { - if (($v->$ks ?? "") == $vs) continue; - else continue 2; - } - if ($v->getType() == $type) $conn[] = $v; - } - return $conn; - } - - public static function getTypeClassName(string $type) { - switch (strtolower($type)) { - case "qq": - case "universal": - return CQConnection::class; - case "webconsole": - return WCConnection::class; - case "proxy": - return ProxyConnection::class; - case "terminal": - return TerminalConnection::class; - default: - foreach (ZMBuf::$custom_connection_class as $v) { - /** @var WSConnection $r */ - $r = new $v(ZMBuf::$server, -1); - if ($r->getType() == strtolower($type)) return $v; - } - return UnknownConnection::class; - } - } - - public static function close($fd) { - foreach (ZMBuf::$connect as $k => $v) { - if ($v->fd == $fd) { - ZMBuf::$server->close($fd); - unset(ZMBuf::$connect[$k]); - break; - } - } - } - - public static function registerCustomClass() { - $classes = getAllClasses(DataProvider::getWorkingDir(). "/src/Custom/Connection/", "Custom\\Connection"); - ZMBuf::$custom_connection_class = $classes; - } -} diff --git a/src/ZM/Connection/ProxyConnection.php b/src/ZM/Connection/ProxyConnection.php deleted file mode 100644 index f43083f0..00000000 --- a/src/ZM/Connection/ProxyConnection.php +++ /dev/null @@ -1,13 +0,0 @@ -server = $server; - $this->fd = $fd; - } - - public abstract function getType(); - - public function exists() { - return $this->available = $this->server->exist($this->fd); - } - - public function close() { - ConnectionManager::close($this->fd); - } - - public function push($data, $push_error_record = true) { - if ($data === null || $data == "") { - Console::warning("推送了空消息"); - return false; - } - if (!$this->server->exist($this->fd)) { - Console::warning("Swoole 原生 websocket连接池中无此连接"); - return false; - } - if ($this->server->push($this->fd, $data) === false) { - $data = unicode_decode($data); - if ($push_error_record) Console::warning("API push failed. Data: " . $data); - Console::warning("websocket数据未成功推送,长度:" . strlen($data)); - return false; - } - return true; - } -} diff --git a/src/ZM/ConsoleApplication.php b/src/ZM/ConsoleApplication.php new file mode 100644 index 00000000..9c81b63d --- /dev/null +++ b/src/ZM/ConsoleApplication.php @@ -0,0 +1,42 @@ +addCommands([ + new RunServerCommand(), //运行主服务的指令控制器 + new InitCommand() //初始化用的,用于项目初始化和phar初始化 + ]); + if (LOAD_MODE === 0) $this->add(new BuildCommand()); //只有在git源码模式才能使用打包指令 + } + + /** + * @param InputInterface|null $input + * @param OutputInterface|null $output + * @return int + */ + public function run(InputInterface $input = null, OutputInterface $output = null) { + try { + return parent::run($input, $output); + } catch (Exception $e) { + die("{$e->getMessage()} at {$e->getFile()}({$e->getLine()})"); + } + } +} diff --git a/src/ZM/Context/Context.php b/src/ZM/Context/Context.php index 83c5b600..503b7526 100644 --- a/src/ZM/Context/Context.php +++ b/src/ZM/Context/Context.php @@ -5,18 +5,16 @@ namespace ZM\Context; use Co; -use Framework\ZMBuf; use Swoole\Http\Request; use Swoole\WebSocket\Frame; use swoole_server; -use ZM\API\CQAPI; -use ZM\Connection\ConnectionManager; -use ZM\Connection\CQConnection; -use ZM\Connection\WSConnection; +use ZM\ConnectionManager\ConnectionObject; +use ZM\ConnectionManager\ManagerGM; use ZM\Exception\InvalidArgumentException; use ZM\Exception\WaitTimeoutException; use ZM\Http\Response; -use ZM\Utils\ZMRobot; +use ZM\API\ZMRobot; +use ZM\Store\ZMBuf; class Context implements ContextInterface { @@ -53,8 +51,8 @@ class Context implements ContextInterface */ public function getResponse() { return ZMBuf::$context[$this->cid]["response"] ?? null; } - /** @return WSConnection */ - public function getConnection() { return ConnectionManager::get($this->getFd()); } + /** @return ConnectionObject|null */ + public function getConnection() { return ManagerGM::get($this->getFd()); } /** * @return int|null @@ -65,8 +63,8 @@ class Context implements ContextInterface * @return ZMRobot|null */ public function getRobot() { - $conn = ConnectionManager::get($this->getFrame()->fd); - return $conn instanceof CQConnection ? new ZMRobot($conn) : null; + $conn = ManagerGM::get($this->getFrame()->fd); + return $conn instanceof ConnectionObject ? new ZMRobot($conn) : null; } public function getMessage() { return ZMBuf::$context[$this->cid]["data"]["message"] ?? null; } @@ -109,7 +107,17 @@ class Context implements ContextInterface case "private": case "discuss": $this->setCache("has_reply", true); - return CQAPI::quick_reply(ConnectionManager::get($this->getFrame()->fd), $this->getData(), $msg, $yield); + $data = $this->getData(); + $conn = $this->getConnection(); + switch ($data["message_type"]) { + case "group": + return (new ZMRobot($conn))->setCallback($yield)->sendGroupMsg($data["group_id"], $msg); + case "private": + return (new ZMRobot($conn))->setCallback($yield)->sendPrivateMsg($data["user_id"], $msg); + case "discuss": + return (new ZMRobot($conn))->setCallback($yield)->sendDiscussMsg($data["discuss_id"], $msg); + } + return null; } return false; } diff --git a/src/ZM/Context/ContextInterface.php b/src/ZM/Context/ContextInterface.php index d736331d..93d81542 100644 --- a/src/ZM/Context/ContextInterface.php +++ b/src/ZM/Context/ContextInterface.php @@ -7,9 +7,9 @@ namespace ZM\Context; use Swoole\Http\Request; use Swoole\WebSocket\Frame; use Swoole\WebSocket\Server; -use ZM\Connection\WSConnection; +use ZM\ConnectionManager\ConnectionObject; use ZM\Http\Response; -use ZM\Utils\ZMRobot; +use ZM\API\ZMRobot; interface ContextInterface { @@ -26,7 +26,7 @@ interface ContextInterface public function setData($data); - /** @return WSConnection */ + /** @return ConnectionObject */ public function getConnection(); /** @return int|null */ diff --git a/src/ZM/DB/DB.php b/src/ZM/DB/DB.php index a2da49a0..6c288471 100644 --- a/src/ZM/DB/DB.php +++ b/src/ZM/DB/DB.php @@ -5,8 +5,9 @@ namespace ZM\DB; use Exception; -use framework\Console; -use framework\ZMBuf; +use ZM\Config\ZMConfig; +use ZM\Console\Console; +use ZM\Store\ZMBuf; use PDOException; use PDOStatement; use Swoole\Coroutine; @@ -23,7 +24,7 @@ class DB */ public static function initTableList() { if (!extension_loaded("mysqlnd")) throw new Exception("Can not find mysqlnd PHP extension."); - $result = self::rawQuery("select TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='" . ZMBuf::globals("sql_config")["sql_database"] . "';", []); + $result = self::rawQuery("select TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='" . ZMConfig::get("global", "sql_config")["sql_database"] . "';", []); foreach ($result as $v) { self::$table_list[] = $v['TABLE_NAME']; } @@ -38,7 +39,7 @@ class DB public static function table($table_name, $enable_cache = null) { if (Table::getTableInstance($table_name) === null) { if (in_array($table_name, self::$table_list)) - return new Table($table_name, $enable_cache ?? ZMBuf::globals("sql_config")["sql_enable_cache"]); + return new Table($table_name, $enable_cache ?? ZMConfig::get("global", "sql_config")["sql_enable_cache"]); elseif(ZMBuf::$sql_pool !== null){ throw new DbException("Table " . $table_name . " not exist in database."); } else { @@ -98,7 +99,7 @@ class DB if (ZMBuf::get("sql_log") === true) { $starttime = microtime(true); } - Console::debug("MySQL: ".$line); + Console::debug("MySQL: ".$line." | ". implode(", ", $params)); try { $conn = ZMBuf::$sql_pool->get(); if ($conn === false) { diff --git a/src/ZM/DB/SelectBody.php b/src/ZM/DB/SelectBody.php index 7d0f8995..a7c882af 100644 --- a/src/ZM/DB/SelectBody.php +++ b/src/ZM/DB/SelectBody.php @@ -4,7 +4,7 @@ namespace ZM\DB; -use Framework\Console; +use ZM\Console\Console; use ZM\Exception\DbException; class SelectBody diff --git a/src/ZM/Event/CQ/MessageEvent.php b/src/ZM/Event/CQ/MessageEvent.php index 11f9492a..ca5d2eb1 100644 --- a/src/ZM/Event/CQ/MessageEvent.php +++ b/src/ZM/Event/CQ/MessageEvent.php @@ -6,25 +6,23 @@ namespace ZM\Event\CQ; use Co; use Doctrine\Common\Annotations\AnnotationException; -use Framework\Console; -use Framework\ZMBuf; +use ZM\ConnectionManager\ConnectionObject; +use ZM\Console\Console; +use ZM\Store\ZMBuf; use ZM\Annotation\CQ\CQAfter; use ZM\Annotation\CQ\CQBefore; use ZM\Annotation\CQ\CQCommand; use ZM\Annotation\CQ\CQMessage; -use ZM\Connection\WSConnection; use ZM\Event\EventHandler; use ZM\Exception\WaitTimeoutException; use ZM\Http\Response; -use ZM\ModBase; -use ZM\ModHandleType; class MessageEvent { private $function_call = false; private $data; private $circle; - /** @var WSConnection|Response */ + /** @var ConnectionObject|Response */ private $connection; public function __construct($data, $conn_or_response, $circle = 0) { @@ -84,6 +82,7 @@ class MessageEvent /** * @throws AnnotationException + * @noinspection PhpRedundantCatchClauseInspection */ public function onActivate() { try { @@ -96,7 +95,6 @@ class MessageEvent $word[$k] = trim($word[$k]); } } - /** @var ModBase[] $obj */ $obj = []; foreach (ZMBuf::$events[CQCommand::class] ?? [] as $v) { /** @var CQCommand $v */ @@ -107,30 +105,26 @@ class MessageEvent ($v->message_type == '' || ($v->message_type != '' && $v->message_type == context()->getData()["message_type"])) ) { $c = $v->class; - $class_construct = [ - "data" => context()->getData(), - "connection" => context()->getConnection() - ]; if (!isset($obj[$c])) { - $obj[$c] = new $c($class_construct); + $obj[$c] = new $c(); } if ($word[0] != "" && $v->match == $word[0]) { Console::debug("Calling $c -> {$v->method}"); - $this->function_call = EventHandler::callWithMiddleware($obj[$c], $v->method, $class_construct, [$word], function ($r) { + $this->function_call = EventHandler::callWithMiddleware($obj[$c], $v->method, [], [$word], function ($r) { if (is_string($r)) context()->reply($r); return true; }); return; } elseif (in_array($word[0], $v->alias)) { Console::debug("Calling $c -> {$v->method}"); - $this->function_call = EventHandler::callWithMiddleware($obj[$c], $v->method, $class_construct, [$word], function ($r) { + $this->function_call = EventHandler::callWithMiddleware($obj[$c], $v->method, [], [$word], function ($r) { if (is_string($r)) context()->reply($r); return true; }); return; } elseif ($v->regexMatch != "" && ($args = matchArgs($v->regexMatch, context()->getMessage())) !== false) { Console::debug("Calling $c -> {$v->method}"); - $this->function_call = EventHandler::callWithMiddleware($obj[$c], $v->method, $class_construct, [$args], function ($r) { + $this->function_call = EventHandler::callWithMiddleware($obj[$c], $v->method, [], [$args], function ($r) { if (is_string($r)) context()->reply($r); return true; }); @@ -138,7 +132,7 @@ class MessageEvent } elseif ($v->fullMatch != "" && (preg_match("/".$v->fullMatch."/u", ctx()->getMessage(), $args)) != 0) { Console::debug("Calling $c -> {$v->method}"); array_shift($args); - $this->function_call = EventHandler::callWithMiddleware($obj[$c], $v->method, $class_construct, [$args], function ($r) { + $this->function_call = EventHandler::callWithMiddleware($obj[$c], $v->method, [], [$args], function ($r) { if (is_string($r)) context()->reply($r); return true; }); @@ -158,10 +152,7 @@ class MessageEvent $c = $v->class; Console::debug("Calling CQMessage: $c -> {$v->method}"); if (!isset($obj[$c])) - $obj[$c] = new $c([ - "data" => context()->getData(), - "connection" => $this->connection - ], ModHandleType::CQ_MESSAGE); + $obj[$c] = new $c(); EventHandler::callWithMiddleware($obj[$c], $v->method, [], [context()->getData()["message"]], function ($r) { if (is_string($r)) context()->reply($r); }); diff --git a/src/ZM/Event/CQ/MetaEvent.php b/src/ZM/Event/CQ/MetaEvent.php index bd418917..52ef7507 100644 --- a/src/ZM/Event/CQ/MetaEvent.php +++ b/src/ZM/Event/CQ/MetaEvent.php @@ -5,19 +5,15 @@ namespace ZM\Event\CQ; use Doctrine\Common\Annotations\AnnotationException; -use Framework\ZMBuf; use ZM\Annotation\CQ\CQBefore; use ZM\Annotation\CQ\CQMetaEvent; -use ZM\Connection\CQConnection; use ZM\Event\EventHandler; use ZM\Exception\WaitTimeoutException; -use ZM\ModBase; -use ZM\ModHandleType; +use ZM\Store\ZMBuf; class MetaEvent { private $data; - /** @var CQConnection */ private $connection; private $circle; @@ -53,7 +49,6 @@ class MetaEvent */ public function onActivate() { try { - /** @var ModBase[] $obj */ $obj = []; foreach (ZMBuf::$events[CQMetaEvent::class] ?? [] as $v) { /** @var CQMetaEvent $v */ @@ -62,10 +57,7 @@ class MetaEvent ($v->sub_type == 0 || ($v->sub_type != 0 && $v->sub_type == $this->data["sub_type"]))) { $c = $v->class; if (!isset($obj[$c])) - $obj[$c] = new $c([ - "data" => $this->data, - "connection" => $this->connection - ], ModHandleType::CQ_META_EVENT); + $obj[$c] = new $c(); EventHandler::callWithMiddleware($obj[$c],$v->method, [], [], function($r) { if (is_string($r)) context()->reply($r); }); diff --git a/src/ZM/Event/CQ/NoticeEvent.php b/src/ZM/Event/CQ/NoticeEvent.php index 0973f826..4ff05dcf 100644 --- a/src/ZM/Event/CQ/NoticeEvent.php +++ b/src/ZM/Event/CQ/NoticeEvent.php @@ -5,20 +5,16 @@ namespace ZM\Event\CQ; use Doctrine\Common\Annotations\AnnotationException; -use Framework\ZMBuf; use ZM\Annotation\CQ\CQAfter; use ZM\Annotation\CQ\CQBefore; use ZM\Annotation\CQ\CQNotice; -use ZM\Connection\CQConnection; use ZM\Event\EventHandler; use ZM\Exception\WaitTimeoutException; -use ZM\ModBase; -use ZM\ModHandleType; +use ZM\Store\ZMBuf; class NoticeEvent { private $data; - /** @var CQConnection */ private $connection; private $circle; @@ -54,7 +50,6 @@ class NoticeEvent */ public function onActivate() { try { - /** @var ModBase[] $obj */ $obj = []; foreach (ZMBuf::$events[CQNotice::class] ?? [] as $v) { /** @var CQNotice $v */ @@ -65,10 +60,7 @@ class NoticeEvent ($v->operator_id == 0 || ($v->operator_id != 0 && $v->operator_id == ($this->data["operator_id"] ?? 0)))) { $c = $v->class; if (!isset($obj[$c])) - $obj[$c] = new $c([ - "data" => $this->data, - "connection" => $this->connection - ], ModHandleType::CQ_NOTICE); + $obj[$c] = new $c(); EventHandler::callWithMiddleware($obj[$c],$v->method, [], [], function($r) { if (is_string($r)) context()->reply($r); }); diff --git a/src/ZM/Event/CQ/RequestEvent.php b/src/ZM/Event/CQ/RequestEvent.php index 84f9cf7f..c600fb77 100644 --- a/src/ZM/Event/CQ/RequestEvent.php +++ b/src/ZM/Event/CQ/RequestEvent.php @@ -5,20 +5,16 @@ namespace ZM\Event\CQ; use Doctrine\Common\Annotations\AnnotationException; -use Framework\ZMBuf; use ZM\Annotation\CQ\CQAfter; use ZM\Annotation\CQ\CQBefore; use ZM\Annotation\CQ\CQRequest; -use ZM\Connection\CQConnection; use ZM\Event\EventHandler; use ZM\Exception\WaitTimeoutException; -use ZM\ModBase; -use ZM\ModHandleType; +use ZM\Store\ZMBuf; class RequestEvent { private $data; - /** @var CQConnection */ private $connection; private $circle; @@ -51,10 +47,10 @@ class RequestEvent /** * @throws AnnotationException + * @noinspection PhpRedundantCatchClauseInspection */ public function onActivate() { try { - /** @var ModBase[] $obj */ $obj = []; foreach (ZMBuf::$events[CQRequest::class] ?? [] as $v) { /** @var CQRequest $v */ @@ -65,10 +61,7 @@ class RequestEvent ($v->comment == 0 || ($v->comment != 0 && $v->comment == ($this->data["comment"] ?? 0)))) { $c = $v->class; if (!isset($obj[$c])) - $obj[$c] = new $c([ - "data" => $this->data, - "connection" => $this->connection - ], ModHandleType::CQ_REQUEST); + $obj[$c] = new $c(); EventHandler::callWithMiddleware($obj[$c],$v->method, [], [], function($r) { if (is_string($r)) context()->reply($r); }); diff --git a/src/ZM/Event/EventHandler.php b/src/ZM/Event/EventHandler.php index 7d7dce31..84631539 100644 --- a/src/ZM/Event/EventHandler.php +++ b/src/ZM/Event/EventHandler.php @@ -8,8 +8,9 @@ use Co; use Doctrine\Common\Annotations\AnnotationException; use Error; use Exception; -use Framework\Console; -use Framework\ZMBuf; +use ZM\ConnectionManager\ConnectionObject; +use ZM\ConnectionManager\ManagerGM; +use ZM\Console\Console; use ZM\Event\Swoole\{MessageEvent, RequestEvent, WorkerStartEvent, WSCloseEvent, WSOpenEvent}; use Swoole\Http\Request; use Swoole\Server; @@ -17,11 +18,10 @@ use Swoole\WebSocket\Frame; use ZM\Annotation\CQ\CQAPIResponse; use ZM\Annotation\CQ\CQAPISend; use ZM\Annotation\Http\MiddlewareClass; -use ZM\Connection\ConnectionManager; -use ZM\Connection\CQConnection; use ZM\Http\MiddlewareInterface; use ZM\Http\Response; -use Framework\DataProvider; +use ZM\Store\ZMBuf; +use ZM\Utils\DataProvider; use ZM\Utils\ZMUtil; class EventHandler @@ -51,7 +51,7 @@ class EventHandler }); ZMBuf::$server = $param0; $r = (new WorkerStartEvent($param0, $param1))->onActivate(); - Console::log("\n=== Worker #" . $param0->worker_id . " 已启动 ===\n", "gold"); + Console::success("Worker #" . $param0->worker_id . " 已启动"); $r->onAfter(); self::startTick(); } catch (Exception $e) { @@ -69,14 +69,14 @@ class EventHandler case "message": /** @var Frame $param1 */ /** @var Server $param0 */ - $conn = ConnectionManager::get($param1->fd); + $conn = ManagerGM::get($param1->fd); set_coroutine_params(["server" => $param0, "frame" => $param1, "connection" => $conn]); try { (new MessageEvent($param0, $param1))->onActivate()->onAfter(); } catch (Error $e) { $error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")"; Console::error("Fatal error when calling $event_name: " . $error_msg); - Console::stackTrace(); + Console::trace(); } break; case "request": @@ -89,7 +89,12 @@ class EventHandler Console::info($param0->server["remote_addr"] . ":" . $param0->server["remote_port"] . " [" . $param1->getStatusCode() . "] " . $param0->server["request_uri"] ); - if (!$param1->isEnd()) $param1->end("Internal server error: " . $e->getMessage()); + if (!$param1->isEnd()) { + if (\ZM\Config\ZMConfig::get("global", "debug_mode")) + $param1->end("Internal server error: " . $e->getMessage()); + else + $param1->end("Internal server error."); + } Console::error("Internal server exception (500), caused by " . get_class($e)); Console::log($e->getTraceAsString(), "gray"); } catch (Error $e) { @@ -100,7 +105,7 @@ class EventHandler ); $doc = "Internal server error
"; $error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")"; - if (ZMBuf::$atomics["info_level"]->get() >= 4) $doc .= $error_msg; + if (Console::getLevel() >= 4) $doc .= $error_msg; if (!$param1->isEnd()) $param1->end($doc); Console::error("Internal server error (500): " . $error_msg); Console::log($e->getTraceAsString(), "gray"); @@ -114,7 +119,7 @@ class EventHandler } catch (Error $e) { $error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")"; Console::error("Fatal error when calling $event_name: " . $error_msg); - Console::stackTrace(); + Console::trace(); } break; case "close": @@ -124,7 +129,7 @@ class EventHandler } catch (Error $e) { $error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")"; Console::error("Fatal error when calling $event_name: " . $error_msg); - Console::stackTrace(); + Console::trace(); } break; } @@ -142,7 +147,7 @@ class EventHandler ctx()->setCache("level", $level); if ($level >= 5) { Console::warning("Recursive call reached " . $level . " times"); - Console::stackTrace(); + Console::trace(); return false; } $starttime = microtime(true); @@ -220,7 +225,7 @@ class EventHandler } } - public static function callCQAPISend($reply, ?CQConnection $connection) { + public static function callCQAPISend($reply, ?ConnectionObject $connection) { $action = $reply["action"] ?? null; if ($action === null) { Console::warning("API 激活事件异常!"); @@ -235,7 +240,7 @@ class EventHandler foreach (ZMBuf::$events[CQAPISend::class] ?? [] as $k => $v) { if (($v->action == "" || $v->action == $action) && !$v->with_result) { $c = $v->class; - self::callWithMiddleware($c, $v->method, context()->copy(), [$reply["action"], $reply["params"] ?? [], $connection->getQQ()]); + self::callWithMiddleware($c, $v->method, context()->copy(), [$reply["action"], $reply["params"] ?? [], $connection->getOption('connect_id')]); if (context()->getCache("block_continue") === true) break; } } diff --git a/src/Framework/ServerEventHandler.php b/src/ZM/Event/ServerEventHandler.php similarity index 80% rename from src/Framework/ServerEventHandler.php rename to src/ZM/Event/ServerEventHandler.php index b4cd762b..e7f757de 100644 --- a/src/Framework/ServerEventHandler.php +++ b/src/ZM/Event/ServerEventHandler.php @@ -1,19 +1,18 @@ taskworker === false) { - FrameworkLoader::$run_time = microtime(true); EventHandler::callSwooleEvent("WorkerStart", $server, $worker_id); } else { ob_start(); - AnnotationParser::registerMods(); - //加载Custom目录下的自定义的内部类 - ConnectionManager::registerCustomClass(); + //AnnotationParser::registerMods(); ob_get_clean(); } } @@ -44,7 +39,8 @@ class ServerEventHandler * @throws AnnotationException */ public function onMessage($server, Frame $frame) { - Console::debug("Calling Swoole \"message\" from fd=" . $frame->fd); + if ($frame->fd !== ZMBuf::get("terminal_fd")) + Console::debug("Calling Swoole \"message\" from fd=" . $frame->fd); EventHandler::callSwooleEvent("message", $server, $frame); } diff --git a/src/ZM/Event/Swoole/MessageEvent.php b/src/ZM/Event/Swoole/MessageEvent.php index 0c6f9298..fc2b8db7 100644 --- a/src/ZM/Event/Swoole/MessageEvent.php +++ b/src/ZM/Event/Swoole/MessageEvent.php @@ -5,17 +5,15 @@ namespace ZM\Event\Swoole; use Closure; -use Framework\Console; -use Framework\ZMBuf; +use ZM\ConnectionManager\ManagerGM; +use ZM\Console\Console; use Swoole\WebSocket\Frame; use Swoole\WebSocket\Server; use ZM\Annotation\Swoole\SwooleEventAfter; use ZM\Annotation\Swoole\SwooleEventAt; -use ZM\Connection\ConnectionManager; use Exception; use ZM\Event\EventHandler; -use ZM\ModBase; -use ZM\ModHandleType; +use ZM\Store\ZMBuf; use ZM\Utils\ZMUtil; class MessageEvent implements SwooleEvent @@ -39,15 +37,15 @@ class MessageEvent implements SwooleEvent */ public function onActivate() { ZMUtil::checkWait(); - $conn = ConnectionManager::get(context()->getFrame()->fd); + $conn = ManagerGM::get(context()->getFrame()->fd); try { - if ($conn->getType() == "qq") { + if ($conn->getName() == "qq") { $data = json_decode(context()->getFrame()->data, true); if (isset($data["post_type"])) { set_coroutine_params(["data" => $data, "connection" => $conn]); ctx()->setCache("level", 0); - Console::debug("Calling CQ Event from fd=" . $conn->fd); - EventHandler::callCQEvent($data, ConnectionManager::get(context()->getFrame()->fd), 0); + Console::debug("Calling CQ Event from fd=" . $conn->getFd()); + EventHandler::callCQEvent($data, ManagerGM::get(context()->getFrame()->fd), 0); } else{ set_coroutine_params(["connection" => $conn]); EventHandler::callCQResponse($data); @@ -78,10 +76,8 @@ class MessageEvent implements SwooleEvent public function onAfter() { foreach (ZMBuf::$events[SwooleEventAfter::class] ?? [] as $v) { if (strtolower($v->type) == "message" && $this->parseSwooleRule($v) === true) { - $conn = ConnectionManager::get($this->frame->fd); $c = $v->class; - /** @var ModBase $class */ - $class = new $c(["server" => $this->server, "frame" => $this->frame, "connection" => $conn], ModHandleType::SWOOLE_MESSAGE); + $class = new $c(); call_user_func_array([$class, $v->method], []); if (context()->getCache("block_continue") === true) break; } @@ -92,7 +88,7 @@ class MessageEvent implements SwooleEvent private function parseSwooleRule($v) { switch (explode(":", $v->rule)[0]) { case "connectType": //websocket连接类型 - if ($v->callback instanceof Closure) return call_user_func($v->callback, ConnectionManager::get($this->frame->fd)); + if ($v->callback instanceof Closure) return call_user_func($v->callback, ManagerGM::get($this->frame->fd)); break; case "dataEqual": //handle websocket message事件时才能用 if ($v->callback instanceof Closure) return call_user_func($v->callback, $this->frame->data); diff --git a/src/ZM/Event/Swoole/RequestEvent.php b/src/ZM/Event/Swoole/RequestEvent.php index 83b38552..54c1fbeb 100644 --- a/src/ZM/Event/Swoole/RequestEvent.php +++ b/src/ZM/Event/Swoole/RequestEvent.php @@ -6,14 +6,14 @@ namespace ZM\Event\Swoole; use Closure; use Exception; -use Framework\Console; +use ZM\Console\Console; use Framework\ZMBuf; use Swoole\Http\Request; use ZM\Annotation\Swoole\SwooleEventAfter; use ZM\Annotation\Swoole\SwooleEventAt; use ZM\Event\EventHandler; use ZM\Http\Response; -use Framework\DataProvider; +use ZM\Utils\DataProvider; use ZM\Utils\ZMUtil; class RequestEvent implements SwooleEvent @@ -38,7 +38,7 @@ class RequestEvent implements SwooleEvent */ public function onActivate() { ZMUtil::checkWait(); - foreach (ZMBuf::globals("http_header") as $k => $v) { + foreach (\ZM\Config\ZMConfig::get("global", "http_header") as $k => $v) { $this->response->setHeader($k, $v); } $uri = $this->request->server["request_uri"]; @@ -81,9 +81,9 @@ class RequestEvent implements SwooleEvent } } - if (ZMBuf::globals("static_file_server")["status"]) { - $base_dir = ZMBuf::globals("static_file_server")["document_root"]; - $base_index = ZMBuf::globals("static_file_server")["document_index"]; + if (\ZM\Config\ZMConfig::get("global", "static_file_server")["status"]) { + $base_dir = \ZM\Config\ZMConfig::get("global", "static_file_server")["document_root"]; + $base_index = \ZM\Config\ZMConfig::get("global", "static_file_server")["document_index"]; $uri = $this->request->server["request_uri"]; $path = realpath($base_dir . urldecode($uri)); if ($path !== false) { @@ -116,7 +116,6 @@ class RequestEvent implements SwooleEvent $this->response->end(ZMUtil::getHttpCodePage(404)); return $this; } - context()->setCache("params", $params); if (in_array(strtoupper($this->request->server["request_method"]), $node["request_method"] ?? [])) { //判断目标方法在不在里面 diff --git a/src/ZM/Event/Swoole/WSCloseEvent.php b/src/ZM/Event/Swoole/WSCloseEvent.php index 8a6e418d..0bd6d214 100644 --- a/src/ZM/Event/Swoole/WSCloseEvent.php +++ b/src/ZM/Event/Swoole/WSCloseEvent.php @@ -6,12 +6,13 @@ namespace ZM\Event\Swoole; use Closure; use Doctrine\Common\Annotations\AnnotationException; -use Framework\ZMBuf; +use ZM\ConnectionManager\ManagerGM; +use ZM\Console\Console; use Swoole\Server; use ZM\Annotation\Swoole\SwooleEventAfter; use ZM\Annotation\Swoole\SwooleEventAt; -use ZM\Connection\ConnectionManager; use ZM\Event\EventHandler; +use ZM\Store\ZMBuf; use ZM\Utils\ZMUtil; class WSCloseEvent implements SwooleEvent @@ -30,8 +31,9 @@ class WSCloseEvent implements SwooleEvent * @throws AnnotationException */ public function onActivate() { + Console::info("Closed #{$this->fd}"); ZMUtil::checkWait(); - set_coroutine_params(["server" => $this->server, "fd" => $this->fd, "connection" => ConnectionManager::get($this->fd)]); + set_coroutine_params(["server" => $this->server, "fd" => $this->fd, "connection" => ManagerGM::get($this->fd)]); foreach(ZMBuf::$events[SwooleEventAt::class] ?? [] as $v) { if(strtolower($v->type) == "close" && $this->parseSwooleRule($v)) { $c = $v->class; @@ -39,7 +41,7 @@ class WSCloseEvent implements SwooleEvent if(context()->getCache("block_continue") === true) break; } } - ConnectionManager::close($this->fd); + ManagerGM::popConnect($this->fd); return $this; } @@ -61,7 +63,7 @@ class WSCloseEvent implements SwooleEvent private function parseSwooleRule($v) { switch (explode(":", $v->rule)[0]) { case "connectType": //websocket连接类型 - if ($v->callback instanceof Closure) return call_user_func($v->callback, ConnectionManager::get($this->fd)); + if ($v->callback instanceof Closure) return call_user_func($v->callback, ManagerGM::get($this->fd)); break; } return true; diff --git a/src/ZM/Event/Swoole/WSOpenEvent.php b/src/ZM/Event/Swoole/WSOpenEvent.php index 833749e1..1524fa3e 100644 --- a/src/ZM/Event/Swoole/WSOpenEvent.php +++ b/src/ZM/Event/Swoole/WSOpenEvent.php @@ -6,19 +6,16 @@ namespace ZM\Event\Swoole; use Closure; use Doctrine\Common\Annotations\AnnotationException; -use Framework\Console; -use Framework\ZMBuf; +use ZM\Config\ZMConfig; +use ZM\ConnectionManager\ConnectionObject; +use ZM\ConnectionManager\ManagerGM; +use ZM\Console\Console; use Swoole\Http\Request; use Swoole\WebSocket\Server; use ZM\Annotation\Swoole\SwooleEventAfter; use ZM\Annotation\Swoole\SwooleEventAt; -use ZM\Connection\ConnectionManager; -use ZM\Connection\CQConnection; -use ZM\Connection\UnknownConnection; -use ZM\Connection\WSConnection; use ZM\Event\EventHandler; -use ZM\ModBase; -use ZM\ModHandleType; +use ZM\Store\ZMBuf; use ZM\Utils\ZMUtil; class WSOpenEvent implements SwooleEvent @@ -31,9 +28,7 @@ class WSOpenEvent implements SwooleEvent * @var Request */ private $request; - /** - * @var WSConnection - */ + /** @var ConnectionObject */ private $conn; public function __construct(Server $server, Request $request) { @@ -47,25 +42,28 @@ class WSOpenEvent implements SwooleEvent */ public function onActivate() { ZMUtil::checkWait(); + ManagerGM::pushConnect($this->request->fd); $type = strtolower($this->request->get["type"] ?? $this->request->header["x-client-role"] ?? ""); - $type_conn = ConnectionManager::getTypeClassName($type); - if ($type_conn == CQConnection::class) { + $type_conn = $this->getTypeClassName($type); + if ($type_conn == "qq") { + ManagerGM::setName($this->request->fd, "qq"); $qq = $this->request->get["qq"] ?? $this->request->header["x-self-id"] ?? ""; - $self_token = ZMBuf::globals("access_token") ?? ""; - if(isset($this->request->header["authorization"])) { + $self_token = ZMConfig::get("global", "access_token") ?? ""; + if (isset($this->request->header["authorization"])) { Console::debug($this->request->header["authorization"]); } $remote_token = $this->request->get["token"] ?? (isset($this->request->header["authorization"]) ? explode(" ", $this->request->header["authorization"])[1] : ""); - if ($qq != "" && ($self_token == $remote_token)) $this->conn = new CQConnection($this->server, $this->request->fd, $qq); - else { - $this->conn = new UnknownConnection($this->server, $this->request->fd); + if ($qq != "" && ($self_token == $remote_token)) { + ManagerGM::setOption($this->request->fd, "connect_id", $qq); + $this->conn = ManagerGM::get($this->request->fd); + } else { + $this->conn = ManagerGM::get($this->request->fd); Console::warning("connection of CQ has invalid QQ or token!"); - Console::debug("Remote token: ".$remote_token); + Console::debug("Remote token: " . $remote_token); } } else { - $this->conn = new $type_conn($this->server, $this->request->fd); + $this->conn = ManagerGM::get($this->request->fd); } - ZMBuf::$connect[$this->request->fd] = $this->conn; set_coroutine_params(["server" => $this->server, "request" => $this->request, "connection" => $this->conn]); foreach (ZMBuf::$events[SwooleEventAt::class] ?? [] as $v) { if (strtolower($v->type) == "open" && $this->parseSwooleRule($v) === true) { @@ -86,11 +84,10 @@ class WSOpenEvent implements SwooleEvent * @inheritDoc */ public function onAfter() { - if (!$this->conn->exists()) return $this; + if (!$this->server->exists($this->conn->getFd())) return $this; foreach (ZMBuf::$events[SwooleEventAfter::class] ?? [] as $v) { if (strtolower($v->type) == "open" && $this->parseSwooleRule($v) === true) { - /** @var ModBase $class */ - $class = new $v["class"](["server" => $this->server, "request" => $this->request, "connection" => $this->conn], ModHandleType::SWOOLE_OPEN); + $class = new $v["class"](); call_user_func_array([$class, $v["method"]], [$this->conn]); if (context()->getCache("block_continue") === true) break; } @@ -106,4 +103,15 @@ class WSOpenEvent implements SwooleEvent } return true; } + + private function getTypeClassName(string $type) { + $map = [ + "qq" => "qq", + "universal" => "qq", + "webconsole" => "webconsole", + "proxy" => "proxy", + "terminal" => "terminal" + ]; + return $map[$type] ?? "default"; + } } diff --git a/src/ZM/Event/Swoole/WorkerStartEvent.php b/src/ZM/Event/Swoole/WorkerStartEvent.php index 5eb11223..d5b5911b 100644 --- a/src/ZM/Event/Swoole/WorkerStartEvent.php +++ b/src/ZM/Event/Swoole/WorkerStartEvent.php @@ -4,7 +4,6 @@ namespace ZM\Event\Swoole; -use Co; use Doctrine\Common\Annotations\AnnotationException; use Exception; use PDO; @@ -14,20 +13,18 @@ use Swoole\Database\PDOConfig; use Swoole\Database\PDOPool; use Swoole\Process; use Swoole\Timer; -use ZM\Annotation\AnnotationBase; use ZM\Annotation\AnnotationParser; use ZM\Annotation\Swoole\OnStart; -use ZM\Annotation\Swoole\SwooleEventAfter; -use ZM\Connection\ConnectionManager; +use ZM\Config\ZMConfig; use ZM\Context\ContextInterface; use ZM\DB\DB; -use Framework\Console; -use Framework\GlobalConfig; -use Framework\ZMBuf; +use ZM\Console\Console; use Swoole\Server; use ZM\Event\EventHandler; use ZM\Exception\DbException; -use Framework\DataProvider; +use ZM\Store\ZMBuf; +use ZM\Utils\DataProvider; +use ZM\Utils\Terminal; use ZM\Utils\ZMUtil; class WorkerStartEvent implements SwooleEvent @@ -50,50 +47,46 @@ class WorkerStartEvent implements SwooleEvent * @throws DbException */ public function onActivate(): WorkerStartEvent { - Console::info("Worker启动中"); - ZMBuf::$server = $this->server; - Console::listenConsole(); //这个方法只能在这里调用,且如果worker_num不为1的话,此功能不可用 - Process::signal(SIGINT, function () { - Console::warning("Server interrupted by keyboard."); - ZMUtil::stop(true); - }); + Console::info("Worker #{$this->server->worker_id} 启动中"); + ZMBuf::$server = $this->server; ZMBuf::resetCache(); //清空变量缓存 ZMBuf::set("wait_start", []); //添加队列,在workerStart运行完成前先让其他协程等待执行 $this->resetConnections();//释放所有与framework的连接 - //设置炸毛buf中储存的对象 - ZMBuf::$globals = new GlobalConfig(); - ZMBuf::$config = []; - $file = scandir(DataProvider::getWorkingDir() . '/config/'); - unset($file[0], $file[1]); - foreach ($file as $k => $v) { - if ($v == "global.php") continue; - $name = explode(".", $v); - if (($prefix = end($name)) == "json") { - ZMBuf::$config[$name[0]] = json_decode(Co::readFile(DataProvider::getWorkingDir() . '/config/' . $v), true); - Console::info("已读取配置文件:" . $v); - } elseif ($prefix == "php") { - ZMBuf::$config[$name[0]] = include_once DataProvider::getWorkingDir() . '/config/' . $v; - if (is_array(ZMBuf::$config[$name[0]])) - Console::info("已读取配置文件:" . $v); - } + global $terminal_id; + + Terminal::listenConsole($terminal_id); //这个方法只能在这里调用,且如果worker_num不为1的话,此功能不可用 + // 这里执行的是只需要执行一遍的代码,比如终端监听器和键盘监听器 + if ($this->server->worker_id === 0) { + if($terminal_id !== null) Console::info("监听console输入"); + Process::signal(SIGINT, function () { + echo PHP_EOL; + Console::warning("Server interrupted by keyboard."); + ZMUtil::stop(); + }); + ZMBuf::$atomics['reload_time']->add(1); + $this->setAutosaveTimer(ZMConfig::get("global", "auto_save_interval")); + } else { + Process::signal(SIGINT, function () { + // Do Nothing + }); } - if (ZMBuf::globals("sql_config")["sql_host"] != "") { + if (ZMConfig::get("global", "sql_config")["sql_host"] != "") { Console::info("新建SQL连接池中"); ob_start(); phpinfo(); $str = ob_get_clean(); $str = explode("\n", $str); - foreach($str as $k => $v) { + foreach ($str as $k => $v) { $v = trim($v); - if($v == "") continue; - if(mb_strpos($v, "API Extensions") === false) continue; - if(mb_strpos($v, "pdo_mysql") === false) { + if ($v == "") continue; + if (mb_strpos($v, "API Extensions") === false) continue; + if (mb_strpos($v, "pdo_mysql") === false) { throw new DbException("未安装 mysqlnd php-mysql扩展。"); } } - $sql = ZMBuf::globals("sql_config"); + $sql = ZMConfig::get("global", "sql_config"); ZMBuf::$sql_pool = new PDOPool((new PDOConfig()) ->withHost($sql["sql_host"]) ->withPort($sql["sql_port"]) @@ -107,11 +100,6 @@ class WorkerStartEvent implements SwooleEvent DB::initTableList(); } - ZMBuf::$atomics['reload_time']->add(1); - - Console::info("监听console输入"); - - $this->setAutosaveTimer(ZMBuf::globals("auto_save_interval")); $this->loadAllClass(); //加载composer资源、phar外置包、注解解析注册等 return $this; } @@ -126,22 +114,14 @@ class WorkerStartEvent implements SwooleEvent } ZMBuf::unsetCache("wait_start"); set_coroutine_params(["server" => $this->server, "worker_id" => $this->worker_id]); - - foreach (ZMBuf::$events[OnStart::class] ?? [] as $v) { - $class_name = $v->class; - Console::debug("正在调用启动时函数: " . $class_name . " -> " . $v->method); - EventHandler::callWithMiddleware($class_name, $v->method, ["server" => $this->server, "worker_id" => $this->worker_id], []); - } - foreach (ZMBuf::$events[SwooleEventAfter::class] ?? [] as $v) { - /** @var AnnotationBase $v */ - if (strtolower($v->type) == "workerstart") { + if($this->server->worker_id === 0) { + foreach (ZMBuf::$events[OnStart::class] ?? [] as $v) { $class_name = $v->class; - Console::debug("正在调用启动时函数after: " . $class_name . " -> " . $v->method); + Console::debug("正在调用启动时函数: " . $class_name . " -> " . $v->method); EventHandler::callWithMiddleware($class_name, $v->method, ["server" => $this->server, "worker_id" => $this->worker_id], []); - if (context()->getCache("block_continue") === true) break; } + Console::debug("@OnStart 执行完毕"); } - Console::debug("调用完毕!"); return $this; } @@ -156,7 +136,6 @@ class WorkerStartEvent implements SwooleEvent } /** - * @throws AnnotationException * @throws ReflectionException * @throws Exception */ @@ -181,15 +160,13 @@ class WorkerStartEvent implements SwooleEvent //加载各个模块的注解类,以及反射 Console::info("检索Module中"); - AnnotationParser::registerMods(); - - //加载Custom目录下的自定义的内部类 - ConnectionManager::registerCustomClass(); + $parser = new AnnotationParser(); + $parser->addRegisterPath(DataProvider::getWorkingDir() . "/src/Module/", "Module"); + $parser->registerMods(); + $parser->sortLevels(); //加载自定义的全局函数 Console::debug("加载自定义的全局函数中"); - if (file_exists(DataProvider::getWorkingDir() . "/src/Custom/global_function.php")) - require_once DataProvider::getWorkingDir() . "/src/Custom/global_function.php"; $this->afterCheck(); } @@ -204,7 +181,7 @@ class WorkerStartEvent implements SwooleEvent * @throws Exception */ private function afterCheck() { - $context_class = ZMBuf::globals("context_class"); + $context_class = ZMConfig::get("global", "context_class"); if (!is_a($context_class, ContextInterface::class, true)) { throw new Exception("Context class must implemented from ContextInterface!"); } diff --git a/src/ZM/Exception/WaitTimeoutException.php b/src/ZM/Exception/WaitTimeoutException.php index 35906de9..561453d6 100644 --- a/src/ZM/Exception/WaitTimeoutException.php +++ b/src/ZM/Exception/WaitTimeoutException.php @@ -6,15 +6,13 @@ namespace ZM\Exception; use Exception; use Throwable; -use ZM\ModBase; class WaitTimeoutException extends Exception { - /** @var ModBase */ public $module; public function __construct($module, $message = "", $code = 0, Throwable $previous = null) { parent::__construct($message, $code, $previous); $this->module = $module; } -} \ No newline at end of file +} diff --git a/src/ZM/Framework.php b/src/ZM/Framework.php new file mode 100644 index 00000000..1cfbe828 --- /dev/null +++ b/src/ZM/Framework.php @@ -0,0 +1,292 @@ +getTtyWidth(); + if (LOAD_MODE == 0) define("WORKING_DIR", getcwd()); + elseif (LOAD_MODE == 1) define("WORKING_DIR", realpath(__DIR__ . "/../../")); + elseif (LOAD_MODE == 2) echo "Phar mode: " . WORKING_DIR . PHP_EOL; + require_once "Utils/DataProvider.php"; + if (file_exists(DataProvider::getWorkingDir() . "/vendor/autoload.php")) { + /** @noinspection PhpIncludeInspection */ + require_once DataProvider::getWorkingDir() . "/vendor/autoload.php"; + } + if (LOAD_MODE == 2) { + // Phar 模式,2.0 不提供哦 + //require_once FRAMEWORK_DIR . "/vendor/autoload.php"; + spl_autoload_register('phar_classloader'); + } elseif (LOAD_MODE == 0) { + /** @noinspection PhpIncludeInspection + * @noinspection RedundantSuppression + */ + require_once WORKING_DIR . "/vendor/autoload.php"; + } + + if (!is_dir(DataProvider::getWorkingDir() . '/src/')) { + die("Unable to find source directory.\nMaybe you need to run \"init\"?"); + } + ZMConfig::setDirectory(DataProvider::getWorkingDir().'/config'); + ZMConfig::env($args["env"] ?? ""); + if(ZMConfig::get("global") === false) die("Global config load failed: ".ZMConfig::$last_error); + + self::$argv = $args; + + $this->defineProperties(); + ZMBuf::initAtomic(); + ManagerGM::init(1024, 0.2, [ + [ + "key" => "connect_id", + "type" => "string", + "size" => 30 + ] + ]); + //start swoole Framework + $this->selfCheck(); + try { + self::$server = new Server(ZMConfig::get("global", "host"), ZMConfig::get("global", "port")); + $this->server_set = ZMConfig::get("global", "swoole"); + Console::init( + ZMConfig::get("global", "info_level"), + self::$server, + $args["log-theme"] ?? "default", + ($o = ZMConfig::get("console_color")) === false ? [] : $o + ); + // 注册 Swoole Server 的事件 + $this->registerServerEvents(); + + $timezone = ZMConfig::get("global", "timezone") ?? "Asia/Shanghai"; + date_default_timezone_set($timezone); + + $this->parseCliArgs(self::$argv); + + $out = [ + "host" => ZMConfig::get("global", "host"), + "port" => ZMConfig::get("global", "port"), + "log_level" => Console::getLevel(), + "version" => ZM_VERSION, + "config" => $args["env"] === null ? 'global.php' : $args["env"], + "working_dir" => DataProvider::getWorkingDir() + ]; + if (isset(ZMConfig::get("global", "swoole")["task_worker_num"])) { + $out["task_worker_num"] = ZMConfig::get("global", "swoole")["task_worker_num"]; + } + if (($num = ZMConfig::get("global", "swoole")["worker_num"] ?? swoole_cpu_num()) != 1) { + $out["worker_num"] = $num; + } + $store = ""; + foreach ($out as $k => $v) { + $line = $k . ": " . $v; + if (strlen($line) > 19 && $store == "" || $tty_width < 53) { + Console::log($line); + } else { + if ($store === "") $store = str_pad($line, 19, " ", STR_PAD_RIGHT); + else { + $store .= (" | " . $line); + Console::log($store); + $store = ""; + } + } + } + if ($store != "") Console::log($store); + + self::$server->set($this->server_set); + if (file_exists(DataProvider::getWorkingDir() . "/config/motd.txt")) { + $motd = file_get_contents(DataProvider::getWorkingDir() . "/config/motd.txt"); + } else { + $motd = file_get_contents(__DIR__."/../../config/motd.txt"); + } + $motd = explode("\n", $motd); + foreach ($motd as $k => $v) { + $motd[$k] = substr($v, 0, $tty_width); + } + $motd = implode("\n", $motd); + echo $motd; + global $asd; + $asd = get_included_files(); + self::$server->start(); + } catch (Exception $e) { + Console::error("Framework初始化出现错误,请检查!"); + Console::error($e->getMessage()); + die; + } + } + + private function defineProperties() { + define("ZM_START_TIME", microtime(true)); + define("ZM_DATA", ZMConfig::get("global", "zm_data")); + define("ZM_VERSION", json_decode(file_get_contents(__DIR__ . "/../../composer.json"), true)["version"] ?? "unknown"); + define("CONFIG_DIR", ZMConfig::get("global", "config_dir")); + define("CRASH_DIR", ZMConfig::get("global", "crash_dir")); + @mkdir(ZM_DATA); + @mkdir(CONFIG_DIR); + @mkdir(CRASH_DIR); + define("ZM_MATCH_ALL", 0); + define("ZM_MATCH_FIRST", 1); + define("ZM_MATCH_NUMBER", 2); + define("ZM_MATCH_SECOND", 3); + define("ZM_BREAKPOINT", 'if(Framework::$argv["debug-mode"]) extract(\Psy\debug(get_defined_vars(), isset($this) ? $this : @get_called_class()));'); + define("BP", ZM_BREAKPOINT); + define("ZM_DEFAULT_FETCH_MODE", 4); + } + + private function selfCheck() { + if (!extension_loaded("swoole")) die("Can not find swoole extension.\n"); + if (version_compare(SWOOLE_VERSION, "4.4.13") == -1) die("You must install swoole version >= 4.4.13 !"); + //if (!extension_loaded("gd")) die("Can not find gd extension.\n"); + if (!extension_loaded("sockets")) die("Can not find sockets extension.\n"); + if (substr(PHP_VERSION, 0, 1) != "7") die("PHP >=7 required.\n"); + //if (!function_exists("curl_exec")) die("Can not find curl extension.\n"); + //if (!class_exists("ZipArchive")) die("Can not find Zip extension.\n"); + //if (!file_exists(CRASH_DIR . "last_error.log")) die("Can not find log file.\n"); + return true; + } + + /** + * 从全局配置文件里读取注入系统事件的类 + * @throws ReflectionException + * @throws ReflectionException + */ + private function registerServerEvents() { + $all_event_class = ZMConfig::get("global", "server_event_handler_class") ?? []; + if (!in_array(ServerEventHandler::class, $all_event_class)) { + $all_event_class[] = ServerEventHandler::class; + } + $event_list = []; + foreach ($all_event_class as $v) { + $reader = new AnnotationReader(); + $reflection_class = new ReflectionClass($v); + $methods = $reflection_class->getMethods(ReflectionMethod::IS_PUBLIC); + foreach ($methods as $vs) { + $method_annotations = $reader->getMethodAnnotations($vs); + if ($method_annotations != []) { + $annotation = $method_annotations[0]; + if ($annotation instanceof OnEvent) { + $annotation->class = $v; + $annotation->method = $vs->getName(); + $event_list[strtolower($annotation->event)] = $annotation; + } + } + } + } + foreach ($event_list as $k => $v) { + self::$server->on($k, function (...$param) use ($v) { + $c = $v->class; + //echo $c.PHP_EOL; + $c = new $c(); + call_user_func_array([$c, $v->method], $param); + }); + } + } + + /** + * 解析命令行的 $argv 参数们 + * @param $args + * @throws Exception + */ + private function parseCliArgs($args) { + $coroutine_mode = true; + global $terminal_id; + $terminal_id = call_user_func(function () { + try { + $data = random_bytes(16); + } catch (Exception $e) { + return ""; + } + $data[6] = chr(ord($data[6]) & 0x0f | 0x40); + $data[8] = chr(ord($data[8]) & 0x3f | 0x80); + return strtoupper(vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4))); + }); + foreach ($args as $x => $y) { + switch ($x) { + case 'debug-mode': + if ($y) { + $coroutine_mode = false; + $terminal_id = null; + Console::warning("You are in debug mode, do not use in production!"); + } + break; + case 'daemon': + if ($y) { + $this->server_set["daemonize"] = 1; + Console::log("已启用守护进程,输出重定向到 " . $this->server_set["log_file"]); + $terminal_id = null; + } + break; + case 'disable-console-input': + if ($y) $terminal_id = null; + break; + case 'remote-shell': + if ($y) { + $host = "127.0.0.1"; + $port = 9599; + RemoteShell::listen(self::$server, $host, $port); + Console::log(Console::setColor("正在监听" . $host . ":" . strval($port) . "的调试接口,请注意安全", "yellow")); + } + break; + case 'log-error': + if ($y) Console::setLevel(0); + break; + case 'log-warning': + if ($y) Console::setLevel(1); + break; + case 'log-info': + if ($y) Console::setLevel(2); + break; + case 'log-verbose': + if ($y) Console::setLevel(3); + break; + case 'log-debug': + if ($y) Console::setLevel(4); + break; + case 'log-theme': + if($y !== null) { + Console::$theme = $y; + } + break; + } + } + if ($coroutine_mode) Runtime::enableCoroutine(true, SWOOLE_HOOK_ALL); + } + + private function getTtyWidth() { + return explode(" ", trim(exec("stty size")))[1]; + } + + public static function getServer() { + return self::$server; + } +} diff --git a/src/ZM/Http/StaticFileHandler.php b/src/ZM/Http/StaticFileHandler.php index fec943bc..f1163405 100644 --- a/src/ZM/Http/StaticFileHandler.php +++ b/src/ZM/Http/StaticFileHandler.php @@ -4,7 +4,7 @@ namespace ZM\Http; -use Framework\Console; +use ZM\Console\Console; use Framework\ZMBuf; use ZM\Utils\ZMUtil; diff --git a/src/ZM/ModBase.php b/src/ZM/ModBase.php deleted file mode 100644 index a6097a89..00000000 --- a/src/ZM/ModBase.php +++ /dev/null @@ -1,170 +0,0 @@ -server = $param0["server"]; - if (isset($param0["frame"])) $this->frame = $param0["frame"]; - if (isset($param0["data"])) $this->data = $param0["data"]; - if (isset($param0["request"])) $this->request = $param0["request"]; - if (isset($param0["response"])) $this->response = $param0["response"]; - if (isset($param0["fd"])) $this->fd = $param0["fd"]; - if (isset($param0["worker_id"])) $this->worker_id = $param0["worker_id"]; - if (isset($param0["connection"])) $this->connection = $param0["connection"]; - $this->handle_type = $handle_type; - } - - /** - * only can used by cq->message event function - * @param $msg - * @param bool $yield - * @return mixed - */ - public function reply($msg, $yield = false) { - switch ($this->data["message_type"]) { - case "group": - case "private": - case "discuss": - return CQAPI::quick_reply($this->connection, $this->data, $msg, $yield); - } - return false; - } - - public function finalReply($msg, $yield = false) { - $this->setBlock(); - if ($msg == "") return true; - return $this->reply($msg, $yield); - } - - /** - * @param string $prompt - * @param int $timeout - * @param string $timeout_prompt - * @return string - * @throws InvalidArgumentException - * @throws WaitTimeoutException - */ - public function waitMessage($prompt = "", $timeout = 600, $timeout_prompt = "") { - if ($prompt != "") $this->reply($prompt); - if (!isset($this->data["user_id"], $this->data["message"], $this->data["self_id"])) - throw new InvalidArgumentException("协程等待参数缺失"); - $cid = Co::getuid(); - $api_id = ZMBuf::$atomics["wait_msg_id"]->get(); - ZMBuf::$atomics["wait_msg_id"]->add(1); - $hang = [ - "coroutine" => $cid, - "user_id" => $this->data["user_id"], - "message" => $this->data["message"], - "self_id" => $this->data["self_id"], - "message_type" => $this->data["message_type"], - "result" => null - ]; - if ($hang["message_type"] == "group" || $hang["message_type"] == "discuss") { - $hang[$hang["message_type"] . "_id"] = $this->data[$this->data["message_type"] . "_id"]; - } - ZMBuf::appendKey("wait_api", $api_id, $hang); - $id = swoole_timer_after($timeout * 1000, function () use ($api_id, $timeout_prompt) { - $r = ZMBuf::get("wait_api")[$api_id] ?? null; - if ($r !== null) { - Co::resume($r["coroutine"]); - } - }); - - Co::suspend(); - $sess = ZMBuf::get("wait_api")[$api_id]; - ZMBuf::unsetByValue("wait_api", $api_id); - $result = $sess["result"]; - if (isset($id)) swoole_timer_clear($id); - if ($result === null) throw new WaitTimeoutException($this, $timeout_prompt); - return $result; - } - - /** - * @param $arg - * @param $mode - * @param $prompt_msg - * @return mixed|string - * @throws InvalidArgumentException - * @throws WaitTimeoutException - */ - public function getArgs(&$arg, $mode, $prompt_msg) { - switch ($mode) { - case ZM_MATCH_ALL: - $p = $arg; - array_shift($p); - return trim(implode(" ", $p)) == "" ? $this->waitMessage($prompt_msg) : trim(implode(" ", $p)); - case ZM_MATCH_NUMBER: - foreach ($arg as $k => $v) { - if (is_numeric($v)) { - array_splice($arg, $k, 1); - return $v; - } - } - return $this->waitMessage($prompt_msg); - case ZM_MATCH_FIRST: - if (isset($arg[1])) { - $a = $arg[1]; - array_splice($arg, 1, 1); - return $a; - } else { - return $this->waitMessage($prompt_msg); - } - } - throw new InvalidArgumentException(); - } - - public function getMessage() { return $this->data["message"] ?? null; } - - public function getUserId() { return $this->data["user_id"] ?? null; } - - public function getGroupId() { return $this->data["group_id"] ?? null; } - - public function getMessageType() { return $this->data["message_type"] ?? null; } - - public function getRobotId() { return $this->data["self_id"]; } - - public function getConnection() { return $this->connection; } - - public function setBlock($result = true) { context()->setCache("block_continue", $result); } -} diff --git a/src/ZM/ModHandleType.php b/src/ZM/ModHandleType.php deleted file mode 100644 index 1082dfc7..00000000 --- a/src/ZM/ModHandleType.php +++ /dev/null @@ -1,20 +0,0 @@ -get($key); - } - static function config($config_name) { return self::$config[$config_name] ?? null; } public static function resetCache() { self::$cache = []; - self::$connect = []; self::$time_nlp = null; self::$instance = []; } @@ -114,8 +104,9 @@ class ZMBuf * 初始化atomic计数器 */ public static function initAtomic() { - foreach (ZMBuf::globals("init_atomics") as $k => $v) { + foreach (ZMConfig::get("global", "init_atomics") as $k => $v) { self::$atomics[$k] = new Atomic($v); } + self::$atomics["show_log_worker"] = new Atomic(999999); } } diff --git a/src/Framework/DataProvider.php b/src/ZM/Utils/DataProvider.php similarity index 91% rename from src/Framework/DataProvider.php rename to src/ZM/Utils/DataProvider.php index 13de875e..e3e8e57c 100644 --- a/src/Framework/DataProvider.php +++ b/src/ZM/Utils/DataProvider.php @@ -1,10 +1,13 @@ get() >= 3) + if (Console::getLevel() >= 3) echo $head; foreach (self::$buffer_list as $k => $v) { Console::debug("Saving " . $k . " to " . $v); @@ -47,12 +50,12 @@ class DataProvider Console::debug("Calling @OnSave: $c -> $method"); $class->$method(); } - if (ZMBuf::$atomics["info_level"]->get() >= 3) + if (Console::getLevel() >= 3) echo Console::setColor("saved", "blue") . PHP_EOL; } public static function getFrameworkLink() { - return ZMBuf::globals("http_reverse_link"); + return ZMConfig::get("global", "http_reverse_link"); } public static function getJsonData(string $string) { diff --git a/src/Framework/RemoteShell.php b/src/ZM/Utils/RemoteShell.php similarity index 98% rename from src/Framework/RemoteShell.php rename to src/ZM/Utils/RemoteShell.php index 0e718824..701b3e74 100644 --- a/src/Framework/RemoteShell.php +++ b/src/ZM/Utils/RemoteShell.php @@ -40,7 +40,6 @@ class RemoteShell * @throws Exception */ static function listen($serv, $host = "127.0.0.1", $port = 9599) { - Console::warning("正在监听".$host.":".strval($port)."的调试接口,请注意安全"); $port = $serv->listen($host, $port, SWOOLE_SOCK_TCP); if (!$port) { throw new Exception("listen fail."); @@ -261,4 +260,4 @@ function get_arg(&$arg) { } $arg = get_class($arg) . ' Object (' . implode(',', $args) . ')'; } -} \ No newline at end of file +} diff --git a/src/ZM/Utils/SQLPool.php b/src/ZM/Utils/SQLPool.php deleted file mode 100644 index 9fb66280..00000000 --- a/src/ZM/Utils/SQLPool.php +++ /dev/null @@ -1,122 +0,0 @@ -pool = new SplQueue; - $this->info = [ - "host" => ZMBuf::globals("sql_config")["sql_host"], - "port" => ZMBuf::globals("sql_config")["sql_port"], - "user" => ZMBuf::globals("sql_config")["sql_username"], - "password" => ZMBuf::globals("sql_config")["sql_password"], - "database" => ZMBuf::globals("sql_config")["sql_database"] - ]; - Console::debug("新建检测 MySQL 连接的计时器"); - zm_timer_tick(10000, function () { - //Console::debug("正在检测是否有坏死的MySQL连接,当前连接池有 ".count($this->pool) . " 个连接"); - if (count($this->pool) > 0) { - /** @var PDO $cnn */ - $cnn = $this->pool->pop(); - $this->connect_cnt -= 1; - try { - $cnn->getAttribute(PDO::ATTR_SERVER_INFO); - } catch (PDOException $e) { - if (strpos($e->getMessage(), 'MySQL server has gone away') !== false) { - Console::info("MySQL 长连接丢失,取消连接"); - unset($cnn); - return; - } - } - $this->pool->push($cnn); - $this->connect_cnt += 1; - } - }); - } - - /** - * 将利用过的连接入队 - * @param $mysql - */ - public function put($mysql) { - $this->pool->push($mysql); - if (($a = array_shift($this->co_list)) !== null) { - Coroutine::resume($a); - } - } - - /** - * 获取队中的连接,如果不存在则创建新的 - * @param bool $no_new_conn - * @return bool|mixed|PDO - */ - public function get($no_new_conn = false) { - if (count($this->pool) == 0 && $this->connect_cnt <= 70) { - if ($no_new_conn) return false; - $this->connect_cnt += 1; - $r = $this->newConnect(); - if ($r !== false) { - return $r; - } else { - $this->connect_cnt -= 1; - return false; - } - } elseif (count($this->pool) > 0) { - /** @var PDO $con */ - $con = $this->pool->pop(); - return $con; - } elseif ($this->connect_cnt > 70) { - $this->co_list[] = Coroutine::getuid(); - Console::warning("数据库连接过多,协程等待重复利用中...当前协程数 " . Coroutine::stats()["coroutine_num"]); - Coroutine::suspend(); - return $this->get($no_new_conn); - } - return false; - } - - public function getCount() { - return $this->pool->count(); - } - - public function destruct() { - // 连接池销毁, 置不可用状态, 防止新的客户端进入常驻连接池, 导致服务器无法平滑退出 - $this->available = false; - while (!$this->pool->isEmpty()) { - $this->pool->pop(); - } - } - - private function newConnect() { - //无空闲连接,创建新连接 - $dsn = "mysql:host=" . $this->info["host"] . ";dbname=" . $this->info["database"] . ";charset=utf8"; - try { - $mysql = new PDO($dsn, $this->info["user"], $this->info["password"], array(PDO::ATTR_PERSISTENT => true)); - } catch (PDOException $e) { - Console::error("PDO Error: " . $e->getMessage()); - return false; - } - Console::info("创建SQL连接中,当前有" . $this->connect_cnt . "个连接"); - return $mysql; - } -} diff --git a/src/ZM/Utils/ScheduleManager.php b/src/ZM/Utils/ScheduleManager.php deleted file mode 100644 index e87e15ce..00000000 --- a/src/ZM/Utils/ScheduleManager.php +++ /dev/null @@ -1,10 +0,0 @@ -worker_id === 0) Console::info("ConsoleCommand disabled."); + return; + } + global $terminal_id; + global $port; + $port = ZMConfig::get("global", "port"); + $vss = new SwooleEventAt(); + $vss->type = "open"; + $vss->level = 256; + $vss->rule = "connectType:terminal"; + + $vss->callback = function (?ConnectionObject $conn) use ($terminal_id) { + $req = ctx()->getRequest(); + if ($conn->getName() != "terminal") return false; + Console::debug("Terminal fd: " . $conn->getFd()); + ZMBuf::set("terminal_fd", $conn->getFd()); + if (($req->header["x-terminal-id"] ?? "") != $terminal_id) { + ZMBuf::$server->close($conn->getFd()); + return false; + } + return false; + }; + ZMBuf::$events[SwooleEventAt::class][] = $vss; + $vss2 = new SwooleEventAt(); + $vss2->type = "message"; + $vss2->rule = "connectType:terminal"; + $vss2->callback = function (?ConnectionObject $conn) { + if ($conn === null) return false; + if ($conn->getName() != "terminal") return false; + $cmd = ctx()->getFrame()->data; + self::executeCommand($cmd); + return false; + }; + ZMBuf::$events[SwooleEventAt::class][] = $vss2; + if (ZMBuf::$server->worker_id === 0) { + go(function () { + global $terminal_id, $port; + $descriptorspec = array( + 0 => STDIN, + 1 => STDOUT, + 2 => STDERR + ); + self::$console_proc = proc_open('php -r \'$terminal_id = "' . $terminal_id . '";$port = ' . $port . ';require "' . __DIR__ . '/terminal_listener.php";\'', $descriptorspec, self::$pipes); + }); + } + } + + /** + * @param string $cmd + * @return bool + */ + private static function executeCommand(string $cmd) { + $it = explodeMsg($cmd); + switch ($it[0] ?? '') { + case 'logtest': + Console::log(date("[H:i:s]") . " [L] This is normal msg. (0)"); + Console::error("This is error msg. (0)"); + Console::warning("This is warning msg. (1)"); + Console::info("This is info msg. (2)"); + Console::success("This is success msg. (2)"); + Console::verbose("This is verbose msg. (3)"); + Console::debug("This is debug msg. (4)"); + return true; + case 'call': + $class_name = $it[1]; + $function_name = $it[2]; + $class = new $class_name([]); + call_user_func_array([$class, $function_name], []); + return true; + case 'bc': + $code = base64_decode($it[1] ?? '', true); + try { + eval($code); + } catch (Exception $e) { + } + return true; + case 'echo': + Console::info($it[1]); + return true; + case 'color': + Console::log($it[2], $it[1]); + return true; + case 'stop': + ZMUtil::stop(); + return false; + case 'reload': + case 'r': + ZMUtil::reload(); + return false; + case 'save': + //$origin = ZMBuf::$atomics["info_level"]->get(); + //ZMBuf::$atomics["info_level"]->set(3); + DataProvider::saveBuffer(); + //ZMBuf::$atomics["info_level"]->set($origin); + return true; + case '': + return true; + default: + Console::info("Command not found: " . $cmd); + return true; + } + } +} diff --git a/src/ZM/Utils/ZMRequest.php b/src/ZM/Utils/ZMRequest.php index fe1c5da5..2a6b6895 100644 --- a/src/ZM/Utils/ZMRequest.php +++ b/src/ZM/Utils/ZMRequest.php @@ -4,8 +4,7 @@ namespace ZM\Utils; -use Framework\Console; -use Swlib\Saber; +use ZM\Console\Console; use Swoole\Coroutine\Http\Client; class ZMRequest @@ -79,14 +78,6 @@ class ZMRequest return new ZMWebSocket($url, $set, $header); } - /** - * @param $option - * @return Saber - */ - public static function session($option) { - return Saber::session($option); - } - /** * @param $url * @param array $attribute diff --git a/src/ZM/Utils/ZMUtil.php b/src/ZM/Utils/ZMUtil.php index f09982a5..c4e5515e 100644 --- a/src/ZM/Utils/ZMUtil.php +++ b/src/ZM/Utils/ZMUtil.php @@ -5,10 +5,10 @@ namespace ZM\Utils; use Co; -use framework\Console; -use Framework\DataProvider; -use Framework\ZMBuf; +use ZM\Config\ZMConfig; +use ZM\Console\Console; use ZM\API\CQ; +use ZM\Store\ZMBuf; class ZMUtil { @@ -34,8 +34,8 @@ class ZMUtil } public static function getHttpCodePage(int $http_code) { - if (isset(ZMBuf::globals("http_default_code_page")[$http_code])) { - return Co::readFile(DataProvider::getResourceFolder() . "html/" . ZMBuf::globals("http_default_code_page")[$http_code]); + if (isset(ZMConfig::get("global", "http_default_code_page")[$http_code])) { + return Co::readFile(DataProvider::getResourceFolder() . "html/" . ZMConfig::get("global", "http_default_code_page")[$http_code]); } else return null; } @@ -51,20 +51,10 @@ class ZMUtil ZMBuf::$server->reload(); } - /** - * 解析CQ码 - * @param $msg - * @return array|null - */ - static function getCQ($msg) { - return CQ::getCQ($msg); - } - public static function getModInstance($class) { if (!isset(ZMBuf::$instance[$class])) { Console::debug("Class instance $class not exist, so I created it."); - ZMBuf::$instance[$class] = new $class(); - return ZMBuf::$instance[$class]; + return ZMBuf::$instance[$class] = new $class(); } else { return ZMBuf::$instance[$class]; } diff --git a/src/ZM/Utils/ZMWebSocket.php b/src/ZM/Utils/ZMWebSocket.php index 6340ba7c..cd17b8aa 100644 --- a/src/ZM/Utils/ZMWebSocket.php +++ b/src/ZM/Utils/ZMWebSocket.php @@ -4,7 +4,7 @@ namespace ZM\Utils; -use Framework\Console; +use ZM\Console\Console; use Swoole\Coroutine\Http\Client; use Swoole\WebSocket\Frame; diff --git a/src/Framework/terminal_listener.php b/src/ZM/Utils/terminal_listener.php similarity index 100% rename from src/Framework/terminal_listener.php rename to src/ZM/Utils/terminal_listener.php diff --git a/src/Framework/global_functions.php b/src/ZM/global_functions.php similarity index 94% rename from src/Framework/global_functions.php rename to src/ZM/global_functions.php index daf8315a..167f6b53 100644 --- a/src/Framework/global_functions.php +++ b/src/ZM/global_functions.php @@ -1,16 +1,18 @@