<commit_before>var should = require('should');
var rest = require('restler');
var async = require('async');
var config = require('./config.js');
var redis = require("redis"),rc = redis.createClient(6379,'localhost');

var host = config.hostname;
var port = config.port;
var protocol = config.protocol;

var trans, trans1 = {};

describe('Inbox', function () {
  "use strict";

  function onError(err, response){
    console.log('error form restler');
    console.dir(err);
    console.log('error form PopBox');
    console.dir(response);
    throw new Error({'err': err, 'response': response});
  }

    after(function (done) {
        this.timeout(8000);
        rc.flushall();
        rc.end();
        done();
    });
    beforeEach(function (done) {
        this.timeout(8000);
        rc.flushall();
        done();
    });

    it('Should return all the transactions', function (done) {
        this.timeout(8000); //Mocha timeout
        var trans = {
            'payload': 'Test',
            'priority': 'H',
            'callback': protocol + '://foo.bar',
            'queue': [
                { 'id': 'q1' },
                { 'id': 'q2' }
            ]
        };

        async.series([
            function (callback) {

                rest.postJson(protocol + '://' + host + ':' + port + '/trans',
                    trans).on('success', function (data, response) {
                        callback();
                    }).on('error', onError);

            },
            function (callback) {

                trans.payload='Test 2';
                rest.postJson(protocol + '://' + host + ':' + port + '/trans',
                    trans).on('success', function (data, response) {
                        callback();
                    }).on('error', onError);

            },
            function (callback) {

                var checkQueue = function (queue, callback) {
                    rest.post(protocol + '://' + host + ':' + port + '/queue/' + queue + '/pop')
                        .on('success', function (data, response) {
                            data.should.not.have.property('error');
                            data.should.have.property('ok');
                            data.should.have.property('data');
                            data.data.length.should.be.equal(2);
                            data.data.should.include('Test');
                            data.data.should.include('Test 2');
                            callback();
                        }).on('error', onError);
                };

                checkQueue('q1', checkQueue.bind({}, 'q2', callback));
            }
        ], function () {
            done();
        });
    });

    it('Should return the high priority transaction', function (done) {

        var transLow = {
            'payload': 'Low priority',
            'priority': 'L',
            'callback': protocol + '://foo.bar',
            'queue': [
                { 'id': 'q1' },
                { 'id': 'q2' }
            ]
        };

        var transHigh = {
            'payload': 'High priority',
            'priority': 'H',
            'callback': protocol + '://foo.bar',
            'queue': [
                { 'id': 'q1' }
            ]
        };

        async.series([
            function (callback) {
                rest.postJson(protocol + '://' + host + ':' + port + '/trans',
                    transLow).on('success', function (data, response) {
                        callback();
                    }).on('error', onError);
            },
            function (callback) {
                rest.postJson(protocol + '://' + host + ':' + port + '/trans',
                    transHigh).on('success', function (data, response) {
                        callback();
                    }).on('error', onError);
            },
            function (callback) {
                rest.post(protocol + '://' + host + ':' + port + '/queue/q1/pop?max=1')
                    .on('success', function (data, response) {
                    data.should.not.have.property('error');
                    data.should.have.property('ok');
                    data.should.have.property('data');
                    data.data.length.should.be.equal(1);
                        (data.data.pop()).should.be.equal('High priority');
                        callback();
                    }).on('error', onError);
            }
        ], function () {
            done();
        });
    });

    it('Should return empty data (timeout)', function (done) {
        this.timeout(8000); //Mocha timeout

        var trans5 = {
            'payload': 'Test timeout',
            'priority': 'L',
            'callback': protocol + '://foo.bar',
            'queue': [
                { 'id': 'q1' }
            ]
        };

        var funcs = [
            function (cb) {
                rest.post(protocol + '://' + host + ':' + port + '/queue/q1/pop?timeout=1',
                    {headers: {'Accept': 'application/json'}})
                    .on('success', function (data, response) {
                        //console.log(data);
                       data.should.not.have.property('error');
                       data.should.have.property('ok');
                       data.should.have.property('data');
                       data.data.length.should.be.equal(0);
                        cb();
                    }).on('error', onError);
            },
            function (cb) {
                setTimeout(function () {
                    rest.postJson(protocol + '://' + host + ':' + port + '/trans',
                        trans5).on('success', function (data, response) {
                            cb();
                        }).on('error', onError);
                }, 2000);

            }
        ];

        var cb = function () {
            done();
        };

        async.parallel(funcs, cb);
    });

    it('Should not return empty data (timeout)', function (done) {
        this.timeout(8000); //Mocha timeout
        var trans6 = {
            'payload': 'Test timeout',
            'priority': 'L',
            'callback': protocol + '://foo.bar',
            'queue': [
                { 'id': 'q1' }
            ]
        };

        var funcs = [
            function (cb) {
                rest.post(protocol + '://' + host + ':' + port + '/queue/q1/pop?timeout=3',
                    {headers: {'Accept': 'application/json'}})
                    .on('success', function (data, response) {
                        data.should.not.have.property('error');
                        data.should.have.property('ok');
                        data.should.have.property('data');
                        data.data.length.should.be.equal(1);
                        data.data.should.include('Test timeout');
                        cb();
                    }).on('error', onError);
            },
            function (cb) {
                setTimeout(function () {
                    rest.postJson(protocol + '://' + host + ':' + port + '/trans',
                        trans6).on('success', function (data, response) {
                            cb();
                        }).on('error', onError);
                }, 1000);

            }
        ];

        var cb = function () {
            done();
        };

        async.parallel(funcs, cb);
    });

});
<commit_msg>fake commit (travis CI blocked)<commit_after>var should = require('should');
var rest = require('restler');
var async = require('async');
var config = require('./config.js');
var redis = require("redis"),rc = redis.createClient(6379,'localhost');

var host = config.hostname;
var port = config.port;
var protocol = config.protocol;

var trans, trans1 = {};

describe('Inbox', function () {
  "use strict";

  function onError(err, response){
    console.log('error form restler');
    console.dir(err);
    console.log('error form PopBox');
    console.dir(response);
    throw new Error({'err': err, 'response': response});
  }

    after(function (done) {
        this.timeout(8000);
        rc.flushall();
        rc.end();
        done();
    });
    beforeEach(function (done) {
        this.timeout(8000);
        rc.flushall();
        done();
    });

    it('Should return all the transactions', function (done) {
        this.timeout(8000); //Mocha timeout
        var trans = {
            'payload': 'Test',
            'priority': 'H',
            'callback': protocol + '://foo.bar',
            'queue': [
                { 'id': 'q1' },
                { 'id': 'q2' }
            ]
        };

        async.series([
            function (callback) {

                rest.postJson(protocol + '://' + host + ':' + port + '/trans',
                    trans).on('success', function (data, response) {
                        callback();
                    }).on('error', onError);

            },
            function (callback) {

                trans.payload='Test 2';
                rest.postJson(protocol + '://' + host + ':' + port + '/trans',
                    trans).on('success', function (data, response) {
                        callback();
                    }).on('error', onError);

            },
            function (callback) {

                var checkQueue = function (queue, callback) {
                    rest.post(protocol + '://' + host + ':' + port + '/queue/' + queue + '/pop')
                        .on('success', function (data, response) {
                            data.should.not.have.property('error');
                            data.should.have.property('ok');
                            data.should.have.property('data');
                            data.data.length.should.be.equal(2);
                            data.data.should.include('Test');
                            data.data.should.include('Test 2');
                            callback();
                        }).on('error', onError);
                };

                checkQueue('q1', checkQueue.bind({}, 'q2', callback));
            }
        ], function () {
            done();
        });
    });

    it('Should return the high priority transaction', function (done) {

        var transLow = {
            'payload': 'Low priority',
            'priority': 'L',
            'callback': protocol + '://foo.bar',
            'queue': [
                { 'id': 'q1' },
                { 'id': 'q2' }
            ]
        };

        var transHigh = {
            'payload': 'High priority',
            'priority': 'H',
            'callback': protocol + '://foo.bar',
            'queue': [
                { 'id': 'q1' }
            ]
        };

        async.series([
            function (callback) {
                rest.postJson(protocol + '://' + host + ':' + port + '/trans',
                    transLow).on('success', function (data, response) {
                        callback();
                    }).on('error', onError);
            },
            function (callback) {
                rest.postJson(protocol + '://' + host + ':' + port + '/trans',
                    transHigh).on('success', function (data, response) {
                        callback();
                    }).on('error', onError);
            },
            function (callback) {
                rest.post(protocol + '://' + host + ':' + port + '/queue/q1/pop?max=1')
                    .on('success', function (data, response) {
                    data.should.not.have.property('error');
                    data.should.have.property('ok');
                    data.should.have.property('data');
                    data.data.length.should.be.equal(1);
                        (data.data.pop()).should.be.equal('High priority');
                        callback();
                    }).on('error', onError);
            }
        ], function () {
            done();
        });
    });

    it('Should return empty data (timeout)', function (done) {
        this.timeout(8000); //Mocha timeout

        var trans5 = {
            'payload': 'Test timeout',
            'priority': 'L',
            'callback': protocol + '://foo.bar',
            'queue': [
                { 'id': 'q1' }
            ]
        };

        var funcs = [
            function (cb) {
                rest.post(protocol + '://' + host + ':' + port + '/queue/q1/pop?timeout=1',
                    {headers: {'Accept': 'application/json'}})
                    .on('success', function (data, response) {
                        //console.log(data);
                       data.should.not.have.property('error');
                       data.should.have.property('ok');
                       data.should.have.property('data');
                       data.data.length.should.be.equal(0);
                        cb();
                    }).on('error', onError);
            },
            function (cb) {
                setTimeout(function () {
                    rest.postJson(protocol + '://' + host + ':' + port + '/trans',
                        trans5).on('success', function (data, response) {
                            cb();
                        }).on('error', onError);
                }, 2000);

            }
        ];

        var cb = function () {
            done();
        };

        async.parallel(funcs, cb);
    });

    it('Should not return empty data (timeout)', function (done) {
        this.timeout(8000); //Mocha timeout
        var trans6 = {
            'payload': 'Test timeout',
            'priority': 'L',
            'callback': protocol + '://foo.bar',
            'queue': [
                { 'id': 'q1' }
            ]
        };

        var funcs = [
            function (cb) {
                rest.post(protocol + '://' + host + ':' + port + '/queue/q1/pop?timeout=3',
                    {headers: {'Accept': 'application/json'}})
                    .on('success', function (data, response) {
                        data.should.not.have.property('error');
                        data.should.have.property('ok');
                        data.should.have.property('data');
                        data.data.length.should.be.equal(1);
                        data.data.should.include('Test timeout');
                        cb();
                    }).on('error', onError);
            },
            function (cb) {
                setTimeout(function () {
                    rest.postJson(protocol + '://' + host + ':' + port + '/trans',
                        trans6).on('success', function (data, response) {
                            cb();
                        }).on('error', onError);
                }, 1000);

            }
        ];

        var cb = function () {
            done();
        };

        async.parallel(funcs, cb);
    });

});
<|endoftext|>


<commit_before>// send a command to:
//   $resource.request.$command.$uuid

var amqp = require('amqp-plus');
var common = require('./common');
var util = require('util');
var EventEmitter = require('events').EventEmitter;

function Client(config) {
    this.config = config || { amqp: {} };
    this.commandTimeout = config.timeout || 60 * 60;
    this.config.reconnect = config.reconnect || false;
    this.verbose = config.verbose;
    this.log = config.log;

    if (!this.log.debug) {
        this.log.debug = console.warn;
    }
    if (!this.log.info) {
        this.log.info = console.warn;
    }
    if (!this.log.trace) {
        this.log.trace = console.warn;
    }
    if (!this.log.error) {
        this.log.error = console.warn;
    }
    if (!this.log.warn) {
        this.log.warn = console.warn;
    }
}

Client.prototype.configureAMQP = common.configureAMQP;

Client.prototype.connect = function (callback) {
    var self = this;

    this.connection = amqp.createConnection(
        this.config.amqp,
        {
            attemptToReconnect: self.config.attemptToReconnect,
            log: self.config.log
        });
    this.connection.reconnect();

    // Set up the exchange we'll be using to publish our commands. We wait for
    // the exchange to open and then run the callback.
    this.connection.addListener('ready', function () {
        self.onConnect();
        callback();
    });
};

Client.prototype.useConnection = function (connection) {
    var self = this;
    self.connection = connection;
    self.connection.on('ready', self.onConnect.bind(self));
};

Client.prototype.onConnect = function () {
    var self = this;
    self.agentHandles = {};
    self.exchange = self.connection.exchange('amq.topic', { type: 'topic' });
};

Client.prototype.end = function () {
    this.config.reconnect = false;
    this.connection.end();
};

/**
 * The 'Client' object is decoupled from the creation and management of queues
 * used to communicate with the agents. We will have the Client object hand us
 * handles/closures/whatever that will deal with their own objects.
 */

Client.prototype.getAgentHandle = function (resource, uuid, callback) {
    var handle;

    if (!this.agentHandles) {
        this.agentHandles = {};
    }

    if (this.agentHandles[uuid]) {
        handle = this.agentHandles[uuid];
        callback(handle);
        return;
    } else {
        handle = this.agentHandles[uuid] = new AgentHandle({
                log:        this.config.log,
                connection: this.connection,
                exchange:   this.exchange,
                uuid:       uuid,
                timeout:    this.commandTimeout,
                resource:   resource
        });

        handle.prepareAgentEventQueue(function () {
            callback(handle);
        });
    }
};

function AgentHandle(args) {
    this.uuid = args.uuid;
    this.connection = args.connection;
    this.exchange = args.exchange;
    this.clientId = common.genId();
    this.resource = args.resource;
    this.commandTimeout = args.timeout;
    this.taskHandles = {};
    this.log = args.log;
}

AgentHandle.prototype.prepareAgentEventQueue = function (callback) {
    var self = this;

    var queueName = common.dotjoin(
                        this.resource + '-client', this.uuid, 'events',
                        common.genId());

    this.log.info('Waiting for task events on queue: ' + queueName);
    var queue = this.connection.queue(
                    queueName, { autoDelete: true }, queueCallback);

    function queueCallback() {
        var rk = common.dotjoin(
                    self.resource, '*', 'event', '*', self.clientId, '*');

        self.log.info('Binding to: ' + rk);
        queue.bind('amq.topic', rk);

        queue.subscribe(function (msg, headers, deliveryInfo) {
            var rkParts = deliveryInfo.routingKey.split('.');
            var eventType = rkParts[3];
            var taskId = rkParts[5];
            if (self.taskHandles[taskId]) {
                self.taskHandles[taskId].emit('event', eventType, msg);
                if (eventType === 'finish') {
                    clearTimeout(self.taskHandles[taskId].timeout);
                    delete self.taskHandles[taskId];
                }
            }
        });
        callback();
    }
};

function TaskHandle(id) {
    EventEmitter.call(this);
    this.id = id;
    this.timeout = null;
}

util.inherits(TaskHandle, EventEmitter);

AgentHandle.prototype.sendTask = function (task, msg, callback) {
    var self = this;

    self.log.debug('Sending task to %s', self.uuid);
    msg.task_id = common.genId();
    msg.client_id = self.clientId;

    var taskHandle
        = this.taskHandles[msg.task_id]
        = new TaskHandle(msg.task_id);

    var routingKey = common.dotjoin(this.resource, this.uuid, 'task', task);

    self.log.debug(
        { message: msg },
        'Publishing message to routing key: "' + routingKey + '"');
    self.exchange.publish(routingKey, msg);

    taskHandle.timeout = setTimeout(function () {
        self.log.error(
            'Task (%s) to (%s) timed out after %d seconds.',
            task, self.uuid, self.commandTimeout * 1000);
        delete self.taskHandles[msg.task_id];
    }, self.commandTimeout * 1000);
    callback(taskHandle);
};

module.exports = Client;
<commit_msg>CNAPI-275: Explicitly clear all event handlers on task handles<commit_after>// send a command to:
//   $resource.request.$command.$uuid

var amqp = require('amqp-plus');
var common = require('./common');
var util = require('util');
var EventEmitter = require('events').EventEmitter;

function Client(config) {
    this.config = config || { amqp: {} };
    this.commandTimeout = config.timeout || 60 * 60;
    this.config.reconnect = config.reconnect || false;
    this.verbose = config.verbose;
    this.log = config.log;

    if (!this.log.debug) {
        this.log.debug = console.warn;
    }
    if (!this.log.info) {
        this.log.info = console.warn;
    }
    if (!this.log.trace) {
        this.log.trace = console.warn;
    }
    if (!this.log.error) {
        this.log.error = console.warn;
    }
    if (!this.log.warn) {
        this.log.warn = console.warn;
    }
}

Client.prototype.configureAMQP = common.configureAMQP;

Client.prototype.connect = function (callback) {
    var self = this;

    this.connection = amqp.createConnection(
        this.config.amqp,
        {
            attemptToReconnect: self.config.attemptToReconnect,
            log: self.config.log
        });
    this.connection.reconnect();

    // Set up the exchange we'll be using to publish our commands. We wait for
    // the exchange to open and then run the callback.
    this.connection.addListener('ready', function () {
        self.onConnect();
        callback();
    });
};

Client.prototype.useConnection = function (connection) {
    var self = this;
    self.connection = connection;
    self.connection.on('ready', self.onConnect.bind(self));
};

Client.prototype.onConnect = function () {
    var self = this;
    self.agentHandles = {};
    self.exchange = self.connection.exchange('amq.topic', { type: 'topic' });
};

Client.prototype.end = function () {
    this.config.reconnect = false;
    this.connection.end();
};

/**
 * The 'Client' object is decoupled from the creation and management of queues
 * used to communicate with the agents. We will have the Client object hand us
 * handles/closures/whatever that will deal with their own objects.
 */

Client.prototype.getAgentHandle = function (resource, uuid, callback) {
    var handle;

    if (!this.agentHandles) {
        this.agentHandles = {};
    }

    if (this.agentHandles[uuid]) {
        handle = this.agentHandles[uuid];
        callback(handle);
        return;
    } else {
        handle = this.agentHandles[uuid] = new AgentHandle({
                log:        this.config.log,
                connection: this.connection,
                exchange:   this.exchange,
                uuid:       uuid,
                timeout:    this.commandTimeout,
                resource:   resource
        });

        handle.prepareAgentEventQueue(function () {
            callback(handle);
        });
    }
};

function AgentHandle(args) {
    this.uuid = args.uuid;
    this.connection = args.connection;
    this.exchange = args.exchange;
    this.clientId = common.genId();
    this.resource = args.resource;
    this.commandTimeout = args.timeout;
    this.taskHandles = {};
    this.log = args.log;
}

AgentHandle.prototype.prepareAgentEventQueue = function (callback) {
    var self = this;

    var queueName = common.dotjoin(
                        this.resource + '-client', this.uuid, 'events',
                        common.genId());

    this.log.info('Waiting for task events on queue: ' + queueName);
    var queue = this.connection.queue(
                    queueName, { autoDelete: true }, queueCallback);

    function queueCallback() {
        var rk = common.dotjoin(
                    self.resource, '*', 'event', '*', self.clientId, '*');

        self.log.info('Binding to: ' + rk);
        queue.bind('amq.topic', rk);

        queue.subscribe(function (msg, headers, deliveryInfo) {
            var rkParts = deliveryInfo.routingKey.split('.');
            var eventType = rkParts[3];
            var taskId = rkParts[5];
            if (self.taskHandles[taskId]) {
                self.taskHandles[taskId].emit('event', eventType, msg);
                if (eventType === 'finish') {
                    clearTimeout(self.taskHandles[taskId].timeout);
                    self.taskHandles[taskId].removeAllListeners();
                    delete self.taskHandles[taskId];
                }
            }
        });
        callback();
    }
};

function TaskHandle(id) {
    EventEmitter.call(this);
    this.id = id;
    this.timeout = null;
}

util.inherits(TaskHandle, EventEmitter);

AgentHandle.prototype.sendTask = function (task, msg, callback) {
    var self = this;

    self.log.debug('Sending task to %s', self.uuid);
    msg.task_id = common.genId();
    msg.client_id = self.clientId;

    var taskHandle
        = this.taskHandles[msg.task_id]
        = new TaskHandle(msg.task_id);

    var routingKey = common.dotjoin(this.resource, this.uuid, 'task', task);

    self.log.debug(
        { message: msg },
        'Publishing message to routing key: "' + routingKey + '"');
    self.exchange.publish(routingKey, msg);

    taskHandle.timeout = setTimeout(function () {
        self.log.error(
            'Task (%s) to (%s) timed out after %d seconds.',
            task, self.uuid, self.commandTimeout * 1000);
        self.taskHandles[msg.task_id].removeAllListeners();
        delete self.taskHandles[msg.task_id];
    }, self.commandTimeout * 1000);
    callback(taskHandle);
};

module.exports = Client;
<|endoftext|>


<commit_before>'use strict';
var Promise = require('bluebird');
var auth = Promise.promisify(require('google-auth2-service-account').auth);
var scope = 'https://www.googleapis.com/auth/mapsengine';
var rawRequest = Promise.promisify(require('request'));
var Deque = require('double-ended-queue');
var fs = require('fs');
var Bulk = require('./bulk');
var limits = require('./limits.json');
var Stream = require('./stream');
var FeatureStream = require('./featureStream');
var readFile = Promise.promisify(fs.readFile, fs);
var TRUE = Promise.resolve(true);
module.exports = GME;
function GME(key, email, table, opts) {
  if (Buffer.isBuffer(key)) {
    this.key = Promise.resolve(key);
  } else {
    this.key = readFile(key);
  }
  if (typeof opts === 'string') {
    opts = {
      primary: opts
    };
  }
  this.iss = email;
  this.tableid = table;
  opts = opts || {};
  this.primary = opts.primary || 'gx_id';
  this.verbose = !!opts.verbose;
  this.nogeo = !!opts.nogeo;
  this.stopOnError = !!opts.stopOnError;
  if (opts.trace) {
    this.trace = opts.trace;
  } else {
    this.trace = false;
  }
  this.baseurl = 'https://www.googleapis.com/mapsengine/v1/';
  this.queue = new Deque();
  this.inProgress = false;
  if (opts.limits && typeof opts.limits === 'object') {
    this.limits = opts.limits;
  } else if (typeof opts.limits === 'string') {
    if (limits[opts.limits]) {
      this.limits = limits[opts.limits];
    }
  }
}

GME.prototype._request = function (opts) {
  return rawRequest(opts).then(function (resp) {
    resp = resp[1];
    if (resp && resp.error) {
      throw resp.error;
    }
    return resp;
  });
};
GME.prototype.request = function (opts) {
  if (this.inProgress) {
    var resolver = Promise.defer();
    this.queue.push({
      resolver: resolver,
      opts: opts
    });
    return resolver.promise;
  }
  return this.createRequest(opts);
};
GME.prototype.createRequest = function (opts) {
  var self = this;
  this.inProgress = true;
  var tries = 1;
  function attemptDownload(){
    return self.auth().then(function (auth) {
      opts.headers = {
        Authorization: 'Bearer ' + auth
      };
      return self._request(opts);
    }).catch(function (err) {
      if (tries++ > 10 || [401, 403, 429].indexOf(err.code) === -1 || self.stopOnError) {
        var error = new Error(err.message);
        error.code = err.code;
        error.errors = err.errors;
        if (self.verbose) {
          if (self.nogeo) {
            try {
              opts.body.features = opts.body.features.map(function (feature) {
                delete feature.geometry;
                return feature;
              });
            } catch(e) {}
          }
          console.log(new Date());
          console.log(err);
          console.log(JSON.stringify(opts, false, 4));
        }
        throw error;
      }
      return Promise.delay(tries * 1000).then(function () {
        return attemptDownload();
      });
    });
  }
  return attemptDownload().finally(function () {
    if (self.queue.length) {
      var next = self.queue.shift();
      next.resolver.resolve(self.createRequest(next.opts));
      return;
    }
    self.inProgress = false;
  });
};

GME.prototype.init = function () {
  var self = this;
  return this.key.then(function (key) {
    return auth(key, {
      iss: self.iss,
      scope: scope
    }).then(function (token) {
      if (self.timeout) {
        clearTimeout(self.timeout);
        self.timeout = null;
      }
      self.token = token;
      self.timeout = setTimeout(function () {
        self.token = null;
        self.timeout = null;
      }, 5 * 60 * 1000);
      return token;
    });
  });
};
GME.prototype.auth = function () {
  if (this.token) {
    return Promise.resolve(this.token);
  } else {
    return this.init();
  }
};
GME.prototype.get = function (url, qs) {
  qs = qs || {};
  url = this.baseurl + url;
  var self = this;
  if (this.trace) {
    qs.trace = this.trace;
  }

  return self.request({
    url: url,
    qs: qs,
    json: true
  });
};
GME.prototype.post = function (url, body) {
  url = this.baseurl + url;
  var self = this;
  var opts = {
    url: url,

    body: body,
    json: true,
    method: 'POST'
  };
  if (self.trace) {
    opts.qs = {
      trace: self.trace
    };
  }
  return self.request(opts);
};
GME.prototype.info = function () {
  return this.get('tables/' + this.tableid);
};
GME.prototype.features = function (query) {
  var self = this;
  return new Promise(function (resolve, reject) {
    var out = {
      type: 'FeatureCollection',
      features: []
    };
    self.readStream(query).on('data', function (d) {
      out.features.push(d);
    }).on('finish', function () {
      resolve(out);
    }).on('error', reject);
  });
};
GME.prototype.featureStream = GME.prototype.readStream = function (query) {
  query = query || {};
  return new FeatureStream(this, query);
};
GME.prototype.feature = function (id) {
  return this.get('tables/' + this.tableid + '/features/' + id);
};
GME.prototype.create = function(arr) {
  if (this.verbose && arr.length) {
    console.log(new Date());
    console.log('create', arr.length);
    arr.forEach(function (item) {
      console.log(item.properties[this.primary]);
    }, this);
  }
  if (!arr.length) {
    return TRUE;
  }
  return this.post('tables/' + this.tableid + '/features/batchInsert', {features: arr});
};
GME.prototype.update = function(arr) {
  if (this.verbose && arr.length) {
    console.log(new Date());
    console.log('update', arr.length);
  }
  if (!arr.length) {
    return TRUE;
  }
  return this.post('tables/' + this.tableid + '/features/batchPatch', {features: arr});
};
GME.prototype.remove = function(arr) {
  if (this.verbose && arr.length) {
    console.log(new Date());
    console.log('remove', arr.length);
    arr.forEach(function (item) {
      console.log(item);
    }, this);
    console.log(this.tableid);
  }
  if (!arr.length) {
    return TRUE;
  }
  var self = this;
  function makeQuery(item) {
    var query = {where: self.primary + '=\'' + item + '\''};
    return self.features(query).then(function (resp) {
      if (!resp.features.length) {
        return item;
      }
      console.log(item, resp.features[0].properties.gx_id);
      return resp.features[0].properties.gx_id || item;
    });
  }
  if (this.primary !== 'gx_id') {
    return Promise.all(arr.map(makeQuery)).then(function (arr) {
      return self.post('tables/' + self.tableid + '/features/batchDelete', {primaryKeys: arr});
    });
  } else {
    return self.post('tables/' + self.tableid + '/features/batchDelete', {primaryKeys: arr});
  }
};

GME.prototype.bulk = function() {
  return new Bulk(this);
};
GME.prototype.writeStream = function() {
  return new Stream(this);
};
<commit_msg>more cleanup<commit_after>'use strict';
var Promise = require('bluebird');
var auth = Promise.promisify(require('google-auth2-service-account').auth);
var scope = 'https://www.googleapis.com/auth/mapsengine';
var rawRequest = Promise.promisify(require('request'));
var Deque = require('double-ended-queue');
var fs = require('fs');
var Bulk = require('./bulk');
var limits = require('./limits.json');
var Stream = require('./stream');
var FeatureStream = require('./featureStream');
var readFile = Promise.promisify(fs.readFile, fs);
var TRUE = Promise.resolve(true);
module.exports = GME;
function GME(key, email, table, opts) {
  if (Buffer.isBuffer(key)) {
    this.key = Promise.resolve(key);
  } else {
    this.key = readFile(key);
  }
  if (typeof opts === 'string') {
    opts = {
      primary: opts
    };
  }
  this.iss = email;
  this.tableid = table;
  opts = opts || {};
  this.primary = opts.primary || 'gx_id';
  this.verbose = !!opts.verbose;
  this.nogeo = !!opts.nogeo;
  this.stopOnError = !!opts.stopOnError;
  if (opts.trace) {
    this.trace = opts.trace;
  } else {
    this.trace = false;
  }
  this.baseurl = 'https://www.googleapis.com/mapsengine/v1/';
  this.queue = new Deque();
  this.inProgress = false;
  if (opts.limits && typeof opts.limits === 'object') {
    this.limits = opts.limits;
  } else if (typeof opts.limits === 'string') {
    if (limits[opts.limits]) {
      this.limits = limits[opts.limits];
    }
  }
}

GME.prototype._request = function (opts) {
  return rawRequest(opts).then(function (resp) {
    resp = resp[1];
    if (resp && resp.error) {
      throw resp.error;
    }
    return resp;
  });
};
GME.prototype.request = function (opts) {
  if (this.inProgress) {
    var resolver = Promise.defer();
    this.queue.push({
      resolver: resolver,
      opts: opts
    });
    return resolver.promise;
  }
  return this.createRequest(opts);
};
GME.prototype.createRequest = function (opts) {
  var self = this;
  this.inProgress = true;
  var tries = 1;
  function attemptDownload(){
    return self.auth().then(function (auth) {
      opts.headers = {
        Authorization: 'Bearer ' + auth
      };
      return self._request(opts);
    }).catch(function (err) {
      if (tries++ > 10 || [401, 403, 429].indexOf(err.code) === -1 || self.stopOnError) {
        var error = new Error(err.message);
        error.code = err.code;
        error.errors = err.errors;
        if (self.verbose) {
          if (self.nogeo) {
            try {
              opts.body.features = opts.body.features.map(function (feature) {
                delete feature.geometry;
                return feature;
              });
            } catch(e) {}
          }
          console.log(new Date());
          console.log(err);
          console.log(JSON.stringify(opts, false, 4));
        }
        throw error;
      }
      return Promise.delay(tries * 1000).then(function () {
        return attemptDownload();
      });
    });
  }
  return attemptDownload().finally(function () {
    if (self.queue.length) {
      var next = self.queue.shift();
      next.resolver.resolve(self.createRequest(next.opts));
      return;
    }
    self.inProgress = false;
  });
};

GME.prototype.init = function () {
  var self = this;
  return this.key.then(function (key) {
    return auth(key, {
      iss: self.iss,
      scope: scope
    }).then(function (token) {
      if (self.timeout) {
        clearTimeout(self.timeout);
        self.timeout = null;
      }
      self.token = token;
      self.timeout = setTimeout(function () {
        self.token = null;
        self.timeout = null;
      }, 5 * 60 * 1000);
      return token;
    });
  });
};
GME.prototype.auth = function () {
  if (this.token) {
    return Promise.resolve(this.token);
  } else {
    return this.init();
  }
};
GME.prototype.get = function (url, qs) {
  qs = qs || {};
  url = this.baseurl + url;
  var self = this;
  if (this.trace) {
    qs.trace = this.trace;
  }

  return self.request({
    url: url,
    qs: qs,
    json: true
  });
};
GME.prototype.post = function (url, body) {
  url = this.baseurl + url;
  var self = this;
  var opts = {
    url: url,

    body: body,
    json: true,
    method: 'POST'
  };
  if (self.trace) {
    opts.qs = {
      trace: self.trace
    };
  }
  return self.request(opts);
};
GME.prototype.info = function () {
  return this.get('tables/' + this.tableid);
};
GME.prototype.features = function (query) {
  var self = this;
  return new Promise(function (resolve, reject) {
    var out = {
      type: 'FeatureCollection',
      features: []
    };
    self.readStream(query).on('data', function (d) {
      out.features.push(d);
    }).on('finish', function () {
      resolve(out);
    }).on('error', reject);
  });
};
GME.prototype.featureStream = GME.prototype.readStream = function (query) {
  query = query || {};
  return new FeatureStream(this, query);
};
GME.prototype.feature = function (id) {
  return this.get('tables/' + this.tableid + '/features/' + id);
};
GME.prototype.create = function(arr) {
  if (this.verbose && arr.length) {
    console.log(new Date());
    console.log('create', arr.length);
    arr.forEach(function (item) {
      console.log(item.properties[this.primary]);
    }, this);
  }
  if (!arr.length) {
    return TRUE;
  }
  return this.post('tables/' + this.tableid + '/features/batchInsert', {features: arr});
};
GME.prototype.update = function(arr) {
  if (this.verbose && arr.length) {
    console.log(new Date());
    console.log('update', arr.length);
  }
  if (!arr.length) {
    return TRUE;
  }
  return this.post('tables/' + this.tableid + '/features/batchPatch', {features: arr});
};
GME.prototype.remove = function(arr) {
  if (this.verbose && arr.length) {
    console.log(new Date());
    console.log('remove', arr.length);
    arr.forEach(function (item) {
      console.log(item);
    }, this);
    console.log(this.tableid);
  }
  if (!arr.length) {
    return TRUE;
  }
  var self = this;
  if (this.primary !== 'gx_id') {
    return Promise.all(arr.map(this._fetchPrimaryKey, this)).then(function (arr) {
      return self.post('tables/' + self.tableid + '/features/batchDelete', {primaryKeys: arr});
    });
  } else {
    return self.post('tables/' + self.tableid + '/features/batchDelete', {primaryKeys: arr});
  }
};
GME.prototype._fetchPrimaryKey = function (item) {
  var query = {where: this.primary + '=\'' + item + '\''};
  return this.features(query).then(function (resp) {
    if (!resp.features.length) {
      return item;
    }
    console.log(item, resp.features[0].properties.gx_id);
    return resp.features[0].properties.gx_id || item;
  });
};

GME.prototype.bulk = function() {
  return new Bulk(this);
};
GME.prototype.writeStream = function() {
  return new Stream(this);
};
<|endoftext|>


<commit_before>var path = require('path');

var defaultPlugins = [
  require('./plugins/JsDocExtractorPlugin'),
  require('./plugins/SourceLastModifiedPlugin')
];

/**
 * @typedef {Object} DocsPluginConfig
 */
module.exports = {
  test: /\.js$/,
  exclude: /node_modules/,

  plugins: defaultPlugins.map(function(Plugin) {
    return new Plugin
  }),

  extractor: null,
  extractorOptions: null,

  page: {
    name: 'docs/[path][name].[ext]/index.html',
    template: path.resolve(__dirname, '../assets/templates/page.twig'),
    templateContext: null,
    render: true,
    emit: true
  },

  example: {
    name: '[doc-path]/examples/[example-id].html',
    template: path.resolve(__dirname, '../assets/templates/example.twig'),
    templateContext: null,
    render: true,
    emit: true,

    files: {
      compile: ['js'],
      emit: true,
      webpackConfig: null
    }
  },

  templateEngine: {
    name: 'twig',
    cache: true,
    context: null
  }
};<commit_msg>Config refactoring<commit_after>/**
 * @typedef {Object} DocsPluginConfig
 */
module.exports = {
  test: /\.js$/,
  exclude: /node_modules/,

  plugins: [
    require('./plugins/JsDocExtractorPlugin')

  ].map(function (Plugin) {
    return new Plugin
  }),

  extractor: null,
  extractorOptions: null
};<|endoftext|>


<commit_before>module.exports = Queue

function Queue(stream) {
    var ended = false
        , array = []
        , queue = {
            shift: shift
            , push: push
            , end: end
            , length: 0
        }

    return queue

    function shift() {
        var chunk = array.shift()
        if (ended && array.length === 0) {
            process.nextTick(stream.end)
        }
        queue.length = array.length
        return chunk
    }

    function push(chunk) {
        if (ended) {
            return
        } else if (chunk === null) {
            return end()
        }

        array.push(chunk)
        if (array.length === 1) {
            stream.emit("readable")
        }

        queue.length = array.length
    }

    function end() {
        if (ended) {
            return
        }

        ended = true
        if (array.length === 0) {
            stream.emit("end")
        }
    }
}
<commit_msg>fix bug with end<commit_after>module.exports = Queue

function Queue(stream) {
    var ended = false
        , array = []
        , queue = {
            shift: shift
            , push: push
            , end: end
            , length: 0
        }

    return queue

    function shift() {
        var chunk = array.shift()
        if (ended && array.length === 0) {
            process.nextTick(emitEnd)
        }
        queue.length = array.length
        return chunk
    }

    function push(chunk) {
        if (ended) {
            return
        } else if (chunk === null) {
            return end()
        }

        array.push(chunk)
        if (array.length === 1) {
            stream.emit("readable")
        }

        queue.length = array.length
    }

    function end() {
        if (ended) {
            return
        }

        ended = true
        if (array.length === 0) {
            stream.emit("end")
        }
    }

    function emitEnd() {
        stream.emit("end")
    }
}
<|endoftext|>


<commit_before>import _ from 'lodash';
import _request from 'request';
import { Promise } from 'rsvp';

const DEFAULT_HOST = "take2-loopback.herokuapp.com";
const DEFAULT_PORT = 80;
const BASE_PATH    = "/api/v1/";

export function buildOptions(method, path, data) {
  let url = [
    'http://', DEFAULT_HOST, ':', DEFAULT_PORT, BASE_PATH, path
  ].join('');

  let options = {
    url    : url,
    method : method
  };

  if(data) {
    options.json = data;
  }

  if(this.headers) {
    options.headers = this.headers;
  }

  return options;
}

const methods = {
  products: {
    list()           { return this.get('products'); },
    retrieve(id)     { return this.get('products/'+id); },
    create(data)     { return this.post('products', data); },
    update(id, data) { return this.put('products/'+id, data); },
    destroy(id)      { return this.del('products/'+id); }
  },
  visitorTokens: {
    // list()           { return this.get('visitorTokens'); },
    // retrieve(id)     { return this.get('visitorTokens/'+id); },
    create(data)     { return this.post('visitorTokens', data); }
    // update(id, data) { return this.put('visitorTokens/'+id, data); },
    // destroy(id)      { return this.del('visitorTokens/'+id); }
  }
};

function Take2(key, options) {
  if(!(this instanceof Take2)) {
    return new Take2(key, options);
  }

  this.options = options || {};

  if(!key) {
    throw new Error('Missing API Key');
  }

  if(this.options.spyable) {
    this._spyable = true;
    this.REQUESTS = [];
  }

  this._key = key;

  this.headers = {
    'Authorization' : `Basic ${key}`,
    'Content-Type'  : 'application/json'
  };

  _.each(methods, (block, resource) => {
    this[resource] = this[resource] || {};
    _.each(block, (method, key) => {
      this[resource][key] = method.bind(this);
    });
  });
}

Take2.prototype = {

  constructor: Take2,

  buildOptions(method, path, data) {
    let url = [
      'http://',
      this.options.DEFAULT_HOST || DEFAULT_HOST,
      ':',
      this.options.DEFAULT_PORT || DEFAULT_PORT,
      this.options.BASE_PATH || BASE_PATH,
      path
    ].join('');

    let options = {
      url    : url,
      method : method
    };

    if(data) {
      options.json = data;
    }

    if(this.headers) {
      options.headers = this.headers;
    }

    return options;
  },

  get(path, data) {
    return this.request('GET', path, data);
  },

  post(path, data) {
    return this.request('POST', path, data);
  },

  put(path, data) {
    return this.request('PUT', path, data);
  },

  del(path, data) {
    return this.request('DELETE', path, data);
  },

  request(method, path, data) {
    let options = this.buildOptions(...arguments);

    console.log(options);

    if(this._spyable) {
      this.LAST_REQUEST = options;
      this.REQUESTS.push(options);
    } else {
      return new Promise((resolve, reject) => {
        _request(options, function(err, res, body) {
          if(err) {
            return reject(err);
          } else {
            try {
              let data = JSON.parse(body);
              resolve(data);
            } catch(e) {
              reject('Unabled to parse response body.');
            }
          }
        });
      });
    }

  }
}

module.exports = Take2;
<commit_msg>remove log<commit_after>import _ from 'lodash';
import _request from 'request';
import { Promise } from 'rsvp';

const DEFAULT_HOST = "take2-loopback.herokuapp.com";
const DEFAULT_PORT = 80;
const BASE_PATH    = "/api/v1/";

export function buildOptions(method, path, data) {
  let url = [
    'http://', DEFAULT_HOST, ':', DEFAULT_PORT, BASE_PATH, path
  ].join('');

  let options = {
    url    : url,
    method : method
  };

  if(data) {
    options.json = data;
  }

  if(this.headers) {
    options.headers = this.headers;
  }

  return options;
}

const methods = {
  products: {
    list()           { return this.get('products'); },
    retrieve(id)     { return this.get('products/'+id); },
    create(data)     { return this.post('products', data); },
    update(id, data) { return this.put('products/'+id, data); },
    destroy(id)      { return this.del('products/'+id); }
  },
  visitorTokens: {
    // list()           { return this.get('visitorTokens'); },
    // retrieve(id)     { return this.get('visitorTokens/'+id); },
    create(data)     { return this.post('visitorTokens', data); }
    // update(id, data) { return this.put('visitorTokens/'+id, data); },
    // destroy(id)      { return this.del('visitorTokens/'+id); }
  }
};

function Take2(key, options) {
  if(!(this instanceof Take2)) {
    return new Take2(key, options);
  }

  this.options = options || {};

  if(!key) {
    throw new Error('Missing API Key');
  }

  if(this.options.spyable) {
    this._spyable = true;
    this.REQUESTS = [];
  }

  this._key = key;

  this.headers = {
    'Authorization' : `Basic ${key}`,
    'Content-Type'  : 'application/json'
  };

  _.each(methods, (block, resource) => {
    this[resource] = this[resource] || {};
    _.each(block, (method, key) => {
      this[resource][key] = method.bind(this);
    });
  });
}

Take2.prototype = {

  constructor: Take2,

  buildOptions(method, path, data) {
    let url = [
      'http://',
      this.options.DEFAULT_HOST || DEFAULT_HOST,
      ':',
      this.options.DEFAULT_PORT || DEFAULT_PORT,
      this.options.BASE_PATH || BASE_PATH,
      path
    ].join('');

    let options = {
      url    : url,
      method : method
    };

    if(data) {
      options.json = data;
    }

    if(this.headers) {
      options.headers = this.headers;
    }

    return options;
  },

  get(path, data) {
    return this.request('GET', path, data);
  },

  post(path, data) {
    return this.request('POST', path, data);
  },

  put(path, data) {
    return this.request('PUT', path, data);
  },

  del(path, data) {
    return this.request('DELETE', path, data);
  },

  request(method, path, data) {
    let options = this.buildOptions(...arguments);

    if(this._spyable) {
      this.LAST_REQUEST = options;
      this.REQUESTS.push(options);
    } else {
      return new Promise((resolve, reject) => {
        _request(options, function(err, res, body) {
          if(err) {
            return reject(err);
          } else {
            try {
              let data = JSON.parse(body);
              resolve(data);
            } catch(e) {
              reject('Unabled to parse response body.');
            }
          }
        });
      });
    }

  }
}

module.exports = Take2;
<|endoftext|>


<commit_before>'use strict';

var stringify = require('json-stringify-safe');
var parsers = require('./parsers');
var zlib = require('zlib');
var utils = require('./utils');
var uuid = require('node-uuid');
var transports = require('./transports');
var nodeUtil = require('util'); // nodeUtil to avoid confusion with "utils"
var events = require('events');
var domain = require('domain');

var extend = utils.extend;

function Raven() {}

nodeUtil.inherits(Raven, events.EventEmitter);

extend(Raven.prototype, {
  config: function config(dsn, options) {
    if (arguments.length === 0) {
      // no arguments, use default from environment
      dsn = process.env.SENTRY_DSN;
      options = {};
    }
    if (typeof dsn === 'object') {
      // They must only be passing through options
      options = dsn;
      dsn = process.env.SENTRY_DSN;
    }
    options = options || {};

    this.raw_dsn = dsn;
    this.dsn = utils.parseDSN(dsn);
    this.name = options.name || process.env.SENTRY_NAME || require('os').hostname();
    this.root = options.root || process.cwd();
    this.transport = options.transport || transports[this.dsn.protocol];
    this.release = options.release || process.env.SENTRY_RELEASE || '';
    this.environment = options.environment || process.env.SENTRY_ENVIRONMENT || '';

    this.loggerName = options.logger || '';
    this.dataCallback = options.dataCallback;
    this.shouldSendCallback = options.shouldSendCallback;

    if (!this.dsn) {
      utils.consoleAlert('no DSN provided, error reporting disabled');
    }

    if (this.dsn.protocol === 'https') {
      // In case we want to provide our own SSL certificates / keys
      this.ca = options.ca || null;
    }

    // enabled if a dsn is set
    this._enabled = !!this.dsn;

    var globalContext = this._globalContext = {};
    if (options.tags) {
      globalContext.tags = options.tags;
    }
    if (options.extra) {
      globalContext.extra = options.extra;
    }

    this.on('error', function (err) {
      utils.consoleAlert('failed to send exception to sentry: ' + err.message);
    });

    return this;
  },

  install: function install(opts, cb) {
    if (typeof opts === 'function') {
      cb = opts;
    }

    registerExceptionHandler(this, cb);
    if (opts && opts.unhandledRejection) {
      registerRejectionHandler(this, cb);
    }
    return this;
  },

  generateEventId: function generateEventId() {
    return uuid().replace(/-/g, '');
  },

  process: function process(eventId, kwargs, cb) {
    // prod codepaths shouldn't hit this branch, for testing
    if (typeof eventId === 'object') {
      cb = kwargs;
      kwargs = eventId;
      eventId = this.generateEventId();
    }

    var domainContext = domain.active && domain.active.sentryContext || {};
    kwargs.user = extend({}, this._globalContext.user, domainContext.user, kwargs.user);
    kwargs.tags = extend({}, this._globalContext.tags, domainContext.tags, kwargs.tags);
    kwargs.extra = extend({}, this._globalContext.extra, domainContext.extra, kwargs.extra);

    kwargs.modules = utils.getModules();
    kwargs.server_name = kwargs.server_name || this.name;

    if (typeof process.version !== 'undefined') {
      kwargs.extra.node = process.version;
    }

    kwargs.environment = kwargs.environment || this.environment;
    kwargs.logger = kwargs.logger || this.loggerName;
    kwargs.event_id = eventId;
    kwargs.timestamp = new Date().toISOString().split('.')[0];
    kwargs.project = this.dsn.project_id;
    kwargs.platform = 'node';

    // Only include release information if it is set
    if (this.release) {
      kwargs.release = this.release;
    }

    if (this.dataCallback) {
      kwargs = this.dataCallback(kwargs);
    }

    var shouldSend = true;
    if (!this._enabled) shouldSend = false;
    if (this.shouldSendCallback && !this.shouldSendCallback()) shouldSend = false;

    if (shouldSend) {
      this.send(kwargs, cb);
    } else {
      // wish there was a good way to communicate to cb why we didn't send; worth considering cb api change?
      // avoiding setImmediate here because node 0.8
      setTimeout(function () {
        cb(null, eventId);
      }, 0);
    }
  },

  send: function send(kwargs, cb) {
    var self = this;
    var skwargs = stringify(kwargs);
    var eventId = kwargs.event_id;

    zlib.deflate(skwargs, function (err, buff) {
      var message = buff.toString('base64'),
          timestamp = new Date().getTime(),
          headers = {
            'X-Sentry-Auth': utils.getAuthHeader(timestamp, self.dsn.public_key, self.dsn.private_key),
            'Content-Type': 'application/octet-stream',
            'Content-Length': message.length
          };

      self.transport.send(self, message, headers, eventId, cb);
    });
  },

  captureMessage: function captureMessage(message, kwargs, cb) {
    if (!cb && typeof kwargs === 'function') {
      cb = kwargs;
      kwargs = {};
    } else {
      kwargs = kwargs || {};
    }
    var eventId = this.generateEventId();
    this.process(eventId, parsers.parseText(message, kwargs), cb);

    return eventId;
  },

  captureException: function captureException(err, kwargs, cb) {
    if (!(err instanceof Error)) {
      // This handles when someone does:
      //   throw "something awesome";
      // We synthesize an Error here so we can extract a (rough) stack trace.
      err = new Error(err);
    }

    if (!cb && typeof kwargs === 'function') {
      cb = kwargs;
      kwargs = {};
    } else {
      kwargs = kwargs || {};
    }

    var self = this;
    var eventId = this.generateEventId();
    parsers.parseError(err, kwargs, function (kw) {
      self.process(eventId, kw, cb);
    });

    return eventId;
  },

  captureQuery: function captureQuery(query, engine, kwargs, cb) {
    if (!cb && typeof kwargs === 'function') {
      cb = kwargs;
      kwargs = {};
    } else {
      kwargs = kwargs || {};
    }

    var eventId = this.generateEventId();
    this.process(eventId, parsers.parseQuery(query, engine, kwargs), cb);

    return eventId;
  },

  /* The onErr param here is sort of ugly and won't typically be used
   * but it lets us write the requestHandler middleware in terms of this function.
   * We could consider getting rid of it and just duplicating the domain
   * instantiation etc logic in the requestHandler middleware
   */
  context: function (ctx, func, onErr) {
    if (!func && typeof ctx === 'function') {
      func = ctx;
      ctx = {};
    }

    // todo/note: raven-js takes an args param to do apply(this, args)
    // i don't think it's correct/necessary to bind this to the wrap call
    // and i don't know if we need to support the args param; it's undocumented
    return this.wrap(ctx, func, onErr).apply(null);
  },

  wrap: function (options, func, onErr) {
    if (!func && typeof options === 'function') {
      func = options;
      options = {};
    }

    var wrapDomain = domain.create();
    // todo: better property name than sentryContext, maybe __raven__ or sth?
    wrapDomain.sentryContext = options;

    var self = this;
    if (typeof onErr !== 'function') {
      onErr = function (err) {
        self.captureException(err, wrapDomain.sentryContext);
      };
    }

    wrapDomain.on('error', onErr);
    var wrapped = wrapDomain.bind(func);

    for (var property in func) {
      if ({}.hasOwnProperty.call(func, property)) {
        wrapped[property] = func[property];
      }
    }
    wrapped.prototype = func.prototype;
    wrapped.__raven__ = true;
    wrapped.__inner__ = func;
    // note: domain.bind sets wrapped.domain, but it's not documented, unsure if we should rely on that
    wrapped.__domain__ = wrapDomain;

    return wrapped;
  },

  interceptErr: function (options, func) {
    if (!func && typeof options === 'function') {
      func = options;
      options = {};
    }
    var self = this;
    var wrapped = function () {
      var err = arguments[0];
      if (err instanceof Error) {
        self.captureException(err, options);
      } else {
        func.apply(null, arguments);
      }
    };

    // repetitive with wrap
    for (var property in func) {
      if ({}.hasOwnProperty.call(func, property)) {
        wrapped[property] = func[property];
      }
    }
    wrapped.prototype = func.prototype;
    wrapped.__raven__ = true;
    wrapped.__inner__ = func;

    return wrapped;
  },

  setContext: function setContext(ctx) {
    if (domain.active) {
      domain.active.sentryContext = ctx;
    } else {
      this._globalContext = ctx;
    }
    return this;
  },

  mergeContext: function mergeContext(ctx) {
    extend(this.getContext(), ctx);
    return this;
  },

  getContext: function getContext() {
    return domain.active ? domain.active.sentryContext : this._globalContext;
  },

  /*
   * Set/clear a user to be sent along with the payload.
   *
   * @param {object} user An object representing user data [optional]
   * @return {Raven}
   */
  setUserContext: function setUserContext() {
    utils.consoleAlert('setUserContext has been deprecated and will be removed in v2.0; use setContext instead');
    return this;
  },

  /*
   * Merge extra attributes to be sent along with the payload.
   *
   * @param {object} extra An object representing extra data [optional]
   * @return {Raven}
   */
  setExtraContext: function setExtraContext() {
    utils.consoleAlert('setExtraContext has been deprecated and will be removed in v2.0; use setContext instead');
    return this;
  },

  /*
   * Merge tags to be sent along with the payload.
   *
   * @param {object} tags An object representing tags [optional]
   * @return {Raven}
   */
  setTagsContext: function setTagsContext() {
    utils.consoleAlert('setTagsContext has been deprecated and will be removed in v2.0; use setContext instead');
    return this;
  },

  setCallbackHelper: function (propertyName, callback) {
    var original = this[propertyName];
    if (typeof callback === 'function') {
      this[propertyName] = function (data) {
        return callback(data, original);
      };
    } else {
      this[propertyName] = callback;
    }

    return this;
  },

  /*
   * Set the dataCallback option
   *
   * @param {function} callback The callback to run which allows the
   *                            data blob to be mutated before sending
   * @return {Raven}
   */
  setDataCallback: function (callback) {
    return this.setCallbackHelper('dataCallback', callback);
  },

  /*
   * Set the shouldSendCallback option
   *
   * @param {function} callback The callback to run which allows
   *                            introspecting the blob before sending
   * @return {Raven}
   */
  setShouldSendCallback: function (callback) {
    return this.setCallbackHelper('shouldSendCallback', callback);
  },

  requestHandler: function () {
    var self = this;
    return function (req, res, next) {
      self.context({}, next, next);
    };
  },

  errorHandler: function () {
    var self = this;
    return function (err, req, res, next) {
      var status = err.status || err.statusCode || err.status_code || 500;

      // skip anything not marked as an internal server error
      if (status < 500) return next(err);

      var kwargs = parsers.parseRequest(req);
      var eventId = self.captureException(err, kwargs);
      res.sentry = eventId;
      return next(err);
    };
  }
});

// Deprecations
extend(Raven.prototype, {
  getIdent: function getIdent(result) {
    utils.consoleAlert('getIdent has been deprecated and will be removed in v2.0');
    return result;
  },
  captureError: function captureError() {
    utils.consoleAlert('captureError has been deprecated and will be removed in v2.0');
    this.captureException.apply(this, arguments);
  },
  patchGlobal: function (cb) {
    utils.consoleAlert('patchGlobal has been deprecated and will be removed in v2.0');
    registerExceptionHandler(this, cb);
    return this;
  }
});
Raven.prototype.get_ident = Raven.prototype.getIdent;

// Maintain old API compat, need to make sure arguments length is preserved
function Client(dsn, options) {
  if (dsn instanceof Client) return dsn;
  var ravenInstance = new Raven();
  return ravenInstance.config.apply(ravenInstance, arguments);
}
nodeUtil.inherits(Client, Raven);

// Singleton-by-default but not strictly enforced
// todo these extra export props are sort of an adhoc mess, better way to manage?
var defaultInstance = new Raven();
defaultInstance.Client = Client;
defaultInstance.patchGlobal = patchGlobal;
defaultInstance.version = require('../package.json').version;
defaultInstance.disableConsoleAlerts = utils.disableConsoleAlerts;

module.exports = defaultInstance;

function registerExceptionHandler(client, cb) {
  var called = false;
  process.on('uncaughtException', function (err) {
    if (cb) { // bind event listeners only if a callback was supplied
      var onLogged = function onLogged() {
        called = false;
        cb(true, err);
      };

      var onError = function onError() {
        called = false;
        cb(false, err);
      };

      if (called) {
        client.removeListener('logged', onLogged);
        client.removeListener('error', onError);
        return cb(false, err);
      }

      client.once('logged', onLogged);
      client.once('error', onError);

      called = true;
    }

    var eventId = client.captureException(err);
    return utils.consoleAlert('uncaughtException: ' + eventId);
  });
}

function registerRejectionHandler(client, cb) {
  process.on('unhandledRejection', function (reason) {
    var eventId = client.captureException(reason, function (sendErr) {
      cb && cb(!sendErr, reason);
    });
    return utils.consoleAlert('unhandledRejection: ' + eventId);
  });
}

function patchGlobal(client, cb) {
  // handle when the first argument is the callback, with no client specified
  if (typeof client === 'function') {
    cb = client;
    client = new Client();
    // first argument is a string DSN
  } else if (typeof client === 'string') {
    client = new Client(client);
  }
  // at the end, if we still don't have a Client, let's make one!
  !(client instanceof Raven) && (client = new Client());

  registerExceptionHandler(client, cb);
}
<commit_msg>Move set*Context to deprecations, fix captureError return value (#227)<commit_after>'use strict';

var stringify = require('json-stringify-safe');
var parsers = require('./parsers');
var zlib = require('zlib');
var utils = require('./utils');
var uuid = require('node-uuid');
var transports = require('./transports');
var nodeUtil = require('util'); // nodeUtil to avoid confusion with "utils"
var events = require('events');
var domain = require('domain');

var extend = utils.extend;

function Raven() {}

nodeUtil.inherits(Raven, events.EventEmitter);

extend(Raven.prototype, {
  config: function config(dsn, options) {
    if (arguments.length === 0) {
      // no arguments, use default from environment
      dsn = process.env.SENTRY_DSN;
      options = {};
    }
    if (typeof dsn === 'object') {
      // They must only be passing through options
      options = dsn;
      dsn = process.env.SENTRY_DSN;
    }
    options = options || {};

    this.raw_dsn = dsn;
    this.dsn = utils.parseDSN(dsn);
    this.name = options.name || process.env.SENTRY_NAME || require('os').hostname();
    this.root = options.root || process.cwd();
    this.transport = options.transport || transports[this.dsn.protocol];
    this.release = options.release || process.env.SENTRY_RELEASE || '';
    this.environment = options.environment || process.env.SENTRY_ENVIRONMENT || '';

    this.loggerName = options.logger || '';
    this.dataCallback = options.dataCallback;
    this.shouldSendCallback = options.shouldSendCallback;

    if (!this.dsn) {
      utils.consoleAlert('no DSN provided, error reporting disabled');
    }

    if (this.dsn.protocol === 'https') {
      // In case we want to provide our own SSL certificates / keys
      this.ca = options.ca || null;
    }

    // enabled if a dsn is set
    this._enabled = !!this.dsn;

    var globalContext = this._globalContext = {};
    if (options.tags) {
      globalContext.tags = options.tags;
    }
    if (options.extra) {
      globalContext.extra = options.extra;
    }

    this.on('error', function (err) {
      utils.consoleAlert('failed to send exception to sentry: ' + err.message);
    });

    return this;
  },

  install: function install(opts, cb) {
    if (typeof opts === 'function') {
      cb = opts;
    }

    registerExceptionHandler(this, cb);
    if (opts && opts.unhandledRejection) {
      registerRejectionHandler(this, cb);
    }
    return this;
  },

  generateEventId: function generateEventId() {
    return uuid().replace(/-/g, '');
  },

  process: function process(eventId, kwargs, cb) {
    // prod codepaths shouldn't hit this branch, for testing
    if (typeof eventId === 'object') {
      cb = kwargs;
      kwargs = eventId;
      eventId = this.generateEventId();
    }

    var domainContext = domain.active && domain.active.sentryContext || {};
    kwargs.user = extend({}, this._globalContext.user, domainContext.user, kwargs.user);
    kwargs.tags = extend({}, this._globalContext.tags, domainContext.tags, kwargs.tags);
    kwargs.extra = extend({}, this._globalContext.extra, domainContext.extra, kwargs.extra);

    kwargs.modules = utils.getModules();
    kwargs.server_name = kwargs.server_name || this.name;

    if (typeof process.version !== 'undefined') {
      kwargs.extra.node = process.version;
    }

    kwargs.environment = kwargs.environment || this.environment;
    kwargs.logger = kwargs.logger || this.loggerName;
    kwargs.event_id = eventId;
    kwargs.timestamp = new Date().toISOString().split('.')[0];
    kwargs.project = this.dsn.project_id;
    kwargs.platform = 'node';

    // Only include release information if it is set
    if (this.release) {
      kwargs.release = this.release;
    }

    if (this.dataCallback) {
      kwargs = this.dataCallback(kwargs);
    }

    var shouldSend = true;
    if (!this._enabled) shouldSend = false;
    if (this.shouldSendCallback && !this.shouldSendCallback()) shouldSend = false;

    if (shouldSend) {
      this.send(kwargs, cb);
    } else {
      // wish there was a good way to communicate to cb why we didn't send; worth considering cb api change?
      // avoiding setImmediate here because node 0.8
      setTimeout(function () {
        cb(null, eventId);
      }, 0);
    }
  },

  send: function send(kwargs, cb) {
    var self = this;
    var skwargs = stringify(kwargs);
    var eventId = kwargs.event_id;

    zlib.deflate(skwargs, function (err, buff) {
      var message = buff.toString('base64'),
          timestamp = new Date().getTime(),
          headers = {
            'X-Sentry-Auth': utils.getAuthHeader(timestamp, self.dsn.public_key, self.dsn.private_key),
            'Content-Type': 'application/octet-stream',
            'Content-Length': message.length
          };

      self.transport.send(self, message, headers, eventId, cb);
    });
  },

  captureMessage: function captureMessage(message, kwargs, cb) {
    if (!cb && typeof kwargs === 'function') {
      cb = kwargs;
      kwargs = {};
    } else {
      kwargs = kwargs || {};
    }
    var eventId = this.generateEventId();
    this.process(eventId, parsers.parseText(message, kwargs), cb);

    return eventId;
  },

  captureException: function captureException(err, kwargs, cb) {
    if (!(err instanceof Error)) {
      // This handles when someone does:
      //   throw "something awesome";
      // We synthesize an Error here so we can extract a (rough) stack trace.
      err = new Error(err);
    }

    if (!cb && typeof kwargs === 'function') {
      cb = kwargs;
      kwargs = {};
    } else {
      kwargs = kwargs || {};
    }

    var self = this;
    var eventId = this.generateEventId();
    parsers.parseError(err, kwargs, function (kw) {
      self.process(eventId, kw, cb);
    });

    return eventId;
  },

  captureQuery: function captureQuery(query, engine, kwargs, cb) {
    if (!cb && typeof kwargs === 'function') {
      cb = kwargs;
      kwargs = {};
    } else {
      kwargs = kwargs || {};
    }

    var eventId = this.generateEventId();
    this.process(eventId, parsers.parseQuery(query, engine, kwargs), cb);

    return eventId;
  },

  /* The onErr param here is sort of ugly and won't typically be used
   * but it lets us write the requestHandler middleware in terms of this function.
   * We could consider getting rid of it and just duplicating the domain
   * instantiation etc logic in the requestHandler middleware
   */
  context: function (ctx, func, onErr) {
    if (!func && typeof ctx === 'function') {
      func = ctx;
      ctx = {};
    }

    // todo/note: raven-js takes an args param to do apply(this, args)
    // i don't think it's correct/necessary to bind this to the wrap call
    // and i don't know if we need to support the args param; it's undocumented
    return this.wrap(ctx, func, onErr).apply(null);
  },

  wrap: function (options, func, onErr) {
    if (!func && typeof options === 'function') {
      func = options;
      options = {};
    }

    var wrapDomain = domain.create();
    // todo: better property name than sentryContext, maybe __raven__ or sth?
    wrapDomain.sentryContext = options;

    var self = this;
    if (typeof onErr !== 'function') {
      onErr = function (err) {
        self.captureException(err, wrapDomain.sentryContext);
      };
    }

    wrapDomain.on('error', onErr);
    var wrapped = wrapDomain.bind(func);

    for (var property in func) {
      if ({}.hasOwnProperty.call(func, property)) {
        wrapped[property] = func[property];
      }
    }
    wrapped.prototype = func.prototype;
    wrapped.__raven__ = true;
    wrapped.__inner__ = func;
    // note: domain.bind sets wrapped.domain, but it's not documented, unsure if we should rely on that
    wrapped.__domain__ = wrapDomain;

    return wrapped;
  },

  interceptErr: function (options, func) {
    if (!func && typeof options === 'function') {
      func = options;
      options = {};
    }
    var self = this;
    var wrapped = function () {
      var err = arguments[0];
      if (err instanceof Error) {
        self.captureException(err, options);
      } else {
        func.apply(null, arguments);
      }
    };

    // repetitive with wrap
    for (var property in func) {
      if ({}.hasOwnProperty.call(func, property)) {
        wrapped[property] = func[property];
      }
    }
    wrapped.prototype = func.prototype;
    wrapped.__raven__ = true;
    wrapped.__inner__ = func;

    return wrapped;
  },

  setContext: function setContext(ctx) {
    if (domain.active) {
      domain.active.sentryContext = ctx;
    } else {
      this._globalContext = ctx;
    }
    return this;
  },

  mergeContext: function mergeContext(ctx) {
    extend(this.getContext(), ctx);
    return this;
  },

  getContext: function getContext() {
    return domain.active ? domain.active.sentryContext : this._globalContext;
  },

  setCallbackHelper: function (propertyName, callback) {
    var original = this[propertyName];
    if (typeof callback === 'function') {
      this[propertyName] = function (data) {
        return callback(data, original);
      };
    } else {
      this[propertyName] = callback;
    }

    return this;
  },

  /*
   * Set the dataCallback option
   *
   * @param {function} callback The callback to run which allows the
   *                            data blob to be mutated before sending
   * @return {Raven}
   */
  setDataCallback: function (callback) {
    return this.setCallbackHelper('dataCallback', callback);
  },

  /*
   * Set the shouldSendCallback option
   *
   * @param {function} callback The callback to run which allows
   *                            introspecting the blob before sending
   * @return {Raven}
   */
  setShouldSendCallback: function (callback) {
    return this.setCallbackHelper('shouldSendCallback', callback);
  },

  requestHandler: function () {
    var self = this;
    return function (req, res, next) {
      self.context({}, next, next);
    };
  },

  errorHandler: function () {
    var self = this;
    return function (err, req, res, next) {
      var status = err.status || err.statusCode || err.status_code || 500;

      // skip anything not marked as an internal server error
      if (status < 500) return next(err);

      var kwargs = parsers.parseRequest(req);
      var eventId = self.captureException(err, kwargs);
      res.sentry = eventId;
      return next(err);
    };
  }
});

// Deprecations
extend(Raven.prototype, {
  getIdent: function getIdent(result) {
    utils.consoleAlert('getIdent has been deprecated and will be removed in v2.0');
    return result;
  },
  captureError: function captureError() {
    utils.consoleAlert('captureError has been deprecated and will be removed in v2.0');
    return this.captureException.apply(this, arguments);
  },
  patchGlobal: function (cb) {
    utils.consoleAlert('patchGlobal has been deprecated and will be removed in v2.0');
    registerExceptionHandler(this, cb);
    return this;
  },
  setUserContext: function setUserContext() {
    utils.consoleAlert('setUserContext has been deprecated and will be removed in v2.0; use setContext instead');
    return this;
  },
  setExtraContext: function setExtraContext() {
    utils.consoleAlert('setExtraContext has been deprecated and will be removed in v2.0; use setContext instead');
    return this;
  },
  setTagsContext: function setTagsContext() {
    utils.consoleAlert('setTagsContext has been deprecated and will be removed in v2.0; use setContext instead');
    return this;
  },
});
Raven.prototype.get_ident = Raven.prototype.getIdent;

// Maintain old API compat, need to make sure arguments length is preserved
function Client(dsn, options) {
  if (dsn instanceof Client) return dsn;
  var ravenInstance = new Raven();
  return ravenInstance.config.apply(ravenInstance, arguments);
}
nodeUtil.inherits(Client, Raven);

// Singleton-by-default but not strictly enforced
// todo these extra export props are sort of an adhoc mess, better way to manage?
var defaultInstance = new Raven();
defaultInstance.Client = Client;
defaultInstance.patchGlobal = patchGlobal;
defaultInstance.version = require('../package.json').version;
defaultInstance.disableConsoleAlerts = utils.disableConsoleAlerts;

module.exports = defaultInstance;

function registerExceptionHandler(client, cb) {
  var called = false;
  process.on('uncaughtException', function (err) {
    if (cb) { // bind event listeners only if a callback was supplied
      var onLogged = function onLogged() {
        called = false;
        cb(true, err);
      };

      var onError = function onError() {
        called = false;
        cb(false, err);
      };

      if (called) {
        client.removeListener('logged', onLogged);
        client.removeListener('error', onError);
        return cb(false, err);
      }

      client.once('logged', onLogged);
      client.once('error', onError);

      called = true;
    }

    var eventId = client.captureException(err);
    return utils.consoleAlert('uncaughtException: ' + eventId);
  });
}

function registerRejectionHandler(client, cb) {
  process.on('unhandledRejection', function (reason) {
    var eventId = client.captureException(reason, function (sendErr) {
      cb && cb(!sendErr, reason);
    });
    return utils.consoleAlert('unhandledRejection: ' + eventId);
  });
}

function patchGlobal(client, cb) {
  // handle when the first argument is the callback, with no client specified
  if (typeof client === 'function') {
    cb = client;
    client = new Client();
    // first argument is a string DSN
  } else if (typeof client === 'string') {
    client = new Client(client);
  }
  // at the end, if we still don't have a Client, let's make one!
  !(client instanceof Raven) && (client = new Client());

  registerExceptionHandler(client, cb);
}
<|endoftext|>


<commit_before>/**
 * ircloggr - a node.js all-in-one implementation of irc logging visible via
 *            a REST/JSON interface.
 *
 * See LICENSE file for licensing information.
 */

// server configuration, config file parsing, and eventually command line switch
// handling.

const path = require('path'),
        fs = require('fs'),
       url = require('url');

exports.bot_name = "ircloggr";

exports.config_path = path.join(path.dirname(__dirname), "config.json");

exports.db_host = '127.0.0.1';
exports.db_port = 3306;
exports.db_user = 'ircloggr';
exports.db_pass = undefined;
exports.database = 'ircloggr';

// handle database string set in the environment
if (process.env['MYSQL_URL']) {
  var u = url.parse(process.env['MYSQL_URL']);
  exports.db_host = u.host;
  exports.db_user = u.auth.split(':')[0];
  exports.db_pass = u.auth.split(':')[1];
  exports.database = u.path.substr(1);
}

winston.info('using mysql database at ' + exports.db_host + " - " + exports.database);

exports.host = "*";

exports.port = 0 || process.env['PORT'];

exports.deployment_url = "http://irclog.gr";

exports.servers = {
};

exports.parse_config_file = function() {
    // let exceptions fly
    var conf = JSON.parse(fs.readFileSync(exports.config_path));

    for (var k in conf) {
        if (exports[k] === undefined || k.substr(0,5) === "parse")
            throw "unsupported key: " + k;
        if (exports[k] !== null && typeof exports[k] !== typeof conf[k]) {
            throw "'"+k+"' is a "+ typeof exports[k] +", it should be a " + typeof conf[k];
        }
        exports[k] = conf[k];
    }
};
<commit_msg>use logging in config.js<commit_after>/**
 * ircloggr - a node.js all-in-one implementation of irc logging visible via
 *            a REST/JSON interface.
 *
 * See LICENSE file for licensing information.
 */

// server configuration, config file parsing, and eventually command line switch
// handling.

const path = require('path'),
        fs = require('fs'),
       url = require('url'),
   winston = require('winston');

exports.bot_name = "ircloggr";

exports.config_path = path.join(path.dirname(__dirname), "config.json");

exports.db_host = '127.0.0.1';
exports.db_port = 3306;
exports.db_user = 'ircloggr';
exports.db_pass = undefined;
exports.database = 'ircloggr';

// handle database string set in the environment
if (process.env['MYSQL_URL']) {
  var u = url.parse(process.env['MYSQL_URL']);
  exports.db_host = u.host;
  exports.db_user = u.auth.split(':')[0];
  exports.db_pass = u.auth.split(':')[1];
  exports.database = u.path.substr(1);
}

winston.info('using mysql database at ' + exports.db_host + " - " + exports.database);

exports.host = "*";

exports.port = 0 || process.env['PORT'];

exports.deployment_url = "http://irclog.gr";

exports.servers = {
};

exports.parse_config_file = function() {
    // let exceptions fly
    var conf = JSON.parse(fs.readFileSync(exports.config_path));

    for (var k in conf) {
        if (exports[k] === undefined || k.substr(0,5) === "parse")
            throw "unsupported key: " + k;
        if (exports[k] !== null && typeof exports[k] !== typeof conf[k]) {
            throw "'"+k+"' is a "+ typeof exports[k] +", it should be a " + typeof conf[k];
        }
        exports[k] = conf[k];
    }
};
<|endoftext|>


<commit_before>"use strict";

var querystring         = require('sdk/querystring');
var _                   = require("sdk/l10n").get;
const XMLHttpRequest    = require("sdk/addon/window").window.XMLHttpRequest;

const SEARCH_API = "https://api.qwant.com/api";
const BOARDS_API = "https://api-boards.qwant.com/api";

var routes = {
	login: {
		path: "/account/login",
		method: "POST",
		apiType: SEARCH_API
	},
	getBookmarks: {
		path: "/account/favorite",
		method: "GET",
		apiType: SEARCH_API
	},
	createBookmark: {
		path: "/account/favorite/create",
		method: "POST",
		apiType: SEARCH_API
	},
	getBoards: {
		path: "/board/getFlatList",
		method: "GET",
		apiType: BOARDS_API
	},
	createBoard: {
		path: "/board/create",
		method: "POST",
		apiType: BOARDS_API
	},
	getNotePreview: {
		path: "/note/preview",
		method: "GET",
		apiType: BOARDS_API
	},
	createNote: {
		path: "/note/create?XDEBUG_SESSION_START=vagrant",
		method: "POST",
		apiType: BOARDS_API
	}
};

var errors = {
	0   : {
		code : "ERROR_EXTENSION",
		message : _("error.0.message")
	},
	1   : {
		code : "ERROR_FORM_VALIDATION",
		message : _("error.1.message")
	},
	2   : {
		code : "ERROR_DATABASE",
		message : _("error.2.message")
	},
	3   : {
		code : "ERROR_INTERNAL",
		message : _("error.3.message")
	},
	101 : {
		code : "ERROR_USER_NOT_FOUND",
		message : _("error.101.message")
	},
	102 : {
		code : "ERROR_USER_DISABLED",
		message : _("error.102.message")
	},
	104 : {
		code : "ERROR_USER_BANNED",
		message : _("error.104.message")
	},
	108 : {
		code : "ERROR_INVALID_TOKEN",
		message : _("error.108.message")
	},
	201 : {
		code : "ERROR_BOARD_NOT_FOUND",
		message : _("error.201.message")
	},
	206 : {
		code : "ERROR_BOARD_ALREADY_EXISTS",
		message : _("error.206.message")
	},
	304 : {
		code : "ERROR_NOTE_ALREADY_EXISTS",
		message : _("error.304.message")
	},
	401 : {
		code : "ERROR_FAVORITE_ALREADY_EXISTS",
		message : _("error.401.message")
	},
	402 : {
		code : "ERROR_FAVORITE_URL_NOT_ACCESSIBLE",
		message : _("error.402.message")
	}
};

var categories = [
	{
		id: 10,
		i18n : _('category.animals')
	},
	{
		id: 6,
		i18n : _('category.architecture')
	},
	{
		id: 2,
		i18n : _('category.art')
	},
	{
		id: 11,
		i18n : _('category.automoto')
	},
	{
		id: 12,
		i18n : _('category.beauty')
	},
	{
		id: 19,
		i18n : _('category.culture')
	},
	{
		id: 14,
		i18n : _('category.entrepreneur')
	},
	{
		id: 7,
		i18n : _('category.fashion')
	},
	{
		id: 9,
		i18n : _('category.gastronomy')
	},
	{
		id: 15,
		i18n : _('category.geek')
	},
	{
		id: 29,
		i18n : _('category.health')
	},
	{
		id: 24,
		i18n : _('category.hightech')
	},
	{
		id: 25,
		i18n : _('category.hobbies')
	},
	{
		id: 3,
		i18n : _('category.humor')
	},
	{
		id: 27,
		i18n : _('category.illustration')
	},
	{
		id: 8,
		i18n : _('category.job')
	},
	{
		id: 13,
		i18n : _('category.kids')
	},
	{
		id: 18,
		i18n : _('category.marketing')
	},
	{
		id: 28,
		i18n : _('category.movies')
	},
	{
		id: 26,
		i18n : _('category.music')
	},
	{
		id: 16,
		i18n : _('category.nature')
	},
	{
		id: 4,
		i18n : _('category.news')
	},
	{
		id: 1,
		i18n : _('category.people')
	},
	{
		id: 5,
		i18n : _('category.politics')
	},
	{
		id: 23,
		i18n : _('category.sciences')
	},
	{
		id: 70,
		i18n : _('category.sexy')
	},
	{
		id: 22,
		i18n : _('category.society')
	},
	{
		id: 21,
		i18n : _('category.sport')
	},
	{
		id: 20,
		i18n : _('category.travel')
	},
	{
		id: 17,
		i18n : _('category.videogames')
	},
	{
		id: 30,
		i18n : _('category.web')
	},
	{
		id: 69,
		i18n : _("category.adult")
	},
	{
		id: 31,
		i18n: _('category.others')
	}
];

var api = function(route, params) {
	return new Promise(function(resolve, reject){
		var client = new XMLHttpRequest();
		var uri = route.apiType + route.path;
		var data = null;

		if (route.method === "POST") {
			params.st_encoded = true;
			data = querystring.unescape(querystring.stringify(params));
		}
		else {
			uri += "?" + querystring.stringify(params);
		}

		client.open(route.method, uri);
		client.send(data);

		client.onload = function () {
			if (this.status >= 200 && this.status < 300) {
				resolve(JSON.parse(this.response));
			} else {
				reject(this.statusText);
			}
		};

		client.onerror = function () {
			reject(this.statusText);
		};
	});
};

var errorMessage = function(errorCode) {
	return errors[errorCode].message;
};

var getCategories = function() {
	var cats = categories.slice(0), // We need to clone the categories array in order not to remove the Adult category
		others = {
			idx : 0,
			item : null
		},
		adult = {
			idx : 0,
			item : null
		},
		stop = false;

	cats.sort(function(a, b) {
		if (a.i18n > b.i18n)
			return 1;
		if (a.i18n < b.i18n)
			return -1;
		return 0;
	});

	stop = false;
	cats.forEach(function(cat, idx) {
		if (69 === cat.id && !stop) {
			adult.idx = idx;
			adult.item = cat;
			cats.splice(adult.idx, 1);
			cats.push(adult.item);
			stop = true;
		}
	});

	stop = false;
	cats.forEach(function(cat, idx) {
		if (31 === cat.id && !stop) {
			others.idx = idx;
			others.item = cat;
			cats.splice(others.idx, 1);
			cats.unshift(others.item);
			stop = true;
		}
	});

	return cats;
};

module.exports = {
	api: api,
	routes: routes,
	errorMessage: errorMessage,
	getCategories: getCategories
};<commit_msg>added timeout for API calls<commit_after>"use strict";

var querystring         = require('sdk/querystring');
var _                   = require("sdk/l10n").get;
const XMLHttpRequest    = require("sdk/addon/window").window.XMLHttpRequest;

const SEARCH_API = "https://api.qwant.com/api";
const BOARDS_API = "https://api-boards.qwant.com/api";

var routes = {
	login: {
		path: "/account/login",
		method: "POST",
		apiType: SEARCH_API
	},
	getBookmarks: {
		path: "/account/favorite",
		method: "GET",
		apiType: SEARCH_API
	},
	createBookmark: {
		path: "/account/favorite/create",
		method: "POST",
		apiType: SEARCH_API
	},
	getBoards: {
		path: "/board/getFlatList",
		method: "GET",
		apiType: BOARDS_API
	},
	createBoard: {
		path: "/board/create",
		method: "POST",
		apiType: BOARDS_API
	},
	getNotePreview: {
		path: "/note/preview",
		method: "GET",
		apiType: BOARDS_API
	},
	createNote: {
		path: "/note/create?XDEBUG_SESSION_START=vagrant",
		method: "POST",
		apiType: BOARDS_API
	}
};

var errors = {
	0   : {
		code : "ERROR_EXTENSION",
		message : _("error.0.message")
	},
	1   : {
		code : "ERROR_FORM_VALIDATION",
		message : _("error.1.message")
	},
	2   : {
		code : "ERROR_DATABASE",
		message : _("error.2.message")
	},
	3   : {
		code : "ERROR_INTERNAL",
		message : _("error.3.message")
	},
	101 : {
		code : "ERROR_USER_NOT_FOUND",
		message : _("error.101.message")
	},
	102 : {
		code : "ERROR_USER_DISABLED",
		message : _("error.102.message")
	},
	104 : {
		code : "ERROR_USER_BANNED",
		message : _("error.104.message")
	},
	108 : {
		code : "ERROR_INVALID_TOKEN",
		message : _("error.108.message")
	},
	201 : {
		code : "ERROR_BOARD_NOT_FOUND",
		message : _("error.201.message")
	},
	206 : {
		code : "ERROR_BOARD_ALREADY_EXISTS",
		message : _("error.206.message")
	},
	304 : {
		code : "ERROR_NOTE_ALREADY_EXISTS",
		message : _("error.304.message")
	},
	401 : {
		code : "ERROR_FAVORITE_ALREADY_EXISTS",
		message : _("error.401.message")
	},
	402 : {
		code : "ERROR_FAVORITE_URL_NOT_ACCESSIBLE",
		message : _("error.402.message")
	}
};

var categories = [
	{
		id: 10,
		i18n : _('category.animals')
	},
	{
		id: 6,
		i18n : _('category.architecture')
	},
	{
		id: 2,
		i18n : _('category.art')
	},
	{
		id: 11,
		i18n : _('category.automoto')
	},
	{
		id: 12,
		i18n : _('category.beauty')
	},
	{
		id: 19,
		i18n : _('category.culture')
	},
	{
		id: 14,
		i18n : _('category.entrepreneur')
	},
	{
		id: 7,
		i18n : _('category.fashion')
	},
	{
		id: 9,
		i18n : _('category.gastronomy')
	},
	{
		id: 15,
		i18n : _('category.geek')
	},
	{
		id: 29,
		i18n : _('category.health')
	},
	{
		id: 24,
		i18n : _('category.hightech')
	},
	{
		id: 25,
		i18n : _('category.hobbies')
	},
	{
		id: 3,
		i18n : _('category.humor')
	},
	{
		id: 27,
		i18n : _('category.illustration')
	},
	{
		id: 8,
		i18n : _('category.job')
	},
	{
		id: 13,
		i18n : _('category.kids')
	},
	{
		id: 18,
		i18n : _('category.marketing')
	},
	{
		id: 28,
		i18n : _('category.movies')
	},
	{
		id: 26,
		i18n : _('category.music')
	},
	{
		id: 16,
		i18n : _('category.nature')
	},
	{
		id: 4,
		i18n : _('category.news')
	},
	{
		id: 1,
		i18n : _('category.people')
	},
	{
		id: 5,
		i18n : _('category.politics')
	},
	{
		id: 23,
		i18n : _('category.sciences')
	},
	{
		id: 70,
		i18n : _('category.sexy')
	},
	{
		id: 22,
		i18n : _('category.society')
	},
	{
		id: 21,
		i18n : _('category.sport')
	},
	{
		id: 20,
		i18n : _('category.travel')
	},
	{
		id: 17,
		i18n : _('category.videogames')
	},
	{
		id: 30,
		i18n : _('category.web')
	},
	{
		id: 69,
		i18n : _("category.adult")
	},
	{
		id: 31,
		i18n: _('category.others')
	}
];

var api = function(route, params) {
	return new Promise(function(resolve, reject){
		var client = new XMLHttpRequest();
		var uri = route.apiType + route.path;
		var data = null;

		if (route.method === "POST") {
			params.st_encoded = true;
			data = querystring.unescape(querystring.stringify(params));
		}
		else {
			uri += "?" + querystring.stringify(params);
		}

		client.open(route.method, uri);
		client.timeout = 5000;
		client.send(data);

		client.onload = function () {
			if (this.status >= 200 && this.status < 300) {
				resolve(JSON.parse(this.response));
			} else {
				reject(this.statusText);
			}
		};

		client.onerror = function () {
			reject(this.statusText);
		};

		client.ontimeout = function () {
			reject(0);
		};
	});
};

var errorMessage = function(errorCode) {
	return errors[errorCode].message;
};

var getCategories = function() {
	var cats = categories.slice(0), // We need to clone the categories array in order not to remove the Adult category
		others = {
			idx : 0,
			item : null
		},
		adult = {
			idx : 0,
			item : null
		},
		stop = false;

	cats.sort(function(a, b) {
		if (a.i18n > b.i18n)
			return 1;
		if (a.i18n < b.i18n)
			return -1;
		return 0;
	});

	stop = false;
	cats.forEach(function(cat, idx) {
		if (69 === cat.id && !stop) {
			adult.idx = idx;
			adult.item = cat;
			cats.splice(adult.idx, 1);
			cats.push(adult.item);
			stop = true;
		}
	});

	stop = false;
	cats.forEach(function(cat, idx) {
		if (31 === cat.id && !stop) {
			others.idx = idx;
			others.item = cat;
			cats.splice(others.idx, 1);
			cats.unshift(others.item);
			stop = true;
		}
	});

	return cats;
};

module.exports = {
	api: api,
	routes: routes,
	errorMessage: errorMessage,
	getCategories: getCategories
};<|endoftext|>