@juzi/wechaty-puppet-whatsapp
Version:
Wechaty Puppet for WhatsApp
437 lines • 21.8 kB
JavaScript
;
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