mirror of
https://github.com/zhamao-robot/zhamao-framework.git
synced 2026-03-17 20:54:52 +08:00
update to 2.4.4 version (build 405)
change requirements: add pcntl as required extension update docs
This commit is contained in:
parent
d72b41a902
commit
77e77e9cc3
@ -23,6 +23,7 @@
|
||||
"php": ">=7.2",
|
||||
"ext-json": "*",
|
||||
"ext-posix": "*",
|
||||
"ext-pcntl": "*",
|
||||
"doctrine/annotations": "~1.10",
|
||||
"psy/psysh": "@stable",
|
||||
"symfony/polyfill-ctype": "^1.20",
|
||||
|
||||
54
docs/FAQ.md
54
docs/FAQ.md
@ -1,54 +0,0 @@
|
||||
# FAQ
|
||||
|
||||
这里会写一些常见的疑难解答。
|
||||
|
||||
## 启动时报错 Address already in use
|
||||
|
||||
1. 检查是否开启了两次框架,每个端口只能开启一个框架。
|
||||
2. 如果是之前已经在 20001 端口或者你设置了别的应用同样占用此端口,更换配置文件 `global.php` 中的 port 即可。
|
||||
3. 如果是之前框架成功启动,但是使用 Ctrl+C 停止后再次启动导致的报错,请根据下面的步骤来检查是否存在僵尸进程。
|
||||
|
||||
- 如果系统内装有 `htop`,可以直接在 `htop` 中开启 Tree 模式并使用 filter 过滤 php,检查残留的框架进程。
|
||||
- 如果系统没有 `htop`,使用 `ps aux | grep vendor/bin/start | grep -v grep` 如果存在进程,请使用以下命令尝试杀掉:
|
||||
|
||||
```bash
|
||||
# 如果确定框架的数据都已保存且没有需要保存的缓存数据,直接杀掉 SIGKILL 即可,输入下面这条
|
||||
ps aux | grep vendor/bin/start | grep -v grep | awk '{print $2}' | xargs kill -9
|
||||
|
||||
# 如果不确定框架是不是还继续运行,想尝试正常关闭(走一遍储存保存数据的事件),使用下面这条
|
||||
# 首先使用 'ps aux | grep vendor/bin/start | grep -v grep' 找到进程中第二列最小的pid
|
||||
# 然后使用下面的这条命令,假设最小的pid是23643
|
||||
kill -INT 23643
|
||||
# 如果使用 ps aux 看不到框架相关进程,证明关闭成功,否则需要使用第一条强行杀死
|
||||
```
|
||||
|
||||
## 出现 deadlock 字样
|
||||
|
||||
一般情况下,如果误操作框架可能会报如下图的错误:
|
||||
|
||||
```
|
||||
===================================================================
|
||||
[FATAL ERROR]: all coroutines (count: 1) are asleep - deadlock!
|
||||
===================================================================
|
||||
|
||||
[Coroutine-1]
|
||||
--------------------------------------------------------------------
|
||||
#0 Swoole\Coroutine\System::sleep() called at [/Users/jerry/project/git-project/zhamao-framework/src/ZM/global_functions.php:232]
|
||||
#1 zm_sleep() called at [/Users/jerry/project/git-project/zhamao-framework/src/Module/Example/Hello.php:38]
|
||||
#2 Module\Example\Hello->onStart() called at [/Users/jerry/project/git-project/zhamao-framework/src/ZM/Event/EventDispatcher.php:205]
|
||||
#3 ZM\Event\EventDispatcher->dispatchEvent() called at [/Users/jerry/project/git-project/zhamao-framework/src/ZM/Event/EventDispatcher.php:89]
|
||||
#4 ZM\Event\EventDispatcher->dispatchEvents() called at [/Users/jerry/project/git-project/zhamao-framework/src/ZM/Event/SwooleEvent/OnWorkerStart.php:130]
|
||||
#5 ZM\Event\SwooleEvent\OnWorkerStart->onCall() called at [/Users/jerry/project/git-project/zhamao-framework/src/ZM/Framework.php:336]
|
||||
```
|
||||
|
||||
这种错误的出现原因一般是因为协程未结束而 Worker 进程提前退出导致的,这个错误也可手动造成(在任意 Worker 进程内的位置使用 `zm_yield()` 且不使用 `zm_resume()` 恢复,期间使用 reload 或 stop 重启或停止框架就会报错)。
|
||||
|
||||
还有一种情况是数据库、文件读取或下载上传还没有传送结束,时间已经超时,在关闭或重启框架时不得不强行切断协程的运行。这种情况建议根据下方的打印输出栈进行插错,建议将协程运行时间长的过程缩短或调长 `swoole` 配置项下面的 `max_wait_time` 时间(秒),2.4.3 版本起此参数默认为 5 秒。
|
||||
|
||||
## 使用 LightCache 关闭时无法正常保存持久化
|
||||
|
||||
LightCache 因为是跨内存使用的,所以每次重启和关闭框架时,都只会让其中一个进程去保存。因为在 2.4.2 版本开始,持久化的逻辑发生了更改,不再支持 `expire = -2` 进行设置持久化(因为那样会很容易让开发者写错),仅支持使用 `LightCache::addPersistence($key)` 这样的方式进行设置持久化,所以在 2.4.2 版本以后,请使用此方法进行持久化设置,保证数据不丢失。
|
||||
|
||||
此外,2.4.2 版本起,不再支持用户手动调用 `savePersistence()` 方法,普通用户不可手动调用此方法,否则会导致数据出错。
|
||||
|
||||
##
|
||||
@ -118,7 +118,7 @@ dump(LightCache::getExpire("test")); // 返回 10
|
||||
|
||||
### LightCache::getExpireTS()
|
||||
|
||||
获取存储项要过期的时间戳。
|
||||
获取存储项要过期的时间戳。(2.4.3 起可用)
|
||||
|
||||
定义:`LightCache::getExpireTS(string $key)`
|
||||
|
||||
@ -135,7 +135,7 @@ dump(LightCache::getExpire("test")); // 返回 null
|
||||
获取轻量缓存使用的总空间大小(字节)
|
||||
|
||||
```php
|
||||
LightCache::getMemoryUsage());
|
||||
LightCache::getMemoryUsage();
|
||||
```
|
||||
|
||||
轻量缓存的内存手工计算方式:(Table 结构体长度` + `KEY 长度 64 字节 + `$size`) * (1 + `$conflict_proportion`) * 列尺寸。
|
||||
|
||||
@ -87,3 +87,29 @@ MessageUtil::splitCommand("我有 三个空格"); // ["我有","三个空格"]
|
||||
|
||||
返回:`\ZM\Entity\MatchObject` 对象,含有匹配成功与否,匹配到的注解对象,匹配到的分割词等,见 []
|
||||
|
||||
### addShortCommand()
|
||||
|
||||
快速添加一条静态消息回复命令。
|
||||
|
||||
定义:`addShortCommand($command, string $reply)`
|
||||
|
||||
参数 `$command` 为问的内容,如 `炸毛不聪明`。
|
||||
|
||||
参数 `$reply` 为回复的内容,如 `其实还是很聪明的!`。
|
||||
|
||||
这个命令推荐在 `@OnStart` 注解下使用,可以用这个来做一个动态的词库,从文件加载后使用。
|
||||
|
||||
```php
|
||||
/**
|
||||
* @OnStart()
|
||||
*/
|
||||
public function onStart() {
|
||||
MessageUtil::addShortCommand("炸毛不聪明", "其实还是很聪明的!");
|
||||
}
|
||||
```
|
||||
|
||||
<chat-box>
|
||||
) 炸毛不聪明
|
||||
( 其实还是很聪明的!
|
||||
</chat-box>
|
||||
|
||||
|
||||
86
docs/component/turing-api.md
Normal file
86
docs/component/turing-api.md
Normal file
@ -0,0 +1,86 @@
|
||||
# 图灵机器人 API(TuringAPI)
|
||||
|
||||
类定义:`\ZM\API\TuringAPI`
|
||||
|
||||
## 方法
|
||||
|
||||
### TuringAPI::getTuringMsg()
|
||||
|
||||
请求图灵接口,返回回复的消息。
|
||||
|
||||
定义:`getTuringMsg($msg, $user_id, $api)`
|
||||
|
||||
参数 `$msg` 为用户的消息内容,如果含有图片 CQ 码,则自动转换为图灵兼容的接口模式。
|
||||
|
||||
参数 `$user_id` 为用户 ID,一般默认给 QQ 号码就可以了,注意最好不要有特殊字符(如 `./\<>*` 等),否则会间断性调用失败。
|
||||
|
||||
参数 `$api` 为图灵机器人的 `apikey`,可以到 <http://www.turingapi.com/> 申请免费或付费的 API key。
|
||||
|
||||
在框架的示例模块中,已经写好了一个正常机器人响应图灵回复的命令,如下:
|
||||
|
||||
```php
|
||||
class Hello {
|
||||
/**
|
||||
* 图灵机器人的内置实现,在www.turingapi.com申请一个apikey填入下方变量即可。
|
||||
* @CQCommand(start_with="机器人",end_with="机器人",message_type="group")
|
||||
* @CQMessage(message_type="private",level=1)
|
||||
*/
|
||||
public function turingAPI() {
|
||||
$user_id = ctx()->getUserId();
|
||||
$api = ""; // 请在这里填入你的图灵机器人的apikey
|
||||
if ($api === "") return false; //如果没有填入apikey则此功能关闭
|
||||
if (($this->_running_annotation ?? null) instanceof CQCommand) {
|
||||
$msg = ctx()->getFullArg("我在!有什么事吗?");
|
||||
} else {
|
||||
$msg = ctx()->getMessage();
|
||||
}
|
||||
ctx()->setMessage($msg);
|
||||
if (MessageUtil::matchCommand($msg, ctx()->getData())->status === false) {
|
||||
return TuringAPI::getTuringMsg($msg, $user_id, $api);
|
||||
} else {
|
||||
QQBot::getInstance()->handle(ctx()->getData(), ctx()->getCache("level") + 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 响应at机器人的消息
|
||||
* @CQBefore("message")
|
||||
*/
|
||||
public function changeAt() {
|
||||
if (MessageUtil::isAtMe(ctx()->getMessage(), ctx()->getRobotId())) {
|
||||
$msg = str_replace(CQ::at(ctx()->getRobotId()), "", ctx()->getMessage());
|
||||
ctx()->setMessage("机器人" . $msg);
|
||||
Console::info(ctx()->getMessage());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
如上述代码,我们将申请的 apikey 填入变量 `$api` 中,启动机器人即可使用,以下是实测消息(我用自己申请的 key 做测试回复的消息)。
|
||||
|
||||
<chat-box>
|
||||
) 你咋了
|
||||
( 我没事哦,谢谢您的关心。
|
||||
) 上海天气
|
||||
( 上海:周一 03月29日,小雨 东南风转东风,最低气温14度,最高气温24度。
|
||||
^ 切换为群内
|
||||
) 机器人
|
||||
( 我在!有什么事吗?
|
||||
) 你叫啥
|
||||
( 我的名字叫炸毛,认识你很高兴呢!
|
||||
</chat-box>
|
||||
|
||||
在默认示例模块中的例子是直接可以拿来用的,这段代码同时做了对 at 的处理、以及兼容用户自定义写的其他命令的方式,下面是默认模块填好 apikey 后可以用的各种方式提问:
|
||||
|
||||
<chat-box>
|
||||
^ 切换为群内
|
||||
) 我是一条普通消息,这条机器人不会回复我
|
||||
) @机器人 你叫啥
|
||||
( 我是聪明可爱的炸毛,认识你很高兴。
|
||||
) 机器人
|
||||
( 我在!有什么事吗?
|
||||
) 一言
|
||||
( 多少事,从来急,天地转,光阴迫,一万年太久,只争朝夕。
|
||||
</chat-box>
|
||||
@ -281,6 +281,7 @@
|
||||
| 参数名称 | 参数范围 | 默认 |
|
||||
| ----------- | ------------------------------ | ---- |
|
||||
| command | `string`,**必填**,命令字符串 | |
|
||||
| alias | `string`,可选,命令的别名 | |
|
||||
| description | `string`,要显示的帮助文本 | 空 |
|
||||
|
||||
## 示例1(机器人连接框架后输出信息)
|
||||
|
||||
@ -333,6 +333,8 @@ TODO:先放着,有时间再更。
|
||||
在设置了 `level` 参数后,如果设置了多个 `@CQBefore` 监听事件函数,更高 `level` 的事件函数返回了 `false`,则低 `level` 的绑定函数不会执行,所有 `@CQMessage` 绑定的事件也不会执行。
|
||||
|
||||
你也可以使用 `@CQBefore` 做一些消息的转发和过滤。比如你想去除用户发来的文字中的 emoji、图片等 CQ 码,只保留文本。
|
||||
|
||||
使用 `ctx()->waitMessage()` 时等待用户输入下一条消息功能和 CQBefore 配合过滤消息时需注意,见 [FAQ - CQBefore 过滤不了 waitMessage](/FAQ/wait-message-cqbefore/)
|
||||
|
||||
## CQAfter()
|
||||
|
||||
|
||||
3
docs/faq/FAQ.md
Normal file
3
docs/faq/FAQ.md
Normal file
@ -0,0 +1,3 @@
|
||||
# FAQ
|
||||
|
||||
这里会写一些常见的疑难解答,点击左侧问题名称打开对应解决方法。
|
||||
19
docs/faq/address-already-in-use.md
Normal file
19
docs/faq/address-already-in-use.md
Normal file
@ -0,0 +1,19 @@
|
||||
# 启动时报错 Address already in use
|
||||
|
||||
1. 检查是否开启了两次框架,每个端口只能开启一个框架。
|
||||
2. 如果是之前已经在 20001 端口或者你设置了别的应用同样占用此端口,更换配置文件 `global.php` 中的 port 即可。
|
||||
3. 如果是之前框架成功启动,但是使用 Ctrl+C 停止后再次启动导致的报错,请根据下面的步骤来检查是否存在僵尸进程。
|
||||
|
||||
- 如果系统内装有 `htop`,可以直接在 `htop` 中开启 Tree 模式并使用 filter 过滤 php,检查残留的框架进程。
|
||||
- 如果系统没有 `htop`,使用 `ps aux | grep vendor/bin/start | grep -v grep` 如果存在进程,请使用以下命令尝试杀掉:
|
||||
|
||||
```bash
|
||||
# 如果确定框架的数据都已保存且没有需要保存的缓存数据,直接杀掉 SIGKILL 即可,输入下面这条
|
||||
ps aux | grep vendor/bin/start | grep -v grep | awk '{print $2}' | xargs kill -9
|
||||
|
||||
# 如果不确定框架是不是还继续运行,想尝试正常关闭(走一遍储存保存数据的事件),使用下面这条
|
||||
# 首先使用 'ps aux | grep vendor/bin/start | grep -v grep' 找到进程中第二列最小的pid
|
||||
# 然后使用下面的这条命令,假设最小的pid是23643
|
||||
kill -INT 23643
|
||||
# 如果使用 ps aux 看不到框架相关进程,证明关闭成功,否则需要使用第一条强行杀死
|
||||
```
|
||||
22
docs/faq/display-deadlock.md
Normal file
22
docs/faq/display-deadlock.md
Normal file
@ -0,0 +1,22 @@
|
||||
# 出现 deadlock 字样
|
||||
|
||||
一般情况下,如果误操作框架可能会报如下图的错误:
|
||||
|
||||
```
|
||||
===================================================================
|
||||
[FATAL ERROR]: all coroutines (count: 1) are asleep - deadlock!
|
||||
===================================================================
|
||||
|
||||
[Coroutine-1]
|
||||
--------------------------------------------------------------------
|
||||
#0 Swoole\Coroutine\System::sleep() called at [/Users/jerry/project/git-project/zhamao-framework/src/ZM/global_functions.php:232]
|
||||
#1 zm_sleep() called at [/Users/jerry/project/git-project/zhamao-framework/src/Module/Example/Hello.php:38]
|
||||
#2 Module\Example\Hello->onStart() called at [/Users/jerry/project/git-project/zhamao-framework/src/ZM/Event/EventDispatcher.php:205]
|
||||
#3 ZM\Event\EventDispatcher->dispatchEvent() called at [/Users/jerry/project/git-project/zhamao-framework/src/ZM/Event/EventDispatcher.php:89]
|
||||
#4 ZM\Event\EventDispatcher->dispatchEvents() called at [/Users/jerry/project/git-project/zhamao-framework/src/ZM/Event/SwooleEvent/OnWorkerStart.php:130]
|
||||
#5 ZM\Event\SwooleEvent\OnWorkerStart->onCall() called at [/Users/jerry/project/git-project/zhamao-framework/src/ZM/Framework.php:336]
|
||||
```
|
||||
|
||||
这种错误的出现原因一般是因为协程未结束而 Worker 进程提前退出导致的,这个错误也可手动造成(在任意 Worker 进程内的位置使用 `zm_yield()` 且不使用 `zm_resume()` 恢复,期间使用 reload 或 stop 重启或停止框架就会报错)。
|
||||
|
||||
还有一种情况是数据库、文件读取或下载上传还没有传送结束,时间已经超时,在关闭或重启框架时不得不强行切断协程的运行。这种情况建议根据下方的打印输出栈进行插错,建议将协程运行时间长的过程缩短或调长 `swoole` 配置项下面的 `max_wait_time` 时间(秒),2.4.3 版本起此参数默认为 5 秒。
|
||||
5
docs/faq/light-cache-wrong.md
Normal file
5
docs/faq/light-cache-wrong.md
Normal file
@ -0,0 +1,5 @@
|
||||
# 使用 LightCache 关闭时无法正常保存持久化
|
||||
|
||||
LightCache 因为是跨内存使用的,所以每次重启和关闭框架时,都只会让其中一个进程去保存。因为在 2.4.2 版本开始,持久化的逻辑发生了更改,不再支持 `expire = -2` 进行设置持久化(因为那样会很容易让开发者写错),仅支持使用 `LightCache::addPersistence($key)` 这样的方式进行设置持久化,所以在 2.4.2 版本以后,请使用此方法进行持久化设置,保证数据不丢失。
|
||||
|
||||
此外,2.4.2 版本起,不再支持用户手动调用 `savePersistence()` 方法,普通用户不可手动调用此方法,否则会导致数据出错。
|
||||
23
docs/faq/wait-message-cqbefore.md
Normal file
23
docs/faq/wait-message-cqbefore.md
Normal file
@ -0,0 +1,23 @@
|
||||
# CQBefore 过滤不了 waitMessage
|
||||
|
||||
因为 `waitMessage()` 功能是要等待接收下一个消息事件的,而消息事件又会被 CQBefore 走一遍。但是这里就会有一个问题,那 `waitMessage()` 的消息会不会走 CQBefore 呢?(显然不会啊!这个问题的题目就是这个!)
|
||||
|
||||
框架在 2.4.2 版本之前是无法过滤 waitMessage() 的(之前在 2.1 版本左右的几个版本是可以的,但这里不讨论历史版本),从 2.4.2 版本起支持过滤 `waitMessage`,但是需要设置一下 `@CQBefore` 的级别。
|
||||
|
||||
```php
|
||||
/**
|
||||
* @CQBefore("message",level=201)
|
||||
*/
|
||||
public function filter1() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @CQBefore("message")
|
||||
*/
|
||||
public function filter2() {
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
如果 `level >= 200`,那么此注解事件则会过滤 `waitMessage()`,如果 `level < 200`,则不会。(`@CQBefore` 的默认 level 为 20,所以默认情况下是不会过滤 waitMessage 的)
|
||||
@ -78,6 +78,7 @@ nav:
|
||||
- CQ 码(多媒体消息): component/cqcode.md
|
||||
- 机器人消息处理: component/message-util.md
|
||||
- Token 验证: component/access-token.md
|
||||
- 图灵机器人 API: component/turing-api.md
|
||||
- 存储:
|
||||
- LightCache 轻量缓存: component/light-cache.md
|
||||
- MySQL 数据库: component/mysql.md
|
||||
@ -106,7 +107,12 @@ nav:
|
||||
- TaskWorker 提高并发: advanced/task-worker.md
|
||||
- 开发实战教程:
|
||||
- 编写管理员才能触发的功能: advanced/example/admin.md
|
||||
- FAQ: FAQ.md
|
||||
- FAQ:
|
||||
- FAQ: faq/FAQ.md
|
||||
- 启动时报错 Address already in use: faq/address-already-in-use.md
|
||||
- 出现 deadlock 字样: faq/display-deadlock.md
|
||||
- 使用 LightCache 关闭时无法正常保存持久化: faq/light-cache-wrong.md
|
||||
- CQBefore 过滤不了 waitMessage: faq/wait-message-cqbefore.md
|
||||
- 更新日志:
|
||||
- 更新日志(v2): update/v2.md
|
||||
- 更新日志(v1): update/v1.md
|
||||
|
||||
@ -19,7 +19,7 @@ use ZM\Command\SystemdCommand;
|
||||
|
||||
class ConsoleApplication extends Application
|
||||
{
|
||||
const VERSION_ID = 404;
|
||||
const VERSION_ID = 405;
|
||||
const VERSION = "2.4.4";
|
||||
|
||||
public function __construct(string $name = 'UNKNOWN') {
|
||||
|
||||
21
src/ZM/Event/SwooleEvent/OnManagerStop.php
Normal file
21
src/ZM/Event/SwooleEvent/OnManagerStop.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace ZM\Event\SwooleEvent;
|
||||
|
||||
|
||||
use ZM\Annotation\Swoole\SwooleHandler;
|
||||
use ZM\Console\Console;
|
||||
use ZM\Event\SwooleEvent;
|
||||
|
||||
/**
|
||||
* Class OnManagerStop
|
||||
* @package ZM\Event\SwooleEvent
|
||||
* @SwooleHandler("ManagerStop")
|
||||
*/
|
||||
class OnManagerStop implements SwooleEvent
|
||||
{
|
||||
public function onCall() {
|
||||
Console::verbose("进程 Manager 已停止!");
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user