diff --git a/docs/update/v2.md b/docs/update/v2.md index 7abf8a9c..cfb23bf4 100644 --- a/docs/update/v2.md +++ b/docs/update/v2.md @@ -1,5 +1,14 @@ # 更新日志(v2 版本) +## v2.2.2 + +> 更新时间:2021.1.29 + +- 修复:模块文件错误时避免循环报错 +- 优化:代码结构 +- 修复:在不同进程时调用机器人 API 无法返回且报错的 bug +- **修复:机器人无法连接的问题(2.1.6 ~ 2.2.1 受影响)** + ## v2.2.1 > 更新时间:2021.1.29 diff --git a/src/Custom/Command/CustomCommand.php b/src/Custom/Command/CustomCommand.php deleted file mode 100644 index 9fe702f4..00000000 --- a/src/Custom/Command/CustomCommand.php +++ /dev/null @@ -1,31 +0,0 @@ -setDescription("custom description | 自定义命令的描述字段"); - $this->addOption("failure", null, null, "以错误码为1返回结果"); - // ... - } - - protected function execute(InputInterface $input, OutputInterface $output) { - if ($input->getOption("failure")) { - $output->writeln("Hello error! I am wrong message."); - return Command::FAILURE; - } else { - $output->writeln("Hello world! I am successful message."); - return Command::SUCCESS; - } - } -} diff --git a/src/Custom/global_function.php b/src/Custom/global_function.php index 3965f5ba..471470ee 100644 --- a/src/Custom/global_function.php +++ b/src/Custom/global_function.php @@ -1,4 +1,4 @@ - $reply, "time" => microtime(true), - "self_id" => $connection->getOption("connect_id") + "self_id" => $connection->getOption("connect_id"), + "echo" => $api_id ]; - if ($function === true) $r[$api_id]["coroutine"] = Co::getuid(); LightCacheInside::set("wait_api", "wait_api", $r); SpinLock::unlock("wait_api"); if (server()->push($connection->getFd(), json_encode($reply))) { if ($function === true) { - Co::suspend(); + return CoMessage::yieldByWS($r[$api_id], ["echo"], 60); + } else { SpinLock::lock("wait_api"); $r = LightCacheInside::get("wait_api", "wait_api"); - $data = $r[$api_id]; unset($r[$api_id]); LightCacheInside::set("wait_api", "wait_api", $r); SpinLock::unlock("wait_api"); - return isset($data['result']) ? $data['result'] : null; } return true; } else { diff --git a/src/ZM/API/ZMRobot.php b/src/ZM/API/ZMRobot.php index 45230948..027fe0ac 100644 --- a/src/ZM/API/ZMRobot.php +++ b/src/ZM/API/ZMRobot.php @@ -228,9 +228,9 @@ class ZMRobot /** * 群组单人禁言 * @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#set_group_ban-%E7%BE%A4%E7%BB%84%E5%8D%95%E4%BA%BA%E7%A6%81%E8%A8%80 - * @param int $group_id - * @param int $user_id - * @param int $duration + * @param $group_id + * @param $user_id + * @param $duration * @return array|bool|null */ public function setGroupBan($group_id, $user_id, $duration = 1800) { diff --git a/src/ZM/Annotation/AnnotationParser.php b/src/ZM/Annotation/AnnotationParser.php index ff0d443b..56e19158 100644 --- a/src/ZM/Annotation/AnnotationParser.php +++ b/src/ZM/Annotation/AnnotationParser.php @@ -90,6 +90,7 @@ class AnnotationParser if ($vs instanceof ErgodicAnnotation) { foreach (($this->annotation_map[$v]["methods"] ?? []) as $method) { $copy = clone $vs; + /** @noinspection PhpUndefinedFieldInspection */ $copy->method = $method->getName(); $this->annotation_map[$v]["methods_annotations"][$method->getName()][] = $copy; } diff --git a/src/ZM/DB/DB.php b/src/ZM/DB/DB.php index 0dd1c35d..8e42e03d 100644 --- a/src/ZM/DB/DB.php +++ b/src/ZM/DB/DB.php @@ -31,7 +31,6 @@ class DB /** * @param $table_name - * @param bool $enable_cache * @return Table * @throws DbException */ @@ -95,6 +94,7 @@ class DB $ps = $conn->prepare($line); if ($ps === false) { SqlPoolStorage::$sql_pool->put(null); + /** @noinspection PhpUndefinedFieldInspection */ throw new DbException("SQL语句查询错误," . $line . ",错误信息:" . $conn->error); } else { if (!($ps instanceof PDOStatement) && !($ps instanceof PDOStatementProxy)) { diff --git a/src/ZM/DB/Table.php b/src/ZM/DB/Table.php index 939bc8ad..5cf4d0a4 100644 --- a/src/ZM/DB/Table.php +++ b/src/ZM/DB/Table.php @@ -47,7 +47,7 @@ class Table return new DeleteBody($this); } - public function statement($line){ + public function statement(){ $this->cache = []; //TODO: 无返回的statement语句 } diff --git a/src/ZM/Event/EventDispatcher.php b/src/ZM/Event/EventDispatcher.php index 4781cff7..16869701 100644 --- a/src/ZM/Event/EventDispatcher.php +++ b/src/ZM/Event/EventDispatcher.php @@ -87,7 +87,6 @@ class EventDispatcher /** * @param mixed ...$params * @throws Exception - * @throws InterruptException */ public function dispatchEvents(...$params) { try { diff --git a/src/ZM/Event/ServerEventHandler.php b/src/ZM/Event/ServerEventHandler.php index 4d3f0d9f..d2cbb7ae 100644 --- a/src/ZM/Event/ServerEventHandler.php +++ b/src/ZM/Event/ServerEventHandler.php @@ -74,17 +74,17 @@ class ServerEventHandler } Process::signal(SIGINT, function () use ($r) { echo "\r"; - Console::warning("Server interrupted by keyboard on Master."); + Console::warning("Server interrupted(SIGINT) on Master."); if ((Framework::$server->inotify ?? null) !== null) /** @noinspection PhpUndefinedFieldInspection */ Event::del(Framework::$server->inotify); ZMUtil::stop(); }); - if(Framework::$argv["daemon"]) { + if (Framework::$argv["daemon"]) { $daemon_data = json_encode([ "pid" => \server()->master_pid, "stdout" => ZMConfig::get("global")["swoole"]["log_file"] - ],128|256); - file_put_contents(DataProvider::getWorkingDir()."/.daemon_pid", $daemon_data); + ], 128 | 256); + file_put_contents(DataProvider::getWorkingDir() . "/.daemon_pid", $daemon_data); } if (Framework::$argv["watch"]) { if (extension_loaded('inotify')) { @@ -238,7 +238,7 @@ class ServerEventHandler Console::error("PHP Error: " . $e->getMessage() . " in " . $e->getFile() . " on line " . $e->getLine()); Console::error("Maybe it caused by your own code if in your own Module directory."); Console::log($e->getTraceAsString(), 'gray'); - ZMUtil::stop(); + posix_kill($server->master_pid, SIGINT); } } else { // 这里是TaskWorker初始化的内容部分 @@ -255,7 +255,7 @@ class ServerEventHandler Console::error("PHP Error: " . $e->getMessage() . " in " . $e->getFile() . " on line " . $e->getLine()); Console::error("Maybe it caused by your own code if in your own Module directory."); Console::log($e->getTraceAsString(), 'gray'); - ZMUtil::stop(); + posix_kill($server->master_pid, SIGINT); } } } @@ -314,7 +314,7 @@ class ServerEventHandler */ public function onRequest(?Request $request, ?\Swoole\Http\Response $response) { $response = new Response($response); - foreach(ZMConfig::get("global")["http_header"] as $k => $v) { + foreach (ZMConfig::get("global")["http_header"] as $k => $v) { $response->setHeader($k, $v); } unset(Context::$context[Co::getCid()]); @@ -491,10 +491,10 @@ class ServerEventHandler /** * @SwooleHandler("pipeMessage") - * @param $server + * @param Server $server * @param $src_worker_id * @param $data - * @throws InterruptException + * @throws Exception */ public function onPipeMessage(Server $server, $src_worker_id, $data) { //var_dump($data, $server->worker_id); @@ -561,10 +561,11 @@ class ServerEventHandler * @param Server|null $server * @param Server\Task $task * @return mixed + * @noinspection PhpUnusedParameterInspection */ public function onTask(?Server $server, Server\Task $task) { $data = $task->data; - switch($data["action"]) { + switch ($data["action"]) { case "runMethod": $c = $data["class"]; $ss = new $c(); diff --git a/src/ZM/Module/QQBot.php b/src/ZM/Module/QQBot.php index 084ad444..e64923e4 100644 --- a/src/ZM/Module/QQBot.php +++ b/src/ZM/Module/QQBot.php @@ -3,7 +3,7 @@ namespace ZM\Module; -use Swoole\Coroutine; +use Exception; use ZM\Annotation\CQ\CQAPIResponse; use ZM\Annotation\CQ\CQBefore; use ZM\Annotation\CQ\CQCommand; @@ -14,8 +14,6 @@ use ZM\Annotation\CQ\CQRequest; use ZM\Event\EventDispatcher; use ZM\Exception\InterruptException; use ZM\Exception\WaitTimeoutException; -use ZM\Store\LightCacheInside; -use ZM\Store\Lock\SpinLock; use ZM\Utils\CoMessage; /** @@ -26,22 +24,25 @@ class QQBot { /** * @throws InterruptException + * @throws Exception */ public function handle() { try { $data = json_decode(context()->getFrame()->data, true); + set_coroutine_params(["data" => $data]); + if (isset($data["echo"])) { + if (CoMessage::resumeByWS()) { + EventDispatcher::interrupt(); + } + } if (isset($data["post_type"])) { //echo TermColor::ITALIC.json_encode($data, 128|256).TermColor::RESET.PHP_EOL; - set_coroutine_params(["data" => $data]); ctx()->setCache("level", 0); //Console::debug("Calling CQ Event from fd=" . ctx()->getConnection()->getFd()); if ($data["post_type"] != "meta_event") { $r = $this->dispatchBeforeEvents($data); // before在这里执行,元事件不执行before为减少不必要的调试日志 if ($r->store === "block") EventDispatcher::interrupt(); } - if (CoMessage::resumeByWS()) { - EventDispatcher::interrupt(); - } //Console::warning("最上数据包:".json_encode($data)); $this->dispatchEvents($data); } else { @@ -55,7 +56,7 @@ class QQBot /** * @param $data * @return EventDispatcher - * @throws InterruptException + * @throws Exception */ public function dispatchBeforeEvents($data) { $before = new EventDispatcher(CQBefore::class); @@ -177,45 +178,16 @@ class QQBot } } + /** + * @param $req + * @throws Exception + */ private function dispatchAPIResponse($req) { - $status = $req["status"]; - $retcode = $req["retcode"]; - $data = $req["data"]; - if (isset($req["echo"]) && is_numeric($req["echo"])) { - $r = LightCacheInside::get("wait_api", "wait_api"); - if (isset($r[$req["echo"]])) { - $origin = $r[$req["echo"]]; - $self_id = $origin["self_id"]; - $response = [ - "status" => $status, - "retcode" => $retcode, - "data" => $data, - "self_id" => $self_id, - "echo" => $req["echo"] - ]; - set_coroutine_params(["cq_response" => $response]); - $dispatcher = new EventDispatcher(CQAPIResponse::class); - $dispatcher->setRuleFunction(function (CQAPIResponse $response) { - return $response->retcode == ctx()->getCQResponse()["retcode"]; - }); - $dispatcher->dispatchEvents($response); - - $origin_ctx = ctx()->copy(); - set_coroutine_params($origin_ctx); - if (($origin["coroutine"] ?? false) !== false) { - SpinLock::lock("wait_api"); - $r = LightCacheInside::get("wait_api", "wait_api"); - $r[$req["echo"]]["result"] = $response; - LightCacheInside::set("wait_api", "wait_api", $r); - SpinLock::unlock("wait_api"); - Coroutine::resume($origin['coroutine']); - } - SpinLock::lock("wait_api"); - $r = LightCacheInside::get("wait_api", "wait_api"); - unset($r[$req["echo"]]); - LightCacheInside::set("wait_api", "wait_api", $r); - SpinLock::unlock("wait_api"); - } - } + set_coroutine_params(["cq_response" => $req]); + $dispatcher = new EventDispatcher(CQAPIResponse::class); + $dispatcher->setRuleFunction(function (CQAPIResponse $response) { + return $response->retcode == ctx()->getCQResponse()["retcode"]; + }); + $dispatcher->dispatchEvents($req); } } diff --git a/src/ZM/Store/LightCacheInside.php b/src/ZM/Store/LightCacheInside.php index c161eca0..1745bb46 100644 --- a/src/ZM/Store/LightCacheInside.php +++ b/src/ZM/Store/LightCacheInside.php @@ -23,9 +23,10 @@ class LightCacheInside $result = self::$kv_table["wait_api"]->create() && self::$kv_table["connect"]->create(); if ($result === false) { self::$last_error = '系统内存不足,申请失败'; - return $result; + return false; + } else { + return true; } - return $result; } /** diff --git a/src/ZM/Store/WorkerCache.php b/src/ZM/Store/WorkerCache.php index 85803ce8..4cb68054 100644 --- a/src/ZM/Store/WorkerCache.php +++ b/src/ZM/Store/WorkerCache.php @@ -35,15 +35,19 @@ class WorkerCache return true; } else { $action = ["action" => $async ? "asyncSetWorkerCache" : "setWorkerCache", "key" => $key, "value" => $value, "cid" => zm_cid()]; - $ss = server()->sendMessage(json_encode($action, JSON_UNESCAPED_UNICODE), $config["worker"]); - if(!$ss) return false; - if ($async) return true; - zm_yield(); - $p = self::$transfer[zm_cid()] ?? null; - unset(self::$transfer[zm_cid()]); - return $p; + return self::processRemote($action, $async, $config); } } + + private static function processRemote($action, $async, $config) { + $ss = server()->sendMessage(json_encode($action, JSON_UNESCAPED_UNICODE), $config["worker"]); + if(!$ss) return false; + if ($async) return true; + zm_yield(); + $p = self::$transfer[zm_cid()] ?? null; + unset(self::$transfer[zm_cid()]); + return $p; + } public static function unset($key, $async = false) { $config = self::$config ?? ZMConfig::get("global", "worker_cache"); @@ -52,13 +56,7 @@ class WorkerCache return true; } else { $action = ["action" => $async ? "asyncUnsetWorkerCache" : "unsetWorkerCache", "key" => $key, "cid" => zm_cid()]; - $ss = server()->sendMessage(json_encode($action, JSON_UNESCAPED_UNICODE), $config["worker"]); - if(!$ss) return false; - if ($async) return true; - zm_yield(); - $p = self::$transfer[zm_cid()] ?? null; - unset(self::$transfer[zm_cid()]); - return $p; + return self::processRemote($action, $async, $config); } } @@ -70,13 +68,7 @@ class WorkerCache return true; } else { $action = ["action" => $async ? "asyncAddWorkerCache" : "addWorkerCache", "key" => $key, "value" => $value, "cid" => zm_cid()]; - $ss = server()->sendMessage(json_encode($action, JSON_UNESCAPED_UNICODE), $config["worker"]); - // if(!$ss) return false; - if ($async) return true; - zm_yield(); - $p = self::$transfer[zm_cid()] ?? null; - unset(self::$transfer[zm_cid()]); - return $p; + return self::processRemote($action, $async, $config); } } @@ -88,13 +80,7 @@ class WorkerCache return true; } else { $action = ["action" => $async ? "asyncSubWorkerCache" : "subWorkerCache", "key" => $key, "value" => $value, "cid" => zm_cid()]; - $ss = server()->sendMessage(json_encode($action, JSON_UNESCAPED_UNICODE), $config["worker"]); - // if(!$ss) return false; - if ($async) return true; - zm_yield(); - $p = self::$transfer[zm_cid()] ?? null; - unset(self::$transfer[zm_cid()]); - return $p; + return self::processRemote($action, $async, $config); } } } \ No newline at end of file diff --git a/src/ZM/Utils/CoMessage.php b/src/ZM/Utils/CoMessage.php index 637f56f7..3f150086 100644 --- a/src/ZM/Utils/CoMessage.php +++ b/src/ZM/Utils/CoMessage.php @@ -16,7 +16,7 @@ class CoMessage * @param array $hang * @param array $compare * @param int $timeout - * @return bool + * @return mixed * @throws Exception */ public static function yieldByWS(array $hang, array $compare, $timeout = 600) { @@ -57,7 +57,8 @@ class CoMessage foreach ($all as $k => $v) { if(!isset($v["compare"])) continue; foreach ($v["compare"] as $vs) { - if ($v[$vs] != ($dat[$vs] ?? null)) { + if (!isset($v[$vs], $dat[$vs])) continue 2; + if ($v[$vs] != $dat[$vs]) { continue 2; } } @@ -68,7 +69,7 @@ class CoMessage LightCacheInside::set("wait_api", "wait_api", $all); SpinLock::unlock("wait_api"); if ($all[$last]["worker_id"] != server()->worker_id) { - ZMUtil::sendActionToWorker($all[$k]["worker_id"], "resume_ws_message", $all[$last]); + ZMUtil::sendActionToWorker($all[$last]["worker_id"], "resume_ws_message", $all[$last]); } else { Co::resume($all[$last]["coroutine"]); } diff --git a/src/ZM/global_functions.php b/src/ZM/global_functions.php index ba10c519..cecac665 100644 --- a/src/ZM/global_functions.php +++ b/src/ZM/global_functions.php @@ -24,6 +24,7 @@ function phar_classloader($p) { return; } try { + /** @noinspection PhpIncludeInspection */ require_once $filepath; } catch (Exception $e) { echo "Error when finding class: " . $p . PHP_EOL; @@ -75,7 +76,7 @@ function unicode_decode($str) { /** * 获取模块文件夹下的每个类文件的类名称 * @param $dir - * @param string $indoor_name + * @param $indoor_name * @return array */ function getAllClasses($dir, $indoor_name) { @@ -95,6 +96,7 @@ function getAllClasses($dir, $indoor_name) { continue 2; } } + if ($v == "global_function.php") continue; $class_name = $indoor_name . "\\" . mb_substr($v, 0, -4); $classes [] = $class_name; }