UNPKG

@juzi/wechaty

Version:

Wechaty is a RPA SDK for Chatbot Makers.

312 lines 11 kB
/** * Wechaty Chatbot SDK - https://github.com/wechaty/wechaty * * @copyright 2016 Huan LI (李卓桓) <https://github.com/huan>, and * Wechaty Contributors <https://github.com/wechaty>. * * 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. * */ import * as PUPPET from '@juzi/wechaty-puppet'; import { concurrencyExecuter } from 'rx-queue'; import { log } from '../config.js'; import { poolifyMixin } from '../user-mixins/poolify.js'; import assert from 'assert'; import { validationMixin } from '../user-mixins/validation.js'; import { wechatifyMixin, } from '../user-mixins/wechatify.js'; const MixinBase = wechatifyMixin(poolifyMixin(Object)()); class TagMixin extends MixinBase { id; /** * * Instance properties * @ignore * */ payload; /** * @hideconstructor */ constructor(id) { super(); this.id = id; log.silly('Tag', 'constructor()'); } type() { return (this.payload && this.payload.type) || PUPPET.types.Tag.Unspecific; } name() { return (this.payload && this.payload.name) || ''; } groupId() { return (this.payload && this.payload.groupId) || ''; } async group() { return this.payload?.groupId ? this.wechaty.TagGroup.find({ id: this.payload.groupId }) : undefined; } static async list() { log.verbose('Tag', 'list()'); const tagIdList = await this.wechaty.puppet.tagTagList(); let continuousErrorCount = 0; let totalErrorCount = 0; const totalErrorThreshold = Math.round(tagIdList.length / 5); const idToTag = async (id) => { if (!this.wechaty.isLoggedIn) { throw new Error('wechaty not logged in'); } const result = this.find({ id }).catch(e => { this.wechaty.emitError(e); continuousErrorCount++; totalErrorCount++; if (continuousErrorCount > 5) { throw new Error('5 continuous errors!'); } if (totalErrorCount > totalErrorThreshold) { throw new Error(`${totalErrorThreshold} total errors!`); } }); continuousErrorCount = 0; return result; }; const CONCURRENCY = 17; const tagIterator = concurrencyExecuter(CONCURRENCY)(idToTag)(tagIdList); const tagList = []; for await (const tag of tagIterator) { if (tag) { tagList.push(tag); } } return tagList; } static async find(filter) { log.silly('Tag', 'find(%s)', JSON.stringify(filter)); if (filter.id) { const tag = this.wechaty.Tag.load(filter.id); try { await tag.ready(); } catch (e) { this.wechaty.emitError(e); return undefined; } return tag; } if (filter.name) { const tags = (await this.wechaty.Tag.list()).filter(t => t.name() === filter.name); if (tags.length > 0) { return tags[0]; } } return undefined; // TODO: use a puppet method to find tag, like how contact and room do it } static async findMulti(filters) { log.silly('Tag', 'find(%s)', JSON.stringify(filters)); const filterIdList = filters.filter(i => !!i.id).map(i => i.id); const filterNameList = filters.filter(i => !!i.name).map(i => i.name); const resultSet = new Set(); if (filterIdList.length) { const tags = filterIdList.map(i => { assert(i, 'Should not be undefined'); return this.wechaty.Tag.load(i); }); try { await Promise.all(tags.map(i => i.ready())); } catch (e) { this.wechaty.emitError(e); return undefined; } for (const tag of tags) { resultSet.add(tag); } } if (filterNameList.length) { const list = await this.wechaty.Tag.list(); const tagMap = new Map(); // FIXME: There are two tag types in wework, and the names can be repeated list.forEach(i => tagMap.set(i.name(), i)); for (const name of filterNameList) { assert(typeof name === 'string', 'Only supported string'); const tag = tagMap.get(name); if (tag) { resultSet.add(tag); } } } return resultSet.size ? Array.from(resultSet) : undefined; // TODO: use a puppet method to find tag, like how contact and room do it } /** * Force reload data for Tag, Sync data from low-level API again. * * @returns {Promise<this>} * @example * await tag.sync() */ async sync() { await this.wechaty.puppet.tagPayloadDirty(this.id); await this.ready(true); } /** * @ignore */ isReady() { return !!(this.payload && this.payload.name); } /** * `ready()` is For FrameWork ONLY! * * Please not to use `ready()` at the user land. * If you want to sync data, use `sync()` instead. * * @ignore */ async ready(forceSync = false) { log.silly('Tag', 'ready() @ %s with Tag key="%s"', this.wechaty.puppet, this.id); if (!forceSync && this.isReady()) { // already ready log.silly('Tag', 'ready() isReady() true'); return; } try { this.payload = await this.wechaty.puppet.tagPayload(this.id); } catch (e) { this.wechaty.emitError(e); log.verbose('Tag', 'ready() this.wechaty.puppet.tagPayload(%s) exception: %s', this.id, e.message); throw e; } } async contactList() { log.verbose('Tag', 'contactList() for tag : %s', this); const contactIds = await this.wechaty.puppet.tagTagContactList(this.id); const contactPromises = contactIds.map(id => this.wechaty.Contact.find({ id })); return (await Promise.all(contactPromises)).filter(contact => !!contact); } async tag(contacts) { log.verbose('Tag', 'tag(%s) for tag : %s', contacts, this); let contactIds; if (Array.isArray(contacts)) { contactIds = contacts.map(c => c.id); } else { contactIds = [contacts.id]; } await this.wechaty.puppet.tagContactTagAdd([this.id], contactIds); } static async createTag(name, tagGroup) { log.verbose('Tag', 'createTag(%s, %s)', tagGroup, name); try { const tagInfoList = await this.wechaty.puppet.tagTagAdd([name], tagGroup?.name()); if (tagInfoList?.length) { const filter = { id: tagInfoList[0]?.id, }; const newTag = await this.find(filter); return newTag; } } catch (e) { this.wechaty.emitError(e); log.error('Tag', 'createTag() exception: %s', e.message); } } static async createMultiTag(nameList, tagGroup) { log.verbose('Tag', 'createMultiTag(%s, %s)', tagGroup, nameList); try { const tagInfoList = await this.wechaty.puppet.tagTagAdd(nameList, tagGroup?.name()); if (tagInfoList?.length) { const filterList = tagInfoList.map(i => ({ id: i.id, })); const newTagList = await this.findMulti(filterList); return newTagList; } } catch (e) { this.wechaty.emitError(e); log.error('Tag', 'createMultiTag() exception: %s', e.message); } } static async deleteTag(tagInstance) { log.verbose('Tag', 'deleteTag(%s, %s)', tagInstance); try { await this.wechaty.puppet.tagTagDelete([tagInstance.id]); } catch (e) { this.wechaty.emitError(e); log.error('Tag', 'deleteTag() exception: %s', e.message); } } static async deleteMultiTag(tagInstances) { log.verbose('Tag', 'deleteMultiTag(%s, %s)', tagInstances); try { await this.wechaty.puppet.tagTagDelete(tagInstances.map(i => i.id)); } catch (e) { this.wechaty.emitError(e); log.error('Tag', 'deleteMultiTag() exception: %s', e.message); } } static async modifyTag(tagInstance, tagNewName) { log.verbose('Tag', 'modifyTag(%s, %s)', tagInstance); try { const tagNewInfo = { id: tagInstance.id, name: tagNewName, }; const tagInfoList = await this.wechaty.puppet.tagTagModify([tagNewInfo]); if (tagInfoList?.length) { const filter = { id: tagInfoList[0]?.id, }; const newTag = await this.find(filter); return newTag; } } catch (e) { this.wechaty.emitError(e); log.error('Tag', 'modifyTag() exception: %s', e.message); } } static async modifyMultiTag(tagInfos) { log.verbose('Tag', 'modifyMultiTag(%o)', tagInfos); try { const tagNewInfoList = tagInfos.map(i => ({ id: i.tag.id, name: i.newName, })); const tagInfoList = await this.wechaty.puppet.tagTagModify(tagNewInfoList); if (tagInfoList?.length) { const filterList = tagInfoList.map(i => ({ id: i.id, })); const newTagList = await this.findMulti(filterList); return newTagList; } } catch (e) { this.wechaty.emitError(e); log.error('Tag', 'modifyMultiTag() exception: %s', e.message); } } toString() { return `<Tag#${this.name() || this.id}>`; } } class TagImplBase extends validationMixin(TagMixin)() { } class TagImpl extends validationMixin(TagImplBase)() { } export { TagImpl, }; //# sourceMappingURL=tag.js.map