提交 da8c652f 编写于 作者: L lijiarui 提交者: Huan (李卓桓)

add wechaty document (#725)

* add doc

* remove useless doc

* change as request

* remove private

* add doc

* add docs index

* add todo & desprate

* change function order

* add \n

* code clean

* code clean

* recover contact order

* recover order

* change ignore & `

* change as request

* change Gender

* add overloading method declaration & change mstType
上级 19887f43
此差异已折叠。
/**
*
* Wechaty - https://github.com/chatie/wechaty
*
* Copyright 2016-2017 Huan LI <zixia@zixia.net>
* @copyright 2016-2017 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.
......@@ -15,6 +16,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @ignore
*/
import {
config,
......@@ -67,7 +69,11 @@ export interface ContactRawObj {
/**
* Enum for Gender values.
*
* @enum {number}
* @property {number} Unknown - 0 for Unknown
* @property {number} Male - 1 for Male
* @property {number} Female - 2 for Female
*/
export enum Gender {
Unknown = 0,
......@@ -84,6 +90,7 @@ export interface ContactQueryFilter {
/**
* @see https://github.com/Chatie/webwx-app-tracker/blob/7c59d35c6ea0cff38426a4c5c912a086c4c512b2/formatted/webwxApp.js#L3848
* @ignore
*/
const specialContactList: string[] = [
'weibo', 'qqmail', 'fmessage', 'tmessage', 'qmessage', 'qqsync', 'floatbottle',
......@@ -93,9 +100,10 @@ const specialContactList: string[] = [
]
/**
* Class Contact
* All wechat contacts(friend) will be encapsulated as a Contact.
*
* `Contact` is `Sayable`
* `Contact` is `Sayable`,
* [Example/Contact-Bot]{@link https://github.com/Chatie/wechaty/blob/master/example/contact-bot.ts}
*/
export class Contact implements Sayable {
private static pool = new Map<string, Contact>()
......@@ -117,6 +125,9 @@ export class Contact implements Sayable {
}
}
/**
* @private
*/
public toString(): string {
if (!this.obj) {
return this.id
......@@ -124,8 +135,14 @@ export class Contact implements Sayable {
return this.obj.alias || this.obj.name || this.id
}
/**
* @private
*/
public toStringEx() { return `Contact(${this.obj && this.obj.name}[${this.id}])` }
/**
* @private
*/
private parse(rawObj: ContactRawObj): ContactObj | null {
if (!rawObj || !rawObj.UserName) {
log.warn('Contact', 'parse() got empty rawObj!')
......@@ -150,25 +167,27 @@ export class Contact implements Sayable {
/**
* @see 1. https://github.com/Chatie/webwx-app-tracker/blob/7c59d35c6ea0cff38426a4c5c912a086c4c512b2/formatted/webwxApp.js#L3243
* @see 2. https://github.com/Urinx/WeixinBot/blob/master/README.md
* @ignore
*/
// tslint:disable-next-line
official: !!rawObj.UserName && !rawObj.UserName.startsWith('@@') && !!(rawObj.VerifyFlag & 8),
/**
* @see 1. https://github.com/Chatie/webwx-app-tracker/blob/7c59d35c6ea0cff38426a4c5c912a086c4c512b2/formatted/webwxApp.js#L3246
* @ignore
*/
special: specialContactList.indexOf(rawObj.UserName) > -1 || /@qqim$/.test(rawObj.UserName),
}
}
/**
* Get the weixin number from a contact
* Get the weixin number from a contact.
*
* Sometimes cannot get weixin number due to weixin security mechanism, not recommend.
* @returns {string | null}
*
* @deprecated
* @returns {string | null}
* @example
* ```ts
* const weixin = contact.weixin()
* ```
*/
public weixin(): string | null {
const wxId = this.obj && this.obj.weixin || null
......@@ -184,23 +203,17 @@ export class Contact implements Sayable {
* Get the name from a contact
*
* @returns {string}
*
* @example
* ```ts
* const name = contact.name()
* ```
*/
public name() { return UtilLib.plainText(this.obj && this.obj.name || '') }
/**
* Check if contact is stranger
*
* @returns {boolean | null} True for not friend of the bot, False for friend of the bot, null for cannot get the info.
*
* @returns {boolean | null} - True for not friend of the bot, False for friend of the bot, null for unknown.
* @example
* ```ts
* const isStranger = contact.stranger()
* ```
*/
public stranger(): boolean|null {
if (!this.obj) return null
......@@ -210,12 +223,11 @@ export class Contact implements Sayable {
/**
* Check if it's a offical account
*
* @returns {boolean|null} True for official account, Flase for contact is not a official account
*
* @returns {boolean|null} - True for official account, Flase for contact is not a official account, null for unknown
* @see {@link https://github.com/Chatie/webwx-app-tracker/blob/7c59d35c6ea0cff38426a4c5c912a086c4c512b2/formatted/webwxApp.js#L3243|webwxApp.js#L324}
* @see {@link https://github.com/Urinx/WeixinBot/blob/master/README.md|Urinx/WeixinBot/README}
* @example
* ```ts
* const isOfficial = contact.official()
* ```
*/
public official(): boolean {
return !!this.obj && this.obj.official
......@@ -224,22 +236,17 @@ export class Contact implements Sayable {
/**
* Check if it's a special contact
*
* the contact who's id in following list will be identify as a special contact
*
* ```ts
* 'weibo', 'qqmail', 'fmessage', 'tmessage', 'qmessage', 'qqsync', 'floatbottle',
* 'lbsapp', 'shakeapp', 'medianote', 'qqfriend', 'readerapp', 'blogapp', 'facebookapp',
* 'masssendapp', 'meishiapp', 'feedsapp', 'voip', 'blogappweixin', 'weixin', 'brandsessionholder',
* 'weixinreminder', 'wxid_novlwrv3lqwv11', 'gh_22b87fa7cb3c', 'officialaccounts', 'notification_messages',
* ```
* @see https://github.com/Chatie/webwx-app-tracker/blob/7c59d35c6ea0cff38426a4c5c912a086c4c512b2/formatted/webwxApp.js#L3848
* The contact who's id in following list will be identify as a special contact
* `weibo`, `qqmail`, `fmessage`, `tmessage`, `qmessage`, `qqsync`, `floatbottle`,
* `lbsapp`, `shakeapp`, `medianote`, `qqfriend`, `readerapp`, `blogapp`, `facebookapp`,
* `masssendapp`, `meishiapp`, `feedsapp`, `voip`, `blogappweixin`, `weixin`, `brandsessionholder`,
* `weixinreminder`, `wxid_novlwrv3lqwv11`, `gh_22b87fa7cb3c`, `officialaccounts`, `notification_messages`,
*
* @see {@link https://github.com/Chatie/webwx-app-tracker/blob/7c59d35c6ea0cff38426a4c5c912a086c4c512b2/formatted/webwxApp.js#L3848|webwxApp.js#L3848}
* @see {@link https://github.com/Chatie/webwx-app-tracker/blob/7c59d35c6ea0cff38426a4c5c912a086c4c512b2/formatted/webwxApp.js#L3246|webwxApp.js#L3246}
* @returns {boolean|null} True for brand, Flase for contact is not a brand
*
* @example
* ```ts
* const isSpecial = contact.special()
* ```
*/
public special(): boolean {
return !!this.obj && this.obj.special
......@@ -248,12 +255,9 @@ export class Contact implements Sayable {
/**
* Check if it's a personal account
*
* @returns {boolean|null} True for personal account, Flase for contact is not a personal account
*
* @returns {boolean|null} - True for personal account, Flase for contact is not a personal account
* @example
* ```ts
* const isPersonal = contact.personal()
* ```
*/
public personal(): boolean {
return !this.official()
......@@ -262,12 +266,9 @@ export class Contact implements Sayable {
/**
* Check if the contact is star contact.
*
* @returns {boolean} True for star friend, False for no star friend, null for cannot get the info.
*
* @returns {boolean} - True for star friend, False for no star friend.
* @example
* ```ts
* const isStar = contact.star()
* ```
*/
public star(): boolean|null {
if (!this.obj) return null
......@@ -277,12 +278,9 @@ export class Contact implements Sayable {
/**
* Contact gender
*
* @returns Gender.Male(2) | Gender.Female(1) | Gender.Unknown(0)
*
* @returns {Gender.Male(2)|Gender.Female(1)|Gender.Unknown(0)}
* @example
* ```ts
* const gender = contact.gender()
* ```
*/
public gender(): Gender { return this.obj ? this.obj.sex : Gender.Unknown }
......@@ -290,11 +288,8 @@ export class Contact implements Sayable {
* Get the region 'province' from a contact
*
* @returns {string | undefined}
*
* @example
* ```ts
* const province = contact.province()
* ```
*/
public province() { return this.obj && this.obj.province }
......@@ -302,11 +297,8 @@ export class Contact implements Sayable {
* Get the region 'city' from a contact
*
* @returns {string | undefined}
*
* @example
* ```ts
* const city = contact.city()
* ```
*/
public city() { return this.obj && this.obj.city }
......@@ -314,15 +306,12 @@ export class Contact implements Sayable {
* Get avatar picture file stream
*
* @returns {Promise<NodeJS.ReadableStream>}
*
* @example
* ```ts
* const avatarFileName = contact.name() + `.jpg`
* const avatarReadStream = await contact.avatar()
* const avatarWriteStream = createWriteStream(avatarFileName)
* avatarReadStream.pipe(avatarWriteStream)
* log.info('Bot', 'Contact: %s: %s with avatar file: %s', contact.weixin(), contact.name(), avatarFileName)
* ```
*/
public async avatar(): Promise<NodeJS.ReadableStream> {
log.verbose('Contact', 'avatar()')
......@@ -345,8 +334,14 @@ export class Contact implements Sayable {
}
}
/**
* @private
*/
public get(prop) { return this.obj && this.obj[prop] }
/**
* @private
*/
public isReady(): boolean {
return !!(this.obj && this.obj.id && this.obj.name)
}
......@@ -360,11 +355,8 @@ export class Contact implements Sayable {
* Force reload data for Contact
*
* @returns {Promise<this>}
*
* @example
* ```ts
* await contact.refresh()
* ```
*/
public async refresh(): Promise<this> {
if (this.isReady()) {
......@@ -379,6 +371,9 @@ export class Contact implements Sayable {
// return this.load()
// }
/**
* @private
*/
public async ready(contactGetter?: (id: string) => Promise<ContactRawObj>): Promise<this> {
log.silly('Contact', 'ready(' + (contactGetter ? typeof contactGetter : '') + ')')
if (!this.id) {
......@@ -413,11 +408,17 @@ export class Contact implements Sayable {
}
}
/**
* @private
*/
public dumpRaw() {
console.error('======= dump raw contact =======')
Object.keys(this.rawObj).forEach(k => console.error(`${k}: ${this.rawObj[k]}`))
}
/**
* @private
*/
public dump() {
console.error('======= dump contact =======')
Object.keys(this.obj).forEach(k => console.error(`${k}: ${this.obj && this.obj[k]}`))
......@@ -427,11 +428,8 @@ export class Contact implements Sayable {
* Check if contact is self
*
* @returns {boolean} True for contact is self, False for contact is others
*
* @example
* ```ts
* const isSelf = contact.self()
* ```
*/
public self(): boolean {
const userId = config.puppetInstance()
......@@ -447,27 +445,30 @@ export class Contact implements Sayable {
}
/**
* find contact by `name` or `alias`
* The way to search Contact
*
* @typedef ContactQueryFilter
* @property {string} name - The name-string set by user-self, should be called name
* @property {string} alias - The name-string set by bot for others, should be called alias
* [More Detail]{@link https://github.com/Chatie/wechaty/issues/365}
*/
/**
* Find contact by `name` or `alias`
*
* If use Contact.findAll() get the contact list of the bot.
*
* #### definition
* - `name` the name-string set by user-self, should be called name
* - `alias` the name-string set by bot for others, should be called alias
* - `name` the name-string set by user-self, should be called name
* - `alias` the name-string set by bot for others, should be called alias
*
* @static
* @param {ContactQueryFilter} [queryArg]
* @returns {Promise<Contact[]>}
*
* @example
* ```ts
* // get the contact list of the bot
* const contactList = await Contact.findAll()
* // find allof the contacts whose name is 'ruirui'
* const contactList = await Contact.findAll({name: 'ruirui'})
* // find allof the contacts whose alias is 'lijiarui'
* const contactList = await Contact.findAll({alias: 'lijiarui'})
* ```
* const contactList = await Contact.findAll() // get the contact list of the bot
* const contactList = await Contact.findAll({name: 'ruirui'}) // find allof the contacts whose name is 'ruirui'
* const contactList = await Contact.findAll({alias: 'lijiarui'}) // find all of the contacts whose alias is 'lijiarui'
*/
public static async findAll(queryArg?: ContactQueryFilter): Promise<Contact[]> {
let query: ContactQueryFilter
......@@ -538,91 +539,41 @@ export class Contact implements Sayable {
}
}
/**
* GET the alias for contact
*
* @returns {(string | null)}
*
* @example
* ```ts
* const alias = contact.alias()
* ```
*/
public alias(): string | null
/**
* SET the alias for contact
*
* tests show it will failed if set alias too frequently(60 times in one minute).
*
* @param {string} newAlias
* @returns {Promise<boolean>} A promise to the result. true for success, false for failure
*
* @example
* ```ts
* const ret = await contact.alias('lijiarui')
* if (ret) {
* console.log(`change ${contact.name()}'s alias successfully!`)
* } else {
* console.error('failed to change ${contact.name()}'s alias!')
* }
* ```
*/
public alias(newAlias: string): Promise<boolean>
/**
* DELETE the alias for a contact
*
* @param {null} empty
* @returns {Promise<boolean>}
*
* @example
* ```ts
* const ret = await contact.alias(null)
* if (ret) {
* console.log(`delete ${contact.name()}'s alias successfully!`)
* } else {
* console.log(`failed to delete ${contact.name()}'s alias!`)
* }
* ```
*/
public alias(empty: null): Promise<boolean>
/**
* GET / SET / DELETE the alias for a contact
*
* @param {(none | string | null)} newAlias ,
* Tests show it will failed if set alias too frequently(60 times in one minute).
* @param {(none | string | null)} newAlias
* @returns {(string | null | Promise<boolean>)}
*
* @example GET the alias for a contact
* ```ts
* @example <caption> GET the alias for a contact, return {(string | null)}</caption>
* const alias = contact.alias()
* if (alias === null) {
* console.log('You have not yet set any alias for contact ' + contact.name())
* } else {
* console.log('You have already set an alias for contact ' + contact.name() + ':' + alias)
* }
* ```
*
* @example SET the alias for a contact
* ```ts
* @example <caption>SET the alias for a contact</caption>
* const ret = await contact.alias('lijiarui')
* if (ret) {
* console.log(`change ${contact.name()}'s alias successfully!`)
* } else {
* console.error('failed to change ${contact.name()}'s alias!')
* console.log(`failed to change ${contact.name()} alias!`)
* }
* ```
*
* @example DELETE the alias for a contact
* ```ts
* @example <caption>DELETE the alias for a contact</caption>
* const ret = await contact.alias(null)
* if (ret) {
* console.log(`delete ${contact.name()}'s alias successfully!`)
* } else {
* console.log(`failed to delete ${contact.name()}'s alias!`)
* }
* ```
*/
public alias(newAlias?: string|null): Promise<boolean> | string | null {
log.silly('Contact', 'alias(%s)', newAlias || '')
......@@ -652,6 +603,9 @@ export class Contact implements Sayable {
})
}
/**
* @private
*/
// function should be deprecated
public remark(newRemark?: string|null): Promise<boolean> | string | null {
log.warn('Contact', 'remark(%s) DEPRECATED, use alias(%s) instead.')
......@@ -668,17 +622,16 @@ export class Contact implements Sayable {
}
/**
* try to find a contact by filter: {name: string | RegExp} / {alias: string | RegExp}
* @description Find contact by name or alias, if the result more than one, return the first one.
* Try to find a contact by filter: {name: string | RegExp} / {alias: string | RegExp}
*
* Find contact by name or alias, if the result more than one, return the first one.
*
* @static
* @param {ContactQueryFilter} query
* @returns {(Promise<Contact | null>)} If can find the contact, return Contact, or return null
*
* @example
* ```ts
* const contactFindByName = await Contact.find({ name:"ruirui"} )
* const contactFindByAlias = await Contact.find({ alias:"lijiarui"} )
* ```
*/
public static async find(query: ContactQueryFilter): Promise<Contact | null> {
log.verbose('Contact', 'find(%s)', JSON.stringify(query))
......@@ -695,17 +648,7 @@ export class Contact implements Sayable {
}
/**
* Load data for Contact by id
*
* @static
* @param {string} id
* @returns {Contact}
*
* @example
* ```ts
* // fake: contactId = @0bb3e4dd746fdbd4a80546aef66f4085
* const contact = Contact.load('@0bb3e4dd746fdbd4a80546aef66f4085')
* ```
* @private
*/
public static load(id: string): Contact {
if (!id || typeof id !== 'string') {
......@@ -719,19 +662,30 @@ export class Contact implements Sayable {
}
/**
* Say `content` to Contact
*
* @param {string} content
* @returns {Promise<void>}
* Sent Text to contact
*
* @example
* ```ts
* await contact.say('welcome to wechaty!')
* ```
* @param {string} text
*/
public async say(text: string)
/**
* Send Media File to Contact
*
* @param {MediaMessage} mediaMessage
* @memberof Contact
*/
public async say(mediaMessage: MediaMessage)
/**
* Send Text or Media File to Contact.
*
* @param {(string | MediaMessage)} textOrMedia
* @returns {Promise<boolean>}
* @example
* const contact = await Contact.find({name: 'lijiarui'}) // change 'lijiarui' to any of your contact name in wechat
* 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(textOrMedia: string | MediaMessage): Promise<boolean> {
const content = textOrMedia instanceof MediaMessage ? textOrMedia.filename() : textOrMedia
log.verbose('Contact', 'say(%s)', content)
......
......@@ -14,7 +14,7 @@
* 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.
*
* @ignore
*/
import * as fs from 'fs'
import * as path from 'path'
......@@ -160,6 +160,29 @@ export interface MsgTypeMap {
// , MessageTypeValue: MessageTypeName
}
/**
*
* Enum for AppMsgType values.
*
* @enum {number}
* @property {number} TEXT - AppMsgType.TEXT (1) for TEXT
* @property {number} IMG - AppMsgType.IMG (2) for IMG
* @property {number} AUDIO - AppMsgType.AUDIO (3) for AUDIO
* @property {number} VIDEO - AppMsgType.VIDEO (4) for VIDEO
* @property {number} URL - AppMsgType.URL (5) for URL
* @property {number} ATTACH - AppMsgType.ATTACH (6) for ATTACH
* @property {number} OPEN - AppMsgType.OPEN (7) for OPEN
* @property {number} EMOJI - AppMsgType.EMOJI (8) for EMOJI
* @property {number} VOICE_REMIND - AppMsgType.VOICE_REMIND (9) for VOICE_REMIND
* @property {number} SCAN_GOOD - AppMsgType.SCAN_GOOD (10) for SCAN_GOOD
* @property {number} GOOD - AppMsgType.GOOD (13) for GOOD
* @property {number} EMOTION - AppMsgType.EMOTION (15) for EMOTION
* @property {number} CARD_TICKET - AppMsgType.CARD_TICKET (16) for CARD_TICKET
* @property {number} REALTIME_SHARE_LOCATION - AppMsgType.REALTIME_SHARE_LOCATION (17) for REALTIME_SHARE_LOCATION
* @property {number} TRANSFERS - AppMsgType.TRANSFERS (2e3) for TRANSFERS
* @property {number} RED_ENVELOPES - AppMsgType.RED_ENVELOPES (2001) for RED_ENVELOPES
* @property {number} READER_TYPE - AppMsgType.READER_TYPE (100001) for READER_TYPE
*/
export enum AppMsgType {
TEXT = 1,
IMG = 2,
......@@ -180,6 +203,29 @@ export enum AppMsgType {
READER_TYPE = 100001,
}
/**
*
* Enum for MsgType values.
* @enum {number}
* @property {number} TEXT - MsgType.TEXT (1) for TEXT
* @property {number} IMAGE - MsgType.IMAGE (3) for IMAGE
* @property {number} VOICE - MsgType.VOICE (34) for VOICE
* @property {number} VERIFYMSG - MsgType.VERIFYMSG (37) for VERIFYMSG
* @property {number} POSSIBLEFRIEND_MSG - MsgType.POSSIBLEFRIEND_MSG (40) for POSSIBLEFRIEND_MSG
* @property {number} SHARECARD - MsgType.SHARECARD (42) for SHARECARD
* @property {number} VIDEO - MsgType.VIDEO (43) for VIDEO
* @property {number} EMOTICON - MsgType.EMOTICON (47) for EMOTICON
* @property {number} LOCATION - MsgType.LOCATION (48) for LOCATION
* @property {number} APP - MsgType.APP (49) for APP
* @property {number} VOIPMSG - MsgType.VOIPMSG (50) for VOIPMSG
* @property {number} STATUSNOTIFY - MsgType.STATUSNOTIFY (51) for STATUSNOTIFY
* @property {number} VOIPNOTIFY - MsgType.VOIPNOTIFY (52) for VOIPNOTIFY
* @property {number} VOIPINVITE - MsgType.VOIPINVITE (53) for VOIPINVITE
* @property {number} MICROVIDEO - MsgType.MICROVIDEO (62) for MICROVIDEO
* @property {number} SYSNOTICE - MsgType.SYSNOTICE (9999) for SYSNOTICE
* @property {number} SYS - MsgType.SYS (10000) for SYS
* @property {number} RECALLED - MsgType.RECALLED (10002) for RECALLED
*/
export enum MsgType {
TEXT = 1,
IMAGE = 3,
......@@ -201,8 +247,21 @@ export enum MsgType {
RECALLED = 10002,
}
/**
* All wechat messages will be encapsulated as a Message.
*
* `Message` is `Sayable`,
* [Example/Ding-Dong-Bot]{@link https://github.com/Chatie/wechaty/blob/master/example/ding-dong-bot.ts}
*/
export class Message implements Sayable {
/**
* @private
*/
public static counter = 0
/**
* @private
*/
public _counter: number
// DEPRECATED: TypeScript ENUM did this for us 201705
......@@ -232,14 +291,26 @@ export class Message implements Sayable {
// RECALLED: 10002,
// }
/**
* @private
*/
public readonly id: string
/**
* @private
*/
public obj = <MsgObj>{}
/**
* @private
*/
public readyStream(): Promise<Readable> {
throw Error('abstract method')
}
/**
* @private
*/
public filename(): string {
throw Error('not a media message')
}
......@@ -260,6 +331,9 @@ export class Message implements Sayable {
this.id = this.obj.id
}
/**
* @private
*/
// Transform rawObj to local obj
private parse(rawObj): MsgObj {
const obj: MsgObj = {
......@@ -291,20 +365,35 @@ export class Message implements Sayable {
return obj
}
/**
* @private
*/
public toString() {
return UtilLib.plainText(this.obj.content)
}
/**
* @private
*/
public toStringDigest() {
const text = UtilLib.digestEmoji(this.obj.digest)
return '{' + this.typeEx() + '}' + text
}
/**
* @private
*/
public toStringEx() {
let s = `${this.constructor.name}#${this._counter}`
s += '(' + this.getSenderString()
s += ':' + this.getContentString() + ')'
return s
}
/**
* @private
*/
public getSenderString() {
const fromName = Contact.load(this.obj.from).name()
const roomTopic = this.obj.room
......@@ -312,6 +401,10 @@ export class Message implements Sayable {
: ''
return `<${fromName}${roomTopic}>`
}
/**
* @private
*/
public getContentString() {
let content = UtilLib.plainText(this.obj.content)
if (content.length > 20) { content = content.substring(0, 17) + '...' }
......@@ -319,11 +412,21 @@ export class Message implements Sayable {
}
/**
* @todo document me
* @private
*/
public from(contact: Contact): void
/**
* @private
*/
public from(id: string): void
public from(): Contact
/**
* Get the sender from a message.
* @returns {Contact}
*/
public from(contact?: Contact|string): Contact|void {
if (contact) {
if (contact instanceof Contact) {
......@@ -346,13 +449,24 @@ export class Message implements Sayable {
// public to(room: Room): void
// public to(): Contact|Room
// public to(contact?: Contact|Room|string): Contact|Room|void {
/**
* @todo document me
* @private
*/
public to(contact: Contact): void
/**
* @private
*/
public to(id: string): void
public to(): Contact|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?: Contact|string): Contact|Room|null|void {
if (contact) {
if (contact instanceof Contact) {
......@@ -374,11 +488,23 @@ export class Message implements Sayable {
}
/**
* @todo document me
* @private
*/
public room(room: Room): void
/**
* @private
*/
public room(id: string): void
public room(): Room|null
/**
* Get the room from the message.
* If the message is not in a room, then will return `null`
*
* @returns {(Room|null)}
*/
public room(room?: Room|string): Room|null|void {
if (room) {
if (room instanceof Room) {
......@@ -397,11 +523,22 @@ export class Message implements Sayable {
}
/**
* @todo document me
* Get the content of the message
*
* @returns {string}
*/
public content(): string
/**
* @private
*/
public content(content: string): void
/**
* Get the content of the message
*
* @returns {string}
*/
public content(content?: string): string|void {
if (content) {
this.obj.content = content
......@@ -411,14 +548,22 @@ export class Message implements Sayable {
}
/**
* @todo document me
* Get the type from the message.
*
* @see {@link MsgType}
* @returns {MsgType}
*/
public type(): MsgType {
return this.obj.type
}
/**
* @todo document me
* Get the typeSub from the message.
*
* If message is a location message: `m.type() === MsgType.TEXT && m.typeSub() === MsgType.LOCATION`
*
* @see {@link MsgType}
* @returns {MsgType}
*/
public typeSub(): MsgType {
if (!this.rawObj) {
......@@ -428,7 +573,10 @@ export class Message implements Sayable {
}
/**
* @todo document me
* Get the typeApp from the message.
*
* @returns {AppMsgType}
* @see {@link AppMsgType}
*/
public typeApp(): AppMsgType {
if (!this.rawObj) {
......@@ -438,16 +586,25 @@ export class Message implements Sayable {
}
/**
* @todo document me
* Get the typeEx from the message.
*
* @returns {MsgType}
*/
public typeEx() { return MsgType[this.obj.type] }
/**
* @todo document me
* @private
*/
public count() { return this._counter }
/**
* @todo document me
* Check if a message is sent by self.
*
* @returns {boolean} - Return `true` for send from self, `false` for send from others.
* @example
* if (message.self()) {
* console.log('this message is sent by myself!')
* }
*/
public self(): boolean {
const userId = config.puppetInstance()
......@@ -464,7 +621,8 @@ export class Message implements Sayable {
/**
*
* Get message mentioned contactList.
* message event table as follows
*
* Message event table as follows
*
* | | Web | Mac PC Client | iOS Mobile | android Mobile |
* | :--- | :--: | :----: | :---: | :---: |
......@@ -473,13 +631,11 @@ export class Message implements Sayable {
* | Identify magic code (8197) by programming | ✘ | ✘ | ✘ | ✘ |
* | Identify two contacts with the same roomAlias by [You were mentioned] tip | ✘ | ✘ | √ | √ |
*
* @returns {Contact[]} return message mentioned contactList
* @returns {Contact[]} - Return message mentioned contactList
*
* @example
* ```ts
* const contactList = message.mentioned()
* console.log(contactList)
* ```
*/
public mentioned(): Contact[] {
let contactList: Contact[] = []
......@@ -531,6 +687,9 @@ export class Message implements Sayable {
return contactList
}
/**
* @private
*/
public async ready(): Promise<void> {
log.silly('Message', 'ready()')
......@@ -559,7 +718,7 @@ export class Message implements Sayable {
}
/**
* @deprecated
* @private
*/
public get(prop: string): string {
log.warn('Message', 'DEPRECATED get() at %s', new Error('stack').stack)
......@@ -572,7 +731,7 @@ export class Message implements Sayable {
}
/**
* @deprecated
* @private
*/
public set(prop: string, value: string): this {
log.warn('Message', 'DEPRECATED set() at %s', new Error('stack').stack)
......@@ -584,19 +743,32 @@ export class Message implements Sayable {
return this
}
/**
* @private
*/
public dump() {
console.error('======= dump message =======')
Object.keys(this.obj).forEach(k => console.error(`${k}: ${this.obj[k]}`))
}
/**
* @private
*/
public dumpRaw() {
console.error('======= dump raw message =======')
Object.keys(this.rawObj).forEach(k => console.error(`${k}: ${this.rawObj && this.rawObj[k]}`))
}
/**
* @todo add function
*/
public static async find(query) {
return Promise.resolve(new Message(<MsgRawObj>{MsgId: '-1'}))
}
/**
* @todo add function
*/
public static async findAll(query) {
return Promise.resolve([
new Message (<MsgRawObj>{MsgId: '-2'}),
......@@ -612,12 +784,30 @@ export class Message implements Sayable {
// })
// }
/**
* @todo document me
*/
public say(text: string, replyTo?: Contact | Contact[]): Promise<any>
public say(mediaMessage: MediaMessage, replyTo?: Contact | Contact[]): Promise<any>
/**
* Reply a Text or Media File message to the sender.
*
* @see {@link https://github.com/Chatie/wechaty/blob/master/example/ding-dong-bot.ts|Example/ding-dong-bot}
* @param {(string | MediaMessage)} textOrMedia
* @param {(Contact|Contact[])} [replyTo]
* @returns {Promise<any>}
*
* @example
* const bot = Wechaty.instance()
* bot
* .on('message', async m => {
* if (/^ding$/i.test(m.content())) {
* await m.say('hello world')
* console.log('Bot REPLY: hello world')
* await m.say(new MediaMessage(__dirname + '/wechaty.png'))
* console.log('Bot REPLY: Image')
* }
* })
*/
public say(textOrMedia: string | MediaMessage, replyTo?: Contact|Contact[]): Promise<any> {
/* tslint:disable:no-use-before-declare */
const content = textOrMedia instanceof MediaMessage ? textOrMedia.filename() : textOrMedia
......@@ -666,13 +856,39 @@ export class Message implements Sayable {
// Message.initType()
/**
* Meidia Type Message
*
*/
export class MediaMessage extends Message {
/**
* @private
*/
private bridge: Bridge
/**
* @private
*/
private filePath: string
/**
* @private
*/
private fileName: string // 'music'
/**
* @private
*/
private fileExt: string // 'mp3'
/**
* @private
*/
constructor(rawObj: Object)
/**
* @private
*/
constructor(filePath: string)
constructor(rawObjOrFilePath: Object | string) {
......@@ -694,6 +910,9 @@ export class MediaMessage extends Message {
.bridge
}
/**
* @private
*/
public async ready(): Promise<void> {
log.silly('MediaMessage', 'ready()')
......@@ -773,7 +992,15 @@ export class MediaMessage extends Message {
}
/**
* @todo document me
* Get the MediaMessage file extension, etc: `jpg`, `gif`, `pdf`, `word` ..
*
* @returns {string}
* @example
* bot.on('message', async function (m) {
* if (m instanceof MediaMessage) {
* console.log('media message file name extention is: ' + m.ext())
* }
* })
*/
public ext(): string {
if (this.fileExt)
......@@ -810,7 +1037,15 @@ export class MediaMessage extends Message {
}
/**
* @todo document me
* Get the MediaMessage filename, etc: `how to build a chatbot.pdf`..
*
* @returns {string}
* @example
* bot.on('message', async function (m) {
* if (m instanceof MediaMessage) {
* console.log('media message file name is: ' + m.filename())
* }
* })
*/
public filename(): string {
if (this.fileName && this.fileExt) {
......@@ -839,6 +1074,9 @@ export class MediaMessage extends Message {
// })
// }
/**
* @private
*/
public async readyStream(): Promise<Readable> {
if (this.filePath)
return fs.createReadStream(this.filePath)
......
此差异已折叠。
/**
* Wechaty - https://github.com/chatie/wechaty
*
* Copyright 2016-2017 Huan LI <zixia@zixia.net>
* Wechaty - https://github.com/chatie/wechaty
* 2016-2017 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
* 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
* 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.
* 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.
*
* Wechaty: Wechat for ChatBots.
*
* Wechaty is a Bot Framework for Wechat **Personal** Account
* which can help you create a bot in 6 lines of javascript
* by easy to use API, with cross-platform support for
* Linux/Mac/Windows.
*
* @ignore
*/
import { EventEmitter } from 'events'
import { StateSwitch } from 'state-switch'
......@@ -59,27 +68,14 @@ export type WechatyEventName = 'error'
| 'EVENT_PARAM_ERROR'
/**
* Main bot class.
*
* Wechaty: Wechat for ChatBots.
*
* Wechaty is a Bot Framework for Wechat **Personal** Account
* which can help you create a bot in 6 lines of javascript
* by easy to use API, with cross-platform support for
* Linux/Mac/Windows.
* [The World's Shortest ChatBot Code: 6 lines of JavaScript]{@link #wechatyinstance}
*
* **Example**
* [Wechaty Starter Project]{@link https://github.com/lijiarui/wechaty-getting-started}
* @example
* import { Wechaty } from 'wechaty'
*
* ```ts
* // The World's Shortest ChatBot Code: 6 lines of JavaScript
* const { Wechaty } = require('wechaty')
*
* Wechaty.instance() // Singleton
* .on('scan', (url, code) => console.log(`Scan QR Code to login: ${code}\n${url}`))
* .on('login', user => console.log(`User ${user} logined`))
* .on('message', message => console.log(`Message: ${message}`))
* .init()
* ```
* @see The <a href="https://github.com/lijiarui/wechaty-getting-started">Wechaty Starter Project</a>
*/
export class Wechaty extends EventEmitter implements Sayable {
/**
......@@ -108,6 +104,15 @@ export class Wechaty extends EventEmitter implements Sayable {
/**
* get the singleton instance of Wechaty
*
* @example <caption>The World's Shortest ChatBot Code: 6 lines of JavaScript</caption>
* const { Wechaty } = require('wechaty')
*
* Wechaty.instance() // Singleton
* .on('scan', (url, code) => console.log(`Scan QR Code to login: ${code}\n${url}`))
* .on('login', user => console.log(`User ${user} logined`))
* .on('message', message => console.log(`Message: ${message}`))
* .init()
*/
public static instance(setting?: PuppetSetting) {
if (setting && this._instance) {
......@@ -153,10 +158,8 @@ export class Wechaty extends EventEmitter implements Sayable {
* otherwise will return git commit hash if .git exists.
* @returns {string} - the version number
* @example
* console.log(Wechaty.instance().version())
* // '#git[af39df]'
* console.log(Wechaty.instance().version(true))
* // '0.7.9'
* console.log(Wechaty.instance().version()) // return '#git[af39df]'
* console.log(Wechaty.instance().version(true)) // return '0.7.9'
*/
public static version(forceNpm = false): string {
if (!forceNpm) {
......@@ -169,16 +172,14 @@ export class Wechaty extends EventEmitter implements Sayable {
}
/**
* @todo document me
* @private
*/
public version(forceNpm?) {
return Wechaty.version(forceNpm)
}
/**
* @todo document me
* @returns {Contact}
* @deprecated
* @private
*/
public user(): Contact {
log.warn('Wechaty', 'user() DEPRECATED. use self() instead.')
......@@ -202,7 +203,12 @@ export class Wechaty extends EventEmitter implements Sayable {
}
/**
* @todo document me
* Initialize the bot, return Promise.
*
* @returns {Promise<void>}
* @example
* await bot.init()
* // do other stuff with bot here
*/
public async init(): Promise<void> {
log.info('Wechaty', 'v%s initializing...' , this.version())
......@@ -231,56 +237,127 @@ export class Wechaty extends EventEmitter implements Sayable {
return
}
// public on(event: WechatyEventName, listener: Function): this
/**
* @listens Wechaty#error
* @param {string} [event='error'] - the `error` event name
* @param {Function} listener - (error) => void callback function
* @return {Wechaty} - this for chain
*/
public on(event: 'error' , listener: (this: Wechaty, error: Error) => void): this
/**
* @todo document me
*/
public on(event: 'friend' , listener: (this: Wechaty, friend: Contact, request?: FriendRequest) => void): this
/**
* @todo document me
*/
public on(event: 'heartbeat' , listener: (this: Wechaty, data: any) => void): this
/**
* @todo document me
*/
public on(event: 'logout' , listener: (this: Wechaty, user: Contact) => void): this
/**
* @todo document me
*/
public on(event: 'login' , listener: (this: Wechaty, user: Contact) => void): this
/**
* @todo document me
*/
public on(event: 'message' , listener: (this: Wechaty, message: Message) => void): this
/**
* @todo document me
*/
public on(event: 'room-join' , listener: (this: Wechaty, room: Room, inviteeList: Contact[], inviter: Contact) => void): this
/**
* @todo document me
*/
public on(event: 'room-leave' , listener: (this: Wechaty, room: Room, leaverList: Contact[]) => void): this
/**
* @todo document me
*/
public on(event: 'room-topic' , listener: (this: Wechaty, room: Room, topic: string, oldTopic: string, changer: Contact) => void): this
/**
* @todo document me
*/
public on(event: 'scan' , listener: (this: Wechaty, url: string, code: number) => void): this
/**
* @todo document me
*/
public on(event: 'EVENT_PARAM_ERROR', listener: () => void): this
/**
* @todo document me
* @desc Wechaty Class Event Type
* @typedef WechatyEventName
* @property {string} error - When the bot get error, there will be a Wechaty error event fired.
* @property {string} login - After the bot login full successful, the event login will be emitted, with a Contact of current logined user.
* @property {string} logout - Logout will be emitted when bot detected log out, with a Contact of the current login user.
* @property {string} scan - A scan event will be emitted when the bot needs to show you a QR Code for scanning.
* @property {string} heartbeat - Get bot's heartbeat.
* @property {string} friend - When someone sends you a friend request, there will be a Wechaty friend event fired.
* @property {string} message - Emit when there's a new message.
* @property {string} room-join - Emit when anyone join any room.
* @property {string} room-topic - Get topic event, emitted when someone change room topic.
* @property {string} room-leave - Emit when anyone leave the room.<br>
* If someone leaves the room by themselves, wechat will not notice other people in the room, so the bot will never get the "leave" event.
*/
/**
* @desc Wechaty Class Event Function
* @typedef WechatyEventFunction
* @property {Function} error -(this: Wechaty, error: Error) => void callback function
* @property {Function} login -(this: Wechaty, user: Contact)=> void
* @property {Function} logout -(this: Wechaty, user: Contact) => void
* @property {Function} scan -(this: Wechaty, url: string, code: number) => void <br>
* <ol>
* <li>URL: {String} the QR code image URL</li>
* <li>code: {Number} the scan status code. some known status of the code list here is:</li>
* </ol>
* <ul>
* <li>0 initial_</li>
* <li>200 login confirmed</li>
* <li>201 scaned, wait for confirm</li>
* <li>408 waits for scan</li>
* </ul>
* @property {Function} heartbeat -(this: Wechaty, data: any) => void
* @property {Function} friend -(this: Wechaty, friend: Contact, request?: FriendRequest) => void
* @property {Function} message -(this: Wechaty, message: Message) => void
* @property {Function} room-join -(this: Wechaty, room: Room, inviteeList: Contact[], inviter: Contact) => void
* @property {Function} room-topic -(this: Wechaty, room: Room, topic: string, oldTopic: string, changer: Contact) => void
* @property {Function} room-leave -(this: Wechaty, room: Room, leaverList: Contact[]) => void
*/
/**
* @listens Wechaty
* @param {WechatyEventName} event - Emit WechatyEvent
* @param {WechatyEventFunction} listener - Depends on the WechatyEvent
* @return {Wechaty} - this for chain
*
* More Example Gist: [Example/Friend-Bot]{@link https://github.com/wechaty/wechaty/blob/master/example/friend-bot.ts}
*
* @example <caption>Event:scan </caption>
* wechaty.on('scan', (url: string, code: number) => {
* console.log(`[${code}] Scan ${url} to login.` )
* })
*
* @example <caption>Event:login </caption>
* bot.on('login', (user: Contact) => {
* console.log(`user ${user} login`)
* })
*
* @example <caption>Event:logout </caption>
* bot.on('logout', (user: Contact) => {
* console.log(`user ${user} logout`)
* })
*
* @example <caption>Event:message </caption>
* wechaty.on('message', (message: Message) => {
* console.log(`message ${message} received`)
* })
*
* @example <caption>Event:friend </caption>
* bot.on('friend', (contact: Contact, request: FriendRequest) => {
* if(request){ // 1. request to be friend from new contact
* let result = await request.accept()
* if(result){
* console.log(`Request from ${contact.name()} is accept succesfully!`)
* } else{
* console.log(`Request from ${contact.name()} failed to accept!`)
* }
* } else { // 2. confirm friend ship
* console.log(`new friendship confirmed with ${contact.name()}`)
* }
* })
*
* @example <caption>Event:room-join </caption>
* bot.on('room-join', (room: Room, inviteeList: Contact[], inviter: Contact) => {
* const nameList = inviteeList.map(c => c.name()).join(',')
* console.log(`Room ${room.topic()} got new member ${nameList}, invited by ${inviter}`)
* })
*
* @example <caption>Event:room-leave </caption>
* bot.on('room-leave', (room: Room, leaverList: Contact[]) => {
* const nameList = leaverList.map(c => c.name()).join(',')
* console.log(`Room ${room.topic()} lost member ${nameList}`)
* })
*
* @example <caption>Event:room-topic </caption>
* bot.on('room-topic', (room: Room, topic: string, oldTopic: string, changer: Contact) => {
* console.log(`Room ${room.topic()} topic changed from ${oldTopic} to ${topic} by ${changer.name()}`)
* })
*/
public on(event: WechatyEventName, listener: (...args: any[]) => any): this {
log.verbose('Wechaty', 'addListener(%s, %s)', event, typeof listener)
......@@ -303,7 +380,6 @@ export class Wechaty extends EventEmitter implements Sayable {
}
/**
* @todo document me
* @private
*/
public async initPuppet(): Promise<Puppet> {
......@@ -358,7 +434,11 @@ export class Wechaty extends EventEmitter implements Sayable {
}
/**
* @todo document me
* Quit the bot
*
* @returns {Promise<void>}
* @example
* await bot.quit()
*/
public async quit(): Promise<void> {
log.verbose('Wechaty', 'quit()')
......@@ -391,7 +471,11 @@ export class Wechaty extends EventEmitter implements Sayable {
}
/**
* @todo document me
* Logout the bot
*
* @returns {Promise<void>}
* @example
* await bot.logout()
*/
public async logout(): Promise<void> {
if (!this.puppet) {
......@@ -407,8 +491,12 @@ export class Wechaty extends EventEmitter implements Sayable {
}
/**
* get current user
* @returns {Contact} current logined user
* Get current user
*
* @returns {Contact}
* @example
* const contact = bot.self()
* console.log(`Bot is ${contact.name()}`)
*/
public self(): Contact {
if (!this.puppet) {
......@@ -418,7 +506,7 @@ export class Wechaty extends EventEmitter implements Sayable {
}
/**
* @todo document me
* @private
*/
public async send(message: Message | MediaMessage): Promise<boolean> {
if (!this.puppet) {
......@@ -433,7 +521,10 @@ export class Wechaty extends EventEmitter implements Sayable {
}
/**
* @todo document me
* Send message to filehelper
*
* @param {string} content
* @returns {Promise<boolean>}
*/
public async say(content: string): Promise<boolean> {
log.verbose('Wechaty', 'say(%s)', content)
......@@ -445,8 +536,7 @@ export class Wechaty extends EventEmitter implements Sayable {
}
/**
* @todo document me
* @static
* @private
*/
public static async sleep(millisecond: number): Promise<void> {
await new Promise(resolve => {
......@@ -455,7 +545,6 @@ export class Wechaty extends EventEmitter implements Sayable {
}
/**
* @todo document me
* @private
*/
public ding() {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册