From 235256d67967bec930f2999648a210e0df687108 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Tue, 23 Mar 2021 14:49:42 +0800 Subject: [PATCH] =?UTF-8?q?rollback=20and=20correct=20to=20398=EF=BC=88v2.?= =?UTF-8?q?3.5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/global.php | 27 ++-- docs/advanced/inside-class.md | 41 ------ docs/advanced/task-worker.md | 3 - docs/assets/img/image-20210321193956832.png | Bin 97908 -> 0 bytes docs/component/global-functions.md | 60 +-------- docs/component/message-util.md | 89 ------------- docs/component/route-manager.md | 54 -------- docs/component/task-worker.md | 26 ---- docs/component/zmutil.md | 44 ------- docs/event/framework-annotations.md | 24 ---- mkdocs.yml | 14 +-- src/Module/Example/Hello.php | 41 ------ src/ZM/API/TuringAPI.php | 118 ------------------ src/ZM/Annotation/Command/TerminalCommand.php | 27 ---- src/ZM/Command/DaemonStopCommand.php | 2 +- src/ZM/Command/RunServerCommand.php | 1 - src/ZM/ConsoleApplication.php | 6 +- src/ZM/Entity/MatchResult.php | 17 --- src/ZM/Event/EventDispatcher.php | 2 - src/ZM/Event/ServerEventHandler.php | 90 +++++++++---- src/ZM/Framework.php | 97 +------------- src/ZM/Module/QQBot.php | 54 ++++++-- src/ZM/Store/LightCache.php | 17 ++- src/ZM/Store/LightCacheInside.php | 6 +- src/ZM/Store/ZMAtomic.php | 3 - src/ZM/Utils/MessageUtil.php | 84 ------------- src/ZM/Utils/ProcessManager.php | 110 ++-------------- src/ZM/Utils/Terminal.php | 62 ++------- src/ZM/Utils/ZMUtil.php | 52 ++++---- src/ZM/global_functions.php | 56 ++------- 30 files changed, 207 insertions(+), 1020 deletions(-) delete mode 100644 docs/advanced/task-worker.md delete mode 100644 docs/assets/img/image-20210321193956832.png delete mode 100644 docs/component/message-util.md delete mode 100644 docs/component/route-manager.md delete mode 100644 docs/component/task-worker.md delete mode 100644 src/ZM/API/TuringAPI.php delete mode 100644 src/ZM/Annotation/Command/TerminalCommand.php delete mode 100644 src/ZM/Entity/MatchResult.php diff --git a/config/global.php b/config/global.php index 8237a76f..5a55d125 100644 --- a/config/global.php +++ b/config/global.php @@ -113,18 +113,21 @@ $config['server_event_handler_class'] = [ ]; /** 服务器启用的外部第三方和内部插件 */ -$config['modules']['onebot'] = [ - // 机器人解析模块,关闭后无法使用如@CQCommand等注解 - 'status' => true, - 'single_bot_mode' => false -]; - -$config['modules']['remote_terminal'] = [ - // 一个远程简易终端,使用nc直接连接即可,但是不建议开放host为0.0.0.0(远程连接) - 'status' => false, - 'host' => '127.0.0.1', - 'port' => 20002, - 'token' => '' +$config['modules'] = [ + 'onebot' => [ // 机器人解析模块,关闭后无法使用如@CQCommand等注解 + 'status' => true, + 'single_bot_mode' => false + ], + 'http_proxy_server' => [ // 一个内置的简单HTTP代理服务器,目前还没有认证功能,预计2.4.0版本完成 + 'status' => false, + 'host' => '0.0.0.0', + 'port' => 8083, + 'swoole_set_override' => [ + 'backlog' => 128, + 'buffer_output_size' => 1024 * 1024 * 128, + 'socket_buffer_size' => 1024 * 1024 * 1 + ] + ], ]; return $config; diff --git a/docs/advanced/inside-class.md b/docs/advanced/inside-class.md index fb300250..b71a30b9 100644 --- a/docs/advanced/inside-class.md +++ b/docs/advanced/inside-class.md @@ -27,44 +27,3 @@ TODO:先放一放。 ``` -## ZM\Entity\MatchObject - -此类是调用方法 `MessageUtil::matchCommand()` 返回的对象体,含有匹配成功与否和匹配到的注解相关的信息。 - -### 属性 - -- `$match`:`bool` 类型,返回匹配是否成功 -- `$object`:`CQCommand` 注解类,如果匹配成功则返回对应的 `@CQCommand` 信息 -- `match`:`array` 类型,如果匹配成功则返回匹配到的参数 - -```php -// 假设我有一个注解事件 @CQCommand(match="你好"),绑定的函数是 \Module\Example\Hello 下的 hello123() - -$obj = MessageUtil::matchCommand("你好 我叫顺溜 我今年二十八", ctx()->getData()); -/* 以下是返回信息,仅供参考 -$obj->match ==> true -$obj->object ==> \ZM\Annotation\CQ\CQCommand: ( - match: "你好", - pattern: "", - regex: "", - start_with: "", - end_with: "", - keyword: "", - alias: [], - message_type: "", - user_id: 0, - group_id: 0, - discuss_id: 0, - level: 20, - method: "hello123", - class: \Module\Example\Hello::class -) -$obj->match ==> [ - "我叫顺溜", - "我今年二十八" -] -*/ -``` - - - diff --git a/docs/advanced/task-worker.md b/docs/advanced/task-worker.md deleted file mode 100644 index 18495898..00000000 --- a/docs/advanced/task-worker.md +++ /dev/null @@ -1,3 +0,0 @@ -# 使用 TaskWorker 进程处理密集运算 - -> 新开个坑,有时间补上。(__填坑标记__) \ No newline at end of file diff --git a/docs/assets/img/image-20210321193956832.png b/docs/assets/img/image-20210321193956832.png deleted file mode 100644 index 3e28f407d51a3f9b7bd19f9bc864d18aedc36da1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 97908 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 diff --git a/docs/component/global-functions.md b/docs/component/global-functions.md index 897fbccc..f4e6e37e 100644 --- a/docs/component/global-functions.md +++ b/docs/component/global-functions.md @@ -134,6 +134,10 @@ set_coroutine_params(["data" => [ 别名:`context()`,获取当前协程的上下文,见 [上下文](/component/context/)。 +## zm_debug() + +同 `Console::debug($msg)`。 + ## zm_sleep() 协程版 `sleep()` 函数。 @@ -251,58 +255,4 @@ bot()->sendPrivateMsg(123456, "你好啊!!"); 定义:`getAllFdByConnectType(string $type = 'default'): array` -当 `$type` 为 `qq` 时,则返回所有 OneBot 机器人接入的 WebSocket 连接号。 - -## zm_dump() - -更漂亮地输出变量值,可替代 `var_dump()`。 - -```php -class Pass { - public $foo = 123; - public $bar = ["a", "b"]; -} -$pass = new Pass(); -$pass->obj = true; -zm_dump($pass); -``` - -image-20210321193956832 - -## zm_config() - -同 `ZMConfig::get()`。 - -定义:`zm_config($name, $key = null)`。 - -有关 ZMConfig 模块的说明,见 [指南 - 基本配置](/guide/basic-config/)。 - -```php -zm_config("global"); //等同于 ZMConfig::get("global"); -zm_config("global", "swoole"); //等同于 ZMConfig::get("global", "swoole"); -``` - -## zm_info() - -同 `Console::info($msg)`。 - -## zm_debug() - -同 `Console::debug($msg)`。 - -## zm_warning() - -同 `Console::warning($msg)`。 - -## zm_success() - -同 `Console::success($msg)`。 - -## zm_error() - -同 `Console::error($msg)`。 - -## zm_verbose() - -同 `Console::verbose($msg)`。 - +当 `$type` 为 `qq` 时,则返回所有 OneBot 机器人接入的 WebSocket 连接号。 \ No newline at end of file diff --git a/docs/component/message-util.md b/docs/component/message-util.md deleted file mode 100644 index 72f6507a..00000000 --- a/docs/component/message-util.md +++ /dev/null @@ -1,89 +0,0 @@ -# MessageUtil 消息处理工具类 - -类定义:`\ZM\Utils\MessageUtil` - -> 2.3.0 版本起可用。 - -这里放置一些机器人聊天消息处理的便捷静态方法,例如下载图片等。 - -## 方法 - -### downloadCQImage() - -下载用户消息中所带的所有图片,并返回文件路径。 - -定义:`downloadCQImage($msg, $path = null)` - -参数 `$msg` 为带图片的用户消息,例如 `你好啊!\n[CQ:image,file=a.jpg,url=https://zhamao.xin/file/hello.jpg]` - -参数 `$path` 为图片下载的路径,如果不填(默认 null)则指定为 `zm_data/images/` 目录,且不存在会自动创建。 - -```php -$r = MessageUtil::downloadCQImage("你好啊!\n[CQ:image,file=a.jpg,url=https://zhamao.xin/file/hello.jpg]"); -/* -$r == [ - "/path-to/zhamao-framework/zm_data/images/a.jpg" -]; -*/ -``` - -如果返回的是空数组 `[ ]`,则表明消息中没有图片。如果返回的是 `false`,则表明其中至少一张下载失败或路径有误。 - -### containsImage() - -检查消息中是否含有图片。 - -定义:`containsImage($msg)` - -返回:`bool`,你懂的,true 就是有,false 就没有。 - -```php -MessageUtil::containsImage("[CQ:image,file=a.jpg,url=http://xxx]"); // true -MessageUtil::containsImage("[CQ:face,id=140] 咦,这是一条带表情的消息"); // false -``` - -### getImageCQFromLocal() - -通过文件路径获取图片的发送 CQ 码。 - -定义:`getImageCQFromLocal($file, $type = 0)` - -参数 `$file` 为图片的绝对路径。 - -返回:图片的 CQ 码,如 `[CQ:image,file=xxxxx]` - -参数 `$type`: - -- `0`:以 base64 的方式发送图片,返回结果如 `[CQ:image,file=base64://xxxxxx]` -- `1`:以 `file://` 本地文件的方式发送图片,返回结果如 `[CQ:image,file=file:///path-to/images/a.jpg]` -- `2`:返回图片的 http:// CQ 码(默认为 /images/ 路径就是文件对应所在的目录),如 `[CQ:image,file=http://127.0.0.1:20001/images/a.jpg]` - -### splitCommand() - -切割用户消息为数组形式(`@CQCommand` 就是使用此方式切割的) - -定义:`splitCommand($msg): array` - -返回:数组,切分后的。 - -!!! tip "为什么不直接使用 explode 呢" - - 因为 `explode()` 只会简单粗暴的切割字符串,假设用户输入的消息中两个词中间有多个空格,则会有空的词出现。例如 `你好 我是一个长空格`。此函数会将多个空格当作一个空格来对待。 - -```php -MessageUtil::splitCommand("你好 我是傻瓜\n我是傻瓜二号"); // ["你好","我是傻瓜","我是傻瓜二号"] -MessageUtil::splitCommand("我有 三个空格"); // ["我有","三个空格"] -``` - -### matchCommand() - -匹配一条消息到 `@CQCommand` 规则的注解事件,返回要执行的类和函数位置。 - -定义:`matchCommand($msg, $obj)` - -参数 `$msg` 为消息内容。 - -参数 `$obj` 为事件的对象,可使用 `ctx()->getData()` 获取原先的事件体(仅限 OneBot 消息类型事件中使用) - -返回:`\ZM\Entity\MatchObject` 对象,含有匹配成功与否,匹配到的注解对象,匹配到的分割词等,见 [] - diff --git a/docs/component/route-manager.md b/docs/component/route-manager.md deleted file mode 100644 index 698e125d..00000000 --- a/docs/component/route-manager.md +++ /dev/null @@ -1,54 +0,0 @@ -# HTTP 路由管理 - -HTTP 路由管理器用作管理炸毛框架内 `@RequestMapping` 和静态目录的路由操作的,可在运行过程中编写添加路由。 - -类定义:`\ZM\Http\RouteManager` - -> 2.3.0 版本起可用。 - -!!! warning "注意" - - 因为炸毛框架的路由实现是不基于跨进程的共享内存的,所以每次使用这里面的工具函数都需要单独在所有 Worker 进程中执行一次,最好的办法就是在启动框架时执行(`@OnStart(-1)` 即可,代表此注解事件将在每个工作进程中都被执行一次)。 - -## 方法 - -### importRouteByAnnotation() - -通过注解类导入路由。(注:此方法一般为框架内部使用) - -定义:`importRouteByAnnotation(RequestMapping $vss, $method, $class, $methods_annotations)` - -参数 `$vss`:RequestMapping 注解类,类中定义 `route` 和 `request_method` 即可。 - -参数 `$method, $class`:执行的目标注解事件函数位置,比如 `$class = \Module\Example\Hello::class`,`$method = 'hitokoto'`。 - -参数 `$methods_annotations`:需要绑定的 Controller 注解类数组,一般数组内建议只带有一个 Controller,如 `[$controller]`。 - -### addStaticFileRoute() - -添加一个单目录(此目录下无子目录,只有文件)并绑定为一个路由。 - -定义:`addStaticFileRoute($route, $path)` - -参数 `$route`:绑定的目标路由,如 `/images/`。 - -参数 `$path`:绑定的文件目录位置,如 `/root/zhamao-framework-starter/zm_data/images/`。 - -```php -/** - * @OnStart(-1) - */ -public function onStart() { - RouteManager::addStaticFileRoute("/images/", DataProvider::getDataFolder()."images/"); -} -``` - -## 属性 - -### RouteManager::$routes - -此为存放路由树的变量,请谨慎操作。 - -定义:`\Symfony\Component\Routing\RouteCollection | null` - -炸毛框架使用了 Symfony 框架的 route 组件,有关详情请查阅 [文档](https://symfony.com/doc/current/routing.html)。 \ No newline at end of file diff --git a/docs/component/task-worker.md b/docs/component/task-worker.md deleted file mode 100644 index 77c955b8..00000000 --- a/docs/component/task-worker.md +++ /dev/null @@ -1,26 +0,0 @@ -# TaskManager 工作进程管理 - -此类管理的是 TaskWorker 相关工作。有关使用 TaskWorker 的教程,见 [进阶 - 使用 TaskWorker 进程处理密集运算](/advanced/task-worker) - -类定义:`\ZM\Utils\TaskManager` - -使用 TaskWorker 需要先在 `global.php` 配置文件中开启! - -## 方法 - -### runTask() - -在 TaskWorker 运行任务。 - -定义:`runTask($task_name, $timeout = -1, ...$params)` - -参数 `$task_name`:对应 `@OnTask` 注解绑定的任务函数。 - -参数 `$timeout`:等待任务函数最长运行的时间(秒),如果超过此时间将返回 false。 - -参数 `剩余`:将变量传入 TaskWorker 进程,除 Closure,资源类型外,可序列化的变量均可。 - -```php -TaskManager::runTask("heavy_task", 100, "param1", "param2"); -``` - diff --git a/docs/component/zmutil.md b/docs/component/zmutil.md index 68f0d795..1ee6cb78 100644 --- a/docs/component/zmutil.md +++ b/docs/component/zmutil.md @@ -21,47 +21,3 @@ class ASD{ ZMUtil::getModInstance(ASD::class)->test = 5; ``` -## ZMUtil::getReloadableFiles() - -返回可通过热重启(reload)来重新加载的 php 文件列表。 - -以下是示例模块下的例子(直接拉取最新的框架源码并运行框架后获取的)。 - -```php -array:31 [ - 94 => "src/ZM/Context/Context.php" - 95 => "src/ZM/Context/ContextInterface.php" - 96 => "src/ZM/Annotation/AnnotationParser.php" - 97 => "src/Custom/Annotation/Example.php" - 98 => "src/ZM/Annotation/Interfaces/CustomAnnotation.php" - 99 => "src/Module/Example/Hello.php" - 100 => "src/ZM/Annotation/Swoole/OnStart.php" - 101 => "src/ZM/Annotation/CQ/CQCommand.php" - 102 => "src/ZM/Annotation/Interfaces/Level.php" - 103 => "src/ZM/Annotation/Command/TerminalCommand.php" - 104 => "src/ZM/Annotation/Http/RequestMapping.php" - 105 => "src/ZM/Annotation/Http/RequestMethod.php" - 106 => "src/ZM/Annotation/Http/Middleware.php" - 107 => "src/ZM/Annotation/Interfaces/ErgodicAnnotation.php" - 108 => "src/ZM/Annotation/Swoole/OnOpenEvent.php" - 109 => "src/ZM/Annotation/Swoole/OnSwooleEventBase.php" - 110 => "src/ZM/Annotation/Interfaces/Rule.php" - 111 => "src/ZM/Annotation/Swoole/OnCloseEvent.php" - 112 => "src/ZM/Annotation/Swoole/OnRequestEvent.php" - 113 => "src/ZM/Http/RouteManager.php" - 114 => "vendor/symfony/routing/RouteCollection.php" - 115 => "vendor/symfony/routing/Route.php" - 116 => "src/Module/Middleware/TimerMiddleware.php" - 117 => "src/ZM/Http/MiddlewareInterface.php" - 118 => "src/ZM/Annotation/Http/MiddlewareClass.php" - 119 => "src/ZM/Annotation/Http/HandleBefore.php" - 120 => "src/ZM/Annotation/Http/HandleAfter.php" - 121 => "src/ZM/Annotation/Http/HandleException.php" - 122 => "src/ZM/Event/EventManager.php" - 123 => "src/ZM/Annotation/Swoole/OnSwooleEvent.php" - 124 => "src/ZM/Event/EventDispatcher.php" -] -``` - -> 为什么不能重载所有文件?因为框架是多进程模型,而重载相当于只重新启动了一次 Worker 进程,Manager 和 Master 进程未重启,所以被 Manager、Master 进程已经加载的 PHP 文件无法使用 reload 命令重新加载。详见 [进阶 - 进程间隔离](/advanced/multi-process/#_5)。 - diff --git a/docs/event/framework-annotations.md b/docs/event/framework-annotations.md index db8e3bcc..874d227d 100644 --- a/docs/event/framework-annotations.md +++ b/docs/event/framework-annotations.md @@ -262,27 +262,6 @@ 无。 -## TerminalCommand() - -添加一个远程终端的自定义命令。(2.4.0 版本起可用) - -### 属性 - -| 类型 | 值 | -| ---------- | --------------------------------------- | -| 名称 | `@TerminalCommand` | -| 触发前提 | 连接到远程终端可触发 | -| 命名空间 | `ZM\Annotation\Command\TerminalCommand` | -| 适用位置 | 方法 | -| 返回值处理 | 无 | - -### 注解参数 - -| 参数名称 | 参数范围 | 默认 | -| ----------- | ------------------------------ | ---- | -| command | `string`,**必填**,命令字符串 | | -| description | `string`,要显示的帮助文本 | 空 | - ## 示例1(机器人连接框架后输出信息) ```php @@ -427,6 +406,3 @@ public function onCrawl() { } ``` -## 示例6(创建一个远程终端命令并调试框架) - -> 开个坑,以后填。(__填坑标记__) \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 28aee039..9c7613ef 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -72,12 +72,9 @@ nav: - 事件分发器: event/event-dispatcher.md - 框架组件: - 框架组件: component/index.md + - 机器人 API: component/robot-api.md + - CQ 码(多媒体消息): component/cqcode.md - 上下文: component/context.md - - 聊天机器人组件: - - 机器人 API: component/robot-api.md - - CQ 码(多媒体消息): component/cqcode.md - - 机器人消息处理: component/message-util.md - - Token 验证: component/access-token.md - 存储: - LightCache 轻量缓存: component/light-cache.md - MySQL 数据库: component/mysql.md @@ -85,15 +82,13 @@ nav: - ZMAtomic 原子计数器: component/atomics.md - SpinLock 自旋锁: component/spin-lock.md - 文件管理: component/data-provider.md - - HTTP 服务器工具类: - - HTTP 和 WebSocket 客户端: component/zmrequest.md - - HTTP 路由管理: component/route-manager.md - 协程池: component/coroutine-pool.md - 单例类: component/singleton-trait.md - ZMUtil 杂项: component/zmutil.md - 全局方法: component/global-functions.md + - HTTP 和 WebSocket 客户端: component/zmrequest.md - Console 终端: component/console.md - - TaskWorker 管理: component/task-worker.md + - Token 验证: component/access-token.md - 进阶开发: - 进阶开发: advanced/index.md - 框架剖析: advanced/framework-structure.md @@ -102,7 +97,6 @@ nav: - 内部类文件手册: advanced/inside-class.md - 接入 WebSocket 客户端: advanced/connect-ws-client.md - 框架多进程: advanced/multi-process.md - - TaskWorker 提高并发: advanced/task-worker.md - 开发实战教程: - 编写管理员才能触发的功能: advanced/example/admin.md - FAQ: FAQ.md diff --git a/src/Module/Example/Hello.php b/src/Module/Example/Hello.php index 52f3aa9e..5abf3a96 100644 --- a/src/Module/Example/Hello.php +++ b/src/Module/Example/Hello.php @@ -2,16 +2,10 @@ namespace Module\Example; -use ZM\Annotation\Command\TerminalCommand; -use ZM\Annotation\CQ\CQBefore; -use ZM\Annotation\CQ\CQMessage; use ZM\Annotation\Http\Middleware; use ZM\Annotation\Swoole\OnCloseEvent; use ZM\Annotation\Swoole\OnOpenEvent; use ZM\Annotation\Swoole\OnRequestEvent; -use ZM\Annotation\Swoole\OnStart; -use ZM\API\CQ; -use ZM\API\TuringAPI; use ZM\ConnectionManager\ConnectionObject; use ZM\Console\Console; use ZM\Annotation\CQ\CQCommand; @@ -19,7 +13,6 @@ use ZM\Annotation\Http\RequestMapping; use ZM\Event\EventDispatcher; use ZM\Exception\InterruptException; use ZM\Requests\ZMRequest; -use ZM\Utils\MessageUtil; use ZM\Utils\ZMUtil; /** @@ -29,12 +22,6 @@ use ZM\Utils\ZMUtil; */ class Hello { - /** - * @OnStart() - */ - public function onStart() { - } - /* * 默认的图片监听路由对应目录,如需要使用可取消下面的注释,把上面的 /* 换成 /** * @OnStart(-1) @@ -80,34 +67,6 @@ class Hello return $obj["hitokoto"] . "\n----「" . $obj["from"] . "」"; } - /** - * @CQCommand(start_with="机器人",end_with="机器人",message_type="group") - * @CQMessage(message_type="private",level=1) - */ - public function turingAPI() { - $user_id = ctx()->getUserId(); - $api = "83513e3d316f44de9c952cda4c9aed30"; // 请在这里填入你的图灵机器人的apikey - if ($api === "") return false; //如果没有填入apikey则此功能关闭 - if (($this->_running_annotation ?? null) instanceof CQCommand) { - $msg = ctx()->getFullArg("我在!有什么事吗?"); - } else { - $msg = ctx()->getMessage(); - } - zm_dump($msg); - return TuringAPI::getTuringMsg($msg, $user_id, $api); - } - - /** - * @CQBefore("message") - */ - public function changeAt() { - if (MessageUtil::isAtMe(ctx()->getMessage(), ctx()->getRobotId())) { - $msg = str_replace(CQ::at(ctx()->getRobotId()), "", ctx()->getMessage()); - ctx()->setMessage("机器人 ".$msg); - } - return true; - } - /** * 一个简单随机数的功能demo * 问法1:随机数 1 20 diff --git a/src/ZM/API/TuringAPI.php b/src/ZM/API/TuringAPI.php deleted file mode 100644 index ab5de163..00000000 --- a/src/ZM/API/TuringAPI.php +++ /dev/null @@ -1,118 +0,0 @@ - 0, - "userInfo" => [ - "apiKey" => $api, - "userId" => $user_id - ] - ]; - if ($msg != "") { - $content["perception"]["inputText"]["text"] = $msg; - } - $msg = trim($msg); - if (mb_strlen($msg) < 1 && !isset($url)) return "请说出你想说的话"; - if (isset($url)) { - $content["perception"]["inputImage"]["url"] = $url; - $content["reqType"] = 1; - } - if (!isset($content["perception"])) return "请说出你想说的话"; - $client = new Client("openapi.tuling123.com", 80); - $client->setHeaders(["Content-type" => "application/json"]); - $client->post("/openapi/api/v2", json_encode($content, JSON_UNESCAPED_UNICODE)); - $api_return = json_decode($client->body, true); - if (!isset($api_return["intent"]["code"])) return "XD 哎呀,我脑子突然短路了,请稍后再问我吧!"; - $status = self::getResultStatus($api_return); - if ($status !== true) { - if ($status == "err:输入文本内容超长(上限150)") return "你的话太多了!!!"; - if ($api_return["intent"]["code"] == 4003) { - return "哎呀,我刚才有点走神了,可能忘记你说什么了,可以重说一遍吗"; - } - Console::error("图灵机器人发送错误!\n错误原始内容:" . $origin . "\n来自:" . $user_id . "\n错误信息:" . $status); - //echo json_encode($r, 128|256); - return "哎呀,我刚才有点走神了,要不一会儿换一种问题试试?"; - } - $result = $api_return["results"]; - //Console::info(Console::setColor(json_encode($result, 128 | 256), "green")); - $final = ""; - foreach ($result as $k => $v) { - switch ($v["resultType"]) { - case "url": - $final .= "\n" . $v["values"]["url"]; - break; - case "text": - $final .= "\n" . $v["values"]["text"]; - break; - case "image": - $final .= "\n" . CQ::image($v["values"]["image"]); - break; - } - } - return trim($final); - } - - public static function getResultStatus($r) { - switch ($r["intent"]["code"]) { - case 5000: - return "err:无解析结果"; - case 4000: - case 6000: - return "err:暂不支持该功能"; - case 4001: - return "err:加密方式错误"; - case 4005: - case 4002: - return "err:无功能权限"; - case 4003: - return "err:该apikey没有可用请求次数"; - case 4007: - return "err:apikey不合法"; - case 4100: - return "err:userid获取失败"; - case 4200: - return "err:上传格式错误"; - case 4300: - return "err:批量操作超过限制"; - case 4400: - return "err:没有上传合法userid"; - case 4500: - return "err:userid申请个数超过限制"; - case 4600: - return "err:输入内容为空"; - case 4602: - return "err:输入文本内容超长(上限150)"; - case 7002: - return "err:上传信息失败"; - case 8008: - return "err:服务器错误"; - default: - return true; - } - } -} \ No newline at end of file diff --git a/src/ZM/Annotation/Command/TerminalCommand.php b/src/ZM/Annotation/Command/TerminalCommand.php deleted file mode 100644 index 30034cb8..00000000 --- a/src/ZM/Annotation/Command/TerminalCommand.php +++ /dev/null @@ -1,27 +0,0 @@ -daemon_file["pid"])); + system("kill -TERM " . intval($this->daemon_file["pid"])); unlink(DataProvider::getWorkingDir() . "/.daemon_pid"); $output->writeln("成功停止!"); return Command::SUCCESS; diff --git a/src/ZM/Command/RunServerCommand.php b/src/ZM/Command/RunServerCommand.php index 6d4b77c2..c5a93d6d 100644 --- a/src/ZM/Command/RunServerCommand.php +++ b/src/ZM/Command/RunServerCommand.php @@ -23,7 +23,6 @@ class RunServerCommand extends Command new InputOption("log-error", null, null, "调整消息等级到error (log-level=0)"), new InputOption("log-theme", null, InputOption::VALUE_REQUIRED, "改变终端的主题配色"), new InputOption("disable-console-input", null, null, "禁止终端输入内容 (废弃)"), - new InputOption("remote-terminal", null, null, "启用远程终端,配置使用global.php中的"), new InputOption("disable-coroutine", null, null, "关闭协程Hook"), new InputOption("daemon", null, null, "以守护进程的方式运行框架"), new InputOption("watch", null, null, "监听 src/ 目录的文件变化并热更新"), diff --git a/src/ZM/ConsoleApplication.php b/src/ZM/ConsoleApplication.php index bd0388ef..74fc50b9 100644 --- a/src/ZM/ConsoleApplication.php +++ b/src/ZM/ConsoleApplication.php @@ -18,8 +18,8 @@ use ZM\Utils\DataProvider; class ConsoleApplication extends Application { - const VERSION_ID = 397; - const VERSION = "2.3.4"; + const VERSION_ID = 398; + const VERSION = "2.3.5"; public function __construct(string $name = 'UNKNOWN') { define("ZM_VERSION_ID", self::VERSION_ID); @@ -100,7 +100,7 @@ class ConsoleApplication extends Application private function selfCheck(): bool { if (!extension_loaded("swoole")) die("Can not find swoole extension.\nSee: https://github.com/zhamao-robot/zhamao-framework/issues/19\n"); - if (version_compare(SWOOLE_VERSION, "4.5.0") == -1) die("You must install swoole version >= 4.5.0 !"); + if (version_compare(SWOOLE_VERSION, "4.4.13") == -1) die("You must install swoole version >= 4.4.13 !"); if (version_compare(PHP_VERSION, "7.2") == -1) die("PHP >= 7.2 required."); return true; } diff --git a/src/ZM/Entity/MatchResult.php b/src/ZM/Entity/MatchResult.php deleted file mode 100644 index d345f797..00000000 --- a/src/ZM/Entity/MatchResult.php +++ /dev/null @@ -1,17 +0,0 @@ -_running_annotation = $v; if ($this->log) Console::verbose("[事件分发{$this->eid}] 正在执行方法 " . $q_c . "::" . $q_f . " ..."); $this->store = $q_o->$q_f(...$params); } catch (Exception $e) { @@ -189,7 +188,6 @@ class EventDispatcher return false; } else { $q_o = ZMUtil::getModInstance($q_c); - $q_o->_running_annotation = $v; if ($this->log) Console::verbose("[事件分发{$this->eid}] 正在执行方法 " . $q_c . "::" . $q_f . " ..."); $this->store = $q_o->$q_f(...$params); $this->status = self::STATUS_NORMAL; diff --git a/src/ZM/Event/ServerEventHandler.php b/src/ZM/Event/ServerEventHandler.php index d0d766a1..1167e61c 100644 --- a/src/ZM/Event/ServerEventHandler.php +++ b/src/ZM/Event/ServerEventHandler.php @@ -17,13 +17,13 @@ use Swoole\Database\PDOConfig; use Swoole\Database\PDOPool; use Swoole\Event; use Swoole\Process; -use Swoole\Timer; use Throwable; use ZM\Annotation\AnnotationParser; use ZM\Annotation\Http\RequestMapping; use ZM\Annotation\Swoole\OnCloseEvent; use ZM\Annotation\Swoole\OnMessageEvent; use ZM\Annotation\Swoole\OnOpenEvent; +use ZM\Annotation\Swoole\OnPipeMessageEvent; use ZM\Annotation\Swoole\OnRequestEvent; use ZM\Annotation\Swoole\OnStart; use ZM\Annotation\Swoole\OnSwooleEvent; @@ -49,9 +49,9 @@ use ZM\Store\LightCache; use ZM\Store\LightCacheInside; use ZM\Store\MySQL\SqlPoolStorage; use ZM\Store\Redis\ZMRedisPool; +use ZM\Store\WorkerCache; use ZM\Utils\DataProvider; use ZM\Utils\HttpUtil; -use ZM\Utils\ProcessManager; use ZM\Utils\ZMUtil; class ServerEventHandler @@ -83,7 +83,7 @@ class ServerEventHandler Process::signal(SIGINT, function () use ($r) { if (zm_atomic("_int_is_reload")->get() === 1) { zm_atomic("_int_is_reload")->set(0); - \server()->reload(); + ZMUtil::reload(); } else { echo "\r"; Console::warning("Server interrupted(SIGINT) on Master."); @@ -133,25 +133,17 @@ class ServerEventHandler if ($worker_id == (ZMConfig::get("worker_cache")["worker"] ?? 0)) { LightCache::savePersistence(); } - Console::verbose(($server->taskworker ? "Task" : "") . "Worker #$worker_id 已停止"); + Console::debug(($server->taskworker ? "Task" : "") . "Worker #$worker_id 已停止"); } /** * @SwooleHandler("WorkerStart") * @param Server $server * @param $worker_id - * @throws Exception */ public function onWorkerStart(Server $server, $worker_id) { - zm_atomic("_#worker_".$worker_id)->set($server->worker_pid); //if (ZMBuf::atomic("stop_signal")->get() != 0) return; - Process::signal(SIGUSR1, function() use ($worker_id){ - Timer::clearAll(); - ProcessManager::resumeAllWorkerCoroutines(); - }); Process::signal(SIGINT, function () use ($worker_id, $server) { - Timer::clearAll(); - ProcessManager::resumeAllWorkerCoroutines(); Console::debug("正在关闭 " . ($server->taskworker ? "Task" : "") . "Worker 进程 " . Console::setColor("#" . \server()->worker_id, "gold") . TermColor::frontColor256(59) . ", pid=" . posix_getpid()); server()->stop($worker_id); }); @@ -480,6 +472,7 @@ class ServerEventHandler Console::error("Uncaught " . get_class($e) . " when calling \"open\": " . $error_msg); Console::trace(); } + //EventHandler::callSwooleEvent("open", $server, $request); } /** @@ -535,27 +528,70 @@ class ServerEventHandler * @param $src_worker_id * @param $data * @throws Exception - * @noinspection PhpUnusedParameterInspection */ public function onPipeMessage(Server $server, $src_worker_id, $data) { //var_dump($data, $server->worker_id); //unset(Context::$context[Co::getCid()]); $data = json_decode($data, true); - ProcessManager::workerAction($src_worker_id, $data); - } - - /** - * @SwooleHandler("beforeReload") - */ - public function onBeforeReload() { - for($i = 0; $i < ZM_WORKER_NUM; ++$i) { - $pid = zm_atomic("_#worker_".$i)->get(); - Process::kill($pid, SIGUSR1); + switch ($data["action"] ?? '') { + case "resume_ws_message": + $obj = $data["data"]; + Co::resume($obj["coroutine"]); + break; + case "getWorkerCache": + $r = WorkerCache::get($data["key"]); + $action = ["action" => "returnWorkerCache", "cid" => $data["cid"], "value" => $r]; + $server->sendMessage(json_encode($action, 256), $src_worker_id); + break; + case "setWorkerCache": + $r = WorkerCache::set($data["key"], $data["value"]); + $action = ["action" => "returnWorkerCache", "cid" => $data["cid"], "value" => $r]; + $server->sendMessage(json_encode($action, 256), $src_worker_id); + break; + case "unsetWorkerCache": + $r = WorkerCache::unset($data["key"]); + $action = ["action" => "returnWorkerCache", "cid" => $data["cid"], "value" => $r]; + $server->sendMessage(json_encode($action, 256), $src_worker_id); + break; + case "hasKeyWorkerCache": + $r = WorkerCache::hasKey($data["key"], $data["subkey"]); + $action = ["action" => "returnWorkerCache", "cid" => $data["cid"], "value" => $r]; + $server->sendMessage(json_encode($action, 256), $src_worker_id); + break; + case "asyncAddWorkerCache": + WorkerCache::add($data["key"], $data["value"], true); + break; + case "asyncSubWorkerCache": + WorkerCache::sub($data["key"], $data["value"], true); + break; + case "asyncSetWorkerCache": + WorkerCache::set($data["key"], $data["value"], true); + break; + case "asyncUnsetWorkerCache": + WorkerCache::unset($data["key"], true); + break; + case "addWorkerCache": + $r = WorkerCache::add($data["key"], $data["value"]); + $action = ["action" => "returnWorkerCache", "cid" => $data["cid"], "value" => $r]; + $server->sendMessage(json_encode($action, 256), $src_worker_id); + break; + case "subWorkerCache": + $r = WorkerCache::sub($data["key"], $data["value"]); + $action = ["action" => "returnWorkerCache", "cid" => $data["cid"], "value" => $r]; + $server->sendMessage(json_encode($action, 256), $src_worker_id); + break; + case "returnWorkerCache": + WorkerCache::$transfer[$data["cid"]] = $data["value"]; + zm_resume($data["cid"]); + break; + default: + $dispatcher = new EventDispatcher(OnPipeMessageEvent::class); + $dispatcher->setRuleFunction(function (OnPipeMessageEvent $v) use ($data) { + return $v->action == $data["action"]; + }); + $dispatcher->dispatchEvents($data); + break; } - - Console::info(Console::setColor("Reloading server...", "gold")); - usleep(800 * 1000); - LightCacheInside::unset("wait_api", "wait_api"); } /** diff --git a/src/ZM/Framework.php b/src/ZM/Framework.php index 1b349f37..c164aeb0 100644 --- a/src/ZM/Framework.php +++ b/src/ZM/Framework.php @@ -5,9 +5,7 @@ namespace ZM; use Doctrine\Common\Annotations\AnnotationReader; -use Error; use Exception; -use Swoole\Server\Port; use ZM\Annotation\Swoole\OnSetup; use ZM\Config\ZMConfig; use ZM\ConnectionManager\ManagerGM; @@ -25,7 +23,6 @@ use Swoole\Runtime; use Swoole\WebSocket\Server; use ZM\Annotation\Swoole\SwooleHandler; use ZM\Console\Console; -use ZM\Utils\Terminal; use ZM\Utils\ZMUtil; class Framework @@ -38,16 +35,11 @@ class Framework * @var Server */ public static $server; - /** - * @var string[] - */ - public static $loaded_files = []; /** * @var array|bool|mixed|null */ private $server_set; - /** @noinspection PhpUnusedParameterInspection */ public function __construct($args = []) { $tty_width = $this->getTtyWidth(); @@ -62,6 +54,7 @@ class Framework //定义常量 include_once "global_defines.php"; + ZMAtomic::init(); try { $sw = ZMConfig::get("global"); if (!is_dir($sw["zm_data"])) mkdir($sw["zm_data"]); @@ -89,17 +82,11 @@ class Framework ($o = ZMConfig::get("console_color")) === false ? [] : $o ); - $worker = ZMConfig::get("global", "swoole")["worker_num"] ?? swoole_cpu_num(); - define("ZM_WORKER_NUM", $worker); - ZMAtomic::init(); $timezone = ZMConfig::get("global", "timezone") ?? "Asia/Shanghai"; date_default_timezone_set($timezone); $this->server_set = ZMConfig::get("global", "swoole"); - $this->server_set["log_level"] = SWOOLE_LOG_DEBUG; - $add_port = ZMConfig::get("global", "modules")["remote_terminal"]["status"] ?? false; - - $this->parseCliArgs(self::$argv, $add_port); + $this->parseCliArgs(self::$argv); // 打印初始信息 $out["listen"] = ZMConfig::get("global", "host") . ":" . ZMConfig::get("global", "port"); @@ -127,82 +114,12 @@ class Framework $out["php_version"] = PHP_VERSION; $out["swoole_version"] = SWOOLE_VERSION; } - if ($add_port) { - $conf = ZMConfig::get("global", "modules")["remote_terminal"]; - $out["terminal"] = $conf["host"] . ":" . $conf["port"]; - } $out["working_dir"] = DataProvider::getWorkingDir(); self::printProps($out, $tty_width, $args["log-theme"] === null); self::$server = new Server(ZMConfig::get("global", "host"), ZMConfig::get("global", "port")); - if ($add_port) { - $welcome_msg = Console::setColor("Welcome! You can use `help` for usage.", "green"); - /** @var Port $port */ - $port = self::$server->listen("127.0.0.1", 20002, SWOOLE_SOCK_TCP); - $port->set([ - 'open_http_protocol' => false - ]); - $port->on('connect', function (?\Swoole\Server $serv, $fd) use ($port, $welcome_msg) { - ManagerGM::pushConnect($fd, "terminal"); - $serv->send($fd, file_get_contents(working_dir() . "/config/motd.txt")); - if (!empty(ZMConfig::get("global", "modules")["remote_terminal"]["token"] ?? '')) { - $serv->send($fd, "Please input token: "); - } else { - $serv->send($fd, $welcome_msg . "\n>>> "); - } - }); - - $port->on('receive', function ($serv, $fd, $reactor_id, $data) use ($welcome_msg) { - ob_start(); - try { - $arr = LightCacheInside::get("light_array", "input_token") ?? []; - if (empty($arr[$fd] ?? '')) { - if (ZMConfig::get("global", "modules")["remote_terminal"]["token"] != '') { - $token = trim($data); - if ($token === ZMConfig::get("global", "modules")["remote_terminal"]["token"]) { - SpinLock::transaction("input_token", function () use ($fd, $token) { - $arr = LightCacheInside::get("light_array", "input_token"); - $arr[$fd] = $token; - LightCacheInside::set("light_array", "input_token", $arr); - }); - $serv->send($fd, Console::setColor("Auth success!!\n", "green")); - $serv->send($fd, $welcome_msg . "\n>>> "); - } else { - $serv->send($fd, Console::setColor("Auth failed!!\n", "red")); - $serv->close($fd); - } - return; - } - } - if (trim($data) == "exit" || trim($data) == "q") { - $serv->send($fd, Console::setColor("Bye!\n", "blue")); - $serv->close($fd); - return; - } - Terminal::executeCommand(trim($data)); - } catch (Exception $e) { - $error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")"; - Console::error("Uncaught exception " . get_class($e) . " when calling \"open\": " . $error_msg); - Console::trace(); - } catch (Error $e) { - $error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")"; - Console::error("Uncaught " . get_class($e) . " when calling \"open\": " . $error_msg); - Console::trace(); - } - - $r = ob_get_clean(); - if (!empty($r)) $serv->send($fd, $r); - if (!in_array(trim($data), ['r', 'reload', 'stop'])) $serv->send($fd, ">>> "); - }); - - $port->on('close', function ($serv, $fd) { - ManagerGM::popConnect($fd); - //echo "Client: Close.\n"; - }); - } - self::$server->set($this->server_set); Console::setServer(self::$server); self::printMotd($tty_width); @@ -278,9 +195,9 @@ class Framework } public function start() { - self::$loaded_files = get_included_files(); self::$server->start(); zm_atomic("server_is_stopped")->set(1); + Console::setLevel(0); } /** @@ -326,9 +243,9 @@ class Framework /** * 解析命令行的 $argv 参数们 * @param $args - * @param $add_port + * @throws Exception */ - private function parseCliArgs($args, &$add_port) { + private function parseCliArgs($args) { $coroutine_mode = true; global $terminal_id; $terminal_id = uuidgen(); @@ -379,9 +296,6 @@ class Framework Console::$theme = $y; } break; - case 'remote-terminal': - $add_port = true; - break; case 'show-php-ver': default: //Console::info("Calculating ".$x); @@ -390,7 +304,6 @@ class Framework } } if ($coroutine_mode) Runtime::enableCoroutine(true, SWOOLE_HOOK_ALL); - else Runtime::enableCoroutine(false, SWOOLE_HOOK_ALL); } private static function writeNoDouble($k, $v, &$line_data, &$line_width, &$current_line, $colorful, $max_border) { diff --git a/src/ZM/Module/QQBot.php b/src/ZM/Module/QQBot.php index 9fbd9721..be54c454 100644 --- a/src/ZM/Module/QQBot.php +++ b/src/ZM/Module/QQBot.php @@ -15,7 +15,6 @@ use ZM\Event\EventDispatcher; use ZM\Exception\InterruptException; use ZM\Exception\WaitTimeoutException; use ZM\Utils\CoMessage; -use ZM\Utils\MessageUtil; /** * Class QQBot @@ -77,19 +76,58 @@ class QQBot //Console::warning("最xia数据包:".json_encode($data)); switch ($data["post_type"]) { case "message": + $word = explodeMsg(str_replace("\r", "", context()->getMessage())); + if (empty($word)) $word = [""]; + if (count(explode("\n", $word[0])) >= 2) { + $enter = explode("\n", context()->getMessage()); + $first = split_explode(" ", array_shift($enter)); + $word = array_merge($first, $enter); + foreach ($word as $k => $v) { + $word[$k] = trim($word[$k]); + } + } //分发CQCommand事件 $dispatcher = new EventDispatcher(CQCommand::class); + $dispatcher->setRuleFunction(function (CQCommand $v) use ($word) { + if (array_diff([$v->match, $v->pattern, $v->regex, $v->keyword, $v->end_with, $v->start_with], [""]) == []) return false; + elseif (($v->user_id == 0 || ($v->user_id != 0 && $v->user_id == ctx()->getUserId())) && + ($v->group_id == 0 || ($v->group_id != 0 && $v->group_id == (ctx()->getGroupId() ?? 0))) && + ($v->message_type == '' || ($v->message_type != '' && $v->message_type == ctx()->getMessageType())) + ) { + if (($word[0] != "" && $v->match == $word[0]) || in_array($word[0], $v->alias)) { + array_shift($word); + ctx()->setCache("match", $word); + return true; + } elseif ($v->start_with != "" && mb_strpos(ctx()->getMessage(), $v->start_with) === 0) { + ctx()->setCache("match", [mb_substr(ctx()->getMessage(), mb_strlen($v->start_with))]); + return true; + } elseif ($v->end_with != "" && strlen(ctx()->getMessage()) == (strripos(ctx()->getMessage(), $v->end_with) + strlen($v->end_with))) { + ctx()->setCache("match", [substr(ctx()->getMessage(), 0, strripos(ctx()->getMessage(), $v->end_with))]); + return true; + } elseif ($v->keyword != "" && mb_strpos(ctx()->getMessage(), $v->keyword) !== false) { + ctx()->setCache("match", explode($v->keyword, ctx()->getMessage())); + return true; + } elseif ($v->pattern != "") { + $match = matchArgs($v->pattern, ctx()->getMessage()); + if ($match !== false) { + ctx()->setCache("match", $match); + return true; + } + } elseif ($v->regex != "") { + if (preg_match("/" . $v->regex . "/u", ctx()->getMessage(), $word2) != 0) { + ctx()->setCache("match", $word2); + return true; + } + } + } + return false; + }); $dispatcher->setReturnFunction(function ($result) { if (is_string($result)) ctx()->reply($result); if (ctx()->getCache("has_reply") === true) EventDispatcher::interrupt(); }); - $s = MessageUtil::matchCommand(ctx()->getMessage(), ctx()->getData()); - if ($s->status !== false) { - if (!empty($s->match)) ctx()->setCache("match", $s->match); - $dispatcher->dispatchEvent($s->object, null); - if (is_string($dispatcher->store)) ctx()->reply($dispatcher->store); - if (ctx()->getCache("has_reply") === true) EventDispatcher::interrupt(); - } + $dispatcher->dispatchEvents(); + if ($dispatcher->status == EventDispatcher::STATUS_INTERRUPTED) EventDispatcher::interrupt(); //分发CQMessage事件 $msg_dispatcher = new EventDispatcher(CQMessage::class); diff --git a/src/ZM/Store/LightCache.php b/src/ZM/Store/LightCache.php index b88ca3dd..060cc0cf 100644 --- a/src/ZM/Store/LightCache.php +++ b/src/ZM/Store/LightCache.php @@ -7,6 +7,7 @@ namespace ZM\Store; use Exception; use Swoole\Table; use ZM\Annotation\Swoole\OnSave; +use ZM\Config\ZMConfig; use ZM\Console\Console; use ZM\Event\EventDispatcher; use ZM\Exception\ZMException; @@ -181,12 +182,17 @@ class LightCache } /** - * 这个只能在唯一一个工作进程中执行 + * @param false $only_worker * @throws Exception */ - public static function savePersistence() { - $dispatcher = new EventDispatcher(OnSave::class); - $dispatcher->dispatchEvents(); + public static function savePersistence($only_worker = false) { + // 下面将OnSave激活一下 + if (server()->worker_id == (ZMConfig::get("global", "worker_cache")["worker"] ?? 0)) { + $dispatcher = new EventDispatcher(OnSave::class); + $dispatcher->dispatchEvents(); + } + + if($only_worker) return; if (self::$kv_table === null) return; $r = []; @@ -201,7 +207,8 @@ class LightCache $r = file_put_contents(self::$config["persistence_path"], json_encode($r, 128 | 256)); if ($r === false) Console::error("Not saved, please check your \"persistence_path\"!"); } - Console::verbose("Saved."); + + } private static function checkExpire($key) { diff --git a/src/ZM/Store/LightCacheInside.php b/src/ZM/Store/LightCacheInside.php index 92c3ab38..b9bcc81a 100644 --- a/src/ZM/Store/LightCacheInside.php +++ b/src/ZM/Store/LightCacheInside.php @@ -18,7 +18,6 @@ class LightCacheInside self::createTable("wait_api", 3, 65536); self::createTable("connect", 3, 64); //用于存单机器人模式下的机器人fd的 self::createTable("static_route", 64, 256);//用于存储 - self::createTable("light_array", 8, 512, 0.6); } catch (ZMException $e) { return false; } //用于存协程等待的状态内容的 @@ -60,11 +59,10 @@ class LightCacheInside * @param $name * @param $size * @param $str_size - * @param int $conflict_proportion * @throws ZMException */ - private static function createTable($name, $size, $str_size, $conflict_proportion = 0) { - self::$kv_table[$name] = new Table($size, $conflict_proportion); + private static function createTable($name, $size, $str_size) { + self::$kv_table[$name] = new Table($size, 0); self::$kv_table[$name]->column("value", Table::TYPE_STRING, $str_size); $r = self::$kv_table[$name]->create(); if ($r === false) throw new ZMException("内存不足,创建静态表失败!"); diff --git a/src/ZM/Store/ZMAtomic.php b/src/ZM/Store/ZMAtomic.php index c1c8bed3..c2cb72a2 100644 --- a/src/ZM/Store/ZMAtomic.php +++ b/src/ZM/Store/ZMAtomic.php @@ -32,9 +32,6 @@ class ZMAtomic self::$atomics["wait_msg_id"] = new Atomic(0); self::$atomics["_event_id"] = new Atomic(0); self::$atomics["server_is_stopped"] = new Atomic(0); - for($i = 0; $i < ZM_WORKER_NUM; ++$i) { - self::$atomics["_#worker_".$i] = new Atomic(0); - } for ($i = 0; $i < 10; ++$i) { self::$atomics["_tmp_" . $i] = new Atomic(0); } diff --git a/src/ZM/Utils/MessageUtil.php b/src/ZM/Utils/MessageUtil.php index 79b48dff..1396d703 100644 --- a/src/ZM/Utils/MessageUtil.php +++ b/src/ZM/Utils/MessageUtil.php @@ -4,13 +4,9 @@ namespace ZM\Utils; -use ZM\Annotation\CQ\CQCommand; use ZM\API\CQ; use ZM\Config\ZMConfig; use ZM\Console\Console; -use ZM\Entity\MatchResult; -use ZM\Event\EventDispatcher; -use ZM\Event\EventManager; use ZM\Requests\ZMRequest; class MessageUtil @@ -59,10 +55,6 @@ class MessageUtil return false; } - public static function isAtMe($msg, $me_id) { - return strpos($msg, CQ::at($me_id)) !== false; - } - /** * 通过本地地址返回图片的 CQ 码 * type == 0 : 返回图片的 base64 CQ 码 @@ -84,80 +76,4 @@ class MessageUtil } return ""; } - - /** - * 分割字符,将用户消息通过空格或换行分割为数组 - * @param $msg - * @return array|string[] - */ - public static function splitCommand($msg) { - $word = explodeMsg(str_replace("\r", "", $msg)); - if (empty($word)) $word = [""]; - if (count(explode("\n", $word[0])) >= 2) { - $enter = explode("\n", $msg); - $first = split_explode(" ", array_shift($enter)); - $word = array_merge($first, $enter); - foreach ($word as $k => $v) { - $word[$k] = trim($word[$k]); - } - } - return $word; - } - - /** - * @param $msg - * @param $obj - * @return MatchResult - */ - public static function matchCommand($msg, $obj) { - $ls = EventManager::$events[CQCommand::class]; - $word = self::splitCommand($msg); - $matched = new MatchResult(); - foreach ($ls as $k => $v) { - if (array_diff([$v->match, $v->pattern, $v->regex, $v->keyword, $v->end_with, $v->start_with], [""]) == []) continue; - elseif (($v->user_id == 0 || ($v->user_id != 0 && $v->user_id == $obj["user_id"])) && - ($v->group_id == 0 || ($v->group_id != 0 && $v->group_id == ($obj["group_id"] ?? 0))) && - ($v->message_type == '' || ($v->message_type != '' && $v->message_type == $obj["message_type"])) - ) { - if (($word[0] != "" && $v->match == $word[0]) || in_array($word[0], $v->alias)) { - array_shift($word); - $matched->match = $word; - $matched->object = $v; - $matched->status = true; - break; - } elseif ($v->start_with != "" && mb_strpos($msg, $v->start_with) === 0) { - $matched->match = [mb_substr($msg, mb_strlen($v->start_with))]; - $matched->object = $v; - $matched->status = true; - break; - } elseif ($v->end_with != "" && strlen($msg) == (strripos($msg, $v->end_with) + strlen($v->end_with))) { - $matched->match = [substr($msg, 0, strripos($msg, $v->end_with))]; - $matched->object = $v; - $matched->status = true; - break; - } elseif ($v->keyword != "" && mb_strpos($msg, $v->keyword) !== false) { - $matched->match = explode($v->keyword, $msg); - $matched->object = $v; - $matched->status = true; - break; - } elseif ($v->pattern != "") { - $match = matchArgs($v->pattern, $msg); - if ($match !== false) { - $matched->match = $match; - $matched->object = $v; - $matched->status = true; - break; - } - } elseif ($v->regex != "") { - if (preg_match("/" . $v->regex . "/u", $msg, $word2) != 0) { - $matched->match = $word2; - $matched->object = $v; - $matched->status = true; - break; - } - } - } - } - return $matched; - } } \ No newline at end of file diff --git a/src/ZM/Utils/ProcessManager.php b/src/ZM/Utils/ProcessManager.php index 973f3d43..83b65ac5 100644 --- a/src/ZM/Utils/ProcessManager.php +++ b/src/ZM/Utils/ProcessManager.php @@ -4,110 +4,14 @@ namespace ZM\Utils; -use Co; -use ZM\Annotation\Swoole\OnPipeMessageEvent; -use ZM\Console\Console; -use ZM\Event\EventDispatcher; -use ZM\Store\LightCache; -use ZM\Store\LightCacheInside; -use ZM\Store\WorkerCache; - class ProcessManager { - public static function workerAction($src_worker_id, $data) { - $server = server(); - switch ($data["action"] ?? '') { - case "eval": - eval($data["data"]); - break; - case "call_static": - call_user_func_array([$data["data"]["class"], $data["data"]["method"]], $data["data"]["params"]); - break; - case "save_persistence": - LightCache::savePersistence(); - break; - case "resume_ws_message": - $obj = $data["data"]; - Co::resume($obj["coroutine"]); - break; - case "getWorkerCache": - $r = WorkerCache::get($data["key"]); - $action = ["action" => "returnWorkerCache", "cid" => $data["cid"], "value" => $r]; - $server->sendMessage(json_encode($action, 256), $src_worker_id); - break; - case "setWorkerCache": - $r = WorkerCache::set($data["key"], $data["value"]); - $action = ["action" => "returnWorkerCache", "cid" => $data["cid"], "value" => $r]; - $server->sendMessage(json_encode($action, 256), $src_worker_id); - break; - case "unsetWorkerCache": - $r = WorkerCache::unset($data["key"]); - $action = ["action" => "returnWorkerCache", "cid" => $data["cid"], "value" => $r]; - $server->sendMessage(json_encode($action, 256), $src_worker_id); - break; - case "hasKeyWorkerCache": - $r = WorkerCache::hasKey($data["key"], $data["subkey"]); - $action = ["action" => "returnWorkerCache", "cid" => $data["cid"], "value" => $r]; - $server->sendMessage(json_encode($action, 256), $src_worker_id); - break; - case "asyncAddWorkerCache": - WorkerCache::add($data["key"], $data["value"], true); - break; - case "asyncSubWorkerCache": - WorkerCache::sub($data["key"], $data["value"], true); - break; - case "asyncSetWorkerCache": - WorkerCache::set($data["key"], $data["value"], true); - break; - case "asyncUnsetWorkerCache": - WorkerCache::unset($data["key"], true); - break; - case "addWorkerCache": - $r = WorkerCache::add($data["key"], $data["value"]); - $action = ["action" => "returnWorkerCache", "cid" => $data["cid"], "value" => $r]; - $server->sendMessage(json_encode($action, 256), $src_worker_id); - break; - case "subWorkerCache": - $r = WorkerCache::sub($data["key"], $data["value"]); - $action = ["action" => "returnWorkerCache", "cid" => $data["cid"], "value" => $r]; - $server->sendMessage(json_encode($action, 256), $src_worker_id); - break; - case "returnWorkerCache": - WorkerCache::$transfer[$data["cid"]] = $data["value"]; - zm_resume($data["cid"]); - break; - default: - $dispatcher = new EventDispatcher(OnPipeMessageEvent::class); - $dispatcher->setRuleFunction(function (OnPipeMessageEvent $v) use ($data) { - return $v->action == $data["action"]; - }); - $dispatcher->dispatchEvents($data); - break; - } - } - - public static function sendActionToWorker($worker_id, $action, $data) { - $obj = ["action" => $action, "data" => $data]; - if (server()->worker_id === -1 && server()->getManagerPid() != posix_getpid()) { - Console::warning("Cannot send worker action from master or manager process!"); - return; - } - if (server()->worker_id == $worker_id) { - self::workerAction($worker_id, $obj); - } else { - server()->sendMessage(json_encode($obj), $worker_id); - } - } - - public static function resumeAllWorkerCoroutines() { - if (server()->worker_id === -1) { - Console::warning("Cannot call '".__FUNCTION__."' in non-worker process!"); - return; - } - foreach ((LightCacheInside::get("wait_api", "wait_api") ?? []) as $k => $v) { - if (($v["result"] ?? false) === null && isset($v["coroutine"], $v["worker_id"])) { - if (server()->worker_id == $v["worker_id"]) Co::resume($v["coroutine"]); - } - } + public static function runOnTask($param, $timeout = 0.5, $dst_worker_id = -1) { + return server()->taskwait([ + "action" => "runMethod", + "class" => $param["class"], + "method" => $param["method"], + "params" => $param["params"] + ], $timeout, $dst_worker_id); } } \ No newline at end of file diff --git a/src/ZM/Utils/Terminal.php b/src/ZM/Utils/Terminal.php index f1eb1054..fc01cc82 100644 --- a/src/ZM/Utils/Terminal.php +++ b/src/ZM/Utils/Terminal.php @@ -6,38 +6,22 @@ namespace ZM\Utils; use Exception; use Psy\Shell; -use ZM\Annotation\Command\TerminalCommand; -use ZM\ConnectionManager\ManagerGM; +use Swoole\Event; use ZM\Console\Console; -use ZM\Event\EventDispatcher; -use ZM\Event\EventManager; use ZM\Framework; class Terminal { /** * @param string $cmd + * @param $resource * @return bool * @noinspection PhpMissingReturnTypeInspection * @noinspection PhpUnused - * @throws Exception */ - public static function executeCommand(string $cmd) { + public static function executeCommand(string $cmd, $resource) { $it = explodeMsg($cmd); switch ($it[0] ?? '') { - case 'help': - $help[] = "exit | q:\t断开远程终端"; - $help[] = "logtest:\t输出所有可以打印的log等级示例消息,用于测试Console"; - $help[] = "call:\t\t用于执行不需要参数的动态函数,比如 `call \Module\Example\Hello hitokoto`"; - $help[] = "level:\t\t设置log等级,例如 `level 0|1|2|3|4`"; - $help[] = "bc:\t\teval执行代码,但输入必须是将代码base64之后的,如 `bc em1faW5mbygn5L2g5aW9Jyk7`"; - $help[] = "stop:\t\t停止服务器"; - $help[] = "reload | r:\t热重启用户编写的模块代码"; - foreach(EventManager::$events[TerminalCommand::class] as $v) { - $help[]=$v->command.":\t\t".(empty($v->description) ? "<用户自定义指令>" : $v->description); - } - echo implode("\n", $help) . PHP_EOL; - return true; case 'logtest': Console::log(date("[H:i:s]") . " [L] This is normal msg. (0)"); Console::error("This is error msg. (0)"); @@ -51,8 +35,7 @@ class Terminal $class_name = $it[1]; $function_name = $it[2]; $class = new $class_name([]); - $r = $class->$function_name(); - if (is_string($r)) Console::success($r); + $class->$function_name(); return true; case 'psysh': if (Framework::$argv["disable-coroutine"]) { @@ -60,11 +43,6 @@ class Terminal } else Console::error("Only \"--disable-coroutine\" mode can use psysh!!!"); return true; - case 'level': - $level = intval(is_numeric($it[1] ?? 99) ? ($it[1] ?? 99) : 99); - if ($level > 4 || $level < 0) Console::warning("Usage: 'level 0|1|2|3|4'"); - else Console::setLevel($level) || Console::success("Success!!"); - break; case 'bc': $code = base64_decode($it[1] ?? '', true); try { @@ -79,6 +57,7 @@ class Terminal Console::log($it[2], $it[1]); return true; case 'stop': + Event::del($resource); ZMUtil::stop(); return false; case 'reload': @@ -88,35 +67,8 @@ class Terminal case '': return true; default: - $dispatcher = new EventDispatcher(TerminalCommand::class); - $dispatcher->setRuleFunction(function ($v) use ($it) { - /** @var TerminalCommand $v */ - return $v->command == $it[0]; - }); - $dispatcher->setReturnFunction(function () { - EventDispatcher::interrupt('none'); - }); - $dispatcher->dispatchEvents($it); - if ($dispatcher->store !== 'none') { - Console::info("Command not found: " . $cmd); - return true; - } - } - return false; - } - - public static function log($type, $log_msg) { - ob_start(); - if (!in_array($type, ["log", "info", "debug", "success", "warning", "error", "verbose"])) { - ob_get_clean(); - return; - } - Console::$type($log_msg); - $r = ob_get_clean(); - $all = ManagerGM::getAllByName("terminal"); - foreach ($all as $k => $v) { - server()->send($v->getFd(), "\r" . $r); - server()->send($v->getFd(), ">>> "); + Console::info("Command not found: " . $cmd); + return true; } } } diff --git a/src/ZM/Utils/ZMUtil.php b/src/ZM/Utils/ZMUtil.php index dc891515..0efc014b 100644 --- a/src/ZM/Utils/ZMUtil.php +++ b/src/ZM/Utils/ZMUtil.php @@ -4,10 +4,13 @@ namespace ZM\Utils; +use Co; use Exception; -use Swoole\Process; +use Swoole\Event; +use Swoole\Timer; use ZM\Console\Console; -use ZM\Framework; +use ZM\Store\LightCache; +use ZM\Store\LightCacheInside; use ZM\Store\Lock\SpinLock; use ZM\Store\ZMAtomic; use ZM\Store\ZMBuf; @@ -21,20 +24,39 @@ class ZMUtil if (SpinLock::tryLock("_stop_signal") === false) return; Console::warning(Console::setColor("Stopping server...", "red")); if (Console::getLevel() >= 4) Console::trace(); + LightCache::savePersistence(); + if (ZMBuf::$terminal !== null) + Event::del(ZMBuf::$terminal); ZMAtomic::get("stop_signal")->set(1); - for($i = 0; $i < ZM_WORKER_NUM; ++$i) { - Process::kill(zm_atomic("_#worker_".$i)->get(), SIGUSR1); + try { + LightCache::set('stop', 'OK'); + } catch (Exception $e) { } server()->shutdown(); server()->stop(); } /** + * @param int $delay * @throws Exception */ - public static function reload() { - zm_atomic("_int_is_reload")->set(1); - system("kill -INT " . intval(server()->master_pid)); + public static function reload($delay = 800) { + if (server()->worker_id !== -1) { + Console::info(server()->worker_id); + zm_atomic("_int_is_reload")->set(1); + system("kill -INT " . intval(server()->master_pid)); + return; + } + Console::info(Console::setColor("Reloading server...", "gold")); + usleep($delay * 1000); + foreach ((LightCacheInside::get("wait_api", "wait_api") ?? []) as $k => $v) { + if (($v["result"] ?? false) === null && isset($v["coroutine"])) Co::resume($v["coroutine"]); + } + LightCacheInside::unset("wait_api", "wait_api"); + LightCache::savePersistence(); + //DataProvider::saveBuffer(); + Timer::clearAll(); + server()->reload(); } public static function getModInstance($class) { @@ -47,22 +69,6 @@ class ZMUtil } public static function sendActionToWorker($target_id, $action, $data) { - Console::verbose($action . ": " . $data); server()->sendMessage(json_encode(["action" => $action, "data" => $data]), $target_id); } - - /** - * 在工作进程中返回可以通过reload重新加载的php文件列表 - * @return string[]|string[][] - */ - public static function getReloadableFiles() { - return array_map( - function ($x) { - return str_replace(DataProvider::getWorkingDir() . "/", "", $x); - }, array_diff( - get_included_files(), - Framework::$loaded_files - ) - ); - } } diff --git a/src/ZM/global_functions.php b/src/ZM/global_functions.php index 9b38f3cf..14e790dd 100644 --- a/src/ZM/global_functions.php +++ b/src/ZM/global_functions.php @@ -3,7 +3,6 @@ use Swoole\Atomic; use Swoole\Coroutine; use Swoole\WebSocket\Server; -use Symfony\Component\VarDumper\VarDumper; use ZM\API\ZMRobot; use ZM\Config\ZMConfig; use ZM\ConnectionManager\ManagerGM; @@ -244,6 +243,8 @@ function ctx(): ?ContextInterface { } } +function zm_debug($msg) { Console::debug($msg); } + function onebot_target_id_name($message_type): string { return ($message_type == "group" ? "group_id" : "user_id"); } @@ -254,21 +255,13 @@ function zm_sleep($s = 1): bool { return true; } -function zm_exec($cmd): array { - return System::exec($cmd); -} +function zm_exec($cmd): array { return System::exec($cmd); } -function zm_cid() { - return Co::getCid(); -} +function zm_cid() { return Co::getCid(); } -function zm_yield() { - Co::yield(); -} +function zm_yield() { Co::yield(); } -function zm_resume(int $cid) { - Co::resume($cid); -} +function zm_resume(int $cid) { Co::resume($cid); } function zm_timer_after($ms, callable $callable) { Swoole\Timer::after($ms, function () use ($callable) { @@ -294,14 +287,10 @@ function zm_timer_tick($ms, callable $callable) { if (zm_cid() === -1) { return go(function () use ($ms, $callable) { Console::debug("Adding extra timer tick of " . $ms . " ms"); - Swoole\Timer::tick($ms, function () use ($callable) { - call_with_catch($callable); - }); + Swoole\Timer::tick($ms, function () use ($callable) {call_with_catch($callable);}); }); } else { - return Swoole\Timer::tick($ms, function () use ($callable) { - call_with_catch($callable); - }); + return Swoole\Timer::tick($ms, function () use ($callable) {call_with_catch($callable);}); } } @@ -365,32 +354,3 @@ function working_dir() { elseif (LOAD_MODE == 2) return realpath('.'); return null; } - -/** @noinspection PhpMissingReturnTypeInspection */ -function zm_dump($var, ...$moreVars) { - VarDumper::dump($var); - - foreach ($moreVars as $v) { - VarDumper::dump($v); - } - - if (1 < func_num_args()) { - return func_get_args(); - } - - return $var; -} - -function zm_info($obj) { Console::info($obj); } - -function zm_warning($obj) { Console::warning($obj); } - -function zm_success($obj) { Console::success($obj); } - -function zm_debug($obj) { Console::debug($obj); } - -function zm_verbose($obj) { Console::verbose($obj); } - -function zm_error($obj) { Console::error($obj); } - -function zm_config($name, $key = null) { return ZMConfig::get($name, $key); }