import * as request from "request" ; export class Uptime { SLACK_WEBHOOK_URL : any ; pingInterval : number ; serviceStatus : { } ; constructor ( options ) { if ( ! options || ( options && ! options . SLACK_WEBHOOK_URL ) ) { throw new Error ( "You need to specify an SLACK_WEBHOOK_URL" ) ; } this . SLACK_WEBHOOK_URL = options . SLACK_WEBHOOK_URL ; this . pingInterval = 1 * 1000 * 60 ; this . serviceStatus = { } ; } pingService ( url , cb ) { request ( { method : "GET" , uri : url , time : true } , ( err , res , body ) => { if ( ! err && res . statusCode == 200 ) { cb ( res . timingPhases . firstByte ) ; } else { cb ( "OUTAGE" ) ; } } ) ; } postToSlack ( serviceUrl ) { var message = "" ; if ( this . serviceStatus [ serviceUrl ] . status == "DEGRADED" ) { message = "`Degraded System Service !!!` :skull: " ; } else if ( this . serviceStatus [ serviceUrl ] . status == "OPERATIONAL" ) { message = "System Operational :robot_face:" ; } else if ( this . serviceStatus [ serviceUrl ] . status == "OUTAGE" ) { message = "System Outage :zzz:" ; } let slackPayload = { text : `*${ message }*\n_${ serviceUrl }_` } ; request ( { method : "POST" , uri : this . SLACK_WEBHOOK_URL , body : slackPayload , json : true } , ( err , res , body ) => { if ( err ) console . log ( `Error posting to Slack: ${ err }` ) ; } ) ; } monitor ( websites ) { websites . forEach ( service => { this . serviceStatus [ service . url ] = { status : "OPERATIONAL" , responseTimes : [ ] , timeout : service . timeout } ; setInterval ( ( ) => { this . pingService ( service . url , serviceResponse => { if ( serviceResponse === "OUTAGE" && this . serviceStatus [ service . url ] . status !== "OUTAGE" ) { this . serviceStatus [ service . url ] . status = "OUTAGE" ; this . postToSlack ( service . url ) ; } else { let responseTimes = this . serviceStatus [ service . url ] . responseTimes ; responseTimes . push ( serviceResponse ) ; if ( responseTimes . length > 3 ) { responseTimes . shift ( ) ; let avgResTime = responseTimes . reduce ( ( a , b ) => a + b , 0 ) / responseTimes . length ; let currService = this . serviceStatus [ service . url ] ; if ( avgResTime > currService . timeout && currService . status !== "DEGRADED" ) { currService . status = "DEGRADED" ; this . postToSlack ( service . url ) ; } else if ( avgResTime < currService . timeout && currService . status !== "OPERATIONAL" ) { currService . status = "OPERATIONAL" ; this . postToSlack ( service . url ) ; } } } } ) ; } , this . pingInterval ) ; } ) ; } }