UNPKG

wechaty-puppet-padplus

Version:
993 lines (992 loc) 53.3 kB
"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 rx_queue_1 = require("rx-queue"); const state_switch_1 = require("state-switch"); const config_1 = require("../config"); const file_box_1 = __importDefault(require("file-box")); const lru_cache_1 = __importDefault(require("lru-cache")); const file_box_to_qrcode_1 = __importDefault(require("../utils/file-box-to-qrcode")); const grpc_gateway_1 = require("../server-manager/grpc-gateway"); const PadPlusServer_pb_1 = require("../server-manager/proto-ts/PadPlusServer_pb"); const wechaty_puppet_1 = require("wechaty-puppet"); const request_1 = require("./api-request/request"); const user_1 = require("./api-request/user"); const contact_1 = require("./api-request/contact"); const message_1 = require("./api-request/message"); const schemas_1 = require("../schemas"); const message_convertor_1 = require("../convert-manager/message-convertor"); const cache_manager_1 = require("../server-manager/cache-manager"); const contact_convertor_1 = require("../convert-manager/contact-convertor"); const room_1 = require("./api-request/room"); const room_convertor_1 = require("../convert-manager/room-convertor"); const callbackHelper_1 = require("../utils/callbackHelper"); const friendship_1 = require("./api-request/friendship"); const room_member_parser_1 = require("../pure-function-helpers/room-member-parser"); const pure_function_helpers_1 = require("../pure-function-helpers"); const events_1 = require("events"); const MEMORY_SLOT_NAME = 'WECHATY_PUPPET_PADPLUS'; const PRE = 'PadplusManager'; class PadplusManager extends events_1.EventEmitter { constructor(options) { super(); this.options = options; config_1.log.verbose(PRE, 'constructor()'); const lruOptions = { dispose(key, val) { config_1.log.silly(PRE, `constructor() lruOptions.dispose(${key}, ${JSON.stringify(val)})`); }, max: config_1.MESSAGE_CACHE_MAX, maxAge: config_1.MESSAGE_CACHE_AGE, }; this.loginStatus = false; this.cachePadplusMessagePayload = new lru_cache_1.default(lruOptions); this.state = new state_switch_1.StateSwitch('PadplusManager'); this.state.off(); this.memorySlot = { qrcodeId: '', uin: '', userName: '', }; this.getContactQueue = new rx_queue_1.DelayQueueExecutor(200); this.getRoomMemberQueue = new rx_queue_1.DelayQueueExecutor(500); this.resetThrottleQueue = new rx_queue_1.ThrottleQueue(5000); this.resetThrottleQueue.subscribe((reason) => __awaiter(this, void 0, void 0, function* () { config_1.log.silly('Puppet', 'constructor() resetThrottleQueue.subscribe() reason: %s', reason); if (this.grpcGatewayEmitter) { this.grpcGatewayEmitter.removeAllListeners(); } delete this.padplusUser; delete this.padplusContact; delete this.padplusFriendship; delete this.padplusRoom; delete this.padplusMesasge; delete this.requestClient; yield this.start(); })); config_1.log.silly(PRE, ` : ${util_1.default.inspect(this.state)}`); } emit(event, ...args) { return super.emit(event, ...args); } on(event, listener) { config_1.log.verbose(PRE, `on(${event}, ${typeof listener}) registered`); super.on(event, (...args) => { try { listener.apply(this, args); } catch (e) { config_1.log.error(PRE, 'onFunction(%s) listener exception: %s', event, e); } }); return this; } start() { return __awaiter(this, void 0, void 0, function* () { config_1.log.silly(PRE, `start()`); this.state.on('pending'); let emitter; try { emitter = yield grpc_gateway_1.GrpcGateway.init(this.options.token, this.options.endpoint || config_1.GRPC_ENDPOINT, String(this.options.name)); } catch (e) { config_1.log.info(`start grpc gateway failed for reason: ${e}, retry start in 5 seconds.`); yield new Promise(resolve => setTimeout(resolve, 5000)); yield this.start(); return; } if (!grpc_gateway_1.GrpcGateway.Instance) { throw new Error(`The grpc gateway has no instance.`); } this.requestClient = new request_1.RequestClient(grpc_gateway_1.GrpcGateway.Instance, emitter); this.padplusUser = new user_1.PadplusUser(this.requestClient); this.padplusMesasge = new message_1.PadplusMessage(this.requestClient); this.padplusContact = new contact_1.PadplusContact(this.requestClient); this.padplusRoom = new room_1.PadplusRoom(this.requestClient); this.padplusFriendship = new friendship_1.PadplusFriendship(this.requestClient); yield this.initGrpcGatewayListener(emitter); this.grpcGatewayEmitter = emitter; if (this.memory) { const slot = yield this.memory.get(MEMORY_SLOT_NAME); if (slot && slot.uin) { config_1.log.silly(PRE, `uin : ${slot.uin}`); emitter.setUIN(slot.uin); yield new Promise((resolve) => setTimeout(resolve, 500)); yield this.padplusUser.initInstance(); } else { yield this.padplusUser.getWeChatQRCode(); } this.memorySlot = Object.assign(Object.assign({}, this.memorySlot), yield this.memory.get(MEMORY_SLOT_NAME)); } }); } stop() { return __awaiter(this, void 0, void 0, function* () { config_1.log.verbose(PRE, `stop()`); this.state.off('pending'); if (this.grpcGatewayEmitter) { this.grpcGatewayEmitter.removeAllListeners(); } yield grpc_gateway_1.GrpcGateway.release(); yield cache_manager_1.CacheManager.release(); this.cacheManager = undefined; this.loginStatus = false; this.state.off(true); config_1.log.verbose(PRE, `stop() finished`); }); } logout(selfId) { return __awaiter(this, void 0, void 0, function* () { config_1.log.verbose(PRE, `logout()`); this.state.off('pending'); if (this.padplusUser) { const logoutResult = yield this.padplusUser.logout(selfId); if (!logoutResult) { config_1.log.error(`Logout WeChat failed!`); } else { config_1.log.silly(PRE, `Logout WeChat success!`); } } else { throw new Error(`no padplus user.`); } if (this.grpcGatewayEmitter) { this.grpcGatewayEmitter.removeAllListeners(); } if (grpc_gateway_1.GrpcGateway.Instance) { yield grpc_gateway_1.GrpcGateway.Instance.stop(); } yield cache_manager_1.CacheManager.release(); this.cacheManager = undefined; this.loginStatus = false; this.state.off(true); config_1.log.verbose(PRE, `logout() finished`); }); } setMemory(memory) { this.memory = memory; } setContactAndRoomData() { return __awaiter(this, void 0, void 0, function* () { config_1.log.silly(PRE, `setContactAndRoomData()`); if (!this.cacheManager) { config_1.log.verbose(PRE, `setContactAndRoomData() can not proceed due to no cache.`); return; } const contactTotal = yield this.cacheManager.getContactCount(); const roomTotal = yield this.cacheManager.getRoomCount(); const friendTotal = (yield this.cacheManager.getAllContacts()).filter(contact => { return contact.contactFlag !== 0; }).length; const now = new Date().getTime(); if (this.contactAndRoomData) { if (this.contactAndRoomData.contactTotal === contactTotal && this.contactAndRoomData.roomTotal === roomTotal && this.contactAndRoomData.friendTotal === friendTotal) { if (now - this.contactAndRoomData.updatedTime > config_1.WAIT_FOR_READY_TIME && !this.contactAndRoomData.readyEmitted) { config_1.log.verbose(PRE, `setContactAndRoomData() more than ${config_1.WAIT_FOR_READY_TIME / 1000 / 60} minutes no change on data, emit ready event.`); this.contactAndRoomData.readyEmitted = true; this.emit('ready'); } config_1.log.silly(PRE, `setContactAndRoomData() found contact, room, friend data no change.`); } else { config_1.log.silly(PRE, `setContactAndRoomData() found contact or room or friend change. Record changes...`); this.contactAndRoomData.contactTotal = contactTotal; this.contactAndRoomData.roomTotal = roomTotal; this.contactAndRoomData.friendTotal = friendTotal; this.contactAndRoomData.updatedTime = now; } } else { config_1.log.silly(PRE, `setContactAndRoomData() initialize contact and room data.`); this.contactAndRoomData = { contactTotal, friendTotal, readyEmitted: false, roomTotal, updatedTime: now, }; } }); } initGrpcGatewayListener(grpcGatewayEmitter) { return __awaiter(this, void 0, void 0, function* () { grpcGatewayEmitter.on('reconnect', () => __awaiter(this, void 0, void 0, function* () { this.resetThrottleQueue.next('reconnect'); })); grpcGatewayEmitter.on('grpc-end', () => __awaiter(this, void 0, void 0, function* () { this.emit('reset', 'grpc server end.'); })); grpcGatewayEmitter.on('heartbeat', (data) => __awaiter(this, void 0, void 0, function* () { this.emit('heartbeat', data); // TODO: 数据同步后,需要停止该函数的执行 if (!this.contactAndRoomData || !this.contactAndRoomData.readyEmitted) { yield this.setContactAndRoomData(); } })); grpcGatewayEmitter.on('EXPIRED_TOKEN', () => __awaiter(this, void 0, void 0, function* () { config_1.log.info(config_1.EXPIRED_TOKEN_MESSAGE); setTimeout(() => process.exit(), 5000); })); grpcGatewayEmitter.on('INVALID_TOKEN', () => __awaiter(this, void 0, void 0, function* () { config_1.log.info(config_1.INVALID_TOKEN_MESSAGE); setTimeout(() => process.exit(), 5000); })); grpcGatewayEmitter.on('data', (data) => __awaiter(this, void 0, void 0, function* () { const type = data.getResponsetype(); switch (type) { case PadPlusServer_pb_1.ResponseType.LOGIN_QRCODE: const qrcodeRawData = data.getData(); if (qrcodeRawData) { const qrcodeData = JSON.parse(qrcodeRawData); grpcGatewayEmitter.setQrcodeId(qrcodeData.qrcodeId); const fileBox = file_box_1.default.fromBase64(qrcodeData.qrcode, `qrcode${(Math.random() * 10000).toFixed()}.png`); const qrcodeUrl = yield file_box_to_qrcode_1.default(fileBox); this.emit('scan', qrcodeUrl, wechaty_puppet_1.ScanStatus.Cancel); this.qrcodeStatus = wechaty_puppet_1.ScanStatus.Cancel; } break; case PadPlusServer_pb_1.ResponseType.QRCODE_SCAN: const scanRawData = data.getData(); if (scanRawData) { config_1.log.silly(PRE, `QRCODE_SCAN : ${util_1.default.inspect(scanRawData)}`); const scanData = JSON.parse(scanRawData); config_1.log.info(PRE, ` ================================================= QRCODE_SCAN MSG : ${scanData.msg || '已确认'} ================================================= `); grpcGatewayEmitter.setQrcodeId(scanData.user_name); switch (scanData.status) { case schemas_1.QrcodeStatus.Scanned: if (this.qrcodeStatus !== wechaty_puppet_1.ScanStatus.Waiting) { this.qrcodeStatus = wechaty_puppet_1.ScanStatus.Waiting; this.emit('scan', '', this.qrcodeStatus); } break; case schemas_1.QrcodeStatus.Confirmed: if (this.qrcodeStatus !== wechaty_puppet_1.ScanStatus.Scanned) { this.qrcodeStatus = wechaty_puppet_1.ScanStatus.Scanned; this.emit('scan', '', this.qrcodeStatus); } break; case schemas_1.QrcodeStatus.Canceled: case schemas_1.QrcodeStatus.Expired: const uin = yield grpcGatewayEmitter.getUIN(); const wxid = yield grpcGatewayEmitter.getUserName(); const data = { uin, wxid, }; this.emit('scan', '', scanData.status); if (this.padplusUser) { yield this.padplusUser.getWeChatQRCode(data); } break; default: break; } } break; case PadPlusServer_pb_1.ResponseType.QRCODE_LOGIN: const grpcLoginData = data.getData(); if (grpcLoginData) { config_1.log.silly(PRE, `QRCODE_LOGIN : ${util_1.default.inspect(grpcLoginData)}`); const loginData = JSON.parse(grpcLoginData); this.loginStatus = true; grpcGatewayEmitter.setQrcodeId(''); grpcGatewayEmitter.setUserName(loginData.userName); grpcGatewayEmitter.setUIN(loginData.uin); if (this.memory) { this.memorySlot = { qrcodeId: '', uin: loginData.uin, userName: loginData.userName, }; config_1.log.silly(PRE, `name: ${this.options.name}, memory slot : ${util_1.default.inspect(this.memorySlot)}`); yield this.memory.set(MEMORY_SLOT_NAME, this.memorySlot); yield this.memory.save(); } config_1.log.verbose(PRE, `init cache manager`); yield cache_manager_1.CacheManager.init(loginData.userName); this.cacheManager = cache_manager_1.CacheManager.Instance; const contactSelf = { alias: loginData.alias, bigHeadUrl: loginData.headImgUrl, city: '', contactFlag: 3, contactType: 0, country: '', labelLists: '', nickName: loginData.nickName, province: '', remark: '', sex: wechaty_puppet_1.ContactGender.Unknown, signature: '', smallHeadUrl: '', stranger: '', ticket: '', userName: loginData.userName, verifyFlag: 0, }; yield this.cacheManager.setContact(contactSelf.userName, contactSelf); this.emit('login', loginData); const selfOnline = yield this.getContact(loginData.userName); if (selfOnline) { yield this.cacheManager.setContact(selfOnline.userName, selfOnline); } } break; case PadPlusServer_pb_1.ResponseType.AUTO_LOGIN: const grpcAutoLoginData = data.getData(); if (grpcAutoLoginData) { const autoLoginData = JSON.parse(grpcAutoLoginData); config_1.log.silly(PRE, `user name : ${util_1.default.inspect(autoLoginData)}`); if (autoLoginData && autoLoginData.online) { if (!this.loginStatus) { const wechatUser = autoLoginData.wechatUser; config_1.log.verbose(PRE, `init cache manager`); yield cache_manager_1.CacheManager.init(wechatUser.userName); this.cacheManager = cache_manager_1.CacheManager.Instance; /* if (this.padplusUser) { await this.padplusUser.reconnect() } else { throw new Error(`no padplus user.`) } */ const contactSelfInfo = yield this.contactSelfInfo(); const contactSelfPayload = contact_convertor_1.convertFromGrpcContactSelf(contactSelfInfo); yield this.cacheManager.setContact(contactSelfPayload.userName, contactSelfPayload); this.emit('login', wechatUser); this.loginStatus = true; } } else { const uin = yield grpcGatewayEmitter.getUIN(); const wxid = yield grpcGatewayEmitter.getUserName(); const data = { uin, wxid, }; yield grpcGatewayEmitter.setUIN(''); yield grpcGatewayEmitter.setUserName(''); if (this.padplusUser) { yield this.padplusUser.getWeChatQRCode(data); } } } break; case PadPlusServer_pb_1.ResponseType.ACCOUNT_LOGOUT: const logoutRawData = data.getData(); if (logoutRawData) { const logoutData = JSON.parse(logoutRawData); const uin = data.getUin(); const _uin = grpcGatewayEmitter.getUIN(); if (uin === _uin) { this.loginStatus = false; if (logoutData.mqType === 1100) { this.emit('error', new schemas_1.PadplusError(schemas_1.PadplusErrorType.EXIT, logoutData.message)); yield new Promise((resolve) => setTimeout(resolve, 20 * 1000)); this.emit('logout'); } } else { const userName = grpcGatewayEmitter.getUserName(); throw new Error(`can not get userName for this uin : ${uin}, userName: ${userName}`); } } else { config_1.log.info(`can not get data from Event LOGOUT, ready to restart...`); if (!this.padplusUser) { throw new Error(`no padplusUser`); } yield this.padplusUser.reconnect(); yield new Promise((resolve) => setTimeout(resolve, 30 * 1000)); this.emit('reset', 'logout with some unknow reasons'); } break; case PadPlusServer_pb_1.ResponseType.CONTACT_LIST: case PadPlusServer_pb_1.ResponseType.CONTACT_MODIFY: const roomRawData = data.getData(); if (roomRawData) { const _data = JSON.parse(roomRawData); if (!pure_function_helpers_1.isRoomId(_data.UserName)) { const contactData = _data; if (contactData.Type7) { config_1.log.warn(`This id: ${contactData.UserName} is not wxid, using weixin instead of wxid will potentially cause system failure. To make sure everything works as excepted, please use the wxid to load Contact.`); } const contact = contact_convertor_1.convertFromGrpcContact(contactData, true); if (this.cacheManager) { yield this.cacheManager.setContact(contact.userName, contact); } callbackHelper_1.CallbackPool.Instance.resolveContactCallBack(contact.userName, contact); } else { const roomData = _data; const roomPayload = room_convertor_1.convertRoomFromGrpc(roomData); if (this.cacheManager) { const roomMembers = room_member_parser_1.briefRoomMemberParser(roomPayload.members); const _roomMembers = yield this.cacheManager.getRoomMember(roomPayload.chatroomId); if (!_roomMembers) { yield this.cacheManager.setRoomMember(roomPayload.chatroomId, roomMembers); } yield this.cacheManager.setRoom(roomPayload.chatroomId, roomPayload); } else { throw new schemas_1.PadplusError(schemas_1.PadplusErrorType.NO_CACHE, `CONTACT_MODIFY`); } callbackHelper_1.CallbackPool.Instance.resolveRoomCallBack(roomPayload.chatroomId, roomPayload); } } break; case PadPlusServer_pb_1.ResponseType.CONTACT_DELETE: const contactDataStr = data.getData(); if (contactDataStr) { const contactData = JSON.parse(contactDataStr); config_1.log.silly(PRE, `delete contact data : ${util_1.default.inspect(contactData)}`); const deleteUserName = contactData.field; if (this.cacheManager) { if (pure_function_helpers_1.isRoomId(deleteUserName)) { const room = yield this.cacheManager.getRoom(deleteUserName); if (!room) { const roomPayload = { alias: '', bigHeadUrl: '', chatRoomOwner: '', chatroomId: deleteUserName, chatroomVersion: 0, contactType: 0, isDelete: true, labelLists: '', memberCount: 0, members: [], nickName: '', smallHeadUrl: '', stranger: '', ticket: '', }; yield this.cacheManager.setRoom(deleteUserName, roomPayload); } else { room.isDelete = true; yield this.cacheManager.setRoom(deleteUserName, room); } yield this.cacheManager.setRoomMember(deleteUserName, {}); } else if (pure_function_helpers_1.isContactId(deleteUserName)) { yield this.cacheManager.deleteContact(deleteUserName); } else { throw new Error(`the filed is not right.`); } } } break; case PadPlusServer_pb_1.ResponseType.MESSAGE_RECEIVE: const rawMessageStr = data.getData(); if (rawMessageStr) { const rawMessage = JSON.parse(rawMessageStr); const message = yield this.onProcessMessage(rawMessage); this.emit('message', message); } break; case PadPlusServer_pb_1.ResponseType.CONTACT_ADD: const addContactCallback = callbackHelper_1.CallbackPool.Instance.getCallback(data.getRequestid()); addContactCallback && addContactCallback(data); callbackHelper_1.CallbackPool.Instance.removeCallback(data.getRequestid()); break; case PadPlusServer_pb_1.ResponseType.CONTACT_SEARCH: const searchContactTraceId = data.getTraceid(); if (searchContactTraceId) { const searchContactCallback = callbackHelper_1.CallbackPool.Instance.getCallback(searchContactTraceId); searchContactCallback && searchContactCallback(data); callbackHelper_1.CallbackPool.Instance.removeCallback(searchContactTraceId); } break; case PadPlusServer_pb_1.ResponseType.ROOM_QRCODE: const roomQrcodeTraceId = data.getTraceid(); if (roomQrcodeTraceId) { const callback = callbackHelper_1.CallbackPool.Instance.getCallback(roomQrcodeTraceId); callback && callback(data); callbackHelper_1.CallbackPool.Instance.removeCallback(roomQrcodeTraceId); } break; case PadPlusServer_pb_1.ResponseType.ROOM_MEMBER_LIST: const roomMembersStr = data.getData(); if (roomMembersStr) { if (this.cacheManager) { const roomMemberList = JSON.parse(roomMembersStr); const roomId = roomMemberList.roomId; const membersStr = roomMemberList.membersJson; const membersList = JSON.parse(membersStr); const members = room_member_parser_1.roomMemberParser(membersList); yield this.cacheManager.setRoomMember(roomId, members); yield Promise.all(membersList.map((member) => __awaiter(this, void 0, void 0, function* () { if (!this.cacheManager) { throw new schemas_1.PadplusError(schemas_1.PadplusErrorType.NO_CACHE, 'roomMemberList'); } const contact = yield this.cacheManager.getContact(member.UserName); if (!contact) { const newContact = { alias: '', bigHeadUrl: member.HeadImgUrl, city: '', contactFlag: 0, contactType: 0, country: '', labelLists: '', nickName: member.NickName, province: '', remark: '', sex: wechaty_puppet_1.ContactGender.Unknown, signature: '', smallHeadUrl: member.HeadImgUrl, stranger: '', ticket: '', userName: member.UserName, verifyFlag: 0, }; yield this.cacheManager.setContact(newContact.userName, newContact); } else { const newContact = Object.assign({}, contact, { bigHeadUrl: member.HeadImgUrl, nickName: member.NickName, smallHeadUrl: member.HeadImgUrl, userName: member.UserName, }); yield this.cacheManager.setContact(newContact.userName, newContact); } callbackHelper_1.CallbackPool.Instance.resolveRoomMemberCallback(roomId, members); }))); } else { throw new schemas_1.PadplusError(schemas_1.PadplusErrorType.NO_CACHE, `CONTACT_MODIFY`); } } else { throw new Error(`can not get receive room member data from server`); } break; case PadPlusServer_pb_1.ResponseType.ROOM_MEMBER_MODIFY: // TODO: not support now break; case PadPlusServer_pb_1.ResponseType.STATUS_NOTIFY: // TODO: not support now break; case PadPlusServer_pb_1.ResponseType.MESSAGE_MEDIA_SRC: const traceId = data.getTraceid(); if (traceId) { const callback = callbackHelper_1.CallbackPool.Instance.getCallback(traceId); callback && callback(data); callbackHelper_1.CallbackPool.Instance.removeCallback(traceId); } else { config_1.log.silly(PRE, `can not get trace id`); } break; case PadPlusServer_pb_1.ResponseType.REQUEST_RESPONSE: const requestId = data.getRequestid(); const responseData = data.getData(); if (responseData) { const callback = callbackHelper_1.CallbackPool.Instance.getCallback(requestId); callback && callback(data); } break; } })); }); } /** * Contact Self Section */ contactSelfQrcode() { return __awaiter(this, void 0, void 0, function* () { config_1.log.silly(PRE, `contactSelfQrcode()`); if (this.padplusContact) { return this.padplusContact.contactSelfQrcode(); } else { throw new Error(`no padplus contact`); } }); } contactSelfName(name) { return __awaiter(this, void 0, void 0, function* () { config_1.log.silly(PRE, `contactSelfName(${name})`); if (this.padplusContact) { const data = { nickName: name, }; yield this.padplusContact.setContactSelfInfo(data); } else { throw new Error(`no padplus contact`); } }); } contactSelfSignature(signature) { return __awaiter(this, void 0, void 0, function* () { config_1.log.silly(PRE, `contactSelfSignature(${signature})`); if (this.padplusContact) { const data = { signature, }; yield this.padplusContact.setContactSelfInfo(data); } else { throw new Error(`no padplus contact`); } }); } contactSelfInfo() { return __awaiter(this, void 0, void 0, function* () { config_1.log.silly(PRE, `contactSelfInfo()`); if (this.padplusContact) { return this.padplusContact.getContactSelfInfo(); } else { throw new Error(`no padplus contact`); } }); } /** * Message Section */ loadRichMediaData(mediaData) { return __awaiter(this, void 0, void 0, function* () { config_1.log.silly(PRE, `loadRichMediaData()`); if (!this.padplusMesasge) { throw new Error(`no padplus message`); } const data = yield this.padplusMesasge.loadRichMeidaData(mediaData); const mediaStr = data.getData(); if (mediaStr) { const mediaData = JSON.parse(mediaStr); return mediaData; } else { throw new Error(`can not load media data on manager`); } }); } sendMessage(selfId, receiver, text, type, mention) { return __awaiter(this, void 0, void 0, function* () { config_1.log.silly(PRE, `selfId : ${selfId}, receiver : ${receiver}, text : ${text}, type : ${type}`); if (!this.padplusMesasge) { throw new Error(`no padplus message`); } return this.padplusMesasge.sendMessage(selfId, receiver, text, type, mention); }); } sendContact(selfId, receiver, contentStr) { return __awaiter(this, void 0, void 0, function* () { config_1.log.silly(PRE, `selfId : ${selfId},receiver : ${receiver}`); if (!this.cacheManager) { throw new schemas_1.PadplusError(schemas_1.PadplusErrorType.NO_CACHE, `sendContact()`); } if (!this.padplusMesasge) { throw new Error(`no padplus message`); } return this.padplusMesasge.sendContact(selfId, receiver, contentStr); }); } addFriend(contactId, hello, isPhoneNumber, strangerV1, strangerV2) { return __awaiter(this, void 0, void 0, function* () { config_1.log.verbose(PRE, `addFriend(), isPhoneNumber: ${isPhoneNumber}`); if (!this.padplusFriendship) { throw new Error(`no padplusFriendship`); } return this.padplusFriendship.addFriend(strangerV1, strangerV2, isPhoneNumber, contactId, hello); }); } generatorFileUrl(file) { return __awaiter(this, void 0, void 0, function* () { config_1.log.verbose(PRE, 'generatorFileUrl(%s)', file); if (this.requestClient) { const url = yield this.requestClient.uploadFile(file.name, yield file.toStream()); return url; } else { throw new Error(`no requestClient`); } }); } sendFile(selfId, receiverId, url, fileName, subType, fileSize) { return __awaiter(this, void 0, void 0, function* () { config_1.log.verbose(PRE, 'sendFile()'); if (!this.padplusMesasge) { throw new Error(`no padplus message`); } return this.padplusMesasge.sendFile(selfId, receiverId, url, fileName, subType, fileSize); }); } sendUrlLink(selfId, receiver, content) { return __awaiter(this, void 0, void 0, function* () { if (!this.padplusMesasge) { throw new Error(`no padplus message`); } return this.padplusMesasge.sendUrlLink(selfId, receiver, content); }); } onProcessMessage(rawMessage) { return __awaiter(this, void 0, void 0, function* () { const payload = yield message_convertor_1.convertMessageFromGrpcToPadplus(rawMessage); this.cachePadplusMessagePayload.set(payload.msgId, payload); return payload; }); } /** * Contact Section */ setContactAlias(contactId, alias) { return __awaiter(this, void 0, void 0, function* () { config_1.log.silly(PRE, `setContactAlias(), contactId : ${contactId}, alias: ${alias}`); if (!this.padplusContact) { throw new Error(`no padplusContact`); } yield this.padplusContact.setAlias(contactId, alias); return new Promise((resolve, reject) => { const timeout = setTimeout(() => { reject(new Error('set alias failed since timeout')); }, 5000); callbackHelper_1.CallbackPool.Instance.pushContactAliasCallback(contactId, alias, () => { clearTimeout(timeout); resolve(); }); }); }); } getContactIdList(selfId) { return __awaiter(this, void 0, void 0, function* () { config_1.log.silly(PRE, `selfId : ${util_1.default.inspect(selfId)}`); if (!this.cacheManager) { throw new schemas_1.PadplusError(schemas_1.PadplusErrorType.NO_CACHE, 'contactList()'); } return this.cacheManager.getContactIds(); }); } getContact(contactId) { return __awaiter(this, void 0, void 0, function* () { if (!this.cacheManager) { throw new Error(); } const contact = yield this.cacheManager.getContact(contactId); if (contact) { return contact; } yield this.getContactQueue.execute(() => __awaiter(this, void 0, void 0, function* () { if (!this.padplusContact) { throw new Error(`no padplusContact`); } yield this.padplusContact.getContactInfo(contactId); })); return new Promise((resolve, reject) => { const timeout = setTimeout(() => reject(new Error('get contact timeout')), 5000); callbackHelper_1.CallbackPool.Instance.pushContactCallback(contactId, (data) => { clearTimeout(timeout); resolve(data); }); }); }); } getContactPayload(contactId) { return __awaiter(this, void 0, void 0, function* () { const payload = yield this.getContact(contactId); if (!payload) { throw new Error('Can not find payload for contactId ' + contactId); } return payload; }); } searchContact(contactId) { return __awaiter(this, void 0, void 0, function* () { if (!this.padplusContact) { throw new Error(`no padplusContact`); } const payload = yield this.padplusContact.searchContact(contactId); if (!payload) { throw new Error('Can not find payload for contactId ' + contactId); } return payload; }); } syncContacts() { return __awaiter(this, void 0, void 0, function* () { config_1.log.silly(PRE, `sync all contacts`); if (!this.padplusContact) { throw new Error(`no padplusContact`); } yield this.padplusContact.syncContacts(); }); } /** * Room Section */ setRoomTopic(roomId, topic) { return __awaiter(this, void 0, void 0, function* () { if (!this.padplusRoom) { throw new Error(`no padplus Room.`); } yield this.padplusRoom.setTopic(roomId, topic); if (this.cacheManager) { yield this.cacheManager.deleteRoom(roomId); } else { throw new Error(`no cache manager.`); } return new Promise((resolve, reject) => { const timeout = setTimeout(() => { reject(new Error('set alias failed since timeout')); }, 5000); callbackHelper_1.CallbackPool.Instance.pushRoomTopicCallback(roomId, topic, () => { clearTimeout(timeout); resolve(); }); }); }); } getRoomQrcode(roomId) { return __awaiter(this, void 0, void 0, function* () { if (!this.padplusRoom) { throw new Error(`no padplusRoom`); } const qrcodeBuf = this.padplusRoom.getRoomQrcode(roomId); return qrcodeBuf; }); } getRoomIdList() { return __awaiter(this, void 0, void 0, function* () { if (!this.cacheManager) { throw new Error(`no cache.`); } return this.cacheManager.getRoomIds(); }); } getRoomMemberIdList(roomId) { return __awaiter(this, void 0, void 0, function* () { const memberMap = yield this.getRoomMembers(roomId); if (memberMap) { return Object.keys(memberMap); } else { return []; } }); } getRoomInfo(roomId) { return __awaiter(this, void 0, void 0, function* () { const room = yield this.getRoom(roomId); if (room) { if (!this.cacheManager) { throw new schemas_1.PadplusError(schemas_1.PadplusErrorType.NO_CACHE, `get room info`); } yield this.cacheManager.setRoom(room.chatroomId, room); return room; } else { throw new Error(`can not get room info by api`); } }); } getRoom(roomId) { return __awaiter(this, void 0, void 0, function* () { if (!this.cacheManager) { throw new Error(); } const room = yield this.cacheManager.getRoom(roomId); if (room) { return room; } yield this.getContactQueue.execute(() => __awaiter(this, void 0, void 0, function* () { if (!this.padplusContact) { throw new Error(`no padplusContact`); } yield this.padplusContact.getContactInfo(roomId); })); return new Promise((resolve, reject) => { const timeout = setTimeout(() => reject(new Error('get room timeout')), 5000); callbackHelper_1.CallbackPool.Instance.pushContactCallback(roomId, (data) => { clearTimeout(timeout); resolve(data); }); }); }); } getRoomMembers(roomId) { return __awaiter(this, void 0, void 0, function* () { if (!this.cacheManager) { throw new Error(`no cache.`); } const memberMap = yield this.cacheManager.getRoomMember(roomId); if (!memberMap) { if (!this.grpcGatewayEmitter) { throw new Error(`no grpcGatewayEmitter.`); } const uin = this.grpcGatewayEmitter.getUIN(); yield this.getRoomMemberQueue.execute(() => __awaiter(this, void 0, void 0, function* () { if (!this.padplusRoom) { throw new Error(`no padplus Room.`); } yield this.padplusRoom.getRoomMembers(uin, roomId); })); return new Promise((resolve, reject) => { const timeout = setTimeout(() => { reject(new Error('get room member failed since timeout')); }, 5000); callbackHelper_1.CallbackPool.Instance.pushRoomMemberCallback(roomId, (data) => { clearTimeout(timeout); resolve(data); }); }); } else { return memberMap; } }); } deleteRoomMember(roomId, contactId) { return __awaiter(this, void 0, void 0, function* () { config_1.log.silly(PRE, `deleteRoomMember(%s, %s)`, roomId, contactId); if (!this.padplusRoom) { throw new Error(`no padplus Room.`); } yield this.padplusRoom.deleteRoomMember(roomId, contactId); }); } setAnnouncement(roomId, announcement) { return __awaiter(this, void 0, void 0, function* () { if (!this.padplusRoom) { throw new Error(`no padplus Room.`); } return this.padplusRoom.setAnnouncement(roomId, announcement); }); } getAnnouncement(roomId) { return __awaiter(this, void 0, void 0, function* () { if (!this.padplusRoom) { throw new Error(`no padplus Room.`); } return this.padplusRoom.getAnnouncement(roomId); }); } roomAddMember(roomId, memberId) { return __awaiter(this, void 0, void 0, function* () { config_1.log.silly(PRE, `roomAddMember: ${roomId}, ${memberId}`); if (!this.padplusRoom) { throw new Error(`no padplus Room.`);