UNPKG

wechaty-puppet

Version:

Abstract Puppet for Wechaty

162 lines 7.18 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.roomMixin = void 0; const config_js_1 = require("../config.js"); const dirty_js_1 = require("../schemas/dirty.js"); const roomMixin = (mixinBase) => { class RoomMixin extends mixinBase { constructor(...args) { super(...args); config_js_1.log.verbose('PuppetRoomMixin', 'constructor()'); } async roomSearch(query) { config_js_1.log.verbose('PuppetRoomMixin', 'roomSearch(%s)', query ? JSON.stringify(query) : ''); /** * Huan(202110): optimize for search id */ if (query?.id) { try { // make sure the room id has valid payload await this.roomPayload(query.id); return [query.id]; } catch (e) { config_js_1.log.verbose('PuppetRoomMixin', 'roomSearch() payload not found for id "%s"', query.id); await this.roomPayloadDirty(query.id); return []; } } /** * Deal with non-id queries */ const allRoomIdList = await this.roomList(); config_js_1.log.silly('PuppetRoomMixin', 'roomSearch() allRoomIdList.length=%d', allRoomIdList.length); if (!query || Object.keys(query).length <= 0) { return allRoomIdList; } const roomPayloadList = []; const BATCH_SIZE = 10; let batchIndex = 0; while (batchIndex * BATCH_SIZE < allRoomIdList.length) { const batchRoomIds = allRoomIdList.slice(BATCH_SIZE * batchIndex, BATCH_SIZE * (batchIndex + 1)); /** * Huan(202110): TODO: use an iterator with works to control the concurrency of Promise.all. * @see https://stackoverflow.com/a/51020535/1123955 */ const batchPayloads = (await Promise.all(batchRoomIds.map(async (id) => { try { return await this.roomPayload(id); } catch (e) { // log.silly('PuppetRoomMixin', 'roomSearch() roomPayload exception: %s', (e as Error).message) this.emit('error', e); // Remove invalid room id from cache to avoid getting invalid room payload again await this.roomPayloadDirty(id); await this.roomMemberPayloadDirty(id); // compatible with {} payload return {}; } }))).filter(payload => Object.keys(payload).length > 0); roomPayloadList.push(...batchPayloads); batchIndex++; } const filterFunction = this.roomQueryFilterFactory(query); const roomIdList = roomPayloadList .filter(filterFunction) .map(payload => payload.id); config_js_1.log.silly('PuppetRoomMixin', 'roomSearch() roomIdList filtered. result length=%d', roomIdList.length); return roomIdList; } /** * Issue #155 - https://github.com/wechaty/puppet/issues/155 * * @protected */ roomQueryFilterFactory(query) { config_js_1.log.verbose('PuppetRoomMixin', 'roomQueryFilterFactory(%s)', JSON.stringify(query)); if (Object.keys(query).length < 1) { throw new Error('query must provide at least one key. current query is empty.'); } else if (Object.keys(query).length > 1) { throw new Error('query only support one key. multi key support is not available now.'); } // Huan(202105): we use `Object.keys(query)[0]!` with `!` at here because we have the above `if` checks // TypeScript bug: have to set `undefined | string | RegExp` at here, or the later code type check will get error const filterKey = Object.keys(query)[0].toLowerCase(); const isValid = [ 'topic', 'id', ].includes(filterKey); if (!isValid) { throw new Error('query key unknown: ' + filterKey); } const filterValue = query[filterKey]; if (!filterValue) { throw new Error('filterValue not found for filterKey: ' + filterKey); } let filterFunction; if (filterValue instanceof RegExp) { filterFunction = (payload) => filterValue.test(payload[filterKey]); } else { // if (typeof filterValue === 'string') { filterFunction = (payload) => filterValue === payload[filterKey]; } return filterFunction; } /** * Check a Room Id if it's still valid. * For example: talk to the server, and see if it should be deleted in the local cache. */ async roomValidate(roomId) { config_js_1.log.silly('PuppetRoomMixin', 'roomValidate(%s) base class just return `true`', roomId); return true; } /** * Issue #155 - https://github.com/wechaty/puppet/issues/155 * * @protected */ roomPayloadCache(roomId) { // log.silly('PuppetRoomMixin', 'roomPayloadCache(id=%s) @ %s', roomId, this) if (!roomId) { throw new Error('no id'); } const cachedPayload = this.cache.room.get(roomId); if (cachedPayload) { // log.silly('PuppetRoomMixin', 'roomPayloadCache(%s) cache HIT', roomId) } else { config_js_1.log.silly('PuppetRoomMixin', 'roomPayloadCache(%s) cache MISS', roomId); } return cachedPayload; } async roomPayload(roomId) { config_js_1.log.verbose('PuppetRoomMixin', 'roomPayload(%s)', roomId); if (!roomId) { throw new Error('no id'); } /** * 1. Try to get from cache first */ const cachedPayload = this.roomPayloadCache(roomId); if (cachedPayload) { return cachedPayload; } /** * 2. Cache not found */ const rawPayload = await this.roomRawPayload(roomId); const payload = await this.roomRawPayloadParser(rawPayload); this.cache.room.set(roomId, payload); config_js_1.log.silly('PuppetRoomMixin', 'roomPayload(%s) cache SET', roomId); return payload; } async roomPayloadDirty(id) { config_js_1.log.verbose('PuppetRoomMixin', 'roomPayloadDirty(%s)', id); await this.__dirtyPayloadAwait(dirty_js_1.DirtyType.Room, id); } } return RoomMixin; }; exports.roomMixin = roomMixin; //# sourceMappingURL=room-mixin.js.map