import { EventEmitter } from 'events' ; import * as rq from 'request-promise-native' ; import * as fs from 'fs' ; import * as stream from 'stream' ; import poll from './functions/poll' ; import { VKError , VKExecuteResponse , VKResponse } from './interfaces/APIResponses' ; import UploadedPhoto from './interfaces/UploadedPhoto' ; import Message from './interfaces/Message' ; import UserEvent from './interfaces/UserEvent' ; import MessageSendParams from './interfaces/MessageSendParams' ; import { build } from './decorators/builder' ; import Keyboard , { KeyboardColor } from './Keyboard' ; export interface Options { token : string ; api ? : { lang ? : string ; v ? : string ; } ; group_id : number ; controllers ? : string [ ] ; } export type replyFunc = ( text ? : string , params ? : MessageSendParams ) => Promise < VKResponse > ; export class Bot extends EventEmitter { _events : Object = { } ; _userEvents : UserEvent [ ] = [ ] ; _stop : boolean = false ; constructor ( public options ) { super ( ) ; if ( ! options . token ) throw new Error ( 'token can\'t be empty' ) ; if ( ! options . group_id ) throw new Error ( 'group_id can\'t be empty' ) ; if ( options . api && Number ( options . api . v ) < 5.80 ) throw new Error ( 'API version must be > 5.80' ) ; if ( options . controllers && options . controllers . length ) build ( this , options . controllers ) ; } /**
     * Access VK API
     */ api ( method , params = { } ) { let o = this . options ; if ( o . api ) { params . v = params . v || o . api . v || '5.80' ; params . lang = params . lang || o . api . lang ; if ( params . lang == null ) delete params . lang ; } else params . v = params . v || '5.80' ; params . access_token = this . options . token ; return rq ( { baseUrl : 'https://api.vk.com' , uri : '/method/' + method , form : params , method : 'POST' , json : true } ) . then ( res => { if ( /execute/ . test ( method ) ) { return res as VKExecuteResponse ; } else if ( res . error ) { throw res . error as VKError ; } return res . response as VKResponse ; } ) ; } /**
     * Send messages
     */ send ( text , peer , params = { } ) { params . message = params . message || text ; params . peer_id = params . peer_id || peer ; if ( params . keyboard && params . keyboard instanceof Keyboard ) { params . keyboard = params . keyboard . toString ( ) ; } return this . api ( 'messages.send' , params ) ; } /**
     * Process Callback API response when using webhook
     */ processUpdate ( res ) { if ( res . type === 'message_new' ) return this . _update ( res ) ; } /**
     * Start polling
     */ start ( poll_delay ? ) { this . on ( 'update' , this . _update ) ; poll ( this , poll_delay ) ; return this ; } stop ( ) { this . _stop = true ; this . removeListener ( 'update' , this . _update ) ; this . _events = { } ; return this ; } /**
     * Listens on specific message matching the RegExp pattern
     */ get ( pattern , listener ) { this . _userEvents . push ( { pattern , listener } ) ; return this ; } getPayload ( jsonString , listener ) { this . on ( 'payload' , ( msg , reply ) => { if ( JSON . stringify ( JSON . parse ( msg . payload ) ) === ( jsonString ) ) { listener ( msg , reply ) ; } } ) ; } /**
     * Upload photo
     */ uploadPhoto ( photo ) { let photoStream ; if ( typeof photo === 'string' ) { photoStream = fs . createReadStream ( photo ) ; } else if ( photo instanceof stream . Stream ) { photoStream = photo ; } return this . api ( 'photos.getMessagesUploadServer' ) . then ( server => rq ( { method : 'POST' , uri : server . upload_url , formData : { photo : photoStream } , json : true } ) ) . then ( upload => this . api ( 'photos.saveMessagesPhoto' , { server : upload . server , photo : upload . photo , hash : upload . hash } ) ) . then ( photos => photos [ 0 ] as UploadedPhoto ) ; } /**
     * The internal update event listener,
     * used to parse messages and fire
     * get events - YOU SHOULD NOT USE THIS
     */ private _update ( update ) { if ( update . group_id !== this . options . group_id ) return ; let msg = update . object || false ; if ( ! msg ) return false ; const hasAttachments = msg . attachments && msg . attachments . length || false ; const message = { id : msg . id , peer_id : msg . peer_id , from_id : msg . from_id , date : msg . date , text : msg . text , attachments : msg . attachments , important : msg . important , conversation_message_id : msg . conversation_message_id , fwd_messages : msg . fwd_messages } ; const reply = ( text , params = { } ) => this . send ( text , message . peer_id , params ) ; if ( msg . payload ) { message . payload = msg . payload ; this . emit ( 'payload' , msg , reply ) ; } if ( hasAttachments && msg . attachments [ 0 ] . type === 'sticker' ) return this . emit ( 'sticker' , message ) ; const isAudioMsg = hasAttachments && msg . attachments [ 0 ] . type === 'doc' && msg . attachments [ 0 ] . doc . preview && msg . attachments [ 0 ] . doc . preview . audio_msg ; if ( isAudioMsg ) return this . emit ( 'voice' , message ) ; if ( ! message . text && ! hasAttachments ) return ; const ev = this . _userEvents . find ( ( { pattern } ) => pattern . test ( message . text ) ) ; if ( ! ev ) { this . emit ( 'command-notfound' , message ) ; return ; } ev . listener ( message , ev . pattern . exec ( message . text ) , reply ) ; } } export { Message , UploadedPhoto , VKError , VKExecuteResponse , VKResponse , UserEvent , MessageSendParams , Keyboard , KeyboardColor } ; export * from './decorators' ;