提交 e41662d5 编写于 作者: Huan (李卓桓)'s avatar Huan (李卓桓)

rename PuppetWeb to PuppetPuppeteer for better naming

上级 7602ce1a
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
"wechaty": { "wechaty": {
"DEFAULT_HEAD": 0, "DEFAULT_HEAD": 0,
"DEFAULT_PORT": 8080, "DEFAULT_PORT": 8080,
"DEFAULT_PUPPET": "web", "DEFAULT_PUPPET": "puppeteer",
"DEFAULT_PROFILE": "demo", "DEFAULT_PROFILE": "demo",
"DEFAULT_PROTOCOL": "io|0.0.1", "DEFAULT_PROTOCOL": "io|0.0.1",
"DEFAULT_TOKEN": "WECHATY_IO_TOKEN", "DEFAULT_TOKEN": "WECHATY_IO_TOKEN",
...@@ -124,7 +124,7 @@ ...@@ -124,7 +124,7 @@
"@types/fluent-ffmpeg": "^2.1.0", "@types/fluent-ffmpeg": "^2.1.0",
"@types/glob": "^5.0.0p", "@types/glob": "^5.0.0p",
"@types/mime": "^2.0.0", "@types/mime": "^2.0.0",
"@types/node": "^10.0.0", "@types/node": "^9.6.7",
"@types/puppeteer": "^1.0.0", "@types/puppeteer": "^1.0.0",
"@types/raven": "^2.1.0", "@types/raven": "^2.1.0",
"@types/read-pkg-up": "^3.0.0", "@types/read-pkg-up": "^3.0.0",
......
...@@ -21,9 +21,9 @@ import { ...@@ -21,9 +21,9 @@ import {
log, log,
Sayable, Sayable,
} from '../config' } from '../config'
import PuppetAccessory from '../puppet-accessory'
import Message from './message' import Message from './message'
import PuppetAccessory from './puppet-accessory'
/** /**
* Enum for Gender values. * Enum for Gender values.
...@@ -51,7 +51,7 @@ export interface ContactQueryFilter { ...@@ -51,7 +51,7 @@ export interface ContactQueryFilter {
* [Examples/Contact-Bot]{@link https://github.com/Chatie/wechaty/blob/master/examples/contact-bot.ts} * [Examples/Contact-Bot]{@link https://github.com/Chatie/wechaty/blob/master/examples/contact-bot.ts}
*/ */
export abstract class Contact extends PuppetAccessory implements Sayable { export abstract class Contact extends PuppetAccessory implements Sayable {
private static pool = new Map<string, Contact>() protected static readonly pool = new Map<string, Contact>()
/** /**
* @private * @private
......
...@@ -18,13 +18,13 @@ ...@@ -18,13 +18,13 @@
* *
*/ */
import Contact from '../abstract-puppet/contact' import PuppetAccessory from '../puppet-accessory'
import { import {
// config, // config,
// log, // log,
} from './config' } from './config'
import PuppetAccessory from './puppet-accessory' import Contact from './contact'
/** /**
* Send, receive friend request, and friend confirmation events. * Send, receive friend request, and friend confirmation events.
......
...@@ -10,13 +10,10 @@ export { ...@@ -10,13 +10,10 @@ export {
} from './message' } from './message'
export { export {
Puppet, Puppet,
PuppetEvent, PuppetEventName,
PuppetOptions, PuppetOptions,
ScanData, ScanData,
} from './puppet' } from './puppet'
export {
PuppetAccessory,
} from './puppet-accessory'
export { export {
Room, Room,
RoomMemberQueryFilter, RoomMemberQueryFilter,
......
...@@ -23,16 +23,16 @@ import { ...@@ -23,16 +23,16 @@ import {
import { import {
MsgType, MsgType,
AppMsgType, AppMsgType,
} from '../puppet-web/schema' } from '../puppet-puppeteer/schema'
import { import {
log, log,
Sayable, Sayable,
} from '../config' } from '../config'
import PuppetAccessory from '../puppet-accessory'
import Contact from './contact' import Contact from './contact'
import Room from './room' import Room from './room'
import PuppetAccessory from './puppet-accessory'
/** /**
* All wechat messages will be encapsulated as a Message. * All wechat messages will be encapsulated as a Message.
...@@ -42,7 +42,7 @@ import PuppetAccessory from './puppet-accessory' ...@@ -42,7 +42,7 @@ import PuppetAccessory from './puppet-accessory'
*/ */
export abstract class Message extends PuppetAccessory implements Sayable { export abstract class Message extends PuppetAccessory implements Sayable {
// tslint:disable-next-line:variable-name // tslint:disable-next-line:variable-name
public static Type = MsgType public static readonly Type = MsgType
/** /**
* @private * @private
......
#!/usr/bin/env ts-node
/**
* 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.
*
*/
// tslint:disable:no-shadowed-variable
import * as test from 'blue-tape'
// import * as sinon from 'sinon'
import PuppetWeb from '../puppet-web/'
import Profile from '../profile'
import Wechaty from '../wechaty'
test('Puppet smoke testing', async t => {
const profile = new Profile(Math.random().toString(36).substr(2, 5))
const wechaty = new Wechaty()
const p = new PuppetWeb({
profile,
wechaty,
})
t.ok(p.state.off(), 'should be OFF state after instanciate')
p.state.on('pending')
t.ok(p.state.on(), 'should be ON state after set')
t.ok(p.state.pending(), 'should be pending state after set')
})
...@@ -27,11 +27,12 @@ import { ...@@ -27,11 +27,12 @@ import {
Constructor, Constructor,
} from 'clone-class' } from 'clone-class'
import { Wechaty } from '../wechaty' import {
WECHATY_EVENT_DICT,
Wechaty,
} from '../wechaty'
import { import {
Sayable, Sayable,
WechatyEvent,
log, log,
} from '../config' } from '../config'
import Profile from '../profile' import Profile from '../profile'
...@@ -54,8 +55,12 @@ export interface ScanData { ...@@ -54,8 +55,12 @@ export interface ScanData {
code: number, // Code code: number, // Code
} }
export type PuppetEvent = WechatyEvent export const PUPPET_EVENT_DICT = {
| 'watchdog' ...WECHATY_EVENT_DICT,
watchdog: 'tbw',
}
export type PuppetEventName = keyof typeof PUPPET_EVENT_DICT
export interface PuppetOptions { export interface PuppetOptions {
profile: Profile, profile: Profile,
...@@ -78,21 +83,21 @@ export interface PuppetClasses { ...@@ -78,21 +83,21 @@ export interface PuppetClasses {
* Abstract Puppet Class * Abstract Puppet Class
*/ */
export abstract class Puppet extends EventEmitter implements Sayable { export abstract class Puppet extends EventEmitter implements Sayable {
public WATCHDOG_TIMEOUT = 1 * 60 * 1000 // 1 minute public readonly WATCHDOG_TIMEOUT = 1 * 60 * 1000 // 1 minute
public user?: Contact public readonly state: StateSwitch
public readonly watchdog: Watchdog
public state: StateSwitch
public watchdog: Watchdog
// tslint:disable-next-line:variable-name // tslint:disable-next-line:variable-name
public Contact: PuppetContact public readonly Contact: PuppetContact
// tslint:disable-next-line:variable-name // tslint:disable-next-line:variable-name
public FriendRequest: PuppetFriendRequest public readonly FriendRequest: PuppetFriendRequest
// tslint:disable-next-line:variable-name // tslint:disable-next-line:variable-name
public Message: PuppetMessage public readonly Message: PuppetMessage
// tslint:disable-next-line:variable-name // tslint:disable-next-line:variable-name
public Room: PuppetRoom public readonly Room: PuppetRoom
public user?: Contact
constructor( constructor(
public options: PuppetOptions, public options: PuppetOptions,
...@@ -133,7 +138,7 @@ export abstract class Puppet extends EventEmitter implements Sayable { ...@@ -133,7 +138,7 @@ export abstract class Puppet extends EventEmitter implements Sayable {
public emit(event: never, ...args: never[]) : never public emit(event: never, ...args: never[]) : never
public emit( public emit(
event: PuppetEvent, event: PuppetEventName,
...args: any[], ...args: any[],
): boolean { ): boolean {
return super.emit(event, ...args) return super.emit(event, ...args)
...@@ -153,7 +158,7 @@ export abstract class Puppet extends EventEmitter implements Sayable { ...@@ -153,7 +158,7 @@ export abstract class Puppet extends EventEmitter implements Sayable {
public on(event: never, listener: never) : never public on(event: never, listener: never) : never
public on( public on(
event: PuppetEvent, event: PuppetEventName,
listener: (...args: any[]) => void, listener: (...args: any[]) => void,
): this { ): this {
super.on(event, listener) super.on(event, listener)
......
...@@ -23,10 +23,10 @@ import { ...@@ -23,10 +23,10 @@ import {
Sayable, Sayable,
log, log,
} from '../config' } from '../config'
import PuppetAccessory from '../puppet-accessory'
import Contact from './contact' import Contact from './contact'
import Message from './message' import Message from './message'
import PuppetAccessory from './puppet-accessory'
export type RoomEventName = 'join' export type RoomEventName = 'join'
| 'leave' | 'leave'
...@@ -49,7 +49,7 @@ export interface RoomQueryFilter { ...@@ -49,7 +49,7 @@ export interface RoomQueryFilter {
* [Examples/Room-Bot]{@link https://github.com/Chatie/wechaty/blob/master/examples/room-bot.ts} * [Examples/Room-Bot]{@link https://github.com/Chatie/wechaty/blob/master/examples/room-bot.ts}
*/ */
export abstract class Room extends PuppetAccessory implements Sayable { export abstract class Room extends PuppetAccessory implements Sayable {
protected static pool = new Map<string, Room>() protected static readonly pool = new Map<string, Room>()
/** /**
* @private * @private
......
...@@ -24,7 +24,9 @@ import * as readPkgUp from 'read-pkg-up' ...@@ -24,7 +24,9 @@ import * as readPkgUp from 'read-pkg-up'
import * as Raven from 'raven' import * as Raven from 'raven'
import { log } from 'brolog' import { log } from 'brolog'
// import Puppet from './puppet' import {
PuppetName,
} from './puppet-config'
const pkg = readPkgUp.sync({ cwd: __dirname }).pkg const pkg = readPkgUp.sync({ cwd: __dirname }).pkg
export const VERSION = pkg.version export const VERSION = pkg.version
...@@ -84,16 +86,6 @@ if (log.level() === 'verbose' || log.level() === 'silly') { ...@@ -84,16 +86,6 @@ if (log.level() === 'verbose' || log.level() === 'silly') {
}) })
} }
export type PuppetName = 'android-pad'
| 'android-phone'
| 'cat-king'
| 'hostie'
| 'ios-app-phone'
| 'ios-app-pad'
| 'mock'
| 'web'
| 'win32'
export interface DefaultSetting { export interface DefaultSetting {
DEFAULT_HEAD : number, DEFAULT_HEAD : number,
DEFAULT_PORT : number, DEFAULT_PORT : number,
...@@ -201,21 +193,6 @@ export interface Sayable { ...@@ -201,21 +193,6 @@ export interface Sayable {
say(text: string, replyTo?: any|any[]): Promise<void> say(text: string, replyTo?: any|any[]): Promise<void>
} }
export type WechatEvent = 'friend'
| 'login'
| 'logout'
| 'message'
| 'room-join'
| 'room-leave'
| 'room-topic'
| 'scan'
export type WechatyEvent = WechatEvent
| 'error'
| 'heartbeat'
| 'start'
| 'stop'
export { export {
log, log,
Raven, Raven,
......
...@@ -15,18 +15,17 @@ export { ...@@ -15,18 +15,17 @@ export {
MediaMessage, MediaMessage,
} from './deprecated' } from './deprecated'
// TODO: move MsgType to Message.Type ?
export {
MsgType,
} from './puppet-web/schema'
export { IoClient } from './io-client' export { IoClient } from './io-client'
export { Profile } from './profile' export { Profile } from './profile'
export { Misc } from './misc' export { Misc } from './misc'
export { PuppetWeb } from './puppet-web/' export {
PuppetPuppeteer,
} from './puppet-puppeteer/'
import Wechaty from './wechaty' import {
Wechaty,
} from './wechaty'
export { export {
Wechaty, Wechaty,
} }
......
...@@ -19,7 +19,9 @@ ...@@ -19,7 +19,9 @@
import * as WebSocket from 'ws' import * as WebSocket from 'ws'
import StateSwitch from 'state-switch' import StateSwitch from 'state-switch'
import PuppetWeb from './puppet-web/' import {
ScanData,
} from './abstract-puppet/'
import { import {
config, config,
...@@ -34,18 +36,22 @@ export interface IoOptions { ...@@ -34,18 +36,22 @@ export interface IoOptions {
protocol?: string, protocol?: string,
} }
type IoEventName = 'botie' export const IO_EVENT_DICT = {
| 'error' botie: 'tbw',
| 'heartbeat' error: 'tbw',
| 'login' heartbeat: 'tbw',
| 'logout' login: 'tbw',
| 'message' logout: 'tbw',
| 'update' message: 'tbw',
| 'raw' update: 'tbw',
| 'reset' raw: 'tbw',
| 'scan' reset: 'tbw',
| 'sys' scan: 'tbw',
| 'shutdown' sys: 'tbw',
shutdown: 'tbw',
}
type IoEventName = keyof typeof IO_EVENT_DICT
interface IoEvent { interface IoEvent {
name: IoEventName, name: IoEventName,
...@@ -53,19 +59,20 @@ interface IoEvent { ...@@ -53,19 +59,20 @@ interface IoEvent {
} }
export class Io { export class Io {
public cuid: string private readonly cuid : string
private readonly protocol : string
private protocol : string
private eventBuffer : IoEvent[] = [] private eventBuffer : IoEvent[] = []
private ws : WebSocket private ws : WebSocket
private state = new StateSwitch('Io', log) private readonly state = new StateSwitch('Io', log)
private reconnectTimer: NodeJS.Timer | null private reconnectTimer? : NodeJS.Timer
private reconnectTimeout: number | null private reconnectTimeout? : number
private onMessage: Function private onMessage: Function
private scanData: ScanData
constructor( constructor(
private options: IoOptions, private options: IoOptions,
) { ) {
...@@ -74,6 +81,8 @@ export class Io { ...@@ -74,6 +81,8 @@ export class Io {
this.cuid = options.wechaty.cuid this.cuid = options.wechaty.cuid
this.scanData = {} as any
this.protocol = options.protocol + '|' + options.wechaty.cuid this.protocol = options.protocol + '|' + options.wechaty.cuid
log.verbose('Io', 'instantiated with apihost[%s], token[%s], protocol[%s], cuid[%s]', log.verbose('Io', 'instantiated with apihost[%s], token[%s], protocol[%s], cuid[%s]',
options.apihost, options.apihost,
...@@ -99,7 +108,10 @@ export class Io { ...@@ -99,7 +108,10 @@ export class Io {
try { try {
await this.initEventHook() await this.initEventHook()
this.ws = this.initWebSocket() this.ws = this.initWebSocket()
this.options.wechaty.on('scan', (url, code) => {
this.scanData.url = url
this.scanData.code = code
})
this.state.on(true) this.state.on(true)
return return
...@@ -215,7 +227,7 @@ export class Io { ...@@ -215,7 +227,7 @@ export class Io {
// FIXME: how to keep alive??? // FIXME: how to keep alive???
// ws._socket.setKeepAlive(true, 100) // ws._socket.setKeepAlive(true, 100)
this.reconnectTimeout = null this.reconnectTimeout = undefined
const name = 'sys' const name = 'sys'
const payload = 'Wechaty version ' + this.options.wechaty.version() + ` with CUID: ${this.cuid}` const payload = 'Wechaty version ' + this.options.wechaty.version() + ` with CUID: ${this.cuid}`
...@@ -294,16 +306,12 @@ export class Io { ...@@ -294,16 +306,12 @@ export class Io {
this.send(loginEvent) this.send(loginEvent)
} }
const puppet = this.options.wechaty.puppet if (this.scanData) {
if (puppet instanceof PuppetWeb) { const scanEvent: IoEvent = {
const scanInfo = puppet.scanInfo name: 'scan',
if (scanInfo) { payload: this.scanData,
const scanEvent: IoEvent = {
name: 'scan',
payload: scanInfo,
}
this.send(scanEvent)
} }
this.send(scanEvent)
} }
break break
...@@ -371,7 +379,7 @@ export class Io { ...@@ -371,7 +379,7 @@ export class Io {
log.warn('Io', 'reconnect() will reconnect after %d s', Math.floor(this.reconnectTimeout / 1000)) log.warn('Io', 'reconnect() will reconnect after %d s', Math.floor(this.reconnectTimeout / 1000))
this.reconnectTimer = setTimeout(_ => { this.reconnectTimer = setTimeout(_ => {
this.reconnectTimer = null this.reconnectTimer = undefined
this.initWebSocket() this.initWebSocket()
}, this.reconnectTimeout)// as any as NodeJS.Timer }, this.reconnectTimeout)// as any as NodeJS.Timer
} }
...@@ -418,7 +426,7 @@ export class Io { ...@@ -418,7 +426,7 @@ export class Io {
if (this.reconnectTimer) { if (this.reconnectTimer) {
clearTimeout(this.reconnectTimer) clearTimeout(this.reconnectTimer)
this.reconnectTimer = null this.reconnectTimer = undefined
} }
this.ws.close() this.ws.close()
......
...@@ -21,9 +21,10 @@ ...@@ -21,9 +21,10 @@
import * as test from 'blue-tape' import * as test from 'blue-tape'
// import * as sinon from 'sinon' // import * as sinon from 'sinon'
import Puppet from './puppet'
import PuppetAccessory from './puppet-accessory' import PuppetAccessory from './puppet-accessory'
import { Puppet } from './abstract-puppet/'
const EXPECTED_PUPPET1 = {p: 1} as any as Puppet const EXPECTED_PUPPET1 = {p: 1} as any as Puppet
const EXPECTED_PUPPET2 = {p: 2} as any as Puppet const EXPECTED_PUPPET2 = {p: 2} as any as Puppet
......
import { EventEmitter } from 'events' import { EventEmitter } from 'events'
import { log } from '../config' import { log } from './config'
import { Puppet } from './puppet' import { Puppet } from './abstract-puppet/'
export abstract class PuppetAccessory extends EventEmitter { export abstract class PuppetAccessory extends EventEmitter {
......
import PuppetPuppeteer from './puppet-puppeteer/'
import PuppetMock from './puppet-mock/'
/**
* would be nice if we have a typing from package.json schema
*
* https://github.com/DefinitelyTyped/DefinitelyTyped/issues/15602
* https://github.com/Microsoft/TypeScript/issues/3136
*/
/**
* Puppet Official Plugins List
*/
export const PUPPET_DICT = {
mock: PuppetMock,
puppeteer: PuppetPuppeteer,
}
export type PuppetName = keyof typeof PUPPET_DICT
// 'android-pad'
// | 'android-phone'
// | 'cat-king'
// | 'hostie'
// | 'ios-app-phone'
// | 'ios-app-pad'
// | 'mock'
// | 'web'
// | 'win32'
...@@ -27,13 +27,12 @@ import { ...@@ -27,13 +27,12 @@ import {
import Message from '../abstract-puppet/message' import Message from '../abstract-puppet/message'
import MockContact from './mock-contact' import MockContact from './mock-contact'
import WebRoom from './mock-room' import MockRoom from './mock-room'
import { import {
MsgRawObj,
MsgType, MsgType,
AppMsgType, AppMsgType,
} from '../puppet-web/schema' } from '../puppet-puppeteer/schema'
export type ParsedPath = Partial<path.ParsedPath> export type ParsedPath = Partial<path.ParsedPath>
...@@ -41,7 +40,7 @@ export class MockMessage extends Message { ...@@ -41,7 +40,7 @@ export class MockMessage extends Message {
public readonly id: string public readonly id: string
constructor( constructor(
fileOrObj?: string | MsgRawObj, fileOrObj?: string | Object,
) { ) {
super() super()
log.silly('MockMessage', 'constructor()') log.silly('MockMessage', 'constructor()')
...@@ -65,11 +64,11 @@ export class MockMessage extends Message { ...@@ -65,11 +64,11 @@ export class MockMessage extends Message {
return loadedContact return loadedContact
} }
public room(room: WebRoom): void public room(room: MockRoom): void
public room(id: string): void public room(id: string): void
public room(): WebRoom|null public room(): MockRoom|null
public room(room?: WebRoom|string): WebRoom|null|void { public room(room?: MockRoom|string): MockRoom|null|void {
if (room) { if (room) {
return return
} }
...@@ -122,13 +121,13 @@ export class MockMessage extends Message { ...@@ -122,13 +121,13 @@ export class MockMessage extends Message {
} }
public static async find(query) { public static async find(query) {
return Promise.resolve(new MockMessage(<MsgRawObj>{MsgId: '-1'})) return Promise.resolve(new MockMessage({MsgId: '-1'}))
} }
public static async findAll(query) { public static async findAll(query) {
return Promise.resolve([ return Promise.resolve([
new MockMessage (<MsgRawObj>{MsgId: '-2'}), new MockMessage({MsgId: '-2'}),
new MockMessage (<MsgRawObj>{MsgId: '-3'}), new MockMessage({MsgId: '-3'}),
]) ])
} }
...@@ -136,7 +135,7 @@ export class MockMessage extends Message { ...@@ -136,7 +135,7 @@ export class MockMessage extends Message {
public to(id: string): void public to(id: string): void
public to(): MockContact | null // if to is not set, then room must had set public to(): MockContact | null // if to is not set, then room must had set
public to(contact?: MockContact | string): MockContact | WebRoom | null | void { public to(contact?: MockContact | string): MockContact | MockRoom | null | void {
if (contact) { if (contact) {
return return
} }
...@@ -164,7 +163,7 @@ export class MockMessage extends Message { ...@@ -164,7 +163,7 @@ export class MockMessage extends Message {
return 'text/plain' return 'text/plain'
} }
public async forward(to: WebRoom|MockContact): Promise<void> { public async forward(to: MockRoom|MockContact): Promise<void> {
/** /**
* 1. Text message * 1. Text message
*/ */
......
...@@ -40,7 +40,7 @@ const PUPPETEER_LAUNCH_OPTIONS = { ...@@ -40,7 +40,7 @@ const PUPPETEER_LAUNCH_OPTIONS = {
'--no-sandbox', '--no-sandbox',
], ],
} }
test('PuppetWebBridge', async t => { test('PuppetPuppeteerBridge', async t => {
const profile = new Profile() const profile = new Profile()
const bridge = new Bridge({ profile }) const bridge = new Bridge({ profile })
try { try {
......
...@@ -27,11 +27,11 @@ import Wechaty from '../wechaty' ...@@ -27,11 +27,11 @@ import Wechaty from '../wechaty'
import { import {
// Event, // Event,
PuppetWeb, PuppetPuppeteer,
} from './puppet-web' } from './puppet-puppeteer'
test('Puppet Web Event smoke testing', async t => { test('Puppet Puppeteer Event smoke testing', async t => {
const pw = new PuppetWeb({ const pw = new PuppetPuppeteer({
profile: new Profile(), profile: new Profile(),
wechaty: new Wechaty(), wechaty: new Wechaty(),
}) })
......
...@@ -27,11 +27,11 @@ import { ...@@ -27,11 +27,11 @@ import {
ScanData, ScanData,
} from '../abstract-puppet/' } from '../abstract-puppet/'
import WebContact from './web-contact' import PuppeteerContact from './puppeteer-contact'
import WebMessage from './web-message' import PuppeteerMessage from './puppeteer-message'
import Firer from './firer' import Firer from './firer'
import PuppetWeb from './puppet-web' import PuppetPuppeteer from './puppet-puppeteer'
import { import {
MsgType, MsgType,
MsgRawObj, MsgRawObj,
...@@ -51,16 +51,16 @@ export const Event = { ...@@ -51,16 +51,16 @@ export const Event = {
} }
function onDing(this: PuppetWeb, data): void { function onDing(this: PuppetPuppeteer, data): void {
log.silly('PuppetWebEvent', 'onDing(%s)', data) log.silly('PuppetPuppeteerEvent', 'onDing(%s)', data)
this.emit('watchdog', { data }) this.emit('watchdog', { data })
} }
async function onScan(this: PuppetWeb, data: ScanData): Promise<void> { async function onScan(this: PuppetPuppeteer, data: ScanData): Promise<void> {
log.verbose('PuppetWebEvent', 'onScan({code: %d, url: %s})', data.code, data.url) log.verbose('PuppetPuppeteerEvent', 'onScan({code: %d, url: %s})', data.code, data.url)
if (this.state.off()) { if (this.state.off()) {
log.verbose('PuppetWebEvent', 'onScan(%s) state.off()=%s, NOOP', log.verbose('PuppetPuppeteerEvent', 'onScan(%s) state.off()=%s, NOOP',
data, this.state.off()) data, this.state.off())
return return
} }
...@@ -73,7 +73,7 @@ async function onScan(this: PuppetWeb, data: ScanData): Promise<void> { ...@@ -73,7 +73,7 @@ async function onScan(this: PuppetWeb, data: ScanData): Promise<void> {
await this.saveCookie() await this.saveCookie()
if (this.user) { if (this.user) {
log.verbose('PuppetWebEvent', 'onScan() there has user when got a scan event. emit logout and set it to null') log.verbose('PuppetPuppeteerEvent', 'onScan() there has user when got a scan event. emit logout and set it to null')
const currentUser = this.user const currentUser = this.user
this.user = undefined this.user = undefined
...@@ -90,21 +90,21 @@ async function onScan(this: PuppetWeb, data: ScanData): Promise<void> { ...@@ -90,21 +90,21 @@ async function onScan(this: PuppetWeb, data: ScanData): Promise<void> {
} }
function onLog(data: any): void { function onLog(data: any): void {
log.silly('PuppetWebEvent', 'onLog(%s)', data) log.silly('PuppetPuppeteerEvent', 'onLog(%s)', data)
} }
async function onLogin(this: PuppetWeb, note: string, ttl = 30): Promise<void> { async function onLogin(this: PuppetPuppeteer, note: string, ttl = 30): Promise<void> {
log.verbose('PuppetWebEvent', 'onLogin(%s, %d)', note, ttl) log.verbose('PuppetPuppeteerEvent', 'onLogin(%s, %d)', note, ttl)
const TTL_WAIT_MILLISECONDS = 1 * 1000 const TTL_WAIT_MILLISECONDS = 1 * 1000
if (ttl <= 0) { if (ttl <= 0) {
log.verbose('PuppetWebEvent', 'onLogin(%s) TTL expired') log.verbose('PuppetPuppeteerEvent', 'onLogin(%s) TTL expired')
this.emit('error', new Error('TTL expired.')) this.emit('error', new Error('TTL expired.'))
return return
} }
if (this.state.off()) { if (this.state.off()) {
log.verbose('PuppetWebEvent', 'onLogin(%s, %d) state.off()=%s, NOOP', log.verbose('PuppetPuppeteerEvent', 'onLogin(%s, %d) state.off()=%s, NOOP',
note, ttl, this.state.off()) note, ttl, this.state.off())
return return
} }
...@@ -112,7 +112,7 @@ async function onLogin(this: PuppetWeb, note: string, ttl = 30): Promise<void> { ...@@ -112,7 +112,7 @@ async function onLogin(this: PuppetWeb, note: string, ttl = 30): Promise<void> {
this.scanInfo = null this.scanInfo = null
if (this.user) { if (this.user) {
log.warn('PuppetWebEvent', 'onLogin(%s) user had already set: "%s"', note, this.user) log.warn('PuppetPuppeteerEvent', 'onLogin(%s) user had already set: "%s"', note, this.user)
} }
try { try {
...@@ -124,47 +124,47 @@ async function onLogin(this: PuppetWeb, note: string, ttl = 30): Promise<void> { ...@@ -124,47 +124,47 @@ async function onLogin(this: PuppetWeb, note: string, ttl = 30): Promise<void> {
const userId = await this.bridge.getUserName() const userId = await this.bridge.getUserName()
if (!userId) { if (!userId) {
log.verbose('PuppetWebEvent', 'onLogin() browser not fully loaded(ttl=%d), retry later', ttl) log.verbose('PuppetPuppeteerEvent', 'onLogin() browser not fully loaded(ttl=%d), retry later', ttl)
const html = await this.bridge.innerHTML() const html = await this.bridge.innerHTML()
log.silly('PuppetWebEvent', 'onLogin() innerHTML: %s', html.substr(0, 500)) log.silly('PuppetPuppeteerEvent', 'onLogin() innerHTML: %s', html.substr(0, 500))
setTimeout(onLogin.bind(this, note, ttl - 1), TTL_WAIT_MILLISECONDS) setTimeout(onLogin.bind(this, note, ttl - 1), TTL_WAIT_MILLISECONDS)
return return
} }
log.silly('PuppetWebEvent', 'bridge.getUserName: %s', userId) log.silly('PuppetPuppeteerEvent', 'bridge.getUserName: %s', userId)
this.user = WebContact.load(userId) this.user = PuppeteerContact.load(userId)
this.user.puppet = this this.user.puppet = this
await this.user.ready() await this.user.ready()
log.silly('PuppetWebEvent', `onLogin() user ${this.user.name()} logined`) log.silly('PuppetPuppeteerEvent', `onLogin() user ${this.user.name()} logined`)
try { try {
if (this.state.on() === true) { if (this.state.on() === true) {
await this.saveCookie() await this.saveCookie()
} }
} catch (e) { // fail safe } catch (e) { // fail safe
log.verbose('PuppetWebEvent', 'onLogin() this.saveCookie() exception: %s', e.message) log.verbose('PuppetPuppeteerEvent', 'onLogin() this.saveCookie() exception: %s', e.message)
} }
// fix issue #668 // fix issue #668
try { try {
await this.readyStable() await this.readyStable()
} catch (e) { // fail safe } catch (e) { // fail safe
log.warn('PuppetWebEvent', 'readyStable() exception: %s', e && e.message || e) log.warn('PuppetPuppeteerEvent', 'readyStable() exception: %s', e && e.message || e)
} }
this.emit('login', this.user) this.emit('login', this.user)
} catch (e) { } catch (e) {
log.error('PuppetWebEvent', 'onLogin() exception: %s', e) log.error('PuppetPuppeteerEvent', 'onLogin() exception: %s', e)
throw e throw e
} }
return return
} }
function onLogout(this: PuppetWeb, data) { function onLogout(this: PuppetPuppeteer, data) {
log.verbose('PuppetWebEvent', 'onLogout(%s)', data) log.verbose('PuppetPuppeteerEvent', 'onLogout(%s)', data)
const currentUser = this.user const currentUser = this.user
this.user = undefined this.user = undefined
...@@ -172,15 +172,15 @@ function onLogout(this: PuppetWeb, data) { ...@@ -172,15 +172,15 @@ function onLogout(this: PuppetWeb, data) {
if (currentUser) { if (currentUser) {
this.emit('logout', currentUser) this.emit('logout', currentUser)
} else { } else {
log.error('PuppetWebEvent', 'onLogout() without this.user initialized') log.error('PuppetPuppeteerEvent', 'onLogout() without this.user initialized')
} }
} }
async function onMessage( async function onMessage(
this: PuppetWeb, this: PuppetPuppeteer,
obj: MsgRawObj, obj: MsgRawObj,
): Promise<void> { ): Promise<void> {
let m = new WebMessage(obj) let m = new PuppeteerMessage(obj)
m.puppet = this m.puppet = this
try { try {
...@@ -202,7 +202,7 @@ async function onMessage( ...@@ -202,7 +202,7 @@ async function onMessage(
const topicRestul = await Firer.checkRoomTopic.call(this , m) const topicRestul = await Firer.checkRoomTopic.call(this , m)
if (!joinResult && !leaveResult && !topicRestul) { if (!joinResult && !leaveResult && !topicRestul) {
log.warn('PuppetWebEvent', `checkRoomSystem message: <${m.content()}> not found`) log.warn('PuppetPuppeteerEvent', `checkRoomSystem message: <${m.content()}> not found`)
} }
} else { } else {
Firer.checkFriendConfirm.call(this, m) Firer.checkFriendConfirm.call(this, m)
...@@ -222,15 +222,15 @@ async function onMessage( ...@@ -222,15 +222,15 @@ async function onMessage(
case MsgType.VOICE: case MsgType.VOICE:
case MsgType.MICROVIDEO: case MsgType.MICROVIDEO:
case MsgType.APP: case MsgType.APP:
log.verbose('PuppetWebEvent', 'onMessage() EMOTICON/IMAGE/VIDEO/VOICE/MICROVIDEO message') log.verbose('PuppetPuppeteerEvent', 'onMessage() EMOTICON/IMAGE/VIDEO/VOICE/MICROVIDEO message')
m = new WebMessage(obj) m = new PuppeteerMessage(obj)
m.puppet = this m.puppet = this
break break
case MsgType.TEXT: case MsgType.TEXT:
if (m.typeSub() === MsgType.LOCATION) { if (m.typeSub() === MsgType.LOCATION) {
log.verbose('PuppetWebEvent', 'onMessage() (TEXT&LOCATION) message') log.verbose('PuppetPuppeteerEvent', 'onMessage() (TEXT&LOCATION) message')
m = new WebMessage(obj) m = new PuppeteerMessage(obj)
} }
break break
} }
...@@ -239,19 +239,19 @@ async function onMessage( ...@@ -239,19 +239,19 @@ async function onMessage(
this.emit('message', m) this.emit('message', m)
} catch (e) { } catch (e) {
log.error('PuppetWebEvent', 'onMessage() exception: %s', e.stack) log.error('PuppetPuppeteerEvent', 'onMessage() exception: %s', e.stack)
throw e throw e
} }
} }
async function onUnload(this: PuppetWeb): Promise<void> { async function onUnload(this: PuppetPuppeteer): Promise<void> {
log.silly('PuppetWebEvent', 'onUnload()') log.silly('PuppetPuppeteerEvent', 'onUnload()')
/* /*
try { try {
await this.quit() await this.quit()
await this.init() await this.init()
} catch (e) { } catch (e) {
log.error('PuppetWebEvent', 'onUnload() exception: %s', e) log.error('PuppetPuppeteerEvent', 'onUnload() exception: %s', e)
this.emit('error', e) this.emit('error', e)
throw e throw e
} }
......
...@@ -24,10 +24,10 @@ import { ...@@ -24,10 +24,10 @@ import {
log, log,
} from '../config' } from '../config'
import WebContact from './web-contact' import PuppeteerContact from './puppeteer-contact'
import WebMessage from './web-message' import PuppeteerMessage from './puppeteer-message'
import WebFriendRequest from './web-friend-request' import PuppeteerFriendRequest from './puppeteer-friend-request'
/* tslint:disable:variable-name */ /* tslint:disable:variable-name */
export const Firer = { export const Firer = {
...@@ -101,25 +101,25 @@ const regexConfig = { ...@@ -101,25 +101,25 @@ const regexConfig = {
], ],
} }
async function checkFriendRequest(m: WebMessage) { async function checkFriendRequest(m: PuppeteerMessage) {
if (!m.rawObj) { if (!m.rawObj) {
throw new Error('message empty') throw new Error('message empty')
} }
const info = m.rawObj.RecommendInfo const info = m.rawObj.RecommendInfo
log.verbose('PuppetWebFirer', 'fireFriendRequest(%s)', info) log.verbose('PuppetPuppeteerFirer', 'fireFriendRequest(%s)', info)
if (!info) { if (!info) {
throw new Error('no info') throw new Error('no info')
} }
const request = new WebFriendRequest() const request = new PuppeteerFriendRequest()
request.puppet = m.puppet request.puppet = m.puppet
request.receive(info) request.receive(info)
await request.contact.ready() await request.contact.ready()
if (!request.contact.isReady()) { if (!request.contact.isReady()) {
log.warn('PuppetWebFirer', 'fireFriendConfirm() contact still not ready after `ready()` call') log.warn('PuppetPuppeteerFirer', 'fireFriendConfirm() contact still not ready after `ready()` call')
} }
this.emit('friend', request.contact, request) this.emit('friend', request.contact, request)
...@@ -140,14 +140,14 @@ function parseFriendConfirm(content: string): boolean { ...@@ -140,14 +140,14 @@ function parseFriendConfirm(content: string): boolean {
} }
} }
async function checkFriendConfirm(m: WebMessage) { async function checkFriendConfirm(m: PuppeteerMessage) {
const content = m.text() const content = m.text()
log.silly('PuppetWebFirer', 'fireFriendConfirm(%s)', content) log.silly('PuppetPuppeteerFirer', 'fireFriendConfirm(%s)', content)
if (!parseFriendConfirm(content)) { if (!parseFriendConfirm(content)) {
return return
} }
const request = new WebFriendRequest() const request = new PuppeteerFriendRequest()
request.puppet = m.puppet request.puppet = m.puppet
const contact = m.from() const contact = m.from()
...@@ -155,7 +155,7 @@ async function checkFriendConfirm(m: WebMessage) { ...@@ -155,7 +155,7 @@ async function checkFriendConfirm(m: WebMessage) {
await contact.ready() await contact.ready()
if (!contact.isReady()) { if (!contact.isReady()) {
log.warn('PuppetWebFirer', 'fireFriendConfirm() contact still not ready after `ready()` call') log.warn('PuppetPuppeteerFirer', 'fireFriendConfirm() contact still not ready after `ready()` call')
} }
this.emit('friend', contact) this.emit('friend', contact)
} }
...@@ -171,7 +171,7 @@ async function checkFriendConfirm(m: WebMessage) { ...@@ -171,7 +171,7 @@ async function checkFriendConfirm(m: WebMessage) {
* 管理员 invited 庆次、小桔妹 to the group chat * 管理员 invited 庆次、小桔妹 to the group chat
*/ */
function parseRoomJoin(content: string): [string[], string] { function parseRoomJoin(content: string): [string[], string] {
log.verbose('PuppetWebFirer', 'checkRoomJoin(%s)', content) log.verbose('PuppetPuppeteerFirer', 'checkRoomJoin(%s)', content)
const reListInvite = regexConfig.roomJoinInvite const reListInvite = regexConfig.roomJoinInvite
const reListQrcode = regexConfig.roomJoinQrcode const reListQrcode = regexConfig.roomJoinQrcode
...@@ -193,11 +193,11 @@ function parseRoomJoin(content: string): [string[], string] { ...@@ -193,11 +193,11 @@ function parseRoomJoin(content: string): [string[], string] {
return [inviteeList, inviter] // put invitee at first place return [inviteeList, inviter] // put invitee at first place
} }
async function checkRoomJoin(m: WebMessage): Promise<boolean> { async function checkRoomJoin(m: PuppeteerMessage): Promise<boolean> {
const room = m.room() const room = m.room()
if (!room) { if (!room) {
log.warn('PuppetWebFirer', 'fireRoomJoin() `room` not found') log.warn('PuppetPuppeteerFirer', 'fireRoomJoin() `room` not found')
return false return false
} }
...@@ -207,20 +207,20 @@ async function checkRoomJoin(m: WebMessage): Promise<boolean> { ...@@ -207,20 +207,20 @@ async function checkRoomJoin(m: WebMessage): Promise<boolean> {
try { try {
[inviteeList, inviter] = parseRoomJoin(text) [inviteeList, inviter] = parseRoomJoin(text)
} catch (e) { } catch (e) {
log.silly('PuppetWebFirer', 'fireRoomJoin() "%s" is not a join message', text) log.silly('PuppetPuppeteerFirer', 'fireRoomJoin() "%s" is not a join message', text)
return false // not a room join message return false // not a room join message
} }
log.silly('PuppetWebFirer', 'fireRoomJoin() inviteeList: %s, inviter: %s', log.silly('PuppetPuppeteerFirer', 'fireRoomJoin() inviteeList: %s, inviter: %s',
inviteeList.join(','), inviteeList.join(','),
inviter, inviter,
) )
let inviterContact: WebContact | null = null let inviterContact: PuppeteerContact | null = null
let inviteeContactList: WebContact[] = [] let inviteeContactList: PuppeteerContact[] = []
try { try {
if (inviter === 'You' || inviter === '' || inviter === 'you') { if (inviter === 'You' || inviter === '' || inviter === 'you') {
inviterContact = WebContact.load(this.userId) as WebContact inviterContact = PuppeteerContact.load(this.userId) as PuppeteerContact
inviterContact.puppet = m.puppet inviterContact.puppet = m.puppet
} }
...@@ -232,13 +232,13 @@ async function checkRoomJoin(m: WebMessage): Promise<boolean> { ...@@ -232,13 +232,13 @@ async function checkRoomJoin(m: WebMessage): Promise<boolean> {
// timeout = 11,250 for {max: 15, backoff: 100} // timeout = 11,250 for {max: 15, backoff: 100}
await retryPromise({ max: max, backoff: backoff }, async (attempt: number) => { await retryPromise({ max: max, backoff: backoff }, async (attempt: number) => {
log.silly('PuppetWebFirer', 'fireRoomJoin() retryPromise() attempt %d with timeout %d', attempt, timeout) log.silly('PuppetPuppeteerFirer', 'fireRoomJoin() retryPromise() attempt %d with timeout %d', attempt, timeout)
await room.refresh() await room.refresh()
let inviteeListAllDone = true let inviteeListAllDone = true
for (const i in inviteeList) { for (const i in inviteeList) {
const loaded = inviteeContactList[i] instanceof WebContact const loaded = inviteeContactList[i] instanceof PuppeteerContact
if (!loaded) { if (!loaded) {
const c = room.member(inviteeList[i]) const c = room.member(inviteeList[i])
...@@ -255,10 +255,10 @@ async function checkRoomJoin(m: WebMessage): Promise<boolean> { ...@@ -255,10 +255,10 @@ async function checkRoomJoin(m: WebMessage): Promise<boolean> {
} }
} }
if (inviteeContactList[i] instanceof WebContact) { if (inviteeContactList[i] instanceof PuppeteerContact) {
const isReady = inviteeContactList[i].isReady() const isReady = inviteeContactList[i].isReady()
if (!isReady) { if (!isReady) {
log.warn('PuppetWebFirer', 'fireRoomJoin() retryPromise() isReady false for contact %s', inviteeContactList[i].id) log.warn('PuppetPuppeteerFirer', 'fireRoomJoin() retryPromise() isReady false for contact %s', inviteeContactList[i].id)
inviteeListAllDone = false inviteeListAllDone = false
await inviteeContactList[i].refresh() await inviteeContactList[i].refresh()
continue continue
...@@ -272,35 +272,35 @@ async function checkRoomJoin(m: WebMessage): Promise<boolean> { ...@@ -272,35 +272,35 @@ async function checkRoomJoin(m: WebMessage): Promise<boolean> {
} }
if (inviteeListAllDone && inviterContact) { if (inviteeListAllDone && inviterContact) {
log.silly('PuppetWebFirer', 'fireRoomJoin() resolve() inviteeContactList: %s, inviterContact: %s', log.silly('PuppetPuppeteerFirer', 'fireRoomJoin() resolve() inviteeContactList: %s, inviterContact: %s',
inviteeContactList.map((c: WebContact) => c.name()).join(','), inviteeContactList.map((c: PuppeteerContact) => c.name()).join(','),
inviterContact.name(), inviterContact.name(),
) )
return true return true
} }
log.error('PuppetWebFirer', 'fireRoomJoin() not found(yet)') log.error('PuppetPuppeteerFirer', 'fireRoomJoin() not found(yet)')
return false return false
// throw new Error('not found(yet)') // throw new Error('not found(yet)')
}).catch(e => { }).catch(e => {
log.warn('PuppetWebFirer', 'fireRoomJoin() reject() inviteeContactList: %s, inviterContact: %s', log.warn('PuppetPuppeteerFirer', 'fireRoomJoin() reject() inviteeContactList: %s, inviterContact: %s',
inviteeContactList.map((c: WebContact) => c.name()).join(','), inviteeContactList.map((c: PuppeteerContact) => c.name()).join(','),
inviter, inviter,
) )
}) })
if (!inviterContact) { if (!inviterContact) {
log.error('PuppetWebFirer', 'firmRoomJoin() inivter not found for %s , `room-join` & `join` event will not fired', inviter) log.error('PuppetPuppeteerFirer', 'firmRoomJoin() inivter not found for %s , `room-join` & `join` event will not fired', inviter)
return false return false
} }
if (!inviteeContactList.every(c => c instanceof WebContact)) { if (!inviteeContactList.every(c => c instanceof PuppeteerContact)) {
log.error('PuppetWebFirer', 'firmRoomJoin() inviteeList not all found for %s , only part of them will in the `room-join` or `join` event', log.error('PuppetPuppeteerFirer', 'firmRoomJoin() inviteeList not all found for %s , only part of them will in the `room-join` or `join` event',
inviteeContactList.join(','), inviteeContactList.join(','),
) )
inviteeContactList = inviteeContactList.filter(c => (c instanceof WebContact)) inviteeContactList = inviteeContactList.filter(c => (c instanceof PuppeteerContact))
if (inviteeContactList.length < 1) { if (inviteeContactList.length < 1) {
log.error('PuppetWebFirer', 'firmRoomJoin() inviteeList empty. `room-join` & `join` event will not fired') log.error('PuppetPuppeteerFirer', 'firmRoomJoin() inviteeList empty. `room-join` & `join` event will not fired')
return false return false
} }
} }
...@@ -314,7 +314,7 @@ async function checkRoomJoin(m: WebMessage): Promise<boolean> { ...@@ -314,7 +314,7 @@ async function checkRoomJoin(m: WebMessage): Promise<boolean> {
return true return true
} catch (e) { } catch (e) {
log.error('PuppetWebFirer', 'exception: %s', e.stack) log.error('PuppetPuppeteerFirer', 'exception: %s', e.stack)
return false return false
} }
...@@ -337,8 +337,8 @@ function parseRoomLeave(content: string): [string, string] { ...@@ -337,8 +337,8 @@ function parseRoomLeave(content: string): [string, string] {
/** /**
* You removed "Bruce LEE" from the group chat * You removed "Bruce LEE" from the group chat
*/ */
async function checkRoomLeave(m: WebMessage): Promise<boolean> { async function checkRoomLeave(m: PuppeteerMessage): Promise<boolean> {
log.verbose('PuppetWebFirer', 'fireRoomLeave(%s)', m.text()) log.verbose('PuppetPuppeteerFirer', 'fireRoomLeave(%s)', m.text())
let leaver: string, remover: string let leaver: string, remover: string
try { try {
...@@ -346,39 +346,39 @@ async function checkRoomLeave(m: WebMessage): Promise<boolean> { ...@@ -346,39 +346,39 @@ async function checkRoomLeave(m: WebMessage): Promise<boolean> {
} catch (e) { } catch (e) {
return false return false
} }
log.silly('PuppetWebFirer', 'fireRoomLeave() got leaver: %s', leaver) log.silly('PuppetPuppeteerFirer', 'fireRoomLeave() got leaver: %s', leaver)
const room = m.room() const room = m.room()
if (!room) { if (!room) {
log.warn('PuppetWebFirer', 'fireRoomLeave() room not found') log.warn('PuppetPuppeteerFirer', 'fireRoomLeave() room not found')
return false return false
} }
/** /**
* FIXME: leaver maybe is a list * FIXME: leaver maybe is a list
* @lijiarui: I have checked, leaver will never be a list. If the bot remove 2 leavers at the same time, it will be 2 sys message, instead of 1 sys message contains 2 leavers. * @lijiarui: I have checked, leaver will never be a list. If the bot remove 2 leavers at the same time, it will be 2 sys message, instead of 1 sys message contains 2 leavers.
*/ */
let leaverContact: WebContact | null, removerContact: WebContact | null let leaverContact: PuppeteerContact | null, removerContact: PuppeteerContact | null
if (leaver === this.userId) { if (leaver === this.userId) {
leaverContact = WebContact.load(this.userId) as WebContact leaverContact = PuppeteerContact.load(this.userId) as PuppeteerContact
leaverContact.puppet = m.puppet leaverContact.puppet = m.puppet
// not sure which is better // not sure which is better
// removerContact = room.member({contactAlias: remover}) || room.member({name: remover}) // removerContact = room.member({contactAlias: remover}) || room.member({name: remover})
removerContact = room.member(remover) removerContact = room.member(remover)
if (!removerContact) { if (!removerContact) {
log.error('PuppetWebFirer', 'fireRoomLeave() bot is removed from the room, but remover %s not found, event `room-leave` & `leave` will not be fired', remover) log.error('PuppetPuppeteerFirer', 'fireRoomLeave() bot is removed from the room, but remover %s not found, event `room-leave` & `leave` will not be fired', remover)
return false return false
} }
} else { } else {
removerContact = WebContact.load(this.userId) as WebContact removerContact = PuppeteerContact.load(this.userId) as PuppeteerContact
removerContact.puppet = m.puppet removerContact.puppet = m.puppet
// not sure which is better // not sure which is better
// leaverContact = room.member({contactAlias: remover}) || room.member({name: leaver}) // leaverContact = room.member({contactAlias: remover}) || room.member({name: leaver})
leaverContact = room.member(remover) leaverContact = room.member(remover)
if (!leaverContact) { if (!leaverContact) {
log.error('PuppetWebFirer', 'fireRoomLeave() bot removed someone from the room, but leaver %s not found, event `room-leave` & `leave` will not be fired', leaver) log.error('PuppetPuppeteerFirer', 'fireRoomLeave() bot removed someone from the room, but leaver %s not found, event `room-leave` & `leave` will not be fired', leaver)
return false return false
} }
} }
...@@ -410,7 +410,7 @@ function parseRoomTopic(content: string): [string, string] { ...@@ -410,7 +410,7 @@ function parseRoomTopic(content: string): [string, string] {
return [topic, changer] return [topic, changer]
} }
async function checkRoomTopic(m: WebMessage): Promise<boolean> { async function checkRoomTopic(m: PuppeteerMessage): Promise<boolean> {
let topic, changer let topic, changer
try { try {
[topic, changer] = parseRoomTopic(m.text()) [topic, changer] = parseRoomTopic(m.text())
...@@ -420,22 +420,22 @@ async function checkRoomTopic(m: WebMessage): Promise<boolean> { ...@@ -420,22 +420,22 @@ async function checkRoomTopic(m: WebMessage): Promise<boolean> {
const room = m.room() const room = m.room()
if (!room) { if (!room) {
log.warn('PuppetWebFirer', 'fireRoomLeave() room not found') log.warn('PuppetPuppeteerFirer', 'fireRoomLeave() room not found')
return false return false
} }
const oldTopic = room.topic() const oldTopic = room.topic()
let changerContact: WebContact | null let changerContact: PuppeteerContact | null
if (/^You$/.test(changer) || /^你$/.test(changer)) { if (/^You$/.test(changer) || /^你$/.test(changer)) {
changerContact = WebContact.load(this.userId) as WebContact changerContact = PuppeteerContact.load(this.userId) as PuppeteerContact
changerContact.puppet = m.puppet changerContact.puppet = m.puppet
} else { } else {
changerContact = room.member(changer) changerContact = room.member(changer)
} }
if (!changerContact) { if (!changerContact) {
log.error('PuppetWebFirer', 'fireRoomTopic() changer contact not found for %s', changer) log.error('PuppetPuppeteerFirer', 'fireRoomTopic() changer contact not found for %s', changer)
return false return false
} }
...@@ -447,7 +447,7 @@ async function checkRoomTopic(m: WebMessage): Promise<boolean> { ...@@ -447,7 +447,7 @@ async function checkRoomTopic(m: WebMessage): Promise<boolean> {
room.refresh() room.refresh()
return true return true
} catch (e) { } catch (e) {
log.error('PuppetWebFirer', 'fireRoomTopic() co exception: %s', e.stack) log.error('PuppetPuppeteerFirer', 'fireRoomTopic() co exception: %s', e.stack)
return false return false
} }
} }
......
...@@ -22,9 +22,9 @@ import * as test from 'blue-tape' ...@@ -22,9 +22,9 @@ import * as test from 'blue-tape'
// import * as sinon from 'sinon' // import * as sinon from 'sinon'
import { import {
PuppetWeb, PuppetPuppeteer,
} from './' } from './'
test('PuppetWeb Module Exports', async t => { test('PuppetPuppeteer Module Exports', async t => {
t.ok(PuppetWeb , 'should export PuppetWeb') t.ok(PuppetPuppeteer , 'should export PuppetPuppeteer')
}) })
...@@ -16,10 +16,10 @@ ...@@ -16,10 +16,10 @@
* limitations under the License. * limitations under the License.
* *
*/ */
import { PuppetWeb } from './puppet-web' import { PuppetPuppeteer } from './puppet-puppeteer'
export { export {
PuppetWeb, PuppetPuppeteer,
} }
export default PuppetWeb export default PuppetPuppeteer
...@@ -31,14 +31,30 @@ const sinonTest = require('sinon-test')(sinon, { ...@@ -31,14 +31,30 @@ const sinonTest = require('sinon-test')(sinon, {
// log.level('silly') // log.level('silly')
import Profile from '../profile' import Profile from '../profile'
import Wechaty from '../wechaty'
import { import {
Contact, Contact,
} from '../abstract-puppet/' } from '../abstract-puppet/'
import PuppetWeb from '../../src/puppet-web/puppet-web'
import Bridge from '../../src/puppet-web/bridge' import PuppetPuppeteer from './puppet-puppeteer'
import Event from '../../src/puppet-web/event' import Bridge from './bridge'
import { Wechaty } from '../wechaty' import Event from './event'
test('Puppet smoke testing', async t => {
const profile = new Profile(Math.random().toString(36).substr(2, 5))
const wechaty = new Wechaty()
const p = new PuppetPuppeteer({
profile,
wechaty,
})
t.ok(p.state.off(), 'should be OFF state after instanciate')
p.state.on('pending')
t.ok(p.state.on(), 'should be ON state after set')
t.ok(p.state.pending(), 'should be pending state after set')
})
test('login/logout events', sinonTest(async function (t: test.Test) { test('login/logout events', sinonTest(async function (t: test.Test) {
...@@ -50,7 +66,7 @@ test('login/logout events', sinonTest(async function (t: test.Test) { ...@@ -50,7 +66,7 @@ test('login/logout events', sinonTest(async function (t: test.Test) {
sinon.stub(Event, 'onScan') // block the scan event to prevent reset logined user sinon.stub(Event, 'onScan') // block the scan event to prevent reset logined user
sinon.stub(Bridge.prototype, 'getUserName').resolves('mockedUserName') sinon.stub(Bridge.prototype, 'getUserName').resolves('mockedUserName')
sinon.stub(PuppetWeb.prototype, 'getContact') .resolves({ sinon.stub(PuppetPuppeteer.prototype, 'getContact') .resolves({
NickName: 'mockedNickName', NickName: 'mockedNickName',
UserName: 'mockedUserName', UserName: 'mockedUserName',
}) })
...@@ -59,11 +75,11 @@ test('login/logout events', sinonTest(async function (t: test.Test) { ...@@ -59,11 +75,11 @@ test('login/logout events', sinonTest(async function (t: test.Test) {
const profile = new Profile() const profile = new Profile()
const wechaty = new Wechaty() const wechaty = new Wechaty()
const pw = new PuppetWeb({ const pw = new PuppetPuppeteer({
profile, profile,
wechaty, wechaty,
}) })
t.ok(pw, 'should instantiated a PuppetWeb') t.ok(pw, 'should instantiated a PuppetPuppeteer')
// config.puppetInstance(pw) // config.puppetInstance(pw)
Contact.puppet = pw Contact.puppet = pw
...@@ -74,7 +90,7 @@ test('login/logout events', sinonTest(async function (t: test.Test) { ...@@ -74,7 +90,7 @@ test('login/logout events', sinonTest(async function (t: test.Test) {
const EXPECTED_CHIPER = 'loginFired' const EXPECTED_CHIPER = 'loginFired'
const loginPromise = new Promise(r => pw.once('login', _ => r(EXPECTED_CHIPER))) const loginPromise = new Promise(r => pw.once('login', _ => r(EXPECTED_CHIPER)))
pw.bridge.emit('login', 'TestPuppetWeb') pw.bridge.emit('login', 'TestPuppetPuppeteer')
t.is(await loginPromise, EXPECTED_CHIPER, 'should fired login event') t.is(await loginPromise, EXPECTED_CHIPER, 'should fired login event')
t.is(pw.logonoff(), true , 'should be logined') t.is(pw.logonoff(), true , 'should be logined')
......
...@@ -24,23 +24,18 @@ import * as test from 'blue-tape' ...@@ -24,23 +24,18 @@ import * as test from 'blue-tape'
import cloneClass from 'clone-class' import cloneClass from 'clone-class'
// import config from '../src/config' import PuppetPuppeteer from './puppet-puppeteer'
import WebContact from './web-contact' import PuppeteerContact from './puppeteer-contact'
import Profile from '../profile' import Profile from '../profile'
import PuppetWeb from './puppet-web' import Wechaty from '../wechaty'
import Wechaty from '../wechaty'
// config.puppetInstance(new PuppetWeb({
// profile: new Profile(),
// }))
test('Contact smoke testing', async t => { test('Contact smoke testing', async t => {
// tslint:disable-next-line:variable-name // tslint:disable-next-line:variable-name
const MyContact = cloneClass(WebContact) const MyContact = cloneClass(PuppeteerContact)
MyContact.puppet = new PuppetWeb({ MyContact.puppet = new PuppetPuppeteer({
profile: new Profile(), profile: new Profile(),
wechaty: new Wechaty(), wechaty: new Wechaty(),
}) })
......
...@@ -31,12 +31,10 @@ import { ...@@ -31,12 +31,10 @@ import {
import Misc from '../misc' import Misc from '../misc'
// import Wechaty from './wechaty' import PuppetPuppeteer from './puppet-puppeteer'
import PuppeteerMessage from './puppeteer-message'
import PuppetWeb from './puppet-web' export interface PuppeteerContactObj {
import WebMessage from './web-message'
export interface WebContactObj {
address: string, address: string,
city: string, city: string,
id: string, id: string,
...@@ -54,7 +52,7 @@ export interface WebContactObj { ...@@ -54,7 +52,7 @@ export interface WebContactObj {
special: boolean, special: boolean,
} }
export interface WebContactRawObj { export interface PuppeteerContactRawObj {
Alias: string, Alias: string,
City: string, City: string,
NickName: string, NickName: string,
...@@ -88,11 +86,11 @@ const specialContactList: string[] = [ ...@@ -88,11 +86,11 @@ const specialContactList: string[] = [
* `Contact` is `Sayable`, * `Contact` is `Sayable`,
* [Examples/Contact-Bot]{@link https://github.com/Chatie/wechaty/blob/master/examples/contact-bot.ts} * [Examples/Contact-Bot]{@link https://github.com/Chatie/wechaty/blob/master/examples/contact-bot.ts}
*/ */
export class WebContact extends Contact implements Sayable { export class PuppeteerContact extends Contact implements Sayable {
public obj: WebContactObj | null public obj: PuppeteerContactObj | null
// private dirtyObj: ContactObj | null // private dirtyObj: ContactObj | null
private rawObj: WebContactRawObj private rawObj: PuppeteerContactRawObj
/** /**
* @private * @private
...@@ -101,7 +99,7 @@ export class WebContact extends Contact implements Sayable { ...@@ -101,7 +99,7 @@ export class WebContact extends Contact implements Sayable {
public readonly id: string, public readonly id: string,
) { ) {
super(id) super(id)
log.silly('WebContact', `constructor(${id})`) log.silly('PuppeteerContact', `constructor(${id})`)
if (typeof id !== 'string') { if (typeof id !== 'string') {
throw new Error('id must be string. found: ' + typeof id) throw new Error('id must be string. found: ' + typeof id)
...@@ -113,24 +111,24 @@ export class WebContact extends Contact implements Sayable { ...@@ -113,24 +111,24 @@ export class WebContact extends Contact implements Sayable {
*/ */
public toString(): string { public toString(): string {
if (!this.obj) { if (!this.obj) {
return `WebContact<this.id>` return `PuppeteerContact<this.id>`
} }
const obj = this.obj const obj = this.obj
const name = obj.alias || obj.name || this.id const name = obj.alias || obj.name || this.id
return `WebContact<${name}>` return `PuppeteerContact<${name}>`
} }
/** /**
* @private * @private
*/ */
public toStringEx() { return `WebContact(${this.obj && this.obj.name}[${this.id}])` } public toStringEx() { return `PuppeteerContact(${this.obj && this.obj.name}[${this.id}])` }
/** /**
* @private * @private
*/ */
private parse(rawObj: WebContactRawObj): WebContactObj | null { private parse(rawObj: PuppeteerContactRawObj): PuppeteerContactObj | null {
if (!rawObj || !rawObj.UserName) { if (!rawObj || !rawObj.UserName) {
log.warn('WebContact', 'parse() got empty rawObj!') log.warn('PuppeteerContact', 'parse() got empty rawObj!')
// config.puppetInstance().emit('error', e) // config.puppetInstance().emit('error', e)
return null return null
} }
...@@ -188,7 +186,7 @@ export class WebContact extends Contact implements Sayable { ...@@ -188,7 +186,7 @@ export class WebContact extends Contact implements Sayable {
* @param {MediaMessage} mediaMessage * @param {MediaMessage} mediaMessage
* @memberof Contact * @memberof Contact
*/ */
public async say(message: WebMessage): Promise<void> public async say(message: PuppeteerMessage): Promise<void>
/** /**
* Send Text or Media File to Contact. * Send Text or Media File to Contact.
...@@ -200,8 +198,8 @@ export class WebContact extends Contact implements Sayable { ...@@ -200,8 +198,8 @@ export class WebContact extends Contact implements Sayable {
* await contact.say('welcome to wechaty!') * await contact.say('welcome to wechaty!')
* await contact.say(new MediaMessage(__dirname + '/wechaty.png') // put the filePath you want to send here * await contact.say(new MediaMessage(__dirname + '/wechaty.png') // put the filePath you want to send here
*/ */
public async say(textOrMessage: string | WebMessage): Promise<void> { public async say(textOrMessage: string | PuppeteerMessage): Promise<void> {
log.verbose('WebContact', 'say(%s)', textOrMessage) log.verbose('PuppeteerContact', 'say(%s)', textOrMessage)
const user = this.puppet.self() const user = this.puppet.self()
...@@ -210,18 +208,18 @@ export class WebContact extends Contact implements Sayable { ...@@ -210,18 +208,18 @@ export class WebContact extends Contact implements Sayable {
} }
let m let m
if (typeof textOrMessage === 'string') { if (typeof textOrMessage === 'string') {
m = new WebMessage() m = new PuppeteerMessage()
m.puppet = this.puppet m.puppet = this.puppet
m.text(textOrMessage) m.text(textOrMessage)
} else if (textOrMessage instanceof WebMessage) { } else if (textOrMessage instanceof PuppeteerMessage) {
m = textOrMessage m = textOrMessage
} else { } else {
throw new Error('not support args') throw new Error('not support args')
} }
m.from(user) m.from(user)
m.to(this) m.to(this)
log.silly('WebContact', 'say() from: %s to: %s content: %s', user.name(), this.name(), textOrMessage) log.silly('PuppeteerContact', 'say() from: %s to: %s content: %s', user.name(), this.name(), textOrMessage)
return await this.puppet.send(m) return await this.puppet.send(m)
} }
...@@ -272,7 +270,7 @@ export class WebContact extends Contact implements Sayable { ...@@ -272,7 +270,7 @@ export class WebContact extends Contact implements Sayable {
* } * }
*/ */
public alias(newAlias?: string|null): Promise<void> | string | null { public alias(newAlias?: string|null): Promise<void> | string | null {
// log.silly('WebContact', 'alias(%s)', newAlias || '') // log.silly('PuppeteerContact', 'alias(%s)', newAlias || '')
if (typeof newAlias === 'undefined') { if (typeof newAlias === 'undefined') {
return this.obj && this.obj.alias || null return this.obj && this.obj.alias || null
...@@ -285,11 +283,11 @@ export class WebContact extends Contact implements Sayable { ...@@ -285,11 +283,11 @@ export class WebContact extends Contact implements Sayable {
if (this.obj) { if (this.obj) {
this.obj.alias = newAlias this.obj.alias = newAlias
} else { } else {
log.error('WebContact', 'alias() without this.obj?') log.error('PuppeteerContact', 'alias() without this.obj?')
} }
}) })
.catch(e => { .catch(e => {
log.error('WebContact', 'alias(%s) rejected: %s', newAlias, e.message) log.error('PuppeteerContact', 'alias(%s) rejected: %s', newAlias, e.message)
Raven.captureException(e) Raven.captureException(e)
}) })
...@@ -402,7 +400,7 @@ export class WebContact extends Contact implements Sayable { ...@@ -402,7 +400,7 @@ export class WebContact extends Contact implements Sayable {
* log.info('Bot', 'Contact: %s: %s with avatar file: %s', contact.weixin(), contact.name(), avatarFileName) * log.info('Bot', 'Contact: %s: %s with avatar file: %s', contact.weixin(), contact.name(), avatarFileName)
*/ */
public async avatar(): Promise<NodeJS.ReadableStream> { public async avatar(): Promise<NodeJS.ReadableStream> {
log.verbose('WebContact', 'avatar()') log.verbose('PuppeteerContact', 'avatar()')
if (!this.obj) { if (!this.obj) {
throw new Error('Can not get avatar: no this.obj!') throw new Error('Can not get avatar: no this.obj!')
...@@ -411,14 +409,14 @@ export class WebContact extends Contact implements Sayable { ...@@ -411,14 +409,14 @@ export class WebContact extends Contact implements Sayable {
} }
try { try {
const hostname = await (this.puppet as any as PuppetWeb).hostname() const hostname = await (this.puppet as any as PuppetPuppeteer).hostname()
const avatarUrl = `http://${hostname}${this.obj.avatar}&type=big` // add '&type=big' to get big image const avatarUrl = `http://${hostname}${this.obj.avatar}&type=big` // add '&type=big' to get big image
const cookies = await (this.puppet as any as PuppetWeb).cookies() const cookies = await (this.puppet as any as PuppetPuppeteer).cookies()
log.silly('WebContact', 'avatar() url: %s', avatarUrl) log.silly('PuppeteerContact', 'avatar() url: %s', avatarUrl)
return Misc.urlStream(avatarUrl, cookies) return Misc.urlStream(avatarUrl, cookies)
} catch (err) { } catch (err) {
log.warn('WebContact', 'avatar() exception: %s', err.stack) log.warn('PuppeteerContact', 'avatar() exception: %s', err.stack)
Raven.captureException(err) Raven.captureException(err)
throw err throw err
} }
...@@ -457,7 +455,7 @@ export class WebContact extends Contact implements Sayable { ...@@ -457,7 +455,7 @@ export class WebContact extends Contact implements Sayable {
* @private * @private
*/ */
public async ready(): Promise<this> { public async ready(): Promise<this> {
// log.silly('WebContact', 'ready(' + (contactGetter ? typeof contactGetter : '') + ')') // log.silly('PuppeteerContact', 'ready(' + (contactGetter ? typeof contactGetter : '') + ')')
if (!this.id) { if (!this.id) {
const e = new Error('ready() call on an un-inited contact') const e = new Error('ready() call on an un-inited contact')
throw e throw e
...@@ -468,8 +466,8 @@ export class WebContact extends Contact implements Sayable { ...@@ -468,8 +466,8 @@ export class WebContact extends Contact implements Sayable {
} }
try { try {
const rawObj = await (this.puppet as any as PuppetWeb).getContact(this.id) as WebContactRawObj const rawObj = await (this.puppet as any as PuppetPuppeteer).getContact(this.id) as PuppeteerContactRawObj
log.silly('WebContact', `contactGetter(${this.id}) resolved`) log.silly('PuppeteerContact', `contactGetter(${this.id}) resolved`)
this.rawObj = rawObj this.rawObj = rawObj
this.obj = this.parse(rawObj) this.obj = this.parse(rawObj)
...@@ -477,7 +475,7 @@ export class WebContact extends Contact implements Sayable { ...@@ -477,7 +475,7 @@ export class WebContact extends Contact implements Sayable {
return this return this
} catch (e) { } catch (e) {
log.error('WebContact', `contactGetter(${this.id}) exception: %s`, e.message) log.error('PuppeteerContact', `contactGetter(${this.id}) exception: %s`, e.message)
Raven.captureException(e) Raven.captureException(e)
throw e throw e
} }
...@@ -532,13 +530,13 @@ export class WebContact extends Contact implements Sayable { ...@@ -532,13 +530,13 @@ export class WebContact extends Contact implements Sayable {
public weixin(): string | null { public weixin(): string | null {
const wxId = this.obj && this.obj.weixin || null const wxId = this.obj && this.obj.weixin || null
if (!wxId) { if (!wxId) {
log.verbose('WebContact', `weixin() is not able to always work, it's limited by Tencent API`) log.verbose('PuppeteerContact', `weixin() is not able to always work, it's limited by Tencent API`)
log.verbose('WebContact', 'weixin() If you want to track a contact between sessions, see FAQ at') log.verbose('PuppeteerContact', 'weixin() If you want to track a contact between sessions, see FAQ at')
log.verbose('WebContact', 'https://github.com/Chatie/wechaty/wiki/FAQ#1-how-to-get-the-permanent-id-for-a-contact') log.verbose('PuppeteerContact', 'https://github.com/Chatie/wechaty/wiki/FAQ#1-how-to-get-the-permanent-id-for-a-contact')
} }
return wxId return wxId
} }
} }
export default WebContact export default PuppeteerContact
...@@ -24,18 +24,23 @@ import * as test from 'blue-tape' ...@@ -24,18 +24,23 @@ import * as test from 'blue-tape'
import cloneClass from 'clone-class' import cloneClass from 'clone-class'
import PuppetMock from '../puppet-mock'
import Profile from '../profile' import Profile from '../profile'
import Wechaty from '../wechaty' import Wechaty from '../wechaty'
import WebContact from './web-contact' import {
import WebMessage from './web-message' Puppet,
import Puppet from '../abstract-puppet/puppet' } from '../abstract-puppet/'
import WebFriendRequest from './web-friend-request' import {
PuppetMock,
} from '../puppet-mock/'
test('PuppetWebFriendRequest.receive smoke testing', async t => { import PuppeteerContact from './puppeteer-contact'
import PuppeteerMessage from './puppeteer-message'
import PuppeteerFriendRequest from './puppeteer-friend-request'
test('PuppetPuppeteerFriendRequest.receive smoke testing', async t => {
// tslint:disable-next-line:variable-name // tslint:disable-next-line:variable-name
const MyFriendRequest = cloneClass(WebFriendRequest) const MyFriendRequest = cloneClass(PuppeteerFriendRequest)
MyFriendRequest.puppet = { MyFriendRequest.puppet = {
userId: 'xxx', userId: 'xxx',
} as any as Puppet } as any as Puppet
...@@ -52,17 +57,17 @@ test('PuppetWebFriendRequest.receive smoke testing', async t => { ...@@ -52,17 +57,17 @@ test('PuppetWebFriendRequest.receive smoke testing', async t => {
t.true(typeof fr.info === 'object', 'should has info object') t.true(typeof fr.info === 'object', 'should has info object')
t.is(fr.hello, '我是群聊"Wechaty"的李卓桓.PreAngel', 'should has right request message') t.is(fr.hello, '我是群聊"Wechaty"的李卓桓.PreAngel', 'should has right request message')
t.true(fr.contact instanceof WebContact, 'should have a Contact instance') t.true(fr.contact instanceof PuppeteerContact, 'should have a Contact instance')
t.is(fr.type as any, 'receive', 'should be receive type') t.is(fr.type as any, 'receive', 'should be receive type')
}) })
test('PuppetWebFriendRequest.confirm smoke testing', async t => { test('PuppetPuppeteerFriendRequest.confirm smoke testing', async t => {
// tslint:disable-next-line:variable-name // tslint:disable-next-line:variable-name
const MyFriendRequest = cloneClass(WebFriendRequest) const MyFriendRequest = cloneClass(PuppeteerFriendRequest)
// tslint:disable-next-line:variable-name // tslint:disable-next-line:variable-name
const MyContact = cloneClass(WebContact) const MyContact = cloneClass(PuppeteerContact)
// tslint:disable-next-line:variable-name // tslint:disable-next-line:variable-name
const MyMessage = cloneClass(WebMessage) const MyMessage = cloneClass(PuppeteerMessage)
MyContact.puppet = MyMessage.puppet = MyFriendRequest.puppet = { MyContact.puppet = MyMessage.puppet = MyFriendRequest.puppet = {
userId: 'xxx', userId: 'xxx',
...@@ -85,6 +90,6 @@ test('PuppetWebFriendRequest.confirm smoke testing', async t => { ...@@ -85,6 +90,6 @@ test('PuppetWebFriendRequest.confirm smoke testing', async t => {
const contact = m.from() const contact = m.from()
fr.confirm(contact || new MyContact('xx')) fr.confirm(contact || new MyContact('xx'))
t.true(fr.contact instanceof WebContact, 'should have a Contact instance') t.true(fr.contact instanceof PuppeteerContact, 'should have a Contact instance')
t.is(fr.type as any, 'confirm', 'should be confirm type') t.is(fr.type as any, 'confirm', 'should be confirm type')
}) })
...@@ -33,36 +33,38 @@ import { ...@@ -33,36 +33,38 @@ import {
// config, // config,
log, log,
} from '../config' } from '../config'
import FriendRequest from '../abstract-puppet/friend-request' import {
FriendRequest,
} from '../abstract-puppet/'
import { import {
RecommendInfo, RecommendInfo,
} from './schema' } from './schema'
import WebContact from './web-contact' import PuppeteerContact from './puppeteer-contact'
/** /**
* @alias FriendRequest * @alias FriendRequest
*/ */
export class WebFriendRequest extends FriendRequest { export class PuppeteerFriendRequest extends FriendRequest {
public info: RecommendInfo public info: RecommendInfo
private ticket: string private ticket: string
constructor() { constructor() {
log.verbose('WebFriendRequest', 'constructor()') log.verbose('PuppeteerFriendRequest', 'constructor()')
super() super()
} }
public receive(info: RecommendInfo): void { public receive(info: RecommendInfo): void {
log.verbose('WebFriendRequest', 'receive(%s)', info) log.verbose('PuppeteerFriendRequest', 'receive(%s)', info)
if (!info || !info.UserName) { if (!info || !info.UserName) {
throw new Error('not valid RecommendInfo: ' + info) throw new Error('not valid RecommendInfo: ' + info)
} }
this.info = info this.info = info
const contact = WebContact.load(info.UserName) const contact = PuppeteerContact.load(info.UserName)
contact.puppet = this.puppet contact.puppet = this.puppet
this.contact = contact this.contact = contact
...@@ -79,8 +81,8 @@ export class WebFriendRequest extends FriendRequest { ...@@ -79,8 +81,8 @@ export class WebFriendRequest extends FriendRequest {
return return
} }
public confirm(contact: WebContact): void { public confirm(contact: PuppeteerContact): void {
log.verbose('WebFriendRequest', 'confirm(%s)', contact) log.verbose('PuppeteerFriendRequest', 'confirm(%s)', contact)
if (!contact) { if (!contact) {
throw new Error('contact not found') throw new Error('contact not found')
...@@ -91,7 +93,7 @@ export class WebFriendRequest extends FriendRequest { ...@@ -91,7 +93,7 @@ export class WebFriendRequest extends FriendRequest {
/** /**
* Send a new friend request * Send a new friend request
* @param {WebContact} contact * @param {PuppeteerContact} contact
* @param {string} [hello='Hi'] * @param {string} [hello='Hi']
* @returns {Promise<boolean>} Return a Promise, true for accept successful, false for failure. * @returns {Promise<boolean>} Return a Promise, true for accept successful, false for failure.
* @example * @example
...@@ -99,8 +101,8 @@ export class WebFriendRequest extends FriendRequest { ...@@ -99,8 +101,8 @@ export class WebFriendRequest extends FriendRequest {
* const request = new FriendRequest() * const request = new FriendRequest()
* request.send(from, 'hello~') * request.send(from, 'hello~')
*/ */
public async send(contact: WebContact, hello = 'Hi'): Promise<void> { public async send(contact: PuppeteerContact, hello = 'Hi'): Promise<void> {
log.verbose('WebFriendRequest', 'send(%s)', contact) log.verbose('PuppeteerFriendRequest', 'send(%s)', contact)
if (!contact) { if (!contact) {
throw new Error('contact not found') throw new Error('contact not found')
...@@ -139,22 +141,22 @@ export class WebFriendRequest extends FriendRequest { ...@@ -139,22 +141,22 @@ export class WebFriendRequest extends FriendRequest {
// refresh to wait contact ready // refresh to wait contact ready
await retryPromise({ max: max, backoff: backoff }, async (attempt: number) => { await retryPromise({ max: max, backoff: backoff }, async (attempt: number) => {
log.silly('WebFriendRequest', 'accept() retryPromise() attempt %d with timeout %d', attempt, timeout) log.silly('PuppeteerFriendRequest', 'accept() retryPromise() attempt %d with timeout %d', attempt, timeout)
await this.contact.ready() await this.contact.ready()
if ((this.contact as WebContact).isReady()) { if ((this.contact as PuppeteerContact).isReady()) {
log.verbose('WebFriendRequest', 'accept() with contact %s ready()', this.contact.name()) log.verbose('PuppeteerFriendRequest', 'accept() with contact %s ready()', this.contact.name())
return return
} }
throw new Error('FriendRequest.accept() content.ready() not ready') throw new Error('FriendRequest.accept() content.ready() not ready')
}).catch( e => { }).catch( e => {
log.warn('WebFriendRequest', 'accept() rejected for contact %s because %s', this.contact, e && e.message || e) log.warn('PuppeteerFriendRequest', 'accept() rejected for contact %s because %s', this.contact, e && e.message || e)
}) })
} }
} }
export default WebFriendRequest export default PuppeteerFriendRequest
...@@ -31,19 +31,19 @@ import { ...@@ -31,19 +31,19 @@ import {
import Profile from '../profile' import Profile from '../profile'
import Wechaty from '../wechaty' import Wechaty from '../wechaty'
import PuppetWeb from './puppet-web' import PuppetPuppeteer from './puppet-puppeteer'
import WebContact from './web-contact' import PuppeteerContact from './puppeteer-contact'
import WebMessage from './web-message' import PuppeteerMessage from './puppeteer-message'
import WebRoom from './web-room' import PuppeteerRoom from './puppeteer-room'
// tslint:disable-next-line:variable-name // tslint:disable-next-line:variable-name
const MyRoom = cloneClass(WebRoom) const MyRoom = cloneClass(PuppeteerRoom)
// tslint:disable-next-line:variable-name // tslint:disable-next-line:variable-name
const MyContact = cloneClass(WebContact) const MyContact = cloneClass(PuppeteerContact)
// tslint:disable-next-line:variable-name // tslint:disable-next-line:variable-name
const MyMessage = cloneClass(WebMessage) const MyMessage = cloneClass(PuppeteerMessage)
const puppet = new PuppetWeb({ const puppet = new PuppetPuppeteer({
profile: new Profile(), profile: new Profile(),
wechaty: new Wechaty(), wechaty: new Wechaty(),
}) })
......
...@@ -27,12 +27,15 @@ import { ...@@ -27,12 +27,15 @@ import {
Raven, Raven,
log, log,
} from '../config' } from '../config'
import Message from '../abstract-puppet/message'
import Misc from '../misc' import Misc from '../misc'
import PuppetWeb from './puppet-web' import {
import WebContact from './web-contact' Message,
import WebRoom from './web-room' } from '../abstract-puppet/'
import PuppetPuppeteer from './puppet-puppeteer'
import PuppeteerContact from './puppeteer-contact'
import PuppeteerRoom from './puppeteer-room'
import { import {
AppMsgType, AppMsgType,
...@@ -54,7 +57,7 @@ export type ParsedPath = Partial<path.ParsedPath> ...@@ -54,7 +57,7 @@ export type ParsedPath = Partial<path.ParsedPath>
* `Message` is `Sayable`, * `Message` is `Sayable`,
* [Examples/Ding-Dong-Bot]{@link https://github.com/Chatie/wechaty/blob/master/examples/ding-dong-bot.ts} * [Examples/Ding-Dong-Bot]{@link https://github.com/Chatie/wechaty/blob/master/examples/ding-dong-bot.ts}
*/ */
export class WebMessage extends Message { export class PuppeteerMessage extends Message {
/** /**
* @private * @private
*/ */
...@@ -75,7 +78,7 @@ export class WebMessage extends Message { ...@@ -75,7 +78,7 @@ export class WebMessage extends Message {
fileOrObj?: string | MsgRawObj, fileOrObj?: string | MsgRawObj,
) { ) {
super() super()
log.silly('WebMessage', 'constructor()') log.silly('PuppeteerMessage', 'constructor()')
this.obj = {} as MsgObj this.obj = {} as MsgObj
...@@ -119,7 +122,7 @@ export class WebMessage extends Message { ...@@ -119,7 +122,7 @@ export class WebMessage extends Message {
} else if (/^@@/.test(rawObj.ToUserName)) { } else if (/^@@/.test(rawObj.ToUserName)) {
obj.room = rawObj.ToUserName obj.room = rawObj.ToUserName
} else { } else {
log.error('WebMessage', 'parse found a room message, but neither FromUserName nor ToUserName is a room(/^@@/)') log.error('PuppeteerMessage', 'parse found a room message, but neither FromUserName nor ToUserName is a room(/^@@/)')
// obj.room = undefined // bug compatible // obj.room = undefined // bug compatible
} }
if (obj.to && /^@@/.test(obj.to)) { // if a message in room without any specific receiver, then it will set to be `undefined` if (obj.to && /^@@/.test(obj.to)) { // if a message in room without any specific receiver, then it will set to be `undefined`
...@@ -134,7 +137,7 @@ export class WebMessage extends Message { ...@@ -134,7 +137,7 @@ export class WebMessage extends Message {
* @private * @private
*/ */
public toString() { public toString() {
return `WebMessage<${Misc.plainText(this.obj.content)}>` return `PuppeteerMessage<${Misc.plainText(this.obj.content)}>`
} }
/** /**
...@@ -149,12 +152,12 @@ export class WebMessage extends Message { ...@@ -149,12 +152,12 @@ export class WebMessage extends Message {
* @private * @private
*/ */
public getSenderString() { public getSenderString() {
const from = WebContact.load(this.obj.from) const from = PuppeteerContact.load(this.obj.from)
from.puppet = this.puppet from.puppet = this.puppet
const fromName = from.name() const fromName = from.name()
const roomTopic = this.obj.room const roomTopic = this.obj.room
? (':' + WebRoom.load(this.obj.room).topic()) ? (':' + PuppeteerRoom.load(this.obj.room).topic())
: '' : ''
return `<${fromName}${roomTopic}>` return `<${fromName}${roomTopic}>`
} }
...@@ -171,22 +174,22 @@ export class WebMessage extends Message { ...@@ -171,22 +174,22 @@ export class WebMessage extends Message {
/** /**
* @private * @private
*/ */
public from(contact: WebContact): void public from(contact: PuppeteerContact): void
/** /**
* @private * @private
*/ */
public from(id: string): void public from(id: string): void
public from(): WebContact public from(): PuppeteerContact
/** /**
* Get the sender from a message. * Get the sender from a message.
* @returns {Contact} * @returns {Contact}
*/ */
public from(contact?: WebContact|string): WebContact|void { public from(contact?: PuppeteerContact|string): PuppeteerContact|void {
if (contact) { if (contact) {
if (contact instanceof WebContact) { if (contact instanceof PuppeteerContact) {
this.obj.from = contact.id this.obj.from = contact.id
} else if (typeof contact === 'string') { } else if (typeof contact === 'string') {
this.obj.from = contact this.obj.from = contact
...@@ -196,7 +199,7 @@ export class WebMessage extends Message { ...@@ -196,7 +199,7 @@ export class WebMessage extends Message {
return return
} }
const loadedContact = WebContact.load(this.obj.from) as WebContact const loadedContact = PuppeteerContact.load(this.obj.from) as PuppeteerContact
loadedContact.puppet = this.puppet loadedContact.puppet = this.puppet
return loadedContact return loadedContact
...@@ -205,24 +208,24 @@ export class WebMessage extends Message { ...@@ -205,24 +208,24 @@ export class WebMessage extends Message {
/** /**
* @private * @private
*/ */
public room(room: WebRoom): void public room(room: PuppeteerRoom): void
/** /**
* @private * @private
*/ */
public room(id: string): void public room(id: string): void
public room(): WebRoom|null public room(): PuppeteerRoom|null
/** /**
* Get the room from the message. * Get the room from the message.
* If the message is not in a room, then will return `null` * If the message is not in a room, then will return `null`
* *
* @returns {(WebRoom|null)} * @returns {(PuppeteerRoom|null)}
*/ */
public room(room?: WebRoom|string): WebRoom|null|void { public room(room?: PuppeteerRoom|string): PuppeteerRoom|null|void {
if (room) { if (room) {
if (room instanceof WebRoom) { if (room instanceof PuppeteerRoom) {
this.obj.room = room.id this.obj.room = room.id
} else if (typeof room === 'string') { } else if (typeof room === 'string') {
this.obj.room = room this.obj.room = room
...@@ -232,7 +235,7 @@ export class WebMessage extends Message { ...@@ -232,7 +235,7 @@ export class WebMessage extends Message {
return return
} }
if (this.obj.room) { if (this.obj.room) {
const r = WebRoom.load(this.obj.room) as WebRoom const r = PuppeteerRoom.load(this.obj.room) as PuppeteerRoom
r.puppet = this.puppet r.puppet = this.puppet
return r return r
} }
...@@ -274,13 +277,13 @@ export class WebMessage extends Message { ...@@ -274,13 +277,13 @@ export class WebMessage extends Message {
return this.obj.content return this.obj.content
} }
public async say(textOrMessage: string | WebMessage, replyTo?: WebContact|WebContact[]): Promise<void> { public async say(textOrMessage: string | PuppeteerMessage, replyTo?: PuppeteerContact|PuppeteerContact[]): Promise<void> {
log.verbose('WebMessage', 'say(%s, %s)', textOrMessage, replyTo) log.verbose('PuppeteerMessage', 'say(%s, %s)', textOrMessage, replyTo)
let m: WebMessage let m: PuppeteerMessage
if (typeof textOrMessage === 'string') { if (typeof textOrMessage === 'string') {
m = new WebMessage() m = new PuppeteerMessage()
m.puppet = this.puppet m.puppet = this.puppet
const room = this.room() const room = this.room()
...@@ -329,7 +332,7 @@ export class WebMessage extends Message { ...@@ -329,7 +332,7 @@ export class WebMessage extends Message {
* @returns {MsgType} * @returns {MsgType}
*/ */
public type(): MsgType { public type(): MsgType {
log.silly('WebMessage', 'type() = %s', MsgType[this.obj.type]) log.silly('PuppeteerMessage', 'type() = %s', MsgType[this.obj.type])
return this.obj.type || MsgType.TEXT return this.obj.type || MsgType.TEXT
} }
...@@ -401,14 +404,14 @@ export class WebMessage extends Message { ...@@ -401,14 +404,14 @@ export class WebMessage extends Message {
* | Identify magic code (8197) by programming | ✘ | ✘ | ✘ | ✘ | * | Identify magic code (8197) by programming | ✘ | ✘ | ✘ | ✘ |
* | Identify two contacts with the same roomAlias by [You were mentioned] tip | ✘ | ✘ | √ | √ | * | Identify two contacts with the same roomAlias by [You were mentioned] tip | ✘ | ✘ | √ | √ |
* *
* @returns {WebContact[]} - Return message mentioned contactList * @returns {PuppeteerContact[]} - Return message mentioned contactList
* *
* @example * @example
* const contactList = message.mentioned() * const contactList = message.mentioned()
* console.log(contactList) * console.log(contactList)
*/ */
public mentioned(): WebContact[] { public mentioned(): PuppeteerContact[] {
let contactList: WebContact[] = [] let contactList: PuppeteerContact[] = []
const room = this.room() const room = this.room()
if (this.type() !== MsgType.TEXT || !room ) { if (this.type() !== MsgType.TEXT || !room ) {
return contactList return contactList
...@@ -444,7 +447,7 @@ export class WebMessage extends Message { ...@@ -444,7 +447,7 @@ export class WebMessage extends Message {
// flatten array, see http://stackoverflow.com/a/10865042/1123955 // flatten array, see http://stackoverflow.com/a/10865042/1123955
const mentionList = [].concat.apply([], rawMentionedList) const mentionList = [].concat.apply([], rawMentionedList)
log.verbose('WebMessage', 'mentioned(%s),get mentionList: %s', this.content(), JSON.stringify(mentionList)) log.verbose('PuppeteerMessage', 'mentioned(%s),get mentionList: %s', this.content(), JSON.stringify(mentionList))
contactList = [].concat.apply([], contactList = [].concat.apply([],
mentionList.map(nameStr => room.memberAll(nameStr)) mentionList.map(nameStr => room.memberAll(nameStr))
...@@ -461,13 +464,13 @@ export class WebMessage extends Message { ...@@ -461,13 +464,13 @@ export class WebMessage extends Message {
* @private * @private
*/ */
public async ready(): Promise<this> { public async ready(): Promise<this> {
log.silly('WebMessage', 'ready()') log.silly('PuppeteerMessage', 'ready()')
try { try {
/** /**
* 1. ready from contact * 1. ready from contact
*/ */
const from = WebContact.load(this.obj.from) const from = PuppeteerContact.load(this.obj.from)
from.puppet = this.puppet from.puppet = this.puppet
await from.ready() // Contact from await from.ready() // Contact from
...@@ -475,7 +478,7 @@ export class WebMessage extends Message { ...@@ -475,7 +478,7 @@ export class WebMessage extends Message {
* 2. ready to contact * 2. ready to contact
*/ */
if (this.obj.to) { if (this.obj.to) {
const to = WebContact.load(this.obj.to) const to = PuppeteerContact.load(this.obj.to)
to.puppet = this.puppet to.puppet = this.puppet
await to.ready() await to.ready()
} }
...@@ -484,13 +487,13 @@ export class WebMessage extends Message { ...@@ -484,13 +487,13 @@ export class WebMessage extends Message {
* 3. ready the room * 3. ready the room
*/ */
if (this.obj.room) { if (this.obj.room) {
const room = WebRoom.load(this.obj.room) const room = PuppeteerRoom.load(this.obj.room)
room.puppet = this.puppet room.puppet = this.puppet
await room.ready() // Room member list await room.ready() // Room member list
} }
} catch (e) { } catch (e) {
log.error('WebMessage', 'ready() exception: %s', e.stack) log.error('PuppeteerMessage', 'ready() exception: %s', e.stack)
Raven.captureException(e) Raven.captureException(e)
// console.log(e) // console.log(e)
// this.dump() // this.dump()
...@@ -504,9 +507,9 @@ export class WebMessage extends Message { ...@@ -504,9 +507,9 @@ export class WebMessage extends Message {
} }
public async readyMedia(): Promise<this> { public async readyMedia(): Promise<this> {
log.silly('WebMessage', 'readyMedia()') log.silly('PuppeteerMessage', 'readyMedia()')
const puppet = this.puppet as PuppetWeb const puppet = this.puppet as PuppetPuppeteer
try { try {
...@@ -550,7 +553,7 @@ export class WebMessage extends Message { ...@@ -550,7 +553,7 @@ export class WebMessage extends Message {
default: default:
const e = new Error('ready() unsupported typeApp(): ' + this.typeApp()) const e = new Error('ready() unsupported typeApp(): ' + this.typeApp())
log.warn('WebMessage', e.message) log.warn('PuppeteerMessage', e.message)
this.dumpRaw() this.dumpRaw()
throw e throw e
} }
...@@ -582,7 +585,7 @@ export class WebMessage extends Message { ...@@ -582,7 +585,7 @@ export class WebMessage extends Message {
this.obj.url = url this.obj.url = url
} catch (e) { } catch (e) {
log.warn('WebMessage', 'ready() exception: %s', e.message) log.warn('PuppeteerMessage', 'ready() exception: %s', e.message)
Raven.captureException(e) Raven.captureException(e)
throw e throw e
} }
...@@ -594,7 +597,7 @@ export class WebMessage extends Message { ...@@ -594,7 +597,7 @@ export class WebMessage extends Message {
* @private * @private
*/ */
public get(prop: string): string { public get(prop: string): string {
log.warn('WebMessage', 'DEPRECATED get() at %s', new Error('stack').stack) log.warn('PuppeteerMessage', 'DEPRECATED get() at %s', new Error('stack').stack)
if (!prop || !(prop in this.obj)) { if (!prop || !(prop in this.obj)) {
const s = '[' + Object.keys(this.obj).join(',') + ']' const s = '[' + Object.keys(this.obj).join(',') + ']'
...@@ -607,7 +610,7 @@ export class WebMessage extends Message { ...@@ -607,7 +610,7 @@ export class WebMessage extends Message {
* @private * @private
*/ */
public set(prop: string, value: string): this { public set(prop: string, value: string): this {
log.warn('WebMessage', 'DEPRECATED set() at %s', new Error('stack').stack) log.warn('PuppeteerMessage', 'DEPRECATED set() at %s', new Error('stack').stack)
if (typeof value !== 'string') { if (typeof value !== 'string') {
throw new Error('value must be string, we got: ' + typeof value) throw new Error('value must be string, we got: ' + typeof value)
...@@ -639,7 +642,7 @@ export class WebMessage extends Message { ...@@ -639,7 +642,7 @@ export class WebMessage extends Message {
* @todo add function * @todo add function
*/ */
public static async find(query) { public static async find(query) {
return Promise.resolve(new WebMessage(<MsgRawObj>{MsgId: '-1'})) return Promise.resolve(new PuppeteerMessage(<MsgRawObj>{MsgId: '-1'}))
} }
/** /**
...@@ -647,8 +650,8 @@ export class WebMessage extends Message { ...@@ -647,8 +650,8 @@ export class WebMessage extends Message {
*/ */
public static async findAll(query) { public static async findAll(query) {
return Promise.resolve([ return Promise.resolve([
new WebMessage (<MsgRawObj>{MsgId: '-2'}), new PuppeteerMessage (<MsgRawObj>{MsgId: '-2'}),
new WebMessage (<MsgRawObj>{MsgId: '-3'}), new PuppeteerMessage (<MsgRawObj>{MsgId: '-3'}),
]) ])
} }
...@@ -659,23 +662,23 @@ export class WebMessage extends Message { ...@@ -659,23 +662,23 @@ export class WebMessage extends Message {
/** /**
* @private * @private
*/ */
public to(contact: WebContact): void public to(contact: PuppeteerContact): void
/** /**
* @private * @private
*/ */
public to(id: string): void public to(id: string): void
public to(): WebContact | null // if to is not set, then room must had set public to(): PuppeteerContact | null // if to is not set, then room must had set
/** /**
* Get the destination of the message * Get the destination of the message
* Message.to() will return null if a message is in a room, use Message.room() to get the room. * Message.to() will return null if a message is in a room, use Message.room() to get the room.
* @returns {(Contact|null)} * @returns {(Contact|null)}
*/ */
public to(contact?: WebContact | string): WebContact | WebRoom | null | void { public to(contact?: PuppeteerContact | string): PuppeteerContact | PuppeteerRoom | null | void {
if (contact) { if (contact) {
if (contact instanceof WebContact) { if (contact instanceof PuppeteerContact) {
this.obj.to = contact.id this.obj.to = contact.id
} else if (typeof contact === 'string') { } else if (typeof contact === 'string') {
this.obj.to = contact this.obj.to = contact
...@@ -690,7 +693,7 @@ export class WebMessage extends Message { ...@@ -690,7 +693,7 @@ export class WebMessage extends Message {
if (!this.obj.to) { if (!this.obj.to) {
return null return null
} }
const to = WebContact.load(this.obj.to) as WebContact const to = PuppeteerContact.load(this.obj.to) as PuppeteerContact
to.puppet = this.puppet to.puppet = this.puppet
return to return to
...@@ -707,7 +710,7 @@ export class WebMessage extends Message { ...@@ -707,7 +710,7 @@ export class WebMessage extends Message {
* @returns {Promise<Readable>} * @returns {Promise<Readable>}
*/ */
public async readyStream(): Promise<Readable> { public async readyStream(): Promise<Readable> {
log.verbose('WebMessage', 'readyStream()') log.verbose('PuppeteerMessage', 'readyStream()')
/** /**
* 1. local file * 1. local file
...@@ -727,14 +730,14 @@ export class WebMessage extends Message { ...@@ -727,14 +730,14 @@ export class WebMessage extends Message {
try { try {
await this.ready() await this.ready()
// FIXME: decoupling needed // FIXME: decoupling needed
const cookies = await (this.puppet as any as PuppetWeb).cookies() const cookies = await (this.puppet as any as PuppetPuppeteer).cookies()
if (!this.obj.url) { if (!this.obj.url) {
throw new Error('no url') throw new Error('no url')
} }
log.verbose('WebMessage', 'readyStream() url: %s', this.obj.url) log.verbose('PuppeteerMessage', 'readyStream() url: %s', this.obj.url)
return Misc.urlStream(this.obj.url, cookies) return Misc.urlStream(this.obj.url, cookies)
} catch (e) { } catch (e) {
log.warn('WebMessage', 'readyStream() exception: %s', e.stack) log.warn('PuppeteerMessage', 'readyStream() exception: %s', e.stack)
Raven.captureException(e) Raven.captureException(e)
throw e throw e
} }
...@@ -818,7 +821,7 @@ export class WebMessage extends Message { ...@@ -818,7 +821,7 @@ export class WebMessage extends Message {
} }
break break
} }
log.silly('WebMessage', `ext() got unknown type: ${this.type()}`) log.silly('PuppeteerMessage', `ext() got unknown type: ${this.type()}`)
return String('.' + this.type()) return String('.' + this.type())
} }
...@@ -840,7 +843,7 @@ export class WebMessage extends Message { ...@@ -840,7 +843,7 @@ export class WebMessage extends Message {
if (!filePath) { if (!filePath) {
throw new Error('saveFile() filePath is invalid') throw new Error('saveFile() filePath is invalid')
} }
log.silly('WebMessage', `saveFile() filePath:'${filePath}'`) log.silly('PuppeteerMessage', `saveFile() filePath:'${filePath}'`)
if (fs.existsSync(filePath)) { if (fs.existsSync(filePath)) {
throw new Error('saveFile() file does exist!') throw new Error('saveFile() file does exist!')
} }
...@@ -849,7 +852,7 @@ export class WebMessage extends Message { ...@@ -849,7 +852,7 @@ export class WebMessage extends Message {
try { try {
readStream = await this.readyStream() readStream = await this.readyStream()
} catch (e) { } catch (e) {
log.error('WebMessage', `saveFile() call readyStream() error: ${e.message}`) log.error('PuppeteerMessage', `saveFile() call readyStream() error: ${e.message}`)
throw new Error(`saveFile() call readyStream() error: ${e.message}`) throw new Error(`saveFile() call readyStream() error: ${e.message}`)
} }
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {
...@@ -859,7 +862,7 @@ export class WebMessage extends Message { ...@@ -859,7 +862,7 @@ export class WebMessage extends Message {
.once('error', reject) .once('error', reject)
}) })
.catch(e => { .catch(e => {
log.error('WebMessage', `saveFile() error: ${e.message}`) log.error('PuppeteerMessage', `saveFile() error: ${e.message}`)
throw e throw e
}) })
} }
...@@ -913,7 +916,7 @@ export class WebMessage extends Message { ...@@ -913,7 +916,7 @@ export class WebMessage extends Message {
* @returns {Promise<boolean>} * @returns {Promise<boolean>}
* @memberof MediaMessage * @memberof MediaMessage
*/ */
public async forward(to: WebRoom|WebContact): Promise<void> { public async forward(to: PuppeteerRoom|PuppeteerContact): Promise<void> {
/** /**
* 1. Text message * 1. Text message
*/ */
...@@ -928,11 +931,11 @@ export class WebMessage extends Message { ...@@ -928,11 +931,11 @@ export class WebMessage extends Message {
try { try {
await this.puppet.forward(this, to) await this.puppet.forward(this, to)
} catch (e) { } catch (e) {
log.error('WebMessage', 'forward(%s) exception: %s', to, e) log.error('PuppeteerMessage', 'forward(%s) exception: %s', to, e)
throw e throw e
} }
} }
} }
export default WebMessage export default PuppeteerMessage
...@@ -27,19 +27,19 @@ import cloneClass from 'clone-class' ...@@ -27,19 +27,19 @@ import cloneClass from 'clone-class'
import Profile from '../profile' import Profile from '../profile'
import Wechaty from '../wechaty' import Wechaty from '../wechaty'
import PuppetWeb from './puppet-web' import PuppetPuppeteer from './puppet-puppeteer'
import WebContact from './web-contact' import PuppeteerContact from './puppeteer-contact'
import WebMessage from './web-message' import PuppeteerMessage from './puppeteer-message'
import WebRoom from './web-room' import PuppeteerRoom from './puppeteer-room'
// tslint:disable-next-line:variable-name // tslint:disable-next-line:variable-name
const MyRoom = cloneClass(WebRoom) const MyRoom = cloneClass(PuppeteerRoom)
// tslint:disable-next-line:variable-name // tslint:disable-next-line:variable-name
const MyContact = cloneClass(WebContact) const MyContact = cloneClass(PuppeteerContact)
// tslint:disable-next-line:variable-name // tslint:disable-next-line:variable-name
const MyMessage = cloneClass(WebMessage) const MyMessage = cloneClass(PuppeteerMessage)
const puppet = new PuppetWeb({ const puppet = new PuppetPuppeteer({
profile: new Profile(), profile: new Profile(),
wechaty: new Wechaty(), wechaty: new Wechaty(),
}) })
...@@ -192,7 +192,7 @@ test('Room smoking test', async t => { ...@@ -192,7 +192,7 @@ test('Room smoking test', async t => {
}) })
test('Room static method', async t => { test('Room static method', async t => {
MyRoom.puppet = new PuppetWeb({ MyRoom.puppet = new PuppetPuppeteer({
profile: new Profile(), profile: new Profile(),
wechaty: new Wechaty(), wechaty: new Wechaty(),
}) })
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
/** /**
* Wechaty - Wechat for Bot, and human who talk to bot. * Wechaty - Wechat for Bot, and human who talk to bot.
* *
* PuppetWeb: WechatyBro * PuppetPuppeteer: WechatyBro
* *
* Inject this js code to browser, * Inject this js code to browser,
* in order to interactive with wechat web program. * in order to interactive with wechat web program.
......
...@@ -30,7 +30,6 @@ import { ...@@ -30,7 +30,6 @@ import {
FriendRequest, FriendRequest,
IoClient, IoClient,
Message, Message,
PuppetWeb,
Room, Room,
Wechaty, Wechaty,
...@@ -48,7 +47,6 @@ test('Export of the Framework', async t => { ...@@ -48,7 +47,6 @@ test('Export of the Framework', async t => {
t.ok(IoClient , 'should export IoClient') t.ok(IoClient , 'should export IoClient')
t.ok(Message , 'should export Message') t.ok(Message , 'should export Message')
t.ok(Puppet , 'should export Puppet') t.ok(Puppet , 'should export Puppet')
t.ok(PuppetWeb , 'should export PuppetWeb')
t.ok(Room , 'should export Room') t.ok(Room , 'should export Room')
t.ok(Wechaty , 'should export Wechaty') t.ok(Wechaty , 'should export Wechaty')
t.ok(log , 'should export log') t.ok(log , 'should export log')
......
...@@ -31,32 +31,51 @@ import { ...@@ -31,32 +31,51 @@ import {
import StateSwitch from 'state-switch' import StateSwitch from 'state-switch'
import { import {
VERSION,
config, config,
log, log,
PuppetName,
Raven, Raven,
Sayable, Sayable,
VERSION, } from './config'
WechatyEvent, import Profile from './profile'
} from './config' import PuppetAccessory from './puppet-accessory'
import { import {
} from './message' PUPPET_DICT,
import Profile from './profile' PuppetName,
} from './puppet-config'
import { import {
Contact, Contact,
FriendRequest, FriendRequest,
Message, Message,
Puppet, Puppet,
PuppetAccessory,
Room, Room,
} from './abstract-puppet/' } from './abstract-puppet/'
export const WECHAT_EVENT_DICT = {
friend : 'tbw',
login : 'tbw',
logout : 'tbw',
message : 'tbw',
'room-join' : 'tbw',
'room-leave': 'tbw',
'room-topic': 'tbw',
scan : 'tbw',
}
import PuppetWeb from './puppet-web/' export const WECHATY_EVENT_DICT = {
import PuppetMock from './puppet-mock/' ...WECHAT_EVENT_DICT,
error: 'tbw',
heartbeat: 'tbw',
start: 'tbw',
stop: 'tbw',
}
export type WechatEventName = keyof typeof WECHAT_EVENT_DICT
export type WechatyEventName = keyof typeof WECHATY_EVENT_DICT
export interface WechatyOptions { export interface WechatyOptions {
puppet?: PuppetName, puppet?: PuppetName | Puppet,
profile?: string, profile?: string,
} }
...@@ -89,7 +108,7 @@ export class Wechaty extends PuppetAccessory implements Sayable { ...@@ -89,7 +108,7 @@ export class Wechaty extends PuppetAccessory implements Sayable {
* the cuid * the cuid
* @private * @private
*/ */
public cuid: string public readonly cuid: string
// tslint:disable-next-line:variable-name // tslint:disable-next-line:variable-name
public Contact : typeof Contact & Constructor<{}> public Contact : typeof Contact & Constructor<{}>
...@@ -230,7 +249,7 @@ export class Wechaty extends PuppetAccessory implements Sayable { ...@@ -230,7 +249,7 @@ export class Wechaty extends PuppetAccessory implements Sayable {
/** /**
* @listens Wechaty * @listens Wechaty
* @param {WechatyEvent} event - Emit WechatyEvent * @param {WechatyEventName} event - Emit WechatyEvent
* @param {WechatyEventFunction} listener - Depends on the WechatyEvent * @param {WechatyEventFunction} listener - Depends on the WechatyEvent
* @return {Wechaty} - this for chain * @return {Wechaty} - this for chain
* *
...@@ -287,7 +306,7 @@ export class Wechaty extends PuppetAccessory implements Sayable { ...@@ -287,7 +306,7 @@ export class Wechaty extends PuppetAccessory implements Sayable {
* console.log(`Room ${room.topic()} topic changed from ${oldTopic} to ${topic} by ${changer.name()}`) * console.log(`Room ${room.topic()} topic changed from ${oldTopic} to ${topic} by ${changer.name()}`)
* }) * })
*/ */
public on(event: WechatyEvent, listener: string | ((...args: any[]) => any)): this { public on(event: WechatyEventName, listener: string | ((...args: any[]) => any)): this {
log.verbose('Wechaty', 'on(%s, %s) registered', log.verbose('Wechaty', 'on(%s, %s) registered',
event, event,
typeof listener === 'string' typeof listener === 'string'
...@@ -303,7 +322,7 @@ export class Wechaty extends PuppetAccessory implements Sayable { ...@@ -303,7 +322,7 @@ export class Wechaty extends PuppetAccessory implements Sayable {
return this return this
} }
private onModulePath(event: WechatyEvent, modulePath: string): void { private onModulePath(event: WechatyEventName, modulePath: string): void {
const absoluteFilename = callerResolve(modulePath, __filename) const absoluteFilename = callerResolve(modulePath, __filename)
log.verbose('Wechaty', 'onModulePath() hotImpor(%s)', absoluteFilename) log.verbose('Wechaty', 'onModulePath() hotImpor(%s)', absoluteFilename)
hotImport(absoluteFilename) hotImport(absoluteFilename)
...@@ -323,7 +342,7 @@ export class Wechaty extends PuppetAccessory implements Sayable { ...@@ -323,7 +342,7 @@ export class Wechaty extends PuppetAccessory implements Sayable {
}) })
} }
private onFunction(event: WechatyEvent, listener: Function): void { private onFunction(event: WechatyEventName, listener: Function): void {
log.verbose('Wechaty', 'onFunction(%s)', event) log.verbose('Wechaty', 'onFunction(%s)', event)
super.on(event, (...args: any[]) => { super.on(event, (...args: any[]) => {
...@@ -339,43 +358,22 @@ export class Wechaty extends PuppetAccessory implements Sayable { ...@@ -339,43 +358,22 @@ export class Wechaty extends PuppetAccessory implements Sayable {
/** /**
* @private * @private
*/ */
public initPuppet(): Puppet { public initPuppet(): void {
log.verbose('Wechaty', 'initPuppet()') log.verbose('Wechaty', 'initPuppet()')
let puppet: Puppet let puppet: Puppet
switch (this.options.puppet) { if (typeof this.options.puppet === 'string') {
case 'web': puppet = new PUPPET_DICT[this.options.puppet]({
puppet = new PuppetWeb({ profile: this.profile,
profile: this.profile, wechaty: this,
wechaty: this, })
}) } else if (this.options.puppet instanceof Puppet) {
break puppet = this.options.puppet
} else {
case 'mock': throw new Error('unsupported options.puppet!')
puppet = new PuppetMock({
profile: this.profile,
wechaty: this,
})
break
default:
throw new Error('Puppet unsupport(yet?): ' + this.options.puppet)
} }
const eventList: WechatyEvent[] = [ for (const event of Object.keys(WECHATY_EVENT_DICT)) {
'error',
'friend',
'heartbeat',
'login',
'logout',
'message',
'room-join',
'room-leave',
'room-topic',
'scan',
]
for (const event of eventList) {
log.verbose('Wechaty', 'initPuppet() puppet.on(%s) registered', event) log.verbose('Wechaty', 'initPuppet() puppet.on(%s) registered', event)
/// e as any ??? Maybe this is a bug of TypeScript v2.5.3 /// e as any ??? Maybe this is a bug of TypeScript v2.5.3
puppet.on(event as any, (...args: any[]) => { puppet.on(event as any, (...args: any[]) => {
...@@ -384,7 +382,23 @@ export class Wechaty extends PuppetAccessory implements Sayable { ...@@ -384,7 +382,23 @@ export class Wechaty extends PuppetAccessory implements Sayable {
} }
/** /**
* Clone Classes for this bot * When `this` is the global instance of Wechaty (`Wechaty.instance()`)
* so we can keep using `Contact.find()` and `Room.find()`
*
* This workaround should be removed after v0.18
*
* See: fix the breaking changes for #518
* https://github.com/Chatie/wechaty/issues/518
*/
if (this === Wechaty._instance) {
Contact.puppet = puppet
FriendRequest.puppet = puppet
Message.puppet = puppet
Room.puppet = puppet
}
/**
* Clone Classes for this bot and attach the `puppet` to the Class
* *
* Fixme: * Fixme:
* https://stackoverflow.com/questions/36886082/abstract-constructor-type-in-typescript * https://stackoverflow.com/questions/36886082/abstract-constructor-type-in-typescript
...@@ -396,7 +410,12 @@ export class Wechaty extends PuppetAccessory implements Sayable { ...@@ -396,7 +410,12 @@ export class Wechaty extends PuppetAccessory implements Sayable {
this.Message = cloneClass(puppet.Message as any) this.Message = cloneClass(puppet.Message as any)
this.Room = cloneClass(puppet.Room as any) this.Room = cloneClass(puppet.Room as any)
return puppet this.Contact.puppet = puppet
this.FriendRequest.puppet = puppet
this.Message.puppet = puppet
this.Room.puppet = puppet
this.puppet = puppet
} }
/** /**
...@@ -424,32 +443,11 @@ export class Wechaty extends PuppetAccessory implements Sayable { ...@@ -424,32 +443,11 @@ export class Wechaty extends PuppetAccessory implements Sayable {
try { try {
this.profile.load() this.profile.load()
this.puppet = this.initPuppet() this.initPuppet()
// set puppet instance to Wechaty Static variable, for using by Contact/Room/Message/FriendRequest etc. // set puppet instance to Wechaty Static variable, for using by Contact/Room/Message/FriendRequest etc.
// config.puppetInstance(puppet) // config.puppetInstance(puppet)
if (this === Wechaty._instance) {
/**
* Here means `this` is the global instance of Wechaty (`Wechaty.instance()`)
* so we can keep using `Contact.find()` and `Room.find()`
*
* This workaround should be removed after v0.18
*
* See: fix the breaking changes for #518
* https://github.com/Chatie/wechaty/issues/518
*/
Contact.puppet = this.puppet
FriendRequest.puppet = this.puppet
Message.puppet = this.puppet
Room.puppet = this.puppet
}
this.Contact.puppet = this.puppet
this.FriendRequest.puppet = this.puppet
this.Message.puppet = this.puppet
this.Room.puppet = this.puppet
await this.puppet.start() await this.puppet.start()
} catch (e) { } catch (e) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册