This commit is contained in:
zhx 2026-07-22 19:14:39 +08:00
parent 8dda287d0a
commit f1f4f46ee9
2 changed files with 24 additions and 11 deletions

View File

@ -97,11 +97,12 @@ func TestTriggerVIPOnlineNoticeChecksBenefitAndPublishesTrustedGlobalPayload(t *
var envelope struct { var envelope struct {
Code string `json:"code"` Code string `json:"code"`
Data struct { Data struct {
EventID string `json:"event_id"` EventID string `json:"event_id"`
GroupID string `json:"group_id"` GroupID string `json:"group_id"`
Status string `json:"status"` Status string `json:"status"`
Created bool `json:"created"` Created bool `json:"created"`
EvaluatedAtMS int64 `json:"evaluated_at_ms"` EvaluatedAtMS int64 `json:"evaluated_at_ms"`
Notice map[string]any `json:"notice"`
} `json:"data"` } `json:"data"`
} }
if err := json.NewDecoder(recorder.Body).Decode(&envelope); err != nil { if err := json.NewDecoder(recorder.Body).Decode(&envelope); err != nil {
@ -110,6 +111,9 @@ func TestTriggerVIPOnlineNoticeChecksBenefitAndPublishesTrustedGlobalPayload(t *
if envelope.Code != httpkit.CodeOK || envelope.Data.EventID != publish.GetEventId() || envelope.Data.GroupID != "hy_fami_bc_g_v2" || envelope.Data.Status != "pending" || !envelope.Data.Created || envelope.Data.EvaluatedAtMS != 1_800_000_000_000 { if envelope.Code != httpkit.CodeOK || envelope.Data.EventID != publish.GetEventId() || envelope.Data.GroupID != "hy_fami_bc_g_v2" || envelope.Data.Status != "pending" || !envelope.Data.Created || envelope.Data.EvaluatedAtMS != 1_800_000_000_000 {
t.Fatalf("response mismatch: %+v", envelope) t.Fatalf("response mismatch: %+v", envelope)
} }
if envelope.Data.Notice["event_id"] != publish.GetEventId() || envelope.Data.Notice["broadcast_type"] != "vip_online_notice" || envelope.Data.Notice["app_code"] != "fami" || envelope.Data.Notice["scope"] != "global" || envelope.Data.Notice["user_id"] != "42" || envelope.Data.Notice["vip_level"] != float64(9) {
t.Fatalf("local notice snapshot mismatch: %+v", envelope.Data.Notice)
}
} }
func TestTriggerVIPOnlineNoticeWithoutEquippedFramePublishesExplicitEmptyFields(t *testing.T) { func TestTriggerVIPOnlineNoticeWithoutEquippedFramePublishesExplicitEmptyFields(t *testing.T) {

View File

@ -274,7 +274,16 @@ func (h *Handler) triggerVIPOnlineNotice(writer http.ResponseWriter, request *ht
if displayID == "" { if displayID == "" {
displayID = strings.TrimSpace(profile.GetDisplayUserId()) displayID = strings.TrimSpace(profile.GetDisplayUserId())
} }
payload, err := json.Marshal(map[string]any{ // event_id 同时进入腾讯 IM payload 和 HTTP 成功响应;发送端用它把本地即时回显
// 与稍后可能回环的 AVChatRoom 消息收敛成一次展示,不能让两条链路各自产生身份。
commandDigest := sha256.Sum256([]byte(commandID))
eventID := fmt.Sprintf("vip_online_notice:%d:%x", userID, commandDigest)
notice := map[string]any{
"event_id": eventID,
"broadcast_type": vipOnlineNoticeBroadcastType,
"scope": "global",
"app_code": appCode,
"sent_at_ms": benefitResp.GetEvaluatedAtMs(),
// VIP 全服播报进入腾讯 IM长用户 ID 必须在首次 JSON 编码时就是字符串。 // VIP 全服播报进入腾讯 IM长用户 ID 必须在首次 JSON 编码时就是字符串。
"user_id": tencentim.FormatOptionalUserID(userID), "user_id": tencentim.FormatOptionalUserID(userID),
"sender_user_id": tencentim.FormatOptionalUserID(userID), "sender_user_id": tencentim.FormatOptionalUserID(userID),
@ -296,15 +305,12 @@ func (h *Handler) triggerVIPOnlineNotice(writer http.ResponseWriter, request *ht
"vip_name": effectiveVIP.GetName(), "vip_name": effectiveVIP.GetName(),
"message": vipOnlineNoticeMessage(benefitResp.GetBenefit().GetMetadataJson()), "message": vipOnlineNoticeMessage(benefitResp.GetBenefit().GetMetadataJson()),
"action": map[string]string{"type": "none"}, "action": map[string]string{"type": "none"},
}) }
payload, err := json.Marshal(notice)
if err != nil { if err != nil {
httpkit.WriteError(writer, request, http.StatusInternalServerError, httpkit.CodeInternalError, "internal error") httpkit.WriteError(writer, request, http.StatusInternalServerError, httpkit.CodeInternalError, "internal error")
return return
} }
// event_id 使用 user_id + command_id 摘要,既隔离不同用户,又避免客户端长命令超过
// activity outbox 的 VARCHAR(128) 主键;相同 command_id 的 HTTP 重试会命中同一条 outbox。
commandDigest := sha256.Sum256([]byte(commandID))
eventID := fmt.Sprintf("vip_online_notice:%d:%x", userID, commandDigest)
broadcastResp, err := h.broadcastClient.PublishGlobalBroadcast(ctx, &activityv1.PublishGlobalBroadcastRequest{ broadcastResp, err := h.broadcastClient.PublishGlobalBroadcast(ctx, &activityv1.PublishGlobalBroadcastRequest{
Meta: httpkit.ActivityMeta(request), Meta: httpkit.ActivityMeta(request),
EventId: eventID, EventId: eventID,
@ -321,6 +327,9 @@ func (h *Handler) triggerVIPOnlineNotice(writer http.ResponseWriter, request *ht
"status": broadcastResp.GetStatus(), "status": broadcastResp.GetStatus(),
"created": broadcastResp.GetCreated(), "created": broadcastResp.GetCreated(),
"evaluated_at_ms": benefitResp.GetEvaluatedAtMs(), "evaluated_at_ms": benefitResp.GetEvaluatedAtMs(),
// notice 是已经通过权益、用户资料和当前佩戴资源校验的可信快照;客户端只可
// 在本机即时回显,其他用户仍必须消费 activity-service 投递的腾讯 IM 消息。
"notice": notice,
}) })
} }