Skip to content

Commit

Permalink
update to 2.2.9 version
Browse files Browse the repository at this point in the history
update reply() to support quick operation
fix reload bug
fix reply() bug
  • Loading branch information
crazywhalecc committed Mar 6, 2021
1 parent 0c24bfd commit a23f3d8
Show file tree
Hide file tree
Showing 13 changed files with 170 additions and 69 deletions.
15 changes: 5 additions & 10 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
{
"name": "zhamao/framework",
"description": "High performance QQ robot and web server development framework",
"description": "High performance chat robot and web server development framework",
"minimum-stability": "stable",
"license": "Apache-2.0",
"version": "2.2.8",
"version": "2.2.9",
"extra": {
"exclude_annotate": [
"src/ZM"
]
},
"authors": [
{
"name": "whale",
"email": "[email protected]"
},
{
"name": "swift",
"email": "[email protected]"
"name": "jerry",
"email": "[email protected]"
}
],
"prefer-stable": true,
Expand Down Expand Up @@ -52,7 +48,6 @@
]
},
"require-dev": {
"swoole/ide-helper": "@dev",
"phpunit/phpunit": "^9.5"
"swoole/ide-helper": "@dev"
}
}
2 changes: 1 addition & 1 deletion config/global.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
/** 对应swoole的server->set参数 */
$config['swoole'] = [
'log_file' => $config['crash_dir'] . 'swoole_error.log',
'worker_num' => swoole_cpu_num(), //如果你只有一个 OneBot 实例连接到框架并且代码没有复杂的CPU密集计算,则可把这里改为1使用全局变量
//'worker_num' => swoole_cpu_num(), //如果你只有一个 OneBot 实例连接到框架并且代码没有复杂的CPU密集计算,则可把这里改为1使用全局变量
'dispatch_mode' => 2, //包分配原则,见 https://wiki.swoole.com/#/server/setting?id=dispatch_mode
'max_coroutine' => 300000,
//'task_worker_num' => 4,
Expand Down
59 changes: 59 additions & 0 deletions docs/component/access-token.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Token 验证

为了保障安全,框架支持给接入的 WebSocket 连接验证 Token,如果不设置 Token 同时又将框架的端口暴露在公网将会非常危险。

炸毛框架兼容 OneBot 标准的机器人客户端,所以自带一个 Token 验证器。

关于 Access Token 方面的标准规范,请参考下面内容:

- [OneBot - 鉴权](https://github.com/howmanybots/onebot/blob/master/v11/specs/communication/authorization.md)
- [go-cqhttp - 配置](https://github.com/Mrs4s/go-cqhttp/blob/master/docs/config.md)

> 以 go-cqhttp 举例,如果要设置验证,则将 go-cqhttp 配置文件中的 `access_token` 项填入内容即可。
## 验证位置

框架对 Token 的验证是内置的,在事件 `open`(WebSocket 连接接入时)触发。

如果是兼容 OneBot 标准的客户端接入,则一切都是兼容的。

如果是自定义的其他 WebSocket 客户端也想接入框架,那么其他 WebSocket 客户端也需要进行相应的设置才能利用此 Token 验证。

如果验证成功(Token 符合要求)则分发事件 `@OnOpenEvent`,否则此事件不触发,同时断开 WebSocket 连接。

## 标准验证(字符串形式)

默认的情况下,在框架的全局配置文件 `global.php` 中,对配置项 `access_token` 填入与 OneBot 客户端相同的 `access_token` 即可实现鉴权。下面是一个最基本的和 go-cqhttp 设置鉴权配置:

go-cqhttp 的配置段:

```hjson
// 访问密钥, 强烈推荐在公网的服务器设置
access_token: "emhhbWFvLXJvYm90"
```

框架的配置文件配置段:

```php
/** onebot连接约定的token */
$config["access_token"] = 'emhhbWFvLXJvYm90';
```

然后重启框架和 go-cqhttp 即可。(其他 OneBot 客户端同理)

## 自定义验证(Token 验证)

有些情况下,使用一个单一的字符串可能无法满足你对 Token 验证的安全需求,需要自定义一些判断模式才能满足,所以框架的 `access_token` 配置项支持动态的闭包函数自行编写判断逻辑,例如下面的一个例子,我可以让框架同时允许接入多个不同 token 的 WebSocket 连接:

```php
/** onebot连接约定的token */
$config["access_token"] = function($token){
$allow = ['emhhbWFvLXJvYm90','aXMtdmVyeS1nb29k'];
if (in_array($token, $allow)) return true;
else return false;
};
```

## 自定义验证(open 事件)

当然,这里设置了自定义方式,其实你也可以在下一层的 `@OnOpenEvent` 注解事件中进行自定义内容和判断,具体见 `@OnOpenEvent` 的相关章节。
5 changes: 3 additions & 2 deletions docs/component/context.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public function hello() {
* @CQCommand("测试fd")
*/
public function testfd() {
ctx()->reply("当前机器人连接的fd是:".ctx()->getFd()",机器人QQ是:".ctx()->getRobotId());
ctx()->reply("当前机器人连接的fd是:".ctx()->getFd().",机器人QQ是:".ctx()->getRobotId());
}
```

Expand Down Expand Up @@ -421,4 +421,5 @@ public function argTest1() {
<chat-box>
) test abc 334 argtest
( 参数内容:abc, 334, argtest
</chat-box>
</chat-box>

19 changes: 18 additions & 1 deletion docs/component/data-provider.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,21 @@ DataProvider 是框架内提供的一个简易的文件管理类。

定义:`loadFromJson($filename)`

文件名同上 `saveToJson()` 的定义,解析后的返回值为原先的内容或 `null`(如果文件不存在或 json 解析失败)。
文件名同上 `saveToJson()` 的定义,解析后的返回值为原先的内容或 `null`(如果文件不存在或 json 解析失败)。

## 其他文件读取

框架比较贴近原生的 PHP,所以推荐直接使用原生的方法来读写文件(`file_get_contents``file_put_contents`)。但有一点要注意,框架内最好使用**工作目录或者绝对路径**

```php
// 读取框架工作目录的文件 composer.json 文件
$r = file_get_contents(working_dir() . "/composer.json");

// 写入 Linux 临时目录下的文件
file_put_contents("/tmp/test.txt", "hello world");
```

!!! warning "注意"

在默认的情况里,框架的根目录均为可写可读的,在读写文件时务必要注意目录的位置和权限。使用 `working_dir()` 获取目录后面需要加 `/` 再追加自己的文件名或子目录名。

46 changes: 23 additions & 23 deletions docs/guide/basic-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,29 @@

框架的全局配置文件在 `config/global.php` 文件中。下面是配置文件的各个选项,请根据自己的需要自行配置。

| 配置名称 | 说明 | 默认值 |
| :--------------------------- | ------------------------------------------------ | ---------------------------- |
| `host` | 框架监听的地址 | 0.0.0.0 |
| `port` | 框架监听的端口 | 20001 |
| `http_reverse_link` | 框架开到公网或外部的 HTTP 反代链接 | 见配置文件 |
| `zm_data` | 框架的配置文件、日志文件等文件目录 | `./` 下的 `zm_data/` |
| `debug_mode` | 框架是否启动 debug 模式 | false |
| `crash_dir` | 存放崩溃和运行日志的目录 | `zm_data` 下的 `crash/` |
| `swoole` | 对应 Swoole server 中 set 的参数,参考Swoole文档 | 见子表 `swoole` |
| `light_cache` | 轻量内置 key-value 缓存 | 见字表 `light_cache` |
| `worker_cache` | 跨进程变量级缓存 | 见子表 `worker_cache` |
| `sql_config` | MySQL 数据库连接信息 | 见子表 `sql_config` |
| `redis_config` | Redis 连接信息 | 见子表 `redis_config` |
| `access_token` | OneBot 客户端连接约定的token,留空则无 ||
| `http_header` | HTTP 请求自定义返回的header | 见配置文件 |
| `http_default_code_page` | HTTP服务器在指定状态码下回复的默认页面 | 见配置文件 |
| `init_atomics` | 框架启动时初始化的原子计数器列表 | 见配置文件 |
| `info_level` | 终端日志显示等级(0-4) | 2 |
| `context_class` | 上下文所定义的类,待上下文完善后见对应文档 | `\ZM\Context\Context::class` |
| `static_file_server` | 静态文件服务器配置项 | 见子表 `static_file_server` |
| `server_event_handler_class` | 注册 Swoole Server 事件注解的类列表 | 见配置文件 |
| `command_register_class` | 注册自定义命令行选项指令的类 | 见配置文件 |
| `modules` | 服务器启用的外部第三方和内部插件 | `['onebot' => true]` |
| 配置名称 | 说明 | 默认值 |
| :--------------------------- | ------------------------------------------------------------ | ---------------------------- |
| `host` | 框架监听的地址 | 0.0.0.0 |
| `port` | 框架监听的端口 | 20001 |
| `http_reverse_link` | 框架开到公网或外部的 HTTP 反代链接 | 见配置文件 |
| `zm_data` | 框架的配置文件、日志文件等文件目录 | `./` 下的 `zm_data/` |
| `debug_mode` | 框架是否启动 debug 模式 | false |
| `crash_dir` | 存放崩溃和运行日志的目录 | `zm_data` 下的 `crash/` |
| `swoole` | 对应 Swoole server 中 set 的参数,参考Swoole文档 | 见子表 `swoole` |
| `light_cache` | 轻量内置 key-value 缓存 | 见字表 `light_cache` |
| `worker_cache` | 跨进程变量级缓存 | 见子表 `worker_cache` |
| `sql_config` | MySQL 数据库连接信息 | 见子表 `sql_config` |
| `redis_config` | Redis 连接信息 | 见子表 `redis_config` |
| `access_token` | OneBot 客户端连接约定的token,留空则无,相关设置见 [组件 - Access Token 验证](component/access-token) ||
| `http_header` | HTTP 请求自定义返回的header | 见配置文件 |
| `http_default_code_page` | HTTP服务器在指定状态码下回复的默认页面 | 见配置文件 |
| `init_atomics` | 框架启动时初始化的原子计数器列表 | 见配置文件 |
| `info_level` | 终端日志显示等级(0-4) | 2 |
| `context_class` | 上下文所定义的类,待上下文完善后见对应文档 | `\ZM\Context\Context::class` |
| `static_file_server` | 静态文件服务器配置项 | 见子表 `static_file_server` |
| `server_event_handler_class` | 注册 Swoole Server 事件注解的类列表 | 见配置文件 |
| `command_register_class` | 注册自定义命令行选项指令的类 | 见配置文件 |
| `modules` | 服务器启用的外部第三方和内部插件 | `['onebot' => true]` |

### 子表 **swoole**

Expand Down
8 changes: 8 additions & 0 deletions docs/update/v2.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# 更新日志(v2 版本)

## v2.2.9

> 更新时间:2021.3.6
- 更新:`reply()` 方法传入数组则变为快速相应的 API 操作
- 修复:在 Worker 进程下调用 `ZMUtil::reload()` 会导致一些奇怪的 bug
- 修复:`reply()` 时会 at 私聊成员的 bug(由 go-cqhttp 导致)

## v2.2.8

> 更新时间:2021.3.2
Expand Down
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ nav:
- 全局方法: component/global-functions.md
- HTTP 和 WebSocket 客户端: component/zmrequest.md
- Console 终端: component/console.md
- Token 验证: component/access-token.md
- 进阶开发:
- 进阶开发: advanced/index.md
- 框架剖析: advanced/framework-structure.md
Expand Down
38 changes: 22 additions & 16 deletions src/ZM/Context/Context.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,25 +104,31 @@ public function getCQResponse() { return self::$context[$this->cid]["cq_response
* @param $msg
* @param bool $yield
* @return mixed
* @noinspection PhpMissingBreakStatementInspection
*/
public function reply($msg, $yield = false) {
switch ($this->getData()["message_type"]) {
case "group":
$operation["at_sender"] = false;
// no break
case "private":
case "discuss":
$this->setCache("has_reply", true);
$data = $this->getData();
$conn = $this->getConnection();
$operation["reply"] = $msg;
return (new ZMRobot($conn))->setCallback($yield)->callExtendedAPI(".handle_quick_operation", [
"context" => $data,
"operation" => $operation
]);
$data = $this->getData();
$conn = $this->getConnection();
if (!is_array($msg)) {
switch ($this->getData()["message_type"]) {
case "group":
case "private":
case "discuss":
$this->setCache("has_reply", true);
$operation["reply"] = $msg;
$operation["at_sender"] = false;
return (new ZMRobot($conn))->setCallback($yield)->callExtendedAPI(".handle_quick_operation", [
"context" => $data,
"operation" => $operation
]);
}
return false;
} else {
$operation = $msg;
return (new ZMRobot($conn))->setCallback(false)->callExtendedAPI(".handle_quick_operation", [
"context" => $data,
"operation" => $operation
]);
}
return false;
}

public function finalReply($msg, $yield = false) {
Expand Down
15 changes: 10 additions & 5 deletions src/ZM/Event/ServerEventHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,16 @@ public function onStart() {
});
}
Process::signal(SIGINT, function () use ($r) {
echo "\r";
Console::warning("Server interrupted(SIGINT) on Master.");
if ((Framework::$server->inotify ?? null) !== null)
/** @noinspection PhpUndefinedFieldInspection */ Event::del(Framework::$server->inotify);
ZMUtil::stop();
if (zm_atomic("_int_is_reload")->get() === 1) {
zm_atomic("_int_is_reload")->set(0);
ZMUtil::reload();
} else {
echo "\r";
Console::warning("Server interrupted(SIGINT) on Master.");
if ((Framework::$server->inotify ?? null) !== null)
/** @noinspection PhpUndefinedFieldInspection */ Event::del(Framework::$server->inotify);
ZMUtil::stop();
}
});
if (Framework::$argv["daemon"]) {
$daemon_data = json_encode([
Expand Down
21 changes: 10 additions & 11 deletions src/ZM/Framework.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,7 @@ public function __construct($args = []) {
die($e->getMessage());
}
try {
self::$server = new Server(ZMConfig::get("global", "host"), ZMConfig::get("global", "port"));
$this->server_set = ZMConfig::get("global", "swoole");

Console::init(
ZMConfig::get("global", "info_level") ?? 2,
self::$server,
Expand All @@ -86,16 +85,14 @@ public function __construct($args = []) {
$timezone = ZMConfig::get("global", "timezone") ?? "Asia/Shanghai";
date_default_timezone_set($timezone);

$this->server_set = ZMConfig::get("global", "swoole");
$this->parseCliArgs(self::$argv);


self::$server->set($this->server_set);

// 打印初始信息
$out["listen"] = ZMConfig::get("global", "host") . ":" . ZMConfig::get("global", "port");
if (!isset(ZMConfig::get("global", "swoole")["worker_num"])) $out["worker"] = swoole_cpu_num() . " (auto)";
else $out["worker"] = ZMConfig::get("global", "swoole")["worker_num"];
$out["env"] = $args["env"] === null ? "default" : $args["env"];
$out["environment"] = $args["env"] === null ? "default" : $args["env"];
$out["log_level"] = Console::getLevel();
$out["version"] = ZM_VERSION;
if (APP_VERSION !== "unknown") $out["app_version"] = APP_VERSION;
Expand All @@ -117,6 +114,10 @@ public function __construct($args = []) {
$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"));

self::$server->set($this->server_set);

self::printMotd($tty_width);

global $asd;
Expand Down Expand Up @@ -170,6 +171,7 @@ public function __construct($args = []) {
} catch (Exception $e) {
Console::error("Framework初始化出现错误,请检查!");
Console::error($e->getMessage());
Console::debug($e);
die;
}
}
Expand Down Expand Up @@ -350,6 +352,7 @@ public static function printProps($out, $tty_width, $colorful = true) {
$line_width = [];
$line_data = [];
foreach ($out as $k => $v) {
start:
if (!isset($line_width[$current_line])) {
$line_width[$current_line] = $max_border - 2;
}
Expand All @@ -363,11 +366,7 @@ public static function printProps($out, $tty_width, $colorful = true) {
if (strlen($tmp_line) > $line_width[$current_line]) { // 地方不够,另起一行
$line_data[$current_line] = str_replace("| ", "", $line_data[$current_line]);
++$current_line;
$line_data[$current_line] = " " . $k . ": ";
if ($colorful) $line_data[$current_line] .= TermColor::color8(32);
$line_data[$current_line] .= $v;
if ($colorful) $line_data[$current_line] .= TermColor::RESET;
++$current_line;
goto start;
} else { // 地方够,直接写到后面并另起一行
$line_data[$current_line] .= $k . ": ";
if ($colorful) $line_data[$current_line] .= TermColor::color8(32);
Expand Down
1 change: 1 addition & 0 deletions src/ZM/Store/ZMAtomic.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public static function init() {
self::$atomics[$k] = new Atomic($v);
}
self::$atomics["stop_signal"] = new Atomic(0);
self::$atomics["_int_is_reload"] = new Atomic(0);
self::$atomics["wait_msg_id"] = new Atomic(0);
self::$atomics["_event_id"] = new Atomic(0);
for ($i = 0; $i < 10; ++$i) {
Expand Down
Loading

0 comments on commit a23f3d8

Please sign in to comment.