/** * Wechaty - https://github.com/chatie/wechaty * * @copyright 2016-2018 Huan LI * * 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. * @ignore */ import { Readable, } from 'stream' import { Sayable, log, } from './config' import Contact from './contact' import Room from './room' import PuppetAccessory from './puppet-accessory' /** * * 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, AUDIO = 3, VIDEO = 4, URL = 5, ATTACH = 6, OPEN = 7, EMOJI = 8, VOICE_REMIND = 9, SCAN_GOOD = 10, GOOD = 13, EMOTION = 15, CARD_TICKET = 16, REALTIME_SHARE_LOCATION = 17, TRANSFERS = 2e3, RED_ENVELOPES = 2001, 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, VOICE = 34, VERIFYMSG = 37, POSSIBLEFRIEND_MSG = 40, SHARECARD = 42, VIDEO = 43, EMOTICON = 47, LOCATION = 48, APP = 49, VOIPMSG = 50, STATUSNOTIFY = 51, VOIPNOTIFY = 52, VOIPINVITE = 53, MICROVIDEO = 62, SYSNOTICE = 9999, SYS = 10000, RECALLED = 10002, } // export type TypeName = 'attachment' // | 'audio' // | 'image' // | 'video' /** * All wechat messages will be encapsulated as a Message. * * `Message` is `Sayable`, * [Examples/Ding-Dong-Bot]{@link https://github.com/Chatie/wechaty/blob/master/examples/ding-dong-bot.ts} */ export abstract class Message extends PuppetAccessory implements Sayable { /** * @private */ constructor( readonly objOrId: Object | string, ) { super() log.silly('Message', 'constructor()') } /** * @private */ public toString() { return `Message` } public abstract async say(text: string, replyTo?: Contact | Contact[]) : Promise public abstract async say(mediaMessage: MediaMessage, replyTo?: Contact | Contact[]): Promise /** * Reply a Text or Media File message to the sender. * * @see {@link https://github.com/Chatie/wechaty/blob/master/examples/ding-dong-bot.ts|Examples/ding-dong-bot} * @param {(string | MediaMessage)} textOrMedia * @param {(Contact|Contact[])} [replyTo] * @returns {Promise} * * @example * const bot = new Wechaty() * 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 abstract async say(textOrMedia: string | MediaMessage, replyTo?: Contact|Contact[]): Promise /** * @private */ public abstract from(contact: Contact): void /** * @private */ public abstract from(id: string): void public abstract from(): Contact /** * Get the sender from a message. * @returns {Contact} */ public abstract from(contact?: Contact|string): Contact|void /** * @private */ public abstract room(room: Room): void /** * @private */ public abstract room(id: string): void public abstract 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 abstract room(room?: Room | string): Room | null | void /** * Get the content of the message * * @returns {string} */ public abstract content(): string /** * @private */ public abstract content(content: string): void /** * Get the content of the message * * @returns {string} */ public abstract content(content?: string): string | void /** * Get the type from the message. * * If type is equal to `MsgType.RECALLED`, {@link Message#id} is the msgId of the recalled message. * @see {@link MsgType} * @returns {MsgType} */ public abstract type(): MsgType /** * 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 abstract typeSub(): MsgType /** * Get the typeApp from the message. * * @returns {AppMsgType} * @see {@link AppMsgType} */ public abstract typeApp(): AppMsgType /** * 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 abstract self(): boolean /** * * Get message mentioned contactList. * * Message event table as follows * * | | Web | Mac PC Client | iOS Mobile | android Mobile | * | :--- | :--: | :----: | :---: | :---: | * | [You were mentioned] tip ([有人@我]的提示) | ✘ | √ | √ | √ | * | Identify magic code (8197) by copy & paste in mobile | ✘ | √ | √ | ✘ | * | Identify magic code (8197) by programming | ✘ | ✘ | ✘ | ✘ | * | Identify two contacts with the same roomAlias by [You were mentioned] tip | ✘ | ✘ | √ | √ | * * @returns {Contact[]} - Return message mentioned contactList * * @example * const contactList = message.mentioned() * console.log(contactList) */ public abstract mentioned(): Contact[] /** * @private */ public abstract async ready(): Promise /** * @todo add function */ public static async find(query) { return this.findAll(query)[0] } /** * @todo add function */ public static async findAll(query) { return Promise.resolve([ new (this as any)(1), new (this as any)(2), ]) } /** * @private */ public abstract to(contact: Contact): void /** * @private */ public abstract to(id: string): void public abstract 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 abstract to(contact?: Contact | string): Contact | Room | null | void } /** * Meidia Type Message * */ export abstract class MediaMessage extends Message { /** * @private */ public toString() { return `MediaMessage<${this.filename()}>` } /** * 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 abstract ext(): string /** * return the MIME Type of this MediaMessage * */ public abstract mimeType(): string | null /** * 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 abstract filename(): string /** * Get the read stream for attachment file */ public abstract async readyStream(): Promise public abstract async forward(to: Room|Contact): Promise } export default Message