snowluma: SnowLuma (OneBot 11) Go SDK, drop-in compatible with napcat
This commit is contained in:
173
README.md
Normal file
173
README.md
Normal file
@ -0,0 +1,173 @@
|
||||
# snowluma
|
||||
|
||||
对接 [SnowLuma](https://snowluma.github.io/)(OneBot v11 协议)的 Go 软件包,零第三方依赖(仅 gorilla/websocket)。
|
||||
|
||||
本包与 [gitea.doicat.com/bot/napcat](https://gitea.doicat.com/bot/napcat) 的公开 API **保持一致**:方法名、消息段构造函数、事件结构、Client/Context 用法完全相同。现有的 napcat 机器人项目,只需改一行导入即可切到 SnowLuma。
|
||||
|
||||
```go
|
||||
bot := snowluma.New().SetToken("xxx").SetForwardWS("ws://127.0.0.1:3001")
|
||||
bot.OnGroupMessage(func(c *snowluma.Context) {
|
||||
if c.HasAtMe() {
|
||||
c.ReplyText("hi")
|
||||
}
|
||||
})
|
||||
bot.Run(ctx)
|
||||
```
|
||||
|
||||
## 从 napcat 迁移(drop-in)
|
||||
|
||||
napcat 用法:
|
||||
|
||||
```go
|
||||
import "gitea.doicat.com/bot/napcat"
|
||||
// ... napcat.New() / napcat.Text(...) / *napcat.Context ...
|
||||
```
|
||||
|
||||
改成:
|
||||
|
||||
```go
|
||||
import napcat "gitea.doicat.com/bot/snowluma"
|
||||
// ... 其余代码一字不改,napcat.New() / napcat.Text(...) / *napcat.Context 全部照常编译
|
||||
```
|
||||
|
||||
导入别名 `napcat` 覆盖了包的声明名,因此所有 `napcat.XXX` 引用保持不变。差异只在协议/能力覆盖上(见下文「与 napcat 的差异」)。
|
||||
|
||||
## 特性
|
||||
|
||||
- **一个对象搞定**:`New()` 创建与 SnowLuma 交互的客户端对象,配置、事件、API 全在对象上
|
||||
- **四种通信方式**,链式配置、可任意叠加:
|
||||
- 正向 WebSocket(自动重连 + 指数退避)
|
||||
- 反向 WebSocket(支持多 bot 实例同时连入)
|
||||
- HTTP API
|
||||
- HTTP POST 上报(自动支持 OneBot 快速操作)
|
||||
- **事件模型**:message / message_sent / notice / request / meta_event 全量结构化,notice 未知字段不丢失(收进 `Extra`)
|
||||
- **消息段**:全类型构造函数;收到的 CQ 码字符串与段数组统一解码
|
||||
- **API 覆盖**:OneBot 11 标准 + go-cqhttp/NapCat 兼容 + SnowLuma 扩展(闪传、Ark 卡片、群待办、群相册、QQ 空间、系统表情、流式接口等);未收录的扩展可用 `Call` 裸调
|
||||
- **echo 路由**:WS 上的 action 请求/响应按 echo 精确配对,支持并发调用
|
||||
- **连接级路由**:事件处理函数里的 API 调用自动走产生该事件的连接,多 bot 互不串线
|
||||
- 内置文本命令路由、请求 Approve/Reject、心跳记录、panic 隔离
|
||||
|
||||
## 目录结构
|
||||
|
||||
```text
|
||||
snowluma/
|
||||
├── doc.go 包文档(pkg.go.dev 首页)
|
||||
├── client.go Client:配置方法、连接汇聚、事件分发、Handler 注册
|
||||
├── context.go Context:处理函数上下文(Reply/Approve/快速操作)
|
||||
├── api.go API:OneBot 11 / go-cqhttp / NapCat 兼容的类型化方法
|
||||
├── api_ext.go API:SnowLuma 扩展动作(闪传/Ark/待办/相册/空间/表情/流式)
|
||||
├── caller.go Caller 接口 + WS echo 路由 + CallAPI 泛型
|
||||
├── connect_ws.go 正向/反向 WebSocket 连接器 + Session
|
||||
├── connect_http.go HTTP 上报(快速操作)+ HTTP API 连接器
|
||||
├── event.go 事件结构(message/notice/request/meta)
|
||||
├── segment.go 消息段构造与解码
|
||||
├── cqcode.go CQ 码解析/编码
|
||||
├── types.go 响应信封与实体类型
|
||||
├── example_test.go 用法示例(godoc Example)
|
||||
└── snowluma_test.go 单元测试(CQ 码回环、事件解码、消息段解码)
|
||||
```
|
||||
|
||||
## 安装
|
||||
|
||||
```text
|
||||
go get gitea.doicat.com/bot/snowluma
|
||||
```
|
||||
|
||||
使用指定版本:
|
||||
|
||||
```text
|
||||
go get gitea.doicat.com/bot/snowluma@v1.0.0
|
||||
```
|
||||
|
||||
**私有仓库使用者**:如果仓库设为私有,除了给 Git 配置 Gitea 凭据外,还需设置:
|
||||
|
||||
```text
|
||||
set GOPRIVATE=gitea.doicat.com
|
||||
```
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 1. SnowLuma 侧配置
|
||||
|
||||
在 SnowLuma 的 OneBot 网络配置里按需启用一项(或多项):
|
||||
|
||||
| 配置方法 | SnowLuma 侧配置 |
|
||||
| --- | --- |
|
||||
| `SetForwardWS("ws://127.0.0.1:3001")` | 启用「正向 WebSocket」,端口 3001 |
|
||||
| `SetReverseWS(":8080")` | 启用「反向 WebSocket」,URL 填 `ws://<本机IP>:8080/` |
|
||||
| `SetHTTPAPI("http://127.0.0.1:3000")` | 启用「HTTP」,端口 3000 |
|
||||
| `SetHTTPReport(":8081")` | 启用「HTTP POST 上报」,地址填 `http://<本机IP>:8081/` |
|
||||
|
||||
若配置了 token,`SetToken` 填同一个值即可,框架会在 WS 握手(query + Authorization 头)和 HTTP 调用(Authorization 头)中自动携带;HTTP 上报场景若配了 secret,`SetSecret` 会自动校验 `X-Signature`(HMAC-SHA1)。
|
||||
|
||||
### 2. 完整示例
|
||||
|
||||
见 [example_test.go](./example_test.go) 的 `Example` 函数。
|
||||
|
||||
## 配置方法一览
|
||||
|
||||
| 方法 | 说明 |
|
||||
| --- | --- |
|
||||
| `SetToken(t)` | OneBot access_token,所有连接自动携带 |
|
||||
| `SetSecret(s)` | HTTP 上报 X-Signature 校验密钥 |
|
||||
| `SetLogger(l)` | 自定义 \*slog.Logger |
|
||||
| `SetForwardWS(urls...)` | 正向 WS 目标,可多个,重复调用替换 |
|
||||
| `SetReverseWS(addrs...)` | 反向 WS 监听地址,可多个,重复调用替换 |
|
||||
| `SetHTTPAPI(baseURL)` | HTTP API 地址 |
|
||||
| `SetHTTPReport(addrs...)` | HTTP 上报监听地址,可多个,重复调用替换 |
|
||||
| `Use(conn...)` | 注册自定义 Connector(高级扩展点) |
|
||||
|
||||
以上方法均返回 `*Client`,支持链式调用。请勿在 `Run` 之后修改配置。
|
||||
|
||||
## 事件处理
|
||||
|
||||
```go
|
||||
bot.OnEvent(fn) // 所有事件
|
||||
bot.OnMessage(fn) // 私聊 + 群聊消息(含 message_sent)
|
||||
bot.OnPrivateMessage(fn) // 私聊消息
|
||||
bot.OnGroupMessage(fn) // 群聊消息
|
||||
bot.OnNotice(fn) // 全部通知
|
||||
bot.OnNoticeType(t, fn) // 指定 notice_type
|
||||
bot.OnRequest(fn) // 好友/群请求
|
||||
bot.OnMeta(fn) // 心跳/生命周期
|
||||
bot.OnCommand(name, fn) // 文本命令,args 为空白切分的参数
|
||||
```
|
||||
|
||||
同一会话的事件**串行分发**(保序);handler 里的 panic 会被隔离并记录日志。
|
||||
|
||||
## Context 常用方法
|
||||
|
||||
| 方法 | 说明 |
|
||||
| --- | --- |
|
||||
| `Reply(msg...)` / `ReplyText(s)` | 回复当前消息(群聊/私聊自动判断) |
|
||||
| `Recall()` | 撤回当前消息 |
|
||||
| `Approve()` / `Reject(reason)` | 同意/拒绝当前的请求事件 |
|
||||
| `HasAtMe()` / `PlainText()` / `Segments()` | 消息内容判断 |
|
||||
| `IsGroup()` / `IsPrivate()` / `IsSelfMessage()` | 事件类型判断 |
|
||||
| `SendGroupMsg(nil, gid, ...)` 等 | 直接调用任意 API(ctx 传 nil 用默认 30s 超时) |
|
||||
| `Call(nil, action, params, &out)` | 裸调未收录的扩展 API |
|
||||
|
||||
## 消息段
|
||||
|
||||
```go
|
||||
snowluma.Text("hello")
|
||||
snowluma.At(12345) // snowluma.AtAll()
|
||||
snowluma.Image("C:/a.jpg") // 支持本地路径 / http(s) URL / base64://
|
||||
snowluma.Reply(678).With("text", "引用")
|
||||
snowluma.CustomNode(10001, "某人", []snowluma.Segment{snowluma.Text("...")})
|
||||
```
|
||||
|
||||
## 测试
|
||||
|
||||
```text
|
||||
go test ./...
|
||||
```
|
||||
|
||||
## 与 napcat 的差异
|
||||
|
||||
两包面向不同运行时(SnowLuma vs NapCatQQ),但都是 OneBot v11 + NapCat 兼容协议。协议层完全一致,方法名一一对应;能力覆盖上的差异体现在:
|
||||
|
||||
- **SnowLuma 独有**:闪传(flash)、Ark 卡片分享、群待办、群分类标签、群相册、QQ 空间、系统表情、流式文件上传/下载等扩展动作;本包在 `api_ext.go` 中提供类型化封装。
|
||||
- **napcat 有而 SnowLuma 可能未实现/改名**:个别 NapCat 私有动作(如 `ArkShareGroup` 这类大小写混合名)在 SnowLuma 中改用了标准名(`send_group_ark_share`),本包对这些动作做了别名适配,保证同名方法仍可用。
|
||||
|
||||
未收录到类型化方法里的动作,一律可通过 `Client.Call` / `Context.Call`(或 `CallAPI[T]` 泛型)裸调,因此能力差异不会卡住迁移。
|
||||
Reference in New Issue
Block a user