Compare commits

..

3 Commits

Author SHA1 Message Date
xuncha
2acbe0fb08 Merge pull request #836 from hicccc77/dev
Dev
2026-04-25 00:59:14 +08:00
xuncha
17c13c2455 Merge pull request #835 from xunchahaha/dev
Dev
2026-04-25 00:58:34 +08:00
xuncha
032aad6539 新增撤回消息推送 2026-04-25 00:57:24 +08:00
4 changed files with 778 additions and 37 deletions

View File

@@ -74,14 +74,14 @@ GET /api/v1/push/messages
- 需要先在设置页开启 `HTTP API 服务`
- 同时需要开启 `主动推送`
- 响应类型为 `text/event-stream`
- 新消息事件名固定为 `message.new`
- 建议接收端按 `messageKey` 去重
- 事件名包含 `message.new``message.revoke`
- 建议接收端按 `event + rawid` 去重
### 事件字段
- `event`
- `sessionId`
- `messageKey`
- `rawid`
- `avatarUrl`
- `sourceName`
- `groupName`(仅群聊)
@@ -98,7 +98,14 @@ curl -N "http://127.0.0.1:5031/api/v1/push/messages?access_token=YOUR_TOKEN
```text
event: message.new
data: {"event":"message.new","sessionId":"xxx@chatroom","messageKey":"server:123456:1760000123:1760000123000:321:wxid_member:1","avatarUrl":"https://example.com/group.jpg","sourceName":"李四","groupName":"项目群","content":"[图片]","timestamp":1760000123}
data: {"event":"message.new","sessionId":"xxx@chatroom","sessionType":"group","rawid":"1234567890123456789","avatarUrl":"https://example.com/group.jpg","sourceName":"李四","groupName":"项目群","content":"[图片]","timestamp":1760000123}
```
撤回事件示例:
```text
event: message.revoke
data: {"event":"message.revoke","sessionId":"wxid_xxx","sessionType":"other","rawid":"1234567890123456789","avatarUrl":"https://example.com/avatar.jpg","sourceName":"张三","content":"对方撤回了一条消息rawid1234567890123456789 内容为“你好”","timestamp":1760000180}
```
---

View File

@@ -290,7 +290,8 @@ class HttpService {
broadcastMessagePush(payload: Record<string, unknown>): void {
if (!this.running) return
const eventId = this.nextMessagePushEventId()
const eventBody = `id: ${eventId}\nevent: message.new\ndata: ${JSON.stringify(payload)}\n\n`
const eventName = this.getMessagePushEventName(payload)
const eventBody = `id: ${eventId}\nevent: ${eventName}\ndata: ${JSON.stringify(payload)}\n\n`
this.rememberMessagePushEvent(eventId, eventBody)
if (this.messagePushClients.size === 0) return
@@ -308,6 +309,11 @@ class HttpService {
}
}
private getMessagePushEventName(payload: Record<string, unknown>): string {
const eventName = String(payload?.event || '').trim()
return /^[a-z0-9._-]+$/i.test(eventName) ? eventName : 'message.new'
}
async autoStart(): Promise<void> {
const enabled = this.configService.get('httpApiEnabled')
if (enabled) {

File diff suppressed because it is too large Load Diff

View File

@@ -4120,16 +4120,16 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) {
<div className="form-group">
<label></label>
<span className="form-hint">SSE `message.new` `avatarUrl/sourceName/content/timestamp` `groupName` `timestamp` Unix </span>
<span className="form-hint">SSE `message.new` `message.revoke` `rawid/avatarUrl/sourceName/content/timestamp` `groupName` `timestamp` Unix </span>
<div className="api-docs">
<div className="api-item">
<div className="api-endpoint">
<span className="method get">GET</span>
<code>{`http://${httpApiHost}:${httpApiPort}/api/v1/push/messages`}</code>
</div>
<p className="api-desc"> SSE `messageKey` </p>
<p className="api-desc"> SSE `event + rawid` </p>
<div className="api-params">
{['event', 'sessionId', 'sessionType', 'messageKey', 'avatarUrl', 'sourceName', 'groupName?', 'content', 'timestamp'].map((param) => (
{['event', 'sessionId', 'sessionType', 'rawid', 'avatarUrl', 'sourceName', 'groupName?', 'content', 'timestamp'].map((param) => (
<span key={param} className="param">
<code>{param}</code>
</span>