package notify import ( "time" flatbuffers "github.com/google/flatbuffers/go" "github.com/google/uuid" fb "scrabble/pkg/fbs/scrabblefb" ) // The constructors below build one Intent per live event, FlatBuffers-encoding // the payload with the shared scrabblefb schema. Keeping the encoding here lets // the game/social/lobby services emit events without importing the wire schema. // YourTurn announces to userID that it is their turn in game gameID, with the // turn's nominal deadline. func YourTurn(userID, gameID uuid.UUID, deadline time.Time) Intent { b := flatbuffers.NewBuilder(64) gid := b.CreateString(gameID.String()) fb.YourTurnEventStart(b) fb.YourTurnEventAddGameId(b, gid) fb.YourTurnEventAddDeadlineUnix(b, deadline.Unix()) b.Finish(fb.YourTurnEventEnd(b)) return Intent{UserID: userID, Kind: KindYourTurn, Payload: b.FinishedBytes(), EventID: eventID()} } // OpponentMoved tells userID that seat just committed a move in game gameID, // summarising it (the client refetches the full state). func OpponentMoved(userID, gameID uuid.UUID, seat int, action string, score, total int) Intent { b := flatbuffers.NewBuilder(64) gid := b.CreateString(gameID.String()) act := b.CreateString(action) fb.OpponentMovedEventStart(b) fb.OpponentMovedEventAddGameId(b, gid) fb.OpponentMovedEventAddSeat(b, int32(seat)) fb.OpponentMovedEventAddAction(b, act) fb.OpponentMovedEventAddScore(b, int32(score)) fb.OpponentMovedEventAddTotal(b, int32(total)) b.Finish(fb.OpponentMovedEventEnd(b)) return Intent{UserID: userID, Kind: KindOpponentMoved, Payload: b.FinishedBytes(), EventID: eventID()} } // ChatMessage delivers a stored chat message (or nudge) to userID. func ChatMessage(userID, gameID, senderID uuid.UUID, id, kind, body string, createdAt time.Time) Intent { b := flatbuffers.NewBuilder(128) idOff := b.CreateString(id) gid := b.CreateString(gameID.String()) sid := b.CreateString(senderID.String()) kindOff := b.CreateString(kind) bodyOff := b.CreateString(body) fb.ChatMessageStart(b) fb.ChatMessageAddId(b, idOff) fb.ChatMessageAddGameId(b, gid) fb.ChatMessageAddSenderId(b, sid) fb.ChatMessageAddKind(b, kindOff) fb.ChatMessageAddBody(b, bodyOff) fb.ChatMessageAddCreatedAtUnix(b, createdAt.Unix()) b.Finish(fb.ChatMessageEnd(b)) return Intent{UserID: userID, Kind: KindChatMessage, Payload: b.FinishedBytes(), EventID: eventID()} } // Nudge tells userID that fromUserID nudged them in game gameID. func Nudge(userID, gameID, fromUserID uuid.UUID) Intent { b := flatbuffers.NewBuilder(64) gid := b.CreateString(gameID.String()) from := b.CreateString(fromUserID.String()) fb.NudgeEventStart(b) fb.NudgeEventAddGameId(b, gid) fb.NudgeEventAddFromUserId(b, from) b.Finish(fb.NudgeEventEnd(b)) return Intent{UserID: userID, Kind: KindNudge, Payload: b.FinishedBytes(), EventID: eventID()} } // MatchFound tells userID that game gameID, which they are seated in, has // started (an auto-match pairing or a robot substitution). func MatchFound(userID, gameID uuid.UUID) Intent { b := flatbuffers.NewBuilder(64) gid := b.CreateString(gameID.String()) fb.MatchFoundEventStart(b) fb.MatchFoundEventAddGameId(b, gid) b.Finish(fb.MatchFoundEventEnd(b)) return Intent{UserID: userID, Kind: KindMatchFound, Payload: b.FinishedBytes(), EventID: eventID()} } // Notification is a lightweight "re-poll" signal to userID that a friend request or // invitation changed. kind is a sub-discriminator (NotifyFriendRequest, // NotifyFriendAdded, NotifyInvitation, NotifyGameStarted) the client may use to // scope its refresh. func Notification(userID uuid.UUID, kind string) Intent { b := flatbuffers.NewBuilder(32) k := b.CreateString(kind) fb.NotificationEventStart(b) fb.NotificationEventAddKind(b, k) b.Finish(fb.NotificationEventEnd(b)) return Intent{UserID: userID, Kind: KindNotification, Payload: b.FinishedBytes(), EventID: eventID()} } // eventID returns a best-effort correlation id for one emitted event. func eventID() string { if id, err := uuid.NewV7(); err == nil { return id.String() } return "" }