Fix bridging receipts with multiple message IDs

This commit is contained in:
Tulir Asokan 2021-11-10 20:26:28 +02:00
parent 5c1b57d7b8
commit 6b260dceda
3 changed files with 27 additions and 53 deletions

2
go.mod
View file

@ -8,7 +8,7 @@ require (
github.com/mattn/go-sqlite3 v1.14.9 github.com/mattn/go-sqlite3 v1.14.9
github.com/prometheus/client_golang v1.11.0 github.com/prometheus/client_golang v1.11.0
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
go.mau.fi/whatsmeow v0.0.0-20211109215855-2e8804d7e690 go.mau.fi/whatsmeow v0.0.0-20211110182414-ba28bae40fb5
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d
google.golang.org/protobuf v1.27.1 google.golang.org/protobuf v1.27.1
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b

4
go.sum
View file

@ -139,8 +139,8 @@ github.com/tidwall/sjson v1.2.3 h1:5+deguEhHSEjmuICXZ21uSSsXotWMA0orU783+Z7Cp8=
github.com/tidwall/sjson v1.2.3/go.mod h1:5WdjKx3AQMvCJ4RG6/2UYT7dLrGvJUV1x4jdTAyGvZs= github.com/tidwall/sjson v1.2.3/go.mod h1:5WdjKx3AQMvCJ4RG6/2UYT7dLrGvJUV1x4jdTAyGvZs=
go.mau.fi/libsignal v0.0.0-20211109153248-a67163214910 h1:9FFhG0OmkuMau5UEaTgiUQ+7cSbtbOQ7hiWKdN8OI3I= go.mau.fi/libsignal v0.0.0-20211109153248-a67163214910 h1:9FFhG0OmkuMau5UEaTgiUQ+7cSbtbOQ7hiWKdN8OI3I=
go.mau.fi/libsignal v0.0.0-20211109153248-a67163214910/go.mod h1:AufGrvVh+00Nc07Jm4hTquh7yleZyn20tKJI2wCPAKg= go.mau.fi/libsignal v0.0.0-20211109153248-a67163214910/go.mod h1:AufGrvVh+00Nc07Jm4hTquh7yleZyn20tKJI2wCPAKg=
go.mau.fi/whatsmeow v0.0.0-20211109215855-2e8804d7e690 h1:Yx5v2ut+kd5YG+bLhCxqPnCEZ+yau2wKsQerk3VYtbY= go.mau.fi/whatsmeow v0.0.0-20211110182414-ba28bae40fb5 h1:ERlXDWd0vj62SldgFSqCkjtVpyUgmxRtyKMH20ADW7Q=
go.mau.fi/whatsmeow v0.0.0-20211109215855-2e8804d7e690/go.mod h1:8jUjOAi3xtGubxcZgG8uSHpAdyQXBRbWAfxkctX/4y4= go.mau.fi/whatsmeow v0.0.0-20211110182414-ba28bae40fb5/go.mod h1:8jUjOAi3xtGubxcZgG8uSHpAdyQXBRbWAfxkctX/4y4=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=

66
user.go
View file

@ -722,58 +722,32 @@ func (user *User) handleReceipt(receipt *events.Receipt) {
if portal == nil || len(portal.MXID) == 0 { if portal == nil || len(portal.MXID) == 0 {
return return
} }
if receipt.IsFromMe { // The order of the message ID array depends on the sender's platform, so we just have to find
user.markSelfRead(portal, receipt.MessageID) // the last message based on timestamp. Also, timestamps only have second precision, so if
} else { // there are many messages at the same second just mark them all as read, because we don't
intent := user.bridge.GetPuppetByJID(receipt.Sender).IntentFor(portal) // know which one is last
ok := user.markOtherRead(portal, intent, receipt.MessageID) markAsRead := make([]*database.Message, 0, 1)
if !ok { var bestTimestamp time.Time
// Message not found, try any previous IDs for _, msgID := range receipt.MessageIDs {
for i := len(receipt.PreviousIDs) - 1; i >= 0; i-- { msg := user.bridge.DB.Message.GetByJID(portal.Key, msgID)
ok = user.markOtherRead(portal, intent, receipt.PreviousIDs[i])
if ok {
break
}
}
}
}
}
func (user *User) markOtherRead(portal *Portal, intent *appservice.IntentAPI, messageID types.MessageID) bool {
msg := user.bridge.DB.Message.GetByJID(portal.Key, messageID)
if msg == nil || msg.IsFakeMXID() { if msg == nil || msg.IsFakeMXID() {
return false continue
} }
if msg.Timestamp.After(bestTimestamp) {
bestTimestamp = msg.Timestamp
markAsRead = append(markAsRead[:0], msg)
} else if msg != nil && msg.Timestamp.Equal(bestTimestamp) {
markAsRead = append(markAsRead, msg)
}
}
intent := user.bridge.GetPuppetByJID(receipt.Sender).IntentFor(portal)
for _, msg := range markAsRead {
err := intent.MarkReadWithContent(portal.MXID, msg.MXID, &CustomReadReceipt{DoublePuppet: intent.IsCustomPuppet}) err := intent.MarkReadWithContent(portal.MXID, msg.MXID, &CustomReadReceipt{DoublePuppet: intent.IsCustomPuppet})
if err != nil { if err != nil {
user.log.Warnfln("Failed to mark message %s as read by %s: %v", msg.MXID, intent.UserID, err) user.log.Warnfln("Failed to mark message %s as read by %s: %v", msg.MXID, intent.UserID, err)
}
return true
}
func (user *User) markSelfRead(portal *Portal, messageID types.MessageID) {
puppet := user.bridge.GetPuppetByCustomMXID(user.MXID)
if puppet == nil || puppet.CustomIntent() == nil {
return
}
var message *database.Message
if messageID == "" {
message = user.bridge.DB.Message.GetLastInChat(portal.Key)
if message == nil {
return
}
user.log.Debugfln("User read chat %s/%s in WhatsApp mobile (last known event: %s/%s)", portal.Key.JID, portal.MXID, message.JID, message.MXID)
} else { } else {
message = user.bridge.DB.Message.GetByJID(portal.Key, messageID) user.log.Debugfln("Marked %s as read by %s", msg.MXID, intent.UserID)
if message == nil || message.IsFakeMXID() {
return
} }
user.log.Debugfln("User read message %s/%s in %s/%s in WhatsApp mobile", message.JID, message.MXID, portal.Key.JID, portal.MXID)
}
err := puppet.CustomIntent().MarkReadWithContent(portal.MXID, message.MXID, &CustomReadReceipt{DoublePuppet: true})
if err != nil {
user.log.Warnfln("Failed to bridge own read receipt in %s: %v", portal.Key.JID, err)
} }
} }
@ -788,7 +762,7 @@ func (user *User) markSelfReadFull(portal *Portal) {
} }
err := puppet.CustomIntent().MarkReadWithContent(portal.MXID, lastMessage.MXID, &CustomReadReceipt{DoublePuppet: true}) err := puppet.CustomIntent().MarkReadWithContent(portal.MXID, lastMessage.MXID, &CustomReadReceipt{DoublePuppet: true})
if err != nil { if err != nil {
user.log.Warnfln("Failed to mark %s in %s as read after backfill: %v", lastMessage.MXID, portal.MXID, err) user.log.Warnfln("Failed to mark %s (last message) in %s as read: %v", lastMessage.MXID, portal.MXID, err)
} }
} }