UNPKG

@juzi/wechaty-puppet-whatsapp

Version:
437 lines 21.8 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.messageRawPayloadParser = exports.messageRawPayload = exports.messageForward = exports.messageLocation = exports.messageSendLocation = exports.messageSendChannel = exports.messageSendMiniProgram = exports.messageSendUrl = exports.messageSendContact = exports.messageSendFile = exports.messageSendText = exports.messageSend = exports.messageChannel = exports.messageMiniProgram = exports.messageUrl = exports.messageFile = exports.messageImage = exports.messagePost = exports.messageRecall = exports.messageContact = void 0; const PUPPET = __importStar(require("@juzi/wechaty-puppet")); const path = __importStar(require("path")); const mime_1 = __importDefault(require("mime")); const whatsapp_interface_js_1 = require("../schema/whatsapp-interface.js"); const error_type_js_1 = require("../exception/error-type.js"); const whatsapp_error_js_1 = __importDefault(require("../exception/whatsapp-error.js")); const config_js_1 = require("../config.js"); const convert_function_js_1 = require("../helper/pure-function/convert-function.js"); const message_raw_payload_parser_js_1 = require("../helper/pure-function/message-raw-payload-parser.js"); const vcard_parser_js_1 = require("../helper/pure-function/vcard-parser.js"); const request_pool_js_1 = require("../request/request-pool.js"); const messageMedia_js_1 = require("../helper/pure-function/messageMedia.js"); const PRE = 'MIXIN_MESSAGE'; /** * Get contact message * @param messageId message Id * @returns contact name */ async function messageContact(messageId) { config_js_1.log.verbose(PRE, 'messageContact(%s)', messageId); const cacheManager = await this.manager.getCacheManager(); const msg = await cacheManager.getMessageRawPayload(messageId); if (!msg) { config_js_1.log.error(PRE, 'Message %s not found', messageId); throw (0, whatsapp_error_js_1.default)(error_type_js_1.WA_ERROR_TYPE.ERR_MSG_NOT_FOUND, `Message ${messageId} not found`); } if (msg.type !== whatsapp_interface_js_1.MessageTypes.CONTACT_CARD) { config_js_1.log.error(PRE, 'Message %s is not contact type', messageId); throw (0, whatsapp_error_js_1.default)(error_type_js_1.WA_ERROR_TYPE.ERR_MSG_NOT_MATCH, `Message ${messageId} is not contact type`); } if (!msg.vCards[0]) { throw (0, whatsapp_error_js_1.default)(error_type_js_1.WA_ERROR_TYPE.ERR_MSG_NOT_MATCH, `Message ${messageId} has no vCards info, detail: ${JSON.stringify(msg)}`); } try { const vcard = (0, vcard_parser_js_1.parseVcard)(msg.vCards[0]); return vcard.TEL[0].waid; } catch (error) { throw (0, whatsapp_error_js_1.default)(error_type_js_1.WA_ERROR_TYPE.ERR_MSG_CONTACT, `Can not parse contact card from message: ${messageId}, error: ${error.message}`); } } exports.messageContact = messageContact; /** * Recall message * @param messageId message id * @returns { Promise<boolean> } */ async function messageRecall(messageId) { config_js_1.log.verbose(PRE, 'messageRecall(%s)', messageId); const cacheManager = await this.manager.getCacheManager(); const msg = await cacheManager.getMessageRawPayload(messageId); if (!msg) { config_js_1.log.error(PRE, 'Message %s not found', messageId); throw (0, whatsapp_error_js_1.default)(error_type_js_1.WA_ERROR_TYPE.ERR_MSG_NOT_FOUND, `Message ${messageId} not found`); } const msgObj = (0, convert_function_js_1.convertMessagePayloadToClass)(this.manager.getWhatsAppClient(), msg); try { await msgObj.delete(true); return true; } catch (err) { config_js_1.log.error(PRE, `Can not recall this message: ${messageId}, error: ${err.message}`); return false; } } exports.messageRecall = messageRecall; /** * Get moment detail image or video from message * @param messageId message id * @param imageType image size to get (may not apply to WhatsApp) * @returns the image or video */ async function messagePost(messageId, imageType) { config_js_1.log.verbose(PRE, 'messagePost(%s, %s)', messageId, PUPPET.types.Image[imageType]); const cacheManager = await this.manager.getCacheManager(); const msg = await cacheManager.getMessageRawPayload(messageId); if (!msg) { config_js_1.log.error(PRE, 'Message %s not found', messageId); throw (0, whatsapp_error_js_1.default)(error_type_js_1.WA_ERROR_TYPE.ERR_MSG_NOT_FOUND, `Message ${messageId} Not Found`); } if (!msg.hasMedia) { config_js_1.log.error(PRE, 'Message %s does not contain any media', messageId); throw (0, whatsapp_error_js_1.default)(error_type_js_1.WA_ERROR_TYPE.ERR_MSG_NOT_MATCH, `Message ${messageId} does not contain any media`); } if (msg.type === whatsapp_interface_js_1.MessageTypes.IMAGE) { return this.messageImage(messageId, imageType); } else if (msg.type === whatsapp_interface_js_1.MessageTypes.VIDEO) { return this.messageFile(messageId); } else { throw (0, whatsapp_error_js_1.default)(error_type_js_1.WA_ERROR_TYPE.ERR_MSG_NOT_MATCH, `Post message ${messageId} with wrong message type: ${msg.type}`); } } exports.messagePost = messagePost; /** * Get image from message * @param messageId message id * @param imageType image size to get (may not apply to WhatsApp) * @returns the image */ async function messageImage(messageId, imageType) { config_js_1.log.verbose(PRE, 'messageImage(%s, %s)', messageId, PUPPET.types.Image[imageType]); const cacheManager = await this.manager.getCacheManager(); const msg = await cacheManager.getMessageRawPayload(messageId); if (!msg) { config_js_1.log.error(PRE, 'Message %s not found', messageId); throw (0, whatsapp_error_js_1.default)(error_type_js_1.WA_ERROR_TYPE.ERR_MSG_NOT_FOUND, `Message ${messageId} Not Found`); } if (msg.type !== whatsapp_interface_js_1.MessageTypes.IMAGE || (!msg.hasMedia && !msg.body)) { config_js_1.log.error(PRE, 'Message %s does not contain any media', messageId); throw (0, whatsapp_error_js_1.default)(error_type_js_1.WA_ERROR_TYPE.ERR_MSG_NOT_MATCH, `Message ${messageId} does not contain any media`); } try { switch (imageType) { case PUPPET.types.Image.HD: case PUPPET.types.Image.Artwork: if (msg.hasMedia) { return downloadMedia.call(this, msg); } else { return config_js_1.FileBox.fromBase64(msg._data.body, 'thumbnail.jpg'); } case PUPPET.types.Image.Thumbnail: default: if (msg._data.body) { return config_js_1.FileBox.fromBase64(msg._data.body, 'thumbnail.jpg'); } else { return downloadMedia.call(this, msg); } } } catch (error) { throw (0, whatsapp_error_js_1.default)(error_type_js_1.WA_ERROR_TYPE.ERR_MSG_IMAGE, `Message ${messageId} does not contain any media`); } } exports.messageImage = messageImage; /** * Get the file attached to the message * @param messageId message id * @returns the file that attached to the message */ async function messageFile(messageId) { config_js_1.log.verbose(PRE, 'messageFile(%s)', messageId); const cacheManager = await this.manager.getCacheManager(); const msg = await cacheManager.getMessageRawPayload(messageId); if (!msg) { config_js_1.log.error(PRE, 'Message %s not found', messageId); throw (0, whatsapp_error_js_1.default)(error_type_js_1.WA_ERROR_TYPE.ERR_MSG_NOT_FOUND, `Message ${messageId} Not Found`); } if (!msg.hasMedia) { config_js_1.log.error(PRE, 'Message %s does not contain any media', messageId); throw (0, whatsapp_error_js_1.default)(error_type_js_1.WA_ERROR_TYPE.ERR_MSG_NOT_MATCH, `Message ${messageId} does not contain any media`); } try { return downloadMedia.call(this, msg); } catch (error) { throw (0, whatsapp_error_js_1.default)(error_type_js_1.WA_ERROR_TYPE.ERR_MSG_FILE, `Message ${messageId} does not contain any media`); } } exports.messageFile = messageFile; async function downloadMedia(msg) { const msgObj = (0, convert_function_js_1.convertMessagePayloadToClass)(this.manager.getWhatsAppClient(), msg); const media = await msgObj.downloadMedia(); const filenameExtension = mime_1.default.getExtension(media.mimetype); const fileBox = config_js_1.FileBox.fromBase64(media.data, media.filename ?? `unknown_name.${filenameExtension}`); fileBox.mimeType = media.mimetype; return fileBox; } /** * Get url in the message * @param messageId message id * @returns url in the message */ async function messageUrl(messageId) { config_js_1.log.verbose(PRE, 'messageUrl(%s)', messageId); const cacheManager = await this.manager.getCacheManager(); const msg = await cacheManager.getMessageRawPayload(messageId); if (!msg) { config_js_1.log.error(PRE, 'Message %s not found', messageId); throw (0, whatsapp_error_js_1.default)(error_type_js_1.WA_ERROR_TYPE.ERR_MSG_NOT_FOUND, `Message ${messageId} Not Found`); } if (!msg.urlLink) { config_js_1.log.error(PRE, 'Message %s is does not contain links', messageId); throw (0, whatsapp_error_js_1.default)(error_type_js_1.WA_ERROR_TYPE.ERR_MSG_NOT_MATCH, `Message ${messageId} does not contain any link message.`); } try { const thumbnail = config_js_1.FileBox.fromBase64(msg._data.thumbnail, 'thumbnail.jpg'); return { description: msg.urlLink.description || 'no description', title: msg.urlLink.title || 'no title', url: msg.urlLink.url || 'no url', thumbnailFileBox: thumbnail, }; } catch (error) { throw (0, whatsapp_error_js_1.default)(error_type_js_1.WA_ERROR_TYPE.ERR_MSG_URL_LINK, `Get link message: ${messageId} failed, error: ${error.message}`); } } exports.messageUrl = messageUrl; /** * Not supported for WhatsApp * @param messageId message id */ async function messageMiniProgram(messageId) { config_js_1.log.verbose(PRE, 'messageMiniProgram(%s)', messageId); const cacheManager = await this.manager.getCacheManager(); const msg = await cacheManager.getMessageRawPayload(messageId); if (!msg) { config_js_1.log.error(PRE, 'Message %s not found', messageId); throw (0, whatsapp_error_js_1.default)(error_type_js_1.WA_ERROR_TYPE.ERR_MSG_NOT_FOUND, `Message ${messageId} Not Found`); } if (!msg.productMessage) { config_js_1.log.error(PRE, 'Message %s is does not contain mini program', messageId); throw (0, whatsapp_error_js_1.default)(error_type_js_1.WA_ERROR_TYPE.ERR_MSG_NOT_MATCH, `Message ${messageId} does not contain any mini program.`); } try { const thumbnail = await downloadMedia.call(this, msg); return { username: msg.productMessage.businessOwnerJid, appid: msg.productMessage.productId, title: msg.productMessage.title || 'no title', description: msg.productMessage.description || 'no description', thumbnailFileBox: thumbnail, }; } catch (error) { throw (0, whatsapp_error_js_1.default)(error_type_js_1.WA_ERROR_TYPE.ERR_MSG_MINI_PROGRAM, `Get miniprogram message: ${messageId} failed, error: ${error.message}`); } } exports.messageMiniProgram = messageMiniProgram; async function messageChannel(messageId) { config_js_1.log.verbose(PRE, 'messageChannel(%s)', messageId); return PUPPET.throwUnsupportedError(); } exports.messageChannel = messageChannel; async function messageSend(conversationId, content, options, timeout = config_js_1.DEFAULT_TIMEOUT.MESSAGE_SEND) { config_js_1.log.info(PRE, 'messageSend(%s, %s)', conversationId, JSON.stringify(options)); void timeout; void request_pool_js_1.RequestPool; const msg = await this.manager.sendMessage(conversationId, content, options); if (msg.ack >= 0) { const cacheManager = await this.manager.getCacheManager(); await cacheManager.setMessageRawPayload(msg.id.id, msg); return msg.id.id; } else { config_js_1.log.error(PRE, 'messageSend failed, id: %s, ack: %s, detail: %s', msg.id.id, msg.ack, JSON.stringify(msg)); throw (0, whatsapp_error_js_1.default)(error_type_js_1.WA_ERROR_TYPE.ERR_SEND_MSG, `Message send failed, id: ${msg.id.id}, ack: ${msg.ack}, detail: ${JSON.stringify(msg)}`); } // const messageId = msg.id.id // const requestPool = RequestPool.Instance // await requestPool.pushRequest(messageId, timeout) // return messageId } exports.messageSend = messageSend; async function messageSendText(conversationId, text, options = {}) { config_js_1.log.info(PRE, 'messageSendText(%s, %s, %s)', conversationId, text, JSON.stringify(options)); let mentions = []; let quoteId; if (Array.isArray(options)) { mentions = options; } else { mentions = options.mentionIdList || []; quoteId = options.quoteId; } const waMessageSendOptions = {}; if (mentions.length > 0) { waMessageSendOptions.mentions = mentions; } if (quoteId) { const quotedMessage = await this.messageRawPayload(quoteId); waMessageSendOptions.quotedMessageId = quotedMessage.id._serialized; } return messageSend.call(this, conversationId, text, waMessageSendOptions, config_js_1.DEFAULT_TIMEOUT.MESSAGE_SEND_TEXT); } exports.messageSendText = messageSendText; async function messageSendFile(conversationId, file, options = {}) { await file.ready(); const type = (file.mediaType && file.mediaType !== 'application/octet-stream') ? file.mediaType.replace(/;.*$/, '') : path.extname(file.name); config_js_1.log.info(PRE, `messageSendFile(${conversationId}, ${JSON.stringify(file.toJSON())}) type: ${type}, filename: ${file.name}`); const fileBoxJsonObject = file.toJSON(); // FIXME: need import FileBoxJsonObject from file-box const remoteUrl = fileBoxJsonObject.url; let msgContent; if (remoteUrl) { msgContent = await whatsapp_interface_js_1.MessageMedia.fromUrl(remoteUrl, { filename: file.name }); } else { const fileData = await file.toBase64(); msgContent = new whatsapp_interface_js_1.MessageMedia(file.mediaType, fileData, file.name); } if (/^mpeg\//.test(type) || /^audio\//.test(type)) { options.sendAudioAsVoice = true; } return messageSend.call(this, conversationId, msgContent, options, config_js_1.DEFAULT_TIMEOUT.MESSAGE_SEND_FILE); } exports.messageSendFile = messageSendFile; async function messageSendContact(conversationId, contactId, options) { config_js_1.log.verbose(PRE, 'messageSendContact(%s, %s)', conversationId, contactId); const contact = await this.manager.getContactById(contactId); await messageSend.call(this, conversationId, contact, options, config_js_1.DEFAULT_TIMEOUT.MESSAGE_SEND_TEXT); } exports.messageSendContact = messageSendContact; async function messageSendUrl(conversationId, urlLinkPayload) { config_js_1.log.verbose(PRE, 'messageSendUrl(%s, %s)', conversationId, JSON.stringify(urlLinkPayload)); let media; if (urlLinkPayload.thumbnailUrl) { media = await whatsapp_interface_js_1.MessageMedia.fromUrl(urlLinkPayload.thumbnailUrl); } else if (urlLinkPayload.thumbnailFileBox) { media = await (0, messageMedia_js_1.getMessageMediaFromFilebox)(urlLinkPayload.thumbnailFileBox); } const urlLink = new whatsapp_interface_js_1.UrlLink(urlLinkPayload.url, urlLinkPayload.title, urlLinkPayload.description, media); return messageSend.call(this, conversationId, urlLink, {}, config_js_1.DEFAULT_TIMEOUT.MESSAGE_SEND_TEXT); } exports.messageSendUrl = messageSendUrl; async function messageSendMiniProgram(conversationId, miniProgramPayload) { config_js_1.log.verbose(PRE, 'messageSendMiniProgram(%s, %s)', conversationId, JSON.stringify(miniProgramPayload)); if (!miniProgramPayload.username || !miniProgramPayload.appid) { throw new Error('a miniProgramPayload must have username and appid'); } let media; if (miniProgramPayload.thumbUrl) { media = await whatsapp_interface_js_1.MessageMedia.fromUrl(miniProgramPayload.thumbUrl); } else if (miniProgramPayload.thumbnailFileBox) { media = await (0, messageMedia_js_1.getMessageMediaFromFilebox)(miniProgramPayload.thumbnailFileBox); } const productMessage = new whatsapp_interface_js_1.ProductMessage(miniProgramPayload.username, miniProgramPayload.appid, miniProgramPayload.title, miniProgramPayload.description, media); return messageSend.call(this, conversationId, productMessage, {}, config_js_1.DEFAULT_TIMEOUT.MESSAGE_SEND_TEXT); } exports.messageSendMiniProgram = messageSendMiniProgram; async function messageSendChannel(conversationId, channelPayload) { config_js_1.log.verbose(PRE, 'messageSendChannel(%s, %s)', conversationId, JSON.stringify(channelPayload)); return PUPPET.throwUnsupportedError(); } exports.messageSendChannel = messageSendChannel; async function messageSendLocation(conversationId, locationPayload) { config_js_1.log.verbose(PRE, 'messageSendLocation(%s, %s)', conversationId, JSON.stringify(locationPayload)); // throw PUPPET.throwUnsupportedError() const location = new whatsapp_interface_js_1.Location(locationPayload.latitude, locationPayload.longitude, { name: locationPayload.name, address: locationPayload.address, }); return messageSend.call(this, conversationId, location); // can send via whatsapp-web.js, however whatsapp-web itself does not offer location sending, so that the message cannot reach the server } exports.messageSendLocation = messageSendLocation; async function messageLocation(messageId) { config_js_1.log.verbose(PRE, 'messageLocation(%s)', messageId); const msg = await this.messageRawPayload(messageId); if (msg.type !== whatsapp_interface_js_1.MessageTypes.LOCATION) { throw (0, whatsapp_error_js_1.default)(error_type_js_1.WA_ERROR_TYPE.ERR_MSG_NOT_MATCH, `Message ${messageId} is not a location message`); } return { accuracy: 15, address: msg.location?.address?.split('\n')[1] || '', latitude: Number(msg.location?.latitude || 0), longitude: Number(msg.location?.longitude || 0), name: msg.location?.name?.split('\n')[0] || '', }; } exports.messageLocation = messageLocation; async function messageForward(conversationId, messageId) { config_js_1.log.verbose(PRE, 'messageForward(%s, %s)', conversationId, messageId); const cacheManager = await this.manager.getCacheManager(); const msg = await cacheManager.getMessageRawPayload(messageId); if (!msg) { config_js_1.log.error(PRE, 'Message %s not found', messageId); throw (0, whatsapp_error_js_1.default)(error_type_js_1.WA_ERROR_TYPE.ERR_MSG_NOT_FOUND, `Message ${messageId} not found`); } const msgObj = (0, convert_function_js_1.convertMessagePayloadToClass)(this.manager.getWhatsAppClient(), msg); try { await msgObj.forward(conversationId); } catch (error) { throw (0, whatsapp_error_js_1.default)(error_type_js_1.WA_ERROR_TYPE.ERR_MSG_FORWARD, `Forward message: ${messageId} failed, error: ${error.message}`); } } exports.messageForward = messageForward; async function messageRawPayload(id) { config_js_1.log.verbose(PRE, 'messageRawPayload(%s)', id); const cacheManager = await this.manager.getCacheManager(); let msg = await cacheManager.getMessageRawPayload(id); if (msg) { return msg; } msg = await this.manager.getMessageWithId(id); if (msg) { msg.timestamp = Date.now(); await cacheManager.setMessageRawPayload(id, msg); return msg; } throw (0, whatsapp_error_js_1.default)(error_type_js_1.WA_ERROR_TYPE.ERR_MSG_NOT_FOUND, `Can not find this message: ${id}`); } exports.messageRawPayload = messageRawPayload; async function messageRawPayloadParser(whatsAppPayload) { const result = (0, message_raw_payload_parser_js_1.parserMessageRawPayload)(whatsAppPayload); config_js_1.log.verbose(PRE, 'messageRawPayloadParser whatsAppPayload(%s) result(%s)', JSON.stringify(whatsAppPayload), JSON.stringify(result)); return result; } exports.messageRawPayloadParser = messageRawPayloadParser; //# sourceMappingURL=message.js.map