@juzi/wechaty
Version:
Wechaty is a RPA SDK for Chatbot Makers.
217 lines • 7.39 kB
JavaScript
/**
* 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 { StateSwitch } from 'state-switch';
import { PuppetServer, } from '@juzi/wechaty-puppet-service';
import { DISABLE_IO_WS, log, } from './config.js';
import { Io } from './io.js';
const DEFAULT_IO_CLIENT_OPTIONS = {
port: 8788,
};
export class IoClient {
/**
* Huan(20161026): keep io `null-able` or not?
* Huan(202002): make it optional.
*/
io;
puppetServer;
state;
options;
constructor(options) {
log.verbose('IoClient', 'constructor({%s})', Object.keys(options)
.map(key => {
return `${key}:${options[key]}`;
})
.reduce((acc, cur) => `${acc}, ${cur}`));
const normalizedOptions = {
...DEFAULT_IO_CLIENT_OPTIONS,
...options,
};
this.options = normalizedOptions;
this.state = new StateSwitch('IoClient', { log });
}
async startPuppetServer() {
log.verbose('IoClient', 'startPuppetServer()');
if (this.puppetServer) {
throw new Error('puppet server exists');
}
const options = {
endpoint: '0.0.0.0:' + this.options.port,
/**
* Huan(202110): FIXME: remove the any
* by updating the puppet-service server code
* to use PuppetInterface
*/
puppet: this.options.wechaty.puppet,
token: this.options.token,
};
this.puppetServer = new PuppetServer(options);
await this.puppetServer.start();
}
async stopPuppetServer() {
log.verbose('IoClient', 'stopPuppetServer()');
if (!this.puppetServer) {
log.error('IoClient', 'stopPuppetServer() this.puppetServer is `undefined`');
return;
}
await this.puppetServer.stop();
this.puppetServer = undefined;
}
async start() {
log.verbose('IoClient', 'start()');
if (this.state.active()) {
log.warn('IoClient', 'start() with a on state, wait and return');
await this.state.stable('active');
return;
}
this.state.active('pending');
try {
await this.hookWechaty(this.options.wechaty);
if (!DISABLE_IO_WS) {
await this.startIo();
}
await this.options.wechaty.start();
await this.startPuppetServer();
this.state.active(true);
}
catch (e) {
log.error('IoClient', 'start() exception: %s', e.message);
this.state.inactive(true);
throw e;
}
}
async hookWechaty(wechaty) {
log.verbose('IoClient', 'hookWechaty()');
if (this.state.inactive()) {
const e = new Error('state.off() is true, skipped');
log.warn('IoClient', 'initWechaty() %s', e.message);
throw e;
}
wechaty
.on('login', user => log.info('IoClient', `${user.name()} logged in`))
.on('logout', user => log.info('IoClient', `${user.name()} logged out`))
.on('message', msg => this.onMessage(msg))
.on('scan', (url, code) => {
log.info('IoClient', [
`[${code}] ${url}`,
`Online QR Code Image: https://wechaty.js.org/qrcode/${encodeURIComponent(url)}`,
].join('\n'));
});
}
async startIo() {
log.verbose('IoClient', 'startIo() with token %s', this.options.token);
if (this.state.inactive()) {
const e = new Error('startIo() state.off() is true, skipped');
log.warn('IoClient', e.message);
throw e;
}
if (this.io) {
throw new Error('io exists');
}
this.io = new Io({
servicePort: this.options.port,
token: this.options.token,
wechaty: this.options.wechaty,
});
try {
await this.io.start();
}
catch (e) {
log.verbose('IoClient', 'startIo() init fail: %s', e.message);
throw e;
}
}
async stopIo() {
log.verbose('IoClient', 'stopIo()');
if (!this.io) {
log.warn('IoClient', 'stopIo() io does not exist');
return;
}
await this.io.stop();
this.io = undefined;
}
async onMessage(msg) {
log.verbose('IoClient', 'onMessage(%s)', msg);
// const from = m.from()
// const to = m.to()
// const content = m.toString()
// const room = m.room()
// log.info('Bot', '%s<%s>:%s'
// , (room ? '['+room.topic()+']' : '')
// , from.name()
// , m.toStringDigest()
// )
// if (/^wechaty|chatie|botie/i.test(m.text()) && !m.self()) {
// await m.say('https://www.chatie.io')
// .then(_ => log.info('Bot', 'REPLIED to magic word "chatie"'))
// }
}
async stop() {
log.verbose('IoClient', 'stop()');
this.state.inactive('pending');
if (!DISABLE_IO_WS) {
await this.stopIo();
}
await this.stopPuppetServer();
await this.options.wechaty.stop();
this.state.inactive(true);
// XXX 20161026
// this.io = null
}
async restart() {
log.verbose('IoClient', 'restart()');
try {
await this.stop();
await this.start();
}
catch (e) {
log.error('IoClient', 'restart() exception %s', e.message);
throw e;
}
}
async quit() {
log.verbose('IoClient', 'quit()');
if (this.state.inactive() === 'pending') {
log.warn('IoClient', 'quit() with state.off() = `pending`, skipped');
throw new Error('quit() with state.off() = `pending`');
}
this.state.inactive('pending');
try {
// if (this.options.wechaty) {
await this.options.wechaty.stop();
// this.wechaty = null
// } else { log.warn('IoClient', 'quit() no this.wechaty') }
if (this.io) {
await this.io.stop();
// this.io = null
}
else {
log.warn('IoClient', 'quit() no this.io');
}
}
catch (e) {
log.error('IoClient', 'exception: %s', e.message);
throw e;
}
finally {
this.state.inactive(true);
}
}
}
//# sourceMappingURL=io-client.js.map