From 871a9705e3a78a3972a0896c1357207785a9e950 Mon Sep 17 00:00:00 2001 From: Sumner Evans Date: Mon, 17 Jun 2024 17:22:47 -0600 Subject: [PATCH] images: implement sending from Matrix -> Telegram Signed-off-by: Sumner Evans --- pkg/connector/client.go | 73 +++++++++++++++++++++++++++--- pkg/connector/msgconv/converter.go | 11 +++++ pkg/connector/msgconv/tomatrix.go | 41 +++++++---------- pkg/store/scoped_store.go | 2 +- 4 files changed, 95 insertions(+), 32 deletions(-) create mode 100644 pkg/connector/msgconv/converter.go diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 56b1a768..44f16d2b 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -10,7 +10,9 @@ import ( "github.com/gotd/td/telegram" "github.com/gotd/td/telegram/message" + "github.com/gotd/td/telegram/message/html" "github.com/gotd/td/telegram/updates" + "github.com/gotd/td/telegram/uploader" "github.com/gotd/td/tg" "github.com/rs/zerolog" "go.mau.fi/zerozap" @@ -18,6 +20,7 @@ import ( "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/database" "maunium.net/go/mautrix/bridgev2/networkid" + "maunium.net/go/mautrix/event" "go.mau.fi/mautrix-telegram/pkg/connector/msgconv" ) @@ -281,22 +284,78 @@ func (t *TelegramClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2. if err != nil { return nil, err } + builder := sender.To(peer) - updates, err := sender.To(peer).Text(ctx, msg.Content.Body) - if err != nil { - return nil, err + // TODO handle sticker + + var updates tg.UpdatesClass + switch msg.Content.MsgType { + case event.MsgText: + updates, err = builder.Text(ctx, msg.Content.Body) + if err != nil { + return nil, err + } + case event.MsgImage, event.MsgFile, event.MsgAudio, event.MsgVideo: + var filename, caption string + if msg.Content.FileName != "" { + filename = msg.Content.FileName + caption = msg.Content.FormattedBody + if caption == "" { + caption = msg.Content.Body + } + } else { + filename = msg.Content.Body + } + + // TODO stream this download straight into the uploader + fileData, err := t.main.Bridge.Bot.DownloadMedia(ctx, msg.Content.URL, msg.Content.File) + if err != nil { + return nil, fmt.Errorf("failed to download media from Matrix: %w", err) + } + uploader := uploader.NewUploader(t.client.API()) + upload, err := uploader.FromBytes(ctx, filename, fileData) + if err != nil { + return nil, fmt.Errorf("failed to upload media to Telegram: %w", err) + } + var photo *message.UploadedPhotoBuilder + if caption != "" { + // TODO resolver? + photo = message.UploadedPhoto(upload, html.String(nil, caption)) + } else { + photo = message.UploadedPhoto(upload) + } + updates, err = builder.Media(ctx, photo) + if err != nil { + return nil, err + } } - sentMessage, ok := updates.(*tg.UpdateShortSentMessage) - if !ok { + + var tgMessageID, tgDate int + switch sentMessage := updates.(type) { + case *tg.UpdateShortSentMessage: + tgMessageID = sentMessage.ID + tgDate = sentMessage.Date + case *tg.Updates: + tgDate = sentMessage.Date + for _, u := range sentMessage.Updates { + if update, ok := u.(*tg.UpdateMessageID); ok { + tgMessageID = update.ID + break + } + } + if tgMessageID == 0 { + return nil, fmt.Errorf("couldn't find update message ID update") + } + default: return nil, fmt.Errorf("unknown update from message response %T", updates) } dbMessage = &database.Message{ - ID: makeMessageID(sentMessage.ID), + ID: makeMessageID(tgMessageID), MXID: msg.Event.ID, RoomID: msg.Portal.ID, SenderID: makeUserID(t.loginID), - Timestamp: time.Unix(int64(sentMessage.Date), 0), + Timestamp: time.Unix(int64(tgDate), 0), } return } diff --git a/pkg/connector/msgconv/converter.go b/pkg/connector/msgconv/converter.go new file mode 100644 index 00000000..50fcc3a5 --- /dev/null +++ b/pkg/connector/msgconv/converter.go @@ -0,0 +1,11 @@ +package msgconv + +import "github.com/gotd/td/telegram" + +type MessageConverter struct { + client *telegram.Client +} + +func NewMessageConverter(client *telegram.Client) *MessageConverter { + return &MessageConverter{client: client} +} diff --git a/pkg/connector/msgconv/tomatrix.go b/pkg/connector/msgconv/tomatrix.go index 53344637..982ada1f 100644 --- a/pkg/connector/msgconv/tomatrix.go +++ b/pkg/connector/msgconv/tomatrix.go @@ -7,7 +7,6 @@ import ( "net/http" "time" - "github.com/gotd/td/telegram" "github.com/gotd/td/telegram/downloader" "github.com/gotd/td/tg" "github.com/rs/zerolog" @@ -17,16 +16,9 @@ import ( "maunium.net/go/mautrix/event" ) -type MessageConverter struct { - client *telegram.Client -} - -func NewMessageConverter(client *telegram.Client) *MessageConverter { - return &MessageConverter{client: client} -} - func (mc *MessageConverter) ToMatrix(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, msg *tg.Message) (*bridgev2.ConvertedMessage, error) { log := zerolog.Ctx(ctx).With().Str("conversion_direction", "to_matrix").Logger() + ctx = log.WithContext(ctx) cm := &bridgev2.ConvertedMessage{ Timestamp: time.Unix(int64(msg.Date), 0), @@ -118,22 +110,23 @@ func (mc *MessageConverter) ToMatrix(ctx context.Context, portal *bridgev2.Porta Extra: extra, }) - case *tg.MessageMediaGeo: // messageMediaGeo#56e0d474 - case *tg.MessageMediaContact: // messageMediaContact#70322949 - case *tg.MessageMediaUnsupported: // messageMediaUnsupported#9f84f49e - case *tg.MessageMediaDocument: // messageMediaDocument#4cf4d72d - case *tg.MessageMediaWebPage: // messageMediaWebPage#ddf10c3b - case *tg.MessageMediaVenue: // messageMediaVenue#2ec0533f - case *tg.MessageMediaGame: // messageMediaGame#fdb19008 - case *tg.MessageMediaInvoice: // messageMediaInvoice#f6a548d3 - case *tg.MessageMediaGeoLive: // messageMediaGeoLive#b940c666 - case *tg.MessageMediaPoll: // messageMediaPoll#4bd6e798 - case *tg.MessageMediaDice: // messageMediaDice#3f7ee58b - case *tg.MessageMediaStory: // messageMediaStory#68cb6283 - case *tg.MessageMediaGiveaway: // messageMediaGiveaway#daad85b0 - case *tg.MessageMediaGiveawayResults: // messageMediaGiveawayResults#c6991068 + // TODO all of these + // case *tg.MessageMediaGeo: // messageMediaGeo#56e0d474 + // case *tg.MessageMediaContact: // messageMediaContact#70322949 + // case *tg.MessageMediaUnsupported: // messageMediaUnsupported#9f84f49e + // case *tg.MessageMediaDocument: // messageMediaDocument#4cf4d72d + // case *tg.MessageMediaWebPage: // messageMediaWebPage#ddf10c3b + // case *tg.MessageMediaVenue: // messageMediaVenue#2ec0533f + // case *tg.MessageMediaGame: // messageMediaGame#fdb19008 + // case *tg.MessageMediaInvoice: // messageMediaInvoice#f6a548d3 + // case *tg.MessageMediaGeoLive: // messageMediaGeoLive#b940c666 + // case *tg.MessageMediaPoll: // messageMediaPoll#4bd6e798 + // case *tg.MessageMediaDice: // messageMediaDice#3f7ee58b + // case *tg.MessageMediaStory: // messageMediaStory#68cb6283 + // case *tg.MessageMediaGiveaway: // messageMediaGiveaway#daad85b0 + // case *tg.MessageMediaGiveawayResults: // messageMediaGiveawayResults#c6991068 default: - log.Error().Type("msg", msg).Msg("Unhandled media type") + return nil, fmt.Errorf("unhandled media type %T", m) } } return cm, nil diff --git a/pkg/store/scoped_store.go b/pkg/store/scoped_store.go index 97928dc4..f13e7f96 100644 --- a/pkg/store/scoped_store.go +++ b/pkg/store/scoped_store.go @@ -157,7 +157,7 @@ var _ updates.ChannelAccessHasher = (*scopedStore)(nil) func (s *scopedStore) GetChannelAccessHash(ctx context.Context, userID int64, channelID int64) (accessHash int64, found bool, err error) { s.assertUserIDMatches(userID) - err = s.db.QueryRow(ctx, getChannelAccessHashQuery, userID).Scan(&accessHash) + err = s.db.QueryRow(ctx, getChannelAccessHashQuery, userID, channelID).Scan(&accessHash) if errors.Is(err, sql.ErrNoRows) { return 0, false, nil }