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 3e28f407..00000000
Binary files a/docs/assets/img/image-20210321193956832.png and /dev/null differ
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);
-```
-
-
-
-## 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); }