From 5d4682449ab8c342af7b323e1fa585e21205869f Mon Sep 17 00:00:00 2001 From: Shigma Date: Thu, 3 Oct 2024 21:57:24 +0800 Subject: [PATCH] platform vs. adapter --- .vitepress/config/zh-CN.json | 6 +++--- .vitepress/theme/index.scss | 4 ++++ zh-CN/advanced/internal.md | 34 +++++++++++++++++++++++----------- zh-CN/resources/login.md | 16 ++++++++-------- zh-CN/resources/user.md | 2 +- 5 files changed, 39 insertions(+), 23 deletions(-) diff --git a/.vitepress/config/zh-CN.json b/.vitepress/config/zh-CN.json index 8330cc3..b6a6341 100644 --- a/.vitepress/config/zh-CN.json +++ b/.vitepress/config/zh-CN.json @@ -32,9 +32,9 @@ }, { "text": "进阶", "items": [ - { "text": "资源文件", "link": "/advanced/resource.md" }, - { "text": "管理接口", "link": "/advanced/admin.md" }, - { "text": "内部接口", "link": "/advanced/internal.md" } + { "text": "跨平台", "link": "/advanced/internal.md" }, + { "text": "资源链接", "link": "/advanced/resource.md" }, + { "text": "管理接口", "link": "/advanced/admin.md" } ] }] } diff --git a/.vitepress/theme/index.scss b/.vitepress/theme/index.scss index a8e73a5..fcd6a9b 100644 --- a/.vitepress/theme/index.scss +++ b/.vitepress/theme/index.scss @@ -13,3 +13,7 @@ blockquote.route { border-bottom-left-radius: 0; } } + +.vp-doc sup a { + text-decoration: none; +} diff --git a/zh-CN/advanced/internal.md b/zh-CN/advanced/internal.md index 3462dc4..89bc202 100644 --- a/zh-CN/advanced/internal.md +++ b/zh-CN/advanced/internal.md @@ -1,13 +1,27 @@ -# 内部接口 可选 +# 跨平台 -::: tip -这是一个可选功能。 -::: - -Satori 提供了访问任意平台原生接口的能力。这意味着,你可以大多数情况下编写通用代码,并在需要的时候使用原生接口来实现平台特定功能。 +作为一个跨平台的聊天协议,Satori 提供了访问任意平台原生接口的能力。这意味着,你可以大多数情况下编写通用代码,并在需要的时候使用原生接口来实现平台特定功能。 这些原生 API 和事件被统称为内部接口。你可以名为 `internal` 的路由或事件来访问它们。 +## 平台与适配器 {#platform-adapter} + +Satori 协议的大多数 API 都需要传入 `Satori-Platform` 和 `Satori-User-ID` 请求头,这是为了区分发起请求的登录号。不同平台的登录号拥有不同的 `login.platform`,而同一平台的不同登录号则拥有不同的 `login.user.id`,由此这套机制实现了安全的隔离。 + +大多数聊天平台的 `platform` 字段都是直接由 SDK 设置的固定值。然而对于另一些允许自建的平台 (例如 Rocket Chat 和 Zulip),SDK 则通常需要让部署者自行设置 `platform`,用来区分不同的服务器。如果直接混用的话,可能导致数据碰撞等问题。 + +所以对于任何一个 Login,我们实际上存在两个不同的概念: + +- `login.platform`:聊天平台。通常来说,同一平台内的用户间具有相互发送消息的能力,而不同平台的用户间则没有。在 Satori 中,`platform` 也相当于一种命名空间,因此 SDK 需要保证同一平台内的 `user.id`, `guild.id` 等字段的唯一性。 + +- `login.adapter`:适配器。适配器更多地是一个实现相关的概念,它决定了如何与平台进行通信。同一个适配器下通常会有相同的扩展 API、事件和消息元素。这个字段通常是 SDK 直接设置的,开发者可以用这个字段判断实现是否支持某些特性。 + +需要注意的是,这两个概念实际上是多对多的,我们可以举出一些特殊场景: + +- **单适配器多平台**:某平台允许用户自建服务器,此时两台独立的自建服务器拥有不同的数据,所有的 `user.id`, `guild.id` 等属于不同的命名空间,因此 `platform` 字段应该是不同的。但这两台服务器使用的通信方式相同,因此 `adapter` 字段应该是相同的。 + +- **单平台多适配器**:某平台同时有官方和非官方的 SDK,两套 SDK 使用的通信方式不同,因此 `adapter` 字段应该是不同的。但这两套 SDK 都是为了与同一平台通信,所有的 `user.id`, `guild.id` 等属于同一个命名空间,因此 `platform` 字段应该是相同的。 + ## API 扩展 SDK 可以通过 `/{path}/{version}/internal/{method}` 路由代理平台原生 API。通信方式与 [HTTP API](../protocol/api.md) 类似。返回值与平台返回值一致。 @@ -34,9 +48,7 @@ SDK 可以通过 `internal` 事件的 `_type` 和 `_data` 属性代理平台原 | --- | --- | --- | | `id` | number | 事件 ID | | `type` | string | 事件类型 (固定为 `internal`) | -| `platform` | string | 接收者的平台名称 | -| `self_id` | string | 接收者的平台账号 | -| `timestamp` | number | 事件的时间戳 | +| `login` | [Login](../resources/login.md) | 登录信息 | | `_type` | string | 原生事件类型 | | `_data` | object | 原生事件数据 | @@ -59,7 +71,7 @@ SDK 可以通过 `internal` 事件的 `_type` 和 `_data` 属性代理平台原 ### 平台原生消息元素 -平台可以提供原生消息元素,但需要加上平台通用名称作为前缀。下面是一个例子: +平台可以提供原生消息元素,但需要加上适配器名称作为前缀。下面是一个例子: ```html @@ -69,7 +81,7 @@ SDK 可以通过 `internal` 事件的 `_type` 和 `_data` 属性代理平台原 ### 标准元素的扩展属性 -标准元素的平台原生属性也可以通过加上平台通用名称作为前缀的方式声明。下面是一个例子: +标准元素的平台原生属性也可以通过加上适配器名称作为前缀的方式声明。下面是一个例子: ```html diff --git a/zh-CN/resources/login.md b/zh-CN/resources/login.md index 2147122..d42b56d 100644 --- a/zh-CN/resources/login.md +++ b/zh-CN/resources/login.md @@ -6,14 +6,14 @@ | 字段 | 类型 | 描述 | | --- | --- | --- | -| user | [User](./user.md)? | 用户对象 | -| self_id | string? | 平台账号 | -| platform | string? | 平台名称 | -| status | [Status](#status) | 登录状态 | -| features | string[] | [平台特性](../protocol/api.md#平台特性) 列表 | -| proxy_urls | string[] | [代理路由](../advanced/resource.md#proxy-route) 列表 | - -### Status +| `adapter` | string | [适配器名称](../advanced/internal.md#platform-adapter) | +| `platform` | string? | 平台名称 | +| `user` | [User](./user.md)? | 用户对象 | +| `status` | [LoginStatus](#loginstatus)? | 登录状态 | +| `features` | string[]? | [平台特性](../protocol/api.md#平台特性) 列表 | +| `proxy_urls` | string[]? | [代理路由](../advanced/resource.md#proxy-route) 列表 | + +### LoginStatus | 名称 | 值 | 描述 | | --- | --- | --- | diff --git a/zh-CN/resources/user.md b/zh-CN/resources/user.md index d8bb9e7..25d44f5 100644 --- a/zh-CN/resources/user.md +++ b/zh-CN/resources/user.md @@ -13,7 +13,7 @@ | is_bot | boolean? | 是否为机器人 | ::: tip -**[1] 关于 `name` 和 `nick` 字段的区别** {#name-nick} +**[1] `name` 和 `nick` 字段的区别** {#name-nick} 这两个字段都可以用于标识用户。在一些平台上 (例如 Telegram),一个用户存在多种不同概念的名称,因此 SDK 可以同时设置这两个字段。而另一些平台可能不存在这两个概念的对立关系,此时 SDK 只需要根据语义设置 `name` 或 `nick` 中的一个即可。