@ -1,16 +1,16 @@ 
			
		
	
		
		
			
				
					const  https  =  require ( "https" ) ; const  https  =  require ( "https" ) ;  
			
		
	
		
		
			
				
					const  dayjs  =  require ( "dayjs" ) ; const  dayjs  =  require ( "dayjs" ) ;  
			
		
	
		
		
			
				
					
					const  utc  =  require ( "dayjs/plugin/utc" ) const  utc  =  require ( "dayjs/plugin/utc" ) ;  
			
				
				
			
		
	
		
		
			
				
					
					let  timezone  =  require ( "dayjs/plugin/timezone" ) let  timezone  =  require ( "dayjs/plugin/timezone" ) ;  
			
				
				
			
		
	
		
		
			
				
					
					dayjs . extend ( utc ) dayjs . extend ( utc ) ;  
			
				
				
			
		
	
		
		
			
				
					
					dayjs . extend ( timezone ) dayjs . extend ( timezone ) ;  
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					const  axios  =  require ( "axios" ) ; const  axios  =  require ( "axios" ) ;  
			
		
	
		
		
			
				
					const  {  Prometheus  }  =  require ( "../prometheus" ) ; const  {  Prometheus  }  =  require ( "../prometheus" ) ;  
			
		
	
		
		
			
				
					const  {  debug ,  UP ,  DOWN ,  PENDING ,  flipStatus ,  TimeLogger  }  =  require ( "../../src/util" ) ; const  {  debug ,  UP ,  DOWN ,  PENDING ,  flipStatus ,  TimeLogger  }  =  require ( "../../src/util" ) ;  
			
		
	
		
		
			
				
					const  {  tcping ,  ping ,  dnsResolve ,  checkCertificate ,  checkStatusCode ,  getTotalClientInRoom  }  =  require ( "../util-server" ) ; const  {  tcping ,  ping ,  dnsResolve ,  checkCertificate ,  checkStatusCode ,  getTotalClientInRoom  }  =  require ( "../util-server" ) ;  
			
		
	
		
		
			
				
					const  {  R  }  =  require ( "redbean-node" ) ; const  {  R  }  =  require ( "redbean-node" ) ;  
			
		
	
		
		
			
				
					const  {  BeanModel  }  =  require ( "redbean-node/dist/bean-model" ) ; const  {  BeanModel  }  =  require ( "redbean-node/dist/bean-model" ) ;  
			
		
	
		
		
			
				
					
					const  {  Notification  }  =  require ( "../notification" ) const  {  Notification  }  =  require ( "../notification" ) ;  
			
				
				
			
		
	
		
		
	
		
		
			
				
					const  version  =  require ( "../../package.json" ) . version ; const  version  =  require ( "../../package.json" ) . version ;  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					/ * * / * *  
			
		
	
	
		
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
					@ -39,7 +39,7 @@ class Monitor extends BeanModel { 
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					        let  list  =  await  R . find ( "monitor_notification" ,  " monitor_id = ? " ,  [         let  list  =  await  R . find ( "monitor_notification" ,  " monitor_id = ? " ,  [  
			
		
	
		
		
			
				
					            this . id ,             this . id ,  
			
		
	
		
		
			
				
					
					        ] )         ] ) ;  
			
				
				
			
		
	
		
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					        for  ( let  bean  of  list )  {         for  ( let  bean  of  list )  {  
			
		
	
		
		
			
				
					            notificationIDList [ bean . notification_id ]  =  true ;             notificationIDList [ bean . notification_id ]  =  true ;  
			
		
	
	
		
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
					@ -77,7 +77,7 @@ class Monitor extends BeanModel { 
			
		
	
		
		
			
				
					     *  @ returns  { boolean }      *  @ returns  { boolean }  
			
		
	
		
		
			
				
					     * /      * /  
			
		
	
		
		
			
				
					    getIgnoreTls ( )  {     getIgnoreTls ( )  {  
			
		
	
		
		
			
				
					
					        return  Boolean ( this . ignoreTls )         return  Boolean ( this . ignoreTls ) ;  
			
				
				
			
		
	
		
		
	
		
		
			
				
					    }     }  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					    / * *     / * *  
			
		
	
	
		
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
					@ -107,12 +107,12 @@ class Monitor extends BeanModel { 
			
		
	
		
		
			
				
					            if  ( !  previousBeat )  {             if  ( !  previousBeat )  {  
			
		
	
		
		
			
				
					                previousBeat  =  await  R . findOne ( "heartbeat" ,  " monitor_id = ? ORDER BY time DESC" ,  [                 previousBeat  =  await  R . findOne ( "heartbeat" ,  " monitor_id = ? ORDER BY time DESC" ,  [  
			
		
	
		
		
			
				
					                    this . id ,                     this . id ,  
			
		
	
		
		
			
				
					
					                ] )                 ] ) ;  
			
				
				
			
		
	
		
		
	
		
		
			
				
					            }             }  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					            const  isFirstBeat  =  ! previousBeat ;             const  isFirstBeat  =  ! previousBeat ;  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					
					            let  bean  =  R . dispense ( "heartbeat" )             let  bean  =  R . dispense ( "heartbeat" ) ;  
			
				
				
			
		
	
		
		
	
		
		
			
				
					            bean . monitor_id  =  this . id ;             bean . monitor_id  =  this . id ;  
			
		
	
		
		
			
				
					            bean . time  =  R . isoDateTime ( dayjs . utc ( ) ) ;             bean . time  =  R . isoDateTime ( dayjs . utc ( ) ) ;  
			
		
	
		
		
			
				
					            bean . status  =  DOWN ;             bean . status  =  DOWN ;  
			
		
	
	
		
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
					@ -148,7 +148,7 @@ class Monitor extends BeanModel { 
			
		
	
		
		
			
				
					                            return  checkStatusCode ( status ,  this . getAcceptedStatuscodes ( ) ) ;                             return  checkStatusCode ( status ,  this . getAcceptedStatuscodes ( ) ) ;  
			
		
	
		
		
			
				
					                        } ,                         } ,  
			
		
	
		
		
			
				
					                    } ) ;                     } ) ;  
			
		
	
		
		
			
				
					
					                    bean . msg  =  ` ${ res . status }  -  ${ res . statusText } `                     bean . msg  =  ` ${ res . status }  -  ${ res . statusText } ` ;  
			
				
				
			
		
	
		
		
	
		
		
			
				
					                    bean . ping  =  dayjs ( ) . valueOf ( )  -  startTime ;                     bean . ping  =  dayjs ( ) . valueOf ( )  -  startTime ;  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					                    // Check certificate if https is used
                     // Check certificate if https is used
  
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
						
					 
					@ -158,12 +158,12 @@ class Monitor extends BeanModel { 
			
		
	
		
		
			
				
					                            tlsInfo  =  await  this . updateTlsInfo ( checkCertificate ( res ) ) ;                             tlsInfo  =  await  this . updateTlsInfo ( checkCertificate ( res ) ) ;  
			
		
	
		
		
			
				
					                        }  catch  ( e )  {                         }  catch  ( e )  {  
			
		
	
		
		
			
				
					                            if  ( e . message  !==  "No TLS certificate in response" )  {                             if  ( e . message  !==  "No TLS certificate in response" )  {  
			
		
	
		
		
			
				
					
					                                console . error ( e . message )                                 console . error ( e . message ) ;  
			
				
				
			
		
	
		
		
	
		
		
			
				
					                            }                             }  
			
		
	
		
		
			
				
					                        }                         }  
			
		
	
		
		
			
				
					                    }                     }  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					
					                    debug ( "Cert Info Query Time: "  +  ( dayjs ( ) . valueOf ( )  -  certInfoStartTime )  +  "ms" )                     debug ( "Cert Info Query Time: "  +  ( dayjs ( ) . valueOf ( )  -  certInfoStartTime )  +  "ms" ) ;  
			
				
				
			
		
	
		
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					                    if  ( this . type  ===  "http" )  {                     if  ( this . type  ===  "http" )  {  
			
		
	
		
		
			
				
					                        bean . status  =  UP ;                         bean . status  =  UP ;  
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
						
					 
					@ -173,26 +173,26 @@ class Monitor extends BeanModel { 
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					                        // Convert to string for object/array
                         // Convert to string for object/array
  
			
		
	
		
		
			
				
					                        if  ( typeof  data  !==  "string" )  {                         if  ( typeof  data  !==  "string" )  {  
			
		
	
		
		
			
				
					
					                            data  =  JSON . stringify ( data )                             data  =  JSON . stringify ( data ) ;  
			
				
				
			
		
	
		
		
	
		
		
			
				
					                        }                         }  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					                        if  ( data . includes ( this . keyword ) )  {                         if  ( data . includes ( this . keyword ) )  {  
			
		
	
		
		
			
				
					
					                            bean . msg  +=  ", keyword is found"                             bean . msg  +=  ", keyword is found" ;  
			
				
				
			
		
	
		
		
	
		
		
			
				
					                            bean . status  =  UP ;                             bean . status  =  UP ;  
			
		
	
		
		
			
				
					                        }  else  {                         }  else  {  
			
		
	
		
		
			
				
					
					                            throw  new  Error ( bean . msg  +  ", but keyword is not found" )                             throw  new  Error ( bean . msg  +  ", but keyword is not found" ) ;  
			
				
				
			
		
	
		
		
	
		
		
			
				
					                        }                         }  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					                    }                     }  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					                }  else  if  ( this . type  ===  "port" )  {                 }  else  if  ( this . type  ===  "port" )  {  
			
		
	
		
		
			
				
					                    bean . ping  =  await  tcping ( this . hostname ,  this . port ) ;                     bean . ping  =  await  tcping ( this . hostname ,  this . port ) ;  
			
		
	
		
		
			
				
					
					                    bean . msg  =  ""                     bean . msg  =  "" ;  
			
				
				
			
		
	
		
		
	
		
		
			
				
					                    bean . status  =  UP ;                     bean . status  =  UP ;  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					                }  else  if  ( this . type  ===  "ping" )  {                 }  else  if  ( this . type  ===  "ping" )  {  
			
		
	
		
		
			
				
					                    bean . ping  =  await  ping ( this . hostname ) ;                     bean . ping  =  await  ping ( this . hostname ) ;  
			
		
	
		
		
			
				
					
					                    bean . msg  =  ""                     bean . msg  =  "" ;  
			
				
				
			
		
	
		
		
	
		
		
			
				
					                    bean . status  =  UP ;                     bean . status  =  UP ;  
			
		
	
		
		
			
				
					                }  else  if  ( this . type  ===  "dns" )  {                 }  else  if  ( this . type  ===  "dns" )  {  
			
		
	
		
		
			
				
					                    let  startTime  =  dayjs ( ) . valueOf ( ) ;                     let  startTime  =  dayjs ( ) . valueOf ( ) ;  
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
						
					 
					@ -212,7 +212,7 @@ class Monitor extends BeanModel { 
			
		
	
		
		
			
				
					                        dnsRes . forEach ( record  =>  {                         dnsRes . forEach ( record  =>  {  
			
		
	
		
		
			
				
					                            dnsMessage  +=  ` Hostname:  ${ record . exchange }  - Priority:  ${ record . priority }  |  ` ;                             dnsMessage  +=  ` Hostname:  ${ record . exchange }  - Priority:  ${ record . priority }  |  ` ;  
			
		
	
		
		
			
				
					                        } ) ;                         } ) ;  
			
		
	
		
		
			
				
					
					                        dnsMessage  =  dnsMessage . slice ( 0 ,  - 2 )                         dnsMessage  =  dnsMessage . slice ( 0 ,  - 2 ) ;  
			
				
				
			
		
	
		
		
	
		
		
			
				
					                    }  else  if  ( this . dns_resolve_type  ==  "NS" )  {                     }  else  if  ( this . dns_resolve_type  ==  "NS" )  {  
			
		
	
		
		
			
				
					                        dnsMessage  +=  "Servers: " ;                         dnsMessage  +=  "Servers: " ;  
			
		
	
		
		
			
				
					                        dnsMessage  +=  dnsRes . join ( " | " ) ;                         dnsMessage  +=  dnsRes . join ( " | " ) ;  
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
						
					 
					@ -222,7 +222,7 @@ class Monitor extends BeanModel { 
			
		
	
		
		
			
				
					                        dnsRes . forEach ( record  =>  {                         dnsRes . forEach ( record  =>  {  
			
		
	
		
		
			
				
					                            dnsMessage  +=  ` Name:  ${ record . name }  | Port:  ${ record . port }  | Priority:  ${ record . priority }  | Weight:  ${ record . weight }  |  ` ;                             dnsMessage  +=  ` Name:  ${ record . name }  | Port:  ${ record . port }  | Priority:  ${ record . priority }  | Weight:  ${ record . weight }  |  ` ;  
			
		
	
		
		
			
				
					                        } ) ;                         } ) ;  
			
		
	
		
		
			
				
					
					                        dnsMessage  =  dnsMessage . slice ( 0 ,  - 2 )                         dnsMessage  =  dnsMessage . slice ( 0 ,  - 2 ) ;  
			
				
				
			
		
	
		
		
	
		
		
			
				
					                    }                     }  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					                    if  ( this . dnsLastResult  !==  dnsMessage )  {                     if  ( this . dnsLastResult  !==  dnsMessage )  {  
			
		
	
	
		
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
					@ -285,20 +285,20 @@ class Monitor extends BeanModel { 
			
		
	
		
		
			
				
					                if  ( ! isFirstBeat  ||  bean . status  ===  DOWN )  {                 if  ( ! isFirstBeat  ||  bean . status  ===  DOWN )  {  
			
		
	
		
		
			
				
					                    let  notificationList  =  await  R . getAll ( "SELECT notification.* FROM notification, monitor_notification WHERE monitor_id = ? AND monitor_notification.notification_id = notification.id " ,  [                     let  notificationList  =  await  R . getAll ( "SELECT notification.* FROM notification, monitor_notification WHERE monitor_id = ? AND monitor_notification.notification_id = notification.id " ,  [  
			
		
	
		
		
			
				
					                        this . id ,                         this . id ,  
			
		
	
		
		
			
				
					
					                    ] )                     ] ) ;  
			
				
				
			
		
	
		
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					                    let  text ;                     let  text ;  
			
		
	
		
		
			
				
					                    if  ( bean . status  ===  UP )  {                     if  ( bean . status  ===  UP )  {  
			
		
	
		
		
			
				
					
					                        text  =  "✅ Up"                         text  =  "✅ Up" ;  
			
				
				
			
		
	
		
		
	
		
		
			
				
					                    }  else  {                     }  else  {  
			
		
	
		
		
			
				
					
					                        text  =  "🔴 Down"                         text  =  "🔴 Down" ;  
			
				
				
			
		
	
		
		
	
		
		
			
				
					                    }                     }  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					                    let  msg  =  ` [ ${ this . name } ] [ ${ text } ]  ${ bean . msg } ` ;                     let  msg  =  ` [ ${ this . name } ] [ ${ text } ]  ${ bean . msg } ` ;  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					                    for  ( let  notification  of  notificationList )  {                     for  ( let  notification  of  notificationList )  {  
			
		
	
		
		
			
				
					                        try  {                         try  {  
			
		
	
		
		
			
				
					
					                            await  Notification . send ( JSON . parse ( notification . config ) ,  msg ,  await  this . toJSON ( ) ,  bean . toJSON ( ) )                             await  Notification . send ( JSON . parse ( notification . config ) ,  msg ,  await  this . toJSON ( ) ,  bean . toJSON ( ) ) ;  
			
				
				
			
		
	
		
		
	
		
		
			
				
					                        }  catch  ( e )  {                         }  catch  ( e )  {  
			
		
	
		
		
			
				
					                            console . error ( "Cannot send notification to "  +  notification . name ) ;                             console . error ( "Cannot send notification to "  +  notification . name ) ;  
			
		
	
		
		
			
				
					                            console . log ( e ) ;                             console . log ( e ) ;  
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
						
					 
					@ -313,18 +313,18 @@ class Monitor extends BeanModel { 
			
		
	
		
		
			
				
					            let  beatInterval  =  this . interval ;             let  beatInterval  =  this . interval ;  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					            if  ( bean . status  ===  UP )  {             if  ( bean . status  ===  UP )  {  
			
		
	
		
		
			
				
					
					                console . info ( ` Monitor # ${ this . id }  ' ${ this . name } ': Successful Response:  ${ bean . ping }  ms | Interval:  ${ beatInterval }  seconds | Type:  ${ this . type } ` )                 console . info ( ` Monitor # ${ this . id }  ' ${ this . name } ': Successful Response:  ${ bean . ping }  ms | Interval:  ${ beatInterval }  seconds | Type:  ${ this . type } ` ) ;  
			
				
				
			
		
	
		
		
	
		
		
			
				
					            }  else  if  ( bean . status  ===  PENDING )  {             }  else  if  ( bean . status  ===  PENDING )  {  
			
		
	
		
		
			
				
					                if  ( this . retryInterval  !==  this . interval )  {                 if  ( this . retryInterval  !==  this . interval )  {  
			
		
	
		
		
			
				
					                    beatInterval  =  this . retryInterval ;                     beatInterval  =  this . retryInterval ;  
			
		
	
		
		
			
				
					                }                 }  
			
		
	
		
		
			
				
					
					                console . warn ( ` Monitor # ${ this . id }  ' ${ this . name } ': Pending:  ${ bean . msg }  | Max retries:  ${ this . maxretries }  | Retry:  ${ retries }  | Retry Interval:  ${ beatInterval }  seconds | Type:  ${ this . type } ` )                 console . warn ( ` Monitor # ${ this . id }  ' ${ this . name } ': Pending:  ${ bean . msg }  | Max retries:  ${ this . maxretries }  | Retry:  ${ retries }  | Retry Interval:  ${ beatInterval }  seconds | Type:  ${ this . type } ` ) ;  
			
				
				
			
		
	
		
		
	
		
		
			
				
					            }  else  {             }  else  {  
			
		
	
		
		
			
				
					
					                console . warn ( ` Monitor # ${ this . id }  ' ${ this . name } ': Failing:  ${ bean . msg }  | Interval:  ${ beatInterval }  seconds | Type:  ${ this . type } ` )                 console . warn ( ` Monitor # ${ this . id }  ' ${ this . name } ': Failing:  ${ bean . msg }  | Interval:  ${ beatInterval }  seconds | Type:  ${ this . type } ` ) ;  
			
				
				
			
		
	
		
		
	
		
		
			
				
					            }             }  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					            io . to ( this . user_id ) . emit ( "heartbeat" ,  bean . toJSON ( ) ) ;             io . to ( this . user_id ) . emit ( "heartbeat" ,  bean . toJSON ( ) ) ;  
			
		
	
		
		
			
				
					
					            Monitor . sendStats ( io ,  this . id ,  this . user_id )             Monitor . sendStats ( io ,  this . id ,  this . user_id ) ;  
			
				
				
			
		
	
		
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					            await  R . store ( bean ) ;             await  R . store ( bean ) ;  
			
		
	
		
		
			
				
					            prometheus . update ( bean ,  tlsInfo ) ;             prometheus . update ( bean ,  tlsInfo ) ;  
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
						
					 
					@ -335,7 +335,7 @@ class Monitor extends BeanModel { 
			
		
	
		
		
			
				
					                this . heartbeatInterval  =  setTimeout ( beat ,  beatInterval  *  1000 ) ;                 this . heartbeatInterval  =  setTimeout ( beat ,  beatInterval  *  1000 ) ;  
			
		
	
		
		
			
				
					            }             }  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					
					        }         } ;  
			
				
				
			
		
	
		
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					        beat ( ) ;         beat ( ) ;  
			
		
	
		
		
			
				
					    }     }  
			
		
	
	
		
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
					@ -481,7 +481,7 @@ class Monitor extends BeanModel { 
			
		
	
		
		
			
				
					        }  else  {         }  else  {  
			
		
	
		
		
			
				
					            // Handle new monitor with only one beat, because the beat's duration = 0
             // Handle new monitor with only one beat, because the beat's duration = 0
  
			
		
	
		
		
			
				
					            let  status  =  parseInt ( await  R . getCell ( "SELECT `status` FROM heartbeat WHERE monitor_id = ?" ,  [  monitorID  ] ) ) ;             let  status  =  parseInt ( await  R . getCell ( "SELECT `status` FROM heartbeat WHERE monitor_id = ?" ,  [  monitorID  ] ) ) ;  
			
		
	
		
		
			
				
					
					            console . log ( "here???"  +  status ) ;  
  
			
				
				
			
		
	
		
		
	
		
		
			
				
					            if  ( status  ===  UP )  {             if  ( status  ===  UP )  {  
			
		
	
		
		
			
				
					                uptime  =  1 ;                 uptime  =  1 ;  
			
		
	
		
		
			
				
					            }             }