<commit_before>/**
 * Worker to fetch MMR data for players
 **/
const utility = require('../util/utility');
const queue = require('../store/queue');
const db = require('../store/db');
const queries = require('../store/queries');
const redis = require('../store/redis');
const config = require('../config');
const mQueue = queue.getQueue('mmr');
const getData = utility.getData;
const retrieverArr = config.RETRIEVER_HOST.split(',');
mQueue.process(retrieverArr.length * config.MMR_PARALLELISM, processMmr);
mQueue.on('completed', (job) => {
  job.remove();
});

function processMmr(job, cb)
{
  const account_id = job.data.payload.account_id;
  getData(
    {
      url: retrieverArr.map((r) => {
        return 'http://' + r + '?key=' + config.RETRIEVER_SECRET + '&account_id=' + account_id;
      })[account_id % retrieverArr.length],
      noRetry: true,
    }, (err, data) => {
    if (err)
        {
      console.error(err);
      return cb(err);
    }
    if (data.solo_competitive_rank || data.competitive_rank)
        {
      data.account_id = job.data.payload.account_id;
      data.match_id = job.data.payload.match_id;
      data.time = new Date();
      if (data.solo_competitive_rank)
            {
        redis.zadd('solo_competitive_rank', data.solo_competitive_rank, data.account_id);
      }
      if (data.competitive_rank)
            {
        redis.zadd('competitive_rank', data.competitive_rank, data.account_id);
      }
      queries.insertPlayerRating(db, data, (err) => {
        if (err)
                {
          console.error(err);
        }
        return cb(err);
      });
    }
    else
        {
      cb();
    }
  });
}
<commit_msg>remove failed mmr jobs<commit_after>/**
 * Worker to fetch MMR data for players
 **/
const utility = require('../util/utility');
const queue = require('../store/queue');
const db = require('../store/db');
const queries = require('../store/queries');
const redis = require('../store/redis');
const config = require('../config');
const mQueue = queue.getQueue('mmr');
const getData = utility.getData;
const retrieverArr = config.RETRIEVER_HOST.split(',');
mQueue.process(retrieverArr.length * config.MMR_PARALLELISM, processMmr);
mQueue.on('completed', (job) => {
  job.remove();
});
mQueue.on('failed', (job) => {
  job.remove();
});

function processMmr(job, cb)
{
  const account_id = job.data.payload.account_id;
  getData(
    {
      url: retrieverArr.map((r) => {
        return 'http://' + r + '?key=' + config.RETRIEVER_SECRET + '&account_id=' + account_id;
      })[account_id % retrieverArr.length],
      noRetry: true,
    }, (err, data) => {
    if (err)
        {
      console.error(err);
      return cb(err);
    }
    if (data.solo_competitive_rank || data.competitive_rank)
        {
      data.account_id = job.data.payload.account_id;
      data.match_id = job.data.payload.match_id;
      data.time = new Date();
      if (data.solo_competitive_rank)
            {
        redis.zadd('solo_competitive_rank', data.solo_competitive_rank, data.account_id);
      }
      if (data.competitive_rank)
            {
        redis.zadd('competitive_rank', data.competitive_rank, data.account_id);
      }
      queries.insertPlayerRating(db, data, (err) => {
        if (err)
                {
          console.error(err);
        }
        return cb(err);
      });
    }
    else
        {
      cb();
    }
  });
}
<|endoftext|>


<commit_before>var Reaction = require("../reaction"),
    util = require("../util"),
    rules = require("../rules"),
    _ = require("underscore"),
    trim = util.trim,
    interpolatorRegex = /#\{([a-zA-Z0-9_\- ]+)(?:\?([a-zA-Z0-9_\- ]+))?(?:\:([a-zA-Z0-9_\- ]*))?}/g;

var AttributeReaction = Reaction.extend({

  init: function(next) {
    this.updateAttributes(this.attributes);
    next();
  },

  updateAttributes: function(attributes) {
    var that = this;
    _(attributes).each(function(value, key) {
      that.el.attr(key, value.replace(interpolatorRegex, function(match, key, valueIfTrue, valueIfFalse) {
        var value = that.get(key = trim(key));

        valueIfTrue = trim(valueIfTrue) || value;
        valueIfFalse = (typeof valueIfFalse == "undefined") ? "": trim(valueIfFalse);

        if(valueIfTrue === true) {
          valueIfTrue = key;
        }

        return value ? valueIfTrue : valueIfFalse;
      }));
    });
  },
  /**
   * TODO, ensure we never set blank src attributes
   **/
  observe: function() {
    var attrString = _.values(this.attributes),
        splitAttrString = attrString.join(" "),
        listenHash = " ";
        splitAttrString.replace(/(?:#{)([^}?]*)/g, function(p1, match){ listenHash = listenHash + " " + match; return ""})
    this.change(listenHash, function() {
      this.updateAttributes(this.attributes);
    }, this);
  }

}, {
  selector: "*",

  reactIf: function(el) {
    return _(el[0].attributes || []).any(function(attribute) {
      return attribute.value.match(/#\{/);
    }, this);
  },

  parse: function(el) {
    var attributes = {};

    _(el[0].attributes || []).each(function(attribute) {
      if(attribute.value.match(/#\{/)) {
        attributes[attribute.name] = attribute.value;
      }
    }, this);
    attributes.src = el.attr("data-src") || attributes.src;

    if(!attributes.src) {
      delete attributes.src;
    }
    return { attributes: attributes };
  }
});

module.exports = AttributeReaction;
<commit_msg>EndDash users can now fire either 'change' or 'change:name' on a model bound to a DOM attribute in order to force the DOM to update based on model changes<commit_after>var Reaction = require("../reaction"),
    util = require("../util"),
    rules = require("../rules"),
    _ = require("underscore"),
    trim = util.trim,
    interpolatorRegex = /#\{([a-zA-Z0-9_\- ]+)(?:\?([a-zA-Z0-9_\- ]+))?(?:\:([a-zA-Z0-9_\- ]*))?}/g;

var AttributeReaction = Reaction.extend({

  init: function(next) {
    this.updateAttributes(this.attributes);
    next();
  },

  updateAttributes: function(attributes) {
    var that = this;
    _(attributes).each(function(value, key) {
      that.el.attr(key, value.replace(interpolatorRegex, function(match, key, valueIfTrue, valueIfFalse) {
        var value = that.get(key = trim(key));

        valueIfTrue = trim(valueIfTrue) || value;
        valueIfFalse = (typeof valueIfFalse == "undefined") ? "": trim(valueIfFalse);

        if(valueIfTrue === true) {
          valueIfTrue = key;
        }

        return value ? valueIfTrue : valueIfFalse;
      }));
    });
  },
  /**
   * TODO, ensure we never set blank src attributes
   **/
  observe: function() {
    var attrString = _.values(this.attributes),
        splitAttrString = attrString.join(" "),
        listenHash = " ";
        splitAttrString.replace(/(?:#{)([^}?]*)/g, function(p1, match){ listenHash = listenHash + " " + match; return ""})
    this.change(listenHash, function() {
      this.updateAttributes(this.attributes);
    }, this);
    this.change(function() {
      this.updateAttributes(this.attributes);
    }, this);
  }
}, {
  selector: "*",

  reactIf: function(el) {
    return _(el[0].attributes || []).any(function(attribute) {
      return attribute.value.match(/#\{/);
    }, this);
  },

  parse: function(el) {
    var attributes = {};

    _(el[0].attributes || []).each(function(attribute) {
      if(attribute.value.match(/#\{/)) {
        attributes[attribute.name] = attribute.value;
      }
    }, this);
    attributes.src = el.attr("data-src") || attributes.src;

    if(!attributes.src) {
      delete attributes.src;
    }
    return { attributes: attributes };
  }
});

module.exports = AttributeReaction;
<|endoftext|>


<commit_before>'use strict'

const ipcRenderer = require('electron').ipcRenderer
const CallbacksRegistry = require('electron').CallbacksRegistry
const v8Util = process.atomBinding('v8_util')
const IDWeakMap = process.atomBinding('id_weak_map').IDWeakMap

const callbacksRegistry = new CallbacksRegistry()

var includes = [].includes

var remoteObjectCache = new IDWeakMap()

// Check for circular reference.
var isCircular = function (field, visited) {
  if (typeof field === 'object') {
    if (includes.call(visited, field)) {
      return true
    }
    visited.push(field)
  }
  return false
}

// Convert the arguments object into an array of meta data.
var wrapArgs = function (args, visited) {
  var valueToMeta
  if (visited == null) {
    visited = []
  }
  valueToMeta = function (value) {
    var field, prop, ret
    if (Array.isArray(value)) {
      return {
        type: 'array',
        value: wrapArgs(value, visited)
      }
    } else if (Buffer.isBuffer(value)) {
      return {
        type: 'buffer',
        value: Array.prototype.slice.call(value, 0)
      }
    } else if (value instanceof Date) {
      return {
        type: 'date',
        value: value.getTime()
      }
    } else if ((value != null ? value.constructor.name : void 0) === 'Promise') {
      return {
        type: 'promise',
        then: valueToMeta(function (v) { value.then(v) })
      }
    } else if ((value != null) && typeof value === 'object' && v8Util.getHiddenValue(value, 'atomId')) {
      return {
        type: 'remote-object',
        id: v8Util.getHiddenValue(value, 'atomId')
      }
    } else if ((value != null) && typeof value === 'object') {
      ret = {
        type: 'object',
        name: value.constructor.name,
        members: []
      }
      for (prop in value) {
        field = value[prop]
        ret.members.push({
          name: prop,
          value: valueToMeta(isCircular(field, visited) ? null : field)
        })
      }
      return ret
    } else if (typeof value === 'function' && v8Util.getHiddenValue(value, 'returnValue')) {
      return {
        type: 'function-with-return-value',
        value: valueToMeta(value())
      }
    } else if (typeof value === 'function') {
      return {
        type: 'function',
        id: callbacksRegistry.add(value),
        location: v8Util.getHiddenValue(value, 'location')
      }
    } else {
      return {
        type: 'value',
        value: value
      }
    }
  }
  return Array.prototype.slice.call(args).map(valueToMeta)
}

// Populate object's members from descriptors.
// This matches |getObjectMemebers| in rpc-server.
let setObjectMembers = function (object, metaId, members) {
  for (let member of members) {
    if (object.hasOwnProperty(member.name)) continue

    let descriptor = { enumerable: member.enumerable }
    if (member.type === 'method') {
      let remoteMemberFunction = function () {
        if (this && this.constructor === remoteMemberFunction) {
          // Constructor call.
          let ret = ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_CONSTRUCTOR', metaId, member.name, wrapArgs(arguments))
          return metaToValue(ret)
        } else {
          // Call member function.
          let ret = ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_CALL', metaId, member.name, wrapArgs(arguments))
          return metaToValue(ret)
        }
      }
      descriptor.writable = true
      descriptor.configurable = true
      descriptor.value = remoteMemberFunction
    } else if (member.type === 'get') {
      descriptor.get = function () {
        return metaToValue(ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_GET', metaId, member.name))
      }

      // Only set setter when it is writable.
      if (member.writable) {
        descriptor.set = function (value) {
          ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_SET', metaId, member.name, value)
          return value
        }
      }
    }

    Object.defineProperty(object, member.name, descriptor)
  }
}

// Populate object's prototype from descriptor.
// This matches |getObjectPrototype| in rpc-server.
let setObjectPrototype = function (object, metaId, descriptor) {
  if (descriptor === null) return
  let proto = {}
  setObjectMembers(proto, metaId, descriptor.members)
  setObjectPrototype(proto, metaId, descriptor.proto)
  Object.setPrototypeOf(object, proto)
}

// Convert meta data from browser into real value.
let metaToValue = function (meta) {
  var el, i, len, ref1, results, ret
  switch (meta.type) {
    case 'value':
      return meta.value
    case 'array':
      ref1 = meta.members
      results = []
      for (i = 0, len = ref1.length; i < len; i++) {
        el = ref1[i]
        results.push(metaToValue(el))
      }
      return results
    case 'buffer':
      return new Buffer(meta.value)
    case 'promise':
      return Promise.resolve({
        then: metaToValue(meta.then)
      })
    case 'error':
      return metaToPlainObject(meta)
    case 'date':
      return new Date(meta.value)
    case 'exception':
      throw new Error(meta.message + '\n' + meta.stack)
    default:
      if (remoteObjectCache.has(meta.id)) return remoteObjectCache.get(meta.id)

      if (meta.type === 'function') {
        // A shadow class to represent the remote function object.
        let remoteFunction = function () {
          if (this && this.constructor === remoteFunction) {
            // Constructor call.
            let obj = ipcRenderer.sendSync('ATOM_BROWSER_CONSTRUCTOR', meta.id, wrapArgs(arguments))
            // Returning object in constructor will replace constructed object
            // with the returned object.
            // http://stackoverflow.com/questions/1978049/what-values-can-a-constructor-return-to-avoid-returning-this
            return metaToValue(obj)
          } else {
            // Function call.
            let obj = ipcRenderer.sendSync('ATOM_BROWSER_FUNCTION_CALL', meta.id, wrapArgs(arguments))
            return metaToValue(obj)
          }
        }
        ret = remoteFunction
      } else {
        ret = {}
      }

      // Populate delegate members.
      setObjectMembers(ret, meta.id, meta.members)
      // Populate delegate prototype.
      setObjectPrototype(ret, meta.id, meta.proto)

      // Set constructor.name to object's name.
      Object.defineProperty(ret.constructor, 'name', { value: meta.name })

      // Track delegate object's life time, and tell the browser to clean up
      // when the object is GCed.
      v8Util.setDestructor(ret, function () {
        ipcRenderer.send('ATOM_BROWSER_DEREFERENCE', meta.id)
      })

      // Remember object's id.
      v8Util.setHiddenValue(ret, 'atomId', meta.id)
      remoteObjectCache.set(meta.id, ret)
      return ret
  }
}

// Construct a plain object from the meta.
var metaToPlainObject = function (meta) {
  var i, len, obj, ref1
  obj = (function () {
    switch (meta.type) {
      case 'error':
        return new Error()
      default:
        return {}
    }
  })()
  ref1 = meta.members
  for (i = 0, len = ref1.length; i < len; i++) {
    let {name, value} = ref1[i]
    obj[name] = value
  }
  return obj
}

// Browser calls a callback in renderer.
ipcRenderer.on('ATOM_RENDERER_CALLBACK', function (event, id, args) {
  return callbacksRegistry.apply(id, metaToValue(args))
})

// A callback in browser is released.
ipcRenderer.on('ATOM_RENDERER_RELEASE_CALLBACK', function (event, id) {
  return callbacksRegistry.remove(id)
})

// List all built-in modules in browser process.
const browserModules = require('../../browser/api/exports/electron')

// And add a helper receiver for each one.
var fn = function (name) {
  return Object.defineProperty(exports, name, {
    get: function () {
      return exports.getBuiltin(name)
    }
  })
}
for (var name in browserModules) {
  fn(name)
}

// Get remote module.
exports.require = function (module) {
  return metaToValue(ipcRenderer.sendSync('ATOM_BROWSER_REQUIRE', module))
}

// Alias to remote.require('electron').xxx.
exports.getBuiltin = function (module) {
  return metaToValue(ipcRenderer.sendSync('ATOM_BROWSER_GET_BUILTIN', module))
}

// Get current BrowserWindow.
exports.getCurrentWindow = function () {
  return metaToValue(ipcRenderer.sendSync('ATOM_BROWSER_CURRENT_WINDOW'))
}

// Get current WebContents object.
exports.getCurrentWebContents = function () {
  return metaToValue(ipcRenderer.sendSync('ATOM_BROWSER_CURRENT_WEB_CONTENTS'))
}

// Get a global object in browser.
exports.getGlobal = function (name) {
  return metaToValue(ipcRenderer.sendSync('ATOM_BROWSER_GLOBAL', name))
}

// Get the process object in browser.
exports.__defineGetter__('process', function () {
  return exports.getGlobal('process')
})

// Create a funtion that will return the specifed value when called in browser.
exports.createFunctionWithReturnValue = function (returnValue) {
  var func
  func = function () {
    return returnValue
  }
  v8Util.setHiddenValue(func, 'returnValue', true)
  return func
}

// Get the guest WebContents from guestInstanceId.
exports.getGuestWebContents = function (guestInstanceId) {
  var meta
  meta = ipcRenderer.sendSync('ATOM_BROWSER_GUEST_WEB_CONTENTS', guestInstanceId)
  return metaToValue(meta)
}
<commit_msg>Remote object's members should reference itself<commit_after>'use strict'

const ipcRenderer = require('electron').ipcRenderer
const CallbacksRegistry = require('electron').CallbacksRegistry
const v8Util = process.atomBinding('v8_util')
const IDWeakMap = process.atomBinding('id_weak_map').IDWeakMap

const callbacksRegistry = new CallbacksRegistry()

var includes = [].includes

var remoteObjectCache = new IDWeakMap()

// Check for circular reference.
var isCircular = function (field, visited) {
  if (typeof field === 'object') {
    if (includes.call(visited, field)) {
      return true
    }
    visited.push(field)
  }
  return false
}

// Convert the arguments object into an array of meta data.
var wrapArgs = function (args, visited) {
  var valueToMeta
  if (visited == null) {
    visited = []
  }
  valueToMeta = function (value) {
    var field, prop, ret
    if (Array.isArray(value)) {
      return {
        type: 'array',
        value: wrapArgs(value, visited)
      }
    } else if (Buffer.isBuffer(value)) {
      return {
        type: 'buffer',
        value: Array.prototype.slice.call(value, 0)
      }
    } else if (value instanceof Date) {
      return {
        type: 'date',
        value: value.getTime()
      }
    } else if ((value != null ? value.constructor.name : void 0) === 'Promise') {
      return {
        type: 'promise',
        then: valueToMeta(function (v) { value.then(v) })
      }
    } else if ((value != null) && typeof value === 'object' && v8Util.getHiddenValue(value, 'atomId')) {
      return {
        type: 'remote-object',
        id: v8Util.getHiddenValue(value, 'atomId')
      }
    } else if ((value != null) && typeof value === 'object') {
      ret = {
        type: 'object',
        name: value.constructor.name,
        members: []
      }
      for (prop in value) {
        field = value[prop]
        ret.members.push({
          name: prop,
          value: valueToMeta(isCircular(field, visited) ? null : field)
        })
      }
      return ret
    } else if (typeof value === 'function' && v8Util.getHiddenValue(value, 'returnValue')) {
      return {
        type: 'function-with-return-value',
        value: valueToMeta(value())
      }
    } else if (typeof value === 'function') {
      return {
        type: 'function',
        id: callbacksRegistry.add(value),
        location: v8Util.getHiddenValue(value, 'location')
      }
    } else {
      return {
        type: 'value',
        value: value
      }
    }
  }
  return Array.prototype.slice.call(args).map(valueToMeta)
}

// Populate object's members from descriptors.
// This matches |getObjectMemebers| in rpc-server.
let setObjectMembers = function (object, metaId, members) {
  for (let member of members) {
    if (object.hasOwnProperty(member.name)) continue

    let descriptor = { enumerable: member.enumerable }
    if (member.type === 'method') {
      let remoteMemberFunction = function () {
        if (this && this.constructor === remoteMemberFunction) {
          // Constructor call.
          let ret = ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_CONSTRUCTOR', metaId, member.name, wrapArgs(arguments))
          return metaToValue(ret)
        } else {
          // Call member function.
          let ret = ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_CALL', metaId, member.name, wrapArgs(arguments))
          return metaToValue(ret)
        }
      }
      descriptor.get = function () {
        remoteMemberFunction.ref = object  // The member should reference its object.
        return remoteMemberFunction
      }
      // Enable monkey-patch the method
      descriptor.set = function (value) {
        remoteMemberFunction = value
        return value
      }
      descriptor.configurable = true
    } else if (member.type === 'get') {
      descriptor.get = function () {
        return metaToValue(ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_GET', metaId, member.name))
      }

      // Only set setter when it is writable.
      if (member.writable) {
        descriptor.set = function (value) {
          ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_SET', metaId, member.name, value)
          return value
        }
      }
    }

    Object.defineProperty(object, member.name, descriptor)
  }
}

// Populate object's prototype from descriptor.
// This matches |getObjectPrototype| in rpc-server.
let setObjectPrototype = function (object, metaId, descriptor) {
  if (descriptor === null) return
  let proto = {}
  setObjectMembers(proto, metaId, descriptor.members)
  setObjectPrototype(proto, metaId, descriptor.proto)
  Object.setPrototypeOf(object, proto)
}

// Convert meta data from browser into real value.
let metaToValue = function (meta) {
  var el, i, len, ref1, results, ret
  switch (meta.type) {
    case 'value':
      return meta.value
    case 'array':
      ref1 = meta.members
      results = []
      for (i = 0, len = ref1.length; i < len; i++) {
        el = ref1[i]
        results.push(metaToValue(el))
      }
      return results
    case 'buffer':
      return new Buffer(meta.value)
    case 'promise':
      return Promise.resolve({
        then: metaToValue(meta.then)
      })
    case 'error':
      return metaToPlainObject(meta)
    case 'date':
      return new Date(meta.value)
    case 'exception':
      throw new Error(meta.message + '\n' + meta.stack)
    default:
      if (remoteObjectCache.has(meta.id)) return remoteObjectCache.get(meta.id)

      if (meta.type === 'function') {
        // A shadow class to represent the remote function object.
        let remoteFunction = function () {
          if (this && this.constructor === remoteFunction) {
            // Constructor call.
            let obj = ipcRenderer.sendSync('ATOM_BROWSER_CONSTRUCTOR', meta.id, wrapArgs(arguments))
            // Returning object in constructor will replace constructed object
            // with the returned object.
            // http://stackoverflow.com/questions/1978049/what-values-can-a-constructor-return-to-avoid-returning-this
            return metaToValue(obj)
          } else {
            // Function call.
            let obj = ipcRenderer.sendSync('ATOM_BROWSER_FUNCTION_CALL', meta.id, wrapArgs(arguments))
            return metaToValue(obj)
          }
        }
        ret = remoteFunction
      } else {
        ret = {}
      }

      // Populate delegate members.
      setObjectMembers(ret, meta.id, meta.members)
      // Populate delegate prototype.
      setObjectPrototype(ret, meta.id, meta.proto)

      // Set constructor.name to object's name.
      Object.defineProperty(ret.constructor, 'name', { value: meta.name })

      // Track delegate object's life time, and tell the browser to clean up
      // when the object is GCed.
      v8Util.setDestructor(ret, function () {
        ipcRenderer.send('ATOM_BROWSER_DEREFERENCE', meta.id)
      })

      // Remember object's id.
      v8Util.setHiddenValue(ret, 'atomId', meta.id)
      remoteObjectCache.set(meta.id, ret)
      return ret
  }
}

// Construct a plain object from the meta.
var metaToPlainObject = function (meta) {
  var i, len, obj, ref1
  obj = (function () {
    switch (meta.type) {
      case 'error':
        return new Error()
      default:
        return {}
    }
  })()
  ref1 = meta.members
  for (i = 0, len = ref1.length; i < len; i++) {
    let {name, value} = ref1[i]
    obj[name] = value
  }
  return obj
}

// Browser calls a callback in renderer.
ipcRenderer.on('ATOM_RENDERER_CALLBACK', function (event, id, args) {
  return callbacksRegistry.apply(id, metaToValue(args))
})

// A callback in browser is released.
ipcRenderer.on('ATOM_RENDERER_RELEASE_CALLBACK', function (event, id) {
  return callbacksRegistry.remove(id)
})

// List all built-in modules in browser process.
const browserModules = require('../../browser/api/exports/electron')

// And add a helper receiver for each one.
var fn = function (name) {
  return Object.defineProperty(exports, name, {
    get: function () {
      return exports.getBuiltin(name)
    }
  })
}
for (var name in browserModules) {
  fn(name)
}

// Get remote module.
exports.require = function (module) {
  return metaToValue(ipcRenderer.sendSync('ATOM_BROWSER_REQUIRE', module))
}

// Alias to remote.require('electron').xxx.
exports.getBuiltin = function (module) {
  return metaToValue(ipcRenderer.sendSync('ATOM_BROWSER_GET_BUILTIN', module))
}

// Get current BrowserWindow.
exports.getCurrentWindow = function () {
  return metaToValue(ipcRenderer.sendSync('ATOM_BROWSER_CURRENT_WINDOW'))
}

// Get current WebContents object.
exports.getCurrentWebContents = function () {
  return metaToValue(ipcRenderer.sendSync('ATOM_BROWSER_CURRENT_WEB_CONTENTS'))
}

// Get a global object in browser.
exports.getGlobal = function (name) {
  return metaToValue(ipcRenderer.sendSync('ATOM_BROWSER_GLOBAL', name))
}

// Get the process object in browser.
exports.__defineGetter__('process', function () {
  return exports.getGlobal('process')
})

// Create a funtion that will return the specifed value when called in browser.
exports.createFunctionWithReturnValue = function (returnValue) {
  var func
  func = function () {
    return returnValue
  }
  v8Util.setHiddenValue(func, 'returnValue', true)
  return func
}

// Get the guest WebContents from guestInstanceId.
exports.getGuestWebContents = function (guestInstanceId) {
  var meta
  meta = ipcRenderer.sendSync('ATOM_BROWSER_GUEST_WEB_CONTENTS', guestInstanceId)
  return metaToValue(meta)
}
<|endoftext|>


<commit_before>"use strict";

const Base = require("../structures/Base");
const DiscordHTTPError = require("../errors/DiscordHTTPError");
const DiscordRESTError = require("../errors/DiscordRESTError");
const Endpoints = require("./Endpoints");
const HTTPS = require("https");
const MultipartData = require("../util/MultipartData");
const SequentialBucket = require("../util/SequentialBucket");
const Zlib = require("zlib");

/**
* Handles API requests
*/
class RequestHandler {
    constructor(client, forceQueueing) {
        this._client = client;
        this.baseURL = Endpoints.BASE_URL;
        this.userAgent = `DiscordBot (https://github.com/abalabahaha/eris, ${require("../../package.json").version})`;
        this.ratelimits = {};
        this.requestTimeout = client.options.requestTimeout;
        this.agent = client.options.agent;
        this.latencyRef = {
            latency: 500,
            offset: client.options.ratelimiterOffset,
            raw: new Array(10).fill(500),
            timeOffset: 0,
            timeOffsets: new Array(10).fill(0),
            lastTimeOffsetCheck: 0
        };
        this.globalBlock = false;
        this.readyQueue = [];
        if(forceQueueing) {
            this.globalBlock = true;
            this._client.once("shardPreReady", () => this.globalUnblock());
        }
    }

    globalUnblock() {
        this.globalBlock = false;
        while(this.readyQueue.length > 0) {
            this.readyQueue.shift()();
        }
    }

    /**
    * Make an API request
    * @arg {String} method Uppercase HTTP method
    * @arg {String} url URL of the endpoint
    * @arg {Boolean} [auth] Whether to add the Authorization header and token or not
    * @arg {Object} [body] Request payload
    * @arg {Object} [file] File object
    * @arg {Buffer} file.file A buffer containing file data
    * @arg {String} file.name What to name the file
    * @returns {Promise<Object>} Resolves with the returned JSON data
    */
    request(method, url, auth, body, file, _route, short) {
        const route = _route || this.routefy(url, method);

        const _stackHolder = {}; // Preserve async stack
        Error.captureStackTrace(_stackHolder);

        return new Promise((resolve, reject) => {
            let attempts = 0;

            const actualCall = (cb) => {
                const headers = {
                    "User-Agent": this.userAgent,
                    "Accept-Encoding": "gzip,deflate",
                    "X-RateLimit-Precision": "millisecond"
                };
                let data;
                let finalURL = url;

                try {
                    if(auth) {
                        headers.Authorization = this._client.token;
                    }
                    if(body && body.reason) { // Audit log reason sniping
                        headers["X-Audit-Log-Reason"] = body.reason;
                        if((method !== "PUT" || !url.includes("/bans")) && (method !== "POST" || !url.includes("/prune"))) {
                            delete body.reason;
                        }
                    }
                    if(file) {
                        if(Array.isArray(file)) {
                            data = new MultipartData();
                            headers["Content-Type"] = "multipart/form-data; boundary=" + data.boundary;
                            file.forEach(function(f) {
                                if(!f.file) {
                                    return;
                                }
                                data.attach(f.name, f.file, f.name);
                            });
                            if(body) {
                                data.attach("payload_json", body);
                            }
                            data = data.finish();
                        } else if(file.file) {
                            data = new MultipartData();
                            headers["Content-Type"] = "multipart/form-data; boundary=" + data.boundary;
                            data.attach("file", file.file, file.name);
                            if(body) {
                                data.attach("payload_json", body);
                            }
                            data = data.finish();
                        } else {
                            throw new Error("Invalid file object");
                        }
                    } else if(body) {
                        if(method === "GET" || method === "DELETE") {
                            let qs = "";
                            Object.keys(body).forEach(function(key) {
                                if(body[key] != undefined) {
                                    if(Array.isArray(body[key])) {
                                        body[key].forEach(function(val) {
                                            qs += `&${encodeURIComponent(key)}=${encodeURIComponent(val)}`;
                                        });
                                    } else {
                                        qs += `&${encodeURIComponent(key)}=${encodeURIComponent(body[key])}`;
                                    }
                                }
                            });
                            finalURL += "?" + qs.substring(1);
                        } else {
                            data = JSON.stringify(body);
                            headers["Content-Type"] = "application/json";
                        }
                    }
                } catch(err) {
                    cb();
                    reject(err);
                    return;
                }

                const req = HTTPS.request({
                    method: method,
                    host: "discord.com",
                    path: this.baseURL + finalURL,
                    headers: headers,
                    agent: this.agent
                });

                let reqError;

                req.once("abort", () => {
                    cb();
                    reqError = reqError || new Error(`Request aborted by client on ${method} ${url}`);
                    reqError.req = req;
                    reject(reqError);
                }).once("error", (err) => {
                    reqError = err;
                    req.abort();
                });

                let latency = Date.now();

                req.once("response", (resp) => {
                    latency = Date.now() - latency;
                    this.latencyRef.raw.push(latency);
                    this.latencyRef.latency = this.latencyRef.latency - ~~(this.latencyRef.raw.shift() / 10) + ~~(latency / 10);

                    if(this._client.listeners("rawREST").length) {
                        /**
                         * Fired when the Client's RequestHandler receives a response
                         * @event Client#rawREST
                         * @prop {Object} [request] The data for the request.
                         * @prop {Boolean} request.auth True if the request required an authorization token
                         * @prop {Object} [request.body] The request payload
                         * @prop {Object} [request.file] The file object sent in the request
                         * @prop {Buffer} request.file.file A buffer containing file data
                         * @prop {String} request.file.name The name of the file
                         * @prop {Number} request.latency The HTTP response latency
                         * @prop {String} request.method Uppercase HTTP method
                         * @prop {IncomingMessage} request.resp The HTTP response to the request
                         * @prop {String} request.route The calculated ratelimiting route for the request
                         * @prop {Boolean} request.short Whether or not the request was prioritized in its ratelimiting queue
                         * @prop {String} request.url URL of the endpoint
                         */
                        this._client.emit("rawREST", {method, url, auth, body, file, route, short, resp, latency});
                    }

                    const headerNow = Date.parse(resp.headers["date"]);
                    if(this.latencyRef.lastTimeOffsetCheck < Date.now() - 5000) {
                        const timeOffset = headerNow + 500 - (this.latencyRef.lastTimeOffsetCheck = Date.now());
                        if(this.latencyRef.timeOffset - this.latencyRef.latency >= this._client.options.latencyThreshold && timeOffset - this.latencyRef.latency >= this._client.options.latencyThreshold) {
                            this._client.emit("warn", new Error(`Your clock is ${this.latencyRef.timeOffset}ms behind Discord's server clock. Please check your connection and system time.`));
                        }
                        this.latencyRef.timeOffset = this.latencyRef.timeOffset - ~~(this.latencyRef.timeOffsets.shift() / 10) + ~~(timeOffset / 10);
                        this.latencyRef.timeOffsets.push(timeOffset);
                    }

                    resp.once("aborted", () => {
                        cb();
                        reqError = reqError || new Error(`Request aborted by server on ${method} ${url}`);
                        reqError.req = req;
                        reject(reqError);
                    });

                    let response = "";

                    let _respStream = resp;
                    if(resp.headers["content-encoding"]) {
                        if(resp.headers["content-encoding"].includes("gzip")) {
                            _respStream = resp.pipe(Zlib.createGunzip());
                        } else if(resp.headers["content-encoding"].includes("deflate")) {
                            _respStream = resp.pipe(Zlib.createInflate());
                        }
                    }

                    _respStream.on("data", (str) => {
                        response += str;
                    }).on("error", (err) => {
                        reqError = err;
                        req.abort();
                    }).once("end", () => {
                        const now = Date.now();

                        if(resp.headers["x-ratelimit-limit"]) {
                            this.ratelimits[route].limit = +resp.headers["x-ratelimit-limit"];
                        }

                        if(method !== "GET" && (resp.headers["x-ratelimit-remaining"] == undefined || resp.headers["x-ratelimit-limit"] == undefined) && this.ratelimits[route].limit !== 1) {
                            this._client.emit("debug", `Missing ratelimit headers for SequentialBucket(${this.ratelimits[route].remaining}/${this.ratelimits[route].limit}) with non-default limit\n`
                                + `${resp.statusCode} ${resp.headers["content-type"]}: ${method} ${route} | ${resp.headers["cf-ray"]}\n`
                                + "content-type = " +  + "\n"
                                + "x-ratelimit-remaining = " + resp.headers["x-ratelimit-remaining"] + "\n"
                                + "x-ratelimit-limit = " + resp.headers["x-ratelimit-limit"] + "\n"
                                + "x-ratelimit-reset = " + resp.headers["x-ratelimit-reset"] + "\n"
                                + "x-ratelimit-global = " + resp.headers["x-ratelimit-global"]);
                        }

                        this.ratelimits[route].remaining = resp.headers["x-ratelimit-remaining"] === undefined ? 1 : +resp.headers["x-ratelimit-remaining"] || 0;

                        let retryAfter = parseInt(resp.headers["retry-after"]);
                        // Discord breaks RFC here, using milliseconds instead of seconds (╯°□°）╯︵ ┻━┻
                        // This is the unofficial Discord dev-recommended way of detecting that
                        if(retryAfter && (typeof resp.headers["via"] !== "string" || !resp.headers["via"].includes("1.1 google"))) {
                            retryAfter *= 1000;
                            if(retryAfter >= 1000 * 1000) {
                                this._client.emit("warn", `Excessive Retry-After interval detected (Retry-After: ${resp.headers["retry-after"]} * 1000, Via: ${resp.headers["via"]})`);
                            }
                        }
                        if(retryAfter >= 0) {
                            if(resp.headers["x-ratelimit-global"]) {
                                this.globalBlock = true;
                                setTimeout(() => this.globalUnblock(), retryAfter || 1);
                            } else {
                                this.ratelimits[route].reset = (retryAfter || 1) + now;
                            }
                        } else if(resp.headers["x-ratelimit-reset"]) {
                            if((~route.lastIndexOf("/reactions/:id")) && (+resp.headers["x-ratelimit-reset"] * 1000 - headerNow) === 1000) {
                                this.ratelimits[route].reset = now + 250;
                            } else {
                                this.ratelimits[route].reset = Math.max(+resp.headers["x-ratelimit-reset"] * 1000 - this.latencyRef.timeOffset, now);
                            }
                        } else {
                            this.ratelimits[route].reset = now;
                        }

                        if(resp.statusCode !== 429) {
                            this._client.emit("debug", `${body && body.content} ${now} ${route} ${resp.statusCode}: ${latency}ms (${this.latencyRef.latency}ms avg) | ${this.ratelimits[route].remaining}/${this.ratelimits[route].limit} left | Reset ${this.ratelimits[route].reset} (${this.ratelimits[route].reset - now}ms left)`);
                        }

                        if(resp.statusCode >= 300) {
                            if(resp.statusCode === 429) {
                                this._client.emit("debug", `${resp.headers["x-ratelimit-global"] ? "Global" : "Unexpected"} 429 (╯°□°）╯︵ ┻━┻: ${response}\n${body && body.content} ${now} ${route} ${resp.statusCode}: ${latency}ms (${this.latencyRef.latency}ms avg) | ${this.ratelimits[route].remaining}/${this.ratelimits[route].limit} left | Reset ${this.ratelimits[route].reset} (${this.ratelimits[route].reset - now}ms left)`);
                                if(retryAfter) {
                                    setTimeout(() => {
                                        cb();
                                        this.request(method, url, auth, body, file, route, true).then(resolve).catch(reject);
                                    }, retryAfter);
                                    return;
                                } else {
                                    cb();
                                    this.request(method, url, auth, body, file, route, true).then(resolve).catch(reject);
                                    return;
                                }
                            } else if(resp.statusCode === 502 && ++attempts < 4) {
                                this._client.emit("debug", "A wild 502 appeared! Thanks CloudFlare!");
                                setTimeout(() => {
                                    this.request(method, url, auth, body, file, route, true).then(resolve).catch(reject);
                                }, Math.floor(Math.random() * 1900 + 100));
                                return cb();
                            }
                            cb();

                            if(response.length > 0) {
                                if(resp.headers["content-type"] === "application/json") {
                                    try {
                                        response = JSON.parse(response);
                                    } catch(err) {
                                        reject(err);
                                        return;
                                    }
                                }
                            }

                            let {stack} = _stackHolder;
                            if(stack.startsWith("Error\n")) {
                                stack = stack.substring(6);
                            }
                            let err;
                            if(response.code) {
                                err = new DiscordRESTError(req, resp, response, stack);
                            } else {
                                err = new DiscordHTTPError(req, resp, response, stack);
                            }
                            reject(err);
                            return;
                        }

                        if(response.length > 0) {
                            if(resp.headers["content-type"] === "application/json") {
                                try {
                                    response = JSON.parse(response);
                                } catch(err) {
                                    cb();
                                    reject(err);
                                    return;
                                }
                            }
                        }

                        cb();
                        resolve(response);
                    });
                });

                req.setTimeout(this.requestTimeout, () => {
                    reqError = new Error(`Request timed out (>${this.requestTimeout}ms) on ${method} ${url}`);
                    req.abort();
                });

                if(Array.isArray(data)) {
                    for(const chunk of data) {
                        req.write(chunk);
                    }
                    req.end();
                } else {
                    req.end(data);
                }
            };

            if(this.globalBlock && auth) {
                this.readyQueue.push(() => {
                    if(!this.ratelimits[route]) {
                        this.ratelimits[route] = new SequentialBucket(1, this.latencyRef);
                    }
                    this.ratelimits[route].queue(actualCall, short);
                });
            } else {
                if(!this.ratelimits[route]) {
                    this.ratelimits[route] = new SequentialBucket(1, this.latencyRef);
                }
                this.ratelimits[route].queue(actualCall, short);
            }
        });
    }

    routefy(url, method) {
        let route = url.replace(/\/([a-z-]+)\/(?:[0-9]{17,19})/g, function(match, p) {
            return p === "channels" || p === "guilds" || p === "webhooks" ? match : `/${p}/:id`;
        }).replace(/\/reactions\/[^/]+/g, "/reactions/:id").replace(/^\/webhooks\/(\d+)\/[A-Za-z0-9-_]{64,}/, "/webhooks/$1/:token");
        if(method === "DELETE" && route.endsWith("/messages/:id")) { // Delete Messsage endpoint has its own ratelimit
            route = method + route;
        }
        return route;
    }

    toString() {
        return "[RequestHandler]";
    }

    toJSON(props = []) {
        return Base.prototype.toJSON.call(this, [
            "baseURL",
            "userAgent",
            "ratelimits",
            "requestTimeout",
            "agent",
            "latencyRef",
            "globalBlock",
            "readyQueue",
            ...props
        ]);
    }
}

module.exports = RequestHandler;
<commit_msg>Filter undefined message content in debug event (#1076)<commit_after>"use strict";

const Base = require("../structures/Base");
const DiscordHTTPError = require("../errors/DiscordHTTPError");
const DiscordRESTError = require("../errors/DiscordRESTError");
const Endpoints = require("./Endpoints");
const HTTPS = require("https");
const MultipartData = require("../util/MultipartData");
const SequentialBucket = require("../util/SequentialBucket");
const Zlib = require("zlib");

/**
* Handles API requests
*/
class RequestHandler {
    constructor(client, forceQueueing) {
        this._client = client;
        this.baseURL = Endpoints.BASE_URL;
        this.userAgent = `DiscordBot (https://github.com/abalabahaha/eris, ${require("../../package.json").version})`;
        this.ratelimits = {};
        this.requestTimeout = client.options.requestTimeout;
        this.agent = client.options.agent;
        this.latencyRef = {
            latency: 500,
            offset: client.options.ratelimiterOffset,
            raw: new Array(10).fill(500),
            timeOffset: 0,
            timeOffsets: new Array(10).fill(0),
            lastTimeOffsetCheck: 0
        };
        this.globalBlock = false;
        this.readyQueue = [];
        if(forceQueueing) {
            this.globalBlock = true;
            this._client.once("shardPreReady", () => this.globalUnblock());
        }
    }

    globalUnblock() {
        this.globalBlock = false;
        while(this.readyQueue.length > 0) {
            this.readyQueue.shift()();
        }
    }

    /**
    * Make an API request
    * @arg {String} method Uppercase HTTP method
    * @arg {String} url URL of the endpoint
    * @arg {Boolean} [auth] Whether to add the Authorization header and token or not
    * @arg {Object} [body] Request payload
    * @arg {Object} [file] File object
    * @arg {Buffer} file.file A buffer containing file data
    * @arg {String} file.name What to name the file
    * @returns {Promise<Object>} Resolves with the returned JSON data
    */
    request(method, url, auth, body, file, _route, short) {
        const route = _route || this.routefy(url, method);

        const _stackHolder = {}; // Preserve async stack
        Error.captureStackTrace(_stackHolder);

        return new Promise((resolve, reject) => {
            let attempts = 0;

            const actualCall = (cb) => {
                const headers = {
                    "User-Agent": this.userAgent,
                    "Accept-Encoding": "gzip,deflate",
                    "X-RateLimit-Precision": "millisecond"
                };
                let data;
                let finalURL = url;

                try {
                    if(auth) {
                        headers.Authorization = this._client.token;
                    }
                    if(body && body.reason) { // Audit log reason sniping
                        headers["X-Audit-Log-Reason"] = body.reason;
                        if((method !== "PUT" || !url.includes("/bans")) && (method !== "POST" || !url.includes("/prune"))) {
                            delete body.reason;
                        }
                    }
                    if(file) {
                        if(Array.isArray(file)) {
                            data = new MultipartData();
                            headers["Content-Type"] = "multipart/form-data; boundary=" + data.boundary;
                            file.forEach(function(f) {
                                if(!f.file) {
                                    return;
                                }
                                data.attach(f.name, f.file, f.name);
                            });
                            if(body) {
                                data.attach("payload_json", body);
                            }
                            data = data.finish();
                        } else if(file.file) {
                            data = new MultipartData();
                            headers["Content-Type"] = "multipart/form-data; boundary=" + data.boundary;
                            data.attach("file", file.file, file.name);
                            if(body) {
                                data.attach("payload_json", body);
                            }
                            data = data.finish();
                        } else {
                            throw new Error("Invalid file object");
                        }
                    } else if(body) {
                        if(method === "GET" || method === "DELETE") {
                            let qs = "";
                            Object.keys(body).forEach(function(key) {
                                if(body[key] != undefined) {
                                    if(Array.isArray(body[key])) {
                                        body[key].forEach(function(val) {
                                            qs += `&${encodeURIComponent(key)}=${encodeURIComponent(val)}`;
                                        });
                                    } else {
                                        qs += `&${encodeURIComponent(key)}=${encodeURIComponent(body[key])}`;
                                    }
                                }
                            });
                            finalURL += "?" + qs.substring(1);
                        } else {
                            data = JSON.stringify(body);
                            headers["Content-Type"] = "application/json";
                        }
                    }
                } catch(err) {
                    cb();
                    reject(err);
                    return;
                }

                const req = HTTPS.request({
                    method: method,
                    host: "discord.com",
                    path: this.baseURL + finalURL,
                    headers: headers,
                    agent: this.agent
                });

                let reqError;

                req.once("abort", () => {
                    cb();
                    reqError = reqError || new Error(`Request aborted by client on ${method} ${url}`);
                    reqError.req = req;
                    reject(reqError);
                }).once("error", (err) => {
                    reqError = err;
                    req.abort();
                });

                let latency = Date.now();

                req.once("response", (resp) => {
                    latency = Date.now() - latency;
                    this.latencyRef.raw.push(latency);
                    this.latencyRef.latency = this.latencyRef.latency - ~~(this.latencyRef.raw.shift() / 10) + ~~(latency / 10);

                    if(this._client.listeners("rawREST").length) {
                        /**
                         * Fired when the Client's RequestHandler receives a response
                         * @event Client#rawREST
                         * @prop {Object} [request] The data for the request.
                         * @prop {Boolean} request.auth True if the request required an authorization token
                         * @prop {Object} [request.body] The request payload
                         * @prop {Object} [request.file] The file object sent in the request
                         * @prop {Buffer} request.file.file A buffer containing file data
                         * @prop {String} request.file.name The name of the file
                         * @prop {Number} request.latency The HTTP response latency
                         * @prop {String} request.method Uppercase HTTP method
                         * @prop {IncomingMessage} request.resp The HTTP response to the request
                         * @prop {String} request.route The calculated ratelimiting route for the request
                         * @prop {Boolean} request.short Whether or not the request was prioritized in its ratelimiting queue
                         * @prop {String} request.url URL of the endpoint
                         */
                        this._client.emit("rawREST", {method, url, auth, body, file, route, short, resp, latency});
                    }

                    const headerNow = Date.parse(resp.headers["date"]);
                    if(this.latencyRef.lastTimeOffsetCheck < Date.now() - 5000) {
                        const timeOffset = headerNow + 500 - (this.latencyRef.lastTimeOffsetCheck = Date.now());
                        if(this.latencyRef.timeOffset - this.latencyRef.latency >= this._client.options.latencyThreshold && timeOffset - this.latencyRef.latency >= this._client.options.latencyThreshold) {
                            this._client.emit("warn", new Error(`Your clock is ${this.latencyRef.timeOffset}ms behind Discord's server clock. Please check your connection and system time.`));
                        }
                        this.latencyRef.timeOffset = this.latencyRef.timeOffset - ~~(this.latencyRef.timeOffsets.shift() / 10) + ~~(timeOffset / 10);
                        this.latencyRef.timeOffsets.push(timeOffset);
                    }

                    resp.once("aborted", () => {
                        cb();
                        reqError = reqError || new Error(`Request aborted by server on ${method} ${url}`);
                        reqError.req = req;
                        reject(reqError);
                    });

                    let response = "";

                    let _respStream = resp;
                    if(resp.headers["content-encoding"]) {
                        if(resp.headers["content-encoding"].includes("gzip")) {
                            _respStream = resp.pipe(Zlib.createGunzip());
                        } else if(resp.headers["content-encoding"].includes("deflate")) {
                            _respStream = resp.pipe(Zlib.createInflate());
                        }
                    }

                    _respStream.on("data", (str) => {
                        response += str;
                    }).on("error", (err) => {
                        reqError = err;
                        req.abort();
                    }).once("end", () => {
                        const now = Date.now();

                        if(resp.headers["x-ratelimit-limit"]) {
                            this.ratelimits[route].limit = +resp.headers["x-ratelimit-limit"];
                        }

                        if(method !== "GET" && (resp.headers["x-ratelimit-remaining"] == undefined || resp.headers["x-ratelimit-limit"] == undefined) && this.ratelimits[route].limit !== 1) {
                            this._client.emit("debug", `Missing ratelimit headers for SequentialBucket(${this.ratelimits[route].remaining}/${this.ratelimits[route].limit}) with non-default limit\n`
                                + `${resp.statusCode} ${resp.headers["content-type"]}: ${method} ${route} | ${resp.headers["cf-ray"]}\n`
                                + "content-type = " +  + "\n"
                                + "x-ratelimit-remaining = " + resp.headers["x-ratelimit-remaining"] + "\n"
                                + "x-ratelimit-limit = " + resp.headers["x-ratelimit-limit"] + "\n"
                                + "x-ratelimit-reset = " + resp.headers["x-ratelimit-reset"] + "\n"
                                + "x-ratelimit-global = " + resp.headers["x-ratelimit-global"]);
                        }

                        this.ratelimits[route].remaining = resp.headers["x-ratelimit-remaining"] === undefined ? 1 : +resp.headers["x-ratelimit-remaining"] || 0;

                        let retryAfter = parseInt(resp.headers["retry-after"]);
                        // Discord breaks RFC here, using milliseconds instead of seconds (╯°□°）╯︵ ┻━┻
                        // This is the unofficial Discord dev-recommended way of detecting that
                        if(retryAfter && (typeof resp.headers["via"] !== "string" || !resp.headers["via"].includes("1.1 google"))) {
                            retryAfter *= 1000;
                            if(retryAfter >= 1000 * 1000) {
                                this._client.emit("warn", `Excessive Retry-After interval detected (Retry-After: ${resp.headers["retry-after"]} * 1000, Via: ${resp.headers["via"]})`);
                            }
                        }
                        if(retryAfter >= 0) {
                            if(resp.headers["x-ratelimit-global"]) {
                                this.globalBlock = true;
                                setTimeout(() => this.globalUnblock(), retryAfter || 1);
                            } else {
                                this.ratelimits[route].reset = (retryAfter || 1) + now;
                            }
                        } else if(resp.headers["x-ratelimit-reset"]) {
                            if((~route.lastIndexOf("/reactions/:id")) && (+resp.headers["x-ratelimit-reset"] * 1000 - headerNow) === 1000) {
                                this.ratelimits[route].reset = now + 250;
                            } else {
                                this.ratelimits[route].reset = Math.max(+resp.headers["x-ratelimit-reset"] * 1000 - this.latencyRef.timeOffset, now);
                            }
                        } else {
                            this.ratelimits[route].reset = now;
                        }

                        if(resp.statusCode !== 429) {
                            const content = typeof body === "object" ? `${body.content} ` : "";
                            this._client.emit("debug", `${content}${now} ${route} ${resp.statusCode}: ${latency}ms (${this.latencyRef.latency}ms avg) | ${this.ratelimits[route].remaining}/${this.ratelimits[route].limit} left | Reset ${this.ratelimits[route].reset} (${this.ratelimits[route].reset - now}ms left)`);
                        }

                        if(resp.statusCode >= 300) {
                            if(resp.statusCode === 429) {
                                const content = typeof body === "object" ? `${body.content} ` : "";
                                this._client.emit("debug", `${resp.headers["x-ratelimit-global"] ? "Global" : "Unexpected"} 429 (╯°□°）╯︵ ┻━┻: ${response}\n${content} ${now} ${route} ${resp.statusCode}: ${latency}ms (${this.latencyRef.latency}ms avg) | ${this.ratelimits[route].remaining}/${this.ratelimits[route].limit} left | Reset ${this.ratelimits[route].reset} (${this.ratelimits[route].reset - now}ms left)`);
                                if(retryAfter) {
                                    setTimeout(() => {
                                        cb();
                                        this.request(method, url, auth, body, file, route, true).then(resolve).catch(reject);
                                    }, retryAfter);
                                    return;
                                } else {
                                    cb();
                                    this.request(method, url, auth, body, file, route, true).then(resolve).catch(reject);
                                    return;
                                }
                            } else if(resp.statusCode === 502 && ++attempts < 4) {
                                this._client.emit("debug", "A wild 502 appeared! Thanks CloudFlare!");
                                setTimeout(() => {
                                    this.request(method, url, auth, body, file, route, true).then(resolve).catch(reject);
                                }, Math.floor(Math.random() * 1900 + 100));
                                return cb();
                            }
                            cb();

                            if(response.length > 0) {
                                if(resp.headers["content-type"] === "application/json") {
                                    try {
                                        response = JSON.parse(response);
                                    } catch(err) {
                                        reject(err);
                                        return;
                                    }
                                }
                            }

                            let {stack} = _stackHolder;
                            if(stack.startsWith("Error\n")) {
                                stack = stack.substring(6);
                            }
                            let err;
                            if(response.code) {
                                err = new DiscordRESTError(req, resp, response, stack);
                            } else {
                                err = new DiscordHTTPError(req, resp, response, stack);
                            }
                            reject(err);
                            return;
                        }

                        if(response.length > 0) {
                            if(resp.headers["content-type"] === "application/json") {
                                try {
                                    response = JSON.parse(response);
                                } catch(err) {
                                    cb();
                                    reject(err);
                                    return;
                                }
                            }
                        }

                        cb();
                        resolve(response);
                    });
                });

                req.setTimeout(this.requestTimeout, () => {
                    reqError = new Error(`Request timed out (>${this.requestTimeout}ms) on ${method} ${url}`);
                    req.abort();
                });

                if(Array.isArray(data)) {
                    for(const chunk of data) {
                        req.write(chunk);
                    }
                    req.end();
                } else {
                    req.end(data);
                }
            };

            if(this.globalBlock && auth) {
                this.readyQueue.push(() => {
                    if(!this.ratelimits[route]) {
                        this.ratelimits[route] = new SequentialBucket(1, this.latencyRef);
                    }
                    this.ratelimits[route].queue(actualCall, short);
                });
            } else {
                if(!this.ratelimits[route]) {
                    this.ratelimits[route] = new SequentialBucket(1, this.latencyRef);
                }
                this.ratelimits[route].queue(actualCall, short);
            }
        });
    }

    routefy(url, method) {
        let route = url.replace(/\/([a-z-]+)\/(?:[0-9]{17,19})/g, function(match, p) {
            return p === "channels" || p === "guilds" || p === "webhooks" ? match : `/${p}/:id`;
        }).replace(/\/reactions\/[^/]+/g, "/reactions/:id").replace(/^\/webhooks\/(\d+)\/[A-Za-z0-9-_]{64,}/, "/webhooks/$1/:token");
        if(method === "DELETE" && route.endsWith("/messages/:id")) { // Delete Messsage endpoint has its own ratelimit
            route = method + route;
        }
        return route;
    }

    toString() {
        return "[RequestHandler]";
    }

    toJSON(props = []) {
        return Base.prototype.toJSON.call(this, [
            "baseURL",
            "userAgent",
            "ratelimits",
            "requestTimeout",
            "agent",
            "latencyRef",
            "globalBlock",
            "readyQueue",
            ...props
        ]);
    }
}

module.exports = RequestHandler;
<|endoftext|>


<commit_before>// Module dependencies.
var debug = require('debug')('ruche:download');
var http = require('http');
var fs = require('fs');
var error = require('./error');
var emitter = require('./emitter');

/**
 * Get a file from HTTP request and save it to the local file system.
 * @param {String}   package  Name of the package
 * @param {String}   url      The HTTP URL of the file you want
 * @param {String}   dest     Destination file on the file system
 * @param {Object}   options  An object of options: port, etc.
 * @fires RucheEmitter#install-package-response
 * @fires RucheEmitter#install-package-chunk
 * @fires RucheEmitter#install-package-dl
 * @fires RucheEmitter#install-package-file
 */
var download = function(pakage, url, dest, options) {

  // Open a file stream
  var file = fs.createWriteStream(dest);

  // Make an HTTP request to get the file
  var req = http.get(url, function(res) {
    debug('Start of HTTP response: ' + package)
    res.pipe(file);
    file.on('finish', function() {
      file.close(function (data) {
        emitter.emit('install-' + package + '-file', data);
        debug('Written to file sytsem: ' + package);
      });
    });
  });

  // Capture the HTTP response
  req.on('response', function (res) {
    var contentLength = parseInt(res.headers['content-length'], 10)
    emitter.emit('install-' + package + '-response', contentLength);

    // When receiving data (chunk by chunk)
    res.on('data', function (chunk) {
      emitter.emit('install-' + package + '-chunk', chunk);
    });

    // When response ends
    res.on('end', function () {
      emitter.emit('install-' + package + '-dl');
      debug('End of HTTP response: ' + package);
    });
  })

  // If there is an error handle it
  req.on('error', function(err) {
    fs.unlink(dest);
    error.handle(err);
  });
};

module.exports = download;<commit_msg>Typo fixed<commit_after>// Module dependencies.
var debug = require('debug')('ruche:download');
var http = require('http');
var fs = require('fs');
var error = require('./error');
var emitter = require('./emitter');

/**
 * Get a file from HTTP request and save it to the local file system.
 * @param {String}   package  Name of the package
 * @param {String}   url      The HTTP URL of the file you want
 * @param {String}   dest     Destination file on the file system
 * @param {Object}   options  An object of options: port, etc.
 * @fires RucheEmitter#install-package-response
 * @fires RucheEmitter#install-package-chunk
 * @fires RucheEmitter#install-package-dl
 * @fires RucheEmitter#install-package-file
 */
var download = function(package, url, dest, options) {

  // Open a file stream
  var file = fs.createWriteStream(dest);

  // Make an HTTP request to get the file
  var req = http.get(url, function(res) {
    debug('Start of HTTP response: ' + package)
    res.pipe(file);
    file.on('finish', function() {
      file.close(function (data) {
        emitter.emit('install-' + package + '-file', data);
        debug('Written to file sytsem: ' + package);
      });
    });
  });

  // Capture the HTTP response
  req.on('response', function (res) {
    var contentLength = parseInt(res.headers['content-length'], 10)
    emitter.emit('install-' + package + '-response', contentLength);

    // When receiving data (chunk by chunk)
    res.on('data', function (chunk) {
      emitter.emit('install-' + package + '-chunk', chunk);
    });

    // When response ends
    res.on('end', function () {
      emitter.emit('install-' + package + '-dl');
      debug('End of HTTP response: ' + package);
    });
  })

  // If there is an error handle it
  req.on('error', function(err) {
    fs.unlink(dest);
    error.handle(err);
  });
};

module.exports = download;<|endoftext|>


<commit_before>var font = Font("main.fnt");
var fontBig = Font("mainBig.fnt");

function render() {
    // Clear
    Renderer.clear(Color(.35, .35, .35, 1));

    // Begin a batch
    SpriteBatch.begin();

    // Normal text
    SpriteBatch.drawText(font, "Lorem ipsum dolor sit amet.", Vector2(10, 10));

    // Bigger font
    SpriteBatch.drawText(fontBig, "CONSECTETUR ADIPISCING ELIT", Vector2(10, 100));

    // Playing with colors
    // ^RGB, where RGB ranged from 0-9
    SpriteBatch.drawText(font, "^933Sed ^993do ^393eiusmod ^399tempor ^339incididunt ^939ut ^111labore ^222et ^444dolore ^666magna ^888aliqua", Vector2(10, 200));

    // Alignment
    var screenResolution = Renderer.getResolution();
    SpriteBatch.drawText(font, "Left aligned", Vector2(10, 300), Align.Left);
    SpriteBatch.drawText(font, "Center aligned", Vector2(screenResolution.x / 2, 300), Align.Center);
    SpriteBatch.drawText(font, "Right aligned", Vector2(screenResolution.x - 10, 300), Align.Right);

    // Cheap outline
    SpriteBatch.drawOutlinedText(font, "Duis aute irure dolor in reprehenderit - Cheap oulines", Vector2(10, 400));

    // Pretty outline
    SpriteBatch.drawPrettyOutlinedText(font, "Duis aute irure dolor in reprehenderit - Better outlines", Vector2(10, 450));

    // End the batch
    SpriteBatch.end();
}
<commit_msg>formating<commit_after>var font = Font("main.fnt");
var fontBig = Font("mainBig.fnt");

function render() {
    // Clear
    Renderer.clear(Color(.35, .35, .35, 1));

    // Begin a batch
    SpriteBatch.begin();

    // Normal text
    SpriteBatch.drawText(font, "Lorem ipsum dolor sit amet.", Vector2(10, 10));

    // Bigger font
    SpriteBatch.drawText(fontBig, "CONSECTETUR ADIPISCING ELIT", Vector2(10, 100));

    // Playing with colors
    // ^RGB, where RGB ranged from 0-9
    SpriteBatch.drawText(font, "^933Sed ^993do ^393eiusmod ^399tempor ^339incididunt ^939ut ^111labore ^222et ^444dolore ^666magna ^888aliqua", Vector2(10, 200));

    // Alignment
    var screenResolution = Renderer.getResolution();
    SpriteBatch.drawText(font, "Left aligned", Vector2(10, 300), Align.Left);
    SpriteBatch.drawText(font, "Center aligned", Vector2(screenResolution.x / 2, 300), Align.Center);
    SpriteBatch.drawText(font, "Right aligned", Vector2(screenResolution.x - 10, 300), Align.Right);

    // Cheap outline
    SpriteBatch.drawOutlinedText(font, "Duis aute irure dolor in reprehenderit - Cheap oulines", Vector2(10, 400));

    // Pretty outline
    SpriteBatch.drawPrettyOutlinedText(font, "Duis aute irure dolor in reprehenderit - Better outlines", Vector2(10, 450));

    // End the batch
    SpriteBatch.end();
}
<|endoftext|>


<commit_before>/**
 * Sender pour le protocole apn (iDevices)
 */

var apns = require("apn"),
    sender = {};

/**
 * Connexion apn
 */
sender.connection = null;

/**
 * Initialisé
 */
sender.initialized = false;

/**
 * Configuration
 */
sender.config = null;

/**
 * Initialisation du sender
 */
sender.initialize = function()
{
   if(this.initialized)
   {
      return ;
   }

   var options = {
         cert: this.config.cert,
         key:  this.config.key,
         gateway: this.config.gateway,
         port: this.config.port
   };

   this.connection = new apns.Connection(options);

   this.initialized = true;
};

/**
 * Envoi d'une notification
 * @param object data
 */
sender.send = function(data, callback)
{
   this.initialize();

   var notification = new apns.Notification(), device = new apns.Device(data.token);

   if(typeof data.badge !== "undefined" && data.badge)
   {
      notification.badge = data.badge;
   }

   if(typeof data.sound !== "undefined" && data.sound)
   {
      notification.sound = data.sound;
   }

   if(typeof data.alert !== "undefined" && data.alert)
   {
      notification.alert = data.alert;
   }

   if(typeof data.payload !== "undefined" && data.payload)
   {
      notification.payload = data.payload;
   }

   notification.device = device;

   this.connection.sendNotification(notification);

   if(typeof callback === "function")
   {
      callback();
   }
};

exports.sender = sender;<commit_msg>gestion des erreurs<commit_after>/**
 * Sender pour le protocole apn (iDevices)
 */

var apns = require("apn"),
    sender = {};

/**
 * Connexion apn
 */
sender.connection = null;

/**
 * Initialisé
 */
sender.initialized = false;

/**
 * Configuration
 */
sender.config = null;

/**
 * Initialisation du sender
 */
sender.initialize = function()
{
   if(this.initialized)
   {
      return ;
   }

   var options = {
         cert: this.config.cert,
         key:  this.config.key,
         gateway: this.config.gateway,
         port: this.config.port,
         errorCallback: this.errorCallback.bind(this)
   };

   this.connection = new apns.Connection(options);

   this.initialized = true;
};

/**
 * Callback error
 * @param int errorCode
 * @param object notification
 */
sender.errorCallback = function(errorCode, notification)
{
   console.log("Erreur " + errorCode + " survenue sur la notification : ");
   console.log(notification);
};

/**
 * Envoi d'une notification
 * @param object data
 */
sender.send = function(data, callback)
{
   this.initialize();

   var notification = new apns.Notification(), device = new apns.Device(data.token);

   if(typeof data.badge !== "undefined" && data.badge)
   {
      notification.badge = data.badge;
   }

   if(typeof data.sound !== "undefined" && data.sound)
   {
      notification.sound = data.sound;
   }

   if(typeof data.alert !== "undefined" && data.alert)
   {
      notification.alert = data.alert;
   }

   if(typeof data.payload !== "undefined" && data.payload)
   {
      notification.payload = data.payload;
   }

   notification.device = device;

   var error = this.connection.sendNotification(notification);

   if(typeof error !== "undefined")
   {
      console.log("Error " + error + " append on " + data.token);
   }

   if(typeof callback === "function")
   {
      callback();
   }
};

exports.sender = sender;<|endoftext|>


<commit_before>"use strict";

var Base = require("../shared/Base.class.js"),
    bootstrapServer = require("./bootstrap.server.js"),
    sanitizeConfig = require("../core/config/sanitizeConfig.js"),
    startServer = require("./startServer.js"),
    config = require("../shared/config.js"),
    session = require("./session.js"),
    router = require("./router.js"),
    setSocketIOOptions = require("./transport/websocket/websocket.js").setSocketIOOptions,
    setConnectInstance = require("./transport/http/http.js").setConnectInstance,
    setSPDYOptions = require("./transport/spdy/spdy.js").setOptions;

/**
 * The Server-Class
 * @type {Class}
 */
var Server = Base.extend("Server", {

    _bootstrapped : false,
    _router : null,

    constructor : function(connectInstance) {

        //set custom connect instance
        if(connectInstance) {
            setConnectInstance(connectInstance);
        }

        this._router = router.get("alamid");
    },
    addRoute : function(methods, route, fns) {
        this._router.addAlamidRoute(methods, route, fns);
    },
    bootstrap : function() {
        bootstrapServer();
        this._bootstrapped = true;
    },
    start : function(port) {

        //only bootstrap if it hadn't been called
        if(!this._bootstrapped) {
            this.bootstrap();
        }

        return this.server = startServer(port);
    },
    set : function(key, value) {
        config[key] = value;
        //re-sanitize config
        //also need to set current paths
        config = sanitizeConfig(config);
    },
    use : function(what, how) {

        if(how === false) {
            config.use[what] = false;
            return this;
        }

        switch (what) {
            case "session" :
                session.set(how);
                break;
            case "http" :
                config.use.http = true;
                setConnectInstance(how);
                break;
            case "websockets" :
                config.use.websockets = true;
                setSocketIOOptions(how);
                break;
            case "spdy" :
                config.use.spdy = true;
                setSPDYOptions(how);
                break;
            case "staticFileServer" :
                config.use.staticFileServer = true;
                break;
            case "services" :
                config.use.services = true;
                break;
            case "validators" :
                config.use.validators = true;
                break;
            default :
                throw new Error("(alamid) server.use '" + what + "' is not supported.");
        }

        return this;
    },
    close : function() {
        router.reset();
        this._bootstrapped = false;
        this.server.close();
    }
});

module.exports = Server;<commit_msg>- exposing router via Server.class.js<commit_after>"use strict";

var Base = require("../shared/Base.class.js"),
    bootstrapServer = require("./bootstrap.server.js"),
    sanitizeConfig = require("../core/config/sanitizeConfig.js"),
    startServer = require("./startServer.js"),
    config = require("../shared/config.js"),
    session = require("./session.js"),
    router = require("./router.js"),
    setSocketIOOptions = require("./transport/websocket/websocket.js").setSocketIOOptions,
    setConnectInstance = require("./transport/http/http.js").setConnectInstance,
    setSPDYOptions = require("./transport/spdy/spdy.js").setOptions;

/**
 * The Server-Class
 * @type {Class}
 */
var Server = Base.extend("Server", {

    _bootstrapped : false,
    _router : null,

    constructor : function(connectInstance) {

        //set custom connect instance
        if(connectInstance) {
            setConnectInstance(connectInstance);
        }

        this._router = router.get("alamid");
    },
    addRoute : function(methods, route, fns) {
        this._router.addAlamidRoute(methods, route, fns);
    },
    getRouter : function(type) {
        return router.get(type);
    },
    bootstrap : function() {
        bootstrapServer();
        this._bootstrapped = true;
    },
    start : function(port) {

        //only bootstrap if it hadn't been called
        if(!this._bootstrapped) {
            this.bootstrap();
        }

        return this.server = startServer(port);
    },
    set : function(key, value) {
        config[key] = value;
        //re-sanitize config
        //also need to set current paths
        config = sanitizeConfig(config);
    },
    use : function(what, how) {

        if(how === false) {
            config.use[what] = false;
            return this;
        }

        switch (what) {
            case "session" :
                session.set(how);
                break;
            case "http" :
                config.use.http = true;
                setConnectInstance(how);
                break;
            case "websockets" :
                config.use.websockets = true;
                setSocketIOOptions(how);
                break;
            case "spdy" :
                config.use.spdy = true;
                setSPDYOptions(how);
                break;
            case "staticFileServer" :
                config.use.staticFileServer = true;
                break;
            case "services" :
                config.use.services = true;
                break;
            case "validators" :
                config.use.validators = true;
                break;
            default :
                throw new Error("(alamid) server.use '" + what + "' is not supported.");
        }

        return this;
    },
    close : function() {
        router.reset();
        this._bootstrapped = false;
        this.server.close();
    }
});

module.exports = Server;<|endoftext|>


<commit_before>/** Mixin: Barefoot.Router.Server
 * This mixin contains any server side specific code for the <Barefoot.Router>.
 *
 * See also:
 * * <Barefoot.Router>
 */
var _ = require('underscore')
	, cheerio = require('cheerio')
	, Q = require('q')
	, CookieAdapter
	, DataStore;

/** Function: preInitialize
 * This function is called before any initialization or constructor of the
 * <Barefoot.Router> is executed. It expects that the passed options object
 * contains the following elements:
 *
 * app - An Express.JS app
 * layoutTemplate - The minimal HTML skeleton to render the application into.
 *                  Example: ""
 * startExpressApp - A callback function which initiates the actual startup of
 *                   the Express.JS app from above.
 *
 * Each of these are copied into this router object directly to access them
 * later on.
 *
 * Parameters:
 *     (Object) options
 */
function preInitialize(options) {
	this.app = options.app;
	this.layoutTemplate = options.layoutTemplate;
	this.startExpressApp = options.startExpressApp;
	this.apiAdapter = options.apiAdapter;
	this.setupRequestContext = options.setupRequestContext;
}

/** Function: route
 * This replacements for the route function of Backbone.Router ensures that each
 * route defined in the router is added to the Express.JS app.
 *
 * The route function ensures that you have access to all cookies from the
 * request via the cookieAdapter property of this router.
 *
 * Parameters:
 *     (String) routeUri - URI
 *
 * Returns:
 *     The created Express.JS route
 *
 * See also:
 * * <Barefoot.CookieAdapter.Server>
 */
function route(routeUri) {
	var self = this
		, Barefoot = require('../')();

	// Lazy-Load the barefoot objects CookieAdapter and DataStore. Otherwise
	// we'd have some cyclic dependency problems.
	CookieAdapter = Barefoot.CookieAdapter;
	DataStore = Barefoot.DataStore;

	return self.app.get('/' + routeUri, function(req, res) {
		var callback = self[self.routes[routeUri]]
			, cookieAdapter = new CookieAdapter({ cookies: req.cookies })
			, dataStore = new DataStore();

		// Ensure that request-local stuff is available locally:
		self.req = req;
		self.res = res;
		self.cookieAdapter = cookieAdapter;
		self.dataStore = dataStore;

		// Ensure the request context is set up locally:
		if(!_.isUndefined(self.setupRequestContext)) {
			self.setupRequestContext.call(self);
		}

		// Ensure that the APIAdapter has access to the current request:
		if(!_.isUndefined(self.apiAdapter)) {
			self.apiAdapter.req = req;
		}

		// Execute the route:
		var routeResult = callback.apply(self, _.values(req.params));

		// Ensure cookies are placed inside the response:
		res.cookies = self.cookieAdapter.cookies;

		return routeResult;
	});
}

/** Function: navigate
 * Rewrites <Backbone.Router.navigate at http://backbonejs.org/#Router-navigate>
 * to replicate its functionality when rendering the application on the server.
 *
 * Basically the callback for the given routeUri is picked and called.
 *
 * Parameters:
 *     (String) routeUri - The URI of the route to navigate to
 *
 * Returns:
 *     (Object) the value which the route callbacks returns.
 */
function navigate(routeUri) {
	this.res.redirect(routeUri);
}

/** Function: render
 * This function initiates the rendering of the passed view. This is done by
 * loading the layout template into a cheerio DOM object.
 *
 * Afterwards the presence of a main view object is checked. If available, that
 * main view gets rendered into the DOM. In any case, the passed view gets
 * rendered.
 *
 * As a final step the presence of registered models in the application wide
 * <Barefoot.DataStore> is checked. If present, its content gets serialized into
 * a script DOM element so the client can properly deserialize its state
 * afterwards. See <Barefoot.Router.Client.start> for the deserialization code.
 *
 * The resulting HTML code is then sent to the client by using the Express.JS
 * response object, buffered from the route callback in the <route> function.
 *
 * Parameters:
 *     (Barefoot.View) view - The view which should be rendered
 *
 * See also:
 * * <route>
 */
function render(view) {
	var self = this
		, $;

	function initDOM() {
		$ = cheerio.load(self.layoutTemplate);
	}

	function renderMainView() {
		var promise;

		if(!_.isUndefined(self.mainView)) {
			var clonedMainView = _.clone(self.mainView());
			clonedMainView.$ = $;
			clonedMainView.$el = clonedMainView.selectDOMElement($);
			promise = clonedMainView.render();
		}

		return promise;
	}

	function renderView() {
		view.$ = $;
		view.$el = view.selectDOMElement($);

		return view.render();
	}

	function serializeDataStore() {
		if(!_.isUndefined(self.dataStore) &&
			_.keys(self.dataStore.registeredModels).length > 0) {
			var serializiedDataStore = JSON.stringify(self.dataStore.toJSON())
				, javaScriptElement =
					'';
			$('body').append(javaScriptElement);
		}
	}

	function writeHTTPResponse() {
		self.res.send($.html());
	}

	function writeHTTPError() {
		self.res.send(500);
	}

	Q.fcall(initDOM)
	.then(renderMainView)
	.then(renderView)
	.then(serializeDataStore)
	.done(writeHTTPResponse, writeHTTPError);
}

/** Function: start
 * Calls the passed starter function, buffered in <preInitialize>.
 */
function start() {
	this.startExpressApp(this.app);
}

module.exports = {
	preInitialize: preInitialize
	, route: route
	, navigate: navigate
	, render: render
	, start: start
};<commit_msg>If an unhandled error occurs, write logs<commit_after>/** Mixin: Barefoot.Router.Server
 * This mixin contains any server side specific code for the <Barefoot.Router>.
 *
 * See also:
 * * <Barefoot.Router>
 */
var _ = require('underscore')
	, cheerio = require('cheerio')
	, winston = require('winston')
	, Q = require('q')
	, CookieAdapter
	, DataStore;

/** Function: toString
 * String representation of this module.
 */
function toString() {
	return 'Router.Server';
}

/** Function: preInitialize
 * This function is called before any initialization or constructor of the
 * <Barefoot.Router> is executed. It expects that the passed options object
 * contains the following elements:
 *
 * app - An Express.JS app
 * layoutTemplate - The minimal HTML skeleton to render the application into.
 *                  Example: ""
 * startExpressApp - A callback function which initiates the actual startup of
 *                   the Express.JS app from above.
 *
 * Each of these are copied into this router object directly to access them
 * later on.
 *
 * Parameters:
 *     (Object) options
 */
function preInitialize(options) {
	this.app = options.app;
	this.layoutTemplate = options.layoutTemplate;
	this.startExpressApp = options.startExpressApp;
	this.apiAdapter = options.apiAdapter;
	this.setupRequestContext = options.setupRequestContext;
}

/** Function: route
 * This replacements for the route function of Backbone.Router ensures that each
 * route defined in the router is added to the Express.JS app.
 *
 * The route function ensures that you have access to all cookies from the
 * request via the cookieAdapter property of this router.
 *
 * Parameters:
 *     (String) routeUri - URI
 *
 * Returns:
 *     The created Express.JS route
 *
 * See also:
 * * <Barefoot.CookieAdapter.Server>
 */
function route(routeUri) {
	var self = this
		, Barefoot = require('../')();

	// Lazy-Load the barefoot objects CookieAdapter and DataStore. Otherwise
	// we'd have some cyclic dependency problems.
	CookieAdapter = Barefoot.CookieAdapter;
	DataStore = Barefoot.DataStore;

	return self.app.get('/' + routeUri, function(req, res) {
		var callback = self[self.routes[routeUri]]
			, cookieAdapter = new CookieAdapter({ cookies: req.cookies })
			, dataStore = new DataStore();

		// Ensure that request-local stuff is available locally:
		self.req = req;
		self.res = res;
		self.cookieAdapter = cookieAdapter;
		self.dataStore = dataStore;

		// Ensure the request context is set up locally:
		if(!_.isUndefined(self.setupRequestContext)) {
			self.setupRequestContext.call(self);
		}

		// Ensure that the APIAdapter has access to the current request:
		if(!_.isUndefined(self.apiAdapter)) {
			self.apiAdapter.req = req;
		}

		// Execute the route:
		var routeResult = callback.apply(self, _.values(req.params));

		// Ensure cookies are placed inside the response:
		res.cookies = self.cookieAdapter.cookies;

		return routeResult;
	});
}

/** Function: navigate
 * Rewrites <Backbone.Router.navigate at http://backbonejs.org/#Router-navigate>
 * to replicate its functionality when rendering the application on the server.
 *
 * Basically the callback for the given routeUri is picked and called.
 *
 * Parameters:
 *     (String) routeUri - The URI of the route to navigate to
 *
 * Returns:
 *     (Object) the value which the route callbacks returns.
 */
function navigate(routeUri) {
	this.res.redirect(routeUri);
}

/** Function: render
 * This function initiates the rendering of the passed view. This is done by
 * loading the layout template into a cheerio DOM object.
 *
 * Afterwards the presence of a main view object is checked. If available, that
 * main view gets rendered into the DOM. In any case, the passed view gets
 * rendered.
 *
 * As a final step the presence of registered models in the application wide
 * <Barefoot.DataStore> is checked. If present, its content gets serialized into
 * a script DOM element so the client can properly deserialize its state
 * afterwards. See <Barefoot.Router.Client.start> for the deserialization code.
 *
 * The resulting HTML code is then sent to the client by using the Express.JS
 * response object, buffered from the route callback in the <route> function.
 *
 * Parameters:
 *     (Barefoot.View) view - The view which should be rendered
 *
 * See also:
 * * <route>
 */
function render(view) {
	var self = this
		, $;

	function initDOM() {
		$ = cheerio.load(self.layoutTemplate);
	}

	function renderMainView() {
		var promise;

		if(!_.isUndefined(self.mainView)) {
			var clonedMainView = _.clone(self.mainView());
			clonedMainView.$ = $;
			clonedMainView.$el = clonedMainView.selectDOMElement($);
			promise = clonedMainView.render();
		}

		return promise;
	}

	function renderView() {
		view.$ = $;
		view.$el = view.selectDOMElement($);

		return view.render();
	}

	function serializeDataStore() {
		if(!_.isUndefined(self.dataStore) &&
			_.keys(self.dataStore.registeredModels).length > 0) {
			var serializiedDataStore = JSON.stringify(self.dataStore.toJSON())
				, javaScriptElement =
					'';
			$('body').append(javaScriptElement);
		}
	}

	function writeHTTPResponse() {
		self.res.send($.html());
	}

	function writeHTTPError(err) {
		winston.log('error', 'Uncatched HTTP Error', {
			source: toString()
			, err: err.toString() || err
			, stack: err.stack || undefined
		});
		self.res.send(500);
	}

	Q.fcall(initDOM)
	.then(renderMainView)
	.then(renderView)
	.then(serializeDataStore)
	.done(writeHTTPResponse, writeHTTPError);
}

/** Function: start
 * Calls the passed starter function, buffered in <preInitialize>.
 */
function start() {
	this.startExpressApp(this.app);
}

module.exports = {
	preInitialize: preInitialize
	, route: route
	, navigate: navigate
	, render: render
	, start: start
};<|endoftext|>


<commit_before>Meteor.startup(() => {
	RocketChat.roomTypes.setPublish('l', (code) => {
		return RocketChat.models.Rooms.findLivechatByCode(code, {
			name: 1,
			t: 1,
			cl: 1,
			u: 1,
			label: 1,
			usernames: 1,
			v: 1,
			livechatData: 1,
			topic: 1,
			tags: 1,
			sms: 1,
			code: 1,
			open: 1
		});
	});

	RocketChat.authz.addRoomAccessValidator(function(room, user) {
		return room.t === 'l' && RocketChat.authz.hasPermission(user._id, 'view-livechat-rooms');
	});

	RocketChat.callbacks.add('beforeLeaveRoom', function(user, room) {
		if (room.t !== 'l') {
			return user;
		}
		throw new Meteor.Error(TAPi18n.__('You_cant_leave_a_livechat_room_Please_use_the_close_button', {
			lng: user.language || RocketChat.settings.get('language') || 'en'
		}));
	}, RocketChat.callbacks.priority.LOW, 'cant-leave-room');
});
<commit_msg>fix room publication<commit_after>Meteor.startup(() => {
	RocketChat.roomTypes.setPublish('l', (code) => {
		return RocketChat.models.Rooms.findLivechatByCode(code, {
			name: 1,
			t: 1,
			cl: 1,
			u: 1,
			label: 1,
			usernames: 1,
			v: 1,
			livechatData: 1,
			topic: 1,
			tags: 1,
			sms: 1,
			code: 1,
			open: 1,
			details: 1
		});
	});

	RocketChat.authz.addRoomAccessValidator(function(room, user) {
		return room.t === 'l' && RocketChat.authz.hasPermission(user._id, 'view-livechat-rooms');
	});

	RocketChat.callbacks.add('beforeLeaveRoom', function(user, room) {
		if (room.t !== 'l') {
			return user;
		}
		throw new Meteor.Error(TAPi18n.__('You_cant_leave_a_livechat_room_Please_use_the_close_button', {
			lng: user.language || RocketChat.settings.get('language') || 'en'
		}));
	}, RocketChat.callbacks.priority.LOW, 'cant-leave-room');
});
<|endoftext|>