<commit_before>var mongoose = require('mongoose');
var Schema   = mongoose.Schema;
var moment   = require('moment');
var async    = require('async');

// models dependencies
var Ping             = require('../models/ping');
var CheckEvent       = require('../models/checkEvent');
var CheckHourlyStat  = require('../models/checkHourlyStat');
var CheckDailyStat   = require('../models/checkDailyStat');
var CheckMonthlyStat = require('../models/checkMonthlyStat');
var CheckYearlyStat  = require('../models/checkYearlyStat');
var Tag              = require('../models/tag');

var statusCounter = 0;

// main model
var Check = new Schema({
  name        : String,
  type        : String,
  url         : String,
  interval    : { type: Number, default: 60000 }, // interval between two pings
  maxTime     : { type: Number, default: 1500 },  // time under which a ping is considered responsive
  nbErrors    : { type: Number, default: 1 },  // nb of errors from which to trigger a new CheckEvent
  tags        : [String],
  lastChanged : Date,
  firstTested : Date,
  lastTested  : Date,
  isUp        : Boolean,
  isPaused    : { type: Boolean, default: false },
  uptime      : { type: Number, default: 0 },
  downtime    : { type: Number, default: 0 },
  qos         : {}
});
Check.plugin(require('mongoose-lifecycle'));

Check.pre('remove', function(next) {
  async.parallel([this.removePings.bind(this), this.removeEvents.bind(this), this.removeStats.bind(this)], function() {
    next();
  });
});

Check.methods.removePings = function(callback) {
  Ping.remove({ check: this._id }, callback);
};

Check.methods.removeEvents = function(callback) {
  CheckEvent.remove({ check: this._id }, callback);
};

Check.methods.removeStats = function(callback) {
  var self = this;
  async.parallel([
    function(cb) { CheckHourlyStat.remove({ check: self._id }, cb); },
    function(cb) { CheckDailyStat.remove({ check: self._id }, cb); },
    function(cb) { CheckMonthlyStat.remove({ check: self._id }, cb); },
    function(cb) { CheckYearlyStat.remove({ check: self._id }, cb); }
  ], callback);
};

Check.methods.needsPoll = function() {
  if (this.isPaused) return false;
  if (!this.firstTested) return true;
  var delay = (this.lastTested.getTime() - this.firstTested.getTime()) % this.interval;
  return (Date.now() - this.lastTested.getTime() + delay) >= (this.interval || 60000);
};

Check.methods.togglePause = function() {
  this.isPaused = !this.isPaused;
  if (!this.isPaused) {
    // restarted
    this.isUp = undefined;
  }
  this.lastChanged = new Date();
};

Check.methods.setLastTest = function(status, time, error) {
  var now = time ? new Date(time) : new Date();
  if (!this.firstTested) {
    this.firstTested = now;
  }
  this.lastTested = now;
  
  // First down check or First up check
  if (this.isUp != status) {
      
      statusCounter = 1;
      
  // more up checks
  } else {
      
      statusCounter++;
      
  }
  
  if (statusCounter>2) {
    var event = new CheckEvent({
      timestamp: now,
      check: this,
      tags: this.tags,
      message: status ? 'up' : 'down',
      details: error
    });
    if (status && this.lastChanged && this.isUp != undefined) {
      // Check comes back up
      event.downtime = now.getTime() - this.lastChanged.getTime();
    }
    event.save();
    this.lastChanged = now;
    this.isUp = status;
    this.uptime = 0;
    this.downtime = 0;
  }
  var durationSinceLastChange = now.getTime() - this.lastChanged.getTime();
  if (status) {
    this.uptime = durationSinceLastChange;
  } else {
    this.downtime = durationSinceLastChange;
  }
  return this;
};

Check.methods.getQosPercentage = function() {
  if (!this.qos) return false;
  return (this.qos.ups / this.qos.count) * 100;
};

Check.methods.updateUptime = function(callback) {
  var self = this;
  Ping<commit_msg>adding alert threshold<commit_after>var mongoose = require('mongoose');
var Schema   = mongoose.Schema;
var moment   = require('moment');
var async    = require('async');

// models dependencies
var Ping             = require('../models/ping');
var CheckEvent       = require('../models/checkEvent');
var CheckHourlyStat  = require('../models/checkHourlyStat');
var CheckDailyStat   = require('../models/checkDailyStat');
var CheckMonthlyStat = require('../models/checkMonthlyStat');
var CheckYearlyStat  = require('../models/checkYearlyStat');
var Tag              = require('../models/tag');

// main model
var Check = new Schema({
  name        : String,
  type        : String,
  url         : String,
  interval    : { type: Number, default: 60000 }, // interval between two pings
  maxTime     : { type: Number, default: 1500 },  // time under which a ping is considered responsive
  nbErrors    : { type: Number, default: 1 },  // nb of errors from which to trigger a new CheckEvent
  statusCounter : { type: Number, default: 4 },  // nb of errors from which to trigger a new CheckEvent
  tags        : [String],
  lastChanged : Date,
  firstTested : Date,
  lastTested  : Date,
  isUp        : Boolean,
  isPaused    : { type: Boolean, default: false },
  uptime      : { type: Number, default: 0 },
  downtime    : { type: Number, default: 0 },
  qos         : {}
});
Check.plugin(require('mongoose-lifecycle'));

Check.pre('remove', function(next) {
  async.parallel([this.removePings.bind(this), this.removeEvents.bind(this), this.removeStats.bind(this)], function() {
    next();
  });
});

Check.methods.removePings = function(callback) {
  Ping.remove({ check: this._id }, callback);
};

Check.methods.removeEvents = function(callback) {
  CheckEvent.remove({ check: this._id }, callback);
};

Check.methods.removeStats = function(callback) {
  var self = this;
  async.parallel([
    function(cb) { CheckHourlyStat.remove({ check: self._id }, cb); },
    function(cb) { CheckDailyStat.remove({ check: self._id }, cb); },
    function(cb) { CheckMonthlyStat.remove({ check: self._id }, cb); },
    function(cb) { CheckYearlyStat.remove({ check: self._id }, cb); }
  ], callback);
};

Check.methods.needsPoll = function() {
  if (this.isPaused) return false;
  if (!this.firstTested) return true;
  var delay = (this.lastTested.getTime() - this.firstTested.getTime()) % this.interval;
  return (Date.now() - this.lastTested.getTime() + delay) >= (this.interval || 60000);
};

Check.methods.togglePause = function() {
  this.isPaused = !this.isPaused;
  if (!this.isPaused) {
    // restarted
    this.isUp = undefined;
  }
  this.lastChanged = new Date();
};

Check.methods.setLastTest = function(status, time, error) {
  var now = time ? new Date(time) : new Date();
  if (!this.firstTested) {
    this.firstTested = now;
  }
  this.lastTested = now;
  
  
  if (!status && this.isUp != status) {      
      this.statusCounter = 1;
  } else if(status && this.isUp != status && this.statusCounter >= this.nbErrors) {
      this.statusCounter = this.nbErrors;
  } else if(!status && this.statusCounter<(this.nbErrors+1)) {
      this.statusCounter++;
  }
    
  if (this.isUp != status) { 

    this.lastChanged = now;
    this.isUp = status;
    this.uptime = 0;
    this.downtime = 0;

  } 
  
  if(this.statusCounter == this.nbErrors) {
    this.statusCounter = this.nbErrors + 1;
    var event = new CheckEvent({
      timestamp: now,
      check: this,
      tags: this.tags,
      message: status ? 'up' : 'down',
      details: error
    });
    if (status && this.lastChanged && this.isUp != undefined) {
      // Check comes back up
      event.downtime = now.getTime() - this.lastChanged.getTime();
    }
    event.save();
  }
  var durationSinceLastChange = now.getTime() - this.lastChanged.getTime();
  if (status) {
    this.uptime = durationSinceLastChange;
  } else {
    this.downtime = durationSinceLastChange;
  }
  return this;
};

Check.methods.getQosPercentage = function() {
  if (!this.qos) return false;
  return (this.qos.ups / this.qos.count) * 100;
};

Check.methods.updateUptime = function(callback) {
  var self = this;
  Ping
{'fraction_non_alphanumeric': 0.15071054599850411, 'fraction_numerical': 0.006357516828721017, 'mean_word_length': 3.064336372847011, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4690350', 'n_tokens_mistral': 2648, 'n_tokens_neox': 2566, 'n_words': 610}