<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

const {classes: Cc, interfaces: Ci, utils: Cu} = Components;

Cu.import('resource://gre/modules/XPCOMUtils.jsm');
XPCOMUtils.defineLazyModuleGetter(this, 'console',
  'resource://gre/modules/Console.jsm');
XPCOMUtils.defineLazyModuleGetter(this, 'CustomizableUI',
  'resource:///modules/CustomizableUI.jsm');
XPCOMUtils.defineLazyModuleGetter(this, 'ObjectUtils',
  'resource://gre/modules/ObjectUtils.jsm');
XPCOMUtils.defineLazyModuleGetter(this, 'PrivateBrowsingUtils',
  'resource://gre/modules/PrivateBrowsingUtils.jsm');
XPCOMUtils.defineLazyModuleGetter(this, 'Services',
  'resource://gre/modules/Services.jsm');
XPCOMUtils.defineLazyModuleGetter(this, 'WindowWatcher',
  'chrome://universalsearch-lib/content/window-watcher.js');

const EXPORTED_SYMBOLS = ['UniversalSearch'];

function Search() {
  /*
  The main UniversalSearch module manages the add-on lifecycle, loading and
  unloading code when the add-on is installed, enabled, disabled, or
  uninstalled. It's invoked by the bootstrap.js file.
  */

  // Due to limitations in passing objects between window contexts, we have to
  // bind the callbacks passed to WindowWatcher.start().
  this.loadIntoWindow = this.loadIntoWindow.bind(this);
  this.unloadFromWindow = this.unloadFromWindow.bind(this);
  this.onError = this.onError.bind(this);
}

Search.prototype = {
  load: function() {
    WindowWatcher.start(this.loadIntoWindow, this.unloadFromWindow, this.onError);
  },

  unload: function() {
    WindowWatcher.stop();
  },

  loadIntoWindow: function(win) {
    console.log('loadIntoWindow start');

    // Sets the app global per window.
    win.universalSearch = win.universalSearch || {}

    win.universalSearch.prefs = this._initializePrefs();
    win.universalSearch.urlbarPrefs = this._initializeUrlbarPrefs();
    this._hideSearchBar(win);
    this._loadStyleSheets(win);
    this._loadScripts(win);
    this._startApp(win);

    console.log('loadIntoWindow finish');
  },

  unloadFromWindow: function(win) {
    console.log('unloadFromWindow start');

    // NOTE: order matters here: _restoreSearchBar needs `win.universalSearch`
    // to be defined, while _stopApp deletes `win.universalSearch`.
    this._restoreSearchBar(win);
    this._stopApp(win);
    this._unloadScripts(win);
    this._unloadStyleSheets(win);

    // Delete any remaining references.
    delete win.universalSearch;

    console.log('unloadFromWindow finish');
  },

  _initializePrefs: function() {
    return Services.prefs.getBranch('extensions.universalsearch.');
  },

  _initializeUrlbarPrefs: function() {
    return Services.prefs.getBranch('browser.urlbar.');
  },

  _hideSearchBar: function(win) {
    // If the search bar is visible, note the location and hide it.
    const searchBarLocation = CustomizableUI.getPlacementOfWidget('search-container');
    if (searchBarLocation) {
      win.universalSearch.searchBarLocation = searchBarLocation;
      CustomizableUI.removeWidgetFromArea('search-container');
    }
  },

  _restoreSearchBar: function(win) {
    // If the search bar was originally visible, restore it.
    if (win.universalSearch.searchBarLocation) {
      const loc = win.universalSearch.searchBarLocation;
      CustomizableUI.addWidgetToArea('search-container', loc.area, loc.position);
    }
  },

  _loadStyleSheets: function(win) {
    const doc = win.document;
    const docEl = doc.documentElement;

    // Insert the main stylesheet with platform-independent styles.
    const stylesheet = doc.createElementNS('http://www.w3.org/1999/xhtml', 'h:link');
    stylesheet.href = 'chrome://universalsearch-skin/content/style.css';
    stylesheet.rel = 'stylesheet';
    stylesheet.type = 'text/css';
    stylesheet.id = 'universal-search-stylesheet';
    stylesheet.style.display = 'none';

    // Insert platform-specific styles, using `Services.appinfo.OS` to
    // distinguish between Mac OS ('Darwin'), Linux, and Windows ('WINNT').
    const stylesheetPlatform = doc.createElementNS('http://www.w3.org/1999/xhtml', 'h:link');
    stylesheetPlatform.rel = 'stylesheet';
    stylesheetPlatform.type = 'text/css';
    stylesheetPlatform.id = 'universal-search-stylesheet-platform';
    stylesheetPlatform.style.display = 'none';

    if (Services.appinfo.OS === 'Darwin') {
      stylesheetPlatform.href = 'chrome://universalsearch-skin/content/style-osx.css';
    } else if (Services.appinfo.OS === 'WINNT') {
      stylesheetPlatform.href = 'chrome://universalsearch-skin/content/style-windows.css';
    } else {
      stylesheetPlatform.href = 'chrome://universalsearch-skin/content/style-linux.css';
    }

    docEl.appendChild(stylesheet);
    docEl.appendChild(stylesheetPlatform);
  },

  _unloadStyleSheets: function(win) {
    const doc = win.document;
    const docEl = win.document.documentElement;

    const stylesheet = doc.getElementById('universal-search-stylesheet');
    const stylesheetPlatform = doc.getElementById('universal-search-stylesheet-platform');

    docEl.removeChild(stylesheet);
    docEl.removeChild(stylesheetPlatform);
  },

  _loadScripts: function(win) {
    // Note that we load the scripts into the app namespace, to ease cleanup.
    // Each module's EXPORTED_SYMBOLS will be properties on win.universalSearch.
    Cu.import('resource://gre/modules/Console.jsm', win.universalSearch);
    Cu.import('resource://gre/modules/Services.jsm', win.universalSearch);

    Cu.import('chrome://universalsearch-lib/content/events.js', win.universalSearch);
    Cu.import('chrome://universalsearch-lib/content/metrics.js', win.universalSearch);
    Cu.import('chrome://universalsearch-lib/content/recommendation-server.js', win.universalSearch);

    Cu.import('chrome://universalsearch-ui/content/highlight-manager.js', win.universalSearch);
    Cu.import('chrome://universalsearch-ui/content/popup.js', win.universalSearch);
    Cu.import('chrome://universalsearch-ui/content/recommendation.js', win.universalSearch);
    Cu.import('chrome://universalsearch-ui/content/recommendation-row.js', win.universalSearch);
    Cu.import('chrome://universalsearch-ui/content/urlbar.js', win.universalSearch);
  },

  _unloadScripts: function(win) {
    // Unload scripts from the namespace. Not clear on whether this is necessary
    // if we just delete win.universalSearch.
    Cu.unload('chrome://universalsearch-ui/content/highlight-manager.js', win.universalSearch);
    Cu.unload('chrome://universalsearch-ui/content/popup.js', win.universalSearch);
    Cu.unload('chrome://universalsearch-ui/content/recommendation.js', win.universalSearch);
    Cu.unload('chrome://universalsearch-ui/content/recommendation-row.js', win.universalSearch);
    Cu.unload('chrome://universalsearch-ui/content/urlbar.js', win.universalSearch);

    Cu.unload('chrome://universalsearch-lib/content/recommendation-server.js', win.universalSearch);
    Cu.unload('chrome://universalsearch-lib/content/metrics.js', win.universalSearch);
    Cu.unload('chrome://universalsearch-lib/content/events.js', win.universalSearch);

    // NOTE: we can't unload Console.jsm until the last console call.
    // It's unloaded by the caller (the unloadFromWindow method).
  },

  _startApp: function(win) {
    // Initialize modules and assemble the object graph.

    const app = win.universalSearch;

    app.events = new app.Events();
    app.events.init();

    app.recommendationServer = new app.RecommendationServer({
      events: app.events,
      xhr: Cc['@mozilla.org/xmlextras/xmlhttprequest;1'],
      timeout: 1000,
      // app.console is provided by loading Console.jsm
      console: app.console,
      prefs: app.prefs,
      urlbarPrefs: app.urlbarPrefs
    });
    app.recommendationServer.init();

    // NOTE: order matters here, the urlbar and highlightManager both need
    // to be handed the initialized recommendation
    app.recommendation = new app.Recommendation({
      eTLD: Services.eTLD,
      events: app.events,
      io: Services.io,
      objectUtils: ObjectUtils,
      win: win,
      RecommendationRow: app.RecommendationRow
    });
    app.recommendation.init();

    app.urlbar = new app.Urlbar({
      win: win,
      events: app.events,
      privateBrowsingUtils: PrivateBrowsingUtils,
      recommendation: app.recommendation
    });
    app.urlbar.init();

    app.popup = new app.Popup({
      win: win,
      events: app.events
    });
    app.popup.init();

    app.highlightManager = new app.HighlightManager({
      win: win,
      events: app.events,
      recommendation: app.recommendation,
      popup: app.popup
    });
    app.highlightManager.init();

    app.metrics = new app.Metrics({
      events: app.events,
      popup: app.popup,
      recommendation: app.recommendation,
      win: win,
      observerService: Cc["@mozilla.org/observer-service;1"]
                       .getService(Ci.nsIObserverService)
    });
    app.metrics.init();
  },

  _stopApp: function(win) {
    const app = win.universalSearch;

    app.popup.destroy();
    app.recommendation.destroy();
    app.highlightManager.destroy();
    app.urlbar.destroy();
    app.recommendationServer.destroy();
    app.events.destroy();

    delete win.universalSearch;
  },

  onError: function(msg) {
    console.error(msg);
  }
};

// Expose a singleton, since we only need one of these for the add-on.
const UniversalSearch = new Search();
<commit_msg>Only unload scripts once<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

const {classes: Cc, interfaces: Ci, utils: Cu} = Components;

Cu.import('resource://gre/modules/XPCOMUtils.jsm');
XPCOMUtils.defineLazyModuleGetter(this, 'console',
  'resource://gre/modules/Console.jsm');
XPCOMUtils.defineLazyModuleGetter(this, 'CustomizableUI',
  'resource:///modules/CustomizableUI.jsm');
XPCOMUtils.defineLazyModuleGetter(this, 'ObjectUtils',
  'resource://gre/modules/ObjectUtils.jsm');
XPCOMUtils.defineLazyModuleGetter(this, 'PrivateBrowsingUtils',
  'resource://gre/modules/PrivateBrowsingUtils.jsm');
XPCOMUtils.defineLazyModuleGetter(this, 'Services',
  'resource://gre/modules/Services.jsm');
XPCOMUtils.defineLazyModuleGetter(this, 'WindowWatcher',
  'chrome://universalsearch-lib/content/window-watcher.js');

const EXPORTED_SYMBOLS = ['UniversalSearch'];

function Search() {
  /*
  The main UniversalSearch module manages the add-on lifecycle, loading and
  unloading code when the add-on is installed, enabled, disabled, or
  uninstalled. It's invoked by the bootstrap.js file.
  */

  // Due to limitations in passing objects between window contexts, we have to
  // bind the callbacks passed to WindowWatcher.start().
  this.loadIntoWindow = this.loadIntoWindow.bind(this);
  this.unloadFromWindow = this.unloadFromWindow.bind(this);
  this.onError = this.onError.bind(this);
}

Search.prototype = {
  load: function() {
    WindowWatcher.start(this.loadIntoWindow, this.unloadFromWindow, this.onError);
  },

  unload: function() {
    // Scripts only need to be unloaded once, globally.
    this._unloadScripts();

    // The running code and styles must be removed from each window.
    WindowWatcher.stop();
  },

  loadIntoWindow: function(win) {
    console.log('loadIntoWindow start');

    // Sets the app global per window.
    win.universalSearch = win.universalSearch || {}

    win.universalSearch.prefs = this._initializePrefs();
    win.universalSearch.urlbarPrefs = this._initializeUrlbarPrefs();
    this._hideSearchBar(win);
    this._loadStyleSheets(win);
    this._loadScripts(win);
    this._startApp(win);

    console.log('loadIntoWindow finish');
  },

  unloadFromWindow: function(win) {
    console.log('unloadFromWindow start');

    // NOTE: order matters here: _restoreSearchBar needs `win.universalSearch`
    // to be defined, while _stopApp deletes `win.universalSearch`.
    this._restoreSearchBar(win);
    this._stopApp(win);
    this._unloadStyleSheets(win);

    // Delete any remaining references.
    delete win.universalSearch;

    console.log('unloadFromWindow finish');
  },

  _initializePrefs: function() {
    return Services.prefs.getBranch('extensions.universalsearch.');
  },

  _initializeUrlbarPrefs: function() {
    return Services.prefs.getBranch('browser.urlbar.');
  },

  _hideSearchBar: function(win) {
    // If the search bar is visible, note the location and hide it.
    const searchBarLocation = CustomizableUI.getPlacementOfWidget('search-container');
    if (searchBarLocation) {
      win.universalSearch.searchBarLocation = searchBarLocation;
      CustomizableUI.removeWidgetFromArea('search-container');
    }
  },

  _restoreSearchBar: function(win) {
    // If the search bar was originally visible, restore it.
    if (win.universalSearch.searchBarLocation) {
      const loc = win.universalSearch.searchBarLocation;
      CustomizableUI.addWidgetToArea('search-container', loc.area, loc.position);
    }
  },

  _loadStyleSheets: function(win) {
    const doc = win.document;
    const docEl = doc.documentElement;

    // Insert the main stylesheet with platform-independent styles.
    const stylesheet = doc.createElementNS('http://www.w3.org/1999/xhtml', 'h:link');
    stylesheet.href = 'chrome://universalsearch-skin/content/style.css';
    stylesheet.rel = 'stylesheet';
    stylesheet.type = 'text/css';
    stylesheet.id = 'universal-search-stylesheet';
    stylesheet.style.display = 'none';

    // Insert platform-specific styles, using `Services.appinfo.OS` to
    // distinguish between Mac OS ('Darwin'), Linux, and Windows ('WINNT').
    const stylesheetPlatform = doc.createElementNS('http://www.w3.org/1999/xhtml', 'h:link');
    stylesheetPlatform.rel = 'stylesheet';
    stylesheetPlatform.type = 'text/css';
    stylesheetPlatform.id = 'universal-search-stylesheet-platform';
    stylesheetPlatform.style.display = 'none';

    if (Services.appinfo.OS === 'Darwin') {
      stylesheetPlatform.href = 'chrome://universalsearch-skin/content/style-osx.css';
    } else if (Services.appinfo.OS === 'WINNT') {
      stylesheetPlatform.href = 'chrome://universalsearch-skin/content/style-windows.css';
    } else {
      stylesheetPlatform.href = 'chrome://universalsearch-skin/content/style-linux.css';
    }

    docEl.appendChild(stylesheet);
    docEl.appendChild(stylesheetPlatform);
  },

  _unloadStyleSheets: function(win) {
    const doc = win.document;
    const docEl = win.document.documentElement;

    const stylesheet = doc.getElementById('universal-search-stylesheet');
    const stylesheetPlatform = doc.getElementById('universal-search-stylesheet-platform');

    docEl.removeChild(stylesheet);
    docEl.removeChild(stylesheetPlatform);
  },

  _loadScripts: function(win) {
    // Note that we load the scripts into the app namespace, to ease cleanup.
    // Each module's EXPORTED_SYMBOLS will be properties on win.universalSearch.
    Cu.import('resource://gre/modules/Console.jsm', win.universalSearch);
    Cu.import('resource://gre/modules/Services.jsm', win.universalSearch);

    Cu.import('chrome://universalsearch-lib/content/events.js', win.universalSearch);
    Cu.import('chrome://universalsearch-lib/content/metrics.js', win.universalSearch);
    Cu.import('chrome://universalsearch-lib/content/recommendation-server.js', win.universalSearch);

    Cu.import('chrome://universalsearch-ui/content/highlight-manager.js', win.universalSearch);
    Cu.import('chrome://universalsearch-ui/content/popup.js', win.universalSearch);
    Cu.import('chrome://universalsearch-ui/content/recommendation.js', win.universalSearch);
    Cu.import('chrome://universalsearch-ui/content/recommendation-row.js', win.universalSearch);
    Cu.import('chrome://universalsearch-ui/content/urlbar.js', win.universalSearch);
  },

  _unloadScripts: function() {
    // Unload scripts from the namespace. Not clear on whether this is necessary
    // if we just delete win.universalSearch.

    // NOTE: ONLY unload scripts that are packaged inside this addon (#268).
    // NEVER unload scripts used globally by Firefox.
    Cu.unload('chrome://universalsearch-ui/content/highlight-manager.js');
    Cu.unload('chrome://universalsearch-ui/content/popup.js');
    Cu.unload('chrome://universalsearch-ui/content/recommendation.js');
    Cu.unload('chrome://universalsearch-ui/content/recommendation-row.js');
    Cu.unload('chrome://universalsearch-ui/content/urlbar.js');

    Cu.unload('chrome://universalsearch-lib/content/recommendation-server.js');
    Cu.unload('chrome://universalsearch-lib/content/metrics.js');
    Cu.unload('chrome://universalsearch-lib/content/events.js');
  },

  _startApp: function(win) {
    // Initialize modules and assemble the object graph.

    const app = win.universalSearch;

    app.events = new app.Events();
    app.events.init();

    app.recommendationServer = new app.RecommendationServer({
      events: app.events,
      xhr: Cc['@mozilla.org/xmlextras/xmlhttprequest;1'],
      timeout: 1000,
      // app.console is provided by loading Console.jsm
      console: app.console,
      prefs: app.prefs,
      urlbarPrefs: app.urlbarPrefs
    });
    app.recommendationServer.init();

    // NOTE: order matters here, the urlbar and highlightManager both need
    // to be handed the initialized recommendation
    app.recommendation = new app.Recommendation({
      eTLD: Services.eTLD,
      events: app.events,
      io: Services.io,
      objectUtils: ObjectUtils,
      win: win,
      RecommendationRow: app.RecommendationRow
    });
    app.recommendation.init();

    app.urlbar = new app.Urlbar({
      win: win,
      events: app.events,
      privateBrowsingUtils: PrivateBrowsingUtils,
      recommendation: app.recommendation
    });
    app.urlbar.init();

    app.popup = new app.Popup({
      win: win,
      events: app.events
    });
    app.popup.init();

    app.highlightManager = new app.HighlightManager({
      win: win,
      events: app.events,
      recommendation: app.recommendation,
      popup: app.popup
    });
    app.highlightManager.init();

    app.metrics = new app.Metrics({
      events: app.events,
      popup: app.popup,
      recommendation: app.recommendation,
      win: win,
      observerService: Cc["@mozilla.org/observer-service;1"]
                       .getService(Ci.nsIObserverService)
    });
    app.metrics.init();
  },

  _stopApp: function(win) {
    const app = win.universalSearch;

    app.popup.destroy();
    app.recommendation.destroy();
    app.highlightManager.destroy();
    app.urlbar.destroy();
    app.recommendationServer.destroy();
    app.events.destroy();

    delete win.universalSearch;
  },

  onError: function(msg) {
    console.error(msg);
  }
};

// Expose a singleton, since we only need one of these for the add-on.
const UniversalSearch = new Search();
<|endoftext|>


<commit_before>// USGS Landsat Imagery Metadata RES API Request Helpers
//
// Forked from https://github.com/FDA/openfda/tree/master/api
// Exposes /landsat/metadata.json and /healthcheck GET endpoints
//
// Author: developmentseed
// Contributer: scisco
//
// License: CC0 1.0 Universal

var underscore = require('underscore');

var EXPECTED_PARAMS = ['search', 'count', 'limit', 'skip'];

exports.API_REQUEST_ERROR = 'ApiRequestError';
var API_REQUEST_ERROR = exports.API_REQUEST_ERROR;

exports.CheckParams = function(params) {
  // Ensure we only have params that are expected.
  underscore.each(underscore.keys(params), function(param) {
    if (EXPECTED_PARAMS.indexOf(param) == -1) {
      throw {
        name: API_REQUEST_ERROR,
        message: 'Invalid parameter: ' + param
      };
    }
  });

  if (params.limit) {
    var limit = parseInt(params.limit);
    if (isNaN(limit)) {
      throw {
        name: API_REQUEST_ERROR,
        message: 'Invalid limit parameter value.'
      };
    }
    params.limit = limit;
  }

  if (params.skip) {
    var skip = parseInt(params.skip);
    if (isNaN(skip)) {
      throw {
        name: API_REQUEST_ERROR,
        message: 'Invalid skip parameter value.'
      };
    }
    params.skip = skip;
  }

  // Limit to 100 results per search request.
  if (!params.count && params.limit && params.limit > 100) {
    throw {
      name: API_REQUEST_ERROR,
      message: 'Limit cannot exceed 100 results for search requests. Use ' +
        'the skip param to get additional results.'
    };
  }

  // Limit to 1000 results per count request.
  if (params.count && params.limit && params.limit > 1000) {
    throw {
      name: API_REQUEST_ERROR,
      message: 'Limit cannot exceed 1000 results for count requests.'
    };
  }

  // Do not allow ski param with count requests.
  if (params.count && params.skip) {
    throw {
      name: API_REQUEST_ERROR,
      message: 'Should not use skip param when using count.'
    };
  }

  // Set default values for missing params
  params.skip = params.skip || 0;
  if (!params.limit) {
    if (params.count) {
      params.limit = 100;
    } else {
      params.limit = 1;
    }
  }

  var clean_params = {};
  underscore.extend(clean_params,
    underscore.pick(params, EXPECTED_PARAMS));

  return clean_params;
};
<commit_msg>read query limit and count limit from env vars if present<commit_after>// USGS Landsat Imagery Metadata RES API Request Helpers
//
// Forked from https://github.com/FDA/openfda/tree/master/api
// Exposes /landsat/metadata.json and /healthcheck GET endpoints
//
// Author: developmentseed
// Contributer: scisco
//
// License: CC0 1.0 Universal

var underscore = require('underscore');

var EXPECTED_PARAMS = ['search', 'count', 'limit', 'skip'];

var QUERY_LIMIT = process.env.QUERY_LIMIT || 100;
var COUNT_LIMIT = process.env.COUNT_LIMIT || 1000;

exports.API_REQUEST_ERROR = 'ApiRequestError';
var API_REQUEST_ERROR = exports.API_REQUEST_ERROR;

exports.CheckParams = function(params) {
  // Ensure we only have params that are expected.
  underscore.each(underscore.keys(params), function(param) {
    if (EXPECTED_PARAMS.indexOf(param) == -1) {
      throw {
        name: API_REQUEST_ERROR,
        message: 'Invalid parameter: ' + param
      };
    }
  });

  if (params.limit) {
    var limit = parseInt(params.limit);
    if (isNaN(limit)) {
      throw {
        name: API_REQUEST_ERROR,
        message: 'Invalid limit parameter value.'
      };
    }
    params.limit = limit;
  }

  if (params.skip) {
    var skip = parseInt(params.skip);
    if (isNaN(skip)) {
      throw {
        name: API_REQUEST_ERROR,
        message: 'Invalid skip parameter value.'
      };
    }
    params.skip = skip;
  }

  // Limit to 100 results per search request.
  if (!params.count && params.limit && params.limit > QUERY_LIMIT) {
    throw {
      name: API_REQUEST_ERROR,
      message: 'Limit cannot exceed ' + QUERY_LIMIT + ' results for search requests. Use ' +
        'the skip param to get additional results.'
    };
  }

  // Limit to 1000 results per count request.
  if (params.count && params.limit && params.limit > COUNT_LIMIT) {
    throw {
      name: API_REQUEST_ERROR,
      message: 'Limit cannot exceed ' + COUNT_LIMIT + ' results for count requests.'
    };
  }

  // Do not allow ski param with count requests.
  if (params.count && params.skip) {
    throw {
      name: API_REQUEST_ERROR,
      message: 'Should not use skip param when using count.'
    };
  }

  // Set default values for missing params
  params.skip = params.skip || 0;
  if (!params.limit) {
    if (params.count) {
      params.limit = 100;
    } else {
      params.limit = 1;
    }
  }

  var clean_params = {};
  underscore.extend(clean_params,
    underscore.pick(params, EXPECTED_PARAMS));

  return clean_params;
};
<|endoftext|>


<commit_before>var iconv = require('iconv-lite');
var net = require('net');
var util = require('./index');
var config = require('../config');

if (!(config.reqCacheSize > 0) || config.reqCacheSize < 512) {
  config.reqCacheSize = 512;
}

if (!(config.frameCacheSize > 0) || config.frameCacheSize < 512) {
  config.frameCacheSize = 512;
}

var TIMEOUT = 36000;
var CLEAR_INTERVAL = 5000;
var CACHE_TIME = CLEAR_INTERVAL * 2;
var MAX_LENGTH = config.reqCacheSize;
var MIN_LENGTH = MAX_LENGTH - 100;
var MAX_FRAMES_LENGTH = config.frameCacheSize;
var COUNT = 100;
var count = 0;
var ids = [];
var reqData = {};
var frames = [];
var proxy, binded, timeout, interval;

function disable() {
  proxy.removeListener('request', handleRequest);
  proxy.removeListener('frame', handleFrame);
  ids = [];
  reqData = {};
  frames = [];
  interval && clearInterval(interval);
  interval = null;
  binded = false;
}

function enable() {
  if (!binded) {
    binded = true;
    proxy.on('request', handleRequest);
    proxy.on('frame', handleFrame);
  }
  clearTimeout(timeout);
  timeout = setTimeout(disable, TIMEOUT);
  if (!interval) {
    interval = setInterval(clearCache, CLEAR_INTERVAL);
  }
}

/**
* 如果超过最大缓存数，清理如下请求数据：
* 1. 已经请求结束且结束时间超过10秒
* 2. 请求#1前面的未结束且未被ui读取过的请求
*/
function clearCache() {
  if (frames.length > MAX_FRAMES_LENGTH) {
    frames.splice(0, 100);
  }
  var len = ids.length;
  if (len <= MAX_LENGTH) {
    return;
  }

  var index = -1; //已经完成，且缓存超过10s的最后一个请求
  var now = Date.now();
  var i, curData;
  for (i = len - 1; i >= 0; i--) {
    curData = reqData[ids[i]];
    if (curData.endTime && now - curData.endTime > TIMEOUT) {
      index = i;
      break;
    }
  }

  if (index < 0) {
    return;
  }

  var _ids = [];
  ++index;
  for (i = 0; i < index; i++) {
    var id = ids[i];
    curData = reqData[id];
    if (curData.read && (!curData.endTime || now - curData.endTime < CACHE_TIME
        || now - curData.startTime < TIMEOUT)) {
      _ids.push(id);
    } else {
      delete reqData[id];
      if (--len <= MIN_LENGTH) {
        _ids.push.apply(_ids, ids.slice(i + 1, index));
        break;
      }
    }
  }
  ids = _ids.concat(ids.slice(index));
}

function getIds(startTime, count, lastRowId) {
  var len = ids.length;
  if (!len) {
    return [];
  }
  startTime = startTime || lastRowId;
  if (!startTime) {
    return ids.slice(-count);
  }
  for (var i = 0; i < len; i++) {
    if (ids[i] === startTime) {
      return ids.slice(i + 1, i + 1 + count);
    }
  }
  return ids.slice(0, count);
}

function getList(ids) {
  if (!Array.isArray(ids)) {
    return [];
  }
  return ids.map(function(id, i) {
    var curData = reqData[id];
    if (curData) {
      curData.read = true;
    }
    return curData;
  });
}

function handleRequest(req) {
  var curData = req.data;
  var id = curData.id = curData.id || (curData.startTime + '-' + ++count);
  reqData[id] = curData;
  ids.indexOf(id) === -1 && ids.push(id);
}

function decodeData(frame) {
  if (frame.text != null) {
    return frame;
  }
  if (frame.bin) {
    var result = [];
    frame.bin.forEach(function(b) {
      b = b.toString(16).toUpperCase();
      result.push(b.length > 1 ? b : '0' + b);
    });
    try {
      frame.text = iconv.decode(frame.bin, frame.charset || 'utf8');
    } catch (e) {
      frame.text = frame.bin + '';
    }
    frame.bin = result.join('');
  } else {
    frame.bin = frame.text = '';
  }

  return frame;
}
function handleFrame(data) {
  frames.push(data);
}

function getFrames(curReqId, lastFrameId) {
  if (!curReqId) {
    return;
  }
  var result = [];
  var count = 10;
  for (var i = frames.length - 1; i >= 0; i--) {
    var frame = frames[i];
    if (frame.reqId === curReqId && (lastFrameId ? frame.frameId > lastFrameId : count > 0)) {
      result.push(decodeData(frame));
      if (--count <= 0) {
        break;
      }
    }
  }
  return result.reverse();
}

module.exports = function init(_proxy) {
  proxy = _proxy;
/**
* options: {
* 		startTime: timestamp || timestamp + '-' + count
* 		count: 获取新数据的数量
* 		ids: 请未结束的id列表
* }
*
* @param options
*/
  function formatFilter(filter, clientIp) {
    if (!filter) {
      return;
    }
    var url = util.trimStr(filter.url).toLowerCase();
    var name = util.trimStr(filter.name).toLowerCase();
    var value = util.trimStr(filter.value).toLowerCase();
    var ip = util.trimStr(filter.ip);
    var list = [];
    if (ip === 'self') {
      ip = clientIp;
    } else if (ip && !net.isIP(ip)) {
      ip.split(',').forEach(function(item) {
        item = item.trim();
        if (item === 'self') {
          item = clientIp;
        }
        if (net.isIP(item) && list.indexOf(item) === -1) {
          list.push(item);
        }
      });
      ip = null;
    }
    var result;
    if (url) {
      result = {};
      result.url = url;
    }
    if (name && value) {
      result = result || {};
      result.name = name;
      result.value = value;
    }
    if (ip) {
      result = result || {};
      result.ip = ip;
    }
    if (list.length) {
      result = result || {};
      result.ipList = list.slice(0, 10);
    }
    return result;
  }
  function checkClientIp(item, filter) {
    var clientIp = item.req.ip;
    if (filter.ip && clientIp !== filter.ip) {
      return false;
    }
    var ipList = filter.ipList;
    if (!ipList) {
      return true;
    }
    for (var i = 0, len = ipList.length; i < len; i++) {
      var ip = ipList[i];
      if (ip === clientIp) {
        return true;
      }
    }
    return false;
  }
  function checkItem(item, filter) {
    if (!item) {
      return false;
    }
    if (!checkClientIp(item, filter)) {
      return false;
    }
    if (filter.url && item.url.toLowerCase().indexOf(filter.url) === -1) {
      return false;
    }
    if (!filter.name) {
      return true;
    }
    var value = item.req.headers[filter.name];
    if (!value || typeof value !== 'string') {
      if (!Array.isArray(value)) {
        return false;
      }
      value = value.join('\n');
    }
    value = value.toLowerCase();
    if (value.indexOf(filter.value) !== -1) {
      return true;
    }
    return value.indexOf(util.encodeURIComponent(filter.value).toLowerCase()) !== -1;
  }
  proxy.getData = function(options, clientIp) {
    enable();
    options = options || {};
    var data = {};
    var newIds = options.startTime == -1 ? [] : getIds(options.startTime, options.count, options.lastRowId);
    var setData = function(item) {
      if (item) {
        data[item.id] = item;
      }
    };
    if (newIds.length > 0) {
      var filter = formatFilter(options, clientIp);
      if (filter) {
        var count = options.count > 0 ? options.count : COUNT;
        var id = newIds[0];
        var index = ids.indexOf(newIds[0]);
        newIds = [];
        while(id && count > 0) {
          var item = reqData[id];
          if (checkItem(item, filter)) {
            setData(item);
            newIds.push(id);
            --count;
          }
          id = ids[++index];
        }
      } else if (!filter) {
        getList(newIds).forEach(setData);
      }
    }
    getList(options.ids).forEach(setData);
    return {
      ids: options.ids || [],
      newIds: newIds,
      data: data,
      lastId: newIds[newIds.length - 1] || ids[ids.length - 1],
      frames: getFrames(options.curReqId, options.lastFrameId)
    };
  };
};
<commit_msg>feat: Support for filtering data through multiple client ip<commit_after>var iconv = require('iconv-lite');
var net = require('net');
var util = require('./index');
var config = require('../config');

if (!(config.reqCacheSize > 0) || config.reqCacheSize < 512) {
  config.reqCacheSize = 512;
}

if (!(config.frameCacheSize > 0) || config.frameCacheSize < 512) {
  config.frameCacheSize = 512;
}

var TIMEOUT = 36000;
var CLEAR_INTERVAL = 5000;
var CACHE_TIME = CLEAR_INTERVAL * 2;
var MAX_LENGTH = config.reqCacheSize;
var MIN_LENGTH = MAX_LENGTH - 100;
var MAX_FRAMES_LENGTH = config.frameCacheSize;
var COUNT = 100;
var count = 0;
var ids = [];
var reqData = {};
var frames = [];
var proxy, binded, timeout, interval;

function disable() {
  proxy.removeListener('request', handleRequest);
  proxy.removeListener('frame', handleFrame);
  ids = [];
  reqData = {};
  frames = [];
  interval && clearInterval(interval);
  interval = null;
  binded = false;
}

function enable() {
  if (!binded) {
    binded = true;
    proxy.on('request', handleRequest);
    proxy.on('frame', handleFrame);
  }
  clearTimeout(timeout);
  timeout = setTimeout(disable, TIMEOUT);
  if (!interval) {
    interval = setInterval(clearCache, CLEAR_INTERVAL);
  }
}

/**
* 如果超过最大缓存数，清理如下请求数据：
* 1. 已经请求结束且结束时间超过10秒
* 2. 请求#1前面的未结束且未被ui读取过的请求
*/
function clearCache() {
  if (frames.length > MAX_FRAMES_LENGTH) {
    frames.splice(0, 100);
  }
  var len = ids.length;
  if (len <= MAX_LENGTH) {
    return;
  }

  var index = -1; //已经完成，且缓存超过10s的最后一个请求
  var now = Date.now();
  var i, curData;
  for (i = len - 1; i >= 0; i--) {
    curData = reqData[ids[i]];
    if (curData.endTime && now - curData.endTime > TIMEOUT) {
      index = i;
      break;
    }
  }

  if (index < 0) {
    return;
  }

  var _ids = [];
  ++index;
  for (i = 0; i < index; i++) {
    var id = ids[i];
    curData = reqData[id];
    if (curData.read && (!curData.endTime || now - curData.endTime < CACHE_TIME
        || now - curData.startTime < TIMEOUT)) {
      _ids.push(id);
    } else {
      delete reqData[id];
      if (--len <= MIN_LENGTH) {
        _ids.push.apply(_ids, ids.slice(i + 1, index));
        break;
      }
    }
  }
  ids = _ids.concat(ids.slice(index));
}

function getIds(startTime, count, lastRowId) {
  var len = ids.length;
  if (!len) {
    return [];
  }
  startTime = startTime || lastRowId;
  if (!startTime) {
    return ids.slice(-count);
  }
  for (var i = 0; i < len; i++) {
    if (ids[i] === startTime) {
      return ids.slice(i + 1, i + 1 + count);
    }
  }
  return ids.slice(0, count);
}

function getList(ids) {
  if (!Array.isArray(ids)) {
    return [];
  }
  return ids.map(function(id, i) {
    var curData = reqData[id];
    if (curData) {
      curData.read = true;
    }
    return curData;
  });
}

function handleRequest(req) {
  var curData = req.data;
  var id = curData.id = curData.id || (curData.startTime + '-' + ++count);
  reqData[id] = curData;
  ids.indexOf(id) === -1 && ids.push(id);
}

function decodeData(frame) {
  if (frame.text != null) {
    return frame;
  }
  if (frame.bin) {
    var result = [];
    frame.bin.forEach(function(b) {
      b = b.toString(16).toUpperCase();
      result.push(b.length > 1 ? b : '0' + b);
    });
    try {
      frame.text = iconv.decode(frame.bin, frame.charset || 'utf8');
    } catch (e) {
      frame.text = frame.bin + '';
    }
    frame.bin = result.join('');
  } else {
    frame.bin = frame.text = '';
  }

  return frame;
}
function handleFrame(data) {
  frames.push(data);
}

function getFrames(curReqId, lastFrameId) {
  if (!curReqId) {
    return;
  }
  var result = [];
  var count = 10;
  for (var i = frames.length - 1; i >= 0; i--) {
    var frame = frames[i];
    if (frame.reqId === curReqId && (lastFrameId ? frame.frameId > lastFrameId : count > 0)) {
      result.push(decodeData(frame));
      if (--count <= 0) {
        break;
      }
    }
  }
  return result.reverse();
}

module.exports = function init(_proxy) {
  proxy = _proxy;
/**
* options: {
* 		startTime: timestamp || timestamp + '-' + count
* 		count: 获取新数据的数量
* 		ids: 请未结束的id列表
* }
*
* @param options
*/
  function formatFilter(filter, clientIp) {
    if (!filter) {
      return;
    }
    var url = util.trimStr(filter.url).toLowerCase();
    var name = util.trimStr(filter.name).toLowerCase();
    var value = util.trimStr(filter.value).toLowerCase();
    var ip = util.trimStr(filter.ip);
    var list = [];
    if (ip === 'self') {
      ip = clientIp;
    } else if (ip && !net.isIP(ip)) {
      ip.split(',').forEach(function(item) {
        item = item.trim();
        if (item === 'self') {
          item = clientIp;
        }
        if (net.isIP(item) && list.indexOf(item) === -1) {
          list.push(item);
        }
      });
      ip = null;
    }
    var result;
    if (url) {
      result = {};
      result.url = url;
    }
    if (name && value) {
      result = result || {};
      result.name = name;
      result.value = value;
    }
    if (ip) {
      result = result || {};
      result.ip = ip;
    }
    if (list.length) {
      result = result || {};
      result.ipList = list.slice(0, 16);
    }
    return result;
  }
  function checkClientIp(item, filter) {
    var clientIp = item.req.ip;
    if (filter.ip && clientIp !== filter.ip) {
      return false;
    }
    var ipList = filter.ipList;
    if (!ipList) {
      return true;
    }
    var len = ipList.length;
    if (len < 3) {
      if (ipList[0] === clientIp) {
        return true;
      }
      if (ipList[1] && ipList[1] === clientIp) {
        return true;
      }
    } else {
      for (var i = 0; i < len; i++) {
        var ip = ipList[i];
        if (ip === clientIp) {
          return true;
        }
      }
    }
    return false;
  }
  function checkItem(item, filter) {
    if (!item) {
      return false;
    }
    if (!checkClientIp(item, filter)) {
      return false;
    }
    if (filter.url && item.url.toLowerCase().indexOf(filter.url) === -1) {
      return false;
    }
    if (!filter.name) {
      return true;
    }
    var value = item.req.headers[filter.name];
    if (!value || typeof value !== 'string') {
      if (!Array.isArray(value)) {
        return false;
      }
      value = value.join('\n');
    }
    value = value.toLowerCase();
    if (value.indexOf(filter.value) !== -1) {
      return true;
    }
    return value.indexOf(util.encodeURIComponent(filter.value).toLowerCase()) !== -1;
  }
  proxy.getData = function(options, clientIp) {
    enable();
    options = options || {};
    var data = {};
    var newIds = options.startTime == -1 ? [] : getIds(options.startTime, options.count, options.lastRowId);
    var setData = function(item) {
      if (item) {
        data[item.id] = item;
      }
    };
    if (newIds.length > 0) {
      var filter = formatFilter(options, clientIp);
      if (filter) {
        var count = options.count > 0 ? options.count : COUNT;
        var id = newIds[0];
        var index = ids.indexOf(newIds[0]);
        newIds = [];
        while(id && count > 0) {
          var item = reqData[id];
          if (checkItem(item, filter)) {
            setData(item);
            newIds.push(id);
            --count;
          }
          id = ids[++index];
        }
      } else if (!filter) {
        getList(newIds).forEach(setData);
      }
    }
    getList(options.ids).forEach(setData);
    return {
      ids: options.ids || [],
      newIds: newIds,
      data: data,
      lastId: newIds[newIds.length - 1] || ids[ids.length - 1],
      frames: getFrames(options.curReqId, options.lastFrameId)
    };
  };
};
<|endoftext|>


<commit_before>//
// Copyright (c) Microsoft and contributors.  All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//

var fs = require('fs');
var path = require('path');
var moment = require('moment');
var utils = require('./utils');

var PluginCache = {};

function getPluginsFile() {
  return path.join(utils.azureDir(), 'plugins.json');
}

function read() {
  var pluginsFile = getPluginsFile();
  if (utils.pathExistsSync(pluginsFile)) {
    var data = fs.readFileSync(pluginsFile);
    var cachedPlugins = JSON.parse(data);
    if (cachedPlugins && !expiredPlugins(cachedPlugins)) {
      return cachedPlugins;
    }
  }

  return null;
}

function save(plugins) {
  plugins.timestamp = new Date();

  var pluginsFile = getPluginsFile();
  fs.writeFileSync(pluginsFile, JSON.stringify(plugins));
  return plugins;
}

function expiredPlugins(plugins) {
  var minutesDifference = moment(plugins.timestamp).diff(new Date(), 'minutes');
  if (plugins.timestamp && minutesDifference < 5) {
    return false;
  }

  return true;
}

function clear() {
  var pluginsFile = getPluginsFile();
  try {
    fs.unlinkSync(pluginsFile);
  } catch (e) {
    // intentionally do nothing
  }
}

PluginCache.read = read;
PluginCache.save = save;
PluginCache.clear = clear;

module.exports = PluginCache;<commit_msg>Fix issue with moving xplat installation directory<commit_after>//
// Copyright (c) Microsoft and contributors.  All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//

var fs = require('fs');
var path = require('path');
var moment = require('moment');
var utils = require('./utils');

var PluginCache = {};

function getPluginsFile() {
  return path.join(utils.azureDir(), 'plugins.json');
}

function read() {
  var pluginsFile = getPluginsFile();
  if (utils.pathExistsSync(pluginsFile)) {
    var data = fs.readFileSync(pluginsFile);
    var cachedPlugins = JSON.parse(data);
    if (cachedPlugins && !expiredPlugins(cachedPlugins)) {
      return cachedPlugins;
    }
  }

  return null;
}

function save(plugins) {
  plugins.timestamp = new Date();

  var pluginsFile = getPluginsFile();
  fs.writeFileSync(pluginsFile, JSON.stringify(plugins));
  return plugins;
}

function expiredPlugins(plugins) {
  var minutesDifference = moment(plugins.timestamp).diff(new Date(), 'minutes');
  if (plugins.timestamp && minutesDifference > 5) {
    return true;
  }

  var helpCommand = plugins.commands.filter(function (c) {
    return c.name === 'help';
  })[0];

  if (helpCommand) {
    if (!utils.pathExistsSync(helpCommand.filePath)) {
      return true;
    }
  }

  return false;
}

function clear() {
  var pluginsFile = getPluginsFile();
  try {
    fs.unlinkSync(pluginsFile);
  } catch (e) {
    // intentionally do nothing
  }
}

PluginCache.read = read;
PluginCache.save = save;
PluginCache.clear = clear;

module.exports = PluginCache;<|endoftext|>


<commit_before>module.exports = exports;

var fs = require('fs')
  , tar = require('tar')
  , path = require('path')
  , zlib = require('zlib')
  , log = require('npmlog')
  , semver = require('semver')
  , request = require('request')
  , win = process.platform == 'win32'
  , os = require('os')
  , existsAsync = fs.exists || path.exists
  , cp = require('child_process')

module.exports.validate = function(opts,callback) {
    var args = [];
    var options = {}
    var shell_cmd;
    var arch_names = {
        'ia32':'-i386',
        'x64':'-x86_64'
    }
    var nw = (opts.runtime && opts.runtime === 'node-webkit');
    if (nw) {
        options.timeout = 5000;
        if (process.platform === 'darwin') {
            shell_cmd = 'node-webkit';
        } else if (process.platform === 'win32') {
            shell_cmd = 'nw.exe';
        } else {
            shell_cmd = 'nw';
        }
    } else if (process.platform === 'darwin' && arch_names[opts.target_arch]) {
        shell_cmd = 'arch';
        args.push(arch_names[opts.target_arch]);
        args.push(process.execPath);
    } else if (process.arch == opts.target_arch) {
        shell_cmd = process.execPath;
    }
    if (!shell_cmd) {
        return callback();
    }
    args.push(opts.module_main);
    log.info("validate","Running test command: '" + shell_cmd + ' ' + args.join(' '));
    cp.execFile(shell_cmd, args, options, function(err, stdout, stderr) {
        // check for normal timeout for node-webkit
        if (err && nw && err.killed == true && err.signal.indexOf('SIG') > -1) {
            return callback();
        }
        if (err || stderr) {
            return callback(new Error(err && err.message || stderr));
        }
        return callback();
    });
}
<commit_msg>close a quote<commit_after>module.exports = exports;

var fs = require('fs')
  , tar = require('tar')
  , path = require('path')
  , zlib = require('zlib')
  , log = require('npmlog')
  , semver = require('semver')
  , request = require('request')
  , win = process.platform == 'win32'
  , os = require('os')
  , existsAsync = fs.exists || path.exists
  , cp = require('child_process')

module.exports.validate = function(opts,callback) {
    var args = [];
    var options = {}
    var shell_cmd;
    var arch_names = {
        'ia32':'-i386',
        'x64':'-x86_64'
    }
    var nw = (opts.runtime && opts.runtime === 'node-webkit');
    if (nw) {
        options.timeout = 5000;
        if (process.platform === 'darwin') {
            shell_cmd = 'node-webkit';
        } else if (process.platform === 'win32') {
            shell_cmd = 'nw.exe';
        } else {
            shell_cmd = 'nw';
        }
    } else if (process.platform === 'darwin' && arch_names[opts.target_arch]) {
        shell_cmd = 'arch';
        args.push(arch_names[opts.target_arch]);
        args.push(process.execPath);
    } else if (process.arch == opts.target_arch) {
        shell_cmd = process.execPath;
    }
    if (!shell_cmd) {
        return callback();
    }
    args.push(opts.module_main);
    log.info("validate","Running test command: '" + shell_cmd + ' ' + args.join(' ') + "'");
    cp.execFile(shell_cmd, args, options, function(err, stdout, stderr) {
        // check for normal timeout for node-webkit
        if (err && nw && err.killed == true && err.signal.indexOf('SIG') > -1) {
            return callback();
        }
        if (err || stderr) {
            return callback(new Error(err && err.message || stderr));
        }
        return callback();
    });
}
<|endoftext|>


<commit_before>import Discussion from '../models/discussion';
import ForumBoard from '../models/forumBoard';

export default function syncElasticsearch() {
  ForumBoard.synchronize();
  Discussion.synchronize();
}
<commit_msg>Log syncElasticsearch<commit_after>import Discussion from '../models/discussion';
import ForumBoard from '../models/forumBoard';

export default function syncElasticsearch() {
  const s1 = ForumBoard.synchronize();
  const s2 = Discussion.synchronize();
  [s1, s2].forEach((stream) => {
    let count = 0;
    stream.on('data', function(err, doc) {
      count += 1;
    });
    stream.on('close', function() {
      console.log('indexed ' + count + ' documents!');
    });
    stream.on('error', function(err) {
      console.log(err);
    });
  });
}
<|endoftext|>


<commit_before>var mongoose = require('mongoose'),
	mongooseTypes = require('mongoose-types'),
	expressMongoose = require('express-mongoose'),
	passport = require('passport'),
	routes = require('../routes'),
	flash = require('connect-flash'),
	session = require('express-session'),
	log = require('./logger'),
	MongoDBStore = require('connect-mongodb-session')(session);

const notForApi = function (callback) {
	return function(req, res, next) {
		if (req.path.indexOf('/api') === 0) {
				next();
		} else {
				callback(req, res, next);
		}
	}
}

// Database connection bootstrap
module.exports = function(app)
{
	log.info('Springroll API is now operational');

	// Attempt to connect to database
	mongoose.connect(process.env.MONGO_DATABASE, function()
	{
		// Include models once
		require('../models/release');
		require('../models/game');
		require('../models/group');
		require('../models/user');
	});

	// Load the types for URL and Email
	mongooseTypes.loadTypes(mongoose);

	// Listen for errors
	var db = mongoose.connection;
	db.on('error', function(err)
	{
		console.error(String("Connection error : " + err).red);
	});

    var store = new MongoDBStore(
        {
            uri: process.env.MONGO_DATABASE,
            collection: 'auth_sessions'
        }
    );

	// Authentication stuff
	app.use(notForApi(session(
	{
		secret: process.env.SECRET_KEY,
		saveUninitialized: true,
		resave: true,
        store: store

	})));
	app.use(notForApi(flash()));
	app.use(notForApi(passport.initialize()));
	app.use(notForApi(passport.session()));
	require('./auth')(passport);

	// Load all the routes
	routes(app);
};
<commit_msg>rackum frackum double tabs....<commit_after>var mongoose = require('mongoose'),
	mongooseTypes = require('mongoose-types'),
	expressMongoose = require('express-mongoose'),
	passport = require('passport'),
	routes = require('../routes'),
	flash = require('connect-flash'),
	session = require('express-session'),
	log = require('./logger'),
	MongoDBStore = require('connect-mongodb-session')(session);

const notForApi = function (callback) {
	return function(req, res, next) {
		if (req.path.indexOf('/api') === 0) {
			next();
		} else {
			callback(req, res, next);
		}
	}
}

// Database connection bootstrap
module.exports = function(app)
{
	log.info('Springroll API is now operational');

	// Attempt to connect to database
	mongoose.connect(process.env.MONGO_DATABASE, function()
	{
		// Include models once
		require('../models/release');
		require('../models/game');
		require('../models/group');
		require('../models/user');
	});

	// Load the types for URL and Email
	mongooseTypes.loadTypes(mongoose);

	// Listen for errors
	var db = mongoose.connection;
	db.on('error', function(err)
	{
		console.error(String("Connection error : " + err).red);
	});

    var store = new MongoDBStore(
        {
            uri: process.env.MONGO_DATABASE,
            collection: 'auth_sessions'
        }
    );

	// Authentication stuff
	app.use(notForApi(session(
	{
		secret: process.env.SECRET_KEY,
		saveUninitialized: true,
		resave: true,
        store: store

	})));
	app.use(notForApi(flash()));
	app.use(notForApi(passport.initialize()));
	app.use(notForApi(passport.session()));
	require('./auth')(passport);

	// Load all the routes
	routes(app);
};
<|endoftext|>


<commit_before>const handlebars = require('handlebars');
const changelogHelper = require('./changelog');
const showdown = require('showdown');

const converter = new showdown.Converter();
converter.setFlavor('github');

module.exports = {
  ensurePr,
  checkAutoMerge,
};

// Ensures that PR exists with matching title/body
async function ensurePr(prConfig) {
  const config = { ...prConfig };

  logger.trace({ config }, 'ensurePr');
  // If there is a group, it will use the config of the first upgrade in the array
  const { branchName, prTitle, upgrades } = config;
  // Check if existing PR exists
  const existingPr = await platform.getBranchPr(branchName);
  if (existingPr) {
    logger.debug('Found existing PR');
  }
  config.upgrades = [];
  const branchStatus = await platform.getBranchStatus(
    branchName,
    config.requiredStatusChecks
  );

  if (config.lockFileErrors && config.lockFileErrors.length) {
    logger.debug('Forcing PR because of lock file errors');
    config.forcePr = true;
  }

  // Only create a PR if a branch automerge has failed
  if (
    config.automerge === true &&
    config.automergeType.startsWith('branch') &&
    !config.forcePr
  ) {
    logger.debug(
      `Branch is configured for branch automerge, branchStatus is: ${branchStatus}`
    );
    if (branchStatus === 'pending' || branchStatus === 'running') {
      logger.debug('Checking how long this branch has been pending');
      const lastCommitTime = await platform.getBranchLastCommitTime(branchName);
      const currentTime = new Date();
      const millisecondsPerHour = 1000 * 60 * 60;
      const elapsedHours = Math.round(
        (currentTime.getTime() - lastCommitTime.getTime()) / millisecondsPerHour
      );
      if (elapsedHours >= config.prNotPendingHours) {
        logger.info('Branch exceeds prNotPending hours - forcing PR creation');
        config.forcePr = true;
      }
    }
    if (config.forcePr || branchStatus === 'failure') {
      logger.debug(`Branch tests failed, so will create PR`);
    } else {
      return null;
    }
  }
  if (config.prCreation === 'status-success') {
    logger.debug('Checking branch combined status');
    if (branchStatus !== 'success') {
      logger.debug(`Branch status is "${branchStatus}" - not creating PR`);
      return null;
    }
    logger.debug('Branch status success');
  } else if (
    config.prCreation === 'not-pending' &&
    !existingPr &&
    !config.forcePr
  ) {
    logger.debug('Checking branch combined status');
    if (branchStatus === 'pending' || branchStatus === 'running') {
      logger.debug(`Branch status is "${branchStatus}" - checking timeout`);
      const lastCommitTime = await platform.getBranchLastCommitTime(branchName);
      const currentTime = new Date();
      const millisecondsPerHour = 1000 * 60 * 60;
      const elapsedHours = Math.round(
        (currentTime.getTime() - lastCommitTime.getTime()) / millisecondsPerHour
      );
      if (elapsedHours < config.prNotPendingHours) {
        logger.debug(
          `Branch is ${elapsedHours} hours old - skipping PR creation`
        );
        return null;
      }
      logger.debug(
        `prNotPendingHours=${
          config.prNotPendingHours
        } threshold hit - creating PR`
      );
    }
    logger.debug('Branch status success');
  }

  const processedUpgrades = [];

  const issueRe = /([\s(])#(\d+)([)\s]?)/g;

  const commitRepos = [];

  let token;
  let endpoint;
  // istanbul ignore if
  if (process.env.GITHUB_ENDPOINT) {
    logger.debug('Removing GHE token before calling changelog');
    endpoint = process.env.GITHUB_ENDPOINT;
    delete process.env.GITHUB_ENDPOINT;
    token = process.env.GITHUB_TOKEN;
    process.env.GITHUB_TOKEN = process.env.GITHUB_COM_TOKEN;
  }
  // Get changelog and then generate template strings
  for (const upgrade of upgrades) {
    const upgradeKey = `${upgrade.depName}-${upgrade.manager}-${
      upgrade.changeLogFromVersion
    }-${upgrade.changeLogToVersion}`;
    if (processedUpgrades.indexOf(upgradeKey) !== -1) {
      continue; // eslint-disable-line no-continue
    }
    processedUpgrades.push(upgradeKey);

    const logJSON = await changelogHelper.getChangeLogJSON({
      manager: upgrade.manager,
      depType: upgrade.depType,
      depName: upgrade.depName,
      fromVersion: upgrade.changeLogFromVersion,
      newVersion: upgrade.changeLogToVersion,
    });

    if (logJSON) {
      upgrade.githubName = logJSON.project.github;
      upgrade.hasReleaseNotes = logJSON.hasReleaseNotes;
      upgrade.releases = [];
      if (!commitRepos.includes(upgrade.githubName)) {
        commitRepos.push(upgrade.githubName);
        logJSON.versions.forEach(version => {
          const release = { ...version };
          // TODO: remove once hasCommits is deprecated
          release.commits = [];
          release.hasCommits = false;
          upgrade.hasCommits = upgrade.hasCommits || release.hasCommits;
          upgrade.releases.push(release);
        });
      }
    }
    config.upgrades.push(upgrade);
  }
  // istanbul ignore if
  if (endpoint) {
    logger.debug('Restoring GHE token and endpoint');
    process.env.GITHUB_TOKEN = token;
    process.env.GITHUB_ENDPOINT = endpoint;
  }

  // Update the config object
  Object.assign(config, upgrades[0]);
  if (config.errors && config.errors.length) {
    config.hasErrors = true;
  }
  if (config.warnings && config.warnings.length) {
    config.hasWarnings = true;
  }
  config.hasReleaseNotes = config.upgrades.some(upg => upg.hasReleaseNotes);
  config.hasCommits = config.upgrades.some(upg => upg.hasCommits);

  const releaseNoteRepos = [];
  for (const upgrade of config.upgrades) {
    if (releaseNoteRepos.includes(upgrade.repositoryUrl)) {
      logger.debug(
        { depName: upgrade.depName },
        'Removing duplicate release notes'
      );
      upgrade.hasReleaseNotes = false;
    } else {
      releaseNoteRepos.push(upgrade.repositoryUrl);
    }
  }

  let prBody = handlebars.compile(config.prBody)(config);
  // istanbul ignore if
  if (config.global) {
    if (config.global.prBanner) {
      prBody = config.global.prBanner + '\n\n' + prBody;
    }
    if (config.global.prFooter) {
      prBody = prBody + '\n---\n\n' + config.global.prFooter;
    }
  }
  prBody = prBody.trim();
  if (config.isGitHub && !config.privateRepo) {
    // Put a zero width space after every # followed by a digit
    prBody = prBody.replace(/#(\d)/gi, '#$1');
    // Put a zero width space after every @ symbol to prevent unintended hyperlinking
    prBody = prBody.replace(/@/g, '@');
    prBody = prBody.replace(/(`\[?@)/g, '$1');
    // Public GitHub repos need links prevented - see #489
    prBody = prBody.replace(issueRe, '$1#$2$3');
    prBody = prBody.replace(
      /(https?:\/\/github.com\/[^/]*\/[^/]*\/(issues|pull)\/\w+)/g,
      '`$1`'
    );
    logger.trace('Escaping links to GitHub users');
    prBody = prBody.replace(
      /]\(https?:\/\/github.com\/[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}\)/gi,
      ']'
    );
    // convert escaped backticks back to `
    const backTickRe = /`([^/]*?)`/g;
    prBody = prBody.replace(backTickRe, '`$1`');
    prBody = prBody.replace(/`#(\d+)`/g, '`#$1`');
  }
  // It would be nice to abstract this to the platform layer but made difficult due to our create/update check
  if (config.isGitLab) {
    // Convert to HTML using GitHub-flavoured markdown as it is more feature-rich than GitLab's flavour
    prBody = converter
      .makeHtml(prBody)
      .replace(/<\/?h4[^>]*>/g, '**') // See #954
      .replace(/Pull Request/g, 'Merge Request')
      .replace(/PR/g, 'MR')
      .replace(//g, '
')
      .replace(/<\/summary><\/p>/g, '
')
      .replace(/

\n/g, '')
      .replace(/
<\/details><\/p>\n/g, '');
  } else if (config.isVsts) {
    // Remove any HTML we use
    prBody = prBody
      .replace('', '**')
      .replace('', '**')
      .replace('', '')
      .replace('', '');
  }

  try {
    if (existingPr) {
      logger.debug('Processing existing PR');
      if (config.automerge && branchStatus === 'failure') {
        logger.debug(`Setting assignees and reviewers as status checks failed`);
        await addAssigneesReviewers(config, existingPr);
      }
      // Check if existing PR needs updating
      if (existingPr.title === prTitle && existingPr.body === prBody) {
        logger.info(`${existingPr.displayNumber} does not need updating`);
        return existingPr;
      }
      // PR must need updating
      if (existingPr.title !== prTitle) {
        logger.info(
          {
            branchName,
            oldPrTitle: existingPr.title,
            newPrTitle: prTitle,
          },
          'PR title changed'
        );
      } else {
        logger.debug(
          {
            prTitle,
            oldPrBody: existingPr.body,
            newPrBody: prBody,
          },
          'PR body changed'
        );
      }

      await platform.updatePr(existingPr.number, prTitle, prBody);
      logger.info({ pr: existingPr.displayNumber }, `Updated PR`);
      return existingPr;
    }
    logger.info({ branchName, prTitle }, `Creating PR`);
    let pr;
    try {
      pr = await platform.createPr(
        branchName,
        prTitle,
        prBody,
        config.labels,
        false,
        config.statusCheckVerify
      );
    } catch (err) {
      logger.warn(
        {
          err,
          message: err.message,
          body: err.response ? err.response.body : undefined,
        },
        `Failed to create PR`
      );
      if (err.message === 'Validation Failed (422)') {
        logger.info({ branchName }, 'Deleting invalid branch');
        await platform.deleteBranch(branchName);
      }
      return null;
    }
    // Skip assign and review if automerging PR
    if (config.automerge && branchStatus !== 'failure') {
      logger.debug(
        `Skipping assignees and reviewers as automerge=${config.automerge}`
      );
    } else {
      await addAssigneesReviewers(config, pr);
    }
    logger.info(`Created ${pr.displayNumber}`);
    return pr;
  } catch (err) {
    // istanbul ignore if
    if (err.message === 'rate-limit-exceeded') {
      logger.debug('Passing rate-limit-exceeded error up');
      throw err;
    }
    logger.error({ err }, 'Failed to ensure PR:', err);
  }
  return null;
}

async function addAssigneesReviewers(config, pr) {
  if (config.assignees.length > 0) {
    try {
      const assignees = config.assignees.map(
        assignee =>
          assignee.length && assignee[0] === '@' ? assignee.slice(1) : assignee
      );
      await platform.addAssignees(pr.number, assignees);
      logger.info({ assignees: config.assignees }, 'Added assignees');
    } catch (err) {
      logger.info(
        { assignees: config.assignees, err },
        'Failed to add assignees'
      );
    }
  }
  if (config.reviewers.length > 0) {
    try {
      const reviewers = config.reviewers.map(
        reviewer =>
          reviewer.length && reviewer[0] === '@' ? reviewer.slice(1) : reviewer
      );
      await platform.addReviewers(pr.number, reviewers);
      logger.info({ reviewers: config.reviewers }, 'Added reviewers');
    } catch (err) {
      logger.info(
        { assignees: config.assignees, err },
        'Failed to add reviewers'
      );
    }
  }
}

async function checkAutoMerge(pr, config) {
  logger.trace({ config }, 'checkAutoMerge');
  logger.debug(`Checking #${pr.number} for automerge`);
  if (config.automerge) {
    logger.info('PR is configured for automerge');
    // Return if PR not ready for automerge
    if (pr.isUnmergeable) {
      logger.info('PR is not mergeable');
      logger.debug({ pr });
      return false;
    }
    if (config.requiredStatusChecks && pr.canMerge !== true) {
      logger.info('PR is not ready for merge');
      return false;
    }
    // Check branch status
    const branchStatus = await platform.getBranchStatus(
      pr.branchName,
      config.requiredStatusChecks
    );
    logger.debug(`branchStatus=${branchStatus}`);
    if (branchStatus !== 'success') {
      logger.info('Branch status is not "success"');
      return false;
    }
    // Check if it's been touched
    if (!pr.canRebase) {
      logger.info('PR is ready for automerge but has been modified');
      return false;
    }
    // Let's merge this
    if (config.automergeType === 'pr') {
      logger.info(`Automerging #${pr.number}`);
      return platform.mergePr(pr.number, config.branchName);
    }
    logger.info(`Applying automerge comment: ${config.automergeComment}`);
    return platform.ensureComment(pr.number, null, config.automergeComment);
  }
  logger.debug('No automerge');
  return false;
}
<commit_msg>fix: delete branch if PR fails with 502 error<commit_after>const handlebars = require('handlebars');
const changelogHelper = require('./changelog');
const showdown = require('showdown');

const converter = new showdown.Converter();
converter.setFlavor('github');

module.exports = {
  ensurePr,
  checkAutoMerge,
};

// Ensures that PR exists with matching title/body
async function ensurePr(prConfig) {
  const config = { ...prConfig };

  logger.trace({ config }, 'ensurePr');
  // If there is a group, it will use the config of the first upgrade in the array
  const { branchName, prTitle, upgrades } = config;
  // Check if existing PR exists
  const existingPr = await platform.getBranchPr(branchName);
  if (existingPr) {
    logger.debug('Found existing PR');
  }
  config.upgrades = [];
  const branchStatus = await platform.getBranchStatus(
    branchName,
    config.requiredStatusChecks
  );

  if (config.lockFileErrors && config.lockFileErrors.length) {
    logger.debug('Forcing PR because of lock file errors');
    config.forcePr = true;
  }

  // Only create a PR if a branch automerge has failed
  if (
    config.automerge === true &&
    config.automergeType.startsWith('branch') &&
    !config.forcePr
  ) {
    logger.debug(
      `Branch is configured for branch automerge, branchStatus is: ${branchStatus}`
    );
    if (branchStatus === 'pending' || branchStatus === 'running') {
      logger.debug('Checking how long this branch has been pending');
      const lastCommitTime = await platform.getBranchLastCommitTime(branchName);
      const currentTime = new Date();
      const millisecondsPerHour = 1000 * 60 * 60;
      const elapsedHours = Math.round(
        (currentTime.getTime() - lastCommitTime.getTime()) / millisecondsPerHour
      );
      if (elapsedHours >= config.prNotPendingHours) {
        logger.info('Branch exceeds prNotPending hours - forcing PR creation');
        config.forcePr = true;
      }
    }
    if (config.forcePr || branchStatus === 'failure') {
      logger.debug(`Branch tests failed, so will create PR`);
    } else {
      return null;
    }
  }
  if (config.prCreation === 'status-success') {
    logger.debug('Checking branch combined status');
    if (branchStatus !== 'success') {
      logger.debug(`Branch status is "${branchStatus}" - not creating PR`);
      return null;
    }
    logger.debug('Branch status success');
  } else if (
    config.prCreation === 'not-pending' &&
    !existingPr &&
    !config.forcePr
  ) {
    logger.debug('Checking branch combined status');
    if (branchStatus === 'pending' || branchStatus === 'running') {
      logger.debug(`Branch status is "${branchStatus}" - checking timeout`);
      const lastCommitTime = await platform.getBranchLastCommitTime(branchName);
      const currentTime = new Date();
      const millisecondsPerHour = 1000 * 60 * 60;
      const elapsedHours = Math.round(
        (currentTime.getTime() - lastCommitTime.getTime()) / millisecondsPerHour
      );
      if (elapsedHours < config.prNotPendingHours) {
        logger.debug(
          `Branch is ${elapsedHours} hours old - skipping PR creation`
        );
        return null;
      }
      logger.debug(
        `prNotPendingHours=${
          config.prNotPendingHours
        } threshold hit - creating PR`
      );
    }
    logger.debug('Branch status success');
  }

  const processedUpgrades = [];

  const issueRe = /([\s(])#(\d+)([)\s]?)/g;

  const commitRepos = [];

  let token;
  let endpoint;
  // istanbul ignore if
  if (process.env.GITHUB_ENDPOINT) {
    logger.debug('Removing GHE token before calling changelog');
    endpoint = process.env.GITHUB_ENDPOINT;
    delete process.env.GITHUB_ENDPOINT;
    token = process.env.GITHUB_TOKEN;
    process.env.GITHUB_TOKEN = process.env.GITHUB_COM_TOKEN;
  }
  // Get changelog and then generate template strings
  for (const upgrade of upgrades) {
    const upgradeKey = `${upgrade.depName}-${upgrade.manager}-${
      upgrade.changeLogFromVersion
    }-${upgrade.changeLogToVersion}`;
    if (processedUpgrades.indexOf(upgradeKey) !== -1) {
      continue; // eslint-disable-line no-continue
    }
    processedUpgrades.push(upgradeKey);

    const logJSON = await changelogHelper.getChangeLogJSON({
      manager: upgrade.manager,
      depType: upgrade.depType,
      depName: upgrade.depName,
      fromVersion: upgrade.changeLogFromVersion,
      newVersion: upgrade.changeLogToVersion,
    });

    if (logJSON) {
      upgrade.githubName = logJSON.project.github;
      upgrade.hasReleaseNotes = logJSON.hasReleaseNotes;
      upgrade.releases = [];
      if (!commitRepos.includes(upgrade.githubName)) {
        commitRepos.push(upgrade.githubName);
        logJSON.versions.forEach(version => {
          const release = { ...version };
          // TODO: remove once hasCommits is deprecated
          release.commits = [];
          release.hasCommits = false;
          upgrade.hasCommits = upgrade.hasCommits || release.hasCommits;
          upgrade.releases.push(release);
        });
      }
    }
    config.upgrades.push(upgrade);
  }
  // istanbul ignore if
  if (endpoint) {
    logger.debug('Restoring GHE token and endpoint');
    process.env.GITHUB_TOKEN = token;
    process.env.GITHUB_ENDPOINT = endpoint;
  }

  // Update the config object
  Object.assign(config, upgrades[0]);
  if (config.errors && config.errors.length) {
    config.hasErrors = true;
  }
  if (config.warnings && config.warnings.length) {
    config.hasWarnings = true;
  }
  config.hasReleaseNotes = config.upgrades.some(upg => upg.hasReleaseNotes);
  config.hasCommits = config.upgrades.some(upg => upg.hasCommits);

  const releaseNoteRepos = [];
  for (const upgrade of config.upgrades) {
    if (releaseNoteRepos.includes(upgrade.repositoryUrl)) {
      logger.debug(
        { depName: upgrade.depName },
        'Removing duplicate release notes'
      );
      upgrade.hasReleaseNotes = false;
    } else {
      releaseNoteRepos.push(upgrade.repositoryUrl);
    }
  }

  let prBody = handlebars.compile(config.prBody)(config);
  // istanbul ignore if
  if (config.global) {
    if (config.global.prBanner) {
      prBody = config.global.prBanner + '\n\n' + prBody;
    }
    if (config.global.prFooter) {
      prBody = prBody + '\n---\n\n' + config.global.prFooter;
    }
  }
  prBody = prBody.trim();
  if (config.isGitHub && !config.privateRepo) {
    // Put a zero width space after every # followed by a digit
    prBody = prBody.replace(/#(\d)/gi, '#$1');
    // Put a zero width space after every @ symbol to prevent unintended hyperlinking
    prBody = prBody.replace(/@/g, '@');
    prBody = prBody.replace(/(`\[?@)/g, '$1');
    // Public GitHub repos need links prevented - see #489
    prBody = prBody.replace(issueRe, '$1#$2$3');
    prBody = prBody.replace(
      /(https?:\/\/github.com\/[^/]*\/[^/]*\/(issues|pull)\/\w+)/g,
      '`$1`'
    );
    logger.trace('Escaping links to GitHub users');
    prBody = prBody.replace(
      /]\(https?:\/\/github.com\/[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}\)/gi,
      ']'
    );
    // convert escaped backticks back to `
    const backTickRe = /`([^/]*?)`/g;
    prBody = prBody.replace(backTickRe, '`$1`');
    prBody = prBody.replace(/`#(\d+)`/g, '`#$1`');
  }
  // It would be nice to abstract this to the platform layer but made difficult due to our create/update check
  if (config.isGitLab) {
    // Convert to HTML using GitHub-flavoured markdown as it is more feature-rich than GitLab's flavour
    prBody = converter
      .makeHtml(prBody)
      .replace(/<\/?h4[^>]*>/g, '**') // See #954
      .replace(/Pull Request/g, 'Merge Request')
      .replace(/PR/g, 'MR')
      .replace(//g, '
')
      .replace(/<\/summary><\/p>/g, '
')
      .replace(/

\n/g, '')
      .replace(/
<\/details><\/p>\n/g, '');
  } else if (config.isVsts) {
    // Remove any HTML we use
    prBody = prBody
      .replace('', '**')
      .replace('', '**')
      .replace('', '')
      .replace('', '');
  }

  try {
    if (existingPr) {
      logger.debug('Processing existing PR');
      if (config.automerge && branchStatus === 'failure') {
        logger.debug(`Setting assignees and reviewers as status checks failed`);
        await addAssigneesReviewers(config, existingPr);
      }
      // Check if existing PR needs updating
      if (existingPr.title === prTitle && existingPr.body === prBody) {
        logger.info(`${existingPr.displayNumber} does not need updating`);
        return existingPr;
      }
      // PR must need updating
      if (existingPr.title !== prTitle) {
        logger.info(
          {
            branchName,
            oldPrTitle: existingPr.title,
            newPrTitle: prTitle,
          },
          'PR title changed'
        );
      } else {
        logger.debug(
          {
            prTitle,
            oldPrBody: existingPr.body,
            newPrBody: prBody,
          },
          'PR body changed'
        );
      }

      await platform.updatePr(existingPr.number, prTitle, prBody);
      logger.info({ pr: existingPr.displayNumber }, `Updated PR`);
      return existingPr;
    }
    logger.info({ branchName, prTitle }, `Creating PR`);
    let pr;
    try {
      pr = await platform.createPr(
        branchName,
        prTitle,
        prBody,
        config.labels,
        false,
        config.statusCheckVerify
      );
    } catch (err) {
      logger.warn(
        {
          err,
          message: err.message,
          body: err.response ? err.response.body : undefined,
        },
        `Failed to create PR`
      );
      if (err.message === 'Validation Failed (422)') {
        logger.info({ branchName }, 'Deleting invalid branch');
        await platform.deleteBranch(branchName);
      }
      // istanbul ignore if
      if (err.statusCode === 502) {
        logger.info({ branchName }, 'Deleting branch due to server error');
        await platform.deleteBranch(branchName);
      }
      return null;
    }
    // Skip assign and review if automerging PR
    if (config.automerge && branchStatus !== 'failure') {
      logger.debug(
        `Skipping assignees and reviewers as automerge=${config.automerge}`
      );
    } else {
      await addAssigneesReviewers(config, pr);
    }
    logger.info(`Created ${pr.displayNumber}`);
    return pr;
  } catch (err) {
    // istanbul ignore if
    if (err.message === 'rate-limit-exceeded') {
      logger.debug('Passing rate-limit-exceeded error up');
      throw err;
    }
    logger.error({ err }, 'Failed to ensure PR:', err);
  }
  return null;
}

async function addAssigneesReviewers(config, pr) {
  if (config.assignees.length > 0) {
    try {
      const assignees = config.assignees.map(
        assignee =>
          assignee.length && assignee[0] === '@' ? assignee.slice(1) : assignee
      );
      await platform.addAssignees(pr.number, assignees);
      logger.info({ assignees: config.assignees }, 'Added assignees');
    } catch (err) {
      logger.info(
        { assignees: config.assignees, err },
        'Failed to add assignees'
      );
    }
  }
  if (config.reviewers.length > 0) {
    try {
      const reviewers = config.reviewers.map(
        reviewer =>
          reviewer.length && reviewer[0] === '@' ? reviewer.slice(1) : reviewer
      );
      await platform.addReviewers(pr.number, reviewers);
      logger.info({ reviewers: config.reviewers }, 'Added reviewers');
    } catch (err) {
      logger.info(
        { assignees: config.assignees, err },
        'Failed to add reviewers'
      );
    }
  }
}

async function checkAutoMerge(pr, config) {
  logger.trace({ config }, 'checkAutoMerge');
  logger.debug(`Checking #${pr.number} for automerge`);
  if (config.automerge) {
    logger.info('PR is configured for automerge');
    // Return if PR not ready for automerge
    if (pr.isUnmergeable) {
      logger.info('PR is not mergeable');
      logger.debug({ pr });
      return false;
    }
    if (config.requiredStatusChecks && pr.canMerge !== true) {
      logger.info('PR is not ready for merge');
      return false;
    }
    // Check branch status
    const branchStatus = await platform.getBranchStatus(
      pr.branchName,
      config.requiredStatusChecks
    );
    logger.debug(`branchStatus=${branchStatus}`);
    if (branchStatus !== 'success') {
      logger.info('Branch status is not "success"');
      return false;
    }
    // Check if it's been touched
    if (!pr.canRebase) {
      logger.info('PR is ready for automerge but has been modified');
      return false;
    }
    // Let's merge this
    if (config.automergeType === 'pr') {
      logger.info(`Automerging #${pr.number}`);
      return platform.mergePr(pr.number, config.branchName);
    }
    logger.info(`Applying automerge comment: ${config.automergeComment}`);
    return platform.ensureComment(pr.number, null, config.automergeComment);
  }
  logger.debug('No automerge');
  return false;
}
<|endoftext|>