mirror of
https://github.com/tulir/mautrix-whatsapp
synced 2024-05-20 12:53:48 +02:00
Add option for max message handling duration
This commit is contained in:
parent
52e3cdb121
commit
d3d69d1a8a
|
@ -363,7 +363,7 @@ func fnCreate(ce *WrappedCommandEvent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ce.Log.Infofln("Creating group for %s with name %s and participants %+v", ce.RoomID, roomNameEvent.Name, participants)
|
ce.Log.Infofln("Creating group for %s with name %s and participants %+v", ce.RoomID, roomNameEvent.Name, participants)
|
||||||
resp, err := ce.User.Client.CreateGroup(roomNameEvent.Name, participants)
|
resp, err := ce.User.Client.CreateGroup(roomNameEvent.Name, participants, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ce.Reply("Failed to create group: %v", err)
|
ce.Reply("Failed to create group: %v", err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
"time"
|
||||||
|
|
||||||
"go.mau.fi/whatsmeow/types"
|
"go.mau.fi/whatsmeow/types"
|
||||||
|
|
||||||
|
@ -109,6 +110,9 @@ type BridgeConfig struct {
|
||||||
URLPreviews bool `yaml:"url_previews"`
|
URLPreviews bool `yaml:"url_previews"`
|
||||||
CaptionInMessage bool `yaml:"caption_in_message"`
|
CaptionInMessage bool `yaml:"caption_in_message"`
|
||||||
|
|
||||||
|
MessageHandlingDeadlineStr string `yaml:"message_handling_deadline"`
|
||||||
|
MessageHandlingDeadline time.Duration `yaml:"-"`
|
||||||
|
|
||||||
DisableStatusBroadcastSend bool `yaml:"disable_status_broadcast_send"`
|
DisableStatusBroadcastSend bool `yaml:"disable_status_broadcast_send"`
|
||||||
DisappearingMessagesInGroups bool `yaml:"disappearing_messages_in_groups"`
|
DisappearingMessagesInGroups bool `yaml:"disappearing_messages_in_groups"`
|
||||||
|
|
||||||
|
@ -195,6 +199,13 @@ func (bc *BridgeConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if bc.MessageHandlingDeadlineStr != "" {
|
||||||
|
bc.MessageHandlingDeadline, err = time.ParseDuration(bc.MessageHandlingDeadlineStr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,6 +91,8 @@ func DoUpgrade(helper *up.Helper) {
|
||||||
helper.Copy(up.Bool, "bridge", "disable_bridge_alerts")
|
helper.Copy(up.Bool, "bridge", "disable_bridge_alerts")
|
||||||
helper.Copy(up.Bool, "bridge", "url_previews")
|
helper.Copy(up.Bool, "bridge", "url_previews")
|
||||||
helper.Copy(up.Bool, "bridge", "caption_in_message")
|
helper.Copy(up.Bool, "bridge", "caption_in_message")
|
||||||
|
helper.Copy(up.Str|up.Null, "bridge", "message_handling_deadline")
|
||||||
|
|
||||||
helper.Copy(up.Str, "bridge", "management_room_text", "welcome")
|
helper.Copy(up.Str, "bridge", "management_room_text", "welcome")
|
||||||
helper.Copy(up.Str, "bridge", "management_room_text", "welcome_connected")
|
helper.Copy(up.Str, "bridge", "management_room_text", "welcome_connected")
|
||||||
helper.Copy(up.Str, "bridge", "management_room_text", "welcome_unconnected")
|
helper.Copy(up.Str, "bridge", "management_room_text", "welcome_unconnected")
|
||||||
|
|
|
@ -280,6 +280,9 @@ bridge:
|
||||||
# Send captions in the same message as images. This will send data compatible with both MSC2530 and MSC3552.
|
# Send captions in the same message as images. This will send data compatible with both MSC2530 and MSC3552.
|
||||||
# This is currently not supported in most clients.
|
# This is currently not supported in most clients.
|
||||||
caption_in_message: false
|
caption_in_message: false
|
||||||
|
# Maximum time for handling Matrix events. A duration string formatted for https://pkg.go.dev/time#ParseDuration
|
||||||
|
# Null means there's no enforced timeout.
|
||||||
|
message_handling_deadline: null
|
||||||
|
|
||||||
# The prefix for commands. Only required in non-management rooms.
|
# The prefix for commands. Only required in non-management rooms.
|
||||||
command_prefix: "!wa"
|
command_prefix: "!wa"
|
||||||
|
|
4
go.mod
4
go.mod
|
@ -10,12 +10,12 @@ require (
|
||||||
github.com/prometheus/client_golang v1.12.2-0.20220613221938-ebd77f036066
|
github.com/prometheus/client_golang v1.12.2-0.20220613221938-ebd77f036066
|
||||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
||||||
github.com/tidwall/gjson v1.14.1
|
github.com/tidwall/gjson v1.14.1
|
||||||
go.mau.fi/whatsmeow v0.0.0-20220628131901-3f187acf2229
|
go.mau.fi/whatsmeow v0.0.0-20220629162100-72294010aba7
|
||||||
golang.org/x/image v0.0.0-20220617043117-41969df76e82
|
golang.org/x/image v0.0.0-20220617043117-41969df76e82
|
||||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e
|
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e
|
||||||
google.golang.org/protobuf v1.28.0
|
google.golang.org/protobuf v1.28.0
|
||||||
maunium.net/go/maulogger/v2 v2.3.2
|
maunium.net/go/maulogger/v2 v2.3.2
|
||||||
maunium.net/go/mautrix v0.11.1-0.20220628090842-e9aa4b6f3ac8
|
maunium.net/go/mautrix v0.11.1-0.20220629165511-d505965036ef
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|
8
go.sum
8
go.sum
|
@ -64,8 +64,8 @@ github.com/yuin/goldmark v1.4.12 h1:6hffw6vALvEDqJ19dOJvJKOoAOKe4NDaTqvd2sktGN0=
|
||||||
github.com/yuin/goldmark v1.4.12/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.12/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
go.mau.fi/libsignal v0.0.0-20220628090436-4d18b66b087e h1:ByHDg+D+dMIGuBA2n+1xOUf4xr3FJFYg8yxl06s1YBE=
|
go.mau.fi/libsignal v0.0.0-20220628090436-4d18b66b087e h1:ByHDg+D+dMIGuBA2n+1xOUf4xr3FJFYg8yxl06s1YBE=
|
||||||
go.mau.fi/libsignal v0.0.0-20220628090436-4d18b66b087e/go.mod h1:RCdzkTWSJv0AKGqurzPXJsEGIVMuQps3E/h7CMUPous=
|
go.mau.fi/libsignal v0.0.0-20220628090436-4d18b66b087e/go.mod h1:RCdzkTWSJv0AKGqurzPXJsEGIVMuQps3E/h7CMUPous=
|
||||||
go.mau.fi/whatsmeow v0.0.0-20220628131901-3f187acf2229 h1:iTJ65cHF4PKn9pTUnbPus6FdFeLXSOvm04FwJwq11hA=
|
go.mau.fi/whatsmeow v0.0.0-20220629162100-72294010aba7 h1:W3wefHGUb4WheA49V9bNK4hNugAqr49XyYRvUb/WC7Y=
|
||||||
go.mau.fi/whatsmeow v0.0.0-20220628131901-3f187acf2229/go.mod h1:hsjqq2xLuoFew8vbsDCJcGf5EbXCRcR/yoQ+87w6m3k=
|
go.mau.fi/whatsmeow v0.0.0-20220629162100-72294010aba7/go.mod h1:hsjqq2xLuoFew8vbsDCJcGf5EbXCRcR/yoQ+87w6m3k=
|
||||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
|
||||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/image v0.0.0-20220617043117-41969df76e82 h1:KpZB5pUSBvrHltNEdK/tw0xlPeD13M6M6aGP32gKqiw=
|
golang.org/x/image v0.0.0-20220617043117-41969df76e82 h1:KpZB5pUSBvrHltNEdK/tw0xlPeD13M6M6aGP32gKqiw=
|
||||||
|
@ -108,5 +108,5 @@ maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M=
|
||||||
maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA=
|
maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA=
|
||||||
maunium.net/go/maulogger/v2 v2.3.2 h1:1XmIYmMd3PoQfp9J+PaHhpt80zpfmMqaShzUTC7FwY0=
|
maunium.net/go/maulogger/v2 v2.3.2 h1:1XmIYmMd3PoQfp9J+PaHhpt80zpfmMqaShzUTC7FwY0=
|
||||||
maunium.net/go/maulogger/v2 v2.3.2/go.mod h1:TYWy7wKwz/tIXTpsx8G3mZseIRiC5DoMxSZazOHy68A=
|
maunium.net/go/maulogger/v2 v2.3.2/go.mod h1:TYWy7wKwz/tIXTpsx8G3mZseIRiC5DoMxSZazOHy68A=
|
||||||
maunium.net/go/mautrix v0.11.1-0.20220628090842-e9aa4b6f3ac8 h1:c5xjJlWALgEVLN3CWA77PrEvyGb9yrAcCq/9RJ/+Ubo=
|
maunium.net/go/mautrix v0.11.1-0.20220629165511-d505965036ef h1:v5axLh3G3cNDNEOn8vCJpafSk4hp7I+aYjmoTq6OjlY=
|
||||||
maunium.net/go/mautrix v0.11.1-0.20220628090842-e9aa4b6f3ac8/go.mod h1:Lj4pBam5P0zIvieIFHnGsuaj+xfFtI3y/sC8yGlyna8=
|
maunium.net/go/mautrix v0.11.1-0.20220629165511-d505965036ef/go.mod h1:Lj4pBam5P0zIvieIFHnGsuaj+xfFtI3y/sC8yGlyna8=
|
||||||
|
|
88
portal.go
88
portal.go
|
@ -967,6 +967,7 @@ func (user *User) updateAvatar(jid types.JID, avatarID *string, avatarURL *id.Co
|
||||||
}
|
}
|
||||||
*avatarURL = url
|
*avatarURL = url
|
||||||
}
|
}
|
||||||
|
log.Debugfln("Updated avatar %s -> %s", *avatarID, avatar.ID)
|
||||||
*avatarID = avatar.ID
|
*avatarID = avatar.ID
|
||||||
*avatarSet = false
|
*avatarSet = false
|
||||||
return true
|
return true
|
||||||
|
@ -2777,12 +2778,12 @@ func createJPEGThumbnail(source []byte) ([]byte, error) {
|
||||||
return data, err
|
return data, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (portal *Portal) downloadThumbnail(original []byte, thumbnailURL id.ContentURIString, eventID id.EventID) ([]byte, error) {
|
func (portal *Portal) downloadThumbnail(ctx context.Context, original []byte, thumbnailURL id.ContentURIString, eventID id.EventID) ([]byte, error) {
|
||||||
if len(thumbnailURL) == 0 {
|
if len(thumbnailURL) == 0 {
|
||||||
// just fall back to making thumbnail of original
|
// just fall back to making thumbnail of original
|
||||||
} else if mxc, err := thumbnailURL.Parse(); err != nil {
|
} else if mxc, err := thumbnailURL.Parse(); err != nil {
|
||||||
portal.log.Warnfln("Malformed thumbnail URL in %s: %v (falling back to generating thumbnail from source)", eventID, err)
|
portal.log.Warnfln("Malformed thumbnail URL in %s: %v (falling back to generating thumbnail from source)", eventID, err)
|
||||||
} else if thumbnail, err := portal.MainIntent().DownloadBytes(mxc); err != nil {
|
} else if thumbnail, err := portal.MainIntent().DownloadBytesContext(ctx, mxc); err != nil {
|
||||||
portal.log.Warnfln("Failed to download thumbnail in %s: %v (falling back to generating thumbnail from source)", eventID, err)
|
portal.log.Warnfln("Failed to download thumbnail in %s: %v (falling back to generating thumbnail from source)", eventID, err)
|
||||||
} else {
|
} else {
|
||||||
return createJPEGThumbnail(thumbnail)
|
return createJPEGThumbnail(thumbnail)
|
||||||
|
@ -2804,7 +2805,7 @@ func (portal *Portal) convertWebPtoPNG(webpImage []byte) ([]byte, error) {
|
||||||
return pngBuffer.Bytes(), nil
|
return pngBuffer.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (portal *Portal) preprocessMatrixMedia(sender *User, relaybotFormatted bool, content *event.MessageEventContent, eventID id.EventID, mediaType whatsmeow.MediaType) (*MediaUpload, error) {
|
func (portal *Portal) preprocessMatrixMedia(ctx context.Context, sender *User, relaybotFormatted bool, content *event.MessageEventContent, eventID id.EventID, mediaType whatsmeow.MediaType) (*MediaUpload, error) {
|
||||||
var caption string
|
var caption string
|
||||||
var mentionedJIDs []string
|
var mentionedJIDs []string
|
||||||
if relaybotFormatted {
|
if relaybotFormatted {
|
||||||
|
@ -2821,7 +2822,7 @@ func (portal *Portal) preprocessMatrixMedia(sender *User, relaybotFormatted bool
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
data, err := portal.MainIntent().DownloadBytes(mxc)
|
data, err := portal.MainIntent().DownloadBytesContext(ctx, mxc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewDualError(errMediaDownloadFailed, err)
|
return nil, util.NewDualError(errMediaDownloadFailed, err)
|
||||||
}
|
}
|
||||||
|
@ -2832,7 +2833,7 @@ func (portal *Portal) preprocessMatrixMedia(sender *User, relaybotFormatted bool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if mediaType == whatsmeow.MediaVideo && content.GetInfo().MimeType == "image/gif" {
|
if mediaType == whatsmeow.MediaVideo && content.GetInfo().MimeType == "image/gif" {
|
||||||
data, err = ffmpeg.ConvertBytes(data, ".mp4", []string{"-f", "gif"}, []string{
|
data, err = ffmpeg.ConvertBytes(ctx, data, ".mp4", []string{"-f", "gif"}, []string{
|
||||||
"-pix_fmt", "yuv420p", "-c:v", "libx264", "-movflags", "+faststart",
|
"-pix_fmt", "yuv420p", "-c:v", "libx264", "-movflags", "+faststart",
|
||||||
"-filter:v", "crop='floor(in_w/2)*2:floor(in_h/2)*2'",
|
"-filter:v", "crop='floor(in_w/2)*2:floor(in_h/2)*2'",
|
||||||
}, content.GetInfo().MimeType)
|
}, content.GetInfo().MimeType)
|
||||||
|
@ -2848,7 +2849,7 @@ func (portal *Portal) preprocessMatrixMedia(sender *User, relaybotFormatted bool
|
||||||
}
|
}
|
||||||
content.Info.MimeType = "image/png"
|
content.Info.MimeType = "image/png"
|
||||||
}
|
}
|
||||||
uploadResp, err := sender.Client.Upload(context.Background(), data, mediaType)
|
uploadResp, err := sender.Client.Upload(ctx, data, mediaType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewDualError(errMediaWhatsAppUploadFailed, err)
|
return nil, util.NewDualError(errMediaWhatsAppUploadFailed, err)
|
||||||
}
|
}
|
||||||
|
@ -2856,7 +2857,7 @@ func (portal *Portal) preprocessMatrixMedia(sender *User, relaybotFormatted bool
|
||||||
// Audio doesn't have thumbnails
|
// Audio doesn't have thumbnails
|
||||||
var thumbnail []byte
|
var thumbnail []byte
|
||||||
if mediaType != whatsmeow.MediaAudio {
|
if mediaType != whatsmeow.MediaAudio {
|
||||||
thumbnail, err = portal.downloadThumbnail(data, content.GetInfo().ThumbnailURL, eventID)
|
thumbnail, err = portal.downloadThumbnail(ctx, data, content.GetInfo().ThumbnailURL, eventID)
|
||||||
// Ignore format errors for non-image files, we don't care about those thumbnails
|
// Ignore format errors for non-image files, we don't care about those thumbnails
|
||||||
if err != nil && (!errors.Is(err, image.ErrFormat) || mediaType == whatsmeow.MediaImage) {
|
if err != nil && (!errors.Is(err, image.ErrFormat) || mediaType == whatsmeow.MediaImage) {
|
||||||
portal.log.Warnfln("Failed to generate thumbnail for %s: %v", eventID, err)
|
portal.log.Warnfln("Failed to generate thumbnail for %s: %v", eventID, err)
|
||||||
|
@ -2947,7 +2948,7 @@ func getUnstableWaveform(content map[string]interface{}) []byte {
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
func (portal *Portal) convertMatrixMessage(sender *User, evt *event.Event) (*waProto.Message, *User, error) {
|
func (portal *Portal) convertMatrixMessage(ctx context.Context, sender *User, evt *event.Event) (*waProto.Message, *User, error) {
|
||||||
content, ok := evt.Content.Parsed.(*event.MessageEventContent)
|
content, ok := evt.Content.Parsed.(*event.MessageEventContent)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, sender, fmt.Errorf("%w %T", errUnexpectedParsedContentType, evt.Content.Parsed)
|
return nil, sender, fmt.Errorf("%w %T", errUnexpectedParsedContentType, evt.Content.Parsed)
|
||||||
|
@ -3003,14 +3004,17 @@ func (portal *Portal) convertMatrixMessage(sender *User, evt *event.Event) (*waP
|
||||||
Text: &text,
|
Text: &text,
|
||||||
ContextInfo: &ctxInfo,
|
ContextInfo: &ctxInfo,
|
||||||
}
|
}
|
||||||
hasPreview := portal.convertURLPreviewToWhatsApp(sender, evt, msg.ExtendedTextMessage)
|
hasPreview := portal.convertURLPreviewToWhatsApp(ctx, sender, evt, msg.ExtendedTextMessage)
|
||||||
|
if ctx.Err() != nil {
|
||||||
|
return nil, nil, ctx.Err()
|
||||||
|
}
|
||||||
if ctxInfo.StanzaId == nil && ctxInfo.MentionedJid == nil && ctxInfo.Expiration == nil && !hasPreview {
|
if ctxInfo.StanzaId == nil && ctxInfo.MentionedJid == nil && ctxInfo.Expiration == nil && !hasPreview {
|
||||||
// No need for extended message
|
// No need for extended message
|
||||||
msg.ExtendedTextMessage = nil
|
msg.ExtendedTextMessage = nil
|
||||||
msg.Conversation = &text
|
msg.Conversation = &text
|
||||||
}
|
}
|
||||||
case event.MsgImage:
|
case event.MsgImage:
|
||||||
media, err := portal.preprocessMatrixMedia(sender, relaybotFormatted, content, evt.ID, whatsmeow.MediaImage)
|
media, err := portal.preprocessMatrixMedia(ctx, sender, relaybotFormatted, content, evt.ID, whatsmeow.MediaImage)
|
||||||
if media == nil {
|
if media == nil {
|
||||||
return nil, sender, err
|
return nil, sender, err
|
||||||
}
|
}
|
||||||
|
@ -3028,7 +3032,7 @@ func (portal *Portal) convertMatrixMessage(sender *User, evt *event.Event) (*waP
|
||||||
}
|
}
|
||||||
case event.MsgVideo:
|
case event.MsgVideo:
|
||||||
gifPlayback := content.GetInfo().MimeType == "image/gif"
|
gifPlayback := content.GetInfo().MimeType == "image/gif"
|
||||||
media, err := portal.preprocessMatrixMedia(sender, relaybotFormatted, content, evt.ID, whatsmeow.MediaVideo)
|
media, err := portal.preprocessMatrixMedia(ctx, sender, relaybotFormatted, content, evt.ID, whatsmeow.MediaVideo)
|
||||||
if media == nil {
|
if media == nil {
|
||||||
return nil, sender, err
|
return nil, sender, err
|
||||||
}
|
}
|
||||||
|
@ -3048,7 +3052,7 @@ func (portal *Portal) convertMatrixMessage(sender *User, evt *event.Event) (*waP
|
||||||
FileLength: proto.Uint64(uint64(media.FileLength)),
|
FileLength: proto.Uint64(uint64(media.FileLength)),
|
||||||
}
|
}
|
||||||
case event.MsgAudio:
|
case event.MsgAudio:
|
||||||
media, err := portal.preprocessMatrixMedia(sender, relaybotFormatted, content, evt.ID, whatsmeow.MediaAudio)
|
media, err := portal.preprocessMatrixMedia(ctx, sender, relaybotFormatted, content, evt.ID, whatsmeow.MediaAudio)
|
||||||
if media == nil {
|
if media == nil {
|
||||||
return nil, sender, err
|
return nil, sender, err
|
||||||
}
|
}
|
||||||
|
@ -3071,7 +3075,7 @@ func (portal *Portal) convertMatrixMessage(sender *User, evt *event.Event) (*waP
|
||||||
msg.AudioMessage.Mimetype = proto.String(addCodecToMime(content.GetInfo().MimeType, "opus"))
|
msg.AudioMessage.Mimetype = proto.String(addCodecToMime(content.GetInfo().MimeType, "opus"))
|
||||||
}
|
}
|
||||||
case event.MsgFile:
|
case event.MsgFile:
|
||||||
media, err := portal.preprocessMatrixMedia(sender, relaybotFormatted, content, evt.ID, whatsmeow.MediaDocument)
|
media, err := portal.preprocessMatrixMedia(ctx, sender, relaybotFormatted, content, evt.ID, whatsmeow.MediaDocument)
|
||||||
if media == nil {
|
if media == nil {
|
||||||
return nil, sender, err
|
return nil, sender, err
|
||||||
}
|
}
|
||||||
|
@ -3159,6 +3163,8 @@ func errorToStatusReason(err error) (reason event.MessageStatusReason, isCertain
|
||||||
errors.Is(err, errBroadcastReactionNotSupported),
|
errors.Is(err, errBroadcastReactionNotSupported),
|
||||||
errors.Is(err, errBroadcastSendDisabled):
|
errors.Is(err, errBroadcastSendDisabled):
|
||||||
return event.MessageStatusUnsupported, true, false, true
|
return event.MessageStatusUnsupported, true, false, true
|
||||||
|
case errors.Is(err, context.DeadlineExceeded):
|
||||||
|
return event.MessageStatusTooOld, false, true, true
|
||||||
case errors.Is(err, errTargetNotFound),
|
case errors.Is(err, errTargetNotFound),
|
||||||
errors.Is(err, errTargetIsFake),
|
errors.Is(err, errTargetIsFake),
|
||||||
errors.Is(err, errReactionDatabaseNotFound),
|
errors.Is(err, errReactionDatabaseNotFound),
|
||||||
|
@ -3179,10 +3185,13 @@ func errorToStatusReason(err error) (reason event.MessageStatusReason, isCertain
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (portal *Portal) sendStatusEvent(evtID id.EventID, err error) {
|
func (portal *Portal) sendStatusEvent(evtID, lastRetry id.EventID, err error) {
|
||||||
if !portal.bridge.Config.Bridge.MessageStatusEvents {
|
if !portal.bridge.Config.Bridge.MessageStatusEvents {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if lastRetry == evtID {
|
||||||
|
lastRetry = ""
|
||||||
|
}
|
||||||
intent := portal.bridge.Bot
|
intent := portal.bridge.Bot
|
||||||
if !portal.Encrypted {
|
if !portal.Encrypted {
|
||||||
// Bridge bot isn't present in unencrypted DMs
|
// Bridge bot isn't present in unencrypted DMs
|
||||||
|
@ -3194,7 +3203,8 @@ func (portal *Portal) sendStatusEvent(evtID id.EventID, err error) {
|
||||||
Type: event.RelReference,
|
Type: event.RelReference,
|
||||||
EventID: evtID,
|
EventID: evtID,
|
||||||
},
|
},
|
||||||
Success: err == nil,
|
Success: err == nil,
|
||||||
|
LastRetry: lastRetry,
|
||||||
}
|
}
|
||||||
if !content.Success {
|
if !content.Success {
|
||||||
reason, isCertain, canRetry, _ := errorToStatusReason(err)
|
reason, isCertain, canRetry, _ := errorToStatusReason(err)
|
||||||
|
@ -3247,6 +3257,10 @@ func (portal *Portal) sendMessageMetrics(evt *event.Event, err error, part strin
|
||||||
if evt.Type == event.EventRedaction {
|
if evt.Type == event.EventRedaction {
|
||||||
evtDescription += fmt.Sprintf(" of %s", evt.Redacts)
|
evtDescription += fmt.Sprintf(" of %s", evt.Redacts)
|
||||||
}
|
}
|
||||||
|
origEvtID := evt.ID
|
||||||
|
if retryMeta := evt.Content.AsMessage().MessageSendRetry; retryMeta != nil {
|
||||||
|
origEvtID = retryMeta.OriginalEventID
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
level := log.LevelError
|
level := log.LevelError
|
||||||
if part == "Ignoring" {
|
if part == "Ignoring" {
|
||||||
|
@ -3259,12 +3273,12 @@ func (portal *Portal) sendMessageMetrics(evt *event.Event, err error, part strin
|
||||||
if sendNotice {
|
if sendNotice {
|
||||||
portal.sendErrorMessage(err.Error(), isCertain)
|
portal.sendErrorMessage(err.Error(), isCertain)
|
||||||
}
|
}
|
||||||
portal.sendStatusEvent(evt.ID, err)
|
portal.sendStatusEvent(origEvtID, evt.ID, err)
|
||||||
} else {
|
} else {
|
||||||
portal.log.Debugfln("Handled Matrix %s %s", msgType, evtDescription)
|
portal.log.Debugfln("Handled Matrix %s %s", msgType, evtDescription)
|
||||||
portal.sendDeliveryReceipt(evt.ID)
|
portal.sendDeliveryReceipt(evt.ID)
|
||||||
portal.bridge.SendMessageSuccessCheckpoint(evt, bridge.MsgStepRemote, 0)
|
portal.bridge.SendMessageSuccessCheckpoint(evt, bridge.MsgStepRemote, 0)
|
||||||
portal.sendStatusEvent(evt.ID, nil)
|
portal.sendStatusEvent(origEvtID, evt.ID, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3276,17 +3290,45 @@ func (portal *Portal) HandleMatrixMessage(sender *User, evt *event.Event) {
|
||||||
go portal.sendMessageMetrics(evt, errBroadcastSendDisabled, "Ignoring")
|
go portal.sendMessageMetrics(evt, errBroadcastSendDisabled, "Ignoring")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
portal.log.Debugfln("Received message %s from %s", evt.ID, evt.Sender)
|
origEvtID := evt.ID
|
||||||
msg, sender, err := portal.convertMatrixMessage(sender, evt)
|
var dbMsg *database.Message
|
||||||
|
if retryMeta := evt.Content.AsMessage().MessageSendRetry; retryMeta != nil {
|
||||||
|
origEvtID = retryMeta.OriginalEventID
|
||||||
|
dbMsg = portal.bridge.DB.Message.GetByMXID(origEvtID)
|
||||||
|
if dbMsg != nil && dbMsg.Sent {
|
||||||
|
portal.log.Debugfln("Ignoring retry request %s (#%d) for %s/%s from %s as message was already sent", evt.ID, retryMeta.RetryCount, origEvtID, dbMsg.JID, evt.Sender)
|
||||||
|
go portal.sendMessageMetrics(evt, nil, "")
|
||||||
|
return
|
||||||
|
} else if dbMsg != nil {
|
||||||
|
portal.log.Debugfln("Got retry request %s (#%d) for %s/%s from %s", evt.ID, retryMeta.RetryCount, origEvtID, dbMsg.JID, evt.Sender)
|
||||||
|
} else {
|
||||||
|
portal.log.Debugfln("Got retry request %s (#%d) for %s from %s (original message not known)", evt.ID, retryMeta.RetryCount, origEvtID, evt.Sender)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
portal.log.Debugfln("Received message %s from %s", evt.ID, evt.Sender)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
if portal.bridge.Config.Bridge.MessageHandlingDeadline > 0 {
|
||||||
|
var cancel context.CancelFunc
|
||||||
|
ctx, cancel = context.WithTimeout(ctx, portal.bridge.Config.Bridge.MessageHandlingDeadline)
|
||||||
|
defer cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, sender, err := portal.convertMatrixMessage(ctx, sender, evt)
|
||||||
if msg == nil {
|
if msg == nil {
|
||||||
go portal.sendMessageMetrics(evt, err, "Error converting")
|
go portal.sendMessageMetrics(evt, err, "Error converting")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
portal.MarkDisappearing(evt.ID, portal.ExpirationTime, true)
|
portal.MarkDisappearing(origEvtID, portal.ExpirationTime, true)
|
||||||
info := portal.generateMessageInfo(sender)
|
info := portal.generateMessageInfo(sender)
|
||||||
dbMsg := portal.markHandled(nil, nil, info, evt.ID, false, true, database.MsgNormal, database.MsgNoError)
|
if dbMsg == nil {
|
||||||
|
dbMsg = portal.markHandled(nil, nil, info, evt.ID, false, true, database.MsgNormal, database.MsgNoError)
|
||||||
|
} else {
|
||||||
|
info.ID = dbMsg.JID
|
||||||
|
}
|
||||||
portal.log.Debugln("Sending event", evt.ID, "to WhatsApp", info.ID)
|
portal.log.Debugln("Sending event", evt.ID, "to WhatsApp", info.ID)
|
||||||
ts, err := sender.Client.SendMessage(portal.Key.JID, info.ID, msg)
|
ts, err := sender.Client.SendMessage(ctx, portal.Key.JID, info.ID, msg)
|
||||||
go portal.sendMessageMetrics(evt, err, "Error sending")
|
go portal.sendMessageMetrics(evt, err, "Error sending")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
dbMsg.MarkSent(ts)
|
dbMsg.MarkSent(ts)
|
||||||
|
@ -3346,7 +3388,7 @@ func (portal *Portal) sendReactionToWhatsApp(sender *User, id types.MessageID, t
|
||||||
messageKeyParticipant = proto.String(target.Sender.ToNonAD().String())
|
messageKeyParticipant = proto.String(target.Sender.ToNonAD().String())
|
||||||
}
|
}
|
||||||
key = variationselector.Remove(key)
|
key = variationselector.Remove(key)
|
||||||
return sender.Client.SendMessage(portal.Key.JID, id, &waProto.Message{
|
return sender.Client.SendMessage(context.TODO(), portal.Key.JID, id, &waProto.Message{
|
||||||
ReactionMessage: &waProto.ReactionMessage{
|
ReactionMessage: &waProto.ReactionMessage{
|
||||||
Key: &waProto.MessageKey{
|
Key: &waProto.MessageKey{
|
||||||
RemoteJid: proto.String(portal.Key.JID.String()),
|
RemoteJid: proto.String(portal.Key.JID.String()),
|
||||||
|
|
|
@ -113,7 +113,7 @@ func (portal *Portal) convertURLPreviewToBeeper(intent *appservice.IntentAPI, so
|
||||||
|
|
||||||
var URLRegex = regexp.MustCompile(`https?://[^\s/_*]+(?:/\S*)?`)
|
var URLRegex = regexp.MustCompile(`https?://[^\s/_*]+(?:/\S*)?`)
|
||||||
|
|
||||||
func (portal *Portal) convertURLPreviewToWhatsApp(sender *User, evt *event.Event, dest *waProto.ExtendedTextMessage) bool {
|
func (portal *Portal) convertURLPreviewToWhatsApp(ctx context.Context, sender *User, evt *event.Event, dest *waProto.ExtendedTextMessage) bool {
|
||||||
var preview *BeeperLinkPreview
|
var preview *BeeperLinkPreview
|
||||||
|
|
||||||
rawPreview := gjson.GetBytes(evt.Content.VeryRaw, `com\.beeper\.linkpreviews`)
|
rawPreview := gjson.GetBytes(evt.Content.VeryRaw, `com\.beeper\.linkpreviews`)
|
||||||
|
@ -163,7 +163,7 @@ func (portal *Portal) convertURLPreviewToWhatsApp(sender *User, evt *event.Event
|
||||||
imageMXC = preview.ImageEncryption.URL.ParseOrIgnore()
|
imageMXC = preview.ImageEncryption.URL.ParseOrIgnore()
|
||||||
}
|
}
|
||||||
if !imageMXC.IsEmpty() {
|
if !imageMXC.IsEmpty() {
|
||||||
data, err := portal.MainIntent().DownloadBytes(imageMXC)
|
data, err := portal.MainIntent().DownloadBytesContext(ctx, imageMXC)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
portal.log.Errorfln("Failed to download URL preview image %s in %s: %v", preview.ImageURL, evt.ID, err)
|
portal.log.Errorfln("Failed to download URL preview image %s in %s: %v", preview.ImageURL, evt.ID, err)
|
||||||
return true
|
return true
|
||||||
|
@ -176,7 +176,7 @@ func (portal *Portal) convertURLPreviewToWhatsApp(sender *User, evt *event.Event
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dest.MediaKeyTimestamp = proto.Int64(time.Now().Unix())
|
dest.MediaKeyTimestamp = proto.Int64(time.Now().Unix())
|
||||||
uploadResp, err := sender.Client.Upload(context.Background(), data, whatsmeow.MediaLinkThumbnail)
|
uploadResp, err := sender.Client.Upload(ctx, data, whatsmeow.MediaLinkThumbnail)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
portal.log.Errorfln("Failed to upload URL preview thumbnail in %s: %v", evt.ID, err)
|
portal.log.Errorfln("Failed to upload URL preview thumbnail in %s: %v", evt.ID, err)
|
||||||
return true
|
return true
|
||||||
|
|
2
user.go
2
user.go
|
@ -671,7 +671,7 @@ func (user *User) sendHackyPhonePing() {
|
||||||
} else {
|
} else {
|
||||||
user.log.Warnfln("Failed to get last app state key ID to send hacky phone ping: %v - sending empty request", err)
|
user.log.Warnfln("Failed to get last app state key ID to send hacky phone ping: %v - sending empty request", err)
|
||||||
}
|
}
|
||||||
ts, err := user.Client.SendMessage(user.JID.ToNonAD(), msgID, &waProto.Message{
|
ts, err := user.Client.SendMessage(context.Background(), user.JID.ToNonAD(), msgID, &waProto.Message{
|
||||||
ProtocolMessage: &waProto.ProtocolMessage{
|
ProtocolMessage: &waProto.ProtocolMessage{
|
||||||
Type: waProto.ProtocolMessage_APP_STATE_SYNC_KEY_REQUEST.Enum(),
|
Type: waProto.ProtocolMessage_APP_STATE_SYNC_KEY_REQUEST.Enum(),
|
||||||
AppStateSyncKeyRequest: &waProto.AppStateSyncKeyRequest{
|
AppStateSyncKeyRequest: &waProto.AppStateSyncKeyRequest{
|
||||||
|
|
Loading…
Reference in a new issue