fix: push realtime del presence to topic sessions on message recall
The REST recall response reached only the caller, so peers kept showing the
recalled message until a full resync. broadcastIMMessageRecalled now pushes
the native {pres what:del delseq} tombstone through the hub for both single
and batch recall (empty pres topic for p2p, required by handlePresence's
xoriginal check); clients flush the message and render the recalled
placeholder. Zentao #16, #2.
This commit is contained in:
@@ -3161,6 +3161,50 @@ func serveIMMessageReceipts(wrt http.ResponseWriter, req *http.Request) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// broadcastIMMessageRecalled pushes the native {pres what:"del" delseq} frame to
|
||||||
|
// the sessions currently attached to the topic so peers learn about a recall in
|
||||||
|
// real time (the REST response alone reaches only the caller). The wire record
|
||||||
|
// carries "low" only (no "hi"): client SDKs then flush the message from their
|
||||||
|
// local cache and leave a content-less tombstone behind, which the webapp
|
||||||
|
// renders as the usual "recalled" placeholder. Routed through the hub so the
|
||||||
|
// p2p topic rewrites the frame's topic name to each recipient's own view.
|
||||||
|
func broadcastIMMessageRecalled(tenantID types.TenantID, topic string, seqs []int64, actor types.Uid) {
|
||||||
|
if globals.hub == nil || topic == "" || actor.IsZero() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
delseq := make([]MsgRange, 0, len(seqs))
|
||||||
|
for _, seq := range seqs {
|
||||||
|
if seq > 0 {
|
||||||
|
delseq = append(delseq, MsgRange{LowId: seq})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(delseq) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// P2P topics are loaded under their canonical name with xoriginal cleared,
|
||||||
|
// so the presence frame must carry an empty topic name to pass the
|
||||||
|
// handlePresence xoriginal check; any other category uses the topic name.
|
||||||
|
presTopic := topic
|
||||||
|
if types.GetTopicCat(topic) == types.TopicCatP2P {
|
||||||
|
presTopic = ""
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case globals.hub.routeSrv <- &ServerComMessage{
|
||||||
|
TenantID: tenantID,
|
||||||
|
RcptTo: topic,
|
||||||
|
Pres: &MsgServerPres{
|
||||||
|
Topic: presTopic,
|
||||||
|
What: "del",
|
||||||
|
Src: actor.UserId(),
|
||||||
|
DelSeq: delseq,
|
||||||
|
FilterIn: int(types.ModeRead),
|
||||||
|
},
|
||||||
|
}:
|
||||||
|
default:
|
||||||
|
logs.Warn.Printf("im message recall: hub presence queue full topic=%s count=%d", topic, len(delseq))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func serveIMMessageRecall(wrt http.ResponseWriter, req *http.Request) {
|
func serveIMMessageRecall(wrt http.ResponseWriter, req *http.Request) {
|
||||||
if req.Method != http.MethodPost {
|
if req.Method != http.MethodPost {
|
||||||
writeIMError(wrt, req, http.StatusMethodNotAllowed, 30002, imReasonMethodNotAllowed, "method not allowed", nil)
|
writeIMError(wrt, req, http.StatusMethodNotAllowed, 30002, imReasonMethodNotAllowed, "method not allowed", nil)
|
||||||
@@ -3215,6 +3259,7 @@ func serveIMMessageRecall(wrt http.ResponseWriter, req *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
broadcastIMMessageRecalled(principal.TenantID, updated.Topic, []int64{seq}, principal.Uid)
|
||||||
writeIMSuccess(wrt, req, messageMutationPayload(updated, "recalled"))
|
writeIMSuccess(wrt, req, messageMutationPayload(updated, "recalled"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3242,6 +3287,7 @@ func serveIMMessageBatchRecall(wrt http.ResponseWriter, req *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
items := make([]map[string]any, 0, len(body.Items))
|
items := make([]map[string]any, 0, len(body.Items))
|
||||||
|
recalledSeqs := make([]int64, 0, len(body.Items))
|
||||||
recalledAt := time.Now().UTC().Round(time.Millisecond)
|
recalledAt := time.Now().UTC().Round(time.Millisecond)
|
||||||
for _, item := range body.Items {
|
for _, item := range body.Items {
|
||||||
if item.Seq <= 0 {
|
if item.Seq <= 0 {
|
||||||
@@ -3281,7 +3327,9 @@ func serveIMMessageBatchRecall(wrt http.ResponseWriter, req *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
items = append(items, result)
|
items = append(items, result)
|
||||||
|
recalledSeqs = append(recalledSeqs, item.Seq)
|
||||||
}
|
}
|
||||||
|
broadcastIMMessageRecalled(principal.TenantID, topic, recalledSeqs, principal.Uid)
|
||||||
writeIMSuccess(wrt, req, map[string]any{"topic": topic, "items": items})
|
writeIMSuccess(wrt, req, map[string]any{"topic": topic, "items": items})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user