hyapp-server/services/activity-service/internal/app/agency_host_removed_notice.go

133 lines
4.9 KiB
Go

package app
import (
"context"
"encoding/json"
"fmt"
"strconv"
"strings"
"hyapp/pkg/appcode"
"hyapp/pkg/rocketmqx"
"hyapp/pkg/usermq"
"hyapp/pkg/xerr"
"hyapp/services/activity-service/internal/config"
messageservice "hyapp/services/activity-service/internal/service/message"
)
const userOutboxEventAgencyHostRemoved = "AgencyHostRemoved"
type agencyHostRemovedUserSnapshot struct {
UserID int64 `json:"user_id"`
DisplayUserID string `json:"display_user_id"`
Username string `json:"username"`
}
type agencyHostRemovedEvent struct {
AppCode string
EventID string
MembershipID int64
AgencyID int64
HostUserID int64
Operator agencyHostRemovedUserSnapshot
RemovedAtMS int64
}
func newAgencyHostRemovedNoticeUserOutboxConsumer(cfg config.Config, services *serviceBundle) (*rocketmqx.Consumer, error) {
consumer, err := rocketmqx.NewConsumer(userOutboxAgencyHostRemovedNoticeConsumerConfig(cfg.RocketMQ))
if err != nil {
return nil, err
}
if err := consumer.Subscribe(cfg.RocketMQ.UserOutbox.Topic, usermq.TagUserOutboxEvent, func(ctx context.Context, message rocketmqx.ConsumedMessage) error {
event, ok, err := agencyHostRemovedEventFromUserMessage(message.Body)
if err != nil || !ok {
return err
}
return createAgencyHostRemovedSystemNotice(appcode.WithContext(ctx, event.AppCode), services.message, event)
}); err != nil {
_ = consumer.Shutdown()
return nil, err
}
return consumer, nil
}
func agencyHostRemovedEventFromUserMessage(body []byte) (agencyHostRemovedEvent, bool, error) {
message, err := usermq.DecodeUserOutboxMessage(body)
if err != nil {
return agencyHostRemovedEvent{}, false, err
}
if message.EventType != userOutboxEventAgencyHostRemoved {
return agencyHostRemovedEvent{}, false, nil
}
var payload struct {
MembershipID int64 `json:"membership_id"`
AgencyID int64 `json:"agency_id"`
HostUserID int64 `json:"host_user_id"`
Operator agencyHostRemovedUserSnapshot `json:"operator"`
RemovedAtMS int64 `json:"removed_at_ms"`
}
if err := json.Unmarshal([]byte(message.PayloadJSON), &payload); err != nil {
// 目标事件损坏必须交回 MQ 重试并告警;确认消息会永久丢失主播可见的移除事实。
return agencyHostRemovedEvent{}, true, err
}
payload.Operator.DisplayUserID = strings.TrimSpace(payload.Operator.DisplayUserID)
payload.Operator.Username = strings.TrimSpace(payload.Operator.Username)
if payload.MembershipID <= 0 || payload.AgencyID <= 0 || payload.HostUserID <= 0 ||
payload.Operator.UserID <= 0 || payload.Operator.DisplayUserID == "" || payload.RemovedAtMS <= 0 ||
message.AggregateType != "agency_membership" || message.AggregateID != payload.MembershipID {
return agencyHostRemovedEvent{}, true, xerr.New(xerr.InvalidArgument, "agency host removed event is invalid")
}
return agencyHostRemovedEvent{
AppCode: appcode.Normalize(message.AppCode),
EventID: message.EventID,
MembershipID: payload.MembershipID,
AgencyID: payload.AgencyID,
HostUserID: payload.HostUserID,
Operator: payload.Operator,
RemovedAtMS: payload.RemovedAtMS,
}, true, nil
}
func createAgencyHostRemovedSystemNotice(ctx context.Context, service *messageservice.Service, event agencyHostRemovedEvent) error {
if service == nil {
return xerr.New(xerr.Unavailable, "message service is not configured")
}
// 昵称为空时只展示短号,避免形成双空格;正常资料同时展示“当前靓号/短 ID + 昵称”。
operatorLabel := strings.Join(nonEmptyStrings(event.Operator.DisplayUserID, event.Operator.Username), " ")
content := fmt.Sprintf("你已被 %s agency移除", operatorLabel)
_, err := service.CreateSystemNotice(ctx, messageservice.NoticeCommand{
TargetUserID: event.HostUserID,
Producer: "user-service",
ProducerEventID: event.EventID,
ProducerEventType: userOutboxEventAgencyHostRemoved,
AggregateType: "agency_membership",
AggregateID: strconv.FormatInt(event.MembershipID, 10),
TemplateID: "agency_host_removed",
TemplateVersion: "v1",
Title: "Agency移除通知",
Summary: content,
Body: content,
Priority: 50,
SentAtMS: event.RemovedAtMS,
Metadata: map[string]any{
"agency_id": event.AgencyID,
"membership_id": event.MembershipID,
"operator_user_id": event.Operator.UserID,
"operator_display_user_id": event.Operator.DisplayUserID,
"operator_username": event.Operator.Username,
"removed_at_ms": event.RemovedAtMS,
},
})
return err
}
func nonEmptyStrings(values ...string) []string {
items := make([]string, 0, len(values))
for _, value := range values {
if value = strings.TrimSpace(value); value != "" {
items = append(items, value)
}
}
return items
}