Add support for deletions in both directions

This commit is contained in:
Tulir Asokan 2023-07-15 01:22:20 +03:00
parent b5257f53d3
commit c0313dca87
3 changed files with 106 additions and 9 deletions

View file

@ -7,6 +7,7 @@
* [x] Reactions (RCS)
* [ ] Typing notifications (RCS)
* [ ] Read receipts (RCS)
* [x] Message deletions (own device only)
* Google Messages → Matrix
* [ ] Message content
* [x] Plain text
@ -15,6 +16,7 @@
* [x] Reactions (RCS)
* [ ] Typing notifications (RCS)
* [ ] Read receipts (RCS)
* [x] Message deletions (own device only)
* Misc
* [x] Automatic portal creation
* [x] After login

View file

@ -79,3 +79,10 @@ func UnicodeToEmojiType(emoji string) EmojiType {
return EmojiType_CUSTOM
}
}
func MakeReactionData(emoji string) *ReactionData {
return &ReactionData{
Unicode: emoji,
Type: UnicodeToEmojiType(emoji),
}
}

106
portal.go
View file

@ -291,6 +291,8 @@ func (portal *Portal) handleMatrixMessageLoopItem(msg PortalMatrixMessage) {
portal.HandleMatrixMessage(msg.user, msg.evt, timings)
case event.EventReaction:
portal.HandleMatrixReaction(msg.user, msg.evt)
case event.EventRedaction:
portal.HandleMatrixRedaction(msg.user, msg.evt)
default:
portal.zlog.Warn().
Str("event_type", msg.evt.Type.Type).
@ -365,7 +367,8 @@ func (portal *Portal) handleMessage(source *User, evt *binary.Message) {
log := portal.zlog.With().
Str("message_id", evt.MessageID).
Str("participant_id", evt.ParticipantID).
Str("action", "handleMessage").
Str("status", evt.GetMessageStatus().GetStatus().String()).
Str("action", "handle google message").
Logger()
ctx := log.WithContext(context.TODO())
switch evt.GetMessageStatus().GetStatus() {
@ -373,7 +376,7 @@ func (portal *Portal) handleMessage(source *User, evt *binary.Message) {
log.Debug().Msg("Not handling incoming message that is auto downloading")
return
case binary.MessageStatusType_MESSAGE_DELETED:
// TODO handle deletion
portal.handleGoogleDeletion(ctx, evt.MessageID)
return
}
if hasInProgressMedia(evt) {
@ -412,6 +415,24 @@ func (portal *Portal) handleMessage(source *User, evt *binary.Message) {
log.Debug().Interface("event_ids", eventIDs).Msg("Handled message")
}
func (portal *Portal) handleGoogleDeletion(ctx context.Context, messageID string) {
log := zerolog.Ctx(ctx)
msg, err := portal.bridge.DB.Message.GetByID(ctx, portal.Key, messageID)
if err != nil {
log.Err(err).Msg("Failed to get deleted message from database")
} else if msg == nil {
log.Debug().Msg("Didn't find deleted message in database")
} else {
if _, err = portal.MainIntent().RedactEvent(portal.MXID, msg.MXID); err != nil {
log.Err(err).Msg("Faield to redact deleted message")
}
if err = msg.Delete(ctx); err != nil {
log.Err(err).Msg("Failed to delete message from database")
}
log.Debug().Msg("Handled message deletion")
}
}
func (portal *Portal) syncReactions(ctx context.Context, source *User, message *database.Message, reactions []*binary.ReactionResponse) {
log := zerolog.Ctx(ctx)
existing, err := portal.bridge.DB.Reaction.GetAllByMessage(ctx, portal.Key, message.ID)
@ -1242,7 +1263,7 @@ func (portal *Portal) handleMatrixReaction(sender *User, evt *event.Event) error
Str("target_event_id", content.RelatesTo.EventID.String()).
Str("action", "handle matrix reaction").
Logger()
ctx := log.WithContext(context.Background())
ctx := log.WithContext(context.TODO())
log.Debug().Msg("Handling Matrix reaction")
msg, err := portal.bridge.DB.Message.GetByMXID(ctx, content.RelatesTo.EventID)
@ -1265,12 +1286,9 @@ func (portal *Portal) handleMatrixReaction(sender *User, evt *event.Event) error
action = binary.Reaction_SWITCH
}
resp, err := sender.Client.Messages.React(&binary.SendReactionPayload{
MessageID: msg.ID,
ReactionData: &binary.ReactionData{
Unicode: emoji,
Type: binary.UnicodeToEmojiType(emoji),
},
Action: action,
MessageID: msg.ID,
ReactionData: binary.MakeReactionData(emoji),
Action: action,
})
if err != nil {
return fmt.Errorf("failed to send reaction: %w", err)
@ -1302,6 +1320,76 @@ func (portal *Portal) handleMatrixReaction(sender *User, evt *event.Event) error
return nil
}
func (portal *Portal) HandleMatrixRedaction(sender *User, evt *event.Event) {
err := portal.handleMatrixRedaction(sender, evt)
go portal.sendMessageMetrics(evt, err, "Error sending", nil)
}
func (portal *Portal) handleMatrixMessageRedaction(ctx context.Context, sender *User, redacts id.EventID) error {
log := zerolog.Ctx(ctx)
msg, err := portal.bridge.DB.Message.GetByMXID(ctx, redacts)
if err != nil {
log.Err(err).Msg("Failed to get redaction target message")
return fmt.Errorf("failed to get event from database")
} else if msg == nil {
return errTargetNotFound
}
resp, err := sender.Client.Messages.Delete(msg.ID)
if err != nil {
return fmt.Errorf("failed to send message removal: %w", err)
} else if !resp.Success {
return fmt.Errorf("got non-success response")
}
err = msg.Delete(ctx)
if err != nil {
log.Err(err).Msg("Failed to delete message from database after Matrix redaction")
}
return nil
}
func (portal *Portal) handleMatrixReactionRedaction(ctx context.Context, sender *User, redacts id.EventID) error {
log := zerolog.Ctx(ctx)
existingReaction, err := portal.bridge.DB.Reaction.GetByMXID(ctx, redacts)
if err != nil {
log.Err(err).Msg("Failed to get redaction target reaction")
return fmt.Errorf("failed to get event from database")
} else if existingReaction == nil {
return errTargetNotFound
}
resp, err := sender.Client.Messages.React(&binary.SendReactionPayload{
MessageID: existingReaction.MessageID,
ReactionData: binary.MakeReactionData(existingReaction.Reaction),
Action: binary.Reaction_REMOVE,
})
if err != nil {
return fmt.Errorf("failed to send reaction removal: %w", err)
} else if !resp.Success {
return fmt.Errorf("got non-success response")
}
err = existingReaction.Delete(ctx)
if err != nil {
log.Err(err).Msg("Failed to remove reaction from database after Matrix redaction")
}
return nil
}
func (portal *Portal) handleMatrixRedaction(sender *User, evt *event.Event) error {
log := portal.zlog.With().
Str("event_id", evt.ID.String()).
Str("target_event_id", evt.Redacts.String()).
Str("action", "handle matrix redaction").
Logger()
ctx := log.WithContext(context.TODO())
log.Debug().Msg("Handling Matrix redaction")
err := portal.handleMatrixMessageRedaction(ctx, sender, evt.Redacts)
if err == errTargetNotFound {
err = portal.handleMatrixReactionRedaction(ctx, sender, evt.Redacts)
}
return err
}
func (portal *Portal) Delete() {
err := portal.Portal.Delete(context.TODO())
if err != nil {