wechaty-puppet-padplus
Version:
Puppet Padplus for Wechaty
1,053 lines • 52.3 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const util_1 = __importDefault(require("util"));
const path_1 = __importDefault(require("path"));
const file_box_1 = __importDefault(require("file-box"));
const array_flatten_1 = __importDefault(require("array-flatten"));
const wechaty_puppet_1 = require("wechaty-puppet");
const config_1 = require("./config");
const request_queue_1 = require("./padplus-manager/api-request/request-queue");
const padplus_manager_1 = __importDefault(require("./padplus-manager/padplus-manager"));
const schemas_1 = require("./schemas");
const room_convertor_1 = require("./convert-manager/room-convertor");
const room_event_join_message_parser_1 = require("./pure-function-helpers/room-event-join-message-parser");
const room_event_leave_message_parser_1 = require("./pure-function-helpers/room-event-leave-message-parser");
const room_event_topic_message_parser_1 = require("./pure-function-helpers/room-event-topic-message-parser");
const friendship_event_message_parser_1 = require("./pure-function-helpers/friendship-event-message-parser");
const pure_function_helpers_1 = require("./pure-function-helpers");
const contact_raw_payload_parser_1 = require("./pure-function-helpers/contact-raw-payload-parser");
const xml_to_json_1 = require("./pure-function-helpers/xml-to-json");
const PRE = 'PUPPET_PADPLUS';
class PuppetPadplus extends wechaty_puppet_1.Puppet {
constructor(options = {}) {
super(options);
this.options = options;
const token = this.options.token || config_1.padplusToken();
const name = this.options.name;
if (token) {
this.manager = new padplus_manager_1.default({
endpoint: this.options.endpoint || config_1.GRPC_ENDPOINT,
name,
token,
});
}
else {
config_1.log.error(PRE, `can not get token info from options for start grpc gateway.`);
throw new Error(`can not get token info.`);
}
}
start() {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.silly(PRE, `start()`);
this.state.on('pending');
yield this.startManager(this.manager);
this.state.on(true);
});
}
startManager(manager) {
const _super = Object.create(null, {
login: { get: () => super.login }
});
return __awaiter(this, void 0, void 0, function* () {
manager.on('scan', (url, status) => __awaiter(this, void 0, void 0, function* () {
config_1.log.silly(PRE, `scan : ${url}, status: ${status}`);
this.emit('scan', url, status);
}));
manager.on('login', (loginData) => __awaiter(this, void 0, void 0, function* () {
config_1.log.silly(PRE, `login success : ${util_1.default.inspect(loginData)}`);
yield _super.login.call(this, loginData.userName);
yield this.manager.syncContacts();
}));
manager.setMemory(this.memory);
manager.on('message', msg => this.onMessage(msg));
manager.on('ready', () => this.emit('ready'));
manager.on('reset', (reason) => {
this.emit('reset', reason);
});
manager.on('heartbeat', (data) => {
this.emit('watchdog', {
data,
});
});
manager.on('logout', () => this.logout());
manager.on('error', (err) => {
this.emit('error', err);
});
yield manager.start();
});
}
stop() {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.verbose(PRE, 'stop()');
if (!this.manager) {
throw new Error('no padplus manager');
}
if (this.state.off()) {
config_1.log.verbose(PRE, 'stop() is called on a OFF puppet. await ready(off) and return.');
yield this.state.ready('off');
return;
}
this.state.off('pending');
yield this.manager.stop();
yield this.manager.removeAllListeners();
this.state.off(true);
config_1.log.verbose(PRE, `stop() finished`);
});
}
logout() {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.verbose(PRE, 'logout()');
yield this.manager.logout(this.selfId());
this.emit('logout', this.selfId());
this.id = undefined;
this.emit('reset', 'padplus reset');
});
}
onMessage(message) {
return __awaiter(this, void 0, void 0, function* () {
const messageType = message.msgType;
switch (messageType) {
case schemas_1.PadplusMessageType.Sys:
yield Promise.all([
this.onRoomJoinEvent(message),
this.onRoomLeaveEvent(message),
this.onRoomTopicEvent(message),
this.onFriendshipEvent(message),
]);
break;
case schemas_1.PadplusMessageType.VerifyMsg:
yield this.onFriendshipEvent(message);
break;
case schemas_1.PadplusMessageType.Recalled:
this.emit('message', message.msgId);
yield this.onRoomJoinEvent(message);
break;
case schemas_1.PadplusMessageType.Text:
yield this.onFriendshipEvent(message);
this.emit('message', message.msgId);
break;
case schemas_1.PadplusMessageType.Contact:
case schemas_1.PadplusMessageType.Image:
case schemas_1.PadplusMessageType.Deleted:
case schemas_1.PadplusMessageType.Voice:
case schemas_1.PadplusMessageType.SelfAvatar:
case schemas_1.PadplusMessageType.PossibleFriendMsg:
case schemas_1.PadplusMessageType.ShareCard:
case schemas_1.PadplusMessageType.Video:
case schemas_1.PadplusMessageType.Emoticon:
case schemas_1.PadplusMessageType.Location:
case schemas_1.PadplusMessageType.App:
case schemas_1.PadplusMessageType.VoipMsg:
case schemas_1.PadplusMessageType.StatusNotify:
case schemas_1.PadplusMessageType.VoipNotify:
case schemas_1.PadplusMessageType.VoipInvite:
case schemas_1.PadplusMessageType.MicroVideo:
case schemas_1.PadplusMessageType.SelfInfo:
case schemas_1.PadplusMessageType.SysNotice:
case schemas_1.PadplusMessageType.N11_2048:
case schemas_1.PadplusMessageType.N15_32768:
default:
this.emit('message', message.msgId);
break;
}
});
}
/**
* ========================
* CONTACT SECTION
* ========================
*/
contactSelfQrcode() {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.silly(PRE, `contactSelfQrcode()`);
return this.manager.contactSelfQrcode();
});
}
contactSelfName(name) {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.silly(PRE, `contactSelfName(${name})`);
yield this.manager.contactSelfName(name);
});
}
contactSelfSignature(signature) {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.silly(PRE, `contactSelfSignature(${signature})`);
yield this.manager.contactSelfSignature(signature);
});
}
contactSelfInfo() {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.silly(PRE, `contactSelfInfo()`);
return this.manager.contactSelfInfo();
});
}
contactAlias(contactId, alias) {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.silly(PRE, `contactAlias(), contactId: ${contactId}, alias : ${alias}`);
if (typeof alias === 'undefined') {
const payload = yield this.contactPayload(contactId);
return payload.alias || '';
}
if (!this.manager) {
throw new Error(`no padplus manage.`);
}
yield this.manager.setContactAlias(contactId, alias || '');
});
}
contactAvatar(contactId, file) {
return __awaiter(this, void 0, void 0, function* () {
if (file) {
if (contactId !== this.selfId()) {
throw new Error(`can not set avatar for others.`);
}
if (!this.manager) {
throw new Error(`no padplus manager.`);
}
return;
}
const payload = yield this.contactRawPayload(contactId);
if (!payload || !payload.bigHeadUrl) {
throw new Error(`can not find contact.`);
}
const fileBox = file_box_1.default.fromUrl(payload.bigHeadUrl, `wechaty-contact-avatar-${payload.userName}.jpg`);
return fileBox;
});
}
contactList() {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.verbose(PRE, `contactList()`);
if (!this.manager) {
throw new Error(`no padplus manager.`);
}
const selfId = this.selfId();
const contactIds = yield this.manager.getContactIdList(selfId);
return contactIds;
});
}
contactRawPayload(contactId) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.manager) {
throw new Error(`no manager.`);
}
const payload = yield this.manager.getContactPayload(contactId);
return payload;
});
}
contactRawPayloadParser(rawPayload) {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.verbose(PRE, `contactRawPayloadParser()`);
const payload = contact_raw_payload_parser_1.contactRawPayloadParser(rawPayload);
return payload;
});
}
/**
* =========================
* FRIENDSHIP SECTION
* =========================
*/
onFriendshipEvent(message) {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.verbose(PRE, 'onPadplusMessageFriendshipEvent({id=%s})', message.msgId);
/**
* 1. Look for friendship confirm event
*/
const friendshipConfirmContactId = friendship_event_message_parser_1.friendshipConfirmEventMessageParser(message);
/**
* 2. Look for friendship receive event
*/
const friendshipReceiveContactId = yield friendship_event_message_parser_1.friendshipReceiveEventMessageParser(message);
/**
* 3. Look for friendship verify event
*/
const friendshipVerifyContactId = friendship_event_message_parser_1.friendshipVerifyEventMessageParser(message);
if (friendshipConfirmContactId
|| friendshipReceiveContactId
|| friendshipVerifyContactId) {
// Maybe load contact here since we know a new friend is added
if (!this.manager) {
throw new Error(`no manager.`);
}
const friendship = yield pure_function_helpers_1.friendshipRawPayloadParser(message);
if (!friendship) {
config_1.log.silly(PRE, `not friendship : ${message.msgId}`);
return;
}
const { msgId } = message;
yield this.manager.saveFriendship(msgId, friendship);
this.emit('friendship', msgId);
}
});
}
friendshipAdd(contactId, hello) {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.verbose(PRE, `friendshipAdd(${contactId}, ${hello})`);
if (!this.manager) {
throw new Error('no padplus manager');
}
const searchContact = yield this.manager.searchContact(contactId);
/**
* If the contact is not stranger, than using WXSearchContact can get userName
*/
if (searchContact.wxid !== '' && !pure_function_helpers_1.isStrangerV1(searchContact.v1) && !pure_function_helpers_1.isStrangerV2(searchContact.v2)) {
config_1.log.verbose(PRE, `friendshipAdd ${contactId} has been friend with bot, no need to send friend request!`);
return;
}
let strangerV1;
let strangerV2;
if (pure_function_helpers_1.isStrangerV1(searchContact.v1)) {
strangerV1 = searchContact.v1;
strangerV2 = searchContact.v2;
}
else if (pure_function_helpers_1.isStrangerV2(searchContact.v2)) {
strangerV2 = searchContact.v2;
strangerV1 = searchContact.v1;
}
else {
throw new Error('stranger neither v1 nor v2!');
}
const isPhoneNumber = contactId.match(/^[1]([3-9])[0-9]{9}$/);
const res = yield this.manager.addFriend(contactId, hello, isPhoneNumber ? schemas_1.SearchContactTypeStatus.MOBILE : schemas_1.SearchContactTypeStatus.WXID, // default to wxid
strangerV1 || '', strangerV2 || '');
if (res && res.status !== '0') {
throw new Error(`add friend failed.`);
}
else if (res && res.status === '0') {
config_1.log.silly(PRE, `add friend request success.`);
}
});
}
friendshipAccept(friendshipId) {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.verbose(PRE, `friendshipAccept(${friendshipId})`);
if (!this.manager) {
throw new Error(`no manager.`);
}
const payload = yield this.manager.getFriendship(friendshipId);
if (!payload || payload.type !== wechaty_puppet_1.FriendshipType.Receive) {
throw new Error(`friendship type error.`);
}
const { contactId, stranger, ticket } = payload;
if (!stranger || !ticket) {
throw new Error(`friendship data error, stranger or ticket is null.`);
}
yield this.manager.confirmFriendship(contactId, stranger, ticket);
});
}
friendshipRawPayload(friendshipId) {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.silly(PRE, `friendshipId : ${util_1.default.inspect(friendshipId)}`);
if (!this.manager) {
throw new Error(`no manager.`);
}
const payload = yield this.manager.getFriendship(friendshipId);
if (payload) {
return payload;
}
throw new Error(`can not find friendship.`);
});
}
friendshipRawPayloadParser(rawPayload) {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.silly(PRE, `friendship rawPayload : ${util_1.default.inspect(rawPayload)}`);
return rawPayload;
});
}
/**
* ========================
* MESSAGE SECTION
* ========================
*/
messageFile(messageId) {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.silly(PRE, `messageFile() messageId : ${util_1.default.inspect(messageId)}`);
const rawPayload = yield this.messageRawPayload(messageId);
const payload = yield this.messagePayload(messageId);
let filename = payload.filename || payload.id;
const type = payload.type === wechaty_puppet_1.MessageType.Image ? 'img' : payload.type === wechaty_puppet_1.MessageType.Video ? 'video' : 'file';
switch (payload.type) {
case wechaty_puppet_1.MessageType.Image:
case wechaty_puppet_1.MessageType.Attachment:
case wechaty_puppet_1.MessageType.Video:
let content = rawPayload.content;
const mediaData = {
appMsgType: type === 'file' ? 6 : 0,
content,
contentType: type,
createTime: rawPayload.createTime,
fileName: rawPayload.fileName || '',
fromUserName: rawPayload.fromUserName,
msgId: rawPayload.msgId,
msgType: rawPayload.msgType,
src: rawPayload.url,
toUserName: rawPayload.toUserName,
};
const data = yield request_queue_1.RequestQueue.exec(() => this.manager.loadRichMediaData(mediaData));
if (data && data.src) {
const name = path_1.default.parse(data.src).base;
return file_box_1.default.fromUrl(encodeURI(data.src), name);
}
else {
throw new Error(`Can not get media data url by this message id: ${messageId}`);
}
case wechaty_puppet_1.MessageType.Emoticon:
if (rawPayload && rawPayload.url) {
return file_box_1.default.fromUrl(rawPayload.url);
}
else {
throw new Error(`can not get image/audio url fot message id: ${messageId}`);
}
case wechaty_puppet_1.MessageType.Audio:
if (rawPayload && rawPayload.url) {
const fileBox = file_box_1.default.fromUrl(rawPayload.url);
let contentXML;
if (pure_function_helpers_1.isRoomId(rawPayload.fromUserName)) {
contentXML = rawPayload.content.split(':\n')[1];
}
else {
contentXML = rawPayload.content;
}
const content = yield xml_to_json_1.xmlToJson(contentXML);
fileBox.metadata = {
voiceLength: content.msg.voicemsg.$.voicelength / 1000,
};
return fileBox;
}
else {
throw new Error(`can not get image/audio url fot message id: ${messageId}`);
}
default:
const base64 = 'Tm90IFN1cHBvcnRlZCBBdHRhY2htZW50IEZpbGUgVHlwZSBpbiBNZXNzYWdlLgpTZWU6IGh0dHBzOi8vZ2l0aHViLmNvbS9DaGF0aWUvd2VjaGF0eS9pc3N1ZXMvMTI0OQo=';
filename = 'wechaty-puppet-padplus-message-attachment-' + messageId + '.txt';
return file_box_1.default.fromBase64(base64, filename);
}
});
}
messageUrl(messageId) {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.silly(PRE, `messageUrl() messageId : ${util_1.default.inspect(messageId)}`);
const rawPayload = yield this.messageRawPayload(messageId);
const payload = yield this.messagePayload(messageId);
if (payload.type !== wechaty_puppet_1.MessageType.Url) {
throw new Error('Can not get url from non url payload');
}
else {
const appPayload = yield pure_function_helpers_1.appMessageParser(rawPayload);
if (appPayload) {
return {
description: appPayload.des,
thumbnailUrl: appPayload.thumburl,
title: appPayload.title,
url: appPayload.url,
};
}
else {
throw new Error('Can not parse url message payload');
}
}
});
}
messageContact(messageId) {
return __awaiter(this, void 0, void 0, function* () {
throw new Error(`not implement`);
});
}
messageMiniProgram(messageId) {
config_1.log.silly(PRE, `messageMiniProgram() messageId : ${util_1.default.inspect(messageId)}`);
throw new Error('Method not implemented.');
}
messageForward(receiver, messageId) {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.silly(PRE, `messageForward() receiver: ${receiver}, messageId : ${util_1.default.inspect(messageId)}`);
const payload = yield this.messagePayload(messageId);
if (payload.type === wechaty_puppet_1.MessageType.Text) {
if (!payload.text) {
throw new Error('no text');
}
yield this.messageSendText(receiver, payload.text);
}
else if (payload.type === wechaty_puppet_1.MessageType.Audio) {
throw new Error('Message type Audio not supported.');
}
else if (payload.type === wechaty_puppet_1.MessageType.Url) {
yield this.messageSendUrl(receiver, yield this.messageUrl(messageId));
}
else if (payload.type === wechaty_puppet_1.MessageType.MiniProgram) {
yield this.messageSendMiniProgram(receiver, yield this.messageMiniProgram(messageId));
}
else if (payload.type === wechaty_puppet_1.MessageType.ChatHistory) {
throw new Error('Message type ChatHistory not supported.');
}
else {
yield this.messageSendFile(receiver, yield this.messageFile(messageId));
}
});
}
generateBaseMsg(msgId, to) {
const msg = {
content: '',
createTime: new Date().getTime(),
fromUserName: this.selfId(),
imgStatus: 0,
l1MsgType: 0,
msgId,
msgSource: '',
msgSourceCd: 0,
msgType: schemas_1.PadplusMessageType.Text,
newMsgId: Number(msgId),
pushContent: '',
status: schemas_1.PadplusMessageStatus.One,
toUserName: to,
uin: '',
wechatUserName: this.selfId(),
};
config_1.log.silly(PRE, 'generateBaseMsg(%s) %s', to, JSON.stringify(msg));
this.manager.cachePadplusMessagePayload.set(msgId, msg);
return msg;
}
messageSendText(receiver, text, mentionIdList) {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.silly(PRE, 'messageSend(%s, %s)', JSON.stringify(receiver), text);
const contactIdOrRoomId = receiver.roomId || receiver.contactId;
let msgData;
if (mentionIdList && mentionIdList.length > 0) {
msgData = yield this.manager.sendMessage(this.selfId(), contactIdOrRoomId, text, schemas_1.PadplusMessageType.Text, mentionIdList.toString());
if (config_1.PADPLUS_REPLAY_MESSAGE) {
this.replayTextMsg(msgData.msgId, contactIdOrRoomId, text, mentionIdList);
}
}
else {
msgData = yield this.manager.sendMessage(this.selfId(), contactIdOrRoomId, text, schemas_1.PadplusMessageType.Text);
if (config_1.PADPLUS_REPLAY_MESSAGE) {
this.replayTextMsg(msgData.msgId, contactIdOrRoomId, text);
}
}
if (msgData.success) {
const msgPayload = {
content: text + ((mentionIdList && mentionIdList.length > 0) ? mentionIdList.toString() : ''),
createTime: msgData.timestamp,
fromUserName: this.selfId(),
imgStatus: 0,
l1MsgType: 0,
msgId: msgData.msgId,
msgSource: 'self',
msgSourceCd: 0,
msgType: schemas_1.PadplusMessageType.Text,
newMsgId: Number(msgData.msgId),
pushContent: text,
status: 1,
toUserName: contactIdOrRoomId,
uin: '',
wechatUserName: '',
};
this.manager.cachePadplusMessagePayload.set(msgData.msgId, msgPayload);
}
return msgData.msgId;
});
}
replayTextMsg(msgId, to, text, atUserList) {
const payload = this.generateBaseMsg(msgId, to);
payload.msgType = schemas_1.PadplusMessageType.Text;
payload.content = text;
if (atUserList) {
payload.msgSource = `<msgsource>\n\t<atuserlist>${atUserList.join(',')}</atuserlist>\n</msgsource>\n`;
}
config_1.log.silly(PRE, 'replayTextMsg replaying message: %s', JSON.stringify(payload));
this.emit('message', payload.msgId);
}
messageSendContact(receiver, contactId) {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.verbose(PRE, `messageSend('%s', %s)`, receiver, contactId);
const contactIdOrRoomId = receiver.roomId || receiver.contactId;
let contact = yield this.manager.getContact(contactId);
if (contact) {
const content = {
headImgUrl: contact.smallHeadUrl,
nickName: contact.nickName,
userName: contact.userName,
};
const contactData = yield this.manager.sendContact(this.selfId(), contactIdOrRoomId, JSON.stringify(content));
if (config_1.PADPLUS_REPLAY_MESSAGE) {
this.replayContactMsg(contactData.msgId, contactIdOrRoomId, JSON.stringify(content));
}
if (contactData.success) {
const msgPayload = {
content: JSON.stringify(content),
createTime: contactData.timestamp,
fromUserName: this.selfId(),
imgStatus: 0,
l1MsgType: 0,
msgId: contactData.msgId,
msgSource: 'self',
msgSourceCd: 0,
msgType: schemas_1.PadplusMessageType.Text,
newMsgId: Number(contactData.msgId),
pushContent: JSON.stringify(content),
status: 1,
toUserName: contactIdOrRoomId,
uin: '',
wechatUserName: '',
};
this.manager.cachePadplusMessagePayload.set(contactData.msgId, msgPayload);
}
return contactData.msgId;
}
else {
throw new Error('not able to send contact');
}
});
}
replayContactMsg(msgId, to, content) {
const payload = this.generateBaseMsg(msgId, to);
payload.msgType = schemas_1.PadplusMessageType.ShareCard;
payload.content = content;
config_1.log.silly(PRE, 'replayContactMsg replaying message: %s', JSON.stringify(payload));
this.emit('message', payload.msgId);
}
messageSendFile(receiver, file) {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.verbose(PRE, 'messageSendFile(%s, %s)', receiver, file);
const contactIdOrRoomId = receiver.roomId || receiver.contactId;
const fileUrl = yield this.manager.generatorFileUrl(file);
const fileSize = (yield file.toBuffer()).length;
config_1.log.silly(PRE, `file url : ${util_1.default.inspect(fileUrl)}`);
// this needs to run before mimeType is available
yield file.ready();
const type = (file.mimeType && file.mimeType !== 'application/octet-stream')
? file.mimeType
: path_1.default.extname(file.name);
config_1.log.silly(PRE, `fileType ${type}`);
switch (type) {
case '.slk':
throw new Error('not support');
case 'image/jpeg':
case 'image/png':
case '.jpg':
case '.jpeg':
case '.png':
const picData = yield this.manager.sendFile(this.selfId(), contactIdOrRoomId, decodeURIComponent(fileUrl), file.name, 'pic');
if (config_1.PADPLUS_REPLAY_MESSAGE) {
this.replayImageMsg(picData.msgId, contactIdOrRoomId, decodeURIComponent(fileUrl));
}
if (picData.success) {
const msgPayload = {
content: `<msg>${fileUrl}</msg>`,
createTime: picData.timestamp,
fromUserName: this.selfId(),
imgStatus: 0,
l1MsgType: 0,
msgId: picData.msgId,
msgSource: 'self',
msgSourceCd: 0,
msgType: schemas_1.PadplusMessageType.Text,
newMsgId: Number(picData.msgId),
pushContent: `<msg>${fileUrl}</msg>`,
status: 1,
toUserName: contactIdOrRoomId,
uin: '',
wechatUserName: '',
};
this.manager.cachePadplusMessagePayload.set(picData.msgId, msgPayload);
}
return picData.msgId;
case 'video/mp4':
case '.mp4':
const videoData = yield this.manager.sendFile(this.selfId(), contactIdOrRoomId, fileUrl, file.name, 'video');
if (config_1.PADPLUS_REPLAY_MESSAGE) {
this.replayAppMsg(videoData.msgId, contactIdOrRoomId, fileUrl);
}
if (videoData.success) {
const msgPayload = {
content: `<msg>${fileUrl}</msg>`,
createTime: videoData.timestamp,
fromUserName: this.selfId(),
imgStatus: 0,
l1MsgType: 0,
msgId: videoData.msgId,
msgSource: 'self',
msgSourceCd: 0,
msgType: schemas_1.PadplusMessageType.Text,
newMsgId: Number(videoData.msgId),
pushContent: `<msg>${fileUrl}</msg>`,
status: 1,
toUserName: contactIdOrRoomId,
uin: '',
wechatUserName: '',
};
this.manager.cachePadplusMessagePayload.set(videoData.msgId, msgPayload);
}
return videoData.msgId;
default:
const docData = yield this.manager.sendFile(this.selfId(), contactIdOrRoomId, fileUrl, file.name, 'doc', fileSize);
if (config_1.PADPLUS_REPLAY_MESSAGE) {
this.replayAppMsg(docData.msgId, contactIdOrRoomId, fileUrl);
}
if (docData.success) {
const msgPayload = {
content: `<msg>${fileUrl}</msg>`,
createTime: docData.timestamp,
fromUserName: this.selfId(),
imgStatus: 0,
l1MsgType: 0,
msgId: docData.msgId,
msgSource: 'self',
msgSourceCd: 0,
msgType: schemas_1.PadplusMessageType.Text,
newMsgId: Number(docData.msgId),
pushContent: `<msg>${fileUrl}</msg>`,
status: 1,
toUserName: contactIdOrRoomId,
uin: '',
wechatUserName: '',
};
this.manager.cachePadplusMessagePayload.set(docData.msgId, msgPayload);
}
return docData.msgId;
}
});
}
replayImageMsg(msgId, to, url) {
const payload = this.generateBaseMsg(msgId, to);
payload.msgType = schemas_1.PadplusMessageType.Image;
payload.content = `<msg>${url}</msg>`;
payload.url = url;
config_1.log.silly(PRE, 'replayImageMsg replaying message: %s', JSON.stringify(payload));
this.emit('message', payload.msgId);
}
replayAppMsg(msgId, to, content) {
const payload = this.generateBaseMsg(msgId, to);
payload.msgType = schemas_1.PadplusMessageType.App;
payload.content = `<msg>${content}</msg>`;
config_1.log.silly(PRE, 'replayAppMsg replaying message: %s', JSON.stringify(payload));
this.emit('message', payload.msgId);
}
messageSendUrl(receiver, urlLinkPayload) {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.verbose(PRE, `messageSendUrl(${receiver})`, JSON.stringify(receiver), JSON.stringify(urlLinkPayload));
const contactIdOrRoomId = receiver.roomId || receiver.contactId;
const { url, title, thumbnailUrl, description } = urlLinkPayload;
const payload = {
description,
thumburl: thumbnailUrl,
title,
type: 5,
url,
};
const urlLinkData = yield this.manager.sendUrlLink(this.selfId(), contactIdOrRoomId, JSON.stringify(payload));
if (config_1.PADPLUS_REPLAY_MESSAGE) {
this.replayUrlLinkMsg(urlLinkData.msgId, contactIdOrRoomId, JSON.stringify(payload));
}
if (urlLinkData.success) {
const msgPayload = {
content: JSON.stringify(payload),
createTime: urlLinkData.timestamp,
fromUserName: this.selfId(),
imgStatus: 0,
l1MsgType: 0,
msgId: urlLinkData.msgId,
msgSource: 'self',
msgSourceCd: 0,
msgType: schemas_1.PadplusMessageType.Text,
newMsgId: Number(urlLinkData.msgId),
pushContent: JSON.stringify(payload),
status: 1,
toUserName: contactIdOrRoomId,
uin: '',
wechatUserName: '',
};
this.manager.cachePadplusMessagePayload.set(urlLinkData.msgId, msgPayload);
}
config_1.log.silly(PRE, `urlLinkData : ${util_1.default.inspect(urlLinkData)}`);
return urlLinkData.msgId;
});
}
replayUrlLinkMsg(msgId, to, content) {
const payload = this.generateBaseMsg(msgId, to);
payload.msgType = schemas_1.PadplusMessageType.App;
payload.content = content;
config_1.log.silly(PRE, 'replayUrlLinkMsg replaying message: %s', JSON.stringify(payload));
this.emit('message', payload.msgId);
}
messageSendMiniProgram(receiver, miniProgramPayload) {
config_1.log.silly(PRE, `messageSendMiniProgram() receiver : ${util_1.default.inspect(receiver)}, miniProgramPayload: ${miniProgramPayload}`);
throw new Error('Method not implemented.');
}
messageRawPayload(messageId) {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.verbose(PRE, 'messageRawPayload(%s)', messageId);
const rawPayload = yield this.manager.cachePadplusMessagePayload.get(messageId);
if (!rawPayload) {
throw new Error('no message rawPayload');
}
return rawPayload;
});
}
messageRawPayloadParser(rawPayload) {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.verbose(PRE, 'messageRawPayloadParser()');
const payload = yield pure_function_helpers_1.messageRawPayloadParser(rawPayload);
if (payload.mentionIdList && payload.mentionIdList.length === 1 && payload.mentionIdList[0] === 'announcement@all') {
const memberIds = yield this.roomMemberList(payload.roomId);
payload.mentionIdList = memberIds.filter(m => m !== payload.fromId);
payload.text = `${payload.text || ''}`;
}
return payload;
});
}
/**
* ========================
* ROOM SECTION
* ========================
*/
onRoomJoinEvent(message) {
return __awaiter(this, void 0, void 0, function* () {
const joinEvent = yield room_event_join_message_parser_1.roomJoinEventMessageParser(message);
if (joinEvent) {
config_1.log.silly(PRE, `receive join event : ${util_1.default.inspect(joinEvent)}`);
const inviteeNameList = joinEvent.inviteeNameList;
const inviterName = joinEvent.inviterName;
const roomId = joinEvent.roomId;
const timestamp = joinEvent.timestamp;
const inviteeIdList = yield config_1.retry((retryException, attempt) => __awaiter(this, void 0, void 0, function* () {
config_1.log.verbose(PRE, 'onPadplusMessageRoomEventJoin({id=%s}) roomJoin retry(attempt=%d)', attempt);
const tryIdList = array_flatten_1.default(yield Promise.all(inviteeNameList.map(inviteeName => this.roomMemberSearch(roomId, inviteeName))));
if (tryIdList.length) {
return tryIdList;
}
if (!this.manager) {
throw new Error('no manager');
}
/**
* Set Cache Dirty
*/
yield this.roomMemberPayloadDirty(roomId);
return retryException(new Error('roomMemberSearch() not found'));
})).catch(e => {
config_1.log.verbose(PRE, 'onPadplusMessageRoomEventJoin({id=%s}) roomJoin retry() fail: %s', e.message);
return [];
});
let inviterIdList = yield this.roomMemberSearch(roomId, inviterName);
if (inviterIdList.length < 1) {
yield this.roomMemberPayloadDirty(roomId);
yield this.manager.getRoomMembers(roomId);
inviterIdList = yield this.roomMemberSearch(roomId, inviterName);
if (inviterIdList.length < 1) {
throw new Error(`can not get room member`);
}
}
else if (inviterIdList.length > 1) {
config_1.log.verbose(PRE, 'onPadplusMessageRoomEventJoin() inviterId found more than 1, use the first one.');
}
const inviterId = inviterIdList[0];
/**
* Set Cache Dirty
*/
yield this.roomMemberPayloadDirty(roomId);
yield this.roomPayloadDirty(roomId);
this.emit('room-join', roomId, inviteeIdList, inviterId, timestamp);
}
});
}
onRoomLeaveEvent(message) {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.verbose(PRE, 'onRoomLeaveEvent({id=%s})', message.msgId);
const leaveEvent = room_event_leave_message_parser_1.roomLeaveEventMessageParser(message);
if (leaveEvent) {
config_1.log.silly(PRE, `receive remove event : ${util_1.default.inspect(leaveEvent)}`);
const leaverNameList = leaveEvent.leaverNameList;
const removerName = leaveEvent.removerName;
const roomId = leaveEvent.roomId;
const timestamp = leaveEvent.timestamp;
const leaverIdList = array_flatten_1.default(yield Promise.all(leaverNameList.map(leaverName => this.roomMemberSearch(roomId, leaverName))));
const removerIdList = yield this.roomMemberSearch(roomId, removerName);
if (removerIdList.length < 1) {
throw new Error('no removerId found');
}
else if (removerIdList.length > 1) {
config_1.log.verbose(PRE, 'onPadplusMessageRoomEventLeave(): removerId found more than 1, use the first one.');
}
const removerId = removerIdList[0];
if (!this.manager) {
throw new Error('no padplusManager');
}
/**
* Set Cache Dirty
*/
yield this.roomMemberPayloadDirty(roomId);
yield this.roomPayloadDirty(roomId);
this.emit('room-leave', roomId, leaverIdList, removerId, timestamp);
}
});
}
onRoomTopicEvent(message) {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.verbose(PRE, 'onPadplusMessageRoomEventTopic({id=%s})', message.msgId);
const topicEvent = room_event_topic_message_parser_1.roomTopicEventMessageParser(message);
if (topicEvent) {
config_1.log.silly(PRE, `receive topic event : ${util_1.default.inspect(topicEvent)}`);
const changerName = topicEvent.changerName;
const newTopic = topicEvent.topic;
const roomId = topicEvent.roomId;
const timestamp = topicEvent.timestamp;
const roomOldPayload = yield this.roomPayload(roomId);
const oldTopic = roomOldPayload.topic;
const changerIdList = yield this.roomMemberSearch(roomId, changerName);
if (changerIdList.length < 1) {
throw new Error('no changerId found');
}
else if (changerIdList.length > 1) {
config_1.log.verbose(PRE, 'onPadplusMessageRoomEventTopic() changerId found more than 1, use the first one.');
}
const changerId = changerIdList[0];
if (!this.manager) {
throw new Error('no padplusManager');
}
/**
* Set Cache Dirty
*/
yield this.roomPayloadDirty(roomId);
if (this.manager && this.manager.cacheManager) {
yield this.manager.cacheManager.deleteRoom(roomId);
}
this.emit('room-topic', roomId, newTopic, oldTopic, changerId, timestamp);
}
});
}
roomInvitationAccept(roomInvitationId) {
config_1.log.silly(PRE, `roomInvitationId : ${util_1.default.inspect(roomInvitationId)}`);
throw new Error('Method not implemented.');
}
roomInvitationRawPayload(roomInvitationId) {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.silly(PRE, `roomInvitationId : ${util_1.default.inspect(roomInvitationId)}`);
if (!this.manager) {
throw new Error(`no manager.`);
}
const payload = yield this.manager.roomInvitationRawPayload(roomInvitationId);
return payload;
});
}
roomInvitationRawPayloadParser(rawPayload) {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.silly(PRE, `room invitation rawPayload : ${util_1.default.inspect(rawPayload)}`);
const payload = {
id: rawPayload.id,
inviterId: rawPayload.fromUser,
roomMemberCount: 0,
roomMemberIdList: [],
roomTopic: rawPayload.roomName,
timestamp: rawPayload.timestamp,
};
return payload;
});
}
roomAdd(roomId, contactId) {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.silly(PRE, `roomId : ${util_1.default.inspect(roomId)}, contactId: ${contactId}`);
if (!this.manager) {
throw new Error(`no manager.`);
}
yield this.manager.roomAddMember(roomId, contactId);
});
}
roomAvatar(roomId) {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.silly(PRE, `roomAvatar(roomId : ${util_1.default.inspect(roomId)})`);
if (!this.manager) {
throw new Error(`no manager.`);
}
const room = yield this.roomRawPayload(roomId);
if (room) {
const avatarUrl = room.bigHeadUrl || room.smallHeadUrl;
return file_box_1.default.fromUrl(avatarUrl, `${roomId}_avatar_${Date.now()}.png`);
}
else {
throw new Error(`Can not load room info by roomId : ${roomId}`);
}
});
}
roomCreate(contactIdList, topic) {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.silly(PRE, `topic : ${topic}, contactIdList: ${contactIdList.join(',')}`);
if (!this.manager) {
throw new Error(`no manager.`);
}
const result = yield this.manager.createRoom(topic || '', contactIdList);
return result;
});
}
roomDel(roomId, contactId) {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.verbose(PRE, `roomDel(${roomId}, ${contactId})`);
const memberIdList = yield this.roomMemberList(roomId);
if (memberIdList.includes(contactId)) {
yield this.manager.deleteRoomMember(roomId, contactId);
}
else {
config_1.log.verbose(PRE, `roomDel() room(${roomId}) has no member contact(${contactId})`);
}
});
}
roomQuit(roomId) {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.silly(PRE, `roomId : ${util_1.default.inspect(roomId)}`);
if (!this.manager) {
throw new Error(`no manager.`);
}
yield this.manager.quitRoom(roomId);
});
}
roomTopic(roomId, topic) {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.silly(PRE, `roomId : ${roomId}, topic: ${topic}`);
if (typeof topic === 'undefined') {
const room = yield this.roomPayload(roomId);
return room && (room.topic || '');
}
if (!this.manager) {
throw new Error(`no manager.`);
}
yield this.manager.setRoomTopic(roomId, topic);
yield this.roomPayloadDirty(roomId);
yield new Promise(resolve => setTimeout(resolve, 500));
yield this.roomTopic(roomId);
});
}
roomQrcode(roomId) {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.silly(PRE, `roomId : ${util_1.default.inspect(roomId)}`);
if (!this.manager) {
throw new Error(`no manager.`);
}
const roomQrcode = yield this.manager.getRoomQrcode(roomId);
return roomQrcode;
});
}
roomList() {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.verbose(PRE, `roomList()`);
if (!this.manager) {
throw new Error(`no manager.`);
}
const roomIds = yield this.manager.getRoomIdList();
return roomIds;
});
}
roomMemberList(roomId) {
return __awaiter(this, void 0, void 0, function* () {
config_1.log.silly(PRE, `roomMemberList(), roomId : ${util_1.default.inspect(roomId)}`);
if (!this.manager) {
throw new Error(`no manager.`);
}
const roomIds = yield this.manager.getRoomMemberIdLis