package logic import ( "context" "encoding/json" "fmt" "time" deliverentity "spark-server/internal/module/deliver/entity" friendentity "spark-server/internal/module/friend/entity" msgentity "spark-server/internal/module/message/entity" "spark-server/internal/pkg/reply" ) const cmdMessage uint16 = 6 // DeliverQueue is Redis deliver:queue Push (C5). type DeliverQueue interface { Push(ctx context.Context, job *deliverentity.Job) error } // SystemGreeter inserts a type-9 system message into the P2P conversation and enqueues deliver. type SystemGreeter struct { chats P2PChats msgs Messages ids IDGen queue DeliverQueue } func NewGreeter(chats P2PChats, msgs Messages, ids IDGen, queue DeliverQueue) *SystemGreeter { return &SystemGreeter{chats: chats, msgs: msgs, ids: ids, queue: queue} } func (g *SystemGreeter) BecameFriends(ctx context.Context, userA, userB int64) error { if g == nil || g.chats == nil || g.msgs == nil || g.ids == nil { return nil } convID, err := g.chats.EnsureP2P(ctx, userA, userB) if err != nil { return err } msgID, err := g.ids.NextID() if err != nil { return err } now := time.Now() content := msgentity.NewSystem(&msgentity.System{Kind: friendentity.SystemKindBecameFriends}) raw, err := content.Marshal() if err != nil { return err } msg := &msgentity.Message{ ID: msgID, ConversationID: convID, SenderID: 0, ClientMsgID: fmt.Sprintf("sys:friend:%d", msgID), Type: msgentity.TypeSystem, Kind: msgentity.KindPrivate, Content: raw, Status: msgentity.StatusNormal, CreatedAtMS: now.UnixMilli(), } if err := g.msgs.Create(ctx, msg); err != nil { return err } if err := g.chats.UpdateLastMsg(ctx, convID, msgID, now.UnixMilli()); err != nil { return err } if g.queue == nil { return nil } return g.queue.Push(ctx, &deliverentity.Job{ MsgID: msgID, Cmd: cmdMessage, ConversationID: convID, ToUserIDs: []int64{userA, userB}, Payload: reply.MustMarshal(reply.OK(pushBodyOf(msg))), }) } type pushBody struct { MsgID int64 `json:"msg_id"` ConversationID int64 `json:"conversation_id"` SenderID int64 `json:"sender_id"` MessageType msgentity.Type `json:"message_type"` Content json.RawMessage `json:"content"` CreatedAt int64 `json:"created_at"` } func pushBodyOf(m *msgentity.Message) pushBody { return pushBody{ MsgID: m.ID, ConversationID: m.ConversationID, SenderID: m.SenderID, MessageType: m.Type, Content: m.Content, CreatedAt: m.CreatedAtMS, } }