Переглянути джерело

Add option to query message from phone when send times out

Tulir Asokan 5 роки тому
батько
коміт
5a62982a56
3 змінених файлів з 61 додано та 33 видалено
  1. 1 0
      config/bridge.go
  2. 4 0
      example-config.yaml
  3. 56 33
      portal.go

+ 1 - 0
config/bridge.go

@@ -36,6 +36,7 @@ type BridgeConfig struct {
 	CommunityTemplate   string `yaml:"community_template"`
 
 	ConnectionTimeout     int  `yaml:"connection_timeout"`
+	FetchMessageOnTimeout bool `yaml:"fetch_message_on_timeout"`
 	LoginQRRegenCount     int  `yaml:"login_qr_regen_count"`
 	MaxConnectionAttempts int  `yaml:"max_connection_attempts"`
 	ConnectionRetryDelay  int  `yaml:"connection_retry_delay"`

+ 4 - 0
example-config.yaml

@@ -73,6 +73,10 @@ bridge:
 
     # WhatsApp connection timeout in seconds.
     connection_timeout: 20
+    # If WhatsApp doesn't respond within connection_timeout, should the bridge try to fetch the message
+    # to see if it was actually bridged? Use this if you have problems with sends timing out but actually
+    # succeeding.
+    fetch_message_on_timeout: false
     # Number of times to regenerate QR code when logging in.
     # The regenerated QR code is sent as an edit and essentially multiplies the login timeout (20 seconds)
     login_qr_regen_count: 2

+ 56 - 33
portal.go

@@ -1263,17 +1263,11 @@ func (portal *Portal) addRelaybotFormat(sender *User, content *event.MessageEven
 	return true
 }
 
-func (portal *Portal) HandleMatrixMessage(sender *User, evt *event.Event) {
-	if !portal.HasRelaybot() && (
-		(portal.IsPrivateChat() && sender.JID != portal.Key.Receiver) ||
-			portal.sendMatrixConnectionError(sender, evt.ID)) {
-		return
-	}
+func (portal *Portal) convertMatrixMessage(sender *User, evt *event.Event) *waProto.WebMessageInfo {
 	content := evt.Content.AsMessage()
 	if content == nil {
-		return
+		return nil
 	}
-	portal.log.Debugfln("Received event %s", evt.ID)
 
 	ts := uint64(evt.Timestamp / 1000)
 	status := waProto.WebMessageInfo_ERROR
@@ -1306,7 +1300,7 @@ func (portal *Portal) HandleMatrixMessage(sender *User, evt *event.Event) {
 				portal.log.Debugln("Database says", sender.MXID, "not in chat and no relaybot, but trying to send anyway")
 			} else {
 				portal.log.Debugln("Ignoring message from", sender.MXID, "in chat with no relaybot")
-				return
+				return nil
 			}
 		} else {
 			relaybotFormatted = portal.addRelaybotFormat(sender, content)
@@ -1316,7 +1310,7 @@ func (portal *Portal) HandleMatrixMessage(sender *User, evt *event.Event) {
 	if evt.Type == event.EventSticker {
 		content.MsgType = event.MsgImage
 	}
-	var err error
+
 	switch content.MsgType {
 	case event.MsgText, event.MsgEmote, event.MsgNotice:
 		text := content.Body
@@ -1341,7 +1335,7 @@ func (portal *Portal) HandleMatrixMessage(sender *User, evt *event.Event) {
 	case event.MsgImage:
 		media := portal.preprocessMatrixMedia(sender, relaybotFormatted, content, evt.ID, whatsapp.MediaImage)
 		if media == nil {
-			return
+			return nil
 		}
 		info.Message.ImageMessage = &waProto.ImageMessage{
 			Caption:       &media.Caption,
@@ -1356,7 +1350,7 @@ func (portal *Portal) HandleMatrixMessage(sender *User, evt *event.Event) {
 	case event.MsgVideo:
 		media := portal.preprocessMatrixMedia(sender, relaybotFormatted, content, evt.ID, whatsapp.MediaVideo)
 		if media == nil {
-			return
+			return nil
 		}
 		duration := uint32(content.GetInfo().Duration)
 		info.Message.VideoMessage = &waProto.VideoMessage{
@@ -1373,7 +1367,7 @@ func (portal *Portal) HandleMatrixMessage(sender *User, evt *event.Event) {
 	case event.MsgAudio:
 		media := portal.preprocessMatrixMedia(sender, relaybotFormatted, content, evt.ID, whatsapp.MediaAudio)
 		if media == nil {
-			return
+			return nil
 		}
 		duration := uint32(content.GetInfo().Duration)
 		info.Message.AudioMessage = &waProto.AudioMessage{
@@ -1388,7 +1382,7 @@ func (portal *Portal) HandleMatrixMessage(sender *User, evt *event.Event) {
 	case event.MsgFile:
 		media := portal.preprocessMatrixMedia(sender, relaybotFormatted, content, evt.ID, whatsapp.MediaDocument)
 		if media == nil {
-			return
+			return nil
 		}
 		info.Message.DocumentMessage = &waProto.DocumentMessage{
 			Url:           &media.URL,
@@ -1401,44 +1395,73 @@ func (portal *Portal) HandleMatrixMessage(sender *User, evt *event.Event) {
 		}
 	default:
 		portal.log.Debugln("Unhandled Matrix event:", evt)
+		return nil
+	}
+	return info
+}
+
+func (portal *Portal) wasMessageSent(sender *User, id string) bool {
+	_, err := sender.Conn.LoadMessagesAfter(portal.Key.JID, id, true, 0)
+	if err != nil {
+		if err != whatsapp.ErrServerRespondedWith404 {
+			portal.log.Warnfln("Failed to check if message was bridged without response: %v", err)
+		}
+		return false
+	}
+	return true
+}
+
+func (portal *Portal) sendErrorMessage(sendErr error) id.EventID {
+	resp, err := portal.sendMainIntentMessage(event.MessageEventContent{
+		MsgType: event.MsgNotice,
+		Body:    fmt.Sprintf("\u26a0 Your message may not have been bridged: %v", sendErr),
+	})
+	if err != nil {
+		portal.log.Warnfln("Failed to send bridging error message:", err)
+		return ""
+	}
+	return resp.EventID
+}
+
+var timeout = errors.New("message sending timed out")
+
+func (portal *Portal) HandleMatrixMessage(sender *User, evt *event.Event) {
+	if !portal.HasRelaybot() && (
+		(portal.IsPrivateChat() && sender.JID != portal.Key.Receiver) ||
+			portal.sendMatrixConnectionError(sender, evt.ID)) {
 		return
 	}
+	portal.log.Debugfln("Received event %s", evt.ID)
+	info := portal.convertMatrixMessage(sender, evt)
 	portal.markHandled(sender, info, evt.ID)
 	portal.log.Debugln("Sending event", evt.ID, "to WhatsApp")
 
 	errChan := make(chan error, 1)
 	go sender.Conn.SendRaw(info, errChan)
 
-	var errorSendResp *mautrix.RespSendEvent
+	var err error
+	var errorEventID id.EventID
 	select {
 	case err = <-errChan:
 	case <-time.After(time.Duration(portal.bridge.Config.Bridge.ConnectionTimeout) * time.Second):
-		portal.log.Warnfln("Response when bridging Matrix event %s is taking long to arrive", evt.ID)
-		errorSendResp, err = portal.sendMainIntentMessage(event.MessageEventContent{
-			MsgType: event.MsgNotice,
-			Body: fmt.Sprintf("\u26a0 Your message may not have been bridged: message sending timed out"),
-		})
-		if err != nil {
-			portal.log.Warnfln("Failed to send bridging timeout message:", err)
+		if portal.bridge.Config.Bridge.FetchMessageOnTimeout && portal.wasMessageSent(sender, info.Key.GetId()) {
+			portal.log.Debugln("Matrix event %s was bridged, but response didn't arrive within timeout")
+		} else {
+			portal.log.Warnfln("Response when bridging Matrix event %s is taking long to arrive", evt.ID)
+			errorEventID = portal.sendErrorMessage(timeout)
 		}
 		err = <-errChan
 	}
 	if err != nil {
 		portal.log.Errorfln("Error handling Matrix event %s: %v", evt.ID, err)
-		_, err = portal.sendMainIntentMessage(event.MessageEventContent{
-			MsgType: event.MsgNotice,
-			Body: fmt.Sprintf("\u26a0 Your message may not have been bridged: %v", err),
-		})
-		if err != nil {
-			portal.log.Warnfln("Failed to send bridging failure message:", err)
-		}
+		portal.sendErrorMessage(err)
 	} else {
-		portal.log.Debugln("Handled Matrix event %s", evt.ID)
+		portal.log.Debugfln("Handled Matrix event %s", evt.ID)
 	}
-	if errorSendResp != nil {
-		_, err = portal.MainIntent().RedactEvent(portal.MXID, errorSendResp.EventID)
+	if errorEventID != "" {
+		_, err = portal.MainIntent().RedactEvent(portal.MXID, errorEventID)
 		if err != nil {
-			portal.log.Warnfln("Failed to redact timeout warning message %s: %v", errorSendResp.EventID, err)
+			portal.log.Warnfln("Failed to redact timeout warning message %s: %v", errorEventID, err)
 		}
 	}
 }