docs-matrix-spec/locales/zh-Hans/client-server-api/modules/threading.md
2025-04-20 16:13:37 +08:00

169 lines
No EOL
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

### 线程
{{% added-in v="1.4" %}}
线程允许用户在一个房间中以可视方式分支他们的对话。通常在线上讨论多个主题时使用,线程相较于传统的 [富回复](#rich-replies) 能够提供更有组织的交流方式,而富回复未必能够兼顾所有场景。
客户端应当在时间线上以区别于普通消息或回复的方式渲染线程,例如为线程提供一些上下文信息,但将完整的对话历史隐藏于可展开内容之后。
线程通过 `rel_type` 设为 `m.thread` 来建立,并引用 *线程根*(即该线程事件所指向的主时间线事件)。无法从本身已是事件关系子事件(即带有 `m.relates_to``rel_type` 属性的事件,参考 [关系类型](#relationship-types))创建线程。因此,线程也无法嵌套。
与富回复链不同,线程中的所有事件都引用线程根,而不是最新的消息。
下面通过示例展示线程及其形成方式:
```json
{
// 已省略无关字段
"type": "m.room.message",
"event_id": "$alice_hello",
"sender": "@alice:example.org",
"content": {
"msgtype": "m.text",
"body": "Hello world! How are you?"
}
}
```
```json
{
// 已省略无关字段
"type": "m.room.message",
"event_id": "$bob_hello",
"sender": "@bob:example.org",
"content": {
"m.relates_to": {
"rel_type": "m.thread",
"event_id": "$alice_hello"
},
"msgtype": "m.text",
"body": "I'm doing okay, thank you! How about yourself?"
}
}
```
```json
{
// 已省略无关字段
"type": "m.room.message",
"event_id": "$alice_reply",
"sender": "@alice:example.org",
"content": {
"m.relates_to": {
"rel_type": "m.thread",
"event_id": "$alice_hello" // 注意:始终指向 *线程根*
},
"msgtype": "m.text",
"body": "I'm doing great! Thanks for asking."
}
}
```
如上所示,任何没有 `rel_type` 的事件都可以仅通过 `m.thread` 关系被引用来成为线程根。
#### 非线程化客户端的回退机制
能够理解线程的客户端应直接以线程方式处理,但某些客户端(出于历史原因或功能范围限制)可能无法向用户有效展现对话历史。
为此,支持线程的客户端发送事件时应包含 [富回复](#rich-replies) 元数据,以尝试形成对话的回复链。这种方式在高线程活跃房间中并不理想,但可以为用户提供与房间内其他消息相关的上下文信息。
该兼容方式通过合并两种关系并为 `is_falling_back` 标记设为 `true` 实现。
```json
// 在事件内容中……
"m.relates_to": {
// m.thread 关系结构
"rel_type": "m.thread",
"event_id": "$root",
// 富回复结构
"m.in_reply_to": {
// 线程中客户端已知的最新消息,应选取其他客户端有较大渲染概率的事件,
// 如 `m.room.message` 事件。
"event_id": "$target"
},
// 标记此事件为带回复回退的线程
"is_falling_back": true
}
```
{{% boxes/note %}}
对于对线程有一定感知(即不直接渲染线程、但知道规范中有该功能)的客户端,可以将对带有 `rel_type``m.thread` 事件的富回复视作线程内部的回复,以实现线程客户端侧的对话连续性。
实现方法为:从被回复事件中复制出 `event_id`(线程根),添加 `m.in_reply_to` 元数据,并在 `m.relates_to` 中加入 `is_falling_back: true`
{{% /boxes/note %}}
#### 线程内的回复
在 [非线程化客户端的回退机制](#fallback-for-unthreaded-clients) 部分,为 `m.relates_to` 新增了 `is_falling_back` 字段。当未提供该字段时,默认为 `false`,这同样允许线程消息本身作为回复。
除了 `is_falling_back``false`(或未指定)以外,客户端应利用非线程化客户端的回退机制在线程内创建回复,并据此渲染事件。
#### 服务器行为
##### `m.thread` 关系的验证
服务器应拒绝客户端针对带有 `m.relates_to` 属性的事件尝试发起线程的请求。如果客户端试图对带有 `m.relates_to` 属性的事件作为目标事件,则应返回 HTTP 400 错误及相应错误信息,按照 [标准错误响应](#standard-error-response) 结构处理。
{{% boxes/note %}}
此种情况目前没有单独的错误码:服务器应与 HTTP 400 一同返回 `M_UNKNOWN`
{{% /boxes/note %}}
##### 服务器侧对 `m.thread` 关系的聚合
由于线程总是引用线程根,一个事件将拥有多个“子事件”,共同组成该线程。服务器应对这些事件进行 [聚合](#aggregations-of-child-events)。
线程聚合的数据包括用户在该线程中的参与情况、线程(服务器已知范围内)大致的事件数量,以及线程内最新(按服务器视角的拓扑顺序)的一条消息。
与任何其他子事件聚合一样,`m.thread` 聚合结果通过 `unsigned` 下的 `m.relations` 属性返回给线程根。例如:
```json
{
"event_id": "$root_event",
// 未显示无关字段
"unsigned": {
"m.relations": {
"m.thread": {
"latest_event": {
// 线程中最新事件的序列化副本。
// 部分字段为简化未示出。
"event_id": "$message",
"sender": "@alice:example.org",
"room_id": "!room:example.org",
"type": "m.room.message",
"content": {
"msgtype": "m.text",
"body": "Woo! Threads!"
},
"unsigned": {
"m.relations": {
// ...
}
}
},
"count": 7,
"current_user_participated": true
}
}
}
}
```
`latest_event` 为线程中由未被[忽略的用户](#ignoring-users)发送,服务器视拓扑顺序最新的一条事件。
注意,正如上例,`latest_event` 的子事件本身也需被聚合并包含在该事件下的 `m.relations` 下。服务器需注意避免形成循环,尽管由于 `m.thread` 不允许指向带有 `m.relates_to` 属性的事件,目前不可能产生循环。
`count` 仅指向目标事件的 `rel_type``m.thread` 的事件数量,未包含[被忽略用户](#ignoring-users)发送的事件。
`current_user_participated``true` 时,表明认证用户满足以下任一条件:
1. 是线程根事件的 `sender`
2. 是某个引用线程根且 `rel_type``m.thread` 的事件的 `sender`
#### 查询房间内线程
客户端如需获取某线程内的所有事件,可通过
[`GET /relations/{threadRootId}/m.thread`](#get_matrixclientv1roomsroomidrelationseventidreltype)
如需获取某房间内所有线程,则需专用 API
{{% http-api spec="client-server" api="threads_list" %}}