Browse Source

Slightly improve waiting for inbound Megolm sessions

Tulir Asokan 4 years ago
parent
commit
6315dac2eb
1 changed files with 52 additions and 6 deletions
  1. 52 6
      matrix.go

+ 52 - 6
matrix.go

@@ -332,7 +332,7 @@ func (mx *MatrixHandler) shouldIgnoreEvent(evt *event.Event) bool {
 	return false
 }
 
-const sessionWaitTimeout = 3 * time.Second
+const sessionWaitTimeout = 5 * time.Second
 
 func (mx *MatrixHandler) HandleEncrypted(evt *event.Event) {
 	defer mx.bridge.Metrics.TrackEvent(evt.Type)()
@@ -341,23 +341,69 @@ func (mx *MatrixHandler) HandleEncrypted(evt *event.Event) {
 	}
 
 	decrypted, err := mx.bridge.Crypto.Decrypt(evt)
-	if err != nil {
+	if errors.Is(err, NoSessionFound) {
 		content := evt.Content.AsEncrypted()
-		if errors.Is(err, NoSessionFound) && mx.bridge.Crypto.WaitForSession(evt.RoomID, content.SenderKey, content.SessionID, sessionWaitTimeout) {
-			mx.log.Debugfln("Got session %s to decrypt %s after waiting a while, trying to decrypt again", evt.ID, content.SessionID)
+		mx.log.Debugfln("Couldn't find session %s trying to decrypt %s, waiting %d seconds...", content.SessionID, evt.ID, int(sessionWaitTimeout.Seconds()))
+		if mx.bridge.Crypto.WaitForSession(evt.RoomID, content.SenderKey, content.SessionID, sessionWaitTimeout) {
+			mx.log.Debugfln("Got session %s after waiting, trying to decrypt %s again", content.SessionID, evt.ID)
 			decrypted, err = mx.bridge.Crypto.Decrypt(evt)
+		} else {
+			go mx.waitLongerForSession(evt)
+			return
 		}
 	}
 	if err != nil {
 		mx.log.Warnfln("Failed to decrypt %s: %v", evt.ID, err)
 		_, _ = mx.bridge.Bot.SendNotice(evt.RoomID, fmt.Sprintf(
-			"\u26a0 Your message was not bridged: %v. "+
-				"Try restarting your client if this error keeps happening.", err))
+			"\u26a0 Your message was not bridged: %v", err))
 		return
 	}
 	mx.bridge.EventProcessor.Dispatch(decrypted)
 }
 
+func (mx *MatrixHandler) waitLongerForSession(evt *event.Event) {
+	const extendedTimeout = sessionWaitTimeout * 2
+
+	content := evt.Content.AsEncrypted()
+	mx.log.Debugfln("Couldn't find session %s trying to decrypt %s, waiting %d more seconds...",
+		content.SessionID, evt.ID, int(extendedTimeout.Seconds()))
+
+	resp, err := mx.bridge.Bot.SendNotice(evt.RoomID, fmt.Sprintf(
+		"\u26a0 Your message was not bridged: the bridge hasn't received the decryption keys. "+
+			"The bridge will retry for %d seconds. If this error keeps happening, try restarting your client.",
+		int(extendedTimeout.Seconds())))
+	if err != nil {
+		mx.log.Errorfln("Failed to send decryption error to %s: %v", evt.RoomID, err)
+	}
+	update := event.MessageEventContent{MsgType: event.MsgNotice}
+
+	if mx.bridge.Crypto.WaitForSession(evt.RoomID, content.SenderKey, content.SessionID, extendedTimeout) {
+		mx.log.Debugfln("Got session %s after waiting more, trying to decrypt %s again", content.SessionID, evt.ID)
+		decrypted, err := mx.bridge.Crypto.Decrypt(evt)
+		if err != nil {
+			mx.bridge.EventProcessor.Dispatch(decrypted)
+			_, _ = mx.bridge.Bot.RedactEvent(evt.RoomID, resp.EventID)
+			return
+		}
+		mx.log.Warnfln("Failed to decrypt %s: %v", err)
+		update.Body = fmt.Sprintf("\u26a0 Your message was not bridged: %v", err)
+	} else {
+		mx.log.Debugfln("Didn't get %s, giving up on %s", content.SessionID, evt.ID)
+		update.Body = "\u26a0 Your message was not bridged: the bridge hasn't received the decryption keys. " +
+			"If this keeps happening, try restarting your client."
+	}
+
+	newContent := update
+	update.NewContent = &newContent
+	if resp != nil {
+		update.RelatesTo = &event.RelatesTo{
+			Type:    event.RelReplace,
+			EventID: resp.EventID,
+		}
+	}
+	_, _ = mx.bridge.Bot.SendMessageEvent(evt.RoomID, event.EventMessage, &update)
+}
+
 func (mx *MatrixHandler) HandleMessage(evt *event.Event) {
 	defer mx.bridge.Metrics.TrackEvent(evt.Type)()
 	if mx.shouldIgnoreEvent(evt) {