2017-09-11 22:54:15 +08:00
const _ = require ( 'lodash' ) ;
const request = require ( "request" ) ;
const url = require ( 'url' ) ;
const EventEmitter = require ( 'events' ) . EventEmitter ;
const config = require ( "./config.js" ) ;
const Logger = require ( "./logger.js" ) ;
const Utils = require ( "./utils.js" ) ;
// Use to perform a callback. Will try several times until the callback is
// properly emitted and stop when successful (or after a given number of tries).
// Used to emit a single callback. Destroy it and create a new class for a new callback.
// Emits "success" on success, "failure" on error and "stopped" when gave up trying
// to perform the callback.
2017-08-25 00:22:30 +08:00
module . exports = class CallbackEmitter extends EventEmitter {
2017-09-11 22:54:15 +08:00
2017-11-02 03:09:09 +08:00
constructor ( callbackURL , message , permanent ) {
2017-09-11 22:54:15 +08:00
super ( ) ;
this . callbackURL = callbackURL ;
this . message = message ;
this . nextInterval = 0 ;
2018-02-01 02:12:27 +08:00
this . timestamp = 0 ;
2017-11-02 03:09:09 +08:00
this . permanent = permanent ;
2017-09-11 22:54:15 +08:00
}
2017-11-02 03:09:09 +08:00
start ( ) {
2017-09-11 22:54:15 +08:00
this . timestamp = new Date ( ) . getTime ( ) ;
this . nextInterval = 0 ;
this . _scheduleNext ( 0 ) ;
}
_scheduleNext ( timeout ) {
setTimeout ( ( ) => {
this . _emitMessage ( ( error , result ) => {
if ( ( error == null ) && result ) {
this . emit ( "success" ) ;
} else {
this . emit ( "failure" , error ) ;
// get the next interval we have to wait and schedule a new try
const interval = config . hooks . retryIntervals [ this . nextInterval ] ;
if ( interval != null ) {
Logger . warn ( ` [Emitter] trying the callback again in ${ interval / 1000.0 } secs ` ) ;
this . nextInterval ++ ;
this . _scheduleNext ( interval ) ;
// no intervals anymore, time to give up
} else {
2018-02-01 02:12:27 +08:00
this . nextInterval = config . hooks . permanentIntervalReset ; // Reset interval to permanent hooks
2017-11-02 03:09:09 +08:00
if ( this . permanent ) {
2018-02-01 02:12:27 +08:00
this . _scheduleNext ( this . nextInterval ) ;
2017-11-02 03:09:09 +08:00
}
else {
return this . emit ( "stopped" ) ;
}
2017-09-11 22:54:15 +08:00
}
}
} ) ;
}
, timeout ) ;
}
_emitMessage ( callback ) {
2017-11-02 03:09:09 +08:00
let data , requestOptions ;
2018-08-22 01:23:17 +08:00
const serverDomain = process . env . SERVER _DOMAIN || config . bbb . serverDomain ;
2018-07-26 02:14:55 +08:00
const sharedSecret = process . env . SHARED _SECRET || config . bbb . sharedSecret ;
2018-08-22 01:23:17 +08:00
const bearerAuth = process . env . BEARER _AUTH || config . bbb . auth2 _0 ;
2018-02-01 02:12:27 +08:00
2018-08-17 11:48:48 +08:00
// data to be sent
// note: keep keys in alphabetical order
data = {
event : "[" + this . message + "]" ,
2018-08-22 01:23:17 +08:00
timestamp : this . timestamp ,
domain : serverDomain
2018-08-17 11:48:48 +08:00
} ;
2017-09-11 22:54:15 +08:00
2018-08-22 01:23:17 +08:00
if ( bearerAuth ) {
2017-11-02 03:09:09 +08:00
const callbackURL = this . callbackURL ;
requestOptions = {
followRedirect : true ,
maxRedirects : 10 ,
uri : callbackURL ,
method : "POST" ,
form : data ,
auth : {
2018-07-26 02:14:55 +08:00
bearer : sharedSecret
2017-11-02 03:09:09 +08:00
}
} ;
}
else {
// calculate the checksum
2018-07-26 02:14:55 +08:00
const checksum = Utils . checksum ( ` ${ this . callbackURL } ${ JSON . stringify ( data ) } ${ sharedSecret } ` ) ;
2017-11-02 03:09:09 +08:00
// get the final callback URL, including the checksum
const urlObj = url . parse ( this . callbackURL , true ) ;
let callbackURL = this . callbackURL ;
callbackURL += _ . isEmpty ( urlObj . search ) ? "?" : "&" ;
callbackURL += ` checksum= ${ checksum } ` ;
requestOptions = {
followRedirect : true ,
maxRedirects : 10 ,
uri : callbackURL ,
method : "POST" ,
form : data
} ;
}
const responseFailed = ( response ) => {
var statusCode = ( response != null ? response . statusCode : undefined )
return ! ( ( statusCode >= 200 ) && ( statusCode < 300 ) )
2017-09-11 22:54:15 +08:00
} ;
request ( requestOptions , function ( error , response , body ) {
2017-11-02 03:09:09 +08:00
if ( ( error != null ) || responseFailed ( response ) ) {
Logger . warn ( ` [Emitter] error in the callback call to: [ ${ requestOptions . uri } ] for ${ simplifiedEvent ( data ) } ` , "error:" , error , "status:" , response != null ? response . statusCode : undefined ) ;
2017-09-11 22:54:15 +08:00
callback ( error , false ) ;
} else {
2017-11-02 03:09:09 +08:00
Logger . info ( ` [Emitter] successful callback call to: [ ${ requestOptions . uri } ] for ${ simplifiedEvent ( data ) } ` ) ;
2017-09-11 22:54:15 +08:00
callback ( null , true ) ;
}
} ) ;
}
2017-08-25 00:22:30 +08:00
} ;
2017-09-11 22:54:15 +08:00
// A simple string that identifies the event
var simplifiedEvent = function ( event ) {
2017-11-02 03:09:09 +08:00
if ( event . event != null ) {
event = event . event
}
2017-09-11 22:54:15 +08:00
try {
const eventJs = JSON . parse ( event ) ;
return ` event: { name: ${ ( eventJs . data != null ? eventJs . data . id : undefined ) } , timestamp: ${ ( eventJs . data . event != null ? eventJs . data . event . ts : undefined ) } } ` ;
} catch ( e ) {
return ` event: ${ event } ` ;
}
} ;