<commit_before>var util = require('util');
var EventEmitter = require('events').EventEmitter;

function GenieMini(id) {
    this.btServiceIds = ['f000474d04514000b000000000000000'];

    this._id = id;
    this._gmCh = null;
    this._dev = null;
    this._moving = false;
    this._angle = null;
    this._position = 0;
    this._currentMove = null;
    this._stepsPerDegree = 186.56716418;
    this._backlash = 0;
    this._lastDirection = 0;

    this.orientation = null;
}

util.inherits(GenieMini, EventEmitter);

GenieMini.prototype._connectBt = function(btPeripheral, callback) {
    var self = this;
    btPeripheral.connect(function(err1) {
        if (err1) {
            if (callback) callback(false);
            return;
        }
        console.log('GenieMini(' + self._id + '): connecting via BLE');
        setTimeout(function(){
            btPeripheral.discoverServices(self.btServiceIds, function(err2, services) {
                if (services && services[0]) {
                    services[0].discoverCharacteristics([], function(err, characteristics) {
                        //console.log("characteristics:", characteristics);
                        self._gmCh = null;
                        self._dev = null;
                        for (var i = 0; i < characteristics.length; i++) {
                            ch = characteristics[i];
                            console.log("ch.uuid", ch.uuid);
                            if (ch.uuid == "2") {
                                self._gmCh = ch;
                            }
                        }
                        if (self._gmCh) {
                            try {
                                self._gmCh.write(new Buffer("012600", 'hex'));
                                self._gmCh.subscribe(function(){
                                    self._dev = btPeripheral;
                                    self._dev.connected = true;
                                    self.connected = true;
                                    self._dev.type = "bt";
                                    self._gmCh.on('data', function(data, isNotification) {
                                        self._parseIncoming(data);
                                    });
                                    console.log("GenieMini(" + self._id + "): connected!");
                                    self._init();
                                    if (callback) callback(true);
                                });
                            } catch(err3) {
                                btPeripheral.disconnect();
                                console.log("GenieMini(" + self._id + "): exception while connecting: ", err3);
                                if (callback) callback(false);
                            }
                        } else {
                            console.log("GenieMini(" + self._id + "): couldn't locate characteristics, disconnecting... ", err);
                            btPeripheral.disconnect();
                            if (callback) callback(false);
                        }
                    });
                } else {
                    console.log("GenieMini(" + self._id + "): couldn't locate services, disconnecting... ", err2);
                    btPeripheral.disconnect();
                    if (callback) callback(false);
                }

            });
        }, 1000);

        btPeripheral.once('disconnect', function() {
            console.log("GenieMini(" + self._id + "): disconnected");
            self._dev = null;
            self.connected = false;
            //clearInterval(self.statusIntervalHandle);
            self.emit("status", self.getStatus());
        });

    });
}

GenieMini.prototype._init = function() {
    var self = this;
    var dataBuf = new Buffer(4);
    dataBuf.fill(0);
    dataBuf.writeInt32LE(0x000B, 0);
    //self.statusIntervalHandle = setInterval(function(){
    self._write(0x001E, dataBuf, function(err) { // checks orientation
        var tries = 0;
        var waitForOrientation = function() {
            tries++;
            if(self.orientation || tries > 5) {
                self.emit("status", self.getStatus());
            } else {
                setTimeout(waitForOrientation, 500);
            }
        }
        waitForOrientation();
    });
    //}, 5000);
}

GenieMini.prototype._parseIncoming = function(data) {
    var id = data.readUInt16LE(1);
    if(id == 0x0060 || id == 0x0061) { // moving steps
        var state = data.readUInt8(7);
        var steps = data.readInt16LE(3);
        this._moving = (state == 0x01);
        if(this._newMove) {
            this._newMove = false;
            this._moving = true;
        }
        console.log("GenieMini(" + this._id + "): moving: ", this._moving, ", steps:", steps, "id:", id);
    } else if(id == 0x000B || id == 0x0052) { // current state
        var state = data.readUInt8(4);
        var angle = data.readUInt16LE(12);
        this._angle = angle;
        this._moving = (state == 0x01);
        console.log("GenieMini(" + this._id + "): moving: ", this._moving, ", angle:", angle, "id:", id);
        if(this._currentMove != null && this._lastAngle != null) {
            if(Math.abs(angle - this._lastAngle) < 180) {
                this._currentMove += angle - this._lastAngle;
            } else {
                if(this._lastAngle < angle) {
                    this._currentMove += 359 - (angle - this._lastAngle);
                } else {
                    this._currentMove -= 359 - (this._lastAngle - angle);
                }
            }
            console.log("GenieMini(" + this._id + "): _currentMove", this._currentMove);
        }
        this._lastAngle = angle;
    } else if(id == 0x0025) {
        var orientationCode = data.readUInt8(3);
        console.log("GenieMini(" + this._id + "): orientationCode:", orientationCode);
        var origOrientation = this.orientation;
        if(orientationCode & 0x4) this.orientation = 'tilt'; else this.orientation = 'pan'; // pan = 0x90, 0x80, tilt = 0x94, 0x84
        if(origOrientation != this.orientation) {
            console.log("GenieMini(" + this._id + "): orientation:", this.orientation);
            this.emit("status", this.getStatus());
        }
    } else if(id == 0x004E) {
        this._init(); // update orientation on change
    } else {
        console.log("GenieMini(" + this._id + "): unknown id", id, "data", data);
    }
}

GenieMini.prototype.connect = function(device, callback) {
    if (device && device.connect) {
        this._moving = false;
        console.log("GenieMini(" + this._id + "): connecting...");
        this._connectBt(device, callback);
    } else {
        console.log("GenieMini(" + this._id + "): invalid device, cannot connect");
        if (callback) callback("invalid device");
    }
}

GenieMini.prototype.disconnect = function() {
    console.log("GenieMini(" + this._id + "): disconnecting...");
    if (this._dev && this._dev.connected) {
        this.connected = false;
        this._dev.connected = false;
        this._dev.disconnect();
    } else {
        this._dev = null;
    }
    this.emit("status", this.getStatus());
}

GenieMini.prototype.getStatus = function() {
    var type = (this._dev && this._dev.type) ? this._dev.type : null;
    return {
        connected: this._dev && this._dev.connected,
        connectionType: type,
        motor1: this._dev && this._dev.connected,
        motor1pos: this._position / this._stepsPerDegree,
        orientation: this.orientation,
        motor1backlash: this._backlash
    }
}

GenieMini.prototype.disable = function(motor) {
    this._enabled = false;
}

GenieMini.prototype.enable = function(motor) {
    this._enabled = true;
}

GenieMini.prototype.move = function(motor, degrees, callback) {
    if (this._moving) {
        if (callback) callback("GenieMini(" + this._id + "): motor already running");
        return console.log("GenieMini(" + this._id + "): motor already running");
    }

    var steps = Math.round(degrees * this._stepsPerDegree);

    var sign = 0;
    if(degrees > 0) sign = 1;
    if(degrees < 0) sign = -1;

    if(sign && this._lastDirection != sign) {
        this._lastDirection = sign;
        degrees += this._backlash * sign;
    }
    var backlashCorrectedSteps = Math.round(degrees * this._stepsPerDegree);
    if(!backlashCorrectedSteps) {
        console.log("GenieMini(" + this._id + "): NOT moving motor", backlashCorrectedSteps, "steps, (", degrees, " degrees)");
        return callback && callback(null, this._position / this._stepsPerDegree);
    }
    console.log("GenieMini(" + this._id + "): moving motor", backlashCorrectedSteps, "steps");
    if(!this._enabled) this.enable();

    var dataBuf = new Buffer(4);
    dataBuf.fill(0);
    dataBuf.writeInt32LE(backlashCorrectedSteps, 0);
    this._moving = true;

    var self = this;
    this._newMove = true;
    self._write(0x005E, dataBuf, function(err) {
        self._moving = true;
        if (!err) {
            var check = function() {
                setTimeout(function() {
                    if(self._moving === undefined) return check();;
                    if(self._moving) {
                        check(); // keep checking until stop
                    } else {
                        self._position += steps;
                        console.log("GenieMini(" + self._id + "): position:", self._position);
                        if (callback) callback(null, self._position / self._stepsPerDegree);
                    }
                }, 300);
            }
            check();
        } else {
            if (callback) callback(err);
            self._moving = false;
        }
    });
}
//<Buffer 01 5e 00 00 00 03 a4 00>
GenieMini.prototype._write = function(command, dataBuf, callback) {
    var template = new Buffer("010000", 'hex');
    var len = dataBuf ? dataBuf.length : 0;
    var COMMAND = 0;

    template.writeUInt16LE(parseInt(command), 1);

    var cmd;
    if (dataBuf) {
        cmd = Buffer.concat([template, dataBuf]);
    } else {
        cmd = template;
    }

    //console.log("GenieMini(" + this._id + "): sending data", cmd);

    try {
        this._gmCh.write(cmd);
        callback && callback();
    } catch(err) {
        callback && callback(err);
    }
}

GenieMini.prototype.constantMove = function(motor, speed, callback) {
    console.log("GenieMini(" + this._id + "): moving motor at speed ", speed, "%");
    if(!this._enabled) this.enable();

    var dataBuf = new Buffer(3);
    var self = this;
    dataBuf.fill(0);
    dataBuf.writeInt8(Math.round(speed), 0);
    dataBuf.writeUInt16LE(speed ? 0x01 : 0x00, 1);
    this._moving = true;

    if(this._watchdog) {
        clearTimeout(this._watchdog);
        this._watchdog = null;
    }
    if(speed) {
        this._watchdog = setTimeout(function(){
            console.log("GenieMini(" + self._id + "): stopping via watchdog");
            self.constantMove(motor, 0);
        }, 3000);
    }

    var sendMove = function() {
        self._write(0x003F, dataBuf, function(err) {
            if (!err) {
                var check = function() {
                    if(this._endTimer) clearTimeout(this._endTimer);
                    if(!speed) {
                        self._endTimer = setTimeout(function() {
                            if(self._moving === undefined) return;
                            if(self._moving) {
                                check(); // keep checking until stop
                            } else {
                                console.log("GenieMini(" + self._id + "): adding", self._currentMove, "° to position");
                                self._position += self._currentMove * self._stepsPerDegree;
                                self._currentMove = null;
                                if (callback) callback(null, self._position / self._stepsPerDegree);
                            }
                        }, 200);
                    } else {
                        if (callback) callback(null, null);
                    }
                }
                check();
            } else {
                if (callback) callback(err);
                self._moving = false;
            }
        });
    }

    var self = this;
    if(this._endTimer) clearTimeout(this._endTimer);
    if(self._currentMove == null) {
        self._lastAngle = null;
        self._currentMove = 0;
        console.log("GenieMini(" + self._id + "): starting move at speed, saving position");
        var d = new Buffer(2);
        d.fill(0);
        d.writeUInt16LE(0x000B, 0);
        this._moving = true;
        self._write(0x001E, d, function(err) {
            sendMove();
        });
    } else {
        sendMove();
    }
}

GenieMini.prototype.resetMotorPosition = function(motor, callback) {
    var self = this;
    var check = function() {
        if(self._moving) {
            setTimeout(check, 200); // keep checking until stop
        } else {
            self._position = 0;
            if (callback) callback();
        }
    }
    check();
}

GenieMini.prototype.setMotorPosition = function(motor, position, callback) {
    var self = this;
    var check = function() {
        if(self._moving) {
            setTimeout(check, 200); // keep checking until stop
        } else {
            self._position = position;
            if (callback) callback();
        }
    }
    check();
}

GenieMini.prototype.setMotorBacklash = function(motor, backlash, callback) {
    this._backlash = backlash;
    if (callback) callback(this._backlash);
}

GenieMini.prototype.getMotorBacklash = function(motor, callback) {
    if (callback) callback(this._backlash);
}

module.exports = GenieMini;
<commit_msg>genie mini position fix<commit_after>var util = require('util');
var EventEmitter = require('events').EventEmitter;

function GenieMini(id) {
    this.btServiceIds = ['f000474d04514000b000000000000000'];

    this._id = id;
    this._gmCh = null;
    this._dev = null;
    this._moving = false;
    this._angle = null;
    this._position = 0;
    this._currentMove = null;
    this._stepsPerDegree = 186.56716418;
    this._backlash = 0;
    this._lastDirection = 0;

    this.orientation = null;
}

util.inherits(GenieMini, EventEmitter);

GenieMini.prototype._connectBt = function(btPeripheral, callback) {
    var self = this;
    btPeripheral.connect(function(err1) {
        if (err1) {
            if (callback) callback(false);
            return;
        }
        console.log('GenieMini(' + self._id + '): connecting via BLE');
        setTimeout(function(){
            btPeripheral.discoverServices(self.btServiceIds, function(err2, services) {
                if (services && services[0]) {
                    services[0].discoverCharacteristics([], function(err, characteristics) {
                        //console.log("characteristics:", characteristics);
                        self._gmCh = null;
                        self._dev = null;
                        for (var i = 0; i < characteristics.length; i++) {
                            ch = characteristics[i];
                            console.log("ch.uuid", ch.uuid);
                            if (ch.uuid == "2") {
                                self._gmCh = ch;
                            }
                        }
                        if (self._gmCh) {
                            try {
                                self._gmCh.write(new Buffer("012600", 'hex'));
                                self._gmCh.subscribe(function(){
                                    self._dev = btPeripheral;
                                    self._dev.connected = true;
                                    self.connected = true;
                                    self._dev.type = "bt";
                                    self._gmCh.on('data', function(data, isNotification) {
                                        self._parseIncoming(data);
                                    });
                                    console.log("GenieMini(" + self._id + "): connected!");
                                    self._init();
                                    if (callback) callback(true);
                                });
                            } catch(err3) {
                                btPeripheral.disconnect();
                                console.log("GenieMini(" + self._id + "): exception while connecting: ", err3);
                                if (callback) callback(false);
                            }
                        } else {
                            console.log("GenieMini(" + self._id + "): couldn't locate characteristics, disconnecting... ", err);
                            btPeripheral.disconnect();
                            if (callback) callback(false);
                        }
                    });
                } else {
                    console.log("GenieMini(" + self._id + "): couldn't locate services, disconnecting... ", err2);
                    btPeripheral.disconnect();
                    if (callback) callback(false);
                }

            });
        }, 1000);

        btPeripheral.once('disconnect', function() {
            console.log("GenieMini(" + self._id + "): disconnected");
            self._dev = null;
            self.connected = false;
            //clearInterval(self.statusIntervalHandle);
            self.emit("status", self.getStatus());
        });

    });
}

GenieMini.prototype._init = function() {
    var self = this;
    var dataBuf = new Buffer(4);
    dataBuf.fill(0);
    dataBuf.writeInt32LE(0x000B, 0);
    //self.statusIntervalHandle = setInterval(function(){
    self._write(0x001E, dataBuf, function(err) { // checks orientation
        var tries = 0;
        var waitForOrientation = function() {
            tries++;
            if(self.orientation || tries > 5) {
                self.emit("status", self.getStatus());
            } else {
                setTimeout(waitForOrientation, 500);
            }
        }
        waitForOrientation();
    });
    //}, 5000);
}

GenieMini.prototype._parseIncoming = function(data) {
    var id = data.readUInt16LE(1);
    if(id == 0x0060 || id == 0x0061) { // moving steps
        var state = data.readUInt8(7);
        var steps = data.readInt16LE(3);
        this._moving = (state == 0x01);
        if(this._newMove) {
            this._newMove = false;
            this._moving = true;
        }
        console.log("GenieMini(" + this._id + "): moving: ", this._moving, ", steps:", steps, "id:", id);
    } else if(id == 0x000B || id == 0x0052) { // current state
        var state = data.readUInt8(4);
        var angle = data.readUInt16LE(12);
        this._angle = angle;
        this._moving = (state == 0x01);
        console.log("GenieMini(" + this._id + "): moving: ", this._moving, ", angle:", angle, "id:", id);
        if(this._currentMove != null && this._lastAngle != null) {
            if(Math.abs(angle - this._lastAngle) < 180) {
                this._currentMove += angle - this._lastAngle;
            } else {
                if(this._lastAngle < angle) {
                    this._currentMove -= 360 - (angle - this._lastAngle);
                } else {
                    this._currentMove += 360 - (this._lastAngle - angle);
                }
            }
            console.log("GenieMini(" + this._id + "): _currentMove", this._currentMove);
        }
        this._lastAngle = angle;
    } else if(id == 0x0025) {
        var orientationCode = data.readUInt8(3);
        console.log("GenieMini(" + this._id + "): orientationCode:", orientationCode);
        var origOrientation = this.orientation;
        if(orientationCode & 0x4) this.orientation = 'tilt'; else this.orientation = 'pan'; // pan = 0x90, 0x80, tilt = 0x94, 0x84
        if(origOrientation != this.orientation) {
            console.log("GenieMini(" + this._id + "): orientation:", this.orientation);
            this.emit("status", this.getStatus());
        }
    } else if(id == 0x004E) {
        this._init(); // update orientation on change
    } else {
        console.log("GenieMini(" + this._id + "): unknown id", id, "data", data);
    }
}

GenieMini.prototype.connect = function(device, callback) {
    if (device && device.connect) {
        this._moving = false;
        console.log("GenieMini(" + this._id + "): connecting...");
        this._connectBt(device, callback);
    } else {
        console.log("GenieMini(" + this._id + "): invalid device, cannot connect");
        if (callback) callback("invalid device");
    }
}

GenieMini.prototype.disconnect = function() {
    console.log("GenieMini(" + this._id + "): disconnecting...");
    if (this._dev && this._dev.connected) {
        this.connected = false;
        this._dev.connected = false;
        this._dev.disconnect();
    } else {
        this._dev = null;
    }
    this.emit("status", this.getStatus());
}

GenieMini.prototype.getStatus = function() {
    var type = (this._dev && this._dev.type) ? this._dev.type : null;
    return {
        connected: this._dev && this._dev.connected,
        connectionType: type,
        motor1: this._dev && this._dev.connected,
        motor1pos: this._position / this._stepsPerDegree,
        orientation: this.orientation,
        motor1backlash: this._backlash
    }
}

GenieMini.prototype.disable = function(motor) {
    this._enabled = false;
}

GenieMini.prototype.enable = function(motor) {
    this._enabled = true;
}

GenieMini.prototype.move = function(motor, degrees, callback) {
    if (this._moving) {
        if (callback) callback("GenieMini(" + this._id + "): motor already running");
        return console.log("GenieMini(" + this._id + "): motor already running");
    }

    var steps = Math.round(degrees * this._stepsPerDegree);

    var sign = 0;
    if(degrees > 0) sign = 1;
    if(degrees < 0) sign = -1;

    if(sign && this._lastDirection != sign) {
        this._lastDirection = sign;
        degrees += this._backlash * sign;
    }
    var backlashCorrectedSteps = Math.round(degrees * this._stepsPerDegree);
    if(!backlashCorrectedSteps) {
        console.log("GenieMini(" + this._id + "): NOT moving motor", backlashCorrectedSteps, "steps, (", degrees, " degrees)");
        return callback && callback(null, this._position / this._stepsPerDegree);
    }
    console.log("GenieMini(" + this._id + "): moving motor", backlashCorrectedSteps, "steps");
    if(!this._enabled) this.enable();

    var dataBuf = new Buffer(4);
    dataBuf.fill(0);
    dataBuf.writeInt32LE(backlashCorrectedSteps, 0);
    this._moving = true;

    var self = this;
    this._newMove = true;
    self._write(0x005E, dataBuf, function(err) {
        self._moving = true;
        if (!err) {
            var check = function() {
                setTimeout(function() {
                    if(self._moving === undefined) return check();;
                    if(self._moving) {
                        check(); // keep checking until stop
                    } else {
                        self._position += steps;
                        console.log("GenieMini(" + self._id + "): position:", self._position);
                        if (callback) callback(null, self._position / self._stepsPerDegree);
                    }
                }, 300);
            }
            check();
        } else {
            if (callback) callback(err);
            self._moving = false;
        }
    });
}
//<Buffer 01 5e 00 00 00 03 a4 00>
GenieMini.prototype._write = function(command, dataBuf, callback) {
    var template = new Buffer("010000", 'hex');
    var len = dataBuf ? dataBuf.length : 0;
    var COMMAND = 0;

    template.writeUInt16LE(parseInt(command), 1);

    var cmd;
    if (dataBuf) {
        cmd = Buffer.concat([template, dataBuf]);
    } else {
        cmd = template;
    }

    //console.log("GenieMini(" + this._id + "): sending data", cmd);

    try {
        this._gmCh.write(cmd);
        callback && callback();
    } catch(err) {
        callback && callback(err);
    }
}

GenieMini.prototype.constantMove = function(motor, speed, callback) {
    console.log("GenieMini(" + this._id + "): moving motor at speed ", speed, "%");
    if(!this._enabled) this.enable();

    var dataBuf = new Buffer(3);
    var self = this;
    dataBuf.fill(0);
    dataBuf.writeInt8(Math.round(speed), 0);
    dataBuf.writeUInt16LE(speed ? 0x01 : 0x00, 1);
    this._moving = true;

    if(this._watchdog) {
        clearTimeout(this._watchdog);
        this._watchdog = null;
    }
    if(speed) {
        this._watchdog = setTimeout(function(){
            console.log("GenieMini(" + self._id + "): stopping via watchdog");
            self.constantMove(motor, 0);
        }, 3000);
    }

    var sendMove = function() {
        self._write(0x003F, dataBuf, function(err) {
            if (!err) {
                var check = function() {
                    if(this._endTimer) clearTimeout(this._endTimer);
                    if(!speed) {
                        self._endTimer = setTimeout(function() {
                            if(self._moving === undefined) return;
                            if(self._moving) {
                                check(); // keep checking until stop
                            } else {
                                console.log("GenieMini(" + self._id + "): adding", self._currentMove, "° to position");
                                self._position += self._currentMove * self._stepsPerDegree;
                                self._currentMove = null;
                                if (callback) callback(null, self._position / self._stepsPerDegree);
                            }
                        }, 200);
                    } else {
                        if (callback) callback(null, null);
                    }
                }
                check();
            } else {
                if (callback) callback(err);
                self._moving = false;
            }
        });
    }

    var self = this;
    if(this._endTimer) clearTimeout(this._endTimer);
    if(self._currentMove == null) {
        self._lastAngle = null;
        self._currentMove = 0;
        console.log("GenieMini(" + self._id + "): starting move at speed, saving position");
        var d = new Buffer(2);
        d.fill(0);
        d.writeUInt16LE(0x000B, 0);
        this._moving = true;
        self._write(0x001E, d, function(err) {
            sendMove();
        });
    } else {
        sendMove();
    }
}

GenieMini.prototype.resetMotorPosition = function(motor, callback) {
    var self = this;
    var check = function() {
        if(self._moving) {
            setTimeout(check, 200); // keep checking until stop
        } else {
            self._position = 0;
            if (callback) callback();
        }
    }
    check();
}

GenieMini.prototype.setMotorPosition = function(motor, position, callback) {
    var self = this;
    var check = function() {
        if(self._moving) {
            setTimeout(check, 200); // keep checking until stop
        } else {
            self._position = position;
            if (callback) callback();
        }
    }
    check();
}

GenieMini.prototype.setMotorBacklash = function(motor, backlash, callback) {
    this._backlash = backlash;
    if (callback) callback(this._backlash);
}

GenieMini.prototype.getMotorBacklash = function(motor, callback) {
    if (callback) callback(this._backlash);
}

module.exports = GenieMini;
<|endoftext|>


<commit_before>'use strict';
var BaseController = require('./base-controller');

/**
 * AdminController
 */
class AdminController extends BaseController {
  index(req, res) {
    return res.render('admin/index', { title: 'admin' });
  }
};

module.exports = new AdminController();
<commit_msg>move instance creation into server/index<commit_after>'use strict';
var BaseController = require('./base-controller');

/**
 * AdminController
 */
module.exports = class AdminController extends BaseController {
  index(req, res) {
    return res.render('admin/index', { title: 'admin' });
  }
};
<|endoftext|>


<commit_before>/**
 * Created by gwennael.buchet on 01/01/17.
 */
"use strict";

let keys = require("./secretKeys.js");
let mqtt = require('mqtt');

exports.init = function (mainCallback) {
	let shiftrClient = mqtt.connect(
		'mqtt://' + keys.SHIFTR_DEVICE_LOGIN + ':' + keys.SHIFTR_DEVICE_PWD + '@broker.shiftr.io', {
			clientId: 'Web Server'
		}
	);

	shiftrClient.on('connect', function () {
		console.log('shiftrClient has connected!');

		shiftrClient.subscribe(keys.SHIFTR_NAMESPACE);
	});

	shiftrClient.on('message', function (topic, message) {
		console.log('new message:', topic, message.toString());
		let json = JSON.parse(message);

		mainCallback(json.sender, json.quantity, "Shiftr.io");
	});
};

<commit_msg>Better console comments<commit_after>/**
 * Created by gwennael.buchet on 01/01/17.
 */
"use strict";

let keys = require("./secretKeys.js");
let mqtt = require('mqtt');

exports.init = function (mainCallback) {
	let shiftrClient = mqtt.connect(
		'mqtt://' + keys.SHIFTR_DEVICE_LOGIN + ':' + keys.SHIFTR_DEVICE_PWD + '@broker.shiftr.io', {
			clientId: 'Web Server'
		}
	);

	shiftrClient.on('connect', function () {
		console.log('Connected to Shiftr.io.');

		shiftrClient.subscribe(keys.SHIFTR_NAMESPACE);
	});

	shiftrClient.on('message', function (topic, message) {
		console.log('new message:', topic, message.toString());
		let json = JSON.parse(message);

		mainCallback(json.sender, json.quantity, "Shiftr.io");
	});
};

<|endoftext|>


<commit_before>/* jslint node: true */
'use strict';

//  ENiGMA½
const Config            = require('./config.js').get;
const stringFormat      = require('./string_format.js');
const Errors            = require('./enig_error.js').Errors;
const resolveMimeType   = require('./mime_util.js').resolveMimeType;
const Events            = require('./events.js');

//  base/modules
const fs        = require('graceful-fs');
const _         = require('lodash');
const pty       = require('node-pty');
const paths     = require('path');

let archiveUtil;

class Archiver {
    constructor(config) {
        this.compress   = config.compress;
        this.decompress = config.decompress;
        this.list       = config.list;
        this.extract    = config.extract;
    }

    ok() {
        return this.canCompress() && this.canDecompress();
    }

    can(what) {
        if(!_.has(this, [ what, 'cmd' ]) || !_.has(this, [ what, 'args' ])) {
            return false;
        }

        return _.isString(this[what].cmd) && Array.isArray(this[what].args) && this[what].args.length > 0;
    }

    canCompress() { return this.can('compress'); }
    canDecompress() { return this.can('decompress'); }
    canList() { return this.can('list'); }  //  :TODO: validate entryMatch
    canExtract() { return this.can('extract'); }
}

module.exports = class ArchiveUtil {

    constructor() {
        this.archivers = {};
        this.longestSignature = 0;
    }

    //  singleton access
    static getInstance() {
        if(!archiveUtil) {
            archiveUtil = new ArchiveUtil();
            archiveUtil.init();
        }
        return archiveUtil;
    }

    init() {
        this.reloadConfig();
        Events.on(Events.getSystemEvents().ConfigChanged, () => {
            this.reloadConfig();
        });
    }

    reloadConfig() {
        const config = Config();
        if(_.has(config, 'archives.archivers')) {
            Object.keys(config.archives.archivers).forEach(archKey => {

                const archConfig    = config.archives.archivers[archKey];
                const archiver      = new Archiver(archConfig);

                if(!archiver.ok()) {
                    //  :TODO: Log warning - bad archiver/config
                }

                this.archivers[archKey] = archiver;
            });
        }

        if(_.isObject(config.fileTypes)) {
            const updateSig = (ft) => {
                ft.sig      = Buffer.from(ft.sig, 'hex');
                ft.offset   = ft.offset || 0;

                //  :TODO: this is broken: sig is NOT this long, it's sig.length long; offset needs to allow for -negative values as well
                const sigLen = ft.offset + ft.sig.length;
                if(sigLen > this.longestSignature) {
                    this.longestSignature = sigLen;
                }
            };

            Object.keys(config.fileTypes).forEach(mimeType => {
                const fileType = config.fileTypes[mimeType];
                if(Array.isArray(fileType)) {
                    fileType.forEach(ft => {
                        if(ft.sig) {
                            updateSig(ft);
                        }
                    });
                } else if(fileType.sig) {
                    updateSig(fileType);
                }
            });
        }
    }

    getArchiver(mimeTypeOrExtension, justExtention) {
        const mimeType = resolveMimeType(mimeTypeOrExtension);

        if(!mimeType) { //  lookup returns false on failure
            return;
        }

        const config = Config();
        let fileType = _.get(config, [ 'fileTypes', mimeType ] );

        if(Array.isArray(fileType)) {
            if(!justExtention) {
                //  need extention for lookup; ambiguous as-is :(
                return;
            }
            //  further refine by extention
            fileType = fileType.find(ft => justExtention === ft.ext);
        }

        if(!_.isObject(fileType)) {
            return;
        }

        if(fileType.archiveHandler) {
            return _.get( config, [ 'archives', 'archivers', fileType.archiveHandler ] );
        }
    }

    haveArchiver(archType) {
        return this.getArchiver(archType) ? true : false;
    }

    //  :TODO: implement me:
    /*
    detectTypeWithBuf(buf, cb) {
    }
    */

    detectType(path, cb) {
        fs.open(path, 'r', (err, fd) => {
            if(err) {
                return cb(err);
            }

            const buf = Buffer.alloc(this.longestSignature);
            fs.read(fd, buf, 0, buf.length, 0, (err, bytesRead) => {
                if(err) {
                    return cb(err);
                }

                const archFormat = _.findKey(Config().fileTypes, fileTypeInfo => {
                    const fileTypeInfos = Array.isArray(fileTypeInfo) ? fileTypeInfo : [ fileTypeInfo ];
                    return fileTypeInfos.find(fti => {
                        if(!fti.sig || !fti.archiveHandler) {
                            return false;
                        }

                        const lenNeeded = fti.offset + fti.sig.length;

                        if(bytesRead < lenNeeded) {
                            return false;
                        }

                        const comp = buf.slice(fti.offset, fti.offset + fti.sig.length);
                        return (fti.sig.equals(comp));
                    });
                });

                return cb(archFormat ? null : Errors.General('Unknown type'), archFormat);
            });
        });
    }

    spawnHandler(proc, action, cb) {
        //  pty.js doesn't currently give us a error when things fail,
        //  so we have this horrible, horrible hack:
        let err;
        proc.once('data', d => {
            if(_.isString(d) && d.startsWith('execvp(3) failed.')) {
                err = Errors.ExternalProcess(`${action} failed: ${d.trim()}`);
            }
        });

        proc.once('exit', exitCode => {
            return cb(exitCode ? Errors.ExternalProcess(`${action} failed with exit code: ${exitCode}`) : err);
        });
    }

    compressTo(archType, archivePath, files, cb) {
        const archiver = this.getArchiver(archType, paths.extname(archivePath));

        if(!archiver) {
            return cb(Errors.Invalid(`Unknown archive type: ${archType}`));
        }

        const fmtObj = {
            archivePath : archivePath,
            fileList    : files.join(' '),  //  :TODO: probably need same hack as extractTo here!
        };

        const args = archiver.compress.args.map( arg => stringFormat(arg, fmtObj) );

        let proc;
        try {
            proc = pty.spawn(archiver.compress.cmd, args, this.getPtyOpts());
        } catch(e) {
            return cb(e);
        }

        return this.spawnHandler(proc, 'Compression', cb);
    }

    extractTo(archivePath, extractPath, archType, fileList, cb) {
        let haveFileList;

        if(!cb && _.isFunction(fileList)) {
            cb = fileList;
            fileList = [];
            haveFileList = false;
        } else {
            haveFileList = true;
        }

        const archiver = this.getArchiver(archType, paths.extname(archivePath));

        if(!archiver) {
            return cb(Errors.Invalid(`Unknown archive type: ${archType}`));
        }

        const fmtObj = {
            archivePath     : archivePath,
            extractPath     : extractPath,
        };

        let action = haveFileList ? 'extract' : 'decompress';
        if('extract' === action && !_.isObject(archiver[action])) {
            //  we're forced to do a full decompress
            action = 'decompress';
            haveFileList = false;
        }

        //  we need to treat {fileList} special in that it should be broken up to 0:n args
        const args = archiver[action].args.map( arg => {
            return '{fileList}' === arg ? arg : stringFormat(arg, fmtObj);
        });

        const fileListPos = args.indexOf('{fileList}');
        if(fileListPos > -1) {
            //  replace {fileList} with 0:n sep file list arguments
            args.splice.apply(args, [fileListPos, 1].concat(fileList));
        }

        let proc;
        try {
            proc = pty.spawn(archiver[action].cmd, args, this.getPtyOpts(extractPath));
        } catch(e) {
            return cb(e);
        }

        return this.spawnHandler(proc, (haveFileList ? 'Extraction' : 'Decompression'), cb);
    }

    listEntries(archivePath, archType, cb) {
        const archiver = this.getArchiver(archType, paths.extname(archivePath));

        if(!archiver) {
            return cb(Errors.Invalid(`Unknown archive type: ${archType}`));
        }

        const fmtObj = {
            archivePath     : archivePath,
        };

        const args  = archiver.list.args.map( arg => stringFormat(arg, fmtObj) );

        let proc;
        try {
            proc = pty.spawn(archiver.list.cmd, args, this.getPtyOpts());
        } catch(e) {
            return cb(e);
        }

        let output = '';
        proc.on('data', data => {
            //  :TODO: hack for: execvp(3) failed.: No such file or directory

            output += data;
        });

        proc.once('exit', exitCode => {
            if(exitCode) {
                return cb(Errors.ExternalProcess(`List failed with exit code: ${exitCode}`));
            }

            const entryGroupOrder = archiver.list.entryGroupOrder || { byteSize : 1, fileName : 2 };

            const entries = [];
            const entryMatchRe = new RegExp(archiver.list.entryMatch, 'gm');
            let m;
            while((m = entryMatchRe.exec(output))) {
                entries.push({
                    byteSize    : parseInt(m[entryGroupOrder.byteSize]),
                    fileName    : m[entryGroupOrder.fileName].trim(),
                });
            }

            return cb(null, entries);
        });
    }

    getPtyOpts(extractPath) {
        const opts = {
            name    : 'enigma-archiver',
            cols    : 80,
            rows    : 24,
            env     : process.env,
        };
        if(extractPath) {
            opts.cwd = extractPath;
        }
        //  :TODO: set cwd to supplied temp path if not sepcific extract
        return opts;
    }
};
<commit_msg>* Fix file descriptor leak * Allow noWatch init (e.g. for oputil)<commit_after>/* jslint node: true */
'use strict';

//  ENiGMA½
const Config            = require('./config.js').get;
const stringFormat      = require('./string_format.js');
const Errors            = require('./enig_error.js').Errors;
const resolveMimeType   = require('./mime_util.js').resolveMimeType;
const Events            = require('./events.js');

//  base/modules
const fs        = require('graceful-fs');
const _         = require('lodash');
const pty       = require('node-pty');
const paths     = require('path');

let archiveUtil;

class Archiver {
    constructor(config) {
        this.compress   = config.compress;
        this.decompress = config.decompress;
        this.list       = config.list;
        this.extract    = config.extract;
    }

    ok() {
        return this.canCompress() && this.canDecompress();
    }

    can(what) {
        if(!_.has(this, [ what, 'cmd' ]) || !_.has(this, [ what, 'args' ])) {
            return false;
        }

        return _.isString(this[what].cmd) && Array.isArray(this[what].args) && this[what].args.length > 0;
    }

    canCompress() { return this.can('compress'); }
    canDecompress() { return this.can('decompress'); }
    canList() { return this.can('list'); }  //  :TODO: validate entryMatch
    canExtract() { return this.can('extract'); }
}

module.exports = class ArchiveUtil {

    constructor() {
        this.archivers = {};
        this.longestSignature = 0;
    }

    //  singleton access
    static getInstance(noWatch = false) {
        if(!archiveUtil) {
            archiveUtil = new ArchiveUtil();
            archiveUtil.init(noWatch);
        }
        return archiveUtil;
    }

    init(noWatch = false) {
        this.reloadConfig();
        if(!noWatch) {
            Events.on(Events.getSystemEvents().ConfigChanged, () => {
                this.reloadConfig();
            });
        }
    }

    reloadConfig() {
        const config = Config();
        if(_.has(config, 'archives.archivers')) {
            Object.keys(config.archives.archivers).forEach(archKey => {

                const archConfig    = config.archives.archivers[archKey];
                const archiver      = new Archiver(archConfig);

                if(!archiver.ok()) {
                    //  :TODO: Log warning - bad archiver/config
                }

                this.archivers[archKey] = archiver;
            });
        }

        if(_.isObject(config.fileTypes)) {
            const updateSig = (ft) => {
                ft.sig      = Buffer.from(ft.sig, 'hex');
                ft.offset   = ft.offset || 0;

                //  :TODO: this is broken: sig is NOT this long, it's sig.length long; offset needs to allow for -negative values as well
                const sigLen = ft.offset + ft.sig.length;
                if(sigLen > this.longestSignature) {
                    this.longestSignature = sigLen;
                }
            };

            Object.keys(config.fileTypes).forEach(mimeType => {
                const fileType = config.fileTypes[mimeType];
                if(Array.isArray(fileType)) {
                    fileType.forEach(ft => {
                        if(ft.sig) {
                            updateSig(ft);
                        }
                    });
                } else if(fileType.sig) {
                    updateSig(fileType);
                }
            });
        }
    }

    getArchiver(mimeTypeOrExtension, justExtention) {
        const mimeType = resolveMimeType(mimeTypeOrExtension);

        if(!mimeType) { //  lookup returns false on failure
            return;
        }

        const config = Config();
        let fileType = _.get(config, [ 'fileTypes', mimeType ] );

        if(Array.isArray(fileType)) {
            if(!justExtention) {
                //  need extention for lookup; ambiguous as-is :(
                return;
            }
            //  further refine by extention
            fileType = fileType.find(ft => justExtention === ft.ext);
        }

        if(!_.isObject(fileType)) {
            return;
        }

        if(fileType.archiveHandler) {
            return _.get( config, [ 'archives', 'archivers', fileType.archiveHandler ] );
        }
    }

    haveArchiver(archType) {
        return this.getArchiver(archType) ? true : false;
    }

    //  :TODO: implement me:
    /*
    detectTypeWithBuf(buf, cb) {
    }
    */

    detectType(path, cb) {
        const closeFile = (fd) => {
            fs.close(fd, () => { /* sadface */ });
        };

        fs.open(path, 'r', (err, fd) => {
            if(err) {
                return cb(err);
            }

            const buf = Buffer.alloc(this.longestSignature);
            fs.read(fd, buf, 0, buf.length, 0, (err, bytesRead) => {
                if(err) {
                    closeFile(fd);
                    return cb(err);
                }

                const archFormat = _.findKey(Config().fileTypes, fileTypeInfo => {
                    const fileTypeInfos = Array.isArray(fileTypeInfo) ? fileTypeInfo : [ fileTypeInfo ];
                    return fileTypeInfos.find(fti => {
                        if(!fti.sig || !fti.archiveHandler) {
                            return false;
                        }

                        const lenNeeded = fti.offset + fti.sig.length;

                        if(bytesRead < lenNeeded) {
                            return false;
                        }

                        const comp = buf.slice(fti.offset, fti.offset + fti.sig.length);
                        return (fti.sig.equals(comp));
                    });
                });

                closeFile(fd);
                return cb(archFormat ? null : Errors.General('Unknown type'), archFormat);
            });
        });
    }

    spawnHandler(proc, action, cb) {
        //  pty.js doesn't currently give us a error when things fail,
        //  so we have this horrible, horrible hack:
        let err;
        proc.once('data', d => {
            if(_.isString(d) && d.startsWith('execvp(3) failed.')) {
                err = Errors.ExternalProcess(`${action} failed: ${d.trim()}`);
            }
        });

        proc.once('exit', exitCode => {
            return cb(exitCode ? Errors.ExternalProcess(`${action} failed with exit code: ${exitCode}`) : err);
        });
    }

    compressTo(archType, archivePath, files, cb) {
        const archiver = this.getArchiver(archType, paths.extname(archivePath));

        if(!archiver) {
            return cb(Errors.Invalid(`Unknown archive type: ${archType}`));
        }

        const fmtObj = {
            archivePath : archivePath,
            fileList    : files.join(' '),  //  :TODO: probably need same hack as extractTo here!
        };

        const args = archiver.compress.args.map( arg => stringFormat(arg, fmtObj) );

        let proc;
        try {
            proc = pty.spawn(archiver.compress.cmd, args, this.getPtyOpts());
        } catch(e) {
            return cb(e);
        }

        return this.spawnHandler(proc, 'Compression', cb);
    }

    extractTo(archivePath, extractPath, archType, fileList, cb) {
        let haveFileList;

        if(!cb && _.isFunction(fileList)) {
            cb = fileList;
            fileList = [];
            haveFileList = false;
        } else {
            haveFileList = true;
        }

        const archiver = this.getArchiver(archType, paths.extname(archivePath));

        if(!archiver) {
            return cb(Errors.Invalid(`Unknown archive type: ${archType}`));
        }

        const fmtObj = {
            archivePath     : archivePath,
            extractPath     : extractPath,
        };

        let action = haveFileList ? 'extract' : 'decompress';
        if('extract' === action && !_.isObject(archiver[action])) {
            //  we're forced to do a full decompress
            action = 'decompress';
            haveFileList = false;
        }

        //  we need to treat {fileList} special in that it should be broken up to 0:n args
        const args = archiver[action].args.map( arg => {
            return '{fileList}' === arg ? arg : stringFormat(arg, fmtObj);
        });

        const fileListPos = args.indexOf('{fileList}');
        if(fileListPos > -1) {
            //  replace {fileList} with 0:n sep file list arguments
            args.splice.apply(args, [fileListPos, 1].concat(fileList));
        }

        let proc;
        try {
            proc = pty.spawn(archiver[action].cmd, args, this.getPtyOpts(extractPath));
        } catch(e) {
            return cb(e);
        }

        return this.spawnHandler(proc, (haveFileList ? 'Extraction' : 'Decompression'), cb);
    }

    listEntries(archivePath, archType, cb) {
        const archiver = this.getArchiver(archType, paths.extname(archivePath));

        if(!archiver) {
            return cb(Errors.Invalid(`Unknown archive type: ${archType}`));
        }

        const fmtObj = {
            archivePath     : archivePath,
        };

        const args  = archiver.list.args.map( arg => stringFormat(arg, fmtObj) );

        let proc;
        try {
            proc = pty.spawn(archiver.list.cmd, args, this.getPtyOpts());
        } catch(e) {
            return cb(e);
        }

        let output = '';
        proc.on('data', data => {
            //  :TODO: hack for: execvp(3) failed.: No such file or directory

            output += data;
        });

        proc.once('exit', exitCode => {
            if(exitCode) {
                return cb(Errors.ExternalProcess(`List failed with exit code: ${exitCode}`));
            }

            const entryGroupOrder = archiver.list.entryGroupOrder || { byteSize : 1, fileName : 2 };

            const entries = [];
            const entryMatchRe = new RegExp(archiver.list.entryMatch, 'gm');
            let m;
            while((m = entryMatchRe.exec(output))) {
                entries.push({
                    byteSize    : parseInt(m[entryGroupOrder.byteSize]),
                    fileName    : m[entryGroupOrder.fileName].trim(),
                });
            }

            return cb(null, entries);
        });
    }

    getPtyOpts(extractPath) {
        const opts = {
            name    : 'enigma-archiver',
            cols    : 80,
            rows    : 24,
            env     : process.env,
        };
        if(extractPath) {
            opts.cwd = extractPath;
        }
        //  :TODO: set cwd to supplied temp path if not sepcific extract
        return opts;
    }
};
<|endoftext|>


<commit_before>var path = require('path');
var webpack = require('webpack');
var _ = require('lodash');

var baseConfig = require('./base');

// Add needed plugins here
var BowerWebpackPlugin = require('bower-webpack-plugin');

var config = _.merge({
  entry: [
    'webpack-dev-server/client?http://127.0.0.1:8000',
    'webpack/hot/only-dev-server',
    './src/components/run'
  ],
  cache: true,
  devtool: 'eval',
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoErrorsPlugin(),
    new BowerWebpackPlugin({
      searchResolveModulesDirectories: false
    })
  ]
}, baseConfig);

// Add needed loaders
config.module.loaders.push({
  test: /\.(js|jsx)$/,
  loader: 'react-hot!babel-loader',
  include: path.join(__dirname, '/../src')
});

module.exports = config;
<commit_msg>change reference to app.js removing reference to run.js<commit_after>var path = require('path');
var webpack = require('webpack');
var _ = require('lodash');

var baseConfig = require('./base');

// Add needed plugins here
var BowerWebpackPlugin = require('bower-webpack-plugin');

var config = _.merge({
  entry: [
    'webpack-dev-server/client?http://127.0.0.1:8000',
    'webpack/hot/only-dev-server',
    './src/components/app'
  ],
  cache: true,
  devtool: 'eval',
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoErrorsPlugin(),
    new BowerWebpackPlugin({
      searchResolveModulesDirectories: false
    })
  ]
}, baseConfig);

// Add needed loaders
config.module.loaders.push({
  test: /\.(js|jsx)$/,
  loader: 'react-hot!babel-loader',
  include: path.join(__dirname, '/../src')
});

module.exports = config;
<|endoftext|>


<commit_before>/**
 * Created by Freddy Snijder on 14/12/14.
 */
(function() {
    var NS              = null;

    var _l              = null;
    var _               = null;
    var Class           = null;

    var $               = null;

    var __isNode = (typeof module !== 'undefined' && typeof module.exports !== 'undefined');
    if (__isNode) {
        //UNTESTED : Based on Zepto-node
        var Domino  = require('domino');
        var Zepto   = require('zepto-node');

        var _window = Domino.createWindow();

        $           = Zepto(_window);

        _           = require('../../util.js').utils;
        _l          = require('../../logger.js').logger;

        Class       = jsface.Class;

        NS          = exports;
    } else {
        //Add to Visionscapers namespace
        NS          = window.__VI__ || window;

        _           = NS.utils;
        _l          = NS.logger;

        $           = window.$;
        Class       = window.jsface.Class;
    }

    NS.ZeptoJSAPIMixin = Class({

        /**
         *
         * Mixin to implement HTTPAPI with the ZeptoJS library
         * Uses JSON as content type
         *
         * @module          corelib-web
         * @class           ZeptoJSAPIMixin
         *
         * @for             HTTPAPI
         *
         */

        $statics : {

            getResponseHeaders : function(xhr) {
                var me      = "ZeptoJSAPIMixin::getResponseHeaders";
                var headers = null;

                if (!_.hasMethod(xhr, 'getAllResponseHeaders')) {
                    _l.error(me, "XHR object is not valid, unable to get response headers");
                    return headers;
                }

                var headerStr = xhr.getAllResponseHeaders();

                //From https://github.com/visionmedia/superagent
                var lines = headerStr.split(/\r?\n/);
                var index;
                var line;
                var field;
                var val;

                headers = {};

                lines.pop(); // trailing CRLF

                for (var i = 0, len = lines.length; i < len; ++i) {
                    line = lines[i];
                    index = line.indexOf(':');
                    field = line.slice(0, index).toLowerCase();
                    val = _.trim(line.slice(index + 1));
                    headers[field] = val;
                }

                return headers;
            }

        },

        /***************************************************************
         *
         * PROTECTED METHODS
         *
         ***************************************************************/
        /**
         *
         * Method that creates a request so it can be send
         * Used by {{#crossLink "HTTPAPI:request"}}{{/crossLink}}
         *
         * This method needs to be overridden by any subclass
         *
         * @method _createRequest
         * @protected
         *
         * @param {String} method           HTTP Method name
         * @param {String} url              Path to resource
         * @param {Object|null} data        data to send
         *
         * @return {Object}                 request object
         */
        _createRequest : function(method, url, data) {
            var me = this.getIName() + "::ZeptoJSAPIMixin::_createRequest";

            if (_.string(method)) {
                method = method.toUpperCase();
                if (method == "DEL") {
                    method = "DELETE";
                }
            } else {
                _l.error(me, "No valid request method provided, unable to create request object.");
                return null;
            }

            return {
                type            : method,
                url             : url,
                data            : _.stringify(data, null, 0),
                contentType     : "application/json",
                dataType        : "json",
                beforeSend      : function(xhr) { xhr.withCredentials = true },
            };
        },

        /**
         *
         * Method that sends requests
         * Used by {{#crossLink "HTTPAPI:request"}}{{/crossLink}}
         *
         * This method needs to be overridden by any subclass
         *
         * @method _sendRequest
         * @protected
         *
         * @param {Object} req                              Request object.
         *                                                  See {{#crossLink "HTTPAPI:_createRequest"}}{{/crossLink}}
         * @param {Function} internalResponseCb             Callback function(data, err, status, headers) on response
         *
         * @return {Boolean}                                True when sending of the request was successful, else false
         *
         * @protected
         */
        _sendRequest : function(req, internalResponseCb) {
            var me      = this.getIName() + "::ZeptoJSAPIMixin::_sendRequest";
            var success = false;

            internalResponseCb = _.ensureFunc(internalResponseCb);

            if (!_.hasMethod($, 'ajax')) {
                _l.error(me, "Expected ajax method not found on $, unable to send request");
                return success;
            }

            if (!_.obj(req)) {
                _l.error(me, "Request is not a valid object, unable to send request");
                return success;
            }

            req.success = function(data, status, xhr) {
                internalResponseCb(data, null, status, ZeptoJSAPIMixin.getResponseHeaders(xhr));
            };

            req.error   = function(xhr, errorType, error) {
                xhr = xhr || {};

                var status  = xhr.status;
                var data    = null;
                if (errorType != "abort") {
                    try {
                        data = JSON.parse(xhr.responseText);
                    } catch(e) {
                        _l.error(me, "Unable to JSON parse {0} error response text".fmt(xhr.status));
                        data = {
                            message : "Unkown error, error response (status : {0}) could not be JSON parsed".fmt(xhr.status),
                            originalError : error
                        };
                    }
                } else {
                    data = {
                        message : "Request aborted, do you have an Internet connection? Service might also be offline.",
                        originalError : error
                    };
                }

                if (!_.def(data.status)) {
                    data.status = status;
                }

                internalResponseCb(
                        null,
                        data,
                        xhr.status,
                        ZeptoJSAPIMixin.getResponseHeaders(xhr));
            };

            $.ajax(req);

            success = true;
            return success;
        }
    });
})();
<commit_msg>Implementation of _setRequestHeader for ZeptoJS + fixed data was not converted in to url query parameters fro GET requests<commit_after>/**
 * Created by Freddy Snijder on 14/12/14.
 */
(function() {
    var NS              = null;

    var _l              = null;
    var _               = null;
    var Class           = null;

    var $               = null;

    var __isNode = (typeof module !== 'undefined' && typeof module.exports !== 'undefined');
    if (__isNode) {
        //UNTESTED : Based on Zepto-node
        var Domino  = require('domino');
        var Zepto   = require('zepto-node');

        var _window = Domino.createWindow();

        $           = Zepto(_window);

        _           = require('../../util.js').utils;
        _l          = require('../../logger.js').logger;

        Class       = jsface.Class;

        NS          = exports;
    } else {
        //Add to Visionscapers namespace
        NS          = window.__VI__ || window;

        _           = NS.utils;
        _l          = NS.logger;

        $           = window.$;
        Class       = window.jsface.Class;
    }

    NS.ZeptoJSAPIMixin = Class({

        /**
         *
         * Mixin to implement HTTPAPI with the ZeptoJS library
         * Uses JSON as content type
         *
         * @module          corelib-web
         * @class           ZeptoJSAPIMixin
         *
         * @for             HTTPAPI
         *
         */

        $statics : {

            getResponseHeaders : function(xhr) {
                var me      = "ZeptoJSAPIMixin::getResponseHeaders";
                var headers = null;

                if (!_.hasMethod(xhr, 'getAllResponseHeaders')) {
                    _l.error(me, "XHR object is not valid, unable to get response headers");
                    return headers;
                }

                var headerStr = xhr.getAllResponseHeaders();

                //From https://github.com/visionmedia/superagent
                var lines = headerStr.split(/\r?\n/);
                var index;
                var line;
                var field;
                var val;

                headers = {};

                lines.pop(); // trailing CRLF

                for (var i = 0, len = lines.length; i < len; ++i) {
                    line = lines[i];
                    index = line.indexOf(':');
                    field = line.slice(0, index).toLowerCase();
                    val = _.trim(line.slice(index + 1));
                    headers[field] = val;
                }

                return headers;
            }

        },

        /***************************************************************
         *
         * PROTECTED METHODS
         *
         ***************************************************************/
        /**
         *
         * Method that creates a request so it can be send
         * Used by {{#crossLink "HTTPAPI:request"}}{{/crossLink}}
         *
         * This method needs to be overridden by any subclass
         *
         * @method _createRequest
         * @protected
         *
         * @param {String} method           HTTP Method name
         * @param {String} url              Path to resource
         * @param {Object|null} data        data to send
         *
         * @return {Object}                 request object
         */
        _createRequest : function(method, url, data) {
            var me = this.getIName() + "::ZeptoJSAPIMixin::_createRequest";

            if (_.string(method)) {
                method = method.toUpperCase();
                if (method == "DEL") {
                    method = "DELETE";
                }
            } else {
                _l.error(me, "No valid request method provided, unable to create request object.");
                return null;
            }

            return {
                type            : method,
                url             : url,
                data            : _.def(data) ? ((method == "GET") ? $.param(data) : _.stringify(data, null, 0)) : null,
                contentType     : "application/json",
                dataType        : "json",
                beforeSend      : function(xhr) { xhr.withCredentials = true },
            };
        },

        _setRequestHeader : function(req, headerName, headerValue) {
            var me      = this.getIName() + "::SuperAgentMixin::_setRequestHeader";
            var success = false;

            if (!_.obj(req)) {
                _l.error(me, "Provided request is invalid unable to set header [{0}]".fmt(headerName));
                return success;
            }

            if (!_.string(headerName) || (_.empty(headerName))) {
                _l.error(me, "Provided header name is not valid, unable to set header".fmt(headerName));
                return success;
            }

            req.headers = req.headers || {};
            req.headers[headerName] = headerValue;

            return (success = true);
        },

        /**
         *
         * Method that sends requests
         * Used by {{#crossLink "HTTPAPI:request"}}{{/crossLink}}
         *
         * This method needs to be overridden by any subclass
         *
         * @method _sendRequest
         * @protected
         *
         * @param {Object} req                              Request object.
         *                                                  See {{#crossLink "HTTPAPI:_createRequest"}}{{/crossLink}}
         * @param {Function} internalResponseCb             Callback function(data, err, status, headers) on response
         *
         * @return {Boolean}                                True when sending of the request was successful, else false
         *
         * @protected
         */
        _sendRequest : function(req, internalResponseCb) {
            var me      = this.getIName() + "::ZeptoJSAPIMixin::_sendRequest";
            var success = false;

            internalResponseCb = _.ensureFunc(internalResponseCb);

            if (!_.hasMethod($, 'ajax')) {
                _l.error(me, "Expected ajax method not found on $, unable to send request");
                return success;
            }

            if (!_.obj(req)) {
                _l.error(me, "Request is not a valid object, unable to send request");
                return success;
            }

            req.success = function(data, status, xhr) {
                internalResponseCb(data, null, status, ZeptoJSAPIMixin.getResponseHeaders(xhr));
            };

            req.error   = function(xhr, errorType, error) {
                xhr = xhr || {};

                var status  = xhr.status;
                var data    = null;
                if (errorType != "abort") {
                    try {
                        data = JSON.parse(xhr.responseText);
                    } catch(e) {
                        _l.error(me, "Unable to JSON parse {0} error response text".fmt(xhr.status));
                        data = {
                            message : "Unkown error, error response (status : {0}) could not be JSON parsed".fmt(xhr.status),
                            originalError : error
                        };
                    }
                } else {
                    data = {
                        message : "Request aborted, do you have an Internet connection? Service might also be offline.",
                        originalError : error
                    };
                }

                if (!_.def(data.status)) {
                    data.status = status;
                }

                internalResponseCb(
                        null,
                        data,
                        xhr.status,
                        ZeptoJSAPIMixin.getResponseHeaders(xhr));
            };

            $.ajax(req);

            success = true;
            return success;
        }
    });
})();
<|endoftext|>


<commit_before>var net = require('net');
var util = require('./index');
var logger = require('./logger');
var config = require('../config');
var socketMgr = require('../socket-mgr');

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

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

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

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

function resetBinding() {
  binding = false;
}

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

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

  var now = Date.now();
  var _ids = [];
  var overflow = len - OVERFLOW_LENGTH;
  if (overflow >= 0) {
    overflow = overflow + MAX_LENGTH * 2;
  }
  for (var i = 0; i < len; i++) {
    var id = ids[i];
    var curData = reqData[id];
    if (i > overflow &&
      (curData.endTime ? now - curData.endTime < CACHE_TIME : now - curData.startTime < TIMEOUT)) {
      _ids.push(id);
    } else {
      delete reqData[id];
      if (--len <= MIN_LENGTH) {
        ids = _ids.concat(ids.slice(i + 1));
        return;
      }
    }
  }
  ids = _ids;
}

function getIds(startTime, count, lastRowId) {
  startTime = startTime || lastRowId;
  if (!startTime) {
    return ids.slice(-count);
  }
  var index = 0;
  if (startTime !== '0') {
    index = ids.indexOf(startTime) + 1;
  }
  return ids.slice(index, index + count);
}

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

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

function decodeData(frame) {
  if (frame.base64 == null) {
    frame.base64 = frame.bin ? frame.bin.toString('base64') : '';
    frame.bin = '';
  }
  return frame;
}
function handleFrame(data) {
  frames.push(data);
}

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

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

  function toBase64String(data) {
    if (Buffer.isBuffer(data.body)) {
      data.base64 = data.body.toString('base64');
      data.body = '';
    }
  }

  proxy.enableCapture = enable;
  proxy.getItem = function(id) {
    var item = reqData[id];
    if (item) {
      toBase64String(item.req);
      toBase64String(item.res);
    }
    return item;
  };

  proxy.getData = function(options, clientIp) {
    enable();
    options = options || {};
    var filter = formatFilter(options, clientIp);
    var data = {};
    var count = options.count;
    var startTime = options.startTime;
    var clearNetwork = count == 0 || startTime == -2;
    if (!clearNetwork) {
      count = count > 0 && count < COUNT ? +count : COUNT;
    }
    var newIds = (clearNetwork || startTime == -1) ? [] : getIds(startTime, count, options.lastRowId);
    var setData = function(item) {
      if (item) {
        var req = item.req;
        var res = item.res;
        toBase64String(req);
        toBase64String(res);
        if (config.secureFilter) {
          try {
            item = config.secureFilter(item, clientIp, filter) || item;
          } catch (e) {
            if (config.debugMode) {
              /* eslint-disable no-console */
              console.log(e);
            }
            logger.error(e);
          }
        }
        data[item.id] = item;
      }
    };
    if (newIds.length > 0) {
      if (filter) {
        var id = newIds[0];
        var index = ids.indexOf(newIds[0]);
        newIds = [];
        while(id && count > 0) {
          var item = reqData[id];
          if (checkItem(item, filter)) {
            setData(item);
            newIds.push(id);
            --count;
          }
          id = ids[++index];
        }
      } else if (!filter) {
        getList(newIds).forEach(setData);
      }
    }
    getList(options.ids).forEach(setData);
    var endId = ids[ids.length - 1];
    return {
      ids: options.ids || [],
      newIds: newIds,
      data: data,
      lastId: clearNetwork ? endId : newIds[newIds.length - 1],
      endId: endId,
      frames: getFrames(options.curReqId, options.lastFrameId),
      socketStatus: socketMgr.getStatus(options.curReqId)
    };
  };
};
<commit_msg>refactor: data server<commit_after>var net = require('net');
var util = require('./index');
var logger = require('./logger');
var config = require('../config');
var socketMgr = require('../socket-mgr');

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

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

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

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

function resetBinding() {
  binding = false;
}

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

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

  var now = Date.now();
  var _ids = [];
  var overflow = len - OVERFLOW_LENGTH;
  if (overflow >= 0) {
    overflow = overflow + MAX_LENGTH * 2;
  }
  for (var i = 0; i < len; i++) {
    var id = ids[i];
    var curData = reqData[id];
    if (i > overflow &&
      (curData.endTime ? now - curData.endTime < CACHE_TIME : now - curData.startTime < TIMEOUT)) {
      _ids.push(id);
    } else {
      delete reqData[id];
      if (--len <= MIN_LENGTH) {
        ids = _ids.concat(ids.slice(i + 1));
        return;
      }
    }
  }
  ids = _ids;
}

function getIds(startTime, count, lastRowId) {
  startTime = startTime || lastRowId;
  if (!startTime) {
    return ids.slice(-count);
  }
  var index = 0;
  if (startTime !== '0') {
    index = ids.indexOf(startTime) + 1;
  }
  return ids.slice(index, index + count);
}

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

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

function decodeData(frame) {
  if (frame.base64 == null) {
    frame.base64 = frame.bin ? frame.bin.toString('base64') : '';
    frame.bin = '';
  }
  return frame;
}
function handleFrame(data) {
  frames.push(data);
}

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

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

  function toBase64String(data) {
    if (Buffer.isBuffer(data.body)) {
      data.base64 = data.body.toString('base64');
      data.body = '';
    }
  }

  proxy.enableCapture = enable;
  proxy.getItem = function(id) {
    var item = reqData[id];
    if (item) {
      toBase64String(item.req);
      toBase64String(item.res);
    }
    return item;
  };

  proxy.getData = function(options, clientIp) {
    enable();
    options = options || {};
    var filter = formatFilter(options, clientIp);
    var data = {};
    var count = options.count;
    var startTime = options.startTime;
    var clearNetwork = count == 0 || startTime == -2;
    if (!clearNetwork) {
      count = count > 0 && count < COUNT ? +count : COUNT;
    }
    var newIds = (clearNetwork || startTime == -1) ? [] : getIds(startTime, count, options.lastRowId);
    var setData = function(item) {
      if (item) {
        var req = item.req;
        var res = item.res;
        toBase64String(req);
        toBase64String(res);
        if (config.secureFilter) {
          try {
            item = config.secureFilter(item, clientIp, filter) || item;
          } catch (e) {
            if (config.debugMode) {
              /* eslint-disable no-console */
              console.log(e);
            }
            logger.error(e);
          }
        }
        data[item.id] = item;
      }
    };
    if (newIds.length > 0) {
      if (filter) {
        var id = newIds[0];
        var index = ids.indexOf(newIds[0]);
        newIds = [];
        while(id && count > 0) {
          var item = reqData[id];
          if (checkItem(item, filter)) {
            setData(item);
            newIds.push(id);
            --count;
          }
          id = ids[++index];
        }
      } else if (!filter) {
        getList(newIds).forEach(setData);
      }
    }
    getList(options.ids).forEach(setData);
    var endId = ids[ids.length - 1];
    return {
      ids: options.ids || [],
      newIds: newIds,
      data: data,
      lastId: clearNetwork ? endId : newIds[newIds.length - 1],
      endId: endId,
      frames: getFrames(options.curReqId, options.lastFrameId),
      socketStatus: socketMgr.getStatus(options.curReqId)
    };
  };
};
<|endoftext|>


<commit_before>var debug = require('debug')('crowi:lib:middlewares');

exports.loginChecker = function(crowi, app) {
  return function(req, res, next) {
    var User = crowi.model('User');

    // session に user object が入ってる
    if (req.session.user && '_id' in req.session.user) {
      User.findById(req.session.user._id, function(err, userData) {
        if (err) {
          next();
        } else {
          req.user = req.session.user = userData;
          res.locals.user = req.user;
          next();
        }
      });
    } else {
      req.user = req.session.user = false;
      res.locals.user = req.user;
      next();
    }
  };
};

exports.swigFunctions = function(crowi, app) {
  return function(req, res, next) {
    require('../util/swigFunctions')(crowi, app, res.locals);
    next();
  };
};

exports.swigFilters = function(app, swig) {
  return function(req, res, next) {

    swig.setFilter('path2name', function(string) {
      return string.replace(/.+\/(.+)?$/, '$1');
    });

    swig.setFilter('datetz', function(input, format) {
      // timezone
      var swigFilters = require('swig/lib/filters');
      return swigFilters.date(input, format, app.get('tzoffset'));
    });

    swig.setFilter('presentation', function(string) {
      // 手抜き
      return string
        .replace(/[\n]+#/g, '\n\n\n#')
        .replace(/\s(https?.+(jpe?g|png|gif))\s/, '\n\n\n![]($1)\n\n\n');
    });

    swig.setFilter('picture', function(user) {
      if (!user) {
        return '';
      }

      user.fbId = user.userId; // migration
      if (user.image && user.image != '/images/userpicture.png') {
        return user.image;
      } else if (user.fbId) {
        return '//graph.facebook.com/' + user.fbId + '/picture?size=square';
      } else {
        return '/images/userpicture.png';
      }
    });

    next();
  };
};

exports.adminRequired = function() {
  return function(req, res, next) {
    if (req.user && '_id' in req.user) {
      if (req.user.admin) {
        next();
        return;
      }
      return res.redirect('/');
    }
    return res.redirect('/login');
  };
};

exports.loginRequired = function(crowi, app) {
  return function(req, res, next) {
    var User = crowi.model('User')

    if (req.user && '_id' in req.user) {
      if (req.user.status === User.STATUS_ACTIVE) {
        // Active の人だけ先に進める
        return next();
      } else if (req.user.status === User.STATUS_REGISTERED) {
        return res.redirect('/login/error/registered');
      } else if (req.user.status === User.STATUS_SUSPENDED) {
        return res.redirect('/login/error/suspended');
      } else if (req.user.status === User.STATUS_INVITED) {
        return res.redirect('/login/invited');
      }
    }

    req.session.jumpTo = req.originalUrl;
    return res.redirect('/login');
  };
};

exports.accessTokenParser = function(crowi, app) {
  return function(req, res, next) {
    var accessToken = req.query.access_token;
    if (!accessToken) {
      return next();
    }

    var User = crowi.model('User')

    User.findUserByApiToken(accessToken)
    .then(function(userData) {
      req.user = userData;
      next();
    }).catch(function(err) {
      next();
    });
  };
};

// this is for Installer
exports.applicationNotInstalled = function() {
  return function(req, res, next) {
    var config = req.config;

    if (Object.keys(config.crowi).length !== 1) {
      return res.render('500', { error: 'Application already installed.' });
    }

    return next();
  };
};

exports.applicationInstalled = function() {
  return function(req, res, next) {
    var config = req.config;

    if (Object.keys(config.crowi).length === 1) { // app:url is set by process
      return res.redirect('/installer');
    }

    return next();
  };
};

exports.awsEnabled = function() {
  return function (req, res, next) {
    var config = req.config;
    if (config.crowi['aws:region'] !== '' && config.crowi['aws:bucket'] !== '' && config.crowi['aws:accessKeyId'] !== '' && config.crowi['aws:secretAccessKey'] !== '') {
      req.flash('globalError', 'AWS settings required to use this function. Please ask the administrator.');
      return res.redirect('/');
    }

    return next();
  };
};
<commit_msg>Improve page path detection<commit_after>var debug = require('debug')('crowi:lib:middlewares');

exports.loginChecker = function(crowi, app) {
  return function(req, res, next) {
    var User = crowi.model('User');

    // session に user object が入ってる
    if (req.session.user && '_id' in req.session.user) {
      User.findById(req.session.user._id, function(err, userData) {
        if (err) {
          next();
        } else {
          req.user = req.session.user = userData;
          res.locals.user = req.user;
          next();
        }
      });
    } else {
      req.user = req.session.user = false;
      res.locals.user = req.user;
      next();
    }
  };
};

exports.swigFunctions = function(crowi, app) {
  return function(req, res, next) {
    require('../util/swigFunctions')(crowi, app, res.locals);
    next();
  };
};

exports.swigFilters = function(app, swig) {
  return function(req, res, next) {

    swig.setFilter('path2name', function(string) {
      var name = string;
      if (string.match(/.+\/([^/]+\/\d{4}\/\d{2}\/\d{2})$/)) { // /.../hoge/YYYY/MM/DD 形式のページ
        return string.replace(/.+\/([^/]+\/\d{4}\/\d{2}\/\d{2})$/, '$1');
      }
      if (string.match(/.+\/([^/]+\/\d{4}\/\d{2})$/)) { // /.../hoge/YYYY/MM 形式のページ
        return string.replace(/.+\/([^/]+\/\d{4}\/\d{2})$/, '$1');
      }
      if (string.match(/.+\/([^/]+\/\d{4})$/)) { // /.../hoge/YYYY 形式のページ
        return string.replace(/.+\/([^/]+\/\d{4})$/, '$1');
      }

      return string.replace(/.+\/(.+)?$/, '$1'); // ページの末尾を拾う
    });

    swig.setFilter('datetz', function(input, format) {
      // timezone
      var swigFilters = require('swig/lib/filters');
      return swigFilters.date(input, format, app.get('tzoffset'));
    });

    swig.setFilter('presentation', function(string) {
      // 手抜き
      return string
        .replace(/[\n]+#/g, '\n\n\n#')
        .replace(/\s(https?.+(jpe?g|png|gif))\s/, '\n\n\n![]($1)\n\n\n');
    });

    swig.setFilter('picture', function(user) {
      if (!user) {
        return '';
      }

      user.fbId = user.userId; // migration
      if (user.image && user.image != '/images/userpicture.png') {
        return user.image;
      } else if (user.fbId) {
        return '//graph.facebook.com/' + user.fbId + '/picture?size=square';
      } else {
        return '/images/userpicture.png';
      }
    });

    next();
  };
};

exports.adminRequired = function() {
  return function(req, res, next) {
    if (req.user && '_id' in req.user) {
      if (req.user.admin) {
        next();
        return;
      }
      return res.redirect('/');
    }
    return res.redirect('/login');
  };
};

exports.loginRequired = function(crowi, app) {
  return function(req, res, next) {
    var User = crowi.model('User')

    if (req.user && '_id' in req.user) {
      if (req.user.status === User.STATUS_ACTIVE) {
        // Active の人だけ先に進める
        return next();
      } else if (req.user.status === User.STATUS_REGISTERED) {
        return res.redirect('/login/error/registered');
      } else if (req.user.status === User.STATUS_SUSPENDED) {
        return res.redirect('/login/error/suspended');
      } else if (req.user.status === User.STATUS_INVITED) {
        return res.redirect('/login/invited');
      }
    }

    req.session.jumpTo = req.originalUrl;
    return res.redirect('/login');
  };
};

exports.accessTokenParser = function(crowi, app) {
  return function(req, res, next) {
    var accessToken = req.query.access_token;
    if (!accessToken) {
      return next();
    }

    var User = crowi.model('User')

    User.findUserByApiToken(accessToken)
    .then(function(userData) {
      req.user = userData;
      next();
    }).catch(function(err) {
      next();
    });
  };
};

// this is for Installer
exports.applicationNotInstalled = function() {
  return function(req, res, next) {
    var config = req.config;

    if (Object.keys(config.crowi).length !== 1) {
      return res.render('500', { error: 'Application already installed.' });
    }

    return next();
  };
};

exports.applicationInstalled = function() {
  return function(req, res, next) {
    var config = req.config;

    if (Object.keys(config.crowi).length === 1) { // app:url is set by process
      return res.redirect('/installer');
    }

    return next();
  };
};

exports.awsEnabled = function() {
  return function (req, res, next) {
    var config = req.config;
    if (config.crowi['aws:region'] !== '' && config.crowi['aws:bucket'] !== '' && config.crowi['aws:accessKeyId'] !== '' && config.crowi['aws:secretAccessKey'] !== '') {
      req.flash('globalError', 'AWS settings required to use this function. Please ask the administrator.');
      return res.redirect('/');
    }

    return next();
  };
};
<|endoftext|>


<commit_before>
var request = global.modules.request;
var sync = global.modules.sync;
var util = global.util;
var database = global.database;

var ranks = global.data.ranks;
var options = global.options;
var styles = global.styles;

var run = function (callbacks, args) {
    for (var key in callbacks) {
        if (typeof callbacks[key] == "function") {
            callbacks[key].apply(null, args);
        }
    }
};

var joinPadding = {};

var viewerHandler = {
    getUser: function (username) {
        var user = sync.wait(database.users.findOne({name: username}), 'exec', [sync.defer('user')]);
        user = (user && 'user' in user && user.user)? user.user : {name: username, rank: (
            username == global.bot.channel ? ranks.broadcaster : (
                username == global.options.twitch.identity ? ranks.bot : null
            )
        )};
        if (user.rank == null) user = undefined;
        return user;
    },
    updateUser: function (user, data) {
        var result = this.getUser(user.name);
        if (result) {
            user = result;
            var update = {};
            var savedRank = user.rank;
            var ircRank = data.rank;
            if (typeof ircRank == "number") {
                if (typeof savedRank == "number" && savedRank >= 0) {
                    if (ircRank < savedRank || ircRank > Math.floor(savedRank / 2) * 2) {
                        // TODO cleanup
                    } else {
                        if (savedRank == ranks.new && user.time >= options.core.userTrustTime) {
                            savedRank = ranks.viewer;
                            util.chatter.log(null, options.output.trustUser.weaveStrict(user.name));
                        }
                        update.rank = savedRank;
                    }
                } else update.rank = ircRank;
            }
            if (update) {
                try {
                    var result = sync.wait(user.update({$set: update}, {}), 'exec', [sync.defer('result')]).result;
                } catch (err) {
                    util.chatter.log(null, "something went wrong? " + err);
                }
            }
        }
        return user;
    },
    update: function () {
        for (var username in joinPadding) {
            if (--joinPadding[username] == 0) {
                delete joinPadding[username];
            }
        }
        request('https://tmi.twitch.tv/group/user/' + global.bot.channel + '/chatters', function (error, response, body) {
            if (!error && response.statusCode == 200) {
                var twitchList = JSON.parse(body).chatters;

                var chatters = {};
                for (var i = 0; i < twitchList.viewers.length; i++) {
                    chatters[twitchList.viewers[i]] = ranks.new;
                }
                for (var i = 0; i < twitchList.moderators.length; i++) {
                    chatters[twitchList.moderators[i]] = ranks.mod;
                }

                for (var username in chatters) {
                    var u = viewerHandler.getUser(username);
                    if (!u || !u.chatting) {
                        viewerHandler.join({name: username, rank: chatters[username]});
                    } else {
                        viewerHandler.updateUser(username, {rank: chatters[username]});
                    }
                }
                var oldChatters = sync.wait(database.users.find({chatting: true}), 'exec', [sync.defer('users')]).users;
                for (var i = 0; i < oldChatters.length; i++) {
                    var username = oldChatters[i].name;
                    // and for any user that was here and isn't anymore...
                    if (!(username in chatters || username in joinPadding)) viewerHandler.part(username);
                }
            }
        });
    },
    join: function (user) {
        if (options.core.blacklist.indexOf(user.name) < 0) {
            viewerHandler.create({name: user.name, rank: user.rank});
            joinPadding[user.name] = 2;
            var existing = viewerHandler.getUser(user.name);
            if (!existing) {
            }
            user = existing;
            if (!user.chatting) {
                if (user) {
                    user = viewerHandler.updateUser(username, {rank: rank});
                    util.chatter.log(null, styles.event.join(user.name + ' has joined!'));
                    run(viewerHandler.on.join, [user]);
                } else {
                }
            }
        } else return false;
    },
    create: function (user) {
        var now = new Date();
        var newUser = new global.database.users({
            name: user.name,
            time: 0,
            create: now,
            rank: user.rank,
            chatting: true
        });
        var result = sync.wait(newUser, 'save');
        console.log(result);

        util.chatter.log(null, styles.event.join(user.name + ' has joined!'));
        run(viewerHandler.on.create, [user, callback]);
        if (callback) callback(user);
    },
    part: function (username) {
        var user = viewerHandler.getUser(username);
        if (user.chatting && user.rank < ranks.broadcaster) {
            util.chatter.log(null, styles.event.leave(username + ' has left!'));
            user.update({$set: {
                chatting: false
            }});
            run(viewerHandler.on.part, [username]);
        }
    },
    on: {
        join: {},
        part: {},
        create: {}
    },
    stats: {
        rank: function (user) {
            for (var name in ranks) if (ranks[name] == user.rank) return name;
            return "unknown" + (typeof user.rank == "number" ? " (" + user.rank + ")" : "");
        }
    }
};

module.exports = viewerHandler;<commit_msg>cleaning up after myself<commit_after><|endoftext|>