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

rename PuppetWeb to PuppetPuppeteer for better naming

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