133 lines
4.9 KiB
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
|
|
}
|