From b2e6d206bd2e4bf1496b6d481984ad70a169d86c Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 15 Jul 2023 19:48:26 +0300 Subject: [PATCH] Remove message builder --- libgm/conversations.go | 7 +- libgm/image_builder.go | 139 ++++++++++++++--------------- libgm/message_builder.go | 186 --------------------------------------- portal.go | 66 ++++++++++---- 4 files changed, 116 insertions(+), 282 deletions(-) delete mode 100644 libgm/message_builder.go diff --git a/libgm/conversations.go b/libgm/conversations.go index 20dc4e5..96c758c 100644 --- a/libgm/conversations.go +++ b/libgm/conversations.go @@ -90,12 +90,7 @@ func (c *Conversations) FetchMessages(conversationId string, count int64, cursor return res, nil } -func (c *Conversations) SendMessage(messageBuilder *MessageBuilder) (*binary.SendMessageResponse, error) { - payload, failedToBuild := messageBuilder.Build() - if failedToBuild != nil { - return nil, failedToBuild - } - +func (c *Conversations) SendMessage(payload *binary.SendMessagePayload) (*binary.SendMessageResponse, error) { actionType := binary.ActionType_SEND_MESSAGE sentRequestId, sendErr := c.client.sessionHandler.completeSendMessage(actionType, true, payload) diff --git a/libgm/image_builder.go b/libgm/image_builder.go index bfb3363..4a76441 100644 --- a/libgm/image_builder.go +++ b/libgm/image_builder.go @@ -1,41 +1,50 @@ package libgm import ( + "go.mau.fi/mautrix-gmessages/libgm/binary" "go.mau.fi/mautrix-gmessages/libgm/crypto" "go.mau.fi/mautrix-gmessages/libgm/util" ) -type ImageType struct { +type MediaType struct { Extension string Format string Type int64 } -var ImageTypes = map[string]ImageType{ - "image/jpeg": {Extension: "jpeg", Format: "image/jpeg", Type: 1}, - "image/jpg": {Extension: "jpg", Format: "image/jpg", Type: 2}, - "image/png": {Extension: "png", Format: "image/png", Type: 3}, - "image/gif": {Extension: "gif", Format: "image/gif", Type: 4}, - "image/wbmp": {Extension: "wbmp", Format: "image/wbmp", Type: 5}, - "image/bmp": {Extension: "bmp", Format: "image/bmp", Type: 6}, - "image/x-ms-bmp": {Extension: "bmp", Format: "image/x-ms-bmp", Type: 6}, - "audio/aac": {Extension: "aac", Format: "audio/aac", Type: 14}, - "audio/amr": {Extension: "amr", Format: "audio/amr", Type: 15}, - "audio/mp3": {Extension: "mp3", Format: "audio/mp3", Type: 16}, - "audio/mpeg": {Extension: "mpeg", Format: "audio/mpeg", Type: 17}, - "audio/mpg": {Extension: "mpg", Format: "audio/mpg", Type: 18}, - "audio/mp4": {Extension: "mp4", Format: "audio/mp4", Type: 19}, - "audio/mp4-latm": {Extension: "latm", Format: "audio/mp4-latm", Type: 20}, - "audio/3gpp": {Extension: "3gpp", Format: "audio/3gpp", Type: 21}, - "audio/ogg": {Extension: "ogg", Format: "audio/ogg", Type: 22}, - "video/mp4": {Extension: "mp4", Format: "video/mp4", Type: 8}, - "video/3gpp2": {Extension: "3gpp2", Format: "video/3gpp2", Type: 9}, - "video/3gpp": {Extension: "3gpp", Format: "video/3gpp", Type: 10}, - "video/webm": {Extension: "webm", Format: "video/webm", Type: 11}, - "video/x-matroska": {Extension: "mkv", Format: "video/x-matroska", Type: 12}, +var MediaTypes = map[string]MediaType{ + "image/jpeg": {Extension: "jpeg", Format: "image/jpeg", Type: 1}, + "image/jpg": {Extension: "jpg", Format: "image/jpg", Type: 2}, + "image/png": {Extension: "png", Format: "image/png", Type: 3}, + "image/gif": {Extension: "gif", Format: "image/gif", Type: 4}, + "image/wbmp": {Extension: "wbmp", Format: "image/wbmp", Type: 5}, + "image/bmp": {Extension: "bmp", Format: "image/bmp", Type: 6}, + "image/x-ms-bmp": {Extension: "bmp", Format: "image/x-ms-bmp", Type: 6}, + "image": {Type: 7}, + + "video/mp4": {Extension: "mp4", Format: "video/mp4", Type: 8}, + "video/3gpp2": {Extension: "3gpp2", Format: "video/3gpp2", Type: 9}, + "video/3gpp": {Extension: "3gpp", Format: "video/3gpp", Type: 10}, + "video/webm": {Extension: "webm", Format: "video/webm", Type: 11}, + "video/x-matroska": {Extension: "mkv", Format: "video/x-matroska", Type: 12}, + "video": {Type: 13}, + + "audio/aac": {Extension: "aac", Format: "audio/aac", Type: 14}, + "audio/amr": {Extension: "amr", Format: "audio/amr", Type: 15}, + "audio/mp3": {Extension: "mp3", Format: "audio/mp3", Type: 16}, + "audio/mpeg": {Extension: "mpeg", Format: "audio/mpeg", Type: 17}, + "audio/mpg": {Extension: "mpg", Format: "audio/mpg", Type: 18}, + "audio/mp4": {Extension: "mp4", Format: "audio/mp4", Type: 19}, + "audio/mp4-latm": {Extension: "latm", Format: "audio/mp4-latm", Type: 20}, + "audio/3gpp": {Extension: "3gpp", Format: "audio/3gpp", Type: 21}, + "audio/ogg": {Extension: "ogg", Format: "audio/ogg", Type: 22}, + "auidio": {Type: 23}, + + "text/vcard": {Extension: "vcard", Format: "text/vcard", Type: 24}, + "text/x-vcard": {Extension: "vcard", Format: "text/x-vcard", Type: 24}, "application/pdf": {Extension: "pdf", Format: "application/pdf", Type: 25}, - "application/txt": {Extension: "txt", Format: "application/txt", Type: 26}, - "application/html": {Extension: "html", Format: "application/html", Type: 27}, + "text/plain": {Extension: "txt", Format: "text/plain", Type: 26}, + "text/html": {Extension: "html", Format: "text/html", Type: 27}, "application/msword": {Extension: "doc", Format: "application/msword", Type: 28}, "application/vnd.openxmlformats-officedocument.wordprocessingml.document": {Extension: "docx", Format: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", Type: 29}, "application/vnd.openxmlformats-officedocument.presentationml.presentation": {Extension: "pptx", Format: "application/vnd.openxmlformats-officedocument.presentationml.presentation", Type: 30}, @@ -51,8 +60,6 @@ var ImageTypes = map[string]ImageType{ "application/vcs": {Extension: "vcs", Format: "application/vcs", Type: 41}, "application/ics": {Extension: "ics", Format: "application/ics", Type: 42}, "application/hbs-vcs": {Extension: "vcs", Format: "application/hbs-vcs", Type: 43}, - "text/vcard": {Extension: "vcard", Format: "text/vcard", Type: 24}, - "text/x-vcard": {Extension: "vcard", Format: "text/x-vcard", Type: 24}, } type Image struct { @@ -60,7 +67,7 @@ type Image struct { imageName string imageID string - imageType ImageType + imageType MediaType imageBytes []byte imageSize int64 } @@ -89,7 +96,7 @@ func (i *Image) GetImageSize() int64 { return i.imageSize } -func (i *Image) GetImageType() ImageType { +func (i *Image) GetImageType() MediaType { return i.imageType } @@ -100,52 +107,42 @@ func (i *Image) GetImageID() string { // This is the equivalent of dragging an image into the window on messages web // // Keep in mind that adding an image to a MessageBuilder will also upload the image to googles server -func (mb *MessageBuilder) AddImage(imgBytes []byte, mime string) *MessageBuilder { - if mb.err != nil { - return mb - } - - newImage, newImageErr := mb.newImageData(imgBytes, mime) - if newImageErr != nil { - mb.err = newImageErr - return mb - } - - startUploadImage, failedUpload := mb.client.StartUploadMedia(newImage) - if failedUpload != nil { - mb.err = failedUpload - return mb - } - - finalizedImage, failedFinalize := mb.client.FinalizeUploadMedia(startUploadImage) - if failedFinalize != nil { - mb.err = failedFinalize - return mb - } - - mb.images = append(mb.images, finalizedImage) - return mb -} - -func (mb *MessageBuilder) newImageData(imgBytes []byte, mime string) (*Image, error) { - // TODO explode on unsupported types - imgType := ImageTypes[mime] - imageId := util.GenerateImageID() - imageName := util.RandStr(8) + "." + imgType.Extension +func (c *Client) UploadMedia(data []byte, mime string) (*binary.MediaContent, error) { + mediaType := MediaTypes[mime] + mediaID := util.GenerateImageID() + fileName := util.RandStr(8) + "." + mediaType.Extension decryptionKey, err := crypto.GenerateKey(32) if err != nil { return nil, err } - imageCryptor, cryptorErr := crypto.NewImageCryptor(decryptionKey) - if cryptorErr != nil { - return nil, cryptorErr + cryptor, err := crypto.NewImageCryptor(decryptionKey) + if err != nil { + return nil, err } - return &Image{ - imageCryptor: imageCryptor, - imageID: imageId, - imageBytes: imgBytes, - imageType: imgType, - imageSize: int64(len(imgBytes)), - imageName: imageName, + image := &Image{ + imageCryptor: cryptor, + imageID: mediaID, + imageBytes: data, + imageType: mediaType, + imageSize: int64(len(data)), + imageName: fileName, + } + + startUploadImage, err := c.StartUploadMedia(image) + if err != nil { + return nil, err + } + + upload, err := c.FinalizeUploadMedia(startUploadImage) + if err != nil { + return nil, err + } + + return &binary.MediaContent{ + Format: binary.MediaFormats(image.GetImageType().Type), + MediaID: upload.MediaID, + MediaName: image.GetImageName(), + Size: image.GetImageSize(), + DecryptionKey: image.GetImageCryptor().GetKey(), }, nil } diff --git a/libgm/message_builder.go b/libgm/message_builder.go deleted file mode 100644 index fceede6..0000000 --- a/libgm/message_builder.go +++ /dev/null @@ -1,186 +0,0 @@ -package libgm - -import ( - "errors" - - "go.mau.fi/mautrix-gmessages/libgm/binary" - "go.mau.fi/mautrix-gmessages/libgm/util" -) - -var ( - errContentNotSet = errors.New("failed to build MessageBuilder: content must be larger than length 0") - errConversationIdNotSet = errors.New("failed to build MessageBuilder: conversationID is empty") - errSelfParticipantIdNotSet = errors.New("failed to build MessageBuilder: selfParticipantID is empty") -) - -type MessageBuilder struct { - client *Client - - content string - conversationID string - tmpID string - selfParticipantID string - - replyToMessageID string - - images []*MediaUpload - - err error -} - -func (mb *MessageBuilder) Err() error { - return mb.err -} - -func (mb *MessageBuilder) GetImages() []*MediaUpload { - return mb.images -} - -func (mb *MessageBuilder) GetContent() string { - return mb.content -} - -func (mb *MessageBuilder) GetConversationID() string { - return mb.conversationID -} - -func (mb *MessageBuilder) GetSelfParticipantID() string { - return mb.selfParticipantID -} - -func (mb *MessageBuilder) GetTmpID() string { - return mb.tmpID -} - -func (mb *MessageBuilder) SetContent(content string) *MessageBuilder { - mb.content = content - return mb -} - -func (mb *MessageBuilder) SetConversationID(conversationId string) *MessageBuilder { - mb.conversationID = conversationId - return mb -} - -// sendmessage function will set this automatically but if u want to set it yourself feel free -func (mb *MessageBuilder) SetSelfParticipantID(participantId string) *MessageBuilder { - mb.selfParticipantID = participantId - return mb -} - -// messageID of the message to reply to -func (mb *MessageBuilder) SetReplyMessage(messageId string) *MessageBuilder { - mb.replyToMessageID = messageId - return mb -} - -// sendmessage function will set this automatically but if u want to set it yourself feel free -func (mb *MessageBuilder) SetTmpID(tmpId string) *MessageBuilder { - mb.tmpID = tmpId - return mb -} - -func (mb *MessageBuilder) Build() (*binary.SendMessagePayload, error) { - - if mb.conversationID == "" { - return nil, errConversationIdNotSet - } - - if mb.selfParticipantID == "" { - return nil, errSelfParticipantIdNotSet - } - - if mb.content == "" { - return nil, errContentNotSet - } - - if mb.tmpID == "" { - mb.tmpID = util.GenerateTmpID() - } - - return mb.newSendConversationMessage(), nil -} - -func (c *Client) NewMessageBuilder() *MessageBuilder { - mb := &MessageBuilder{ - client: c, - } - - tmpId := util.GenerateTmpID() - mb.SetTmpID(tmpId) - - return mb -} - -func (mb *MessageBuilder) newSendConversationMessage() *binary.SendMessagePayload { - - convId := mb.GetConversationID() - content := mb.GetContent() - selfParticipantId := mb.GetSelfParticipantID() - tmpId := mb.GetTmpID() - - messageInfo := make([]*binary.MessageInfo, 0) - messageInfo = append(messageInfo, &binary.MessageInfo{Data: &binary.MessageInfo_MessageContent{ - MessageContent: &binary.MessageContent{ - Content: content, - }, - }}) - - mb.appendImagesPayload(&messageInfo) - - sendMsgPayload := &binary.SendMessagePayload{ - ConversationID: convId, - MessagePayload: &binary.MessagePayload{ - TmpID: tmpId, - ConversationID: convId, - SelfParticipantID: selfParticipantId, - MessageInfo: messageInfo, - TmpID2: tmpId, - }, - TmpID: tmpId, - } - - if len(content) > 0 { - sendMsgPayload.MessagePayload.MessagePayloadContent = &binary.MessagePayloadContent{ - MessageContent: &binary.MessageContent{ - Content: content, - }, - } - } - - if mb.replyToMessageID != "" { - sendMsgPayload.IsReply = true - sendMsgPayload.Reply = &binary.ReplyPayload{MessageID: mb.replyToMessageID} - } - - mb.client.Logger.Debug().Any("sendMsgPayload", sendMsgPayload).Msg("sendMessagePayload") - - return sendMsgPayload -} - -func (mb *MessageBuilder) appendImagesPayload(messageInfo *[]*binary.MessageInfo) { - if len(mb.images) <= 0 { - return - } - - for _, media := range mb.images { - imgData := mb.newImageContent(media) - *messageInfo = append(*messageInfo, imgData) - } -} - -func (mb *MessageBuilder) newImageContent(media *MediaUpload) *binary.MessageInfo { - imageMessage := &binary.MessageInfo{ - Data: &binary.MessageInfo_MediaContent{ - MediaContent: &binary.MediaContent{ - Format: binary.MediaFormats(media.Image.GetImageType().Type), - MediaID: media.MediaID, - MediaName: media.Image.GetImageName(), - Size: media.Image.GetImageSize(), - DecryptionKey: media.Image.GetImageCryptor().GetKey(), - }, - }, - } - mb.client.Logger.Debug().Any("imageMessage", imageMessage).Msg("New Media Content") - return imageMessage -} diff --git a/portal.go b/portal.go index b3c95b0..b2c1652 100644 --- a/portal.go +++ b/portal.go @@ -1207,7 +1207,24 @@ func (portal *Portal) HandleMatrixMessage(sender *User, evt *event.Event, timing return } - var replyToID string + txnID := util.GenerateTmpID() + portal.outgoingMessagesLock.Lock() + portal.outgoingMessages[txnID] = &outgoingMessage{Event: evt} + portal.outgoingMessagesLock.Unlock() + if evt.Type == event.EventSticker { + content.MsgType = event.MsgImage + } + req := &binary.SendMessagePayload{ + ConversationID: portal.ID, + TmpID: txnID, + MessagePayload: &binary.MessagePayload{ + ConversationID: portal.ID, + TmpID: txnID, + TmpID2: txnID, + SelfParticipantID: portal.SelfUserID, + }, + } + replyToMXID := content.RelatesTo.GetReplyTo() if replyToMXID != "" { replyToMsg, err := portal.bridge.DB.Message.GetByMXID(ctx, replyToMXID) @@ -1216,35 +1233,46 @@ func (portal *Portal) HandleMatrixMessage(sender *User, evt *event.Event, timing } else if replyToMsg == nil { log.Warn().Str("reply_to_mxid", replyToMXID.String()).Msg("Reply target message not found") } else { - replyToID = replyToMsg.ID + req.IsReply = true + req.Reply = &binary.ReplyPayload{MessageID: replyToMsg.ID} } } - txnID := util.GenerateTmpID() - portal.outgoingMessagesLock.Lock() - portal.outgoingMessages[txnID] = &outgoingMessage{Event: evt} - portal.outgoingMessagesLock.Unlock() switch content.MsgType { case event.MsgText, event.MsgEmote, event.MsgNotice: text := content.Body if content.MsgType == event.MsgEmote { text = "/me " + text } - _, err := sender.Client.Conversations.SendMessage( - sender.Client.NewMessageBuilder(). - SetConversationID(portal.ID). - SetSelfParticipantID(portal.SelfUserID). - SetReplyMessage(replyToID). - SetContent(text). - SetTmpID(txnID), - ) - if err != nil { - go ms.sendMessageMetrics(evt, err, "Error sending", true) - } else { - go ms.sendMessageMetrics(evt, nil, "", true) - } + req.MessagePayload.MessageInfo = []*binary.MessageInfo{{ + Data: &binary.MessageInfo_MessageContent{MessageContent: &binary.MessageContent{ + Content: text, + }}, + }} + case event.MsgImage, event.MsgVideo, event.MsgAudio, event.MsgFile: + //fileName := content.Body + //if content.FileName != "" { + // fileName = content.FileName + //} + //sender.Client.StartUploadMedia() + //req.MessagePayload.MessageInfo = []*binary.MessageInfo{{ + // Data: &binary.MessageInfo_MediaContent{MediaContent: &binary.MediaContent{ + // Format: 0, + // MediaID: mediaID, + // MediaName: fileName, + // Size: int64(len(data)), + // DecryptionKey: decryptionKey, + // }}, + //}} default: go ms.sendMessageMetrics(evt, fmt.Errorf("unsupported msgtype"), "Ignoring", true) + return + } + _, err := sender.Client.Conversations.SendMessage(req) + if err != nil { + go ms.sendMessageMetrics(evt, err, "Error sending", true) + } else { + go ms.sendMessageMetrics(evt, nil, "", true) } }