feat: sync ephemeral transient messages
Sync telesrv 570ccf8 (feat(ephemeral): implement Layer 228 transient messages). Skipped telesrv docs changes per public sync rules; normalized the public appearance seed label.
This commit is contained in:
parent
3f78eaa2c6
commit
f49c817def
53 changed files with 5793 additions and 112 deletions
|
|
@ -1,5 +1,7 @@
|
|||
package domain
|
||||
|
||||
import "time"
|
||||
|
||||
// BotAPIUpdateKind is the Bot API delivery shape for a queued update.
|
||||
type BotAPIUpdateKind string
|
||||
|
||||
|
|
@ -22,6 +24,109 @@ type BotCallbackQuery struct {
|
|||
InlineMessage *BotInlineMessageID
|
||||
}
|
||||
|
||||
// BotAPIEphemeralPayload is a self-contained 24-hour Bot API queue snapshot.
|
||||
// Ordinary queued messages are reloaded from their durable message tables;
|
||||
// ephemeral messages have no such table and therefore travel in this explicit
|
||||
// envelope instead of overloading SourcePts or an ordinary message id. The
|
||||
// public shape deliberately cannot represent random IDs, payload hashes,
|
||||
// auth-key/session identifiers, or the originating device.
|
||||
type BotAPIEphemeralPayload struct {
|
||||
Message BotAPIEphemeralMessage
|
||||
ReplyTo *BotAPIEphemeralMessage `json:",omitempty"`
|
||||
}
|
||||
|
||||
type BotAPIEphemeralMessage struct {
|
||||
ID int
|
||||
Peer Peer
|
||||
SenderUserID int64
|
||||
ReceiverUserID int64
|
||||
Date int
|
||||
EditDate int
|
||||
TopMessageID int
|
||||
ReplyToEphemeralID int
|
||||
Content EphemeralContent
|
||||
Version uint64
|
||||
ExpiresAt time.Time
|
||||
}
|
||||
|
||||
func NewBotAPIEphemeralPayload(message EphemeralMessage) *BotAPIEphemeralPayload {
|
||||
payload := &BotAPIEphemeralPayload{Message: publicBotAPIEphemeralMessage(message)}
|
||||
if message.BotAPIReply != nil {
|
||||
reply := publicBotAPIEphemeralMessage(*message.BotAPIReply)
|
||||
payload.ReplyTo = &reply
|
||||
}
|
||||
return payload
|
||||
}
|
||||
|
||||
func publicBotAPIEphemeralMessage(message EphemeralMessage) BotAPIEphemeralMessage {
|
||||
return BotAPIEphemeralMessage{
|
||||
ID: message.ID, Peer: message.Peer,
|
||||
SenderUserID: message.SenderUserID, ReceiverUserID: message.ReceiverUserID,
|
||||
Date: message.Date, EditDate: message.EditDate,
|
||||
TopMessageID: message.TopMessageID, ReplyToEphemeralID: message.ReplyToEphemeralID,
|
||||
Content: message.Content, Version: message.Version, ExpiresAt: message.ExpiresAt,
|
||||
}
|
||||
}
|
||||
|
||||
func (m BotAPIEphemeralMessage) EphemeralMessage() EphemeralMessage {
|
||||
return EphemeralMessage{
|
||||
ID: m.ID, Peer: m.Peer,
|
||||
SenderUserID: m.SenderUserID, ReceiverUserID: m.ReceiverUserID,
|
||||
Date: m.Date, EditDate: m.EditDate,
|
||||
TopMessageID: m.TopMessageID, ReplyToEphemeralID: m.ReplyToEphemeralID,
|
||||
Content: m.Content, Version: m.Version, ExpiresAt: m.ExpiresAt,
|
||||
}
|
||||
}
|
||||
|
||||
func (p BotAPIEphemeralPayload) EphemeralMessage() EphemeralMessage {
|
||||
message := p.Message.EphemeralMessage()
|
||||
if p.ReplyTo != nil {
|
||||
reply := p.ReplyTo.EphemeralMessage()
|
||||
message.BotAPIReply = &reply
|
||||
}
|
||||
return message
|
||||
}
|
||||
|
||||
func (p BotAPIEphemeralPayload) Validate() error {
|
||||
if err := p.Message.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
if p.Message.ReplyToEphemeralID == 0 {
|
||||
if p.ReplyTo != nil {
|
||||
return ErrEphemeralInvalid
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if p.ReplyTo == nil || p.ReplyTo.Validate() != nil || p.ReplyTo.ID != p.Message.ReplyToEphemeralID ||
|
||||
p.ReplyTo.Peer != p.Message.Peer || p.ReplyTo.Date > p.Message.Date ||
|
||||
!sameEphemeralParticipantPair(p.Message.SenderUserID, p.Message.ReceiverUserID, p.ReplyTo.SenderUserID, p.ReplyTo.ReceiverUserID) {
|
||||
return ErrEphemeralInvalid
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func sameEphemeralParticipantPair(firstSender, firstReceiver, secondSender, secondReceiver int64) bool {
|
||||
return (firstSender == secondSender && firstReceiver == secondReceiver) ||
|
||||
(firstSender == secondReceiver && firstReceiver == secondSender)
|
||||
}
|
||||
|
||||
func (m BotAPIEphemeralMessage) Expired(now time.Time) bool {
|
||||
return !m.ExpiresAt.IsZero() && !now.Before(m.ExpiresAt)
|
||||
}
|
||||
|
||||
func (m BotAPIEphemeralMessage) Validate() error {
|
||||
date := time.Unix(int64(m.Date), 0)
|
||||
if m.ID <= 0 || m.ID > MaxMessageBoxID || m.Peer.Type != PeerTypeChannel || m.Peer.ID <= 0 ||
|
||||
m.SenderUserID <= 0 || m.ReceiverUserID <= 0 || m.SenderUserID == m.ReceiverUserID ||
|
||||
m.Date <= 0 || m.Version == 0 || m.ExpiresAt.IsZero() || !m.ExpiresAt.After(date) ||
|
||||
m.ExpiresAt.Sub(date) > EphemeralMessageRetention+time.Second ||
|
||||
(m.EditDate != 0 && m.EditDate < m.Date) || m.TopMessageID < 0 || m.TopMessageID > MaxMessageBoxID ||
|
||||
m.ReplyToEphemeralID < 0 || m.ReplyToEphemeralID > MaxMessageBoxID || m.ReplyToEphemeralID == m.ID {
|
||||
return ErrEphemeralInvalid
|
||||
}
|
||||
return ValidateEphemeralContent(m.Content)
|
||||
}
|
||||
|
||||
// BotInlineMessageID is the domain-only shape of inputBotInlineMessageID64.
|
||||
// It can be projected both to MTProto and to Bot API's opaque
|
||||
// inline_message_id without leaking tg types into the store boundary.
|
||||
|
|
@ -44,6 +149,7 @@ type BotAPIUpdate struct {
|
|||
SourcePts int
|
||||
Date int
|
||||
Callback *BotCallbackQuery
|
||||
Ephemeral *BotAPIEphemeralPayload
|
||||
}
|
||||
|
||||
// EnqueueBotAPIUpdateRequest describes a message-like update that should be
|
||||
|
|
@ -56,4 +162,5 @@ type EnqueueBotAPIUpdateRequest struct {
|
|||
SourcePts int
|
||||
Date int
|
||||
Callback *BotCallbackQuery
|
||||
Ephemeral *BotAPIEphemeralPayload
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue