UNPKG

wechaty-puppet-wechat4u

Version:
907 lines 38.4 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.PuppetWechat4u = void 0; /** * Wechaty - https://github.com/chatie/wechaty * * @copyright 2016-2018 Huan LI <zixia@zixia.net> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ const wechat4u_1 = __importDefault(require("wechat4u")); const quick_lru_1 = __importDefault(require("@alloc/quick-lru")); const PUPPET = __importStar(require("wechaty-puppet")); const wechaty_puppet_1 = require("wechaty-puppet"); const file_box_1 = require("file-box"); const gerror_1 = require("gerror"); const config_js_1 = require("./config.js"); const web_schemas_js_1 = require("./web-schemas.js"); const mod_js_1 = require("./wechat4u/events/mod.js"); const message_js_1 = require("./wechat4u/schema-mapper/message.js"); // 解析小程序数据格式 const message_miniprogram_js_1 = require("./wechat4u/messages/message-miniprogram.js"); // 解析appmsg 数据格式 const message_appmsg_js_1 = require("./wechat4u/messages/message-appmsg.js"); // 解析表情数据格式 const message_emotion_js_1 = require("./wechat4u/messages/message-emotion.js"); const contact_js_1 = require("./wechat4u/schema-mapper/contact.js"); const room_js_1 = require("./wechat4u/schema-mapper/room.js"); const is_type_js_1 = require("./wechat4u/utils/is-type.js"); const MEMORY_SLOT_NAME = 'PUPPET-WECHAT4U'; class PuppetWechat4u extends PUPPET.Puppet { options; static VERSION = config_js_1.VERSION; /** * Wecaht4u * * Code from: * https://github.com/nodeWechat/wechat4u/blob/46931e78bcb56899b8d2a42a37b919e7feaebbef/run-core.js * */ wechat4u; scanQrCode; // 启动时间 为了处理历史消息 startTime = 0; unknownContactId = []; getContactInterval; _heartBeatTimer; cacheMessageRawPayload; constructor(options = {}) { super(options); this.options = options; const lruOptions = { maxAge: 1000 * 60 * 60, maxSize: 10000, onEviction(key, val) { wechaty_puppet_1.log.silly('PuppetWechat4u', 'constructor() lruOptions.dispose(%s, %s)', key, JSON.stringify(val)); }, }; this.cacheMessageRawPayload = new quick_lru_1.default(lruOptions); } version() { return `${config_js_1.VERSION}<${super.version()}>`; } name() { return `${config_js_1.NAME}<${super.name()}>`; } async onStart() { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'onStart() with %s', this.memory.name || 'NONAME'); if (this.wechat4u) { wechaty_puppet_1.log.warn('PuppetWechat4u', 'onStart() wechat4u exist, will be overwrited'); } this.startTime = parseInt(String(new Date().getTime() / 1000)); /** * Huan(202110): rename `onStart()` to `tryStart()` * then we will be able to use `MemoryMixin` * to init MemoryCard for the child puppet */ try { await this.memory.load(); } catch (_) { } // console.info('faint 1') const syncData = await this.memory.get(MEMORY_SLOT_NAME); // console.info('faint 2') if (syncData) { this.wechat4u = new wechat4u_1.default(syncData); } else { this.wechat4u = new wechat4u_1.default(); } this.monkeyPatch(this.wechat4u); this.initHookEvents(this.wechat4u); /** * Should not `await` onStart/restart for wechat4u * because it will blocks... */ if (this.wechat4u.PROP.uin) { // 存在登录数据时,可以随时调用restart进行重启 this.wechat4u.restart(); } else { this.wechat4u.start(); } } /** * At present, if a user information that does not exist is found, it will be called once. * If it is a group message, it will send a lot of information requests, and finally most of the interface requests will fail. * At present, the method of timer is used to regularly obtain user information * 1、A timer is started when the search request is triggered for the first time * 2、All requested unknown user ids will be stored in unknownContactId * 3、The timer will be executed once every 500ms, each time fetching 50 pieces of data in unknownContactId * 4、If the data of unknownContactId is empty, the timer will be cleared and wait for the next establishment * @private */ getContactsInfo() { const tempArray = this.unknownContactId.splice(0, 40); if (tempArray.length === 0 && this.getContactInterval) { clearInterval(this.getContactInterval); this.getContactInterval = undefined; } if (tempArray.length) { const userDataList = tempArray.map(contact => { return { EncryChatRoomId: contact[1], UserName: contact[0], }; }); this.wechat4u.batchGetContact(userDataList).then((result) => { result.forEach((item) => { if ((0, is_type_js_1.isRoomId)(item.UserName)) { const membersList = item.MemberList.map((mItem) => { return { ...mItem, EncryChatRoomId: item.UserName, }; }); this.wechat4u.updateContacts(membersList); } }); this.wechat4u.updateContacts(result); return null; }).catch((e) => { wechaty_puppet_1.log.warn('PuppetWechat4u', 'contactRawPayload(%s) wechat4u.batchGetContact() exception: %s', e); }); } } monkeyPatch(wechat4u) { wechaty_puppet_1.log.silly('PuppetWechat4u', 'monkeyPatch()'); // fake wechat4u to think as we had logined.) this.monkeyPatchOffState(wechat4u, 'checkLogin', Promise.resolve({ code: 200 })); this.monkeyPatchOffState(wechat4u, 'login', Promise.resolve()); this.monkeyPatchOffState(wechat4u, '_init', Promise.resolve()); this._startPuppetHeart(true, wechat4u); /** * Disable Wechat4u for Sending Message to Filehelper when Heartbeat. */ // tslint:disable-next-line wechat4u.setPollingTargetGetter(() => { return ''; }); wechat4u.setPollingMessageGetter(() => { return ''; }); // 自定义心跳间隔(以毫秒为单位) // 25 days: https://stackoverflow.com/a/12633556/1123955 // this.wechat4u.setPollingIntervalGetter(() => Math.pow(2,31) - 1) } // 开始监听心跳 _startPuppetHeart(firstTime = true, wechat4u) { if (firstTime && this._heartBeatTimer) { return; } let status = wechat4u.state; if (status === wechat4u.CONF.STATE.login) { status = 'normal'; } else if (status === wechat4u.CONF.STATE.logout) { status = 'logout'; } else if (status === wechat4u.CONF.STATE.init) { status = 'init'; } else if (status === wechat4u.CONF.STATE.uuid) { status = 'uuid'; } this.emit('heartbeat', { data: `heartbeat@puppet-wechat4u:${status}` }); // eslint-disable-next-line @typescript-eslint/no-misused-promises this._heartBeatTimer = setTimeout(async () => { await this._startPuppetHeart(false, wechat4u); return undefined; }, 15 * 1000); // 15s } /** * Monkey Patch for Wechat4u * - https://www.audero.it/blog/2016/12/05/monkey-patching-javascript/#what-is-monkey-patching * * What is Monkey patching? * Monkey patching is a technique to add, modify, or suppress * the default behavior of a piece of code at runtime * without changing its original source code. */ monkeyPatchOffState(wechat4u, func, valueWhenLogouted) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'monkeyPatchOffState(wechat4u, %s)', func); const puppetThis = this; const funcOrig = wechat4u[func]; function funcNew() { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'monkeyPatchOffState(%s) funcNew()', func); if (puppetThis.state.inactive()) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'monkeyPatchOffState(%s) funcNew() state.off() is true, return', func); return valueWhenLogouted; } return funcOrig.call(this); } wechat4u[func] = funcNew; } /** * @private * For issue https://github.com/wechaty/puppet-wechat/issues/107 */ async waitStable() { wechaty_puppet_1.log.verbose('PuppetWeChat', 'waitStable()'); let maxNum = 0; let curNum = 0; let unchangedNum = 0; const SLEEP_SECOND = 4; const STABLE_CHECK_NUM = 5; while (unchangedNum < STABLE_CHECK_NUM) { // wait 1 second await new Promise(resolve => setTimeout(resolve, SLEEP_SECOND * 1000)); const contactList = await this.contactList(); curNum = contactList.length; if (curNum > 0 && curNum === maxNum) { unchangedNum++; } else /* curNum < maxNum */ { unchangedNum = 0; } if (curNum > maxNum) { maxNum = curNum; } wechaty_puppet_1.log.silly('PuppetWeChat', 'readyStable() while() curNum=%s, maxNum=%s, unchangedNum=%s', curNum, maxNum, unchangedNum); } wechaty_puppet_1.log.verbose('PuppetWeChat', 'readyStable() emit(ready)'); this.emit('ready', { data: 'stable' }); } initHookEvents(wechat4u) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'initHookEvents()'); /** * uuid事件,参数为uuid,根据uuid生成二维码 */ this.wechat4u.on('uuid', (uuid) => { wechaty_puppet_1.log.silly('PuppetWechat4u', 'initHookEvents() wechat4u.on(uuid)'); this.scanQrCode = 'https://login.weixin.qq.com/l/' + uuid; this.emit('scan', { qrcode: this.scanQrCode, status: PUPPET.types.ScanStatus.Waiting }); }); /** * 登录用户头像事件,手机扫描后可以得到登录用户头像的Data URL */ wechat4u.on('user-avatar', (avatarDataUrl) => { this.emit('scan', { data: avatarDataUrl, qrcode: this.scanQrCode || '', status: PUPPET.types.ScanStatus.Scanned, }); }); /** * 登录成功事件 */ wechat4u.on('login', async () => { // 由于初始好友列表没有存储当前bot的基础信息,所以在登录后直接更新当前机器人的信息 this.wechat4u.updateContacts([this.wechat4u.user]); this.startTime = parseInt(String(new Date().getTime() / 1000)); // FIXME: where's the logined user id? const userId = this.wechat4u.user.UserName; if (!userId) { this.emit('error', { data: gerror_1.GError.stringify(new Error('login event can not found selfId')), }); return; } // we do not wait `ready` before emit `login` this.waitStable().catch(e => { wechaty_puppet_1.log.error('PuppetWeChatEvent', 'onLogin() this.waitStable() rejection: %s', e && e.message); }); await this.login(userId); // 保存数据,将数据序列化之后保存到任意位置 await this.memory.set(MEMORY_SLOT_NAME, wechat4u.botData); await this.memory.save(); }); /** * 登出成功事件 */ wechat4u.on('logout', async () => { wechaty_puppet_1.log.silly('PuppetWechat4u', 'initHookEvents() wechat4u.on(logout)'); if (this.isLoggedIn) { await this.logout(); } // 清除数据 await this.memory.delete(MEMORY_SLOT_NAME); await this.memory.save(); this.wechat4u.start(); }); /** * 联系人更新事件,参数为被更新的联系人列表 */ wechat4u.on('contacts-updated', (contacts) => { wechaty_puppet_1.log.silly('PuppetWechat4u', 'initHookEvents() wechat4u.on(contacts-updated) new/total contacts.length=%d/%d', contacts.length, Object.keys(wechat4u.contacts).length); contacts.forEach((item) => { if ((0, is_type_js_1.isRoomId)(item.UserName)) { const membersList = item.MemberList.map((mItem) => { this.unknownContactId.push([mItem.UserName, item.UserName]); return { ...mItem, EncryChatRoomId: item.UserName, }; }); this.wechat4u.updateContacts(membersList); } }); if (!this.getContactInterval) { this.getContactsInfo(); this.getContactInterval = setInterval(() => { this.getContactsInfo(); }, 2000); } }); /** * 错误事件,参数一般为Error对象 */ wechat4u.on('error', (err) => { this.emit('error', { data: gerror_1.GError.stringify(err), }); }); /** * 如何处理会话消息 */ wechat4u.on('message', async (msg) => { if (!msg.MsgId) { wechaty_puppet_1.log.warn('PuppetWechat4u', 'initHookEvents() wechat4u.on(message) no message id: %s', JSON.stringify(msg)); throw new Error('no id'); } // 如果是消息的创建时间小于机器人启动的时间 直接丢弃 if (msg.CreateTime < this.startTime) { // log.warn('PuppetWechat4u', 'initHookEvents() wechat4u.on(message) is history message: %s', JSON.stringify(msg)) return; } this.cacheMessageRawPayload.set(msg.MsgId, msg); const event = await (0, mod_js_1.parseEvent)(this, msg); switch (event.type) { case mod_js_1.EventType.Message: this.emit('message', { messageId: msg.MsgId }); break; case mod_js_1.EventType.Friendship: { this.emit('friendship', { friendshipId: msg.MsgId, }); break; } case mod_js_1.EventType.RoomInvite: { this.emit('room-invite', { roomInvitationId: msg.MsgId, }); break; } case mod_js_1.EventType.RoomJoin: { const roomJoin = event.payload; this.emit('room-join', roomJoin); break; } case mod_js_1.EventType.RoomLeave: { const roomLeave = event.payload; this.emit('room-leave', roomLeave); break; } case mod_js_1.EventType.RoomTopic: { const roomTopic = event.payload; this.emit('room-topic', roomTopic); break; } } }); } async onStop() { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'onStop()'); this.wechat4u.stop(); this.wechat4u = undefined; if (this._heartBeatTimer) { clearTimeout(this._heartBeatTimer); this._heartBeatTimer = undefined; } } async ding(data) { wechaty_puppet_1.log.silly('PuppetWechat4u', 'ding(%s)', data || ''); this.emit('dong', { data }); } /** * * ContactSelf * * */ async contactSelfQRCode() { return PUPPET.throwUnsupportedError(); } async contactSelfName(name) { return PUPPET.throwUnsupportedError(name); } async contactSelfSignature(signature) { return PUPPET.throwUnsupportedError(signature); } async contactAlias(contactId, alias) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'contactAlias(%s, %s)', contactId, alias); if (typeof alias === 'undefined') { const payload = await this.contactPayload(contactId); return payload.alias; } await this.wechat4u.updateRemarkName(contactId, alias); } async contactList() { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'contactList()'); const idList = Object.keys(this.wechat4u.contacts) .filter((contact) => !this.wechat4u.Contact.isRoomContact(this.wechat4u.contacts[contact])); return idList; } async contactAvatar(contactId, file) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'contactAvatar(%s)', contactId); if (file) { return PUPPET.throwUnsupportedError(); } const rawPayload = await this.contactRawPayload(contactId); const payload = await this.contactPayload(contactId); const name = payload.name; // add '&type=big' to get big image if (rawPayload.HeadImgUrl) { const res = await this.wechat4u.getHeadImg(rawPayload.HeadImgUrl + '&type=big'); /** * 如何获取联系人头像 */ return file_box_1.FileBox.fromBuffer(res.data, `wechaty-contact-avatar-${name}.jpg`); } } async contactRawPayload(contactId) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'contactRawPayload(%s) with contacts.length=%d', contactId, Object.keys(this.wechat4u.contacts).length); if (!(contactId in this.wechat4u.contacts)) { this.unknownContactId.push([contactId, '']); if (!this.getContactInterval) { this.getContactsInfo(); this.getContactInterval = setInterval(() => { this.getContactsInfo(); }, 2000); } } const rawPayload = await (0, config_js_1.retry)(async (retryException, attempt) => { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'contactRawPayload(%s) retry() attempt=%d', contactId, attempt); if (contactId in this.wechat4u.contacts) { return this.wechat4u.contacts[contactId]; } retryException(new Error('no this.wechat4u.contacts[' + contactId + ']')); }); return rawPayload; } async contactRawPayloadParser(rawPayload) { return (0, contact_js_1.wechat4uContactToWechaty)(rawPayload); } /** * * Message * */ async messageContact(messageId) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'messageContact(%s)', messageId); return PUPPET.throwUnsupportedError(); } // web支持撤回消息 https://github.com/nodeWechat/wechat4u/blob/8e20b34507dbe783ada8c769b72ef1792f33c94a/src/core.js#L1219 async messageRecall(messageId) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'messageRecall(%s)', messageId); const rawPayload = await this.messageRawPayload(messageId); this.wechat4u.revokeMsg(messageId, rawPayload.ToUserName); return true; } async messageImage(messageId, imageType) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'messageImage(%s, %s[%s])', messageId, imageType, PUPPET.types.Image[imageType]); /** * 图片消息 */ // console.log('图片消息,保存到本地') const filename = `${messageId}.jpg`; const msg = await this.wechat4u.getMsgImg(messageId); const file = file_box_1.FileBox.fromStream(msg.data, filename); return file; } async messageFile(id) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'messageFile(%s)', id); const payload = await this.messagePayload(id); const rawPayload = await this.messageRawPayload(id); let filename = payload.filename || 'unknown.txt'; /** * 判断消息类型 */ switch (payload.type) { case PUPPET.types.Message.Text: /** * 文本消息 */ throw new Error('msg type is text'); case PUPPET.types.Message.Emoticon: { /** * 表情消息 */ const emotionPayload = await (0, message_emotion_js_1.parseEmotionMessagePayload)(rawPayload); const emoticonBox = file_box_1.FileBox.fromUrl(emotionPayload.cdnurl, { name: `message-${id}-emoticon.jpg` }); emoticonBox.metadata = { payload: emotionPayload, type: 'emoticon', }; return emoticonBox; } // eslint-disable-next-lint no-fallthrough case PUPPET.types.Message.Image: { /** * 图片消息 */ // console.log('图片消息,保存到本地') filename = `${rawPayload.MsgId}.jpg`; const msg = await this.wechat4u.getMsgImg(rawPayload.MsgId); const file = file_box_1.FileBox.fromBuffer(msg.data, filename); return file; } case PUPPET.types.Message.Audio: { /** * 语音消息 */ const audioFileBox = file_box_1.FileBox.fromBuffer((await this.wechat4u.getVoice(rawPayload.MsgId)).data, `message-${id}-audio.sil`); const voiceLength = rawPayload.VoiceLength; audioFileBox.metadata = { voiceLength, }; // console.log('语音消息,保存到本地') return audioFileBox; } case PUPPET.types.Message.Video: /** * 视频消息 */ // console.log('视频消息,保存到本地') return file_box_1.FileBox.fromBuffer((await this.wechat4u.getVideo(rawPayload.MsgId)).data, `message-${id}-video.mp4`); case PUPPET.types.Message.Attachment: if (rawPayload.AppMsgType === 6) { /** * 文件消息 */ // console.log('文件消息,保存到本地') filename = rawPayload.FileName; return file_box_1.FileBox.fromBuffer((await this.wechat4u.getDoc(rawPayload.FromUserName, rawPayload.MediaId, rawPayload.FileName)).data, filename); } break; default: break; } throw new Error('unsupported message. id: ' + id); } async messageUrl(messageId) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'messageUrl(%s)', messageId); const rawPayload = this.cacheMessageRawPayload.get(messageId); if (!rawPayload) { throw new Error('id not found'); } const message = await this.messageRawPayloadParser(rawPayload); if (message.type !== PUPPET.types.Message.Url) { throw new Error('Can not get url from non url payload'); } const appPayload = await (0, message_appmsg_js_1.parseAppmsgMessagePayload)(rawPayload.Content); return { description: appPayload.des, thumbnailUrl: appPayload.thumburl, title: appPayload.title, url: appPayload.url, }; } async messageMiniProgram(messageId) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'messageMiniProgram(%s)', messageId); const rawPayload = this.cacheMessageRawPayload.get(messageId); if (!rawPayload) { throw new Error('id not found'); } const message = await this.messageRawPayloadParser(rawPayload); if (message.type !== PUPPET.types.Message.MiniProgram) { throw new Error('message is not mini program, can not get MiniProgramPayload'); } return (0, message_miniprogram_js_1.parseMiniProgramMessagePayload)(rawPayload); } async messageRawPayload(id) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'messageRawPayload(%s)', id); const rawPayload = this.cacheMessageRawPayload.get(id); if (!rawPayload) { throw new Error('id not found'); } return rawPayload; } async messageRawPayloadParser(rawPayload) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'messageRawPayloadParser(%s) @ %s', rawPayload, this); // console.log(rawPayload) const payload = (0, message_js_1.webMessageToWechaty)(this, rawPayload); return payload; } async messageSendText(conversationId, text) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'messageSend(%s, %s)', conversationId, text); /** * 发送文本消息,可以包含emoji(😒)和QQ表情([坏笑]) */ await this.wechat4u.sendMsg(text, conversationId); /** * { BaseResponse: { Ret: 0, ErrMsg: '' }, * MsgID: '830582407297708303', * LocalID: '15279119663740094' } */ } async messageSendFile(conversationId, file) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'messageSend(%s, %s)', conversationId, file); /** * 通过表情MD5发送表情 */ // wechat4u.sendMsg({ // emoticonMd5: '00c801cdf69127550d93ca52c3f853ff' // }, ToUserName) // .catch(err => { // bot.emit('error', err) // }) /** * 以下通过上传文件发送图片,视频,附件等 * 通用方法为入下 * file为多种类型 * filename必填,主要为了判断文件类型 */ await this.wechat4u.sendMsg({ file: await file.toStream(), filename: file.name, }, conversationId); } async messageSendContact(conversationId, contactId) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'messageSend("%s", %s)', conversationId, contactId); PUPPET.throwUnsupportedError(); } async messageSendUrl(conversationId, urlLinkPayload) { PUPPET.throwUnsupportedError(conversationId, urlLinkPayload); } async messageSendMiniProgram(conversationId, miniProgramPayload) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'messageSendMiniProgram("%s", %s)', JSON.stringify(conversationId), JSON.stringify(miniProgramPayload)); PUPPET.throwUnsupportedError(conversationId, miniProgramPayload); } async messageForward(conversationid, messageId) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'messageForward(%s, %s)', conversationid, messageId); const rawPayload = await this.messageRawPayload(messageId); /** * 如何直接转发消息 */ await this.wechat4u.forwardMsg(rawPayload, conversationid); } async conversationReadMark(conversationId, hasRead) { return PUPPET.throwUnsupportedError(conversationId, hasRead); } /** * * Room Invitation * */ async roomInvitationAccept(roomInvitationId) { return PUPPET.throwUnsupportedError(roomInvitationId); } async roomInvitationRawPayload(roomInvitationId) { return PUPPET.throwUnsupportedError(roomInvitationId); } async roomInvitationRawPayloadParser(rawPayload) { return PUPPET.throwUnsupportedError(rawPayload); } /** * * Room * */ async roomRawPayload(id) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'roomRawPayload(%s)', id); const rawPayload = await (0, config_js_1.retry)((retryException, attempt) => { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'contactRawPayload(%s) retry() attempt=%d', id, attempt); if (!this.wechat4u.contacts[id]) { retryException(new Error('no this.wechat4u.contacts[' + id + ']')); } return this.wechat4u.contacts[id]; }); return rawPayload; } async roomRawPayloadParser(rawPayload) { return (0, room_js_1.wechat4uRoomToWechaty)(rawPayload); } async roomList() { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'roomList()'); const idList = Object.keys(this.wechat4u.contacts) .filter((contact) => this.wechat4u.Contact.isRoomContact(this.wechat4u.contacts[contact])); return idList; } async roomDel(roomId, contactId) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'roomDel(%s, %s)', roomId, contactId); const type = 'delmember'; // XXX: [contactId] or [{ UserName: id }, ...] ? await this.wechat4u.updateChatroom(roomId, [contactId], type); } async roomAvatar(roomId) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'roomAvatar(%s)', roomId); const payload = await this.roomPayload(roomId); if (payload.avatar) { // FIXME: set http headers with cookies return file_box_1.FileBox.fromUrl(payload.avatar); } wechaty_puppet_1.log.warn('PuppetWechat4u', 'roomAvatar() avatar not found, use the chatie default.'); return (0, config_js_1.qrCodeForChatie)(); } async roomAdd(roomId, contactId) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'roomAdd(%s, %s)', roomId, contactId); const roomPayload = await this.roomPayload(roomId); // TODO: if the room owner enabled "invite only?" let type = 'addmember'; // invitemember ??? if (roomPayload.memberIdList.length > 40) { type = 'invitemember'; } // https://github.com/nodeWechat/wechat4u/tree/46931e78bcb56899b8d2a42a37b919e7feaebbef#botupdatechatroomchatroomusername-memberlist-fun const ret = await this.wechat4u.updateChatroom(roomId, [contactId], type); wechaty_puppet_1.log.verbose('PuppetWechat4u', 'roomAdd(%s, %s) ret: %s', roomId, contactId, JSON.stringify(ret)); } async roomTopic(roomId, topic) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'roomTopic(%s, %s)', roomId, topic); const roomPayload = await this.roomPayload(roomId); if (typeof topic === 'undefined') { return roomPayload.topic; } await this.wechat4u.updateChatRoomName(roomId, topic); } async roomCreate(contactIdList, topic) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'roomCreate(%s, %s)', contactIdList, topic); const memberList = contactIdList.map(id => ({ UserName: id })); const roomId = await this.wechat4u.createChatroom(topic, memberList); return roomId; } async roomAnnounce(roomId, text) { return PUPPET.throwUnsupportedError(roomId, text); } async roomQuit(roomId) { return PUPPET.throwUnsupportedError(roomId); } async roomQRCode(roomId) { return PUPPET.throwUnsupportedError(roomId); } async roomMemberList(roomId) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'roommemberList(%s)', roomId); const rawPayload = await this.roomRawPayload(roomId); const memberIdList = (rawPayload.MemberList || []) .map(member => member.UserName); return memberIdList; } async roomMemberRawPayload(roomId, contactId) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'roomMemberRawPayload(%s, %s)', roomId, contactId); const rawPayload = await this.roomRawPayload(roomId); const memberPayloadList = rawPayload.MemberList || []; const memberPayloadResult = memberPayloadList.filter(payload => payload.UserName === contactId); if (memberPayloadResult.length > 0) { return memberPayloadResult[0]; } else { throw new Error('not found'); } } async roomMemberRawPayloadParser(rawPayload) { return (0, room_js_1.wechat4uRoomMemberToWechaty)(rawPayload); } /** * * Friendship * */ async friendshipSearchPhone(phone) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'friendshipSearchPhone(%s)', phone); return PUPPET.throwUnsupportedError(); } async friendshipSearchWeixin(weixin) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'friendshipSearchWeixin(%s)', weixin); return PUPPET.throwUnsupportedError(); } async friendshipAdd(contactId, hello) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'friendshipAdd(%s, %s)', contactId, hello); return PUPPET.throwUnsupportedError(); // await this.wechat4u.addFriend(contactId, hello) } async friendshipAccept(friendshipId) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'friendshipAccept(%s)', friendshipId); const payload = await this.friendshipPayload(friendshipId); await this.wechat4u.verifyUser(payload.contactId, payload.ticket); } async friendshipRawPayload(id) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'friendshipRawPayload(%s)', id); const rawPayload = this.cacheMessageRawPayload.get(id); if (!rawPayload) { throw new Error('no rawPayload'); } return rawPayload; } async friendshipRawPayloadParser(rawPayload) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'friendshipRawPayloadParser(%s)', rawPayload); const timestamp = Math.floor(Date.now() / 1000); // in seconds switch (rawPayload.MsgType) { case web_schemas_js_1.WebMessageType.VERIFYMSG: { const recommendInfo = rawPayload.RecommendInfo; if (!recommendInfo) { throw new Error('no recommendInfo'); } const payloadReceive = { contactId: recommendInfo.UserName, hello: recommendInfo.Content, id: rawPayload.MsgId, ticket: recommendInfo.Ticket, timestamp, type: PUPPET.types.Friendship.Receive, }; return payloadReceive; } case web_schemas_js_1.WebMessageType.SYS: { const payloadConfirm = { contactId: rawPayload.FromUserName, id: rawPayload.MsgId, timestamp, type: PUPPET.types.Friendship.Confirm, }; return payloadConfirm; } default: throw new Error('not supported friend request message raw payload'); } } /** * * Tag * */ async tagContactAdd(tagId, contactId) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'tagContactAdd(%s)', tagId, contactId); } async tagContactRemove(tagId, contactId) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'tagContactRemove(%s)', tagId, contactId); } async tagContactDelete(tagId) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'tagContactDelete(%s)', tagId); } async tagContactList(contactId) { wechaty_puppet_1.log.verbose('PuppetWechat4u', 'tagContactList(%s)', contactId); return []; } contactCorporationRemark(..._) { return PUPPET.throwUnsupportedError(); } contactDescription(..._) { return PUPPET.throwUnsupportedError(); } contactPhone(..._) { return PUPPET.throwUnsupportedError(); } async messageLocation(messageId) { return PUPPET.throwUnsupportedError(messageId); } async messageSendLocation(conversationId, locationPayload) { return PUPPET.throwUnsupportedError(conversationId, locationPayload); } } exports.PuppetWechat4u = PuppetWechat4u; exports.default = PuppetWechat4u; //# sourceMappingURL=puppet-wechat4u.js.map