From d7a9896ec3f6b3e57a2d8d0480f72b8ca2029fd4 Mon Sep 17 00:00:00 2001 From: Gabriel Augusto Date: Fri, 20 Oct 2023 16:37:50 -0300 Subject: [PATCH 1/4] send message --- controllers/send_audio_message_controller.go | 39 +------ controllers/send_image_message_controller.go | 38 +------ ...ler.go => send_text_message_controller.go} | 22 +--- services/account_service.go | 1 - services/wpp_service.go | 101 +++++++++++++++++- 5 files changed, 110 insertions(+), 91 deletions(-) rename controllers/{sent_text_message_controller.go => send_text_message_controller.go} (78%) diff --git a/controllers/send_audio_message_controller.go b/controllers/send_audio_message_controller.go index b131752..461bcee 100644 --- a/controllers/send_audio_message_controller.go +++ b/controllers/send_audio_message_controller.go @@ -1,16 +1,12 @@ package controllers import ( - "context" "zapmeow/models" "zapmeow/services" "zapmeow/utils" "github.com/gin-gonic/gin" "github.com/vincent-petithory/dataurl" - "go.mau.fi/whatsmeow" - waProto "go.mau.fi/whatsmeow/binary/proto" - "google.golang.org/protobuf/proto" ) type audioMessageBody struct { @@ -67,42 +63,13 @@ func (a *sendAudioMessageController) Handler(c *gin.Context) { return } - instance, err := a.wppService.GetAuthenticatedInstance(instanceID) - if err != nil { - utils.RespondInternalServerError(c, err.Error()) - return - } - audioURL, err := dataurl.DecodeString(body.Base64) if err != nil { utils.RespondInternalServerError(c, err.Error()) return } - uploaded, err := instance.Client.Upload( - context.Background(), - audioURL.Data, - whatsmeow.MediaAudio, - ) - if err != nil { - utils.RespondInternalServerError(c, err.Error()) - return - } - - msg := &waProto.Message{ - AudioMessage: &waProto.AudioMessage{ - Ptt: proto.Bool(true), - Url: proto.String(uploaded.URL), - DirectPath: proto.String(uploaded.DirectPath), - MediaKey: uploaded.MediaKey, - Mimetype: proto.String(mimitype), - FileEncSha256: uploaded.FileEncSHA256, - FileSha256: uploaded.FileSHA256, - FileLength: proto.Uint64(uint64(len(audioURL.Data))), - }, - } - - resp, err := instance.Client.SendMessage(context.Background(), jid, msg) + resp, err := a.wppService.SendImageMessage(instanceID, jid, audioURL, mimitype) if err != nil { utils.RespondInternalServerError(c, err.Error()) return @@ -121,8 +88,8 @@ func (a *sendAudioMessageController) Handler(c *gin.Context) { message := models.Message{ ChatJID: jid.User, - SenderJID: instance.Client.Store.ID.User, - InstanceID: instance.ID, + SenderJID: resp.Sender.User, + InstanceID: instanceID, MediaType: "audio", MediaPath: path, Timestamp: resp.Timestamp, diff --git a/controllers/send_image_message_controller.go b/controllers/send_image_message_controller.go index 22f6ee2..2bcf40b 100644 --- a/controllers/send_image_message_controller.go +++ b/controllers/send_image_message_controller.go @@ -1,16 +1,12 @@ package controllers import ( - "context" "zapmeow/models" "zapmeow/services" "zapmeow/utils" "github.com/gin-gonic/gin" "github.com/vincent-petithory/dataurl" - "go.mau.fi/whatsmeow" - waProto "go.mau.fi/whatsmeow/binary/proto" - "google.golang.org/protobuf/proto" ) type imageMessageBody struct { @@ -67,41 +63,13 @@ func (i *sendImageMessageController) Handler(c *gin.Context) { return } - instance, err := i.wppService.GetAuthenticatedInstance(instanceID) - if err != nil { - utils.RespondInternalServerError(c, err.Error()) - return - } - imageURL, err := dataurl.DecodeString(body.Base64) if err != nil { utils.RespondInternalServerError(c, err.Error()) return } - uploaded, err := instance.Client.Upload( - context.Background(), - imageURL.Data, - whatsmeow.MediaImage, - ) - if err != nil { - utils.RespondInternalServerError(c, err.Error()) - return - } - - msg := &waProto.Message{ - ImageMessage: &waProto.ImageMessage{ - Url: proto.String(uploaded.URL), - DirectPath: proto.String(uploaded.DirectPath), - MediaKey: uploaded.MediaKey, - Mimetype: proto.String(mimitype), - FileEncSha256: uploaded.FileEncSHA256, - FileSha256: uploaded.FileSHA256, - FileLength: proto.Uint64(uint64(len(imageURL.Data))), - }, - } - - resp, err := instance.Client.SendMessage(context.Background(), jid, msg) + resp, err := i.wppService.SendImageMessage(instanceID, jid, imageURL, mimitype) if err != nil { utils.RespondInternalServerError(c, err.Error()) return @@ -120,8 +88,8 @@ func (i *sendImageMessageController) Handler(c *gin.Context) { message := models.Message{ ChatJID: jid.User, - SenderJID: instance.Client.Store.ID.User, - InstanceID: instance.ID, + SenderJID: resp.Sender.User, + InstanceID: instanceID, MediaType: "image", MediaPath: path, Timestamp: resp.Timestamp, diff --git a/controllers/sent_text_message_controller.go b/controllers/send_text_message_controller.go similarity index 78% rename from controllers/sent_text_message_controller.go rename to controllers/send_text_message_controller.go index 2a595a6..bed5682 100644 --- a/controllers/sent_text_message_controller.go +++ b/controllers/send_text_message_controller.go @@ -1,13 +1,11 @@ package controllers import ( - "context" "zapmeow/models" "zapmeow/services" "zapmeow/utils" "github.com/gin-gonic/gin" - waProto "go.mau.fi/whatsmeow/binary/proto" ) type textMessageBody struct { @@ -56,21 +54,9 @@ func (t *sendTextMessageController) Handler(c *gin.Context) { utils.RespondBadRequest(c, "Invalid phone") return } - instanceId := c.Param("instanceId") + instanceID := c.Param("instanceId") - instance, err := t.wppService.GetAuthenticatedInstance(instanceId) - if err != nil { - utils.RespondInternalServerError(c, err.Error()) - return - } - - msg := &waProto.Message{ - ExtendedTextMessage: &waProto.ExtendedTextMessage{ - Text: &body.Text, - }, - } - - resp, err := instance.Client.SendMessage(context.Background(), jid, msg) + resp, err := t.wppService.SendTextMessage(instanceID, jid, body.Text) if err != nil { utils.RespondInternalServerError(c, err.Error()) return @@ -78,8 +64,8 @@ func (t *sendTextMessageController) Handler(c *gin.Context) { message := models.Message{ ChatJID: jid.User, - SenderJID: instance.Client.Store.ID.User, - InstanceID: instance.ID, + SenderJID: resp.Sender.User, + InstanceID: instanceID, Body: body.Text, Timestamp: resp.Timestamp, FromMe: true, diff --git a/services/account_service.go b/services/account_service.go index 36dd596..20d6751 100644 --- a/services/account_service.go +++ b/services/account_service.go @@ -10,7 +10,6 @@ type AccountService interface { GetConnectedAccounts() ([]models.Account, error) GetAccountByInstanceID(instanceID string) (*models.Account, error) UpdateAccount(instanceID string, data map[string]interface{}) error - // DeleteAccountInfos(instanceID string) error } type accountService struct { diff --git a/services/wpp_service.go b/services/wpp_service.go index 00483ef..78f413b 100644 --- a/services/wpp_service.go +++ b/services/wpp_service.go @@ -12,7 +12,9 @@ import ( "zapmeow/queues" "zapmeow/utils" + "github.com/vincent-petithory/dataurl" "go.mau.fi/whatsmeow" + waProto "go.mau.fi/whatsmeow/binary/proto" "go.mau.fi/whatsmeow/store" "go.mau.fi/whatsmeow/types" "go.mau.fi/whatsmeow/types/events" @@ -33,12 +35,23 @@ type ContactInfo struct { Picture string } +type SendMessageResponse struct { + ID string + Sender types.JID + Timestamp time.Time +} + type WppService interface { GetInstance(instanceID string) (*configs.Instance, error) GetAuthenticatedInstance(instanceID string) (*configs.Instance, error) + GetContactInfo(instanceID string, jid types.JID) (*ContactInfo, error) + SendMessage(instanceID string, jid types.JID, message *waProto.Message) (*SendMessageResponse, error) + SendTextMessage(instanceID string, jid types.JID, message string) (*SendMessageResponse, error) + SendAudioMessage(instanceID string, jid types.JID, audio *dataurl.DataURL, mimitype string) (*SendMessageResponse, error) + SendImageMessage(instanceID string, jid types.JID, image *dataurl.DataURL, mimitype string) (*SendMessageResponse, error) + UploadMedia(instanceID string, media *dataurl.DataURL, type_ string) (*whatsmeow.UploadResponse, error) DestroyInstance(instanceID string) error Logout(instanceID string) error - GetContactInfo(instanceID string, jid types.JID) (*ContactInfo, error) DeleteInstanceMessages(instanceID string) error } @@ -107,6 +120,92 @@ func (w *wppService) GetAuthenticatedInstance(instanceID string) (*configs.Insta return instance, nil } +func (w *wppService) SendTextMessage(instanceID string, jid types.JID, text string) (*SendMessageResponse, error) { + message := &waProto.Message{ + ExtendedTextMessage: &waProto.ExtendedTextMessage{ + Text: &text, + }, + } + + return w.SendMessage(instanceID, jid, message) +} + +func (w *wppService) SendAudioMessage(instanceID string, jid types.JID, audioURL *dataurl.DataURL, mimitype string) (*SendMessageResponse, error) { + uploaded, err := w.UploadMedia(instanceID, audioURL, "audio") + if err != nil { + return nil, err + } + + message := &waProto.Message{ + AudioMessage: &waProto.AudioMessage{ + Ptt: proto.Bool(true), + Url: proto.String(uploaded.URL), + DirectPath: proto.String(uploaded.DirectPath), + MediaKey: uploaded.MediaKey, + Mimetype: proto.String(mimitype), + FileEncSha256: uploaded.FileEncSHA256, + FileSha256: uploaded.FileSHA256, + FileLength: proto.Uint64(uint64(len(audioURL.Data))), + }, + } + + return w.SendMessage(instanceID, jid, message) +} + +func (w *wppService) SendImageMessage(instanceID string, jid types.JID, imageURL *dataurl.DataURL, mimitype string) (*SendMessageResponse, error) { + uploaded, err := w.UploadMedia(instanceID, imageURL, "image") + if err != nil { + return nil, err + } + + message := &waProto.Message{ + ImageMessage: &waProto.ImageMessage{ + Url: proto.String(uploaded.URL), + DirectPath: proto.String(uploaded.DirectPath), + MediaKey: uploaded.MediaKey, + Mimetype: proto.String(mimitype), + FileEncSha256: uploaded.FileEncSHA256, + FileSha256: uploaded.FileSHA256, + FileLength: proto.Uint64(uint64(len(imageURL.Data))), + }, + } + + return w.SendMessage(instanceID, jid, message) +} + +func (w *wppService) SendMessage(instanceID string, jid types.JID, message *waProto.Message) (*SendMessageResponse, error) { + instance, err := w.GetAuthenticatedInstance(instanceID) + if err != nil { + return nil, err + } + + resp, err := instance.Client.SendMessage(context.Background(), jid, message) + if err != nil { + return nil, err + } + + return &SendMessageResponse{ + ID: resp.ID, + Sender: *instance.Client.Store.ID, + Timestamp: resp.Timestamp, + }, nil +} + +func (w *wppService) UploadMedia(instanceID string, media *dataurl.DataURL, type_ string) (*whatsmeow.UploadResponse, error) { + instance, err := w.GetAuthenticatedInstance(instanceID) + if err != nil { + return nil, err + } + + mediaType := whatsmeow.MediaAudio + if type_ == "image" { + mediaType = whatsmeow.MediaImage + } + + uploaded, err := instance.Client.Upload(context.Background(), media.Data, mediaType) + return &uploaded, nil +} + func (w *wppService) DestroyInstance(instanceID string) error { instance, err := w.GetInstance(instanceID) if err != nil { From b15b69367836fdd137605bf9d493548a2b0928f5 Mon Sep 17 00:00:00 2001 From: Gabriel Augusto Date: Fri, 20 Oct 2023 17:25:47 -0300 Subject: [PATCH 2/4] refactor: logout --- services/account_service.go | 31 +++++++++++++++++++++++++++ services/wpp_service.go | 38 +++++----------------------------- workers/history_sync_worker.go | 2 +- 3 files changed, 37 insertions(+), 34 deletions(-) diff --git a/services/account_service.go b/services/account_service.go index 20d6751..76c1468 100644 --- a/services/account_service.go +++ b/services/account_service.go @@ -1,8 +1,12 @@ package services import ( + "fmt" + "os" + "path/filepath" "zapmeow/models" "zapmeow/repositories" + "zapmeow/utils" ) type AccountService interface { @@ -10,6 +14,7 @@ type AccountService interface { GetConnectedAccounts() ([]models.Account, error) GetAccountByInstanceID(instanceID string) (*models.Account, error) UpdateAccount(instanceID string, data map[string]interface{}) error + DeleteAccountMessages(instanceID string) error } type accountService struct { @@ -39,3 +44,29 @@ func (a *accountService) GetAccountByInstanceID(instanceID string) (*models.Acco func (a *accountService) UpdateAccount(instanceID string, data map[string]interface{}) error { return a.accountRepo.UpdateAccount(instanceID, data) } + +func (a *accountService) DeleteAccountMessages(instanceID string) error { + err := a.messageService.DeleteMessagesByInstanceID(instanceID) + if err != nil { + return err + } + return a.deleteAccountDirectory(instanceID) +} + +func (a *accountService) deleteAccountDirectory(instanceID string) error { + dirPath := utils.MakeAccountStoragePath(instanceID) + err := filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if !info.IsDir() { + err = os.Remove(path) + if err != nil { + return err + } + fmt.Printf("File removed: %s\n", path) + } + return nil + }) + return err +} diff --git a/services/wpp_service.go b/services/wpp_service.go index 78f413b..e460518 100644 --- a/services/wpp_service.go +++ b/services/wpp_service.go @@ -4,8 +4,6 @@ import ( "context" "errors" "fmt" - "os" - "path/filepath" "time" "zapmeow/configs" "zapmeow/models" @@ -50,9 +48,8 @@ type WppService interface { SendAudioMessage(instanceID string, jid types.JID, audio *dataurl.DataURL, mimitype string) (*SendMessageResponse, error) SendImageMessage(instanceID string, jid types.JID, image *dataurl.DataURL, mimitype string) (*SendMessageResponse, error) UploadMedia(instanceID string, media *dataurl.DataURL, type_ string) (*whatsmeow.UploadResponse, error) - DestroyInstance(instanceID string) error Logout(instanceID string) error - DeleteInstanceMessages(instanceID string) error + destroyInstance(instanceID string) error } func NewWppService( @@ -206,13 +203,13 @@ func (w *wppService) UploadMedia(instanceID string, media *dataurl.DataURL, type return &uploaded, nil } -func (w *wppService) DestroyInstance(instanceID string) error { +func (w *wppService) destroyInstance(instanceID string) error { instance, err := w.GetInstance(instanceID) if err != nil { return err } - err = w.DeleteInstanceMessages(instanceID) + err = w.accountService.DeleteAccountMessages(instanceID) if err != nil { return err } @@ -241,15 +238,7 @@ func (w *wppService) Logout(instanceID string) error { return err } - return w.DestroyInstance(instanceID) -} - -func (a *wppService) DeleteInstanceMessages(instanceID string) error { - err := a.messageService.DeleteMessagesByInstanceID(instanceID) - if err != nil { - return err - } - return a.deleteInstanceDirectory(instanceID) + return w.destroyInstance(instanceID) } func (w *wppService) GetContactInfo(instanceID string, jid types.JID) (*ContactInfo, error) { @@ -380,23 +369,6 @@ func (w *wppService) qrcode(instanceID string) { } } -func (a *wppService) deleteInstanceDirectory(instanceID string) error { - dirPath := utils.MakeAccountStoragePath(instanceID) - err := filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - if !info.IsDir() { - err = os.Remove(path) - if err != nil { - return err - } - fmt.Printf("File removed: %s\n", path) - } - return nil - }) - return err -} func (w *wppService) eventHandler(instanceID string, rawEvt interface{}) { switch evt := rawEvt.(type) { case *events.Message: @@ -445,7 +417,7 @@ func (w *wppService) handleConnected(instanceID string) { } func (w *wppService) handleLoggedOut(instanceID string) { - err := w.DestroyInstance(instanceID) + err := w.destroyInstance(instanceID) if err != nil { fmt.Println("Error", err) } diff --git a/workers/history_sync_worker.go b/workers/history_sync_worker.go index 53cb23d..1e1cf23 100644 --- a/workers/history_sync_worker.go +++ b/workers/history_sync_worker.go @@ -75,7 +75,7 @@ func (q *historySyncWorker) ProcessQueue() { } if !account.WasSynced { - if err := q.wppService.DeleteInstanceMessages(account.InstanceID); err != nil { + if err := q.accountService.DeleteAccountMessages(account.InstanceID); err != nil { fmt.Println(err) continue } From b57d7585f317f867ec03b42361082e895ad2fe1e Mon Sep 17 00:00:00 2001 From: Gabriel Augusto Date: Sun, 22 Oct 2023 20:29:37 -0300 Subject: [PATCH 3/4] wip --- controllers/send_audio_message_controller.go | 8 +- controllers/send_image_message_controller.go | 8 +- services/message_service.go | 171 ------------- services/wpp_service.go | 254 +++++++++++++++++-- utils/save_midia.go | 2 +- workers/history_sync_worker.go | 39 ++- 6 files changed, 272 insertions(+), 210 deletions(-) diff --git a/controllers/send_audio_message_controller.go b/controllers/send_audio_message_controller.go index 461bcee..1aa744b 100644 --- a/controllers/send_audio_message_controller.go +++ b/controllers/send_audio_message_controller.go @@ -77,8 +77,8 @@ func (a *sendAudioMessageController) Handler(c *gin.Context) { path, err := utils.SaveMedia( instanceID, - audioURL.Data, resp.ID, + audioURL.Data, mimitype, ) if err != nil { @@ -87,14 +87,14 @@ func (a *sendAudioMessageController) Handler(c *gin.Context) { } message := models.Message{ + FromMe: true, ChatJID: jid.User, SenderJID: resp.Sender.User, InstanceID: instanceID, - MediaType: "audio", - MediaPath: path, Timestamp: resp.Timestamp, - FromMe: true, MessageID: resp.ID, + MediaType: "audio", + MediaPath: path, } err = a.messageService.CreateMessage(&message) diff --git a/controllers/send_image_message_controller.go b/controllers/send_image_message_controller.go index 2bcf40b..3dc1967 100644 --- a/controllers/send_image_message_controller.go +++ b/controllers/send_image_message_controller.go @@ -77,8 +77,8 @@ func (i *sendImageMessageController) Handler(c *gin.Context) { path, err := utils.SaveMedia( instanceID, - imageURL.Data, resp.ID, + imageURL.Data, mimitype, ) if err != nil { @@ -87,14 +87,14 @@ func (i *sendImageMessageController) Handler(c *gin.Context) { } message := models.Message{ + FromMe: true, ChatJID: jid.User, SenderJID: resp.Sender.User, InstanceID: instanceID, - MediaType: "image", - MediaPath: path, Timestamp: resp.Timestamp, - FromMe: true, MessageID: resp.ID, + MediaType: "image", + MediaPath: path, } err = i.messageService.CreateMessage(&message) diff --git a/services/message_service.go b/services/message_service.go index 85b549b..fd88520 100644 --- a/services/message_service.go +++ b/services/message_service.go @@ -5,16 +5,10 @@ import ( "fmt" "io/ioutil" "mime" - "os" "path/filepath" "time" - "zapmeow/configs" "zapmeow/models" "zapmeow/repositories" - "zapmeow/utils" - - waProto "go.mau.fi/whatsmeow/binary/proto" - "go.mau.fi/whatsmeow/types/events" ) type MessageService interface { @@ -23,7 +17,6 @@ type MessageService interface { GetChatMessages(instanceID string, chatJID string) (*[]models.Message, error) CountChatMessages(instanceID string, chatJID string) (int64, error) DeleteMessagesByInstanceID(instanceID string) error - Parse(instance *configs.Instance, msg *events.Message) *models.Message ToJSON(message models.Message) Message } @@ -72,43 +65,6 @@ func (m *messageService) DeleteMessagesByInstanceID(instanceID string) error { return m.messageRep.DeleteMessagesByInstanceID(instanceID) } -func (m *messageService) Parse(instance *configs.Instance, msg *events.Message) *models.Message { - mediaType, path := m.downloadMessageMedia( - instance, - msg.Message, - msg.Info.ID, - ) - - var body = m.getTextMessage(msg.Message) - if mediaType == "" && body == "" { - return nil - } - - if mediaType != "" { - return &models.Message{ - InstanceID: instance.ID, - MessageID: msg.Info.ID, - FromMe: msg.Info.MessageSource.IsFromMe, - ChatJID: msg.Info.Chat.User, - SenderJID: msg.Info.Sender.User, - Body: body, - MediaPath: mediaType, - MediaType: path, - Timestamp: msg.Info.Timestamp, - } - } - - return &models.Message{ - InstanceID: instance.ID, - MessageID: msg.Info.ID, - FromMe: msg.Info.MessageSource.IsFromMe, - ChatJID: msg.Info.Chat.User, - SenderJID: msg.Info.Sender.User, - Body: body, - Timestamp: msg.Info.Timestamp, - } -} - func (m *messageService) ToJSON(message models.Message) Message { messageJson := Message{ ID: message.ID, @@ -140,130 +96,3 @@ func (m *messageService) ToJSON(message models.Message) Message { return messageJson } - -func (m *messageService) downloadMessageMedia( - instance *configs.Instance, - message *waProto.Message, - fileName string, -) (string, string) { - path := "" - mediaType := "" - - dirPath := utils.MakeAccountStoragePath(instance.ID) - err := os.MkdirAll(dirPath, 0751) - if err != nil { - return "", "" - } - - document := message.GetDocumentMessage() - if document != nil { - mediaType = "document" - - data, err := instance.Client.Download(document) - - if err != nil { - // fmt.Println("Failed to download document", err) - return mediaType, "" - } - - path, err = utils.SaveMedia( - instance.ID, - data, - fileName, - document.GetMimetype(), - ) - if err != nil { - // fmt.Println("Failed to save document", err) - return mediaType, "" - } - // fmt.Println("Document saved") - } - - audio := message.GetAudioMessage() - if audio != nil { - mediaType = "audio" - - data, err := instance.Client.Download(audio) - if err != nil { - // fmt.Println("Failed to download audio", err) - return mediaType, "" - } - - path, err = utils.SaveMedia( - instance.ID, - data, - fileName, - audio.GetMimetype(), - ) - - if err != nil { - // fmt.Println("Failed to save audio", err) - return mediaType, "" - } - // fmt.Println("Audio saved") - } - - image := message.GetImageMessage() - if image != nil { - mediaType = "image" - data, err := instance.Client.Download(image) - if err != nil { - fmt.Println("Failed to download image", err) - return mediaType, "" - } - - path, err = utils.SaveMedia( - instance.ID, - data, - fileName, - image.GetMimetype(), - ) - if err != nil { - fmt.Println("Failed to save image", err) - return mediaType, "" - } - fmt.Println("Image saved") - } - - sticker := message.GetStickerMessage() - if sticker != nil { - mediaType = "image" - data, err := instance.Client.Download(sticker) - if err != nil { - // fmt.Println("Failed to download sticker", err) - return mediaType, "" - } - - path, err = utils.SaveMedia( - instance.ID, - data, - fileName, - sticker.GetMimetype(), - ) - if err != nil { - // fmt.Println("Failed to download sticker", err) - return mediaType, "" - } - - // fmt.Println("Sticker saved") - } - - video := message.GetVideoMessage() - if video != nil { - return "video", "" - } - - if path != "" && mediaType != "" { - return mediaType, path - } - - return "", "" -} - -func (m *messageService) getTextMessage(message *waProto.Message) string { - extendedTextMessage := message.GetExtendedTextMessage() - if extendedTextMessage != nil { - return *extendedTextMessage.Text - } - return message.GetConversation() -} diff --git a/services/wpp_service.go b/services/wpp_service.go index e460518..c82a467 100644 --- a/services/wpp_service.go +++ b/services/wpp_service.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "os" "time" "zapmeow/configs" "zapmeow/models" @@ -39,17 +40,65 @@ type SendMessageResponse struct { Timestamp time.Time } +type DownloadedMedia struct { + Data []byte + Type MediaType + Mimetype string +} + +type ParsedEventMessage struct { + InstanceID string + Body string + SenderJID string + ChatJID string + MessageID string + Timestamp time.Time + FromMe bool + MediaType *MediaType + Media *[]byte + Mimetype *string +} + +type MediaType int + +const ( + Audio MediaType = iota + Image + Document + Sticker + Video +) + +func (m MediaType) String() string { + switch m { + case Audio: + return "audio" + case Document: + return "document" + case Sticker: + return "sticker" + case Video: + return "video" + case Image: + return "image" + } + return "unknown" +} + type WppService interface { GetInstance(instanceID string) (*configs.Instance, error) GetAuthenticatedInstance(instanceID string) (*configs.Instance, error) GetContactInfo(instanceID string, jid types.JID) (*ContactInfo, error) - SendMessage(instanceID string, jid types.JID, message *waProto.Message) (*SendMessageResponse, error) - SendTextMessage(instanceID string, jid types.JID, message string) (*SendMessageResponse, error) - SendAudioMessage(instanceID string, jid types.JID, audio *dataurl.DataURL, mimitype string) (*SendMessageResponse, error) - SendImageMessage(instanceID string, jid types.JID, image *dataurl.DataURL, mimitype string) (*SendMessageResponse, error) - UploadMedia(instanceID string, media *dataurl.DataURL, type_ string) (*whatsmeow.UploadResponse, error) + SendMessage(instanceID string, jid types.JID, message *waProto.Message) (SendMessageResponse, error) + SendTextMessage(instanceID string, jid types.JID, message string) (SendMessageResponse, error) + SendAudioMessage(instanceID string, jid types.JID, audio *dataurl.DataURL, mimitype string) (SendMessageResponse, error) + SendImageMessage(instanceID string, jid types.JID, image *dataurl.DataURL, mimitype string) (SendMessageResponse, error) + ParseEventMessage(instance *configs.Instance, message *events.Message) (ParsedEventMessage, error) Logout(instanceID string) error destroyInstance(instanceID string) error + getTextMessage(message *waProto.Message) string + downloadMedia(instance *configs.Instance, message *waProto.Message) (*DownloadedMedia, error) + uploadMedia(instanceID string, media *dataurl.DataURL, mediaType MediaType) (*whatsmeow.UploadResponse, error) } func NewWppService( @@ -117,7 +166,7 @@ func (w *wppService) GetAuthenticatedInstance(instanceID string) (*configs.Insta return instance, nil } -func (w *wppService) SendTextMessage(instanceID string, jid types.JID, text string) (*SendMessageResponse, error) { +func (w *wppService) SendTextMessage(instanceID string, jid types.JID, text string) (SendMessageResponse, error) { message := &waProto.Message{ ExtendedTextMessage: &waProto.ExtendedTextMessage{ Text: &text, @@ -127,10 +176,10 @@ func (w *wppService) SendTextMessage(instanceID string, jid types.JID, text stri return w.SendMessage(instanceID, jid, message) } -func (w *wppService) SendAudioMessage(instanceID string, jid types.JID, audioURL *dataurl.DataURL, mimitype string) (*SendMessageResponse, error) { - uploaded, err := w.UploadMedia(instanceID, audioURL, "audio") +func (w *wppService) SendAudioMessage(instanceID string, jid types.JID, audioURL *dataurl.DataURL, mimitype string) (SendMessageResponse, error) { + uploaded, err := w.uploadMedia(instanceID, audioURL, Audio) if err != nil { - return nil, err + return SendMessageResponse{}, err } message := &waProto.Message{ @@ -149,10 +198,10 @@ func (w *wppService) SendAudioMessage(instanceID string, jid types.JID, audioURL return w.SendMessage(instanceID, jid, message) } -func (w *wppService) SendImageMessage(instanceID string, jid types.JID, imageURL *dataurl.DataURL, mimitype string) (*SendMessageResponse, error) { - uploaded, err := w.UploadMedia(instanceID, imageURL, "image") +func (w *wppService) SendImageMessage(instanceID string, jid types.JID, imageURL *dataurl.DataURL, mimitype string) (SendMessageResponse, error) { + uploaded, err := w.uploadMedia(instanceID, imageURL, Image) if err != nil { - return nil, err + return SendMessageResponse{}, err } message := &waProto.Message{ @@ -170,39 +219,168 @@ func (w *wppService) SendImageMessage(instanceID string, jid types.JID, imageURL return w.SendMessage(instanceID, jid, message) } -func (w *wppService) SendMessage(instanceID string, jid types.JID, message *waProto.Message) (*SendMessageResponse, error) { +func (w *wppService) SendMessage(instanceID string, jid types.JID, message *waProto.Message) (SendMessageResponse, error) { instance, err := w.GetAuthenticatedInstance(instanceID) if err != nil { - return nil, err + return SendMessageResponse{}, err } resp, err := instance.Client.SendMessage(context.Background(), jid, message) if err != nil { - return nil, err + return SendMessageResponse{}, err } - return &SendMessageResponse{ + return SendMessageResponse{ ID: resp.ID, Sender: *instance.Client.Store.ID, Timestamp: resp.Timestamp, }, nil } -func (w *wppService) UploadMedia(instanceID string, media *dataurl.DataURL, type_ string) (*whatsmeow.UploadResponse, error) { +func (w *wppService) ParseEventMessage(instance *configs.Instance, message *events.Message) (ParsedEventMessage, error) { + media, err := w.downloadMedia( + instance, + message.Message, + ) + + if err != nil && media == nil { + fmt.Println("================== aaaaaaaaa ==================", media.Type) + return ParsedEventMessage{}, err + } + + text := w.getTextMessage(message.Message) + base := ParsedEventMessage{ + InstanceID: instance.ID, + Body: text, + MessageID: message.Info.ID, + ChatJID: message.Info.Chat.User, + SenderJID: message.Info.Sender.User, + FromMe: message.Info.MessageSource.IsFromMe, + Timestamp: message.Info.Timestamp, + } + + if media != nil && err == nil { + base.MediaType = &media.Type + base.Mimetype = &media.Mimetype + base.Media = &media.Data + return base, nil + } + + return base, nil +} + +func (w *wppService) uploadMedia(instanceID string, media *dataurl.DataURL, mediaType MediaType) (*whatsmeow.UploadResponse, error) { instance, err := w.GetAuthenticatedInstance(instanceID) if err != nil { return nil, err } - mediaType := whatsmeow.MediaAudio - if type_ == "image" { - mediaType = whatsmeow.MediaImage + var mType whatsmeow.MediaType + switch mediaType { + case Image: + mType = whatsmeow.MediaImage + case Audio: + mType = whatsmeow.MediaAudio + default: + return nil, errors.New("unknown media type") + } + + uploaded, err := instance.Client.Upload(context.Background(), media.Data, mType) + if err != nil { + return nil, err } - uploaded, err := instance.Client.Upload(context.Background(), media.Data, mediaType) return &uploaded, nil } +func (m *wppService) downloadMedia(instance *configs.Instance, message *waProto.Message) (*DownloadedMedia, error) { + dirPath := utils.MakeAccountStoragePath(instance.ID) + err := os.MkdirAll(dirPath, 0751) + if err != nil { + return nil, err + } + + document := message.GetDocumentMessage() + if document != nil { + data, err := instance.Client.Download(document) + if err != nil { + return &DownloadedMedia{Type: Document}, err + } + + return &DownloadedMedia{ + Data: data, + Type: Document, + Mimetype: document.GetMimetype(), + }, nil + } + + audio := message.GetAudioMessage() + if audio != nil { + data, err := instance.Client.Download(audio) + if err != nil { + return &DownloadedMedia{Type: Audio}, err + } + + return &DownloadedMedia{ + Data: data, + Type: Audio, + Mimetype: audio.GetMimetype(), + }, nil + } + + image := message.GetImageMessage() + if image != nil { + data, err := instance.Client.Download(image) + if err != nil { + return &DownloadedMedia{Type: Image}, err + } + + return &DownloadedMedia{ + Data: data, + Type: Image, + Mimetype: image.GetMimetype(), + }, nil + } + + sticker := message.GetStickerMessage() + if sticker != nil { + data, err := instance.Client.Download(sticker) + if err != nil { + return &DownloadedMedia{Type: Sticker}, err + } + + return &DownloadedMedia{ + Data: data, + Type: Sticker, + Mimetype: sticker.GetMimetype(), + }, nil + } + + video := message.GetVideoMessage() + if video != nil { + data, err := instance.Client.Download(video) + if err != nil { + return &DownloadedMedia{Type: Video}, err + } + + return &DownloadedMedia{ + Data: data, + Type: Video, + Mimetype: video.GetMimetype(), + }, nil + } + + return nil, nil +} + +func (m *wppService) getTextMessage(message *waProto.Message) string { + extendedTextMessage := message.GetExtendedTextMessage() + if extendedTextMessage != nil { + return *extendedTextMessage.Text + } + return message.GetConversation() +} + func (w *wppService) destroyInstance(instanceID string) error { instance, err := w.GetInstance(instanceID) if err != nil { @@ -432,20 +610,46 @@ func (w *wppService) handleLoggedOut(instanceID string) { func (w *wppService) handleMessage(instanceId string, evt *events.Message) { instance := w.app.Instances[instanceId] - message := w.messageService.Parse(instance, evt) + parsedEventMessage, err := w.ParseEventMessage(instance, evt) - if message == nil { + if err != nil { return } - err := w.messageService.CreateMessage(message) + message := models.Message{ + SenderJID: parsedEventMessage.SenderJID, + ChatJID: parsedEventMessage.ChatJID, + InstanceID: parsedEventMessage.InstanceID, + MessageID: parsedEventMessage.MessageID, + Timestamp: parsedEventMessage.Timestamp, + Body: parsedEventMessage.Body, + FromMe: parsedEventMessage.FromMe, + } + + if parsedEventMessage.MediaType != nil { + path, err := utils.SaveMedia( + instance.ID, + parsedEventMessage.MessageID, + *parsedEventMessage.Media, + *parsedEventMessage.Mimetype, + ) + + if err != nil { + fmt.Println(err) + } + + message.MediaType = parsedEventMessage.MediaType.String() + message.MediaPath = path + } + + err = w.messageService.CreateMessage(&message) if err != nil { fmt.Println(err) } body := map[string]interface{}{ "InstanceId": instanceId, - "Message": w.messageService.ToJSON(*message), + "Message": w.messageService.ToJSON(message), } err = utils.Request(w.app.Config.WebhookURL, body) diff --git a/utils/save_midia.go b/utils/save_midia.go index b59109c..90907ad 100644 --- a/utils/save_midia.go +++ b/utils/save_midia.go @@ -6,7 +6,7 @@ import ( "os" ) -func SaveMedia(instanceID string, data []byte, fileName string, mimetype string) (string, error) { +func SaveMedia(instanceID string, fileName string, data []byte, mimetype string) (string, error) { dirPath := MakeAccountStoragePath(instanceID) err := os.MkdirAll(dirPath, 0751) if err != nil { diff --git a/workers/history_sync_worker.go b/workers/history_sync_worker.go index 1e1cf23..c83bf42 100644 --- a/workers/history_sync_worker.go +++ b/workers/history_sync_worker.go @@ -109,11 +109,11 @@ func (q *historySyncWorker) ProcessQueue() { var eventsMessage []*events.Message for _, msg := range historySyncMsgs { - parsedMsg, err := instance.Client.ParseWebMessage(chatJID, msg.GetMessage()) + parsedMessage, err := instance.Client.ParseWebMessage(chatJID, msg.GetMessage()) if err != nil { continue } - eventsMessage = append(eventsMessage, parsedMsg) + eventsMessage = append(eventsMessage, parsedMessage) } sort.Slice(eventsMessage, func(i, j int) bool { @@ -124,9 +124,38 @@ func (q *historySyncWorker) ProcessQueue() { slice := eventsMessage[:limit] for _, eventMessage := range slice { - message := q.messageService.Parse(instance, eventMessage) - if message != nil { - messages = append(messages, *message) + parsedEventMessage, err := q.wppService.ParseEventMessage(instance, eventMessage) + + message := models.Message{ + SenderJID: parsedEventMessage.SenderJID, + ChatJID: parsedEventMessage.ChatJID, + InstanceID: parsedEventMessage.InstanceID, + MessageID: parsedEventMessage.MessageID, + Timestamp: parsedEventMessage.Timestamp, + Body: parsedEventMessage.Body, + FromMe: parsedEventMessage.FromMe, + } + + if parsedEventMessage.MediaType != nil { + path, err := utils.SaveMedia( + instance.ID, + parsedEventMessage.MessageID, + *parsedEventMessage.Media, + *parsedEventMessage.Mimetype, + ) + + if err != nil { + fmt.Println(err) + } + + message.MediaType = parsedEventMessage.MediaType.String() + message.MediaPath = path + } + + fmt.Println(message) + + if err != nil { + messages = append(messages, message) } } } From 09e82058e9f150de28cb826e8f0661c1d1d093f9 Mon Sep 17 00:00:00 2001 From: Gabriel Augusto Date: Wed, 25 Oct 2023 18:02:21 -0300 Subject: [PATCH 4/4] remove print --- workers/history_sync_worker.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/workers/history_sync_worker.go b/workers/history_sync_worker.go index c83bf42..911b078 100644 --- a/workers/history_sync_worker.go +++ b/workers/history_sync_worker.go @@ -152,8 +152,6 @@ func (q *historySyncWorker) ProcessQueue() { message.MediaPath = path } - fmt.Println(message) - if err != nil { messages = append(messages, message) }