You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
854 lines
24 KiB
854 lines
24 KiB
package whatsapp
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/base64"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
|
|
webp "github.com/nickalie/go-webpbin"
|
|
"github.com/sunshineplan/imgconv"
|
|
|
|
qrCode "github.com/skip2/go-qrcode"
|
|
"google.golang.org/protobuf/proto"
|
|
|
|
"go.mau.fi/whatsmeow"
|
|
waproto "go.mau.fi/whatsmeow/binary/proto"
|
|
"go.mau.fi/whatsmeow/store"
|
|
"go.mau.fi/whatsmeow/store/sqlstore"
|
|
"go.mau.fi/whatsmeow/types"
|
|
|
|
"github.com/dimaskiddo/go-whatsapp-multidevice-rest/pkg/env"
|
|
"github.com/dimaskiddo/go-whatsapp-multidevice-rest/pkg/log"
|
|
)
|
|
|
|
var WhatsAppDatastore *sqlstore.Container
|
|
var WhatsAppClient = make(map[string]*whatsmeow.Client)
|
|
|
|
func init() {
|
|
var err error
|
|
|
|
dbType, err := env.GetEnvString("WHATSAPP_DATASTORE_TYPE")
|
|
if err != nil {
|
|
log.Print(nil).Fatal("Error Parse Environment Variable for WhatsApp Client Datastore Type")
|
|
}
|
|
|
|
dbURI, err := env.GetEnvString("WHATSAPP_DATASTORE_URI")
|
|
if err != nil {
|
|
log.Print(nil).Fatal("Error Parse Environment Variable for WhatsApp Client Datastore URI")
|
|
}
|
|
|
|
datastore, err := sqlstore.New(dbType, dbURI, nil)
|
|
if err != nil {
|
|
log.Print(nil).Fatal("Error Connect WhatsApp Client Datastore")
|
|
}
|
|
|
|
WhatsAppDatastore = datastore
|
|
}
|
|
|
|
func WhatsAppInitClient(device *store.Device, jid string) {
|
|
var err error
|
|
|
|
if WhatsAppClient[jid] == nil {
|
|
if device == nil {
|
|
// Initialize New WhatsApp Client Device in Datastore
|
|
device = WhatsAppDatastore.NewDevice()
|
|
}
|
|
|
|
// Set Client Properties
|
|
store.CompanionProps.Os = proto.String("Go WhatsApp Multi-Device REST")
|
|
store.CompanionProps.PlatformType = waproto.CompanionProps_DESKTOP.Enum()
|
|
|
|
// Set Client Versions
|
|
version.Major, err = env.GetEnvInt("WHATSAPP_VERSION_MAJOR")
|
|
if err == nil {
|
|
store.CompanionProps.Version.Primary = proto.Uint32(uint32(version.Major))
|
|
}
|
|
version.Minor, err = env.GetEnvInt("WHATSAPP_VERSION_MINOR")
|
|
if err == nil {
|
|
store.CompanionProps.Version.Secondary = proto.Uint32(uint32(version.Minor))
|
|
}
|
|
version.Patch, err = env.GetEnvInt("WHATSAPP_VERSION_PATCH")
|
|
if err == nil {
|
|
store.CompanionProps.Version.Tertiary = proto.Uint32(uint32(version.Patch))
|
|
}
|
|
|
|
// Initialize New WhatsApp Client
|
|
// And Save it to The Map
|
|
WhatsAppClient[jid] = whatsmeow.NewClient(device, nil)
|
|
|
|
// Set WhatsApp Client Auto Reconnect
|
|
WhatsAppClient[jid].EnableAutoReconnect = true
|
|
|
|
// Set WhatsApp Client Auto Trust Identity
|
|
WhatsAppClient[jid].AutoTrustIdentity = true
|
|
}
|
|
}
|
|
|
|
func WhatsAppGenerateQR(qrChan <-chan whatsmeow.QRChannelItem) (string, int) {
|
|
qrChanCode := make(chan string)
|
|
qrChanTimeout := make(chan int)
|
|
|
|
// Get QR Code Data and Timeout
|
|
go func() {
|
|
for evt := range qrChan {
|
|
if evt.Event == "code" {
|
|
qrChanCode <- evt.Code
|
|
qrChanTimeout <- int(evt.Timeout.Seconds())
|
|
}
|
|
}
|
|
}()
|
|
|
|
// Generate QR Code Data to PNG Image
|
|
qrTemp := <-qrChanCode
|
|
qrPNG, _ := qrCode.Encode(qrTemp, qrCode.Medium, 256)
|
|
|
|
// Return QR Code PNG in Base64 Format and Timeout Information
|
|
return base64.StdEncoding.EncodeToString(qrPNG), <-qrChanTimeout
|
|
}
|
|
|
|
func WhatsAppLogin(jid string) (string, int, error) {
|
|
if WhatsAppClient[jid] != nil {
|
|
// Make Sure WebSocket Connection is Disconnected
|
|
WhatsAppClient[jid].Disconnect()
|
|
|
|
if WhatsAppClient[jid].Store.ID == nil {
|
|
// Device ID is not Exist
|
|
// Generate QR Code
|
|
qrChanGenerate, _ := WhatsAppClient[jid].GetQRChannel(context.Background())
|
|
|
|
// Connect WebSocket while Initialize QR Code Data to be Sent
|
|
err := WhatsAppClient[jid].Connect()
|
|
if err != nil {
|
|
return "", 0, err
|
|
}
|
|
|
|
// Set WhatsApp Client Presence to Available
|
|
_ = WhatsAppClient[jid].SendPresence(types.PresenceAvailable)
|
|
|
|
// Get Generated QR Code and Timeout Information
|
|
qrImage, qrTimeout := WhatsAppGenerateQR(qrChanGenerate)
|
|
|
|
// Return QR Code in Base64 Format and Timeout Information
|
|
return "data:image/png;base64," + qrImage, qrTimeout, nil
|
|
} else {
|
|
// Device ID is Exist
|
|
// Reconnect WebSocket
|
|
err := WhatsAppReconnect(jid)
|
|
if err != nil {
|
|
return "", 0, err
|
|
}
|
|
|
|
return "WhatsApp Client is Reconnected", 0, nil
|
|
}
|
|
}
|
|
|
|
// Return Error WhatsApp Client is not Valid
|
|
return "", 0, errors.New("WhatsApp Client is not Valid")
|
|
}
|
|
|
|
func WhatsAppReconnect(jid string) error {
|
|
if WhatsAppClient[jid] != nil {
|
|
// Make Sure WebSocket Connection is Disconnected
|
|
WhatsAppClient[jid].Disconnect()
|
|
|
|
// Make Sure Store ID is not Empty
|
|
// To do Reconnection
|
|
if WhatsAppClient[jid].Store.ID != nil {
|
|
err := WhatsAppClient[jid].Connect()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Set WhatsApp Client Presence to Available
|
|
_ = WhatsAppClient[jid].SendPresence(types.PresenceAvailable)
|
|
|
|
return nil
|
|
}
|
|
|
|
return errors.New("WhatsApp Client Store ID is Empty, Please Re-Login and Scan QR Code Again")
|
|
}
|
|
|
|
return errors.New("WhatsApp Client is not Valid")
|
|
}
|
|
|
|
func WhatsAppLogout(jid string) error {
|
|
if WhatsAppClient[jid] != nil {
|
|
// Make Sure Store ID is not Empty
|
|
if WhatsAppClient[jid].Store.ID != nil {
|
|
var err error
|
|
|
|
// Set WhatsApp Client Presence to Unavailable
|
|
_ = WhatsAppClient[jid].SendPresence(types.PresenceUnavailable)
|
|
|
|
// Logout WhatsApp Client and Disconnect from WebSocket
|
|
err = WhatsAppClient[jid].Logout()
|
|
if err != nil {
|
|
// Force Disconnect
|
|
WhatsAppClient[jid].Disconnect()
|
|
|
|
// Manually Delete Device from Datastore Store
|
|
err = WhatsAppClient[jid].Store.Delete()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// Free WhatsApp Client Map
|
|
WhatsAppClient[jid] = nil
|
|
delete(WhatsAppClient, jid)
|
|
|
|
return nil
|
|
}
|
|
|
|
return errors.New("WhatsApp Client Store ID is Empty, Please Re-Login and Scan QR Code Again")
|
|
}
|
|
|
|
// Return Error WhatsApp Client is not Valid
|
|
return errors.New("WhatsApp Client is not Valid")
|
|
}
|
|
|
|
func WhatsAppClientIsOK(jid string) error {
|
|
// Make Sure WhatsApp Client is Connected
|
|
if !WhatsAppClient[jid].IsConnected() {
|
|
return errors.New("WhatsApp Client is not Connected")
|
|
}
|
|
|
|
// Make Sure WhatsApp Client is Logged In
|
|
if !WhatsAppClient[jid].IsLoggedIn() {
|
|
return errors.New("WhatsApp Client is not Logged In")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func WhatsAppJIDIsOK(jid types.JID) error {
|
|
// Make Sure JID is not Empty
|
|
if jid.IsEmpty() {
|
|
return errors.New("Phone Number is not Registered")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func WhatsAppGetJID(jid string, phone string) types.JID {
|
|
if WhatsAppClient[jid] != nil {
|
|
var phones []string
|
|
|
|
phones = append(phones, "+"+phone)
|
|
jidInfos, err := WhatsAppClient[jid].IsOnWhatsApp(phones)
|
|
if err == nil {
|
|
// If Phone Number is Registered as JID
|
|
if jidInfos[0].IsIn {
|
|
// Return JID Information
|
|
return jidInfos[0].JID
|
|
}
|
|
}
|
|
}
|
|
|
|
// Return Empty JID Information
|
|
return types.EmptyJID
|
|
}
|
|
|
|
func WhatsAppComposeJID(jid string, phone string) (types.JID, error) {
|
|
// Decompose Phone Number First Before Recomposing
|
|
phone = WhatsAppDecomposeJID(phone)
|
|
|
|
// Get Registered JID Information from Phone Number
|
|
jidInfo := WhatsAppGetJID(jid, phone)
|
|
|
|
// Check if JID Information is OK
|
|
err := WhatsAppJIDIsOK(jidInfo)
|
|
if err != nil {
|
|
// Return Empty JID
|
|
return types.EmptyJID, err
|
|
}
|
|
|
|
// Return New Composed JID from Phone Number and JID Server Information
|
|
return types.NewJID(phone, jidInfo.Server), nil
|
|
}
|
|
|
|
func WhatsAppDecomposeJID(phone string) string {
|
|
// Check if Phone Number Contains '@' Symbol
|
|
if strings.ContainsRune(phone, '@') {
|
|
// Split Phone Number Based on '@' Symbol
|
|
// and Get Only The First Section Before The Symbol
|
|
buffers := strings.Split(phone, "@")
|
|
phone = buffers[0]
|
|
}
|
|
|
|
// Check if Phone Number First Character is '+' Symbol
|
|
if phone[0] == '+' {
|
|
// Remove '+' Symbol from Phone Number
|
|
phone = phone[1:]
|
|
}
|
|
|
|
return phone
|
|
}
|
|
|
|
func WhatsAppComposeStatus(jid string, rjid types.JID, isComposing bool, isAudio bool) {
|
|
// Set Compose Status
|
|
var typeCompose types.ChatPresence
|
|
if isComposing {
|
|
typeCompose = types.ChatPresenceComposing
|
|
} else {
|
|
typeCompose = types.ChatPresencePaused
|
|
}
|
|
|
|
// Set Compose Media Audio (Recording) or Text (Typing)
|
|
var typeComposeMedia types.ChatPresenceMedia
|
|
if isAudio {
|
|
typeComposeMedia = types.ChatPresenceMediaAudio
|
|
} else {
|
|
typeComposeMedia = types.ChatPresenceMediaText
|
|
}
|
|
|
|
// Send Chat Compose Status
|
|
_ = WhatsAppClient[jid].SendChatPresence(rjid, typeCompose, typeComposeMedia)
|
|
}
|
|
|
|
func WhatsAppSendText(jid string, rjid string, message string) (string, error) {
|
|
if WhatsAppClient[jid] != nil {
|
|
var err error
|
|
|
|
// Make Sure WhatsApp Client is OK
|
|
err = WhatsAppClientIsOK(jid)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Check if Remote JID is Registered and
|
|
// Compose New Remote JID
|
|
remoteJID, err := WhatsAppComposeJID(jid, rjid)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Set Chat Presence
|
|
WhatsAppComposeStatus(jid, remoteJID, true, false)
|
|
defer WhatsAppComposeStatus(jid, remoteJID, false, false)
|
|
|
|
// Compose WhatsApp Proto
|
|
msgId := whatsmeow.GenerateMessageID()
|
|
msgContent := &waproto.Message{
|
|
Conversation: proto.String(message),
|
|
}
|
|
|
|
// Send WhatsApp Message Proto
|
|
_, err = WhatsAppClient[jid].SendMessage(remoteJID, msgId, msgContent)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return msgId, nil
|
|
}
|
|
|
|
// Return Error WhatsApp Client is not Valid
|
|
return "", errors.New("WhatsApp Client is not Valid")
|
|
}
|
|
|
|
func WhatsAppSendLocation(jid string, rjid string, latitude float64, longitude float64) (string, error) {
|
|
if WhatsAppClient[jid] != nil {
|
|
var err error
|
|
|
|
// Make Sure WhatsApp Client is OK
|
|
err = WhatsAppClientIsOK(jid)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Check if Remote JID is Registered and
|
|
// Compose New Remote JID
|
|
remoteJID, err := WhatsAppComposeJID(jid, rjid)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Set Chat Presence
|
|
WhatsAppComposeStatus(jid, remoteJID, true, false)
|
|
defer WhatsAppComposeStatus(jid, remoteJID, false, false)
|
|
|
|
// Compose WhatsApp Proto
|
|
msgId := whatsmeow.GenerateMessageID()
|
|
msgContent := &waproto.Message{
|
|
LocationMessage: &waproto.LocationMessage{
|
|
DegreesLatitude: proto.Float64(latitude),
|
|
DegreesLongitude: proto.Float64(longitude),
|
|
},
|
|
}
|
|
|
|
// Send WhatsApp Message Proto
|
|
_, err = WhatsAppClient[jid].SendMessage(remoteJID, msgId, msgContent)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return msgId, nil
|
|
}
|
|
|
|
// Return Error WhatsApp Client is not Valid
|
|
return "", errors.New("WhatsApp Client is not Valid")
|
|
}
|
|
|
|
func WhatsAppSendDocument(jid string, rjid string, fileBytes []byte, fileType string, fileName string) (string, error) {
|
|
if WhatsAppClient[jid] != nil {
|
|
var err error
|
|
|
|
// Make Sure WhatsApp Client is OK
|
|
err = WhatsAppClientIsOK(jid)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Check if Remote JID is Registered and
|
|
// Compose New Remote JID
|
|
remoteJID, err := WhatsAppComposeJID(jid, rjid)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Set Chat Presence
|
|
WhatsAppComposeStatus(jid, remoteJID, true, false)
|
|
defer WhatsAppComposeStatus(jid, remoteJID, false, false)
|
|
|
|
// Upload File to WhatsApp Storage Server
|
|
fileUploaded, err := WhatsAppClient[jid].Upload(context.Background(), fileBytes, whatsmeow.MediaDocument)
|
|
if err != nil {
|
|
return "", errors.New("Error While Uploading Media to WhatsApp Server")
|
|
}
|
|
|
|
// Compose WhatsApp Proto
|
|
msgId := whatsmeow.GenerateMessageID()
|
|
msgContent := &waproto.Message{
|
|
DocumentMessage: &waproto.DocumentMessage{
|
|
Url: proto.String(fileUploaded.URL),
|
|
DirectPath: proto.String(fileUploaded.DirectPath),
|
|
Mimetype: proto.String(fileType),
|
|
Title: proto.String(fileName),
|
|
FileName: proto.String(fileName),
|
|
FileLength: proto.Uint64(fileUploaded.FileLength),
|
|
FileSha256: fileUploaded.FileSHA256,
|
|
FileEncSha256: fileUploaded.FileEncSHA256,
|
|
MediaKey: fileUploaded.MediaKey,
|
|
},
|
|
}
|
|
|
|
// Send WhatsApp Message Proto
|
|
_, err = WhatsAppClient[jid].SendMessage(remoteJID, msgId, msgContent)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return msgId, nil
|
|
}
|
|
|
|
// Return Error WhatsApp Client is not Valid
|
|
return "", errors.New("WhatsApp Client is not Valid")
|
|
}
|
|
|
|
func WhatsAppSendImage(jid string, rjid string, imageBytes []byte, imageType string, imageCaption string, isViewOnce bool) (string, error) {
|
|
if WhatsAppClient[jid] != nil {
|
|
var err error
|
|
|
|
// Make Sure WhatsApp Client is OK
|
|
err = WhatsAppClientIsOK(jid)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Check if Remote JID is Registered and
|
|
// Compose New Remote JID
|
|
remoteJID, err := WhatsAppComposeJID(jid, rjid)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Set Chat Presence
|
|
WhatsAppComposeStatus(jid, remoteJID, true, false)
|
|
defer WhatsAppComposeStatus(jid, remoteJID, false, false)
|
|
|
|
// Issue #7 Old Version Client Cannot Render WebP Format
|
|
// If MIME Type is "image/webp" Then Convert it as PNG
|
|
isWhatsAppImageConvertWebP, err := env.GetEnvBool("WHATSAPP_MEDIA_IMAGE_CONVERT_WEBP")
|
|
if err != nil {
|
|
isWhatsAppImageConvertWebP = false
|
|
}
|
|
|
|
if imageType == "image/webp" && isWhatsAppImageConvertWebP {
|
|
imgConvDecode, err := imgconv.Decode(bytes.NewReader(imageBytes))
|
|
if err != nil {
|
|
return "", errors.New("Error While Decoding Convert Image Stream")
|
|
}
|
|
|
|
imgConvEncode := new(bytes.Buffer)
|
|
|
|
err = imgconv.Write(imgConvEncode, imgConvDecode, imgconv.FormatOption{Format: imgconv.PNG})
|
|
if err != nil {
|
|
return "", errors.New("Error While Encoding Convert Image Stream")
|
|
}
|
|
|
|
imageBytes = imgConvEncode.Bytes()
|
|
imageType = "image/png"
|
|
}
|
|
|
|
// If WhatsApp Media Compression Enabled
|
|
// Then Resize The Image to Width 1024px and Preserve Aspect Ratio
|
|
isWhatsAppImageCompression, err := env.GetEnvBool("WHATSAPP_MEDIA_IMAGE_COMPRESSION")
|
|
if err != nil {
|
|
isWhatsAppImageCompression = false
|
|
}
|
|
|
|
if isWhatsAppImageCompression {
|
|
imgResizeDecode, err := imgconv.Decode(bytes.NewReader(imageBytes))
|
|
if err != nil {
|
|
return "", errors.New("Error While Decoding Resize Image Stream")
|
|
}
|
|
|
|
imgResizeEncode := new(bytes.Buffer)
|
|
|
|
err = imgconv.Write(imgResizeEncode,
|
|
imgconv.Resize(imgResizeDecode, imgconv.ResizeOption{Width: 1024}),
|
|
imgconv.FormatOption{})
|
|
|
|
if err != nil {
|
|
return "", errors.New("Error While Encoding Resize Image Stream")
|
|
}
|
|
|
|
imageBytes = imgResizeEncode.Bytes()
|
|
}
|
|
|
|
// Creating Image JPEG Thumbnail
|
|
// With Permanent Width 640px and Preserve Aspect Ratio
|
|
imgThumbDecode, err := imgconv.Decode(bytes.NewReader(imageBytes))
|
|
if err != nil {
|
|
return "", errors.New("Error While Decoding Thumbnail Image Stream")
|
|
}
|
|
|
|
imgThumbEncode := new(bytes.Buffer)
|
|
|
|
err = imgconv.Write(imgThumbEncode,
|
|
imgconv.Resize(imgThumbDecode, imgconv.ResizeOption{Width: 640}),
|
|
imgconv.FormatOption{Format: imgconv.JPEG})
|
|
|
|
if err != nil {
|
|
return "", errors.New("Error While Encoding Thumbnail Image Stream")
|
|
}
|
|
|
|
// Upload Image to WhatsApp Storage Server
|
|
imageUploaded, err := WhatsAppClient[jid].Upload(context.Background(), imageBytes, whatsmeow.MediaImage)
|
|
if err != nil {
|
|
return "", errors.New("Error While Uploading Media to WhatsApp Server")
|
|
}
|
|
|
|
// Compose WhatsApp Proto
|
|
msgId := whatsmeow.GenerateMessageID()
|
|
msgContent := &waproto.Message{
|
|
ImageMessage: &waproto.ImageMessage{
|
|
Url: proto.String(imageUploaded.URL),
|
|
DirectPath: proto.String(imageUploaded.DirectPath),
|
|
Mimetype: proto.String(imageType),
|
|
Caption: proto.String(imageCaption),
|
|
FileLength: proto.Uint64(imageUploaded.FileLength),
|
|
FileSha256: imageUploaded.FileSHA256,
|
|
FileEncSha256: imageUploaded.FileEncSHA256,
|
|
MediaKey: imageUploaded.MediaKey,
|
|
JpegThumbnail: imgThumbEncode.Bytes(),
|
|
ViewOnce: proto.Bool(isViewOnce),
|
|
},
|
|
}
|
|
|
|
// Send WhatsApp Message Proto
|
|
_, err = WhatsAppClient[jid].SendMessage(remoteJID, msgId, msgContent)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return msgId, nil
|
|
}
|
|
|
|
// Return Error WhatsApp Client is not Valid
|
|
return "", errors.New("WhatsApp Client is not Valid")
|
|
}
|
|
|
|
func WhatsAppSendAudio(jid string, rjid string, audioBytes []byte, audioType string) (string, error) {
|
|
if WhatsAppClient[jid] != nil {
|
|
var err error
|
|
|
|
// Make Sure WhatsApp Client is OK
|
|
err = WhatsAppClientIsOK(jid)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Check if Remote JID is Registered and
|
|
// Compose New Remote JID
|
|
remoteJID, err := WhatsAppComposeJID(jid, rjid)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Set Chat Presence
|
|
WhatsAppComposeStatus(jid, remoteJID, true, true)
|
|
defer WhatsAppComposeStatus(jid, remoteJID, false, true)
|
|
|
|
// Upload Audio to WhatsApp Storage Server
|
|
audioUploaded, err := WhatsAppClient[jid].Upload(context.Background(), audioBytes, whatsmeow.MediaAudio)
|
|
if err != nil {
|
|
return "", errors.New("Error While Uploading Media to WhatsApp Server")
|
|
}
|
|
|
|
// Compose WhatsApp Proto
|
|
msgId := whatsmeow.GenerateMessageID()
|
|
msgContent := &waproto.Message{
|
|
AudioMessage: &waproto.AudioMessage{
|
|
Url: proto.String(audioUploaded.URL),
|
|
DirectPath: proto.String(audioUploaded.DirectPath),
|
|
Mimetype: proto.String(audioType),
|
|
FileLength: proto.Uint64(audioUploaded.FileLength),
|
|
FileSha256: audioUploaded.FileSHA256,
|
|
FileEncSha256: audioUploaded.FileEncSHA256,
|
|
MediaKey: audioUploaded.MediaKey,
|
|
},
|
|
}
|
|
|
|
// Send WhatsApp Message Proto
|
|
_, err = WhatsAppClient[jid].SendMessage(remoteJID, msgId, msgContent)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return msgId, nil
|
|
}
|
|
|
|
// Return Error WhatsApp Client is not Valid
|
|
return "", errors.New("WhatsApp Client is not Valid")
|
|
}
|
|
|
|
func WhatsAppSendVideo(jid string, rjid string, videoBytes []byte, videoType string, videoCaption string, isViewOnce bool) (string, error) {
|
|
if WhatsAppClient[jid] != nil {
|
|
var err error
|
|
|
|
// Make Sure WhatsApp Client is OK
|
|
err = WhatsAppClientIsOK(jid)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Check if Remote JID is Registered and
|
|
// Compose New Remote JID
|
|
remoteJID, err := WhatsAppComposeJID(jid, rjid)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Set Chat Presence
|
|
WhatsAppComposeStatus(jid, remoteJID, true, false)
|
|
defer WhatsAppComposeStatus(jid, remoteJID, false, false)
|
|
|
|
// Upload Video to WhatsApp Storage Server
|
|
videoUploaded, err := WhatsAppClient[jid].Upload(context.Background(), videoBytes, whatsmeow.MediaVideo)
|
|
if err != nil {
|
|
return "", errors.New("Error While Uploading Media to WhatsApp Server")
|
|
}
|
|
|
|
// Compose WhatsApp Proto
|
|
msgId := whatsmeow.GenerateMessageID()
|
|
msgContent := &waproto.Message{
|
|
VideoMessage: &waproto.VideoMessage{
|
|
Url: proto.String(videoUploaded.URL),
|
|
DirectPath: proto.String(videoUploaded.DirectPath),
|
|
Mimetype: proto.String(videoType),
|
|
Caption: proto.String(videoCaption),
|
|
FileLength: proto.Uint64(videoUploaded.FileLength),
|
|
FileSha256: videoUploaded.FileSHA256,
|
|
FileEncSha256: videoUploaded.FileEncSHA256,
|
|
MediaKey: videoUploaded.MediaKey,
|
|
ViewOnce: proto.Bool(isViewOnce),
|
|
},
|
|
}
|
|
|
|
// Send WhatsApp Message Proto
|
|
_, err = WhatsAppClient[jid].SendMessage(remoteJID, msgId, msgContent)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return msgId, nil
|
|
}
|
|
|
|
// Return Error WhatsApp Client is not Valid
|
|
return "", errors.New("WhatsApp Client is not Valid")
|
|
}
|
|
|
|
func WhatsAppSendContact(jid string, rjid string, contactName string, contactNumber string) (string, error) {
|
|
if WhatsAppClient[jid] != nil {
|
|
var err error
|
|
|
|
// Make Sure WhatsApp Client is OK
|
|
err = WhatsAppClientIsOK(jid)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Check if Remote JID is Registered and
|
|
// Compose New Remote JID
|
|
remoteJID, err := WhatsAppComposeJID(jid, rjid)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Set Chat Presence
|
|
WhatsAppComposeStatus(jid, remoteJID, true, false)
|
|
defer WhatsAppComposeStatus(jid, remoteJID, false, false)
|
|
|
|
// Compose WhatsApp Proto
|
|
msgId := whatsmeow.GenerateMessageID()
|
|
msgVCard := fmt.Sprintf("BEGIN:VCARD\nVERSION:3.0\nN:;%v;;;\nFN:%v\nTEL;type=CELL;waid=%v:+%v\nEND:VCARD",
|
|
contactName, contactName, contactNumber, contactNumber)
|
|
msgContent := &waproto.Message{
|
|
ContactMessage: &waproto.ContactMessage{
|
|
DisplayName: proto.String(contactName),
|
|
Vcard: proto.String(msgVCard),
|
|
},
|
|
}
|
|
|
|
// Send WhatsApp Message Proto
|
|
_, err = WhatsAppClient[jid].SendMessage(remoteJID, msgId, msgContent)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return msgId, nil
|
|
}
|
|
|
|
// Return Error WhatsApp Client is not Valid
|
|
return "", errors.New("WhatsApp Client is not Valid")
|
|
}
|
|
|
|
func WhatsAppSendLink(jid string, rjid string, linkCaption string, linkURL string) (string, error) {
|
|
if WhatsAppClient[jid] != nil {
|
|
var err error
|
|
|
|
// Make Sure WhatsApp Client is OK
|
|
err = WhatsAppClientIsOK(jid)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Check if Remote JID is Registered and
|
|
// Compose New Remote JID
|
|
remoteJID, err := WhatsAppComposeJID(jid, rjid)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Set Chat Presence
|
|
WhatsAppComposeStatus(jid, remoteJID, true, false)
|
|
defer WhatsAppComposeStatus(jid, remoteJID, false, false)
|
|
|
|
// Compose WhatsApp Proto
|
|
msgId := whatsmeow.GenerateMessageID()
|
|
msgCaption := "Open Link"
|
|
msgText := linkURL
|
|
|
|
if len(strings.TrimSpace(linkCaption)) > 0 {
|
|
msgCaption = linkCaption
|
|
msgText = fmt.Sprintf("%s\n%s", linkCaption, linkURL)
|
|
}
|
|
|
|
msgContent := &waproto.Message{
|
|
ExtendedTextMessage: &waproto.ExtendedTextMessage{
|
|
Text: proto.String(msgText),
|
|
CanonicalUrl: proto.String(linkURL),
|
|
ContextInfo: &waproto.ContextInfo{
|
|
ActionLink: &waproto.ActionLink{
|
|
Url: proto.String(linkURL),
|
|
ButtonTitle: proto.String(msgCaption),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
// Send WhatsApp Message Proto
|
|
_, err = WhatsAppClient[jid].SendMessage(remoteJID, msgId, msgContent)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return msgId, nil
|
|
}
|
|
|
|
// Return Error WhatsApp Client is not Valid
|
|
return "", errors.New("WhatsApp Client is not Valid")
|
|
}
|
|
|
|
func WhatsAppSendSticker(jid string, rjid string, stickerBytes []byte) (string, error) {
|
|
if WhatsAppClient[jid] != nil {
|
|
var err error
|
|
|
|
// Make Sure WhatsApp Client is OK
|
|
err = WhatsAppClientIsOK(jid)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Check if Remote JID is Registered and
|
|
// Compose New Remote JID
|
|
remoteJID, err := WhatsAppComposeJID(jid, rjid)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Set Chat Presence
|
|
WhatsAppComposeStatus(jid, remoteJID, true, false)
|
|
defer WhatsAppComposeStatus(jid, remoteJID, false, false)
|
|
|
|
stickerConvDecode, err := imgconv.Decode(bytes.NewReader(stickerBytes))
|
|
if err != nil {
|
|
return "", errors.New("Error While Decoding Convert Sticker Stream")
|
|
}
|
|
|
|
stickerConvResize := imgconv.Resize(stickerConvDecode, imgconv.ResizeOption{Width: 512, Height: 512})
|
|
stickerConvEncode := new(bytes.Buffer)
|
|
|
|
err = webp.Encode(stickerConvEncode, stickerConvResize)
|
|
if err != nil {
|
|
return "", errors.New("Error While Encoding Convert Sticker Stream")
|
|
}
|
|
|
|
stickerBytes = stickerConvEncode.Bytes()
|
|
|
|
// Upload Image to WhatsApp Storage Server
|
|
stickerUploaded, err := WhatsAppClient[jid].Upload(context.Background(), stickerBytes, whatsmeow.MediaImage)
|
|
if err != nil {
|
|
return "", errors.New("Error While Uploading Media to WhatsApp Server")
|
|
}
|
|
|
|
// Compose WhatsApp Proto
|
|
msgId := whatsmeow.GenerateMessageID()
|
|
msgContent := &waproto.Message{
|
|
StickerMessage: &waproto.StickerMessage{
|
|
Url: proto.String(stickerUploaded.URL),
|
|
DirectPath: proto.String(stickerUploaded.DirectPath),
|
|
Mimetype: proto.String("image/webp"),
|
|
FileLength: proto.Uint64(stickerUploaded.FileLength),
|
|
FileSha256: stickerUploaded.FileSHA256,
|
|
FileEncSha256: stickerUploaded.FileEncSHA256,
|
|
MediaKey: stickerUploaded.MediaKey,
|
|
},
|
|
}
|
|
|
|
// Send WhatsApp Message Proto
|
|
_, err = WhatsAppClient[jid].SendMessage(remoteJID, msgId, msgContent)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return msgId, nil
|
|
}
|
|
|
|
// Return Error WhatsApp Client is not Valid
|
|
return "", errors.New("WhatsApp Client is not Valid")
|
|
}
|