Skip to content

Commit

Permalink
fix anchors
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed Jan 22, 2024
1 parent 7775646 commit b988241
Show file tree
Hide file tree
Showing 6 changed files with 29 additions and 28 deletions.
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,18 @@
"devDependencies": {
"@cordisjs/vitepress": "^3.2.4",
"@intlify/unplugin-vue-i18n": "^1.5.0",
"@koishijs/components": "^1.5.6",
"@koishijs/core": "^4.16.4",
"@koishijs/components": "^1.5.7",
"@koishijs/core": "^4.16.6",
"@koishijs/dns": "^1.0.1",
"@koishijs/market": "^4.2.3",
"@koishijs/registry": "^7.0.0",
"@koishijs/registry": "^7.0.1",
"@types/node": "^20.10.2",
"@types/spark-md5": "^3.0.4",
"@vueuse/core": "^10.6.1",
"cross-env": "^7.0.3",
"element-plus": "2.4.0",
"esbuild-register": "^3.5.0",
"koishi": "^4.16.4",
"koishi": "^4.16.6",
"markdown-it-mathjax3": "^4.3.2",
"marked-vue": "^1.3.0",
"typescript": "^5.3.2",
Expand Down
2 changes: 1 addition & 1 deletion zh-CN/api/message/elements.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ hello<message/>world

交互元素用于显然消息中的可交互性内容。如果平台不支持此类元素且难以提供回退,可以直接忽略整个元素。实现侧应当根据平台特性,针对性地返回带有交互和不带有交互的消息。

### 按钮 (button) {#button} <badge type="warning">实验性</badge>
### 按钮 (button) <badge type="warning">实验性</badge> {#button}

- **id:** `string` 按钮的 ID
- **type:** `string` 按钮的类型
Expand Down
16 changes: 8 additions & 8 deletions zh-CN/guide/adapter/adapter.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

我们已经知道,单独一个 `Bot` 类已经构成一个合法的插件了。不过,这样的插件只具备调用平台 API 的能力,还无法接收消息。这个时候就需要 `Adapter` 类出场了。

## 适配器的类型
## 适配器的类型 {#types}

适配器需要建立并维护机器人与聊天平台之间的连接。通常来说,根据协议的不同,适配器与机器人可能是一对一的,也可能是一对多的。让我们再看一眼之前介绍过的 `ReplBot` 实例:

Expand All @@ -23,11 +23,11 @@ class ReplBot<C extends Context> extends Bot<C> {

简单来说就是,在实现适配器时,首先需要协议的类型确定适配器与机器人的对应关系。如果是一对一的,就需要声明 `reusable` 属性,否则不需要声明。此外,对于部分典型场景,我们又进一步派生出了 `Adapter.WsClient` 等子类,方便你快速实现适配器。

## 典型实现
## 典型实现 {#typical-impls}

下面让我们看几种典型的适配器实现。

### WebSocket
### WebSocket {#websocket}

一种常见的通信方式是 WebSocket,许多平台 (Discord、KOOK、钉钉等) 都会使用这项技术。它的工作原理是,机器人首先向聊天平台的 WebSocket 网关发起连接请求,随后平台会将事件推送到机器人的 WebSocket 连接上。这里我们还是以 Discord 平台为例:

Expand Down Expand Up @@ -86,7 +86,7 @@ if (session) this.dispatch(session)

`createSession()` 会根据事件的类型,创建不同的 `Session` 实例。如果无法对应到标准的会话事件,那么 `createSession()` 方法会返回空值,表示我们不需要调用 `dispatch()` 方法。

### Webhook
### Webhook {#webhook}

另一种常见的通信方式是 Webhook,使用这种通信方式的平台有飞书、企业微信、Line 等。它的工作原理是,机器人搭建者首先在聊天平台的开发者后台配置一个 HTTP 服务器地址,随后平台会将事件推送到该地址上。这里我们以 Line 平台为例:

Expand Down Expand Up @@ -147,7 +147,7 @@ for (const event of parsed.events) {
}
```

### 其他通信方式
### 其他通信方式 {#others}

除了 WebSocket 和 Webhook 以外,还有一些其他可能出现的通信方式:

Expand All @@ -156,11 +156,11 @@ for (const event of parsed.events) {

当然,对于那些不太像聊天平台的聊天平台,你也可以不必拘泥于传统的通信方式。直接继承 `Adapter` 基类,实现自己的逻辑即可。无论是我们在本章开始介绍的命令行环境,又或者是邮件、短信,甚至是社交媒体的评论区、私信,只要是能打字的地方,都可以通过适配器的方式接入到 Koishi 中!

## 进阶技巧
## 进阶技巧 {#advanced}

接下来我们将介绍一些复杂适配器的实现技巧。

### 多协议支持
### 多协议支持 {#multi-protocol}

部分平台同时支持了多种通信方式,例如 Telegram 就同时支持了 Webhook 和 HTTP 轮询。对于此类平台,我们可以提供一个配置项,让用户根据需要自行选择通信方式。

Expand Down Expand Up @@ -243,7 +243,7 @@ namespace TelegramBot {
}
```

### 动态创建机器人
### 动态创建机器人 {#dynamic}

到此为止,我们的适配器开发中都存在一个隐含限制:用户的一次插件加载只能对应于一个 `Bot` 实例。如果用户需要创建多个机器人,那么就需要多次加载插件。这是因为在绝大多数适配器的使用场景下,用户都能很明确地知道自己需要创建多少个机器人。然而总有一些例外情况:

Expand Down
4 changes: 2 additions & 2 deletions zh-CN/guide/adapter/integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

至此,Koishi 的适配器开发已经接近尾声。经过前面的几节内容,我们的适配器已经封装了平台接口,与服务器稳定地进行连接,并能够顺利地接受和发送消息。但除此以外,部分平台还提供了一些额外的能力,允许机器人做得更好。Koishi 当然也要把这些能力集成到机器人中。

## 斜线指令
## 斜线指令 {#slash-command}

::: tip
相关章节:[指令开发](../basic/command.md)
Expand All @@ -24,7 +24,7 @@ class DiscordBot {
}
```

## 用户语言偏好
## 用户语言偏好 {#user-locale}

::: tip
相关章节:[多语言支持](../i18n/index.md)
Expand Down
22 changes: 11 additions & 11 deletions zh-CN/guide/adapter/message.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const encodeGuild = (data: Universal.Guild): Discord.Guild => ({

Koishi 使用 [消息元素](../basic/element.md) 表达任何聊天平台的消息。这是一种类似于 HTML 的格式。消息元素作为组成消息的基本单位,可以表示具有特定语义的内容,如文本、表情、图片、引用、元信息等。本节将介绍如何在消息元素与平台消息之间互相转换。

## 接收消息
## 接收消息 {#receive}

在会话对象上存在两个属性与消息的内容有关:`content``elements`,它们分别对应着字符串形式和消息元素形式的消息内容。它们之间会自动转换,因此下面的两种写法是等价的:

Expand All @@ -41,9 +41,9 @@ session.elements = [
session.content = input.replace(/@(\d+)/g, '<at id="$1"/>')
```

## 发送消息
## 发送消息 {#send}

### 兼容性原则
### 兼容性原则 {#compatibility}

在具体介绍消息发送之前,不知道你是否有这样的疑问:Koishi 提供了一整套标准的消息元素,但并非所有平台都支持这些元素。对于那些不支持的元素,应该如何处理呢?

Expand All @@ -59,7 +59,7 @@ Koishi 的建议是**尽量兼容实现**。对于平台不支持的元素,可

对于更加复杂的元素,适配器也可以发挥自主性,设计最适合的交互形式。例如,如果用户的需求是「从若干个选项中选择一个」,那么平台 A 可以渲染出多个按钮供用户点击;平台 B 则可以发送一条带有表态的消息,点击表态对应选择选项;实在不行,平台 C 也可以直接发送选项列表和文本提示语,并将用户的下一次输入作为选项。

### 消息编码器
### 消息编码器 {#encoder}

之前介绍过的 REPL 适配器为了简化写法,并未包含消息的编码过程。对于一般的适配器,我们建议通过继承 `MessageEncoder` 类来实现消息的发送逻辑。

Expand Down Expand Up @@ -128,7 +128,7 @@ export class TelegramBot<C extends Context> extends Bot<C, TelegramBot.Config> {
}
```

### 行内元素
### 行内元素 {#inline}

上面的例子仅仅包含了消息编码器的基本结构,并未实现除了文本外的任何消息元素。对于任何非文本元素,上面的代码都会回退到其内部的文本。要添加更多消息元素的支持,只需在 `visit` 方法中添加更多的判断分支,就像这样:

Expand All @@ -148,7 +148,7 @@ if (type === 'text') {
}
```

### 消息分片
### 消息分片 {#fragment}

在 Koishi 中,一次消息发送可能在目标平台产生多条独立的消息,称为消息分片。这也是为什么上面的 `results` 是一个数组。消息分片产生的原因是多样的:

Expand All @@ -168,7 +168,7 @@ if (type === 'text') {
} else ...
```

### 资源元素
### 资源元素 {#asset}

由于不同平台对于媒体资源的支持类型、发送方式、渲染形式有所不同,因此资源元素的情况会更加复杂。可以大致将各种平台规定的发送方式分为以下几类:

Expand Down Expand Up @@ -224,11 +224,11 @@ class TelegramMessageEncoder<C extends Context> extends MessageEncoder<C, Telegr

差不多这样就实现了资源元素的发送。值得一提的是,这里的代码使用了 `http.file()` 方法。它可以自动为我们处理 `http:``file:``data:` 等各种协议的资源链接,并将它们统一转换为 `ArrayBuffer`。这可以省去适配器解析资源链接的步骤,对于适配器开发是非常方便的。

## 进阶知识
## 进阶知识 {#advanced}

下面的知识并非适用于所有适配器。但对于一些特殊的平台,你可能会用到它们。

### 发送被动消息
### 发送被动消息 {#passive}

我们通常将机器人做出的交互行为分为两种:主动交互和被动交互。

Expand All @@ -252,7 +252,7 @@ class QQGuildMessageEncoder {

在这一段代码中使用了 `this.options`,它存储了一些额外的发送选项。其中 `session` 正好对应着接收到消息的会话对象。当我们调用 `session.send()` 时,Koishi 会把当前的会话对象传递给 `MessageEncoder`。这样一来,我们就可以在发送消息时带上回复目标了。

### 资源反向代理
### 资源反向代理 {#reverse-proxy}

一些平台会使用 ID 标识资源文件 (例如 Lark)。当你接收到来自平台的消息时,拿到的是资源 ID 而非资源链接。此时你需要将资源 ID 转换为资源链接,才能构造合法的资源元素。

Expand Down Expand Up @@ -303,7 +303,7 @@ h.image(`http://${host}/image/${message_id}/${image_key}?self_id=${selfId}`)
反向代理同时也带来了一个新的问题,那就是当这个链接被原样发送时,外网可能无法访问到这个链接。但无需担心,上面提到的 `http.file()` 方法恰好可以解决这个问题。因此,即使经过了反向代理,Koishi 也可以确保消息的跨平台转发插件能够正常工作。
:::

### 扩展消息元素
### 扩展消息元素 {#extension}

平台可以提供扩展消息元素,但需要加上平台通用名称作为前缀。下面是一个例子:

Expand Down
5 changes: 3 additions & 2 deletions zh-CN/manual/recipe/search.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,15 @@ Koishi 有着丰富的插件生态。为了让用户更方便地搜索插件,

- <market-icon name="solid:core" />`category:core`:核心功能
- <market-icon name="solid:adapter" />`category:adapter`:适配器
- <market-icon name="solid:storage" />`category:storage`:存储服务
- <market-icon name="solid:general" />`category:general`:存储服务
- <market-icon name="solid:extension" />`category:extension`:扩展功能
- <market-icon name="solid:console" />`category:console`:控制台
- <market-icon name="solid:webui" />`category:webui`:控制台
- <market-icon name="solid:manage" />`category:manage`:管理工具
- <market-icon name="solid:preset" />`category:preset`:行为预设
- <market-icon name="solid:image" />`category:image`:图片服务
- <market-icon name="solid:media" />`category:media`:资讯服务
- <market-icon name="solid:tool" />`category:tool`:实用工具
- <market-icon name="solid:life" />`category:life`:生活指南
- <market-icon name="solid:ai" />`category:ai`:人工智能
- <market-icon name="solid:meme" />`category:meme`:趣味交互
- <market-icon name="solid:game" />`category:game`:娱乐玩法
Expand Down

0 comments on commit b988241

Please sign in to comment.