ErisPulse-WebhookAdapter 4.0.0__tar.gz → 4.0.1__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,419 @@
1
+ Metadata-Version: 2.4
2
+ Name: ErisPulse-WebhookAdapter
3
+ Version: 4.0.1
4
+ Summary: ErisPulse的Webhook通用桥接适配模块
5
+ Author: ErisPulse
6
+ License: MIT
7
+ Project-URL: homepage, https://github.com/ErisPulse/ErisPulse-WebhookAdapter
8
+ Requires-Python: >=3.10
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Dynamic: license-file
12
+
13
+ # ErisPulse Webhook Adapter
14
+
15
+ [English](#english) | [中文](#中文)
16
+
17
+ ---
18
+
19
+ <a id="english"></a>
20
+
21
+ ## English
22
+
23
+ ErisPulse's **Webhook universal bridge adapter** (a low-code universal bridge). It is a bidirectional bridge adapter: it ingests messages from any external system into ErisPulse via HTTP, while forwarding messages emitted by ErisPulse modules to any target system via HTTP.
24
+
25
+ ### Adapter Positioning
26
+
27
+ Each "account" is an independent **webhook bridge configuration**:
28
+
29
+ | Direction | Description |
30
+ |-----------|-------------|
31
+ | **Inbound (External → ErisPulse)** | External systems POST events to the webhook route registered by the adapter via HTTP; the adapter converts them into standard OneBot12 events and dispatches them |
32
+ | **Outbound (ErisPulse → External)** | When a module calls `adapter.Send.To(...).Text(...)`, the adapter POSTs the message to the account's configured `outgoing_url` (i.e., "the user subscribes a webhook to another system, providing a send API") |
33
+
34
+ One account = one inbound path + one outbound URL + one authentication secret.
35
+
36
+ ### Installation
37
+
38
+ ```bash
39
+ epsdk install
40
+
41
+ # Select `Adapter` to install the `Webhook` adapter
42
+ ```
43
+
44
+ ### Configuration
45
+
46
+ Configuration is located in the `[WebhookAdapter]` section of `config.toml`, or via the Dashboard's adapter configuration:
47
+
48
+ ```toml
49
+ [WebhookAdapter.accounts.default]
50
+ bot_id = "webhook_bot"
51
+ callback_path = "/webhook/default"
52
+ outgoing_url = "https://example.com/api/receive" # Module messages will be POSTed here
53
+ secret = "my-secret-key" # Authentication secret (empty = no verification)
54
+ detail_type = "private" # Default session type
55
+ enabled = true
56
+
57
+ # Multiple bridge accounts can be configured
58
+ [WebhookAdapter.accounts.discord_bridge]
59
+ bot_id = "discord_bot_123"
60
+ callback_path = "/webhook/discord"
61
+ outgoing_url = "https://my-discord-relay.example.com/send"
62
+ secret = "another-secret"
63
+ detail_type = "group"
64
+ enabled = true
65
+ ```
66
+
67
+ #### Field Description
68
+
69
+ | Field | Default | Description |
70
+ |-------|---------|-------------|
71
+ | `bot_id` | `webhook_bot` | The bot identity ID represented by this bridge (written into the event's `self.user_id`) |
72
+ | `callback_path` | `/webhook/{account}` | Inbound path; supports the `{account}` placeholder (auto-replaced with the account name) |
73
+ | `outgoing_url` | `""` | Outbound target URL; empty means inbound only, no sending |
74
+ | `secret` | `""` | Authentication secret; empty means no inbound request verification |
75
+ | `detail_type` | `private` | Default session type, used when the inbound body does not specify `detail_type` |
76
+
77
+ ### Inbound Protocol (External → ErisPulse)
78
+
79
+ #### HTTP Request
80
+
81
+ External systems POST to `{callback_path}/{account}` with a JSON body:
82
+
83
+ ```json
84
+ {
85
+ "user_id": "xxx",
86
+ "user_nickname": "username",
87
+ "group_id": "optional, group/channel ID",
88
+ "detail_type": "private or group",
89
+ "message": [{"type": "text", "data": {"text": "content"}}],
90
+ "raw": {}
91
+ }
92
+ ```
93
+
94
+ - When `detail_type` is not provided, the account's configured default is used
95
+ - `group_id` is only provided for group sessions
96
+ - `message` is an array of standard OneBot12 message segments
97
+ - `raw` is optional and stored as-is in `webhook_raw.raw`
98
+
99
+ #### Authentication
100
+
101
+ If the account has a `secret` configured, inbound requests must carry the secret (one of the following):
102
+
103
+ - Header: `X-Webhook-Secret: {secret}`
104
+ - Query: `?secret={secret}`
105
+
106
+ No verification is performed when `secret` is empty.
107
+
108
+ #### Health Check (GET)
109
+
110
+ On receiving a GET request, returns `{"status":"ok","account":"account_name"}`, which can be used for health checks.
111
+
112
+ #### Inbound Example
113
+
114
+ ```bash
115
+ curl -X POST http://localhost:8000/webhook/default \
116
+ -H "Content-Type: application/json" \
117
+ -H "X-Webhook-Secret: my-secret-key" \
118
+ -d '{
119
+ "user_id": "u123",
120
+ "user_nickname": "test_user",
121
+ "detail_type": "private",
122
+ "message": [{"type": "text", "data": {"text": "hello"}}]
123
+ }'
124
+ ```
125
+
126
+ Response:
127
+
128
+ ```json
129
+ {"status": "ok"}
130
+ ```
131
+
132
+ #### Converted OneBot12 Event
133
+
134
+ ```json
135
+ {
136
+ "id": "auto-generated",
137
+ "time": 1700000000,
138
+ "type": "message",
139
+ "detail_type": "private",
140
+ "platform": "webhook",
141
+ "self": {"platform": "webhook", "user_id": "webhook_bot"},
142
+ "user_id": "u123",
143
+ "user_nickname": "test_user",
144
+ "message": [{"type": "text", "data": {"text": "hello"}}],
145
+ "webhook_raw": {},
146
+ "webhook_account": "default",
147
+ "webhook_raw_type": "message"
148
+ }
149
+ ```
150
+
151
+ ### Outbound Protocol (ErisPulse → External)
152
+
153
+ When a module calls `Send`, the adapter POSTs the message to the account's `outgoing_url`:
154
+
155
+ ```json
156
+ {
157
+ "target_type": "private|group|user",
158
+ "target_id": "xxx",
159
+ "account": "account_name",
160
+ "message": [{"type": "text", "data": {"text": "content"}}],
161
+ "timestamp": 1234567890
162
+ }
163
+ ```
164
+
165
+ Request header (if `secret` is configured):
166
+
167
+ ```
168
+ X-Webhook-Secret: {secret}
169
+ ```
170
+
171
+ The adapter normalizes the response returned by the outbound target into a standard response format: it extracts the `message_id` field from the response JSON.
172
+
173
+ #### Send Example
174
+
175
+ ```python
176
+ from ErisPulse import sdk
177
+
178
+ # Send text (using the default account)
179
+ await sdk.adapter.webhook.Send.To("user", "target_user_id").Text("hello")
180
+
181
+ # Send via a specific account
182
+ await sdk.adapter.webhook.Send.To("group", "group_123").Using("discord_bridge").Text("group message")
183
+
184
+ # Raw JSON passthrough
185
+ await sdk.adapter.webhook.Send.To("user", "u1").Json({"custom": "data"})
186
+
187
+ # OneBot12 raw message segments
188
+ await sdk.adapter.webhook.Send.To("user", "u1").Raw_ob12([
189
+ {"type": "text", "data": {"text": "hello"}}
190
+ ])
191
+ ```
192
+
193
+ ### Use Cases
194
+
195
+ #### Scenario 1: Integrating Your Own System
196
+
197
+ Your business system pushes user messages to ErisPulse via webhook for processing, then receives them back:
198
+
199
+ 1. Configure an account with `callback_path` pointing to your inbound path, and `outgoing_url` pointing to your receiving API
200
+ 2. The business system POSTs user messages to `callback_path`
201
+ 3. After ErisPulse modules process them, reply messages are POSTed to `outgoing_url`
202
+
203
+ #### Scenario 2: Bridging Non-Natively Supported Platforms
204
+
205
+ Through an intermediate relay script, connect other platforms (such as self-built IM or enterprise internal systems) to ErisPulse without developing a full adapter.
206
+
207
+ #### Scenario 3: Webhook Relay
208
+
209
+ Act as a message relay: aggregate multiple webhook sources into ErisPulse for unified processing, then dispatch to multiple targets.
210
+
211
+ ### Documentation
212
+
213
+ - [Platform Features](platform-features.md) — Inbound/outbound protocol details and field mappings
214
+
215
+ ### License
216
+
217
+ MIT
218
+
219
+ ---
220
+
221
+ <a id="中文"></a>
222
+
223
+ ## 中文
224
+
225
+ ErisPulse 的 **Webhook 通用桥接适配器**(低代码万能桥)。它是一个双向桥接适配器:把任意外部系统的消息通过 HTTP 接入 ErisPulse,同时把 ErisPulse 模块发出的消息通过 HTTP 转发给任意目标系统。
226
+
227
+ ### 适配器定位
228
+
229
+ 每个「账户」即一个独立的 **webhook 桥接配置**:
230
+
231
+ | 方向 | 说明 |
232
+ |------|------|
233
+ | **入站(外部 → ErisPulse)** | 外部系统通过 HTTP POST 把事件发到适配器注册的 webhook 路由,适配器转换为 OneBot12 标准事件并分发 |
234
+ | **出站(ErisPulse → 外部)** | 模块调用 `adapter.Send.To(...).Text(...)` 时,适配器把消息 POST 到账户配置的 `outgoing_url`(即"用户订阅 webhook 到其他系统,提供发送 api") |
235
+
236
+ 一个账户 = 一个入站路径 + 一个出站 URL + 一个鉴权密钥。
237
+
238
+ ### 安装
239
+
240
+ ```bash
241
+ epsdk install
242
+
243
+ # 选择 `适配器` 安装 `Webhook` 适配器
244
+ ```
245
+
246
+ ### 配置
247
+
248
+ 配置位于 `config.toml` 的 `[WebhookAdapter]` 段,或通过Dashboard的`适配器配置进行配置`:
249
+
250
+ ```toml
251
+ [WebhookAdapter.accounts.default]
252
+ bot_id = "webhook_bot"
253
+ callback_path = "/webhook/default"
254
+ outgoing_url = "https://example.com/api/receive" # 模块发消息会 POST 到这里
255
+ secret = "my-secret-key" # 鉴权密钥(留空则不校验)
256
+ detail_type = "private" # 默认会话类型
257
+ enabled = true
258
+
259
+ # 可以配置多个桥接账户
260
+ [WebhookAdapter.accounts.discord_bridge]
261
+ bot_id = "discord_bot_123"
262
+ callback_path = "/webhook/discord"
263
+ outgoing_url = "https://my-discord-relay.example.com/send"
264
+ secret = "another-secret"
265
+ detail_type = "group"
266
+ enabled = true
267
+ ```
268
+
269
+ #### 字段说明
270
+
271
+ | 字段 | 默认值 | 说明 |
272
+ |------|--------|------|
273
+ | `bot_id` | `webhook_bot` | 该桥接代表的机器人身份 ID(写入事件的 `self.user_id`) |
274
+ | `callback_path` | `/webhook/{account}` | 入站路径,支持 `{account}` 占位符(自动替换为账户名) |
275
+ | `outgoing_url` | `""` | 出站目标 URL,留空则仅入站不发送 |
276
+ | `secret` | `""` | 鉴权密钥,留空则不校验入站请求 |
277
+ | `detail_type` | `private` | 默认会话类型,入站 body 未指定 `detail_type` 时使用 |
278
+
279
+ ### 入站协议(外部 → ErisPulse)
280
+
281
+ #### HTTP 请求
282
+
283
+ 外部系统 POST 到 `{callback_path}/{account}`,body 为 JSON:
284
+
285
+ ```json
286
+ {
287
+ "user_id": "xxx",
288
+ "user_nickname": "用户名",
289
+ "group_id": "可选,群组/频道ID",
290
+ "detail_type": "private 或 group",
291
+ "message": [{"type": "text", "data": {"text": "内容"}}],
292
+ "raw": {}
293
+ }
294
+ ```
295
+
296
+ - `detail_type` 未提供时使用账户配置的默认值
297
+ - `group_id` 仅在群组会话时提供
298
+ - `message` 为 OneBot12 标准消息段数组
299
+ - `raw` 可选,原样存入 `webhook_raw.raw`
300
+
301
+ #### 鉴权
302
+
303
+ 如果账户配置了 `secret`,入站请求需携带密钥(二选一):
304
+
305
+ - Header:`X-Webhook-Secret: {secret}`
306
+ - Query:`?secret={secret}`
307
+
308
+ `secret` 留空时不校验。
309
+
310
+ #### 健康检查(GET)
311
+
312
+ 收到 GET 请求时返回 `{"status":"ok","account":"账户名"}`,可用于健康检查。
313
+
314
+ #### 入站示例
315
+
316
+ ```bash
317
+ curl -X POST http://localhost:8000/webhook/default \
318
+ -H "Content-Type: application/json" \
319
+ -H "X-Webhook-Secret: my-secret-key" \
320
+ -d '{
321
+ "user_id": "u123",
322
+ "user_nickname": "测试用户",
323
+ "detail_type": "private",
324
+ "message": [{"type": "text", "data": {"text": "你好"}}]
325
+ }'
326
+ ```
327
+
328
+ 响应:
329
+
330
+ ```json
331
+ {"status": "ok"}
332
+ ```
333
+
334
+ #### 转换后的 OneBot12 事件
335
+
336
+ ```json
337
+ {
338
+ "id": "自动生成",
339
+ "time": 1700000000,
340
+ "type": "message",
341
+ "detail_type": "private",
342
+ "platform": "webhook",
343
+ "self": {"platform": "webhook", "user_id": "webhook_bot"},
344
+ "user_id": "u123",
345
+ "user_nickname": "测试用户",
346
+ "message": [{"type": "text", "data": {"text": "你好"}}],
347
+ "webhook_raw": {},
348
+ "webhook_account": "default",
349
+ "webhook_raw_type": "message"
350
+ }
351
+ ```
352
+
353
+ ### 出站协议(ErisPulse → 外部)
354
+
355
+ 模块调用 `Send` 时,适配器把消息 POST 到账户的 `outgoing_url`:
356
+
357
+ ```json
358
+ {
359
+ "target_type": "private|group|user",
360
+ "target_id": "xxx",
361
+ "account": "账户名",
362
+ "message": [{"type": "text", "data": {"text": "内容"}}],
363
+ "timestamp": 1234567890
364
+ }
365
+ ```
366
+
367
+ 请求头(若配置了 `secret`):
368
+
369
+ ```
370
+ X-Webhook-Secret: {secret}
371
+ ```
372
+
373
+ 适配器会把出站目标返回的响应标准化为标准响应格式:从响应 JSON 中提取 `message_id` 字段。
374
+
375
+ #### 发送示例
376
+
377
+ ```python
378
+ from ErisPulse import sdk
379
+
380
+ # 发送文本(使用默认账户)
381
+ await sdk.adapter.webhook.Send.To("user", "target_user_id").Text("你好")
382
+
383
+ # 指定账户发送
384
+ await sdk.adapter.webhook.Send.To("group", "group_123").Using("discord_bridge").Text("群消息")
385
+
386
+ # 原始 JSON 透传
387
+ await sdk.adapter.webhook.Send.To("user", "u1").Json({"custom": "data"})
388
+
389
+ # OneBot12 原始消息段
390
+ await sdk.adapter.webhook.Send.To("user", "u1").Raw_ob12([
391
+ {"type": "text", "data": {"text": "hello"}}
392
+ ])
393
+ ```
394
+
395
+ ### 使用场景
396
+
397
+ #### 场景一:接入自有系统
398
+
399
+ 你的业务系统通过 webhook 把用户消息推给 ErisPulse 处理,处理后再回传:
400
+
401
+ 1. 配置一个账户,`callback_path` 指向你的入站路径,`outgoing_url` 指向你的接收 API
402
+ 2. 业务系统把用户消息 POST 到 `callback_path`
403
+ 3. ErisPulse 模块处理后,回复消息会 POST 到 `outgoing_url`
404
+
405
+ #### 场景二:桥接非原生支持的平台
406
+
407
+ 通过中间转发脚本,把其他平台(如自建 IM、企业内部系统)接入 ErisPulse,无需开发完整适配器。
408
+
409
+ #### 场景三:Webhook 中继
410
+
411
+ 作为消息中继,把多个 webhook 源汇聚到 ErisPulse 统一处理,再分发给多个目标。
412
+
413
+ ### 文档
414
+
415
+ - [平台特性说明](platform-features.md) — 入站/出站协议详解与字段映射
416
+
417
+ ### 许可证
418
+
419
+ MIT