From 886816e3d5b06320febd9d0fd7accd15c1f0d99a Mon Sep 17 00:00:00 2001 From: whale Date: Sun, 10 May 2020 14:11:32 +0800 Subject: [PATCH] update to 1.3.1 version fix DataProvider::setJsonData bug add Root document of default request :warning: change MySQL driver to PDO, mysqlnd required improve exception catcher --- composer.json | 8 ++++-- src/Framework/DataProvider.php | 5 +++- src/Framework/FrameworkLoader.php | 12 ++++++--- src/Module/Example/Hello.php | 1 + src/ZM/DB/DB.php | 15 ++++++----- src/ZM/DB/SelectBody.php | 2 +- src/ZM/Event/EventHandler.php | 33 +++++++++++++++++++++--- src/ZM/Event/Swoole/MessageEvent.php | 2 +- src/ZM/Event/Swoole/WorkerStartEvent.php | 3 ++- src/ZM/Utils/SQLPool.php | 29 +++++++++++---------- 10 files changed, 78 insertions(+), 32 deletions(-) diff --git a/composer.json b/composer.json index 82cc2087..eb514751 100644 --- a/composer.json +++ b/composer.json @@ -3,7 +3,7 @@ "description": "high-performance intelligent assistant", "minimum-stability": "stable", "license": "proprietary", - "version": "1.3.0", + "version": "1.3.1", "authors": [ { "name": "whale", @@ -22,12 +22,16 @@ "ext-json": "*", "ext-posix": "*", "ext-ctype": "*", - "nikic/php-parser": "^4.4" + "nikic/php-parser": "^4.4", + "ext-pdo": "*" }, "repositories": { "packagist": { "type": "composer", "url": "https://mirrors.aliyun.com/composer/" } + }, + "require-dev": { + "phpunit/phpunit": "^9.1" } } diff --git a/src/Framework/DataProvider.php b/src/Framework/DataProvider.php index 8f8d2462..5b324966 100644 --- a/src/Framework/DataProvider.php +++ b/src/Framework/DataProvider.php @@ -55,7 +55,10 @@ class DataProvider private static function setJsonData($filename, array $args) { $pathinfo = pathinfo($filename); - if (!is_dir($pathinfo["dirname"])) mkdir(self::getDataConfig() . $pathinfo["dirname"]); + if (!is_dir(self::getDataConfig() . $pathinfo["dirname"])) { + Console::debug("Making Directory: " . self::getDataConfig() . $pathinfo["dirname"]); + mkdir(self::getDataConfig() . $pathinfo["dirname"]); + } $r = file_put_contents(self::getDataConfig() . $filename, json_encode($args, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_BIGINT_AS_STRING)); if ($r === false) { Console::warning("无法保存文件: " . $filename); diff --git a/src/Framework/FrameworkLoader.php b/src/Framework/FrameworkLoader.php index a9eed746..bdc9476a 100644 --- a/src/Framework/FrameworkLoader.php +++ b/src/Framework/FrameworkLoader.php @@ -4,6 +4,7 @@ namespace Framework; use Co; +use Doctrine\Common\Annotations\AnnotationException; use Swoole\Http\Request; use Swoole\Runtime; use Swoole\WebSocket\Frame; @@ -46,9 +47,7 @@ class FrameworkLoader echo "Phar mode: " . WORKING_DIR . PHP_EOL; } $this->registerAutoloader('classLoader'); - Runtime::enableCoroutine(); - - + 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"); @@ -95,7 +94,7 @@ class FrameworkLoader ", port: " . self::$settings->get("port") . ", log_level: " . ZMBuf::$atomics["info_level"]->get() . ", version: " . json_decode(file_get_contents(WORKING_DIR . "/composer.json"), true)["version"] . - "\nworking_dir: ".(isPharMode() ? realpath('.') : WORKING_DIR) + "\nworking_dir: " . (isPharMode() ? realpath('.') : WORKING_DIR) ); global $motd; echo $motd . PHP_EOL; @@ -141,6 +140,11 @@ class FrameworkLoader return true; } + /** + * @param \Swoole\Server $server + * @param $worker_id + * @throws AnnotationException + */ public function onWorkerStart(\Swoole\Server $server, $worker_id) { self::$instance = $this; self::$run_time = microtime(true); diff --git a/src/Module/Example/Hello.php b/src/Module/Example/Hello.php index 4bc124f6..9a94d417 100644 --- a/src/Module/Example/Hello.php +++ b/src/Module/Example/Hello.php @@ -73,6 +73,7 @@ class Hello extends ModBase /** * 默认示例页面 * @RequestMapping("/index") + * @RequestMapping("/") */ public function index() { return "Hello Zhamao!"; diff --git a/src/ZM/DB/DB.php b/src/ZM/DB/DB.php index e274c1da..f239e0fb 100644 --- a/src/ZM/DB/DB.php +++ b/src/ZM/DB/DB.php @@ -4,10 +4,11 @@ namespace ZM\DB; +use Exception; use framework\Console; use framework\ZMBuf; +use PDOStatement; use Swoole\Coroutine; -use Swoole\Coroutine\MySQL\Statement; use ZM\Exception\DbException; class DB @@ -16,8 +17,10 @@ class DB /** * @throws DbException + * @throws Exception */ 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"] . "';", []); foreach ($result as $v) { self::$table_list[] = $v['TABLE_NAME']; @@ -99,11 +102,10 @@ class DB } $ps = $conn->prepare($line); if ($ps === false) { - $conn->close(); ZMBuf::$sql_pool->connect_cnt -= 1; throw new DbException("SQL语句查询错误," . $line . ",错误信息:" . $conn->error); } else { - if (!($ps instanceof Statement)) { + if (!($ps instanceof PDOStatement)) { throw new DbException("语句查询错误!" . $line); } if ($params == []) $result = $ps->execute(); @@ -111,8 +113,8 @@ class DB $result = $ps->execute([$params]); } else $result = $ps->execute($params); ZMBuf::$sql_pool->put($conn); - if ($ps->errno != 0) { - throw new DBException("语句[$line]错误!" . $ps->error); + if ($result !== true) { + throw new DBException("语句[$line]错误!" . $ps->errorInfo()[2]); //echo json_encode(debug_backtrace(), 128 | 256); } if (ZMBuf::get("sql_log") === true) { @@ -122,7 +124,7 @@ class DB "] " . $line . " " . json_encode($params, JSON_UNESCAPED_UNICODE) . "\n"; Coroutine::writeFile(CRASH_DIR . "sql.log", $log, FILE_APPEND); } - return $result; + return $ps->fetchAll(); } } catch (DBException $e) { if (ZMBuf::get("sql_log") === true) { @@ -133,6 +135,7 @@ class DB Coroutine::writeFile(CRASH_DIR . "sql.log", $log, FILE_APPEND); } Console::warning($e->getMessage()); + throw $e; } } diff --git a/src/ZM/DB/SelectBody.php b/src/ZM/DB/SelectBody.php index 1982c7e4..c4164603 100644 --- a/src/ZM/DB/SelectBody.php +++ b/src/ZM/DB/SelectBody.php @@ -38,7 +38,7 @@ class SelectBody if ($this->table->isCacheEnabled()) { $rr = md5(implode(",", $this->select_thing) . serialize($this->where_thing)); if (array_key_exists($rr, $this->table->cache)) { - Console::info('SQL query cached: ' . $rr, date("[H:i:s ") . 'DB] '); + Console::debug('SQL query cached: ' . $rr); return $this->table->cache[$rr]->getResult(); } } diff --git a/src/ZM/Event/EventHandler.php b/src/ZM/Event/EventHandler.php index 7e2d978c..eca25c95 100644 --- a/src/ZM/Event/EventHandler.php +++ b/src/ZM/Event/EventHandler.php @@ -63,7 +63,12 @@ class EventHandler /** @var Server $param0 */ $conn = ConnectionManager::get($param1->fd); set_coroutine_params(["server" => $param0, "frame" => $param1, "connection" => $conn]); - (new MessageEvent($param0, $param1))->onActivate()->onAfter(); + 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); + } break; case "request": try { @@ -78,15 +83,37 @@ class EventHandler if (!$param1->isEnd()) $param1->end("Internal server error: " . $e->getMessage()); Console::error("Internal server error (500), caused by uncaught exception."); Console::log($e->getTraceAsString(), "gray"); + } catch (Error $e) { + /** @var Response $param1 */ + $param1->status(500); + Console::info($param0->server["remote_addr"] . ":" . $param0->server["remote_port"] . + " [" . $param1->getStatusCode() . "] " . $param0->server["request_uri"] + ); + $doc = "Internal server error
"; + $error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")"; + if (ZMBuf::$atomics["info_level"]->get() >= 4) $doc .= $error_msg; + if (!$param1->isEnd()) $param1->end($doc); + Console::error("Internal server error (500): " . $error_msg); + Console::log($e->getTraceAsString(), "gray"); } break; case "open": set_coroutine_params(["server" => $param0, "request" => $param1]); - (new WSOpenEvent($param0, $param1))->onActivate()->onAfter(); + try { + (new WSOpenEvent($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); + } break; case "close": set_coroutine_params(["server" => $param0, "fd" => $param1]); - (new WSCloseEvent($param0, $param1))->onActivate()->onAfter(); + try { + (new WSCloseEvent($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); + } break; } //Console::info(Console::setColor("Event: " . $event_name . " 运行了 " . round(microtime(true) - $starttime, 5) . " 秒", "gold")); diff --git a/src/ZM/Event/Swoole/MessageEvent.php b/src/ZM/Event/Swoole/MessageEvent.php index 17461f85..e632e105 100644 --- a/src/ZM/Event/Swoole/MessageEvent.php +++ b/src/ZM/Event/Swoole/MessageEvent.php @@ -63,7 +63,7 @@ class MessageEvent implements SwooleEvent } } } catch (Exception $e) { - Console::warning("Websocket message event exception: " . $e->getMessage()); + Console::warning("Websocket message event exception: " . (($cs = $e->getMessage()) == "" ? get_class($e) : $cs)); } return $this; } diff --git a/src/ZM/Event/Swoole/WorkerStartEvent.php b/src/ZM/Event/Swoole/WorkerStartEvent.php index c929d835..adc3a797 100644 --- a/src/ZM/Event/Swoole/WorkerStartEvent.php +++ b/src/ZM/Event/Swoole/WorkerStartEvent.php @@ -133,6 +133,7 @@ class WorkerStartEvent implements SwooleEvent //加载phar包 Console::info("加载外部phar包中"); $dir = DataProvider::getWorkingDir() . "/resources/package/"; + if (version_compare(SWOOLE_VERSION, "4.4.0", ">=")) Timer::clearAll(); if (is_dir($dir)) { $list = scandir($dir); unset($list[0], $list[1]); @@ -147,7 +148,7 @@ class WorkerStartEvent implements SwooleEvent Console::info("加载composer资源中"); require_once DataProvider::getWorkingDir() . "/vendor/autoload.php"; } else { - if(isPharMode()) require_once WORKING_DIR . "/vendor/autoload.php"; + if (isPharMode()) require_once WORKING_DIR . "/vendor/autoload.php"; } //加载各个模块的注解类,以及反射 diff --git a/src/ZM/Utils/SQLPool.php b/src/ZM/Utils/SQLPool.php index db5805fa..d813b6f9 100644 --- a/src/ZM/Utils/SQLPool.php +++ b/src/ZM/Utils/SQLPool.php @@ -10,6 +10,8 @@ namespace ZM\Utils; use framework\Console; use framework\ZMBuf; +use PDO; +use PDOException; use SplQueue; use Swoole\Coroutine; use Swoole\Coroutine\Mysql; @@ -48,11 +50,11 @@ class SQLPool /** * 获取队中的连接,如果不存在则创建新的 * @param bool $no_new_conn - * @return bool|mixed|Mysql + * @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; + if ($no_new_conn) return false; $this->connect_cnt += 1; $r = $this->newConnect(); if ($r !== false) { @@ -62,11 +64,12 @@ class SQLPool return false; } } elseif (count($this->pool) > 0) { + /** @var PDO $con */ $con = $this->pool->pop(); - if ($con->connected !== false) return $con; + return $con; } elseif ($this->connect_cnt > 70) { - $this->co_list[]=Coroutine::getuid(); - Console::warning("数据库连接过多,协程等待重复利用中...当前协程数 ".Coroutine::stats()["coroutine_num"]); + $this->co_list[] = Coroutine::getuid(); + Console::warning("数据库连接过多,协程等待重复利用中...当前协程数 " . Coroutine::stats()["coroutine_num"]); Coroutine::suspend(); return $this->get($no_new_conn); } @@ -88,14 +91,14 @@ class SQLPool private function newConnect() { //无空闲连接,创建新连接 $mysql = new Mysql(); - - Console::info("创建SQL连接中,当前有" . $this->connect_cnt . "个连接"); - $res = $mysql->connect($this->info); - if ($res == false) { - echo $mysql->error . PHP_EOL; + $dsn = "mysql:host=" . $this->info["host"] . ";dbname=" . $this->info["database"]; + 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; - } else { - return $mysql; } + Console::info("创建SQL连接中,当前有" . $this->connect_cnt . "个连接"); + return $mysql; } -} \ No newline at end of file +}