Convert Portal to zerolog

This commit is contained in:
Tulir Asokan
2023-04-30 18:49:14 +03:00
parent a44ceea836
commit bd56d33c89
6 changed files with 316 additions and 171 deletions

View File

@@ -17,6 +17,7 @@
package main
import (
"context"
"fmt"
"html"
"strconv"
@@ -24,6 +25,7 @@ import (
"time"
"github.com/bwmarrin/discordgo"
"github.com/rs/zerolog"
"maunium.net/go/mautrix"
"maunium.net/go/mautrix/appservice"
@@ -48,14 +50,14 @@ func (portal *Portal) createMediaFailedMessage(bridgeErr error) *event.MessageEv
const DiscordStickerSize = 160
func (portal *Portal) convertDiscordFile(typeName string, intent *appservice.IntentAPI, id, url string, content *event.MessageEventContent) *event.MessageEventContent {
func (portal *Portal) convertDiscordFile(ctx context.Context, typeName string, intent *appservice.IntentAPI, id, url string, content *event.MessageEventContent) *event.MessageEventContent {
meta := AttachmentMeta{AttachmentID: id, MimeType: content.Info.MimeType}
if typeName == "sticker" && content.Info.MimeType == "application/json" {
meta.Converter = portal.bridge.convertLottie
}
dbFile, err := portal.bridge.copyAttachmentToMatrix(intent, url, portal.Encrypted, meta)
if err != nil {
portal.log.Errorfln("Error copying attachment %s to Matrix: %v", id, err)
zerolog.Ctx(ctx).Err(err).Msg("Failed to copy attachment to Matrix")
return portal.createMediaFailedMessage(err)
}
if typeName == "sticker" && content.Info.MimeType == "application/json" {
@@ -95,7 +97,7 @@ func (portal *Portal) cleanupConvertedStickerInfo(content *event.MessageEventCon
}
}
func (portal *Portal) convertDiscordSticker(intent *appservice.IntentAPI, sticker *discordgo.Sticker) *ConvertedMessage {
func (portal *Portal) convertDiscordSticker(ctx context.Context, intent *appservice.IntentAPI, sticker *discordgo.Sticker) *ConvertedMessage {
var mime, ext string
switch sticker.FormatType {
case discordgo.StickerFormatTypePNG:
@@ -111,7 +113,10 @@ func (portal *Portal) convertDiscordSticker(intent *appservice.IntentAPI, sticke
mime = "image/gif"
ext = "gif"
default:
portal.log.Warnfln("Unknown sticker format %d in %s", sticker.FormatType, sticker.ID)
zerolog.Ctx(ctx).Warn().
Int("sticker_format", int(sticker.FormatType)).
Str("sticker_id", sticker.ID).
Msg("Unknown sticker format")
}
content := &event.MessageEventContent{
Body: sticker.Name, // TODO find description from somewhere?
@@ -122,7 +127,7 @@ func (portal *Portal) convertDiscordSticker(intent *appservice.IntentAPI, sticke
mxc := portal.bridge.Config.Bridge.MediaPatterns.Sticker(sticker.ID, ext)
if mxc.IsEmpty() {
content = portal.convertDiscordFile("sticker", intent, sticker.ID, sticker.URL(), content)
content = portal.convertDiscordFile(ctx, "sticker", intent, sticker.ID, sticker.URL(), content)
} else {
content.URL = mxc.CUString()
}
@@ -134,7 +139,7 @@ func (portal *Portal) convertDiscordSticker(intent *appservice.IntentAPI, sticke
}
}
func (portal *Portal) convertDiscordAttachment(intent *appservice.IntentAPI, att *discordgo.MessageAttachment) *ConvertedMessage {
func (portal *Portal) convertDiscordAttachment(ctx context.Context, intent *appservice.IntentAPI, att *discordgo.MessageAttachment) *ConvertedMessage {
content := &event.MessageEventContent{
Body: att.Filename,
Info: &event.FileInfo{
@@ -174,7 +179,7 @@ func (portal *Portal) convertDiscordAttachment(intent *appservice.IntentAPI, att
}
mxc := portal.bridge.Config.Bridge.MediaPatterns.Attachment(portal.Key.ChannelID, att.ID, att.Filename)
if mxc.IsEmpty() {
content = portal.convertDiscordFile("attachment", intent, att.ID, att.URL, content)
content = portal.convertDiscordFile(ctx, "attachment", intent, att.ID, att.URL, content)
} else {
content.URL = mxc.CUString()
}
@@ -186,10 +191,11 @@ func (portal *Portal) convertDiscordAttachment(intent *appservice.IntentAPI, att
}
}
func (portal *Portal) convertDiscordVideoEmbed(intent *appservice.IntentAPI, embed *discordgo.MessageEmbed) *ConvertedMessage {
func (portal *Portal) convertDiscordVideoEmbed(ctx context.Context, intent *appservice.IntentAPI, embed *discordgo.MessageEmbed) *ConvertedMessage {
attachmentID := fmt.Sprintf("video_%s", embed.URL)
dbFile, err := portal.bridge.copyAttachmentToMatrix(intent, embed.Video.ProxyURL, portal.Encrypted, NoMeta)
if err != nil {
zerolog.Ctx(ctx).Err(err).Msg("Failed to copy video embed to Matrix")
return &ConvertedMessage{
AttachmentID: attachmentID,
Type: event.EventMessage,
@@ -238,22 +244,24 @@ func (portal *Portal) convertDiscordVideoEmbed(intent *appservice.IntentAPI, emb
}
}
func (portal *Portal) convertDiscordMessage(intent *appservice.IntentAPI, msg *discordgo.Message) []*ConvertedMessage {
func (portal *Portal) convertDiscordMessage(ctx context.Context, intent *appservice.IntentAPI, msg *discordgo.Message) []*ConvertedMessage {
predictedLength := len(msg.Attachments) + len(msg.StickerItems)
if msg.Content != "" {
predictedLength++
}
parts := make([]*ConvertedMessage, 0, predictedLength)
if textPart := portal.convertDiscordTextMessage(intent, msg); textPart != nil {
if textPart := portal.convertDiscordTextMessage(ctx, intent, msg); textPart != nil {
parts = append(parts, textPart)
}
log := zerolog.Ctx(ctx)
handledIDs := make(map[string]struct{})
for _, att := range msg.Attachments {
if _, handled := handledIDs[att.ID]; handled {
continue
}
handledIDs[att.ID] = struct{}{}
if part := portal.convertDiscordAttachment(intent, att); part != nil {
log := log.With().Str("attachment_id", att.ID).Logger()
if part := portal.convertDiscordAttachment(log.WithContext(ctx), intent, att); part != nil {
parts = append(parts, part)
}
}
@@ -262,11 +270,12 @@ func (portal *Portal) convertDiscordMessage(intent *appservice.IntentAPI, msg *d
continue
}
handledIDs[sticker.ID] = struct{}{}
if part := portal.convertDiscordSticker(intent, sticker); part != nil {
log := log.With().Str("sticker_id", sticker.ID).Logger()
if part := portal.convertDiscordSticker(log.WithContext(ctx), intent, sticker); part != nil {
parts = append(parts, part)
}
}
for _, embed := range msg.Embeds {
for i, embed := range msg.Embeds {
// Ignore non-video embeds, they're handled in convertDiscordTextMessage
if getEmbedType(embed) != EmbedVideo {
continue
@@ -276,7 +285,12 @@ func (portal *Portal) convertDiscordMessage(intent *appservice.IntentAPI, msg *d
continue
}
handledIDs[embed.URL] = struct{}{}
part := portal.convertDiscordVideoEmbed(intent, embed)
log := log.With().
Str("computed_embed_type", "video").
Str("embed_type", string(embed.Type)).
Int("embed_index", i).
Logger()
part := portal.convertDiscordVideoEmbed(log.WithContext(ctx), intent, embed)
if part != nil {
parts = append(parts, part)
}
@@ -305,7 +319,8 @@ const (
embedFooterDateSeparator = ``
)
func (portal *Portal) convertDiscordRichEmbed(intent *appservice.IntentAPI, embed *discordgo.MessageEmbed, msgID string, index int) string {
func (portal *Portal) convertDiscordRichEmbed(ctx context.Context, intent *appservice.IntentAPI, embed *discordgo.MessageEmbed, msgID string, index int) string {
log := zerolog.Ctx(ctx)
var htmlParts []string
if embed.Author != nil {
var authorHTML string
@@ -317,7 +332,7 @@ func (portal *Portal) convertDiscordRichEmbed(intent *appservice.IntentAPI, embe
if embed.Author.ProxyIconURL != "" {
dbFile, err := portal.bridge.copyAttachmentToMatrix(intent, embed.Author.ProxyIconURL, false, NoMeta)
if err != nil {
portal.log.Warnfln("Failed to reupload author icon in embed #%d of message %s: %v", index+1, msgID, err)
log.Warn().Err(err).Msg("Failed to reupload author icon in embed")
} else {
authorHTML = fmt.Sprintf(embedHTMLAuthorWithImage, dbFile.MXC, authorNameHTML)
}
@@ -367,7 +382,7 @@ func (portal *Portal) convertDiscordRichEmbed(intent *appservice.IntentAPI, embe
if embed.Image != nil {
dbFile, err := portal.bridge.copyAttachmentToMatrix(intent, embed.Image.ProxyURL, false, NoMeta)
if err != nil {
portal.log.Warnfln("Failed to reupload image in embed #%d of message %s: %v", index+1, msgID, err)
log.Warn().Err(err).Msg("Failed to reupload image in embed")
} else {
htmlParts = append(htmlParts, fmt.Sprintf(embedHTMLImage, dbFile.MXC))
}
@@ -377,7 +392,7 @@ func (portal *Portal) convertDiscordRichEmbed(intent *appservice.IntentAPI, embe
formattedTime := embed.Timestamp
parsedTS, err := time.Parse(time.RFC3339, embed.Timestamp)
if err != nil {
portal.log.Warnfln("Failed to parse timestamp in embed #%d of message %s: %v", index+1, msgID, err)
log.Warn().Err(err).Msg("Failed to parse timestamp in embed")
} else {
formattedTime = parsedTS.Format(discordTimestampStyle('F').Format())
}
@@ -393,7 +408,7 @@ func (portal *Portal) convertDiscordRichEmbed(intent *appservice.IntentAPI, embe
if embed.Footer.ProxyIconURL != "" {
dbFile, err := portal.bridge.copyAttachmentToMatrix(intent, embed.Footer.ProxyIconURL, false, NoMeta)
if err != nil {
portal.log.Warnfln("Failed to reupload footer icon in embed #%d of message %s: %v", index+1, msgID, err)
log.Warn().Err(err).Msg("Failed to reupload footer icon in embed")
} else {
footerHTML = fmt.Sprintf(embedHTMLFooterWithImage, dbFile.MXC, html.EscapeString(embed.Footer.Text), datePart)
}
@@ -422,40 +437,40 @@ type BeeperLinkPreview struct {
ImageEncryption *event.EncryptedFileInfo `json:"beeper:image:encryption,omitempty"`
}
func (portal *Portal) convertDiscordLinkEmbedImage(intent *appservice.IntentAPI, url string, width, height int, preview *BeeperLinkPreview) {
func (portal *Portal) convertDiscordLinkEmbedImage(ctx context.Context, intent *appservice.IntentAPI, url string, width, height int, preview *BeeperLinkPreview) {
dbFile, err := portal.bridge.copyAttachmentToMatrix(intent, url, portal.Encrypted, NoMeta)
if err != nil {
portal.log.Warnfln("Failed to copy image in URL preview: %v", err)
zerolog.Ctx(ctx).Warn().Err(err).Msg("Failed to reupload image in URL preview")
return
}
if width != 0 || height != 0 {
preview.ImageWidth = width
preview.ImageHeight = height
} else {
if width != 0 || height != 0 {
preview.ImageWidth = width
preview.ImageHeight = height
} else {
preview.ImageWidth = dbFile.Width
preview.ImageHeight = dbFile.Height
}
preview.ImageSize = dbFile.Size
preview.ImageType = dbFile.MimeType
if dbFile.Encrypted {
preview.ImageEncryption = &event.EncryptedFileInfo{
EncryptedFile: *dbFile.DecryptionInfo,
URL: dbFile.MXC.CUString(),
}
} else {
preview.ImageURL = dbFile.MXC.CUString()
preview.ImageWidth = dbFile.Width
preview.ImageHeight = dbFile.Height
}
preview.ImageSize = dbFile.Size
preview.ImageType = dbFile.MimeType
if dbFile.Encrypted {
preview.ImageEncryption = &event.EncryptedFileInfo{
EncryptedFile: *dbFile.DecryptionInfo,
URL: dbFile.MXC.CUString(),
}
} else {
preview.ImageURL = dbFile.MXC.CUString()
}
}
func (portal *Portal) convertDiscordLinkEmbedToBeeper(intent *appservice.IntentAPI, embed *discordgo.MessageEmbed) *BeeperLinkPreview {
func (portal *Portal) convertDiscordLinkEmbedToBeeper(ctx context.Context, intent *appservice.IntentAPI, embed *discordgo.MessageEmbed) *BeeperLinkPreview {
var preview BeeperLinkPreview
preview.MatchedURL = embed.URL
preview.Title = embed.Title
preview.Description = embed.Description
if embed.Image != nil {
portal.convertDiscordLinkEmbedImage(intent, embed.Image.ProxyURL, embed.Image.Width, embed.Image.Height, &preview)
portal.convertDiscordLinkEmbedImage(ctx, intent, embed.Image.ProxyURL, embed.Image.Width, embed.Image.Height, &preview)
} else if embed.Thumbnail != nil {
portal.convertDiscordLinkEmbedImage(intent, embed.Thumbnail.ProxyURL, embed.Thumbnail.Width, embed.Thumbnail.Height, &preview)
portal.convertDiscordLinkEmbedImage(ctx, intent, embed.Thumbnail.ProxyURL, embed.Thumbnail.Width, embed.Thumbnail.Height, &preview)
}
return &preview
}
@@ -503,7 +518,8 @@ func isPlainGifMessage(msg *discordgo.Message) bool {
return len(msg.Embeds) == 1 && msg.Embeds[0].Video != nil && msg.Embeds[0].URL == msg.Content && msg.Embeds[0].Type == discordgo.EmbedTypeGifv
}
func (portal *Portal) convertDiscordTextMessage(intent *appservice.IntentAPI, msg *discordgo.Message) *ConvertedMessage {
func (portal *Portal) convertDiscordTextMessage(ctx context.Context, intent *appservice.IntentAPI, msg *discordgo.Message) *ConvertedMessage {
log := zerolog.Ctx(ctx)
if msg.Type == discordgo.MessageTypeCall {
return &ConvertedMessage{Type: event.EventMessage, Content: &event.MessageEventContent{
MsgType: event.MsgEmote,
@@ -526,15 +542,21 @@ func (portal *Portal) convertDiscordTextMessage(intent *appservice.IntentAPI, ms
}
previews := make([]*BeeperLinkPreview, 0)
for i, embed := range msg.Embeds {
with := log.With().
Str("embed_type", string(embed.Type)).
Int("embed_index", i)
switch getEmbedType(embed) {
case EmbedRich:
htmlParts = append(htmlParts, portal.convertDiscordRichEmbed(intent, embed, msg.ID, i))
log := with.Str("computed_embed_type", "rich").Logger()
htmlParts = append(htmlParts, portal.convertDiscordRichEmbed(log.WithContext(ctx), intent, embed, msg.ID, i))
case EmbedLinkPreview:
previews = append(previews, portal.convertDiscordLinkEmbedToBeeper(intent, embed))
log := with.Str("computed_embed_type", "link preview").Logger()
previews = append(previews, portal.convertDiscordLinkEmbedToBeeper(log.WithContext(ctx), intent, embed))
case EmbedVideo:
// Ignore video embeds, they're handled as separate messages
default:
portal.log.Warnfln("Unknown type %s in embed #%d of message %s", embed.Type, i+1, msg.ID)
log := with.Logger()
log.Warn().Msg("Unknown embed type in message")
}
}