nonebot-adapter-matrix 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,271 @@
1
+ Metadata-Version: 2.4
2
+ Name: nonebot-adapter-matrix
3
+ Version: 0.2.0
4
+ Summary: Matrix adapter for nonebot2
5
+ Keywords: nonebot,matrix,bot
6
+ Author: CMHopeSunshine, yanyongyu, scdhh
7
+ Author-email: CMHopeSunshine <277073121@qq.com>, yanyongyu <yyy@nonebot.dev>, scdhh <wallfjjd@gmail.com>
8
+ License-Expression: MIT
9
+ Requires-Dist: nonebot2>=2.4.4
10
+ Requires-Dist: requests-oauth2client>=1.8.0
11
+ Requires-Python: >=3.10, <4.0.0
12
+ Project-URL: homepage, https://github.com/nonebot/adapter-matrix
13
+ Project-URL: repository, https://github.com/nonebot/adapter-matrix
14
+ Project-URL: documentation, https://github.com/nonebot/adapter-matrix
15
+ Description-Content-Type: text/markdown
16
+
17
+ <p align="center">
18
+ <a href="https://nonebot.dev/"><img src="assets/logo.svg" width="200" height="200" alt="nonebot-adapter-discord"></a>
19
+ </p>
20
+
21
+ <div align="center">
22
+
23
+ # NoneBot-Adapter-Matrix
24
+
25
+ _✨ Matrix Client-Server 协议适配 ✨_
26
+
27
+ </div>
28
+
29
+ ## 安装
30
+
31
+ ```bash
32
+ pip install nonebot-adapter-matrix
33
+ ```
34
+ 开发版本可从当前仓库构建安装:
35
+
36
+ ```bash
37
+ pip install git+https://github.com/elysia-best/adapter-matrix.git@master
38
+ ```
39
+
40
+ ## 配置
41
+
42
+ Matrix adapter 使用 Client-Server API 与 homeserver 通信,需要可发起 HTTP 请求的 NoneBot ForwardDriver。
43
+
44
+ ```dotenv
45
+ DRIVER=~httpx
46
+ ```
47
+
48
+ ### 三种启动模式
49
+
50
+ 适配器支持三种 token 管理模式:
51
+
52
+ #### 1. 静态 token 模式(兼容模式)
53
+
54
+ 适合已有 access token 的场景。不会自动获取或刷新 token。
55
+
56
+ ```dotenv
57
+ MATRIX_BOTS='[
58
+ {
59
+ "homeserver": "https://matrix.example.org",
60
+ "access_token": "YOUR_ACCESS_TOKEN",
61
+ "user_id": "@bot:example.org"
62
+ }
63
+ ]'
64
+ ```
65
+
66
+ 注意:此模式下如果没有额外提供登录凭据或 OAuth2 配置,协议上无法自动获取首个 refresh token。access token 过期后需要手动更新配置。
67
+
68
+ #### 2. 传统 Matrix 登录模式
69
+
70
+ 提供登录凭据,适配器启动时自动调用 `/login` 获取 token 对,并在需要时自动 refresh。
71
+
72
+ ```dotenv
73
+ MATRIX_BOTS='[
74
+ {
75
+ "homeserver": "https://matrix.example.org",
76
+ "access_token": "",
77
+ "login_user": "@bot:example.org",
78
+ "login_password": "your-password",
79
+ "device_id": "BOTDEVICE",
80
+ "set_presence": "online"
81
+ }
82
+ ]'
83
+ ```
84
+
85
+ - `login_user`:Matrix 用户 ID,用于 `/login` 请求。
86
+ - `login_password`:Matrix 账户密码。
87
+ - `login_initial_device_display_name`:可选;初始设备显示名称。
88
+ - 登录成功后会自动设置 `session_type: "legacy_login"`,后续 refresh 走 `/_matrix/client/v3/refresh`。
89
+ - 若 refresh 返回 `soft_logout: true`,适配器会自动用密码重新登录。
90
+
91
+ #### 3. OAuth2 模式
92
+
93
+ 通过 OAuth2 Authorization Code + PKCE 登录,适合支持 Matrix next-gen auth / OIDC 的 homeserver。
94
+
95
+ 最小配置:
96
+
97
+ ```dotenv
98
+ MATRIX_BOTS='[
99
+ {
100
+ "homeserver": "https://matrix.example.org",
101
+ "access_token": "",
102
+ "oauth_enabled": true,
103
+ "oauth_server_url": "https://account.matrix.org",
104
+ "oauth_open_browser": true
105
+ }
106
+ ]'
107
+ ```
108
+
109
+ 也可以手动指定已注册的 client:
110
+
111
+ ```dotenv
112
+ MATRIX_BOTS='[
113
+ {
114
+ "homeserver": "https://matrix.example.org",
115
+ "access_token": "",
116
+ "oauth_enabled": true,
117
+ "oauth_server_url": "https://account.matrix.org",
118
+ "oauth_client_id": "your-client-id",
119
+ "oauth_redirect_uri": "https://your-app.example/callback"
120
+ }
121
+ ]'
122
+ ```
123
+
124
+ - `oauth_enabled`:启用 OAuth2 登录流程。
125
+ - `oauth_server_url`:可选;直接指定 OAuth2/OIDC server 根地址,例如 `https://account.matrix.org`。若未提供,会优先尝试 Matrix `/_matrix/client/v1/auth_metadata` 自动发现。
126
+ - `oauth_metadata_url`:可选;直接指定 metadata 文档地址,优先级高于 `oauth_server_url`。
127
+ - `oauth_client_id`:可选;若未提供且 server 暴露 `registration_endpoint`,适配器会自动注册一个 OAuth2 client 并持久化保存。
128
+ - `oauth_client_uri`:可选;动态注册时写入 client metadata。某些 Matrix Authentication Service(例如 matrix.org)要求该字段存在;未配置时默认使用 `homeserver` 作为回退值。需要注意这里需要填写有效的域名
129
+ - `oauth_redirect_uri`:可选;若不提供,则默认使用 loopback 回调并自动选择一个可用随机端口。若提供 localhost / `127.0.0.1` 回调地址,则必须显式写出端口,且注册、授权、换 token 全程使用该 URI 原样值;若想用自动随机端口,请直接省略 `oauth_redirect_uri`。若提供外部回调地址,则需要手动复制授权结果中的 `code` 或完整回调 URL 到终端。
130
+ - `oauth_scope`:可选;默认会构造符合 MSC2967 的 scope,并自动补上 `urn:matrix:org.matrix.msc2967.client:device:{DEVICE_ID}`;若你自定义 scope,适配器仍会补 device scope。
131
+ - `oauth_device_id`:可选;指定请求的 Matrix device ID。未提供时会自动生成一个 12 位的大写字母数字 ID。
132
+ - `oauth_open_browser`:是否自动打开浏览器访问授权 URL,默认 `false`。
133
+ - `oauth_callback_timeout`:等待回调的超时时间(秒),默认 `300`。
134
+
135
+ OAuth2 登录流程:
136
+ 1. 适配器按如下顺序发现元数据:`oauth_metadata_url` → `/_matrix/client/v1/auth_metadata`(及其 unstable MSC2965 端点)→ `oauth_server_url` 兜底。
137
+ 2. 校验 server 支持 `response_type=code`、`response_mode=fragment` 和 PKCE `S256`。
138
+ 3. 若未配置 `oauth_client_id`,则通过 metadata 返回的 `registration_endpoint` 自动注册 client。
139
+ 4. 生成 device ID、`state`、`code_verifier`/`code_challenge`,并构造符合 MSC2967 的 scope。
140
+ 5. 输出授权 URL(若 `oauth_open_browser: true` 则自动打开浏览器)。
141
+ 6. 获取 authorization code 并交换首个 access/refresh token。
142
+ 7. 后续 refresh 走 metadata 返回的 OAuth2 token endpoint(`grant_type=refresh_token`)。
143
+
144
+ ### 通用字段
145
+
146
+ ```dotenv
147
+ MATRIX_BOTS='[
148
+ {
149
+ "homeserver": "https://matrix.example.org",
150
+ "access_token": "YOUR_ACCESS_TOKEN",
151
+ "refresh_token": "OPTIONAL_REFRESH_TOKEN",
152
+ "access_token_expires_at_ms": 1760000000000,
153
+ "refresh_before_expiry_ms": 60000,
154
+ "user_id": "@bot:example.org",
155
+ "device_id": "BOTDEVICE",
156
+ "sync_filter": {"room": {"timeline": {"limit": 50}}},
157
+ "set_presence": "online"
158
+ }
159
+ ]'
160
+ ```
161
+
162
+ - `homeserver`:Matrix homeserver 根地址(必填)。
163
+ - `access_token`:当前使用的 Matrix access token(使用登录模式时可留空)。
164
+ - `refresh_token`:通常由登录流程获得,不要求手动填写。持久化到 `MATRIX_TOKEN_STORE_PATH` 后会自动加载。
165
+ - `access_token_expires_at_ms`:当前 access token 的绝对过期时间戳,单位毫秒。
166
+ - `refresh_before_expiry_ms`:距离过期多久前主动 refresh,默认 `60000`(1 分钟)。
167
+ - `user_id`:启动时通过 `/account/whoami` 校验 token 所属用户。
168
+ - `device_id`:记录当前 token 对应的 Matrix 设备 ID。
169
+ - `sync_filter`:传给 `/sync` 的 filter id 或 filter JSON。
170
+ - `set_presence`:`online`、`offline` 或 `unavailable`。
171
+
172
+ ### 其他配置
173
+
174
+ ```dotenv
175
+ MATRIX_API_TIMEOUT=30.0
176
+ MATRIX_SYNC_TIMEOUT=30000
177
+ MATRIX_RETRY_INTERVAL=3.0
178
+ MATRIX_HANDLE_SELF_MESSAGE=false
179
+ MATRIX_HANDLE_OLD_EVENTS=false
180
+ MATRIX_PROXY='http://127.0.0.1:7890'
181
+ MATRIX_TOKEN_STORE_PATH='.data/matrix-tokens.json'
182
+ ```
183
+
184
+ - `MATRIX_API_TIMEOUT`:普通 API 请求超时时间,单位秒。
185
+ - `MATRIX_SYNC_TIMEOUT`:`/sync` long-poll 超时时间,单位毫秒。
186
+ - `MATRIX_RETRY_INTERVAL`:网络错误后的重试间隔,单位秒。
187
+ - `MATRIX_HANDLE_SELF_MESSAGE`:是否处理机器人自己发送的消息。
188
+ - `MATRIX_HANDLE_OLD_EVENTS`:是否处理早于本次启动时间的旧事件,默认丢弃旧事件。
189
+ - `MATRIX_PROXY`:可选 HTTP 代理。
190
+ - `MATRIX_TOKEN_STORE_PATH`:可选 token 状态文件路径;配置后会将 token 持久化到该文件,重启时自动加载。
191
+
192
+ ### Refresh Token 行为
193
+
194
+ - 启动时若配置了 `MATRIX_TOKEN_STORE_PATH`,会优先读取状态文件中的最新 token 和 `session_type`。
195
+ - access token 接近 `access_token_expires_at_ms` 时,会在下一次 `/sync` 前主动 refresh。
196
+ - 若 homeserver 提前使当前 token 失效并返回 `M_UNKNOWN_TOKEN`,adapter 会尝试使用 refresh token 恢复。
197
+ - **refresh 失败语义**:
198
+ - 网络错误或 5xx:保留旧 refresh token,稍后重试。
199
+ - 4xx 且带 `soft_logout: true`:若配置了 `login_password`,自动重新登录。
200
+ - 4xx 无 `soft_logout`:视为会话失效,等待重试。
201
+ - refresh 成功后更新内存中的 `access_token`、`refresh_token`、`access_token_expires_at_ms`,并写回状态文件。
202
+ - adapter 不会回写 `.env` 或其他部署配置;`/sync` 的 `next_batch` 仍然不会持久化。
203
+
204
+ ## 插件示例
205
+
206
+ ```python
207
+ from nonebot import on_command
208
+ from nonebot.params import CommandArg
209
+
210
+ from nonebot.adapters.matrix import Bot, Message, MessageEvent, MessageSegment
211
+
212
+ matcher = on_command("echo")
213
+
214
+
215
+ @matcher.handle()
216
+ async def handle_echo(bot: Bot, event: MessageEvent, msg: Message = CommandArg()):
217
+ text = msg.extract_plain_text()
218
+ if text == "mention":
219
+ await matcher.finish(MessageSegment.mention_user(event.get_user_id()))
220
+ if text == "notice":
221
+ await matcher.finish(MessageSegment.notice("这是一条 Matrix notice"))
222
+ await bot.send(event, MessageSegment.text(text or "hello matrix"))
223
+ ```
224
+
225
+ ### 发送媒体
226
+
227
+ Matrix 媒体需要先上传到 media repository,消息正文再引用返回的 `mxc://` URI;`MessageSegment.image/file/audio/video` 在传入 bytes 时会自动执行这个流程。
228
+
229
+ ```python
230
+ from pathlib import Path
231
+
232
+ from nonebot import on_command
233
+ from nonebot.adapters.matrix import Bot, MessageEvent, MessageSegment
234
+
235
+ matcher = on_command("image")
236
+
237
+
238
+ @matcher.handle()
239
+ async def handle_img_send():
240
+ cur_dir = os.path.dirname(__file__)
241
+ # Read img from current directory
242
+ content = Path(os.path.join(cur_dir, "./assets/test.jpg")).read_bytes()
243
+ await send_img.finish(
244
+ MessageSegment.image(
245
+ content,
246
+ filename="test.jpg",
247
+ content_type="image/jpg"
248
+ )
249
+ )
250
+
251
+ ```
252
+
253
+ ### 常用 Matrix 操作
254
+
255
+ ```python
256
+ await bot.react(event.room_id, event.event_id, "👍")
257
+ await bot.set_typing_state(event.room_id, typing=True, timeout=5000)
258
+ await bot.mark_read(event.room_id, event.event_id)
259
+ await bot.redact(event.room_id, event.event_id, reason="handled")
260
+ ```
261
+
262
+ ## 当前范围
263
+
264
+ 当前实现面向 Matrix Client-Server bot 场景:
265
+
266
+ - 通过 `/account/whoami` 校验身份。
267
+ - 通过 `/sync` long-poll 接收 room timeline、state、typing、receipt 等事件。
268
+ - 支持发送 `m.room.message`、上传媒体、reaction、redaction、typing 和 receipt。
269
+ - 不包含端到端加密房间支持。
270
+ - 不包含 Matrix Application Service API。
271
+ - 不持久化 `/sync` 的 `next_batch`;进程内重连会复用内存状态,跨进程重启默认丢弃早于本次启动时间的旧事件。
@@ -0,0 +1,255 @@
1
+ <p align="center">
2
+ <a href="https://nonebot.dev/"><img src="assets/logo.svg" width="200" height="200" alt="nonebot-adapter-discord"></a>
3
+ </p>
4
+
5
+ <div align="center">
6
+
7
+ # NoneBot-Adapter-Matrix
8
+
9
+ _✨ Matrix Client-Server 协议适配 ✨_
10
+
11
+ </div>
12
+
13
+ ## 安装
14
+
15
+ ```bash
16
+ pip install nonebot-adapter-matrix
17
+ ```
18
+ 开发版本可从当前仓库构建安装:
19
+
20
+ ```bash
21
+ pip install git+https://github.com/elysia-best/adapter-matrix.git@master
22
+ ```
23
+
24
+ ## 配置
25
+
26
+ Matrix adapter 使用 Client-Server API 与 homeserver 通信,需要可发起 HTTP 请求的 NoneBot ForwardDriver。
27
+
28
+ ```dotenv
29
+ DRIVER=~httpx
30
+ ```
31
+
32
+ ### 三种启动模式
33
+
34
+ 适配器支持三种 token 管理模式:
35
+
36
+ #### 1. 静态 token 模式(兼容模式)
37
+
38
+ 适合已有 access token 的场景。不会自动获取或刷新 token。
39
+
40
+ ```dotenv
41
+ MATRIX_BOTS='[
42
+ {
43
+ "homeserver": "https://matrix.example.org",
44
+ "access_token": "YOUR_ACCESS_TOKEN",
45
+ "user_id": "@bot:example.org"
46
+ }
47
+ ]'
48
+ ```
49
+
50
+ 注意:此模式下如果没有额外提供登录凭据或 OAuth2 配置,协议上无法自动获取首个 refresh token。access token 过期后需要手动更新配置。
51
+
52
+ #### 2. 传统 Matrix 登录模式
53
+
54
+ 提供登录凭据,适配器启动时自动调用 `/login` 获取 token 对,并在需要时自动 refresh。
55
+
56
+ ```dotenv
57
+ MATRIX_BOTS='[
58
+ {
59
+ "homeserver": "https://matrix.example.org",
60
+ "access_token": "",
61
+ "login_user": "@bot:example.org",
62
+ "login_password": "your-password",
63
+ "device_id": "BOTDEVICE",
64
+ "set_presence": "online"
65
+ }
66
+ ]'
67
+ ```
68
+
69
+ - `login_user`:Matrix 用户 ID,用于 `/login` 请求。
70
+ - `login_password`:Matrix 账户密码。
71
+ - `login_initial_device_display_name`:可选;初始设备显示名称。
72
+ - 登录成功后会自动设置 `session_type: "legacy_login"`,后续 refresh 走 `/_matrix/client/v3/refresh`。
73
+ - 若 refresh 返回 `soft_logout: true`,适配器会自动用密码重新登录。
74
+
75
+ #### 3. OAuth2 模式
76
+
77
+ 通过 OAuth2 Authorization Code + PKCE 登录,适合支持 Matrix next-gen auth / OIDC 的 homeserver。
78
+
79
+ 最小配置:
80
+
81
+ ```dotenv
82
+ MATRIX_BOTS='[
83
+ {
84
+ "homeserver": "https://matrix.example.org",
85
+ "access_token": "",
86
+ "oauth_enabled": true,
87
+ "oauth_server_url": "https://account.matrix.org",
88
+ "oauth_open_browser": true
89
+ }
90
+ ]'
91
+ ```
92
+
93
+ 也可以手动指定已注册的 client:
94
+
95
+ ```dotenv
96
+ MATRIX_BOTS='[
97
+ {
98
+ "homeserver": "https://matrix.example.org",
99
+ "access_token": "",
100
+ "oauth_enabled": true,
101
+ "oauth_server_url": "https://account.matrix.org",
102
+ "oauth_client_id": "your-client-id",
103
+ "oauth_redirect_uri": "https://your-app.example/callback"
104
+ }
105
+ ]'
106
+ ```
107
+
108
+ - `oauth_enabled`:启用 OAuth2 登录流程。
109
+ - `oauth_server_url`:可选;直接指定 OAuth2/OIDC server 根地址,例如 `https://account.matrix.org`。若未提供,会优先尝试 Matrix `/_matrix/client/v1/auth_metadata` 自动发现。
110
+ - `oauth_metadata_url`:可选;直接指定 metadata 文档地址,优先级高于 `oauth_server_url`。
111
+ - `oauth_client_id`:可选;若未提供且 server 暴露 `registration_endpoint`,适配器会自动注册一个 OAuth2 client 并持久化保存。
112
+ - `oauth_client_uri`:可选;动态注册时写入 client metadata。某些 Matrix Authentication Service(例如 matrix.org)要求该字段存在;未配置时默认使用 `homeserver` 作为回退值。需要注意这里需要填写有效的域名
113
+ - `oauth_redirect_uri`:可选;若不提供,则默认使用 loopback 回调并自动选择一个可用随机端口。若提供 localhost / `127.0.0.1` 回调地址,则必须显式写出端口,且注册、授权、换 token 全程使用该 URI 原样值;若想用自动随机端口,请直接省略 `oauth_redirect_uri`。若提供外部回调地址,则需要手动复制授权结果中的 `code` 或完整回调 URL 到终端。
114
+ - `oauth_scope`:可选;默认会构造符合 MSC2967 的 scope,并自动补上 `urn:matrix:org.matrix.msc2967.client:device:{DEVICE_ID}`;若你自定义 scope,适配器仍会补 device scope。
115
+ - `oauth_device_id`:可选;指定请求的 Matrix device ID。未提供时会自动生成一个 12 位的大写字母数字 ID。
116
+ - `oauth_open_browser`:是否自动打开浏览器访问授权 URL,默认 `false`。
117
+ - `oauth_callback_timeout`:等待回调的超时时间(秒),默认 `300`。
118
+
119
+ OAuth2 登录流程:
120
+ 1. 适配器按如下顺序发现元数据:`oauth_metadata_url` → `/_matrix/client/v1/auth_metadata`(及其 unstable MSC2965 端点)→ `oauth_server_url` 兜底。
121
+ 2. 校验 server 支持 `response_type=code`、`response_mode=fragment` 和 PKCE `S256`。
122
+ 3. 若未配置 `oauth_client_id`,则通过 metadata 返回的 `registration_endpoint` 自动注册 client。
123
+ 4. 生成 device ID、`state`、`code_verifier`/`code_challenge`,并构造符合 MSC2967 的 scope。
124
+ 5. 输出授权 URL(若 `oauth_open_browser: true` 则自动打开浏览器)。
125
+ 6. 获取 authorization code 并交换首个 access/refresh token。
126
+ 7. 后续 refresh 走 metadata 返回的 OAuth2 token endpoint(`grant_type=refresh_token`)。
127
+
128
+ ### 通用字段
129
+
130
+ ```dotenv
131
+ MATRIX_BOTS='[
132
+ {
133
+ "homeserver": "https://matrix.example.org",
134
+ "access_token": "YOUR_ACCESS_TOKEN",
135
+ "refresh_token": "OPTIONAL_REFRESH_TOKEN",
136
+ "access_token_expires_at_ms": 1760000000000,
137
+ "refresh_before_expiry_ms": 60000,
138
+ "user_id": "@bot:example.org",
139
+ "device_id": "BOTDEVICE",
140
+ "sync_filter": {"room": {"timeline": {"limit": 50}}},
141
+ "set_presence": "online"
142
+ }
143
+ ]'
144
+ ```
145
+
146
+ - `homeserver`:Matrix homeserver 根地址(必填)。
147
+ - `access_token`:当前使用的 Matrix access token(使用登录模式时可留空)。
148
+ - `refresh_token`:通常由登录流程获得,不要求手动填写。持久化到 `MATRIX_TOKEN_STORE_PATH` 后会自动加载。
149
+ - `access_token_expires_at_ms`:当前 access token 的绝对过期时间戳,单位毫秒。
150
+ - `refresh_before_expiry_ms`:距离过期多久前主动 refresh,默认 `60000`(1 分钟)。
151
+ - `user_id`:启动时通过 `/account/whoami` 校验 token 所属用户。
152
+ - `device_id`:记录当前 token 对应的 Matrix 设备 ID。
153
+ - `sync_filter`:传给 `/sync` 的 filter id 或 filter JSON。
154
+ - `set_presence`:`online`、`offline` 或 `unavailable`。
155
+
156
+ ### 其他配置
157
+
158
+ ```dotenv
159
+ MATRIX_API_TIMEOUT=30.0
160
+ MATRIX_SYNC_TIMEOUT=30000
161
+ MATRIX_RETRY_INTERVAL=3.0
162
+ MATRIX_HANDLE_SELF_MESSAGE=false
163
+ MATRIX_HANDLE_OLD_EVENTS=false
164
+ MATRIX_PROXY='http://127.0.0.1:7890'
165
+ MATRIX_TOKEN_STORE_PATH='.data/matrix-tokens.json'
166
+ ```
167
+
168
+ - `MATRIX_API_TIMEOUT`:普通 API 请求超时时间,单位秒。
169
+ - `MATRIX_SYNC_TIMEOUT`:`/sync` long-poll 超时时间,单位毫秒。
170
+ - `MATRIX_RETRY_INTERVAL`:网络错误后的重试间隔,单位秒。
171
+ - `MATRIX_HANDLE_SELF_MESSAGE`:是否处理机器人自己发送的消息。
172
+ - `MATRIX_HANDLE_OLD_EVENTS`:是否处理早于本次启动时间的旧事件,默认丢弃旧事件。
173
+ - `MATRIX_PROXY`:可选 HTTP 代理。
174
+ - `MATRIX_TOKEN_STORE_PATH`:可选 token 状态文件路径;配置后会将 token 持久化到该文件,重启时自动加载。
175
+
176
+ ### Refresh Token 行为
177
+
178
+ - 启动时若配置了 `MATRIX_TOKEN_STORE_PATH`,会优先读取状态文件中的最新 token 和 `session_type`。
179
+ - access token 接近 `access_token_expires_at_ms` 时,会在下一次 `/sync` 前主动 refresh。
180
+ - 若 homeserver 提前使当前 token 失效并返回 `M_UNKNOWN_TOKEN`,adapter 会尝试使用 refresh token 恢复。
181
+ - **refresh 失败语义**:
182
+ - 网络错误或 5xx:保留旧 refresh token,稍后重试。
183
+ - 4xx 且带 `soft_logout: true`:若配置了 `login_password`,自动重新登录。
184
+ - 4xx 无 `soft_logout`:视为会话失效,等待重试。
185
+ - refresh 成功后更新内存中的 `access_token`、`refresh_token`、`access_token_expires_at_ms`,并写回状态文件。
186
+ - adapter 不会回写 `.env` 或其他部署配置;`/sync` 的 `next_batch` 仍然不会持久化。
187
+
188
+ ## 插件示例
189
+
190
+ ```python
191
+ from nonebot import on_command
192
+ from nonebot.params import CommandArg
193
+
194
+ from nonebot.adapters.matrix import Bot, Message, MessageEvent, MessageSegment
195
+
196
+ matcher = on_command("echo")
197
+
198
+
199
+ @matcher.handle()
200
+ async def handle_echo(bot: Bot, event: MessageEvent, msg: Message = CommandArg()):
201
+ text = msg.extract_plain_text()
202
+ if text == "mention":
203
+ await matcher.finish(MessageSegment.mention_user(event.get_user_id()))
204
+ if text == "notice":
205
+ await matcher.finish(MessageSegment.notice("这是一条 Matrix notice"))
206
+ await bot.send(event, MessageSegment.text(text or "hello matrix"))
207
+ ```
208
+
209
+ ### 发送媒体
210
+
211
+ Matrix 媒体需要先上传到 media repository,消息正文再引用返回的 `mxc://` URI;`MessageSegment.image/file/audio/video` 在传入 bytes 时会自动执行这个流程。
212
+
213
+ ```python
214
+ from pathlib import Path
215
+
216
+ from nonebot import on_command
217
+ from nonebot.adapters.matrix import Bot, MessageEvent, MessageSegment
218
+
219
+ matcher = on_command("image")
220
+
221
+
222
+ @matcher.handle()
223
+ async def handle_img_send():
224
+ cur_dir = os.path.dirname(__file__)
225
+ # Read img from current directory
226
+ content = Path(os.path.join(cur_dir, "./assets/test.jpg")).read_bytes()
227
+ await send_img.finish(
228
+ MessageSegment.image(
229
+ content,
230
+ filename="test.jpg",
231
+ content_type="image/jpg"
232
+ )
233
+ )
234
+
235
+ ```
236
+
237
+ ### 常用 Matrix 操作
238
+
239
+ ```python
240
+ await bot.react(event.room_id, event.event_id, "👍")
241
+ await bot.set_typing_state(event.room_id, typing=True, timeout=5000)
242
+ await bot.mark_read(event.room_id, event.event_id)
243
+ await bot.redact(event.room_id, event.event_id, reason="handled")
244
+ ```
245
+
246
+ ## 当前范围
247
+
248
+ 当前实现面向 Matrix Client-Server bot 场景:
249
+
250
+ - 通过 `/account/whoami` 校验身份。
251
+ - 通过 `/sync` long-poll 接收 room timeline、state、typing、receipt 等事件。
252
+ - 支持发送 `m.room.message`、上传媒体、reaction、redaction、typing 和 receipt。
253
+ - 不包含端到端加密房间支持。
254
+ - 不包含 Matrix Application Service API。
255
+ - 不持久化 `/sync` 的 `next_batch`;进程内重连会复用内存状态,跨进程重启默认丢弃早于本次启动时间的旧事件。
@@ -0,0 +1,50 @@
1
+ from .adapter import Adapter
2
+ from .api import UNSET, is_not_unset, is_unset
3
+ from .bot import Bot
4
+ from .event import (
5
+ Event,
6
+ EventType,
7
+ InviteEvent,
8
+ LeaveEvent,
9
+ MessageEvent,
10
+ MetaEvent,
11
+ NoticeEvent,
12
+ ReactionEvent,
13
+ ReceiptEvent,
14
+ RedactionEvent,
15
+ RoomMemberEvent,
16
+ RoomMessageEvent,
17
+ SyncMetaEvent,
18
+ TypingEvent,
19
+ UnknownRoomEvent,
20
+ event_classes,
21
+ )
22
+ from .message import Message, MessageSegment
23
+ from .utils import log
24
+
25
+ __all__ = (
26
+ "UNSET",
27
+ "Adapter",
28
+ "Bot",
29
+ "Event",
30
+ "EventType",
31
+ "InviteEvent",
32
+ "LeaveEvent",
33
+ "Message",
34
+ "MessageEvent",
35
+ "MessageSegment",
36
+ "MetaEvent",
37
+ "NoticeEvent",
38
+ "ReactionEvent",
39
+ "ReceiptEvent",
40
+ "RedactionEvent",
41
+ "RoomMemberEvent",
42
+ "RoomMessageEvent",
43
+ "SyncMetaEvent",
44
+ "TypingEvent",
45
+ "UnknownRoomEvent",
46
+ "event_classes",
47
+ "is_not_unset",
48
+ "is_unset",
49
+ "log",
50
+ )