@juzi/wechaty
Version:
Wechaty is a RPA SDK for Chatbot Makers.
443 lines • 16.3 kB
JavaScript
"use strict";
/**
* 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.
*
*/
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;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PostImpl = exports.PostBuilder = void 0;
/**
* Issue #2245 - New Wechaty User Module (WUM):
* `Post` for supporting Moments, Channel, Tweet, Weibo, Facebook feeds, etc.
*
* @see https://github.com/wechaty/wechaty/issues/2245#issuecomment-914886835
*/
const PUPPET = __importStar(require("@juzi/wechaty-puppet"));
const wechaty_puppet_1 = require("@juzi/wechaty-puppet");
const mod_js_1 = require("../user-mixins/mod.js");
const mod_js_2 = require("../sayable/mod.js");
const contact_js_1 = require("./contact.js");
const rx_queue_1 = require("rx-queue");
class PostBuilder {
Impl;
payload;
/**
* Wechaty Sayable List
*/
sayableList = [];
/**
* Huan(202201): why use Impl as a parameter?
*/
static new(Impl) { return new this(Impl); }
constructor(Impl) {
this.Impl = Impl;
this.payload = {
sayableList: [],
type: PUPPET.types.Post.Unspecified,
};
}
add(sayable) {
this.sayableList.push(sayable);
return this;
}
type(type) {
this.payload.type = type;
return this;
}
reply(post) {
if (!post.id) {
throw new Error('can not link to a post without id: ' + JSON.stringify(post));
}
this.payload.parentId = post.payload.id;
this.payload.rootId = post.payload.rootId || post.payload.id;
return this;
}
location(location) {
this.payload.location = {
...location.payload,
};
}
visible(contactList) {
const contactIds = contactList.map(contact => {
if (!contact_js_1.ContactImpl.valid(contact)) {
wechaty_puppet_1.log.warn(`expect contact instance but ${contact} is not a contact`);
return '';
}
return contact.id;
});
this.payload.visibleList = contactIds.filter(id => !!id);
}
async build() {
const sayablePayloadListNested = await Promise.all(this.sayableList.map(mod_js_2.sayableToPayload));
this.payload.sayableList = sayablePayloadListNested.filter(Boolean);
return this.Impl.create(this.payload);
}
}
exports.PostBuilder = PostBuilder;
class PostMixin extends (0, mod_js_1.wechatifyMixinBase)() {
static builder() { return PostBuilder.new(this); }
/**
*
* Create
*
*/
static create(payload) {
wechaty_puppet_1.log.verbose('Post', 'create()');
return new this(payload);
}
static load(id) {
wechaty_puppet_1.log.verbose('Post', 'static load(%s)', id);
/**
* Must NOT use `Post` at here
* MUST use `this` at here
*
* because the class will be `cloneClass`-ed
*/
const post = new this(id);
return post;
}
static async find(filter) {
wechaty_puppet_1.log.verbose('Post', 'find(%s)', JSON.stringify(filter));
if (filter.id) {
const post = this.wechaty.Post.load(filter.id);
await post.ready();
return post;
}
const [postList] = await this.findAll(filter, { pageSize: 1 });
if (postList.length > 0) {
return postList[0];
}
return undefined;
}
static async findAll(filter, pagination) {
wechaty_puppet_1.log.verbose('Post', 'findAll(%s%s)', JSON.stringify(filter), pagination ? ', ' + JSON.stringify(pagination) : '');
const { nextPageToken, response: postIdList, } = await this.wechaty.puppet.postSearch(filter, pagination);
const idToPost = async (id) => this.wechaty.Post.find({ id })
.catch(e => this.wechaty.emitError(e));
/**
* we need to use concurrencyExecuter to reduce the parallel number of the requests
*/
const CONCURRENCY = 17;
const postIterator = (0, rx_queue_1.concurrencyExecuter)(CONCURRENCY)(idToPost)(postIdList);
const postList = [];
for await (const post of postIterator) {
if (post) {
postList.push(post);
}
}
return [postList, nextPageToken];
}
_payload;
get payload() {
if (!this._payload) {
throw new Error('no payload, need to call `ready()` first.');
}
return this._payload;
}
id;
/*
* @hideconstructor
*/
constructor(idOrPayload) {
super();
wechaty_puppet_1.log.verbose('Post', 'constructor(%s)', typeof idOrPayload === 'string'
? idOrPayload
: JSON.stringify(idOrPayload.id));
if (typeof idOrPayload === 'string') {
this.id = idOrPayload;
}
else {
this._payload = idOrPayload;
this.id = idOrPayload.id;
}
}
counter() {
return {
children: 0,
descendant: 0,
taps: {},
...(PUPPET.payloads.isPostServer(this.payload) && this.payload.counter),
};
}
async author() {
wechaty_puppet_1.log.silly('Post', 'author()');
if (PUPPET.payloads.isPostClient(this.payload)) {
return this.wechaty.currentUser;
}
const author = await this.wechaty.Contact.find({ id: this.payload.contactId });
if (!author) {
throw new Error('no author for id: ' + this.payload.contactId);
}
return author;
}
async root() {
wechaty_puppet_1.log.silly('Post', 'root()');
if (!this.payload.rootId) {
return undefined;
}
const post = this.wechaty.Post.load(this.payload.rootId);
await post.ready();
return post;
}
async parent() {
wechaty_puppet_1.log.silly('Post', 'parent()');
if (!this.payload.parentId) {
return undefined;
}
const post = this.wechaty.Post.load(this.payload.parentId);
await post.ready();
return post;
}
async sync() {
wechaty_puppet_1.log.silly('Post', 'sync()');
if (!this.id) {
throw new Error('no post id found');
}
this._payload = await this.wechaty.puppet.postPayload(this.id);
}
async ready() {
wechaty_puppet_1.log.silly('Post', 'ready()');
if (!this.id) {
throw new Error('no post id found');
}
if (this._payload) {
return;
}
await this.sync();
}
async *[Symbol.asyncIterator]() {
wechaty_puppet_1.log.verbose('Post', '[Symbol.asyncIterator]()');
const payloadToSayable = (0, mod_js_2.payloadToSayableWechaty)(this.wechaty);
if (PUPPET.payloads.isPostServer(this.payload)) {
for (const sayableId of this.payload.sayableList) {
const sayable = await this.getSayableWithId(sayableId);
if (sayable) {
yield sayable;
}
}
}
else { // client
for (const sayablePayload of this.payload.sayableList) {
const sayable = await payloadToSayable(sayablePayload);
if (sayable) {
yield sayable;
}
}
}
}
async getSayableWithIndex(sayableIndex) {
wechaty_puppet_1.log.verbose('Post', 'getSayableWithIndex(%s)', sayableIndex);
const payloadToSayable = (0, mod_js_2.payloadToSayableWechaty)(this.wechaty);
if (PUPPET.payloads.isPostServer(this.payload)) {
const sayablePayload = await this.wechaty.puppet.postPayloadSayable(this.id, this.payload.sayableList[sayableIndex]);
const sayable = await payloadToSayable(sayablePayload);
return sayable;
}
else {
const sayablePayload = this.payload.sayableList[sayableIndex];
if (sayablePayload) {
const sayable = await payloadToSayable(sayablePayload);
return sayable;
}
else {
throw new Error(`post has no sayable with index ${sayableIndex}`);
}
}
}
async getSayableWithId(id) {
wechaty_puppet_1.log.verbose('Post', 'getSayableWithId(%s)', id);
if (PUPPET.payloads.isPostServer(this.payload)) {
const payloadToSayable = (0, mod_js_2.payloadToSayableWechaty)(this.wechaty);
const sayablePayload = await this.wechaty.puppet.postPayloadSayable(this.id, id);
const sayable = await payloadToSayable(sayablePayload);
return sayable;
}
else {
throw new Error('client post sayable has no Id');
}
}
async *children(filter = {}) {
wechaty_puppet_1.log.verbose('Post', '*children(%s)', Object.keys(filter).length ? JSON.stringify(filter) : '');
const pagination = {
pageSize: 100,
};
const parentIdFilter = {
...filter,
parentId: this.id,
};
let [postList, nextPageToken] = await this.wechaty.Post.findAll(parentIdFilter, pagination);
while (true) {
yield* postList;
postList.length = 0;
if (!nextPageToken) {
break;
}
[postList, nextPageToken] = await this.wechaty.Post.findAll(parentIdFilter, {
...pagination,
pageToken: nextPageToken,
});
}
}
async *descendants(filter = {}) {
wechaty_puppet_1.log.verbose('Post', '*descendants(%s)', Object.keys(filter).length ? JSON.stringify(filter) : '');
for await (const post of this.children(filter)) {
yield post;
yield* post.descendants(filter);
}
}
async *likes(filter = {}) {
wechaty_puppet_1.log.verbose('Post', '*likes(%s)', Object.keys(filter).length ? JSON.stringify(filter) : '');
return this.taps({
...filter,
type: PUPPET.types.Tap.Like,
});
}
async *taps(filter = {}) {
wechaty_puppet_1.log.verbose('Post', '*taps(%s)', Object.keys(filter).length ? JSON.stringify(filter) : '');
const pagination = {};
let [tapList, nextPageToken] = await this.tapFind(filter, pagination);
while (true) {
yield* tapList;
tapList.length = 0;
if (!nextPageToken) {
break;
}
[tapList, nextPageToken] = await this.tapFind(filter, { ...pagination, pageToken: nextPageToken });
}
}
async reply(sayable) {
wechaty_puppet_1.log.verbose('Post', 'reply(%s)', sayable);
if (!this.id) {
console.error('You can only call `reply()` on received posts, but it seems that you are trying to call reply on a post created from local.');
throw new Error('no post id found');
}
const builder = this.wechaty.Post.builder();
if (Array.isArray(sayable)) {
sayable.forEach(s => builder.add(s));
}
else {
builder.add(sayable);
}
const post = await builder
.reply(this)
.build();
const postId = await this.wechaty.puppet.postPublish(post.payload);
if (postId) {
const newPost = this.wechaty.Post.load(postId);
await newPost.ready();
return newPost;
}
}
async like(status) {
wechaty_puppet_1.log.verbose('Post', 'like(%s)', typeof status === 'undefined' ? '' : status);
if (typeof status === 'undefined') {
return this.tap(PUPPET.types.Tap.Like);
}
else {
return this.tap(PUPPET.types.Tap.Like, status);
}
}
async tap(type, status) {
wechaty_puppet_1.log.verbose('Post', 'tap(%s%s)', PUPPET.types.Tap[type], typeof status === 'undefined'
? ''
: ', ' + status);
if (!this.id) {
throw new Error('can not tap for post without id');
}
return this.wechaty.puppet.tap(this.id, type, status);
}
async tapFind(filter, pagination) {
wechaty_puppet_1.log.verbose('Post', 'tapFind()');
if (!this.id) {
throw new Error('can not get tapFind for client created post');
}
const { nextPageToken, response, } = await this.wechaty.puppet.tapSearch(this.id, filter, pagination);
const tapList = [];
for (const [type, data] of Object.entries(response)) {
for (const [i, contactId] of data.contactId.entries()) {
const contact = await this.wechaty.Contact.find({ id: contactId });
if (!contact) {
wechaty_puppet_1.log.warn('Post', 'tapFind() contact not found for id: %s', contactId);
continue;
}
const timestamp = data.timestamp[i];
const date = timestamp ? new Date(timestamp) : new Date();
tapList.push({
contact,
date,
type: Number(type),
});
}
}
return [tapList, nextPageToken];
}
location() {
wechaty_puppet_1.log.verbose('Post', 'location()');
if (!this.payload.location) {
wechaty_puppet_1.log.warn('this post has no location info');
return;
}
return new this.wechaty.Location(this.payload.location);
}
async visibleList() {
wechaty_puppet_1.log.verbose('Post', 'visibleList()');
if (!this.payload.visibleList) {
return [];
}
const contactIdList = this.payload.visibleList;
const idToContact = async (id) => this.wechaty.Contact.find({ id }).catch(e => this.wechaty.emitError(e));
/**
* we need to use concurrencyExecuter to reduce the parallel number of the requests
*/
const CONCURRENCY = 17;
const contactIterator = (0, rx_queue_1.concurrencyExecuter)(CONCURRENCY)(idToContact)(contactIdList);
const contactList = [];
for await (const contact of contactIterator) {
if (contact) {
contactList.push(contact);
}
}
return contactList;
}
}
class PostImpl extends (0, mod_js_1.validationMixin)(PostMixin)() {
}
exports.PostImpl = PostImpl;
//# sourceMappingURL=post.js.map