update to 2.1.6 version

优化代码结构
增加更多提示语
修复处理空格消息时的报错
修复上下文的bug
This commit is contained in:
jerry
2021-01-18 18:08:29 +08:00
parent c208298937
commit 187a08a621
19 changed files with 594 additions and 45 deletions

View File

@@ -0,0 +1,143 @@
# 接入 WebSocket 客户端
炸毛框架其实从本质上讲,就是一个 HTTP + WebSocket 服务器,所以框架也支持对接其他任何 HTTP 客户端和 WebSocket 客户端,实际上炸毛框架非常适合用 WebSocket 做在线的 IM 聊天通讯,也可以方便地进行 WS 通信。这里主要说明如何对接一个自定义的 WebSocket 客户端。
## 类型指定
由于 WebSocket 连接都具有同样的性质,没有状态,所以在建立 WebSocket 连接的时候,需要客户端表明自己的身份和类型。指定客户端连接类型的方式有两种:
- `GET` 参数传递,在连接的时候,加上 GET 参数 `type` 即可。比如 js 中 WebSocket 建立时地址写:`ws://127.0.0.1:20001/?type=foo`,这时传入的连接就是 `foo` 类型。
- `Header` 传递,用户需要在建立连接时指定 HTTP 的头部信息 `X-Client-Role`,例如 `X-Client-Role: foo`,这时传入的连接就是 `foo` 类型。
以上两种方式,`Header` 方式比 `GET` 方式优先级要高,如果两者均没有指定,框架会将此连接当作 `default` 类型接入。
!!! note "提示"
对于对接 OneBot 标准的机器人客户端,只要符合 OneBot 标准,即 `X-Client-Role` 会自动带上 `universal``qq` 等字样,就会自动标记为 `qq` 类型。
## 逻辑编写
传入连接后,我们就能通过注解事件绑定来做我们自己想做的事情了!比如下方是传入类型为 foo 连接要做的事情
```php
<?php
namespace Module\Example;
use ZM\Annotation\Swoole\OnOpenEvent;
use ZM\Console\Console;
use ZM\ConnectionManager\ConnectionObject;
class Hello {
/**
* @OnOpenEvent("foo")
*/
public function onFooConnect(ConnectionObject $conn) {
Console::info($conn->getName()." 已连接!");
}
```
以上作用就是在终端输出 `foo 已连接!` 这个提示的。关于 `ConnectionObject` 对象,见下方。
## WS 连接对象
对于每一个 WebSocket 连接,框架内都有一个专属的操作类,有获取类型名称、保存链接参数和属性以及获取文件标识符等功能。
### getFd()
获取文件标示符,用于发送消息、接收消息等。这个参数获取的 `fd` 是 Swoole 指定的,用于发送信息等。
```php
$fd = $conn->getFd();
server()->send($fd, "hello world");
```
> WebSocket 是全双工的,所以发送和接收其实是互不干扰的,你可以不仅仅在 WebSocket 相关的上下文中,还可以比如在 HTTP 或者机器人上下文中给别的 WebSocket 客户端发请求。
### getName()
获取连接对象绑定的连接类型,例如上方提到的 `foo``default` 等。
```php
Console::info("当前连接类型:".$conn->getName()); //当前连接类型foo
```
### setName()
改变连接对象绑定的连接类型,例如从 `foo` 改为 `bar`
```php
$s = $conn->getName(); // foo
$conn->setName("bar");
$s = $conn->getName(); // bar
```
### getOptions()
获取此连接存储的所有参数,以数组形式。存储内容见下方 `setOption()`
格式:`["参数1" => {参数1的值}, "参数2" => {参数2的值}]`
### getOption()
获取此连接存储的参数,获取指定名称的,此方法拥有一个参数 `$key`,指定即可获取。
如果没有对应参数,则返回 `null`
我们在前面的机器人部分知道,框架主要是用于机器人的连接,那么机器人客户端在连接后,比如我们想知道这个机器人的 WS 连接对应的是哪个 QQ 号的机器人,我们就可以用 `getOption("connect_id")` 来获取。这个 `connect_id` 是 OneBot 标准的客户端接入后自动填入的一个参数。例如,我们想在机器人接入后打出接入机器人的 QQ 号:
```php
/**
* @OnOpenEvent("qq")
*/
public function onQQConnect($conn) {
Console::success("机器人 ".$conn->getOption("connect_id")." 已连接!"); // 机器人 123456 已连接!
}
```
### setOption()
设置连接存储的参数。参数:`setOption($key, $value)``$key` 限定为 `connect_id` 一种。(因为目前有了 LightCache所以这里暂时不提供别的 key 设定)
```php
$conn->setOption("connect_id", "asdasdasd"); // $value 最长长度为 29
```
## 发送到 WebSocket 客户端
很简单,从上面获取到 `fd` 后使用下面的方式就可以了~
```php
server()->push($conn->getFd(), "hello"); // 第二个为 string 类型的参数
```
## 从客户端接收
接收消息必须从 `@OnMessageEvent` 注解事件下接收,使用上下文 `ctx()->getFrame()` 获取消息帧。
从这里获取的 `Frame` 对象,见 [Swoole 文档 - Frame](https://wiki.swoole.com/#/websocket_server?id=swoolewebsocketframe)。
Frame 对象有四个参数:
- `$frame->fd`:获取发来帧的 fd
- `$frame->data`:数据本体
- `$frame->opcode`:数据类型 int 值,见 [Swoole 文档 - 数据帧类型](https://wiki.swoole.com/#/websocket_server?id=%e6%95%b0%e6%8d%ae%e5%b8%a7%e7%b1%bb%e5%9e%8b)
- `$frame->finish`是否发送完毕bool
下面以接收一个 json 字符串为例,并进行后续的解析:
```php
/**
* @OnMessageEvent("foo")
*/
public function onMessage() {
$frame = ctx()->getFrame();
$json_str = $frame->data; // 假设传入的是 {"key1":"value1","k2":"v2"}
$json = json_decode($json_str, true);
Console::info("key1 的值是:" . $json["key1"]);
}
```
## 关闭连接
```php
server()->close($conn->getFd());
```

View File

@@ -0,0 +1,107 @@
# 框架高级启动
## 框架下载方式
从前面的几章中,我们了解到框架有多种下载到本地的方式。
- Composer 依赖模式
- Starter 从模板创建模式
- 源码模式
### Composer 依赖模式
从 Composer 依赖加载框架是一种拉取框架的方式,这种方式的优点在于,你可以直观地感受到是如何使用框架从零开始一个完整的项目的过程。
从 Composer 依赖的启动步骤:
```bash
mkdir my-bot # 新建一个空的文件夹
cd my-bot/
composer require zhamao/framework # 从 composer 拉取后会自动部署 autoload 和 composer.json 等内容
# 使用命令初始化框架
vendor/bin/start init
# 启动框架
vendor/bin/start server
```
注意:使用 `init` 命令时,会给当前目录解压以下文件:
```php
$extract_files = [
"/config/global.php", // 全局配置文件
"/.gitignore", // git 排除文件
"/config/file_header.json", // HTTP 文件头
"/config/console_color.json", // 终端颜色主题文件
"/config/motd.txt", // 框架启动时自定义的 motd
"/src/Module/Example/Hello.php", // 框架自带的示例模块
"/src/Module/Middleware/TimerMiddleware.php", // 框架自带的函数运行时间监控中间件
"/src/Custom/global_function.php" // 用户可在这里自定义编写自己的全局函数
];
```
经过 init 解压这些文件后,你的框架就能正常运行且开始编写代码了!
### Starter 模板模式
从模板新建其实原理和 Composer 依赖模式完全一样,只不过,这个过程是使用模板仓库新建的项目,使用 Composer 自带的 `create-project` 方式创建的。starter 也是一个 GitHub 项目,见 [地址](https://github.com/zhamao-robot/zhamao-framework-starter)。
```bash
composer create-project zhamao/framework-starter my-bot/ # my-bot 是你自定义的文件夹名称,和上方相同
cd my-bot
vendor/bin/start server # 启动框架
```
Starter 模式相当于直接从 GitHub 拉取 `zhamao-framework-starter` 项目,然后执行 `composer update`
那和 Composer 依赖模式有什么区别呢?没区别!构建出来的框架和文件是一模一样的!使用 Composer 依赖模式,使用 `init` 命令后,文件会和 `zhamao-framework-starter` 仓库拉取回来的模板一模一样!(或者换句话说,这个仓库就是使用 `init` 命令生成的文件的)
那使用哪种好呢?看你自己!如果你想给你自己的已有项目套上炸毛框架,那么就推荐使用 Composer 依赖模式,如果是从 0 开始编写框架模块,则推荐使用模板模式。
### 源码模式
源码模式和以上两种方案都不一样,源码模式允许你对框架本身进行一系列修改,框架本体就可以直接运行。
Composer 依赖模式(以及模板模式)和源码模式的区别是:
- 依赖模式和模板模式是通过 library 方式引入框架的,框架本身会放在 composer 的 `vendor/` 目录下,从 composer 引入的 library 相当于子集vendor 目录下的文件最好不要手动修改(应该都知道吧),所以框架本身也只是加载了进来。
- 源码模式相当于直接从框架源码目录运行框架和模块,框架源码都在 `src/ZM` 目录下,默认的示例模块都在 `src/Module` 下,是同级目录。而此时的 `vendor/` 目录只包含了框架依赖的外部组件,例如注解解析器和 psysh 等。
源码模式可以方便地调试和修改框架本身,拉取方式很简单,用 `git clone` 或从 GitHub 下载最新版的源码包解压即可。
```bash
git clone https://github.com/zhamao-robot/zhamao-framework.git
cd zhamao-framework/
bin/start server # 第一次运行时会提示一个“框架源码模式需要在autoload文件中添加Module目录为自动加载”
composer update # 更新 autoload 文件,应用刚才上一步添加的 `src/Module` 文件夹下的模块自动加载
bin/start server # 通过源码模式启动框架
```
## 框架启动参数
框架启动时可以根据实际情况指定启动参数。
- `--debug-mode`:启用调试模式,调试模式的作用是关闭一键协程化和终端交互,减少 Swoole 本身对代码逻辑的干扰(比如执行 `shell_exec()` 报错的话可以开启这个进行调试)。
- `--log-{mode}`:设置 log 等级。支持 `--log-debug``--log-verbose``--log-info``--log-warning``--log-error`
- `--log-theme`:设置终端信息的主题。这个选项适用于多种终端信息显示的兼容,例如白色终端和不支持颜色的终端。详见 [Console - 主题设置](/component/console/#_2)。
- `--disable-console-input`:关闭终端交互,如果你使用的不是 tmux、screen 而是直接将进程使用 systemd 等方式运行到 init 守护进程下,则需要关闭终端交互输入,关闭后不可以使用 `stop, reload, logtest` 等交互命令。
- `--disable-coroutine`:关闭一键协程化。
- `--daemon`:以守护进程方式运行框架,此参数将直接在输出 motd 后将进程挂到 init 下运行,后台常驻。
- `--watch`:监控 `src/` 目录下的文件变化,有变化则自动重新载入代码。开启监控需要安装 PHP 扩展inotify。使用 pecl 就可以安装:`pecl install inotify`
- `--env`:设置运行环境,设置运行环境后将优先加载指定环境的配置文件,支持 `--env=production``--env=staging``--env=development`,见 [基本配置](/guide/basic-config/#_2)。
## 独立启动其他组件
框架默认不止启动框架的 `server` 命令,还有 `init` 命令和 `simple-http-server` 命令。`init` 命令在上方 Composer 依赖模式中提到过,就是初始化各个文件的。
### 独立 HTTP 文件服务器
如果你只需要一个静态文件服务器,类似 Nginx那么框架也支持。
```bash
vendor/bin/start simple-http-server your-web-dir/ --host=0.0.0.0 --port=8080
```
- `your-web-dir` 是必填的参数。
- `--host``--port` 是可选参数,如果不填,则默认使用 `global.php` 配置文件中的配置。

View File

@@ -0,0 +1,6 @@
# 框架剖析
## 框架运行总结构图
![](../assets/img/framework-structure.png)

View File

@@ -1,3 +1,9 @@
# 进阶开发
## 深入
还没填坑,敬请期待!
在本章,下面的部分将详细说明一些具体的案例和自定义框架的操作。
- 如何自定义修改框架本身?- [框架启动方式](/advanced/custom-start/)
- 如何接入一个自己的 WebSocket 客户端?- [接入 WebSocket 客户端](/advanced/connect-ws-client/)
- 框架到底是怎么工作的?- [框架结构剖析](/advanced/framework-structure/)
> 更多进阶教程敬请期待....(或者你可以选择提 Issue 到框架 GitHub有需求就写入文档