feat(gateway+web): D 消息编辑/删除 WS 实时广播 — message_edited/message_deleted
- 后端: ws_hub.go broadcastMessageEdited(完整DTO,thinking剥离)/broadcastMessageDeleted(全广播+sessionId,前端过滤); history_write.go PATCH/DELETE成功后触发(404/400/501不广播); history/message_ops.go GetMessage(导出壳,取删除前sessionId) - 前端: useAppStore.updateMessageById/removeMessageById + messageEventApplies(同会话过滤); ws.ts 消费两事件(缺content丢弃); dispatchFrame导出(可测) - 真机e2e: PATCH/DELETE → WS收到 message_edited/message_deleted, 二次删404无帧 - Docs/api-client v0.34 §3.8; 测试 history_write_broadcast_test + messageSync.test(14 checks) - 遗留: 前端编辑/删除UI入口+api客户端函数未接(lib/api 无 PATCH/DELETE messages); ws_hub.go 589行>500(既有)
This commit is contained in:
1 parent
4ea68d17f3
commit
2720d77331
8 files changed
+485
-15
No files matched your search
@@ -188,6 +188,35 @@ func (h *hub) broadcast(ev wsEvent) {
|
||||
}
|
||||
}
|
||||
|
||||
// wsMessageEdited / wsMessageDeleted are the downstream event types of the D3
|
||||
// history writes: a message's content was edited, or a message was removed. Both
|
||||
// reuse the wsEvent envelope and the same all-connections fan-out as
|
||||
// `message_persisted` — the hub has no per-session subscription, so the frame
|
||||
// carries SessionID and a client filters it by its active session, exactly as it
|
||||
// does for message_persisted.
|
||||
const (
|
||||
wsMessageEdited = "message_edited"
|
||||
wsMessageDeleted = "message_deleted"
|
||||
)
|
||||
|
||||
// broadcastMessageEdited fans a content edit out to every client as a
|
||||
// `message_edited` frame whose data is the updated message DTO. The frame is a
|
||||
// render-only sync: the edited content's single source of truth stays the history
|
||||
// store, so a client that missed the frame converges again on its next read. The
|
||||
// caller strips Thinking to match the message_persisted/replay contract.
|
||||
func (h *hub) broadcastMessageEdited(msg historyMessage) {
|
||||
h.broadcast(wsEvent{Type: wsMessageEdited, SessionID: msg.SessionID, Data: msg})
|
||||
}
|
||||
|
||||
// broadcastMessageDeleted fans a removal out to every client as a
|
||||
// `message_deleted` frame carrying the removed id (plus the owning sessionId for
|
||||
// client-side session filtering), so every browser of the account drops the row
|
||||
// without a refresh. sessionID may be empty when the store could not report it;
|
||||
// clients then fall back to the globally unique id.
|
||||
func (h *hub) broadcastMessageDeleted(sessionID, id string) {
|
||||
h.broadcast(wsEvent{Type: wsMessageDeleted, SessionID: sessionID, Data: map[string]any{"id": id}})
|
||||
}
|
||||
|
||||
// relay is the bus handler for the ws.> pattern and the producer bridge
|
||||
// patterns. The ws.chat subject is a streaming trigger (run the loop and emit
|
||||
// chunks); a ws.* subject becomes an outbound event of its design type; a
|
||||
|
||||
Reference in new issue
Block a user