Browse Source

Move read receipt handling to portal loop

This ensures that read receipts are only handled after the message
they're pointing at, even if the read receipt is sent immediately
(e.g. when the user has WhatsApp open on their phone).
Tulir Asokan 3 năm trước cách đây
mục cha
commit
9e39ce565b
2 tập tin đã thay đổi với 48 bổ sung34 xóa
  1. 47 0
      portal.go
  2. 1 34
      user.go

+ 47 - 0
portal.go

@@ -139,6 +139,7 @@ func (bridge *Bridge) NewManualPortal(key database.PortalKey) *Portal {
 		log:    bridge.Log.Sub(fmt.Sprintf("Portal/%s", key)),
 
 		messages:       make(chan PortalMessage, bridge.Config.Bridge.PortalMessageBuffer),
+		receipts:       make(chan PortalReceipt, bridge.Config.Bridge.PortalMessageBuffer),
 		matrixMessages: make(chan PortalMatrixMessage, bridge.Config.Bridge.PortalMessageBuffer),
 	}
 	portal.Key = key
@@ -153,6 +154,7 @@ func (bridge *Bridge) NewPortal(dbPortal *database.Portal) *Portal {
 		log:    bridge.Log.Sub(fmt.Sprintf("Portal/%s", dbPortal.Key)),
 
 		messages:       make(chan PortalMessage, bridge.Config.Bridge.PortalMessageBuffer),
+		receipts:       make(chan PortalReceipt, bridge.Config.Bridge.PortalMessageBuffer),
 		matrixMessages: make(chan PortalMatrixMessage, bridge.Config.Bridge.PortalMessageBuffer),
 	}
 	go portal.handleMessageLoop()
@@ -176,6 +178,11 @@ type PortalMessage struct {
 	source        *User
 }
 
+type PortalReceipt struct {
+	evt    *events.Receipt
+	source *User
+}
+
 type PortalMatrixMessage struct {
 	evt  *event.Event
 	user *User
@@ -206,6 +213,7 @@ type Portal struct {
 	currentlyTypingLock sync.Mutex
 
 	messages       chan PortalMessage
+	receipts       chan PortalReceipt
 	matrixMessages chan PortalMatrixMessage
 
 	relayUser *User
@@ -248,11 +256,50 @@ func (portal *Portal) handleMatrixMessageLoopItem(msg PortalMatrixMessage) {
 	}
 }
 
+func (portal *Portal) handleReceipt(receipt *events.Receipt, source *User) {
+	// The order of the message ID array depends on the sender's platform, so we just have to find
+	// the last message based on timestamp. Also, timestamps only have second precision, so if
+	// there are many messages at the same second just mark them all as read, because we don't
+	// know which one is last
+	markAsRead := make([]*database.Message, 0, 1)
+	var bestTimestamp time.Time
+	for _, msgID := range receipt.MessageIDs {
+		msg := portal.bridge.DB.Message.GetByJID(portal.Key, msgID)
+		if msg == nil || msg.IsFakeMXID() {
+			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)
+		}
+	}
+	if receipt.Sender.User == source.JID.User {
+		if len(markAsRead) > 0 {
+			source.SetLastReadTS(portal.Key, markAsRead[0].Timestamp)
+		} else {
+			source.SetLastReadTS(portal.Key, receipt.Timestamp)
+		}
+	}
+	intent := portal.bridge.GetPuppetByJID(receipt.Sender).IntentFor(portal)
+	for _, msg := range markAsRead {
+		err := intent.SetReadMarkers(portal.MXID, makeReadMarkerContent(msg.MXID, intent.IsCustomPuppet))
+		if err != nil {
+			portal.log.Warnfln("Failed to mark message %s as read by %s: %v", msg.MXID, intent.UserID, err)
+		} else {
+			portal.log.Debugfln("Marked %s as read by %s", msg.MXID, intent.UserID)
+		}
+	}
+}
+
 func (portal *Portal) handleMessageLoop() {
 	for {
 		select {
 		case msg := <-portal.messages:
 			portal.handleMessageLoopItem(msg)
+		case receipt := <-portal.receipts:
+			portal.handleReceipt(receipt.evt, receipt.source)
 		case msg := <-portal.matrixMessages:
 			portal.handleMatrixMessageLoopItem(msg)
 		}

+ 1 - 34
user.go

@@ -851,40 +851,7 @@ func (user *User) handleReceipt(receipt *events.Receipt) {
 	if portal == nil || len(portal.MXID) == 0 {
 		return
 	}
-	// The order of the message ID array depends on the sender's platform, so we just have to find
-	// the last message based on timestamp. Also, timestamps only have second precision, so if
-	// there are many messages at the same second just mark them all as read, because we don't
-	// know which one is last
-	markAsRead := make([]*database.Message, 0, 1)
-	var bestTimestamp time.Time
-	for _, msgID := range receipt.MessageIDs {
-		msg := user.bridge.DB.Message.GetByJID(portal.Key, msgID)
-		if msg == nil || msg.IsFakeMXID() {
-			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)
-		}
-	}
-	if receipt.Sender.User == user.JID.User {
-		if len(markAsRead) > 0 {
-			user.SetLastReadTS(portal.Key, markAsRead[0].Timestamp)
-		} else {
-			user.SetLastReadTS(portal.Key, receipt.Timestamp)
-		}
-	}
-	intent := user.bridge.GetPuppetByJID(receipt.Sender).IntentFor(portal)
-	for _, msg := range markAsRead {
-		err := intent.SetReadMarkers(portal.MXID, makeReadMarkerContent(msg.MXID, intent.IsCustomPuppet))
-		if err != nil {
-			user.log.Warnfln("Failed to mark message %s as read by %s: %v", msg.MXID, intent.UserID, err)
-		} else {
-			user.log.Debugfln("Marked %s as read by %s", msg.MXID, intent.UserID)
-		}
-	}
+	portal.receipts <- PortalReceipt{evt: receipt, source: user}
 }
 
 func makeReadMarkerContent(eventID id.EventID, doublePuppet bool) CustomReadMarkers {