Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent checkpoints for double puppeted events #342

Merged
merged 5 commits into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion appservice/intent.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,12 +142,16 @@ func (intent *IntentAPI) EnsureJoined(ctx context.Context, roomID id.RoomID, ext
return nil
}

func (intent *IntentAPI) IsDoublePuppet() bool {
return intent.IsCustomPuppet && intent.as.DoublePuppetValue != ""
}

func (intent *IntentAPI) AddDoublePuppetValue(into any) any {
return intent.AddDoublePuppetValueWithTS(into, 0)
}

func (intent *IntentAPI) AddDoublePuppetValueWithTS(into any, ts int64) any {
if !intent.IsCustomPuppet || intent.as.DoublePuppetValue == "" {
if !intent.IsDoublePuppet() {
return into
}
// Only use ts deduplication feature with appservice double puppeting
Expand Down
28 changes: 15 additions & 13 deletions bridgev2/database/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@ type Message struct {
PartID networkid.PartID
MXID id.EventID

Room networkid.PortalKey
SenderID networkid.UserID
SenderMXID id.UserID
Timestamp time.Time
EditCount int
Room networkid.PortalKey
SenderID networkid.UserID
SenderMXID id.UserID
Timestamp time.Time
EditCount int
IsDoublePuppeted bool

ThreadRoot networkid.MessageID
ReplyTo networkid.MessageOptionalPartID
Expand All @@ -48,7 +49,7 @@ type Message struct {
const (
getMessageBaseQuery = `
SELECT rowid, bridge_id, id, part_id, mxid, room_id, room_receiver, sender_id, sender_mxid,
timestamp, edit_count, thread_root_id, reply_to_id, reply_to_part_id, metadata
timestamp, edit_count, double_puppeted, thread_root_id, reply_to_id, reply_to_part_id, metadata
FROM message
`
getAllMessagePartsByIDQuery = getMessageBaseQuery + `WHERE bridge_id=$1 AND (room_receiver=$2 OR room_receiver='') AND id=$3`
Expand All @@ -72,15 +73,16 @@ const (
insertMessageQuery = `
INSERT INTO message (
bridge_id, id, part_id, mxid, room_id, room_receiver, sender_id, sender_mxid,
timestamp, edit_count, thread_root_id, reply_to_id, reply_to_part_id, metadata
timestamp, edit_count, double_puppeted, thread_root_id, reply_to_id, reply_to_part_id, metadata
)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)
RETURNING rowid
`
updateMessageQuery = `
UPDATE message SET id=$2, part_id=$3, mxid=$4, room_id=$5, room_receiver=$6, sender_id=$7, sender_mxid=$8,
timestamp=$9, edit_count=$10, thread_root_id=$11, reply_to_id=$12, reply_to_part_id=$13, metadata=$14
WHERE bridge_id=$1 AND rowid=$15
timestamp=$9, edit_count=$10, double_puppeted=$11, thread_root_id=$12, reply_to_id=$13,
reply_to_part_id=$14, metadata=$15
WHERE bridge_id=$1 AND rowid=$16
`
deleteAllMessagePartsByIDQuery = `
DELETE FROM message WHERE bridge_id=$1 AND (room_receiver=$2 OR room_receiver='') AND id=$3
Expand Down Expand Up @@ -174,7 +176,7 @@ func (m *Message) Scan(row dbutil.Scannable) (*Message, error) {
var threadRootID, replyToID, replyToPartID sql.NullString
err := row.Scan(
&m.RowID, &m.BridgeID, &m.ID, &m.PartID, &m.MXID, &m.Room.ID, &m.Room.Receiver, &m.SenderID, &m.SenderMXID,
&timestamp, &m.EditCount, &threadRootID, &replyToID, &replyToPartID, dbutil.JSON{Data: m.Metadata},
&timestamp, &m.EditCount, &m.IsDoublePuppeted, &threadRootID, &replyToID, &replyToPartID, dbutil.JSON{Data: m.Metadata},
)
if err != nil {
return nil, err
Expand All @@ -200,8 +202,8 @@ func (m *Message) ensureHasMetadata(metaType MetaTypeCreator) *Message {
func (m *Message) sqlVariables() []any {
return []any{
m.BridgeID, m.ID, m.PartID, m.MXID, m.Room.ID, m.Room.Receiver, m.SenderID, m.SenderMXID,
m.Timestamp.UnixNano(), m.EditCount, dbutil.StrPtr(m.ThreadRoot), dbutil.StrPtr(m.ReplyTo.MessageID), m.ReplyTo.PartID,
dbutil.JSON{Data: m.Metadata},
m.Timestamp.UnixNano(), m.EditCount, m.IsDoublePuppeted, dbutil.StrPtr(m.ThreadRoot),
dbutil.StrPtr(m.ReplyTo.MessageID), m.ReplyTo.PartID, dbutil.JSON{Data: m.Metadata},
}
}

Expand Down
3 changes: 2 additions & 1 deletion bridgev2/database/upgrades/00-latest.sql
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ CREATE TABLE message (
-- would try to set bridge_id to null as well.

-- only: sqlite (line commented)
-- rowid INTEGER PRIMARY KEY,
-- rowid INTEGER PRIMARY KEY,
-- only: postgres
rowid BIGINT PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,

Expand All @@ -102,6 +102,7 @@ CREATE TABLE message (
sender_mxid TEXT NOT NULL,
timestamp BIGINT NOT NULL,
edit_count INTEGER NOT NULL,
double_puppeted BOOLEAN,
thread_root_id TEXT,
reply_to_id TEXT,
reply_to_part_id TEXT,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- v19 (compatible with v9+): Add double puppeted state to messages
ALTER TABLE message ADD COLUMN double_puppeted BOOLEAN;
14 changes: 9 additions & 5 deletions bridgev2/matrix/connector.go
Original file line number Diff line number Diff line change
Expand Up @@ -450,13 +450,17 @@ func (br *Connector) internalSendMessageStatus(ctx context.Context, ms *bridgev2
return ""
}
log := zerolog.Ctx(ctx)
err := br.SendMessageCheckpoints([]*status.MessageCheckpoint{ms.ToCheckpoint(evt)})
if err != nil {
log.Err(err).Msg("Failed to send message checkpoint")

if !evt.IsSourceEventDoublePuppeted {
err := br.SendMessageCheckpoints([]*status.MessageCheckpoint{ms.ToCheckpoint(evt)})
if err != nil {
log.Err(err).Msg("Failed to send message checkpoint")
}
}

if !ms.DisableMSS && br.Config.Matrix.MessageStatusEvents {
mssEvt := ms.ToMSSEvent(evt)
_, err = br.Bot.SendMessageEvent(ctx, evt.RoomID, event.BeeperMessageStatus, mssEvt)
_, err := br.Bot.SendMessageEvent(ctx, evt.RoomID, event.BeeperMessageStatus, mssEvt)
if err != nil {
log.Err(err).
Stringer("room_id", evt.RoomID).
Expand All @@ -482,7 +486,7 @@ func (br *Connector) internalSendMessageStatus(ctx context.Context, ms *bridgev2
}
}
if ms.Status == event.MessageStatusSuccess && br.Config.Matrix.DeliveryReceipts {
err = br.Bot.SendReceipt(ctx, evt.RoomID, evt.SourceEventID, event.ReceiptTypeRead, nil)
err := br.Bot.SendReceipt(ctx, evt.RoomID, evt.SourceEventID, event.ReceiptTypeRead, nil)
if err != nil {
log.Err(err).
Stringer("room_id", evt.RoomID).
Expand Down
4 changes: 4 additions & 0 deletions bridgev2/matrix/intent.go
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,10 @@ func (as *ASIntent) GetMXID() id.UserID {
return as.Matrix.UserID
}

func (as *ASIntent) IsDoublePuppet() bool {
return as.Matrix.IsDoublePuppet()
}

func (as *ASIntent) EnsureJoined(ctx context.Context, roomID id.RoomID) error {
err := as.Matrix.EnsureJoined(ctx, roomID)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions bridgev2/matrixinterface.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ func (ce CallbackError) Unwrap() error {

type MatrixAPI interface {
GetMXID() id.UserID
IsDoublePuppet() bool

SendMessage(ctx context.Context, roomID id.RoomID, eventType event.Type, content *event.Content, extra *MatrixSendExtra) (*mautrix.RespSendEvent, error)
SendState(ctx context.Context, roomID id.RoomID, eventType event.Type, stateKey string, content *event.Content, ts time.Time) (*mautrix.RespSendEvent, error)
Expand Down
8 changes: 8 additions & 0 deletions bridgev2/messagestatus.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

"go.mau.fi/util/jsontime"

"maunium.net/go/mautrix/appservice"
"maunium.net/go/mautrix/bridge/status"
"maunium.net/go/mautrix/event"
"maunium.net/go/mautrix/id"
Expand All @@ -26,20 +27,27 @@ type MessageStatusEventInfo struct {
Sender id.UserID
ThreadRoot id.EventID
StreamOrder int64

IsSourceEventDoublePuppeted bool
}

func StatusEventInfoFromEvent(evt *event.Event) *MessageStatusEventInfo {
var threadRoot id.EventID
if relatable, ok := evt.Content.Parsed.(event.Relatable); ok {
threadRoot = relatable.OptionalGetRelatesTo().GetThreadParent()
}

_, isDoublePuppeted := evt.Content.Raw[appservice.DoublePuppetKey]

return &MessageStatusEventInfo{
RoomID: evt.RoomID,
SourceEventID: evt.ID,
EventType: evt.Type,
MessageType: evt.Content.AsMessage().MsgType,
Sender: evt.Sender,
ThreadRoot: threadRoot,

IsSourceEventDoublePuppeted: isDoublePuppeted,
}
}

Expand Down
21 changes: 12 additions & 9 deletions bridgev2/portal.go
Original file line number Diff line number Diff line change
Expand Up @@ -1827,15 +1827,16 @@ func (portal *Portal) sendConvertedMessage(
for i, part := range converted.Parts {
portal.applyRelationMeta(part.Content, replyTo, threadRoot, prevThreadEvent)
dbMessage := &database.Message{
ID: id,
PartID: part.ID,
Room: portal.PortalKey,
SenderID: senderID,
SenderMXID: intent.GetMXID(),
Timestamp: ts,
ThreadRoot: ptr.Val(converted.ThreadRoot),
ReplyTo: ptr.Val(converted.ReplyTo),
Metadata: part.DBMetadata,
ID: id,
PartID: part.ID,
Room: portal.PortalKey,
SenderID: senderID,
SenderMXID: intent.GetMXID(),
Timestamp: ts,
ThreadRoot: ptr.Val(converted.ThreadRoot),
ReplyTo: ptr.Val(converted.ReplyTo),
Metadata: part.DBMetadata,
IsDoublePuppeted: intent.IsDoublePuppet(),
}
if part.DontBridge {
dbMessage.SetFakeMXID()
Expand Down Expand Up @@ -2603,6 +2604,8 @@ func (portal *Portal) handleRemoteDeliveryReceipt(ctx context.Context, source *U
RoomID: portal.MXID,
SourceEventID: part.MXID,
Sender: part.SenderMXID,

IsSourceEventDoublePuppeted: part.IsDoublePuppeted,
})
}
}
Expand Down
21 changes: 11 additions & 10 deletions bridgev2/portalbackfill.go
Original file line number Diff line number Diff line change
Expand Up @@ -333,16 +333,17 @@ func (portal *Portal) compileBatchMessage(ctx context.Context, source *UserLogin
portal.applyRelationMeta(part.Content, replyTo, threadRoot, prevThreadEvent)
evtID := portal.Bridge.Matrix.GenerateDeterministicEventID(portal.MXID, portal.PortalKey, msg.ID, part.ID)
dbMessage := &database.Message{
ID: msg.ID,
PartID: part.ID,
MXID: evtID,
Room: portal.PortalKey,
SenderID: msg.Sender.Sender,
SenderMXID: intent.GetMXID(),
Timestamp: msg.Timestamp,
ThreadRoot: ptr.Val(msg.ThreadRoot),
ReplyTo: ptr.Val(msg.ReplyTo),
Metadata: part.DBMetadata,
ID: msg.ID,
PartID: part.ID,
MXID: evtID,
Room: portal.PortalKey,
SenderID: msg.Sender.Sender,
SenderMXID: intent.GetMXID(),
Timestamp: msg.Timestamp,
ThreadRoot: ptr.Val(msg.ThreadRoot),
ReplyTo: ptr.Val(msg.ReplyTo),
Metadata: part.DBMetadata,
IsDoublePuppeted: intent.IsDoublePuppet(),
}
if part.DontBridge {
dbMessage.SetFakeMXID()
Expand Down
Loading