<commit_before>var dgram = require('dgram')

var DELAY = 800
var FREQ = 100
var lastSend = 0

module.exports = {
  init: init,
  send: send,
  getVersion: getVersion,
  getSerial: getSerial,
  getEnergy: getEnergy
}

var sequenceNumber = 100;
var callbacks = [];
var version = "Unknown"
var serial = "Unknown"
var energy = "Unknown"

var server = dgram.createSocket("udp4");

var queue = [];

function getVersion() {
  return version
}

function getSerial() {
  return serial
}

function getEnergy() {
  return energy
}

server.on("error", function (err) {
  console.warn("server error:\n" + err.stack);
  server.close();
});

server.on("message", function (msg, rinfo) {
  var str = String(msg)

  if (str.charAt(0) == '*') {
    var obj = JSON.parse(str.substring(2))

    if (obj.type == 'hub') {
      version = obj.fw
      serial = '74:0A:BC:' + obj.mac
    } else if (obj.type == 'energy') {
      energy = obj.cUse
    }
  } else {
    var recvSequenceNumber = 'S' + String(msg).substring(0, 3)

    var callback = false

    if (callbacks[recvSequenceNumber]) {
      callbacks[recvSequenceNumber](msg, rinfo)
      delete callbacks[recvSequenceNumber]
      callback = true
    }
  }

  console.log("recv: " + String(msg).replace('\n', '') + " (callback=" + callback + ")")
});

server.on("listening", function () {
  server.setBroadcast(true);
});

server.bind(9761);

function init(callback) {
  send("@H", "", "", "", "Retrieving", "Version", null)
}

function send(command, room, device, func, line1, line2, callback) {
  for (i = 0; i < queue.length; i++) {
    if (queue[i].room == room && queue[i].device == device && queue[i].func.substring(0,1) == func.substring(0,1)) {
      // removedCallback = queue[i].callback

      console.log('Duplicate message dropped ', JSON.stringify(queue[i]))

      queue.splice(i, 1);

      removedCallback("100,OK", null)
    }
  }

  if (callback) {
    callback("100,OK", null)
  }

  queue.push({command: command, room: room, device: device, func: func, line1: line1, line2: line2, callback: callback});
}

function sendFromQueue() {
  var now = new Date().getTime()

  if (now > lastSend + DELAY) {
    var command = queue.shift();

    if (command) {
      var buffer = new Buffer(sequenceNumber + "," +
        (command.command? command.command : "!") +
        (command.room? "R" + command.room : "") +
        (command.device? "D" + command.device : "") +
        (command.func? "F" + command.func : "") +
        "|" + (command.line1? command.line1 : "") +
        "|" + (command.line2? command.line2 : "") +
        "\n");

      // if (command.callback) {
      //   callbacks[String('S' + sequenceNumber)] = command.callback;
      // }

      if( sequenceNumber++ == 1000) {
        sequenceNumber = 100;
      }

      console.log("send: " + buffer.toString().replace('\n', ''));

      server.send(buffer, 0, buffer.length, 9760, "255.255.255.255", function(err, bytes) {
        if (err) {
          console.error(err);
        }
      });
    }

    lastSend = now
  }
}

setInterval(sendFromQueue, FREQ);
<commit_msg>Call callbacks immediately.<commit_after>var dgram = require('dgram')

var DELAY = 800
var FREQ = 100
var lastSend = 0

module.exports = {
  init: init,
  send: send,
  getVersion: getVersion,
  getSerial: getSerial,
  getEnergy: getEnergy
}

var sequenceNumber = 100;
var callbacks = [];
var version = "Unknown"
var serial = "Unknown"
var energy = "Unknown"

var server = dgram.createSocket("udp4");

var queue = [];

function getVersion() {
  return version
}

function getSerial() {
  return serial
}

function getEnergy() {
  return energy
}

server.on("error", function (err) {
  console.warn("server error:\n" + err.stack);
  server.close();
});

server.on("message", function (msg, rinfo) {
  var str = String(msg)

  if (str.charAt(0) == '*') {
    var obj = JSON.parse(str.substring(2))

    if (obj.type == 'hub') {
      version = obj.fw
      serial = '74:0A:BC:' + obj.mac
    } else if (obj.type == 'energy') {
      energy = obj.cUse
    }
  } else {
    var recvSequenceNumber = 'S' + String(msg).substring(0, 3)

    var callback = false

    if (callbacks[recvSequenceNumber]) {
      callbacks[recvSequenceNumber](msg, rinfo)
      delete callbacks[recvSequenceNumber]
      callback = true
    }
  }

  console.log("recv: " + String(msg).replace('\n', '') + " (callback=" + callback + ")")
});

server.on("listening", function () {
  server.setBroadcast(true);
});

server.bind(9761);

function init(callback) {
  send("@H", "", "", "", "Retrieving", "Version", null)
}

function send(command, room, device, func, line1, line2, callback) {
  for (i = 0; i < queue.length; i++) {
    if (queue[i].room == room && queue[i].device == device && queue[i].func.substring(0,1) == func.substring(0,1)) {
      // removedCallback = queue[i].callback

      console.log('Duplicate message dropped ', JSON.stringify(queue[i]))

      queue.splice(i, 1);

      //removedCallback("100,OK", null)
    }
  }

  if (callback) {
    callback("100,OK", null)
  }

  queue.push({command: command, room: room, device: device, func: func, line1: line1, line2: line2, callback: callback});
}

function sendFromQueue() {
  var now = new Date().getTime()

  if (now > lastSend + DELAY) {
    var command = queue.shift();

    if (command) {
      var buffer = new Buffer(sequenceNumber + "," +
        (command.command? command.command : "!") +
        (command.room? "R" + command.room : "") +
        (command.device? "D" + command.device : "") +
        (command.func? "F" + command.func : "") +
        "|" + (command.line1? command.line1 : "") +
        "|" + (command.line2? command.line2 : "") +
        "\n");

      // if (command.callback) {
      //   callbacks[String('S' + sequenceNumber)] = command.callback;
      // }

      if( sequenceNumber++ == 1000) {
        sequenceNumber = 100;
      }

      console.log("send: " + buffer.toString().replace('\n', ''));

      server.send(buffer, 0, buffer.length, 9760, "255.255.255.255", function(err, bytes) {
        if (err) {
          console.error(err);
        }
      });
    }

    lastSend = now
  }
}

setInterval(sendFromQueue, FREQ);
<|endoftext|>


<commit_before>(function(){

var HTTPResponse = function() {
    this._output = false;
    this._ct = false; /* Content-type - the only header which must be present */
}

HTTPResponse.prototype.write = function(str) {
    if (!this._output) {
	this._output = true;
	if (!this._ct) { this.header({"Content-type":"text/html"}); }
	System.stdout("\n");
    }
    System.stdout(str);
}

HTTPResponse.prototype.cookie = function(name, value, expires, path, domain, secure, httponly) {
    if (expires && !(expires instanceof Date)) { return false; }
    var arr = [];
    arr.push(encodeURIComponent(name)+"="+encodeURIComponent(value));
    if (expires) { arr.push("expires="+expires.toGMTString()); }
    if (path) { arr.push("path="+path); }
    if (domain) { arr.push("domain="+domain); }
    if (secure) { arr.push("secure"); }
    if (httponly) { arr.push("httponly"); }

    var str = arr.join("; ");
    this.header({"Set-Cookie":str});
    return true;
}

HTTPResponse.prototype.error = function(txt) {
    this.write("
Error: "+txt+"
");
}

HTTPResponse.prototype.header = function(h) {
    for (var p in h) {
	if (p.match(/content-type/i)) { this._ct = true; }
	if (p.match(/location/i)) { this.header({"Status":"302 Found"}); }
	var str = p+": "+h[p]+"\n";
	System.stdout(str);
    }
}

HTTPResponse.prototype.escape = function(str) {
    if (!str) { return ""; }
    return str.toString().replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'"); // "
}

HTTPResponse.prototype.dump = function(obj, depth) {
    var d = depth || 0;
    if (!d) { this.write("
\n"); }
    for (var p in obj) {
	var val = obj[p];
	for (var i=0;i<2*d;i++) { this.write(" "); }
	this.write(p+": "+this.escape(val)+"\n");
	if (typeof(val) == "object") {
	    arguments.callee.call(this, val, d+1);
	}
    }
    if (!d) { this.write("
\n"); }
}

var HTTPRequest = function() {
    this.get = {};
    this.post = {};
    this.cookie = {};
    this.files = {};

    this.method = null;
    if (System.env["REQUEST_METHOD"]) { this.method = System.env["REQUEST_METHOD"].toUpperCase(); }
    if (!this.method) { return; }

    this._parseCookie();
    this._parseQS(System.env["QUERY_STRING"], this.get);
    if (this.method == "POST") { this._parsePOST(); }
}

HTTPRequest.prototype.header = function(name) {
    var n = "HTTP_" + name.toUpperCase().replace(/-/g,"_");
    return (n in System.env ? System.env[n] : null);
}

HTTPRequest.prototype._parseCookie = function() {
    if (!("HTTP_COOKIE" in System.env)) { return; }
    var all = System.env["HTTP_COOKIE"].split("; ");
    for (var i=0;i<all.length;i++) {
	var row = all[i];
	var eq = row.indexOf("=");
	var name = row.substring(0,eq);
	var value = row.substring(eq+1);
	if (!this.cookie[name]) { this.cookie[name] = unescape(value); }
    }
}

HTTPRequest.prototype._decode = function(str) {
    var s = str;
    var err = false;
    try {
		s = decodeURIComponent(str);
    } catch(e) {
	//	response.error("Cannot urldecode string");
    } finally {
		return s;
    }
}

HTTPRequest.prototype._parseQS = function(qs, output) {
    if (!qs) { return; }
    var parts = qs.split("&");
    for (var i=0;i<parts.length;i++) {
	var item = parts[i];
	if (!item) { continue; }
	var eq = item.indexOf("=");
	var name = "";
	var value = "";

	if (eq == -1) {
	    name = item;
	} else {
	    name = item.substring(0,eq);
	    value = item.substring(eq+1);
	}
	if (name.substring(name.length-2) == "[]") { name = name.substring(0,name.length-2); }

	name = this._decode(name);
	value = this._decode(value);

	this._addField(output, name, value);
    }
}

HTTPRequest.prototype._parsePOST = function() {
    var ct = System.env["CONTENT_TYPE"] || "";
    var length = parseInt(System.env["CONTENT_LENGTH"], 10);
    if (!length) { return false; }

    if (System.env["CONTENT_TYPE"] == "application/x-www-form-urlencoded") {
		var data = System.stdin(length);
		this._parseQS(data, this.post);
    } else if (ct.match(/boundary/)) {
		var arr = System.stdin(length, true);
		var str = String.fromCharCode.apply(this, arr); /* convert from array to string */
		this._parseMultipart(ct, str, false);
    } else {
		return false;
    }
    return true;
}

HTTPRequest.prototype._addField = function(output, name, value) {
    if (!(name in output)) {
        output[name] = value;
    } else if (output[name] instanceof Array) {
        output[name].push(value);
    } else {
	output[name] = [output[name], value];
    }
}

HTTPRequest.prototype._parseMultipart = function(header, data, name) {
    var boundary = header.match(/boundary=(.*)/); /* find boundary */
    boundary = boundary[1];
    var start = "--"+boundary+"\r\n";
    var end = "--"+boundary+"--";
    var parts = data.split(start); /* split by boundary */
    for (var i=0;i<parts.length;i++) { /* all multipart parts */
		var item = parts[i].substring(0, parts[i].length-2);
		if (item == "" || item == "--") { continue; }

		var lines = item.split("\r\n");
		var done = false;
		var obj = {
			headers:{},
			data:""
		};
		for (var j=0;j<lines.length;j++) {
			if (lines[j] == end) { continue; }
			if (done) { /* data */
			obj.data += (obj.data.length ? "\r\n" : "")+lines[j];
			} else { /* headers */
			if (lines[j] == "") { done = true; continue; } /* headers done */
			var r = lines[j].match(/([^:]+): *(.*)/);
			var name = r[1].replace(/-/g,"_").toUpperCase();
			var value = r[2];
			obj.headers[name] = value;
			}
		}
		this._processMultipart(obj, name); /* content parsed, decide how to handle it */
    }
}

HTTPRequest.prototype._processMultipart = function(obj, n) {
    var name = n;
    var cd = obj.headers["CONTENT_DISPOSITION"] || "";
    var ct = obj.headers["CONTENT_TYPE"] || "";
    var r = cd.match(/ name="(.*?)"/i); /* form field name */
    if (r) { name = r[1]; }
    if (ct.match(/multipart\/mixed/i)) { /* recursive processing */
		this._parseMultipart(ct, obj.data, name);
    } else { /* no recursion: either file or form field */
        var r = cd.match(/filename="(.*?)"/i);
		if (r) { /* file */
			obj.originalName = r[1];
			this._addField(this.files, name, obj);
		} else { /* form field */
			var utf = Util.utf8encode(obj.data);
			this._addField(this.post, name, utf);
		}
	}
}

var HTTPSession = function() {
    this._data = {};
    this._id = null;
    this._file = null;

    this._name = Config.sessionCookie || "V8SID";
    this._path = Config.sessionPath || "/tmp";
    this._domain = Config.sessionDomain || "/";
    if (this._path.charAt(this._path.length-1) != "/") { this._path += "/"; }
    this._lifetime = Config.sessionTime || 60*60;
    this._gc();

    var ok = false;
    if (request.cookie[this._name]) { /* cookie here */
	var id = request.cookie[this._name];
	var f = new File(this._fileName(id));
	if (f.exists()) { /* matching file */
	    this._id = id;
	    this._file = f;
	    this._load();
	    ok = true;
	}
    }
    if (!ok) {
	this.setId();
	this.clear();
    }

    var self = this;
    var callback = function() { self.save(); }
    onexit(callback);
}

HTTPSession.prototype.set = function(name, value) {
    this._data[name] = value;
}

HTTPSession.prototype.get = function(name) {
    return this._data[name] || null;
}

HTTPSession.prototype.clear = function() {
    this._data = {};
    if (this._file.exists()) { this._file.remove(); }
}

HTTPSession.prototype.save = function() {
    var propcnt = 0;
    for (var p in this._data) { propcnt++; }
    if (propcnt == 0) {
	if (this._file.exists()) { this._file.remove(); }
	return;
    }
    var str = Util.serialize(this._data);
    this._file.open("w").write(str).close();
}

HTTPSession.prototype.getId = function() {
    return this._id;
}

HTTPSession.prototype.setId = function(id) {
    this._id = id || this._newId();
    this._cookie();
    this._file = new File(this._fileName(this._id));
}

HTTPSession.prototype._newId = function() {
    var str = "";
    for (var i=0;i<3;i++) {
	str += Math.random().toString();
    }
    return Util.sha1(str);
}

HTTPSession.prototype._fileName = function(id) {
    return this._path + Util.sha1(id);
}

HTTPSession.prototype._gc = function() {
    var d = new Directory(this._path);
    var files = d.listFiles();
    var now = Math.round(new Date().getTime()/1000);
    for (var i=0;i<files.length;i++) {
	var file = new File(this._path + files[i]);
	var data = file.stat();
	if (now - data.atime > this._lifetime && now - data.mtime > this._lifetime) {
	    try { file.remove(); } catch(e) { }
	}
    }
}

HTTPSession.prototype._cookie = function() {
    var d = new Date();
    d.setFullYear(100+d.getFullYear());
    response.cookie(this._name, this._id, d, this._domain);
}

HTTPSession.prototype._load = function() {
    var str = this._file.open("r").read();
    this._file.close();
    this._data = Util.unserialize(str);
}

this.response = new HTTPResponse();
this.request = new HTTPRequest();
this.session = new HTTPSession();

})();
<commit_msg>fixed http escaping<commit_after>(function(){

var HTTPResponse = function() {
    this._output = false;
    this._ct = false; /* Content-type - the only header which must be present */
}

HTTPResponse.prototype.write = function(str) {
    if (!this._output) {
	this._output = true;
	if (!this._ct) { this.header({"Content-type":"text/html"}); }
	System.stdout("\n");
    }
    System.stdout(str);
}

HTTPResponse.prototype.cookie = function(name, value, expires, path, domain, secure, httponly) {
    if (expires && !(expires instanceof Date)) { return false; }
    var arr = [];
    arr.push(encodeURIComponent(name)+"="+encodeURIComponent(value));
    if (expires) { arr.push("expires="+expires.toGMTString()); }
    if (path) { arr.push("path="+path); }
    if (domain) { arr.push("domain="+domain); }
    if (secure) { arr.push("secure"); }
    if (httponly) { arr.push("httponly"); }

    var str = arr.join("; ");
    this.header({"Set-Cookie":str});
    return true;
}

HTTPResponse.prototype.error = function(txt) {
    this.write("
Error: "+txt+"
");
}

HTTPResponse.prototype.header = function(h) {
    for (var p in h) {
	if (p.match(/content-type/i)) { this._ct = true; }
	if (p.match(/location/i)) { this.header({"Status":"302 Found"}); }
	var str = p+": "+h[p]+"\n";
	System.stdout(str);
    }
}

HTTPResponse.prototype.escape = function(str) {
	if (!str.toString) { return ""; }
    return str.toString().replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'"); // "
}

HTTPResponse.prototype.dump = function(obj, depth) {
    var d = depth || 0;
    if (!d) { this.write("
\n"); }
    for (var p in obj) {
		var val = obj[p];
		for (var i=0;i<2*d;i++) { this.write(" "); }
		this.write(p+": "+this.escape(val)+"\n");
		if (typeof(val) == "object") {
	    	arguments.callee.call(this, val, d+1);
		}
    }
    if (!d) { this.write("
\n"); }
}

var HTTPRequest = function() {
    this.get = {};
    this.post = {};
    this.cookie = {};
    this.files = {};

    this.method = null;
    if (System.env["REQUEST_METHOD"]) { this.method = System.env["REQUEST_METHOD"].toUpperCase(); }
    if (!this.method) { return; }

    this._parseCookie();
    this._parseQS(System.env["QUERY_STRING"], this.get);
    if (this.method == "POST") { this._parsePOST(); }
}

HTTPRequest.prototype.header = function(name) {
    var n = "HTTP_" + name.toUpperCase().replace(/-/g,"_");
    return (n in System.env ? System.env[n] : null);
}

HTTPRequest.prototype._parseCookie = function() {
    if (!("HTTP_COOKIE" in System.env)) { return; }
    var all = System.env["HTTP_COOKIE"].split("; ");
    for (var i=0;i<all.length;i++) {
	var row = all[i];
	var eq = row.indexOf("=");
	var name = row.substring(0,eq);
	var value = row.substring(eq+1);
	if (!this.cookie[name]) { this.cookie[name] = unescape(value); }
    }
}

HTTPRequest.prototype._decode = function(str) {
    var s = str;
    var err = false;
    try {
		s = decodeURIComponent(str);
    } catch(e) {
	//	response.error("Cannot urldecode string");
    } finally {
		return s;
    }
}

HTTPRequest.prototype._parseQS = function(qs, output) {
    if (!qs) { return; }
    var parts = qs.split("&");
    for (var i=0;i<parts.length;i++) {
	var item = parts[i];
	if (!item) { continue; }
	var eq = item.indexOf("=");
	var name = "";
	var value = "";

	if (eq == -1) {
	    name = item;
	} else {
	    name = item.substring(0,eq);
	    value = item.substring(eq+1);
	}
	if (name.substring(name.length-2) == "[]") { name = name.substring(0,name.length-2); }

	name = this._decode(name);
	value = this._decode(value);

	this._addField(output, name, value);
    }
}

HTTPRequest.prototype._parsePOST = function() {
    var ct = System.env["CONTENT_TYPE"] || "";
    var length = parseInt(System.env["CONTENT_LENGTH"], 10);
    if (!length) { return false; }

    if (System.env["CONTENT_TYPE"] == "application/x-www-form-urlencoded") {
		var data = System.stdin(length);
		this._parseQS(data, this.post);
    } else if (ct.match(/boundary/)) {
		var arr = System.stdin(length, true);
		var str = String.fromCharCode.apply(this, arr); /* convert from array to string */
		this._parseMultipart(ct, str, false);
    } else {
		return false;
    }
    return true;
}

HTTPRequest.prototype._addField = function(output, name, value) {
    if (!(name in output)) {
        output[name] = value;
    } else if (output[name] instanceof Array) {
        output[name].push(value);
    } else {
	output[name] = [output[name], value];
    }
}

HTTPRequest.prototype._parseMultipart = function(header, data, name) {
    var boundary = header.match(/boundary=(.*)/); /* find boundary */
    boundary = boundary[1];
    var start = "--"+boundary+"\r\n";
    var end = "--"+boundary+"--";
    var parts = data.split(start); /* split by boundary */
    for (var i=0;i<parts.length;i++) { /* all multipart parts */
		var item = parts[i].substring(0, parts[i].length-2);
		if (item == "" || item == "--") { continue; }

		var lines = item.split("\r\n");
		var done = false;
		var obj = {
			headers:{},
			data:""
		};
		for (var j=0;j<lines.length;j++) {
			if (lines[j] == end) { continue; }
			if (done) { /* data */
			obj.data += (obj.data.length ? "\r\n" : "")+lines[j];
			} else { /* headers */
			if (lines[j] == "") { done = true; continue; } /* headers done */
			var r = lines[j].match(/([^:]+): *(.*)/);
			var name = r[1].replace(/-/g,"_").toUpperCase();
			var value = r[2];
			obj.headers[name] = value;
			}
		}
		this._processMultipart(obj, name); /* content parsed, decide how to handle it */
    }
}

HTTPRequest.prototype._processMultipart = function(obj, n) {
    var name = n;
    var cd = obj.headers["CONTENT_DISPOSITION"] || "";
    var ct = obj.headers["CONTENT_TYPE"] || "";
    var r = cd.match(/ name="(.*?)"/i); /* form field name */
    if (r) { name = r[1]; }
    if (ct.match(/multipart\/mixed/i)) { /* recursive processing */
		this._parseMultipart(ct, obj.data, name);
    } else { /* no recursion: either file or form field */
        var r = cd.match(/filename="(.*?)"/i);
		if (r) { /* file */
			obj.originalName = r[1];
			this._addField(this.files, name, obj);
		} else { /* form field */
			var utf = Util.utf8encode(obj.data);
			this._addField(this.post, name, utf);
		}
	}
}

var HTTPSession = function() {
    this._data = {};
    this._id = null;
    this._file = null;

    this._name = Config.sessionCookie || "V8SID";
    this._path = Config.sessionPath || "/tmp";
    this._domain = Config.sessionDomain || "/";
    if (this._path.charAt(this._path.length-1) != "/") { this._path += "/"; }
    this._lifetime = Config.sessionTime || 60*60;
    this._gc();

    var ok = false;
    if (request.cookie[this._name]) { /* cookie here */
	var id = request.cookie[this._name];
	var f = new File(this._fileName(id));
	if (f.exists()) { /* matching file */
	    this._id = id;
	    this._file = f;
	    this._load();
	    ok = true;
	}
    }
    if (!ok) {
	this.setId();
	this.clear();
    }

    var self = this;
    var callback = function() { self.save(); }
    onexit(callback);
}

HTTPSession.prototype.set = function(name, value) {
    this._data[name] = value;
}

HTTPSession.prototype.get = function(name) {
    return this._data[name] || null;
}

HTTPSession.prototype.clear = function() {
    this._data = {};
    if (this._file.exists()) { this._file.remove(); }
}

HTTPSession.prototype.save = function() {
    var propcnt = 0;
    for (var p in this._data) { propcnt++; }
    if (propcnt == 0) {
	if (this._file.exists()) { this._file.remove(); }
	return;
    }
    var str = Util.serialize(this._data);
    this._file.open("w").write(str).close();
}

HTTPSession.prototype.getId = function() {
    return this._id;
}

HTTPSession.prototype.setId = function(id) {
    this._id = id || this._newId();
    this._cookie();
    this._file = new File(this._fileName(this._id));
}

HTTPSession.prototype._newId = function() {
    var str = "";
    for (var i=0;i<3;i++) {
	str += Math.random().toString();
    }
    return Util.sha1(str);
}

HTTPSession.prototype._fileName = function(id) {
    return this._path + Util.sha1(id);
}

HTTPSession.prototype._gc = function() {
    var d = new Directory(this._path);
    var files = d.listFiles();
    var now = Math.round(new Date().getTime()/1000);
    for (var i=0;i<files.length;i++) {
	var file = new File(this._path + files[i]);
	var data = file.stat();
	if (now - data.atime > this._lifetime && now - data.mtime > this._lifetime) {
	    try { file.remove(); } catch(e) { }
	}
    }
}

HTTPSession.prototype._cookie = function() {
    var d = new Date();
    d.setFullYear(100+d.getFullYear());
    response.cookie(this._name, this._id, d, this._domain);
}

HTTPSession.prototype._load = function() {
    var str = this._file.open("r").read();
    this._file.close();
    this._data = Util.unserialize(str);
}

this.response = new HTTPResponse();
this.request = new HTTPRequest();
this.session = new HTTPSession();

})();
<|endoftext|>


<commit_before>/*jslint indent:2, white:true, node:true, sloppy:true */
var Link = require('freedom/src/link');
var Debug = require("./debug");

/**
 * A port providing message transport between two freedom contexts existing in
 * separate Node.js VMs.  Uses node's 'require("vm")' to generate a separate
 * namespace with a shared global object for communication. The module-side
 * implementation is in @see(lib/modulecontext.js)
 * @class NodeLink
 * @extends Link
 * @uses handleEvents
 * @constructor
 */
var NodeLink = function(id, resource) {
  Link.call(this, id, resource);
  this.id = id;
  this.started = false;
};

/**
 * Start this port.
 * @method start
 * @private
 */
NodeLink.prototype.start = function() {
  this.obj = require('child_process').fork(
    __dirname + '/../index.js',
    [ '--id="' + this.id + '"' ],
    Debug.nextExecArgv()
  );

  this.obj.on('message', function(msg) {
    if (!this.started) {
      this.emit('started');
      this.started = true;
      return;
    }
    this.fix(msg.message);
    this.emitMessage(msg.flow, msg.message);
  }.bind(this), true);
  this.obj.on('close', function() {
    delete this.obj;
    this.emitMessage('control', {type: 'close'});
  }.bind(this));
  this.obj.on('error', function(err) {
    this.resource.debug.error(err);
    delete this.obj;
    this.emitMessage('control', {type: 'close'});
  });
};

/**
 * Stop this port by deleting the frame.
 * @method stop
 * @private
 */
NodeLink.prototype.stop = function() {
  if (this.config.moduleContext) {
    process.exit();
  } else {
    this.obj.kill();
    delete this.obj;
  }
};

/**
 * Get the textual description of this port.
 * @method toString
 * @return {String} the description of this port.
 */
NodeLink.prototype.toString = function() {
  return "[NodeLink " + this.id + "]";
};

/**
 * Receive messages from the hub to this port.
 * Received messages will be emitted from the other side of the port.
 * @method deliverMessage
 * @param {String} flow the channel/flow of the message.
 * @param {Object} message The Message.
 */
NodeLink.prototype.deliverMessage = function(flow, message) {
  if (this.obj) {
    /* //- For Debugging Purposes -
    if (!this.config.moduleContext) {
      console.warn('->[' + flow + '] ' + JSON.stringify(message));
    } else {
      console.warn('<-[' + flow + '] ' + JSON.stringify(message));
    }
    */

    // Convert binary blobs into native buffers pre-send
    if (message && message.message && message.message.binary) {
      var out = [], i = 0;
      for (i = 0; i < message.message.binary.length; i += 1) {
        out.push(new Buffer(new Uint8Array(message.message.binary[i])));
      }
      message.message.binary = out;
    }
    this.obj.send({flow: flow, message: message});
  } else {
    this.once('started', this.onMessage.bind(this, flow, message));
  }
};

/**
 * Rewrite node buffers back to array buffers.
 */
NodeLink.prototype.fix = function(message) {
  if (message && message.message && message.message.message) {
    message.message.message = this.replaceBuffers(message.message.message);
    //console.log(message.message.message);
  }
  if (message && message.message && message.message.binary) {
    var out = [], i = 0;
    for (i = 0; i < message.message.binary.length;i += 1) {
      out.push(new Uint8Array(message.message.binary[i]).buffer);
    }
    message.message.binary = out;
  }
};

NodeLink.prototype.replaceBuffers = function(msg) {
  var retValue, i;
  if (typeof msg === 'object' && msg && msg.byteLength) {
    retValue = msg;
    try {
      retValue = new Uint8Array(new ArrayBuffer(msg.byteLength));
      for (i = 0; i < msg.byteLength; i+= 1) {
        retValue[i] = msg[i];
      }
    } catch (e) {
      console.error("Failed to convert ArrayBuffer");
    }
    return retValue;
  } else if (Array.isArray(msg)) {
    return msg.map(this.replaceBuffers.bind(this));
  } else if (typeof msg === 'object') {
    for (i in msg) {
      if (msg.hasOwnProperty(i)) {
        msg[i] = this.replaceBuffers(msg[i]);
      }
    }
    return msg;
  } else {
    return msg;
  }
};

module.exports = NodeLink;
<commit_msg>node message payloads now are in .data field<commit_after>/*jslint indent:2, white:true, node:true, sloppy:true */
var Link = require('freedom/src/link');
var Debug = require("./debug");

/**
 * A port providing message transport between two freedom contexts existing in
 * separate Node.js VMs.  Uses node's 'require("vm")' to generate a separate
 * namespace with a shared global object for communication. The module-side
 * implementation is in @see(lib/modulecontext.js)
 * @class NodeLink
 * @extends Link
 * @uses handleEvents
 * @constructor
 */
var NodeLink = function(id, resource) {
  Link.call(this, id, resource);
  this.id = id;
  this.started = false;
};

/**
 * Start this port.
 * @method start
 * @private
 */
NodeLink.prototype.start = function() {
  this.obj = require('child_process').fork(
    __dirname + '/../index.js',
    [ '--id="' + this.id + '"' ],
    Debug.nextExecArgv()
  );

  this.obj.on('message', function(msg) {
    if (!this.started) {
      this.emit('started');
      this.started = true;
      return;
    }
    this.fix(msg.message);
    this.emitMessage(msg.flow, msg.message);
  }.bind(this), true);
  this.obj.on('close', function() {
    delete this.obj;
    this.emitMessage('control', {type: 'close'});
  }.bind(this));
  this.obj.on('error', function(err) {
    this.resource.debug.error(err);
    delete this.obj;
    this.emitMessage('control', {type: 'close'});
  });
};

/**
 * Stop this port by deleting the frame.
 * @method stop
 * @private
 */
NodeLink.prototype.stop = function() {
  if (this.config.moduleContext) {
    process.exit();
  } else {
    this.obj.kill();
    delete this.obj;
  }
};

/**
 * Get the textual description of this port.
 * @method toString
 * @return {String} the description of this port.
 */
NodeLink.prototype.toString = function() {
  return "[NodeLink " + this.id + "]";
};

/**
 * Receive messages from the hub to this port.
 * Received messages will be emitted from the other side of the port.
 * @method deliverMessage
 * @param {String} flow the channel/flow of the message.
 * @param {Object} message The Message.
 */
NodeLink.prototype.deliverMessage = function(flow, message) {
  if (this.obj) {
    /* //- For Debugging Purposes -
    if (!this.config.moduleContext) {
      console.warn('->[' + flow + '] ' + JSON.stringify(message));
    } else {
      console.warn('<-[' + flow + '] ' + JSON.stringify(message));
    }
    */

    // Convert binary blobs into native buffers pre-send
    if (message && message.message && message.message.binary) {
      var out = [], i = 0;
      for (i = 0; i < message.message.binary.length; i += 1) {
        out.push(new Buffer(new Uint8Array(message.message.binary[i])));
      }
      message.message.binary = out;
    }
    this.obj.send({flow: flow, message: message});
  } else {
    this.once('started', this.onMessage.bind(this, flow, message));
  }
};

/**
 * Rewrite node buffers back to array buffers.
 */
NodeLink.prototype.fix = function(message) {
  if (message && message.message && message.message.message) {
    message.message.message = this.replaceBuffers(message.message.message);
  }
  if (message && message.message && message.message.binary) {
    var out = [], i = 0;
    for (i = 0; i < message.message.binary.length;i += 1) {
      if (process.versions.node < '0.12') {
        out.push(new Uint8Array(message.message.binary[i]).buffer);
      } else {
        out.push(new Uint8Array(message.message.binary[i].data).buffer);
      }
    }
    message.message.binary = out;
  }
};

NodeLink.prototype.replaceBuffers = function(msg) {
  var retValue, i;
  if (typeof msg === 'object' && msg && msg.byteLength) {
    retValue = msg;
    try {
      retValue = new Uint8Array(new ArrayBuffer(msg.byteLength));
      for (i = 0; i < msg.byteLength; i+= 1) {
        retValue[i] = msg[i];
      }
    } catch (e) {
      console.error("Failed to convert ArrayBuffer");
    }
    return retValue;
  } else if (Array.isArray(msg)) {
    return msg.map(this.replaceBuffers.bind(this));
  } else if (typeof msg === 'object') {
    for (i in msg) {
      if (msg.hasOwnProperty(i)) {
        msg[i] = this.replaceBuffers(msg[i]);
      }
    }
    return msg;
  } else {
    return msg;
  }
};

module.exports = NodeLink;
<|endoftext|>


<commit_before>var _      = require('underscore')
    , path = require('path');

/**
 * Parse JSON file confing and set controller
 *
 * @param app
 * @param options
 */
module.exports = function (app, options) {

    var jsonFileName = path.join(options.basePathJson, options.routeName + '.json');

    // load json file inside try catch, if not load exit
    try {
        var json = require(jsonFileName); // loading definition file
    } catch (ex) {

        console.log('\x1b[31m *** ROUTING FILE DEFINITION ERROR :' + jsonFileName + '\x1b[0m');
        console.log('\x1b[31m All routes inside this file are not loaded, please check json syntax!\x1b[0m');

        return true;
    }

    var basePathController = options.basePathController; // controller path file
    var basePathPolicy = options.basePathPolicy; // policy path file
    var controller = getControllerName(options.routeName); // controller name
    var globalMiddleware = []; // populate middleware get from global file
    var baseUrl = "";

    //set global file options
    setFileGlobalParams(json);

    // start parsing json file
    main();

    /**
     * main job
     * parse json file
     */
    function main() {

        for (uri in json) {
            // go to parse verbs
            parseRoutes(uri, json);
        }
    }

    /**
     * parse verbs
     * @param uri
     * @param json
     */
    function parseRoutes(uri, json) {

        for (key in json[uri]) {

            // route defaults
            var data = json[uri]
                , verb = key.toLowerCase()
                , action = "index"
                , middleware = null
                , regex = false
                , params = data[key]
                , pattern = path.join(baseUrl, uri)
                , controllerPath
                , route
                , routes
                , defaultRoute = controller + ":index";

            // set default route
            if (_.isUndefined(params.route)) params.route = defaultRoute;

            route = parseRoute(params.route);
            controllerPath = getControllerPath(route[0]);

            middleware = getMiddleware(params.policy);

            //check cors
            if(options.cors) {
                middleware = addCors(middleware);
            }

            regex = params.regex;
            routes = require(controllerPath);

            // get handler
            handler = routes[route[1]];

            if (regex) pattern = addRegex(regex, pattern);

            addRoute(middleware, verb, pattern, handler);
        }
    }

    function addCors(mdlw) {

        //exit if cors disabled
        if (!options.cors) {
             return mdlw;
        }

        //cors is required

        //no middleware, normalize as null array
        if (_.isNull(mdlw)) {
            mdlw = [];
        }

        //TODO var override, need to be changed
        //exist a middleware pass as string, normalize as array
        if (_.isString(mdlw)) {
            mdlw = [mdlw];
        }

        if (_.isArray(mdlw)) {

            // console.log('*****array' + mdlw.length);

            mdlw.push([function (req, res, next) {
                // console.log('cors array');
                res.header("Access-Control-Allow-Origin", "*");
                res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
                res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
                // res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");

                // intercept OPTIONS method
                if ('OPTIONS' == req.method) {
                    res.send(200);
                }
                else {
                    next();
                }
            }]);

            return mdlw;
        }

        console.log('impossible!!');
        return mdlw;
    }

    /**
     * create routes
     *
     * @param middleware
     * @param verb
     * @param pattern
     * @param handler
     */
    function addRoute(middleware, verb, pattern, handler) {

        try {

            if (middleware) {
                app[verb](pattern, middleware, handler);
            } else {
                app[verb](pattern, handler);
            }

        } catch (ex) {
            console.log('\x1b[31m*** ROUTIG ERROR: ' + pattern + '\x1b[0m');
            console.log('file: ' + jsonFileName);
            console.log('verb: ' + verb);
            console.log('error:' + ex);
            console.log('\x1b[31m****************\x1b[0m');
        }
    }

    /**
     * return array
     * [0] action
     * [1] controller
     *
     * @param routeParams
     * @returns {*}
     */
    function parseRoute(routeParams) {

        var result = [];

        // case no param is passed
        if (_.isUndefined(routeParams)) {
            result[0] = controller;
            result[1] = 'index';

            return result;
        }

        var arrayParams = routeParams.split(':');

        // params is passed only with action
        if (arrayParams.length == 1) {
            result[0] = controller;
            result[1] = routeParams;

            return result;
        }

        // all params
        return arrayParams;
    }

    /**
     * return controller path
     * if controller start with "." it start from project root
     * else use default dir
     *
     * @param controller
     * @returns {*}
     */
    function getControllerPath(controller) {

        if (startWith(controller, '.')) {
            // return dir from root project
            return path.join(options.processdir, controller + '.js');
        }

        // default dir
        return path.join(basePathController, controller + '.js');
    }

    /**
     * get middlewarePath
     *
     * @param middleware
     * @returns {string}
     */
    function getMiddlewarePath(middleware) {
        if (startWith(middleware, '.')) {
            // return dir from root project
            return path.join(options.processdir, middleware + '.js');
        }

        // default dir
        return path.join(basePathPolicy, middleware + '.js');
    }

    /**
     * return all middleware
     *
     * @param routeMiddleware
     * @returns {*}
     */
    function getAllMiddleWare(routeMiddleware) {

        if (globalMiddleware.length > 0) {

            // fix if policy is string and global array
            if (_.isString(routeMiddleware)) {
                routeMiddleware = [routeMiddleware];
            }

            return _.union(globalMiddleware, routeMiddleware);
        }
        return routeMiddleware;
    }

    /**
     * Parse middleware
     * check if is string or array and parse it
     *
     * @param input
     * @returns {*}
     */
    function getMiddleware(input) {

        var mdlw = getAllMiddleWare(input);

        if (_.isString(mdlw)) {

            var items = [];

            items.push(parseMiddleware(mdlw));

            return items;

        } else if (_.isArray(mdlw)) {

            var items = [];

            mdlw.forEach(function (item) {
                items.push(parseMiddleware(item));
            });

            return items;
        }

        return null;
    }

    /**
     * Parse middleware
     *
     * @param input
     * @returns {*}
     */
    function parseMiddleware(input) {

        var parts = input.split(':');

        // prevent malformed policy routes
        if (parts.length != 2) error(uri, "malformed json middleware");

        var middlewareFile = getMiddlewareFile(parts[0]);
        var middleware = require(middlewareFile);

        return middleware[parts[1]];
    }

    /**
     * return  middleware path
     *
     * @param fileName
     * @returns {string}
     */
    function getMiddlewareFile(fileName) {

        if (startWith(fileName, '.')) {
            return path.join(options.processdir, fileName + '.js');
        }

        return path.join(basePathPolicy, fileName + '.js');
    }

    /**
     * check if a string start with a value
     *
     * @param value
     * @param char
     * @returns {boolean}
     */
    function startWith(value, char) {

        if (value.substring(0, 1) == char) {
            return true;
        }

        return false;
    }

    /**
     * check for json global params
     *
     * @param json
     * @returns {boolean}
     */
    function checkGlobalVars(json) {
        if (_.isUndefined(json.GLOBAL)) {
            return false;
        }
        return true;
    }

    /**
     * override Global default params with Global
     * file if present
     *
     * @param json
     * @returns {boolean}
     */
    function setFileGlobalParams(json) {

        if (!checkGlobalVars(json)) {
            return true
        }

        if (checkGlobalVars(json)) {

            //check controllerPath
            if (json.GLOBAL.hasOwnProperty('controllerPath')) {
                basePathController = path.join(options.processdir, json.GLOBAL.controllerPath);
            }

            // check controller Name
            if (json.GLOBAL.hasOwnProperty('controller')) {
                controller = json.GLOBAL.controller;
            }

            // check policy Path
            if (json.GLOBAL.hasOwnProperty('policyPath')) {
                basePathPolicy = path.join(options.processdir, json.GLOBAL.policyPath);
            }

            // check global policy and add it
            if (json.GLOBAL.hasOwnProperty('policy')) {

                if (_.isString(json.GLOBAL.policy)) {
                    globalMiddleware.push(json.GLOBAL.policy);
                } else {
                    globalMiddleware = json.GLOBAL.policy;
                }
            }

            // check global file Base Url
            if (json.GLOBAL.hasOwnProperty('baseUrl')) {
                baseUrl = json.GLOBAL.baseUrl;
            }

            // sanitize json route removing global setting
            delete json.GLOBAL;
        }

        return true;
    }

    /**
     * cerate a valid route if regex is true
     *
     * @param regex
     * @param pattern
     * @returns {*}
     */
    function addRegex(regex, pattern) {

        // process RegEx!
        if (regex) {
            var regexPattern = pattern;
            var flags = "";

            // pull apart regex patten from the flags
            if (pattern.indexOf("/") != -1) {
                var regexParts = pattern.split('/');
                flags = regexParts.pop();

                // check to see if we need to strip off a starting slash
                if (regexParts[0].trim() == "") {
                    regexParts.shift();
                }

                regexPattern = regexParts.join("/");
            }

            return new RegExp(regexPattern, flags);
        }

        return pattern;
    }

    /**
     * controller name is composed:
     * route name capitalizzed + Controller
     * route = "ping"
     * controller = "PingController"
     * suffix ".js" is added later
     *
     * @param string
     * @returns {string}
     */
    function getControllerName(string) {
        return string.charAt(0).toUpperCase() + string.slice(1) + 'Controller';
    }

};

/**
 * set errors
 *
 * @param uri
 * @param reason
 */
function error(uri, reason) {
    throw new Error("For " + uri + " " + reason);
}<commit_msg>fix windows platform path!<commit_after>var _      = require('underscore')
    , path = require('path');

/**
 * Parse JSON file confing and set controller
 *
 * @param app
 * @param options
 */
module.exports = function (app, options) {

    var jsonFileName = path.join(options.basePathJson, options.routeName + '.json');

    // load json file inside try catch, if not load exit
    try {
        var json = require(jsonFileName); // loading definition file
    } catch (ex) {

        console.log('\x1b[31m *** ROUTING FILE DEFINITION ERROR :' + jsonFileName + '\x1b[0m');
        console.log('\x1b[31m All routes inside this file are not loaded, please check json syntax!\x1b[0m');

        return true;
    }

    var basePathController = options.basePathController; // controller path file
    var basePathPolicy = options.basePathPolicy; // policy path file
    var controller = getControllerName(options.routeName); // controller name
    var globalMiddleware = []; // populate middleware get from global file
    var baseUrl = "";

    //set global file options
    setFileGlobalParams(json);

    // start parsing json file
    main();

    /**
     * main job
     * parse json file
     */
    function main() {

        for (uri in json) {
            // go to parse verbs
            parseRoutes(uri, json);
        }
    }

    /**
     * parse verbs
     * @param uri
     * @param json
     */
    function parseRoutes(uri, json) {

        for (key in json[uri]) {

            // route defaults
            var data = json[uri]
                , verb = key.toLowerCase()
                , action = "index"
                , middleware = null
                , regex = false
                , params = data[key]
                , pattern = baseUrl + uri
                , controllerPath
                , route
                , routes
                , defaultRoute = controller + ":index";

            // set default route
            if (_.isUndefined(params.route)) params.route = defaultRoute;

            route = parseRoute(params.route);
            controllerPath = getControllerPath(route[0]);

            middleware = getMiddleware(params.policy);

            //check cors
            if(options.cors) {
                middleware = addCors(middleware);
            }

            regex = params.regex;
            routes = require(controllerPath);

            // get handler
            handler = routes[route[1]];

            if (regex) pattern = addRegex(regex, pattern);

            addRoute(middleware, verb, pattern, handler);
        }
    }

    function addCors(mdlw) {

        //exit if cors disabled
        if (!options.cors) {
             return mdlw;
        }

        //cors is required

        //no middleware, normalize as null array
        if (_.isNull(mdlw)) {
            mdlw = [];
        }

        //TODO var override, need to be changed
        //exist a middleware pass as string, normalize as array
        if (_.isString(mdlw)) {
            mdlw = [mdlw];
        }

        if (_.isArray(mdlw)) {

            // console.log('*****array' + mdlw.length);

            mdlw.push([function (req, res, next) {
                // console.log('cors array');
                res.header("Access-Control-Allow-Origin", "*");
                res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
                res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
                // res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");

                // intercept OPTIONS method
                if ('OPTIONS' == req.method) {
                    res.send(200);
                }
                else {
                    next();
                }
            }]);

            return mdlw;
        }

        console.log('impossible!!');
        return mdlw;
    }

    /**
     * create routes
     *
     * @param middleware
     * @param verb
     * @param pattern
     * @param handler
     */
    function addRoute(middleware, verb, pattern, handler) {

        try {

            if (middleware) {
                app[verb](pattern, middleware, handler);
            } else {
                app[verb](pattern, handler);
            }

        } catch (ex) {
            console.log('\x1b[31m*** ROUTIG ERROR: ' + pattern + '\x1b[0m');
            console.log('file: ' + jsonFileName);
            console.log('verb: ' + verb);
            console.log('error:' + ex);
            console.log('\x1b[31m****************\x1b[0m');
        }
    }

    /**
     * return array
     * [0] action
     * [1] controller
     *
     * @param routeParams
     * @returns {*}
     */
    function parseRoute(routeParams) {

        var result = [];

        // case no param is passed
        if (_.isUndefined(routeParams)) {
            result[0] = controller;
            result[1] = 'index';

            return result;
        }

        var arrayParams = routeParams.split(':');

        // params is passed only with action
        if (arrayParams.length == 1) {
            result[0] = controller;
            result[1] = routeParams;

            return result;
        }

        // all params
        return arrayParams;
    }

    /**
     * return controller path
     * if controller start with "." it start from project root
     * else use default dir
     *
     * @param controller
     * @returns {*}
     */
    function getControllerPath(controller) {

        if (startWith(controller, '.')) {
            // return dir from root project
            return path.join(options.processdir, controller + '.js');
        }

        // default dir
        return path.join(basePathController, controller + '.js');
    }

    /**
     * get middlewarePath
     *
     * @param middleware
     * @returns {string}
     */
    function getMiddlewarePath(middleware) {
        if (startWith(middleware, '.')) {
            // return dir from root project
            return path.join(options.processdir, middleware + '.js');
        }

        // default dir
        return path.join(basePathPolicy, middleware + '.js');
    }

    /**
     * return all middleware
     *
     * @param routeMiddleware
     * @returns {*}
     */
    function getAllMiddleWare(routeMiddleware) {

        if (globalMiddleware.length > 0) {

            // fix if policy is string and global array
            if (_.isString(routeMiddleware)) {
                routeMiddleware = [routeMiddleware];
            }

            return _.union(globalMiddleware, routeMiddleware);
        }
        return routeMiddleware;
    }

    /**
     * Parse middleware
     * check if is string or array and parse it
     *
     * @param input
     * @returns {*}
     */
    function getMiddleware(input) {

        var mdlw = getAllMiddleWare(input);

        if (_.isString(mdlw)) {

            var items = [];

            items.push(parseMiddleware(mdlw));

            return items;

        } else if (_.isArray(mdlw)) {

            var items = [];

            mdlw.forEach(function (item) {
                items.push(parseMiddleware(item));
            });

            return items;
        }

        return null;
    }

    /**
     * Parse middleware
     *
     * @param input
     * @returns {*}
     */
    function parseMiddleware(input) {

        var parts = input.split(':');

        // prevent malformed policy routes
        if (parts.length != 2) error(uri, "malformed json middleware");

        var middlewareFile = getMiddlewareFile(parts[0]);
        var middleware = require(middlewareFile);

        return middleware[parts[1]];
    }

    /**
     * return  middleware path
     *
     * @param fileName
     * @returns {string}
     */
    function getMiddlewareFile(fileName) {

        if (startWith(fileName, '.')) {
            return path.join(options.processdir, fileName + '.js');
        }

        return path.join(basePathPolicy, fileName + '.js');
    }

    /**
     * check if a string start with a value
     *
     * @param value
     * @param char
     * @returns {boolean}
     */
    function startWith(value, char) {

        if (value.substring(0, 1) == char) {
            return true;
        }

        return false;
    }

    /**
     * check for json global params
     *
     * @param json
     * @returns {boolean}
     */
    function checkGlobalVars(json) {
        if (_.isUndefined(json.GLOBAL)) {
            return false;
        }
        return true;
    }

    /**
     * override Global default params with Global
     * file if present
     *
     * @param json
     * @returns {boolean}
     */
    function setFileGlobalParams(json) {

        if (!checkGlobalVars(json)) {
            return true
        }

        if (checkGlobalVars(json)) {

            //check controllerPath
            if (json.GLOBAL.hasOwnProperty('controllerPath')) {
                basePathController = path.join(options.processdir, json.GLOBAL.controllerPath);
            }

            // check controller Name
            if (json.GLOBAL.hasOwnProperty('controller')) {
                controller = json.GLOBAL.controller;
            }

            // check policy Path
            if (json.GLOBAL.hasOwnProperty('policyPath')) {
                basePathPolicy = path.join(options.processdir, json.GLOBAL.policyPath);
            }

            // check global policy and add it
            if (json.GLOBAL.hasOwnProperty('policy')) {

                if (_.isString(json.GLOBAL.policy)) {
                    globalMiddleware.push(json.GLOBAL.policy);
                } else {
                    globalMiddleware = json.GLOBAL.policy;
                }
            }

            // check global file Base Url
            if (json.GLOBAL.hasOwnProperty('baseUrl')) {
                baseUrl = json.GLOBAL.baseUrl;
            }

            // sanitize json route removing global setting
            delete json.GLOBAL;
        }

        return true;
    }

    /**
     * cerate a valid route if regex is true
     *
     * @param regex
     * @param pattern
     * @returns {*}
     */
    function addRegex(regex, pattern) {

        // process RegEx!
        if (regex) {
            var regexPattern = pattern;
            var flags = "";

            // pull apart regex patten from the flags
            if (pattern.indexOf("/") != -1) {
                var regexParts = pattern.split('/');
                flags = regexParts.pop();

                // check to see if we need to strip off a starting slash
                if (regexParts[0].trim() == "") {
                    regexParts.shift();
                }

                regexPattern = regexParts.join("/");
            }

            return new RegExp(regexPattern, flags);
        }

        return pattern;
    }

    /**
     * controller name is composed:
     * route name capitalizzed + Controller
     * route = "ping"
     * controller = "PingController"
     * suffix ".js" is added later
     *
     * @param string
     * @returns {string}
     */
    function getControllerName(string) {
        return string.charAt(0).toUpperCase() + string.slice(1) + 'Controller';
    }

};

/**
 * set errors
 *
 * @param uri
 * @param reason
 */
function error(uri, reason) {
    throw new Error("For " + uri + " " + reason);
}<|endoftext|>


<commit_before>// Imports lib and tests from given paths

'use strict';

var path          = require('path')
  , vm            = require('vm')
  , fs            = require('fs')

  , commonLeft    = require('es5-ext/lib/Array/prototype/common-left')
  , merge         = require('es5-ext/lib/Object/prototype/merge')
  , endsWith      = require('es5-ext/lib/String/ends-with').call
  , deferred      = require('deferred/lib/deferred')
  , ba2p          = require('deferred/lib/async-to-promise').bind
  , requireSilent = require('next/lib/require-silent')(
		require('next/lib/require-in-context'))
  , requireFirst  = require('next/lib/require-first-in-tree')
  , ptrim         = require('next/lib/path/trim')

  , readFile = ba2p(fs.readFile)
  , dirname = path.dirname

  , ctxRequireSilent;

module.exports = function (testeePath, testPath, context, withcoverage) {
	var o, scopes;
	o = {
		testee: requireSilent(testeePath, context),
		test: requireSilent(testPath, context)
	};

	if (!o.test && endsWith(testeePath, '/index.js')) {
		o.test = require('./utils/index-test')(dirname(testeePath));
	}

	if (o.test && o.test.__generic) {
		scopes = requireFirst('__scopes', dirname(testPath),
			ptrim(testeePath.slice(0, commonLeft.call(testeePath, testPath))));
		merge.call(o.test, require('./utils/factory')(scopes, o.test.__generic));
		delete o.test.__generic;
	}

	return o;
};
<commit_msg>Update up to changes in es5-ext<commit_after>// Imports lib and tests from given paths

'use strict';

var path          = require('path')
  , vm            = require('vm')
  , fs            = require('fs')

  , commonLeft    = require('es5-ext/lib/Array/prototype/common-left')
  , merge         = require('es5-ext/lib/Object/prototype/merge')
  , endsWith      = require('es5-ext/lib/String/prototype/ends-with')
  , deferred      = require('deferred/lib/deferred')
  , ba2p          = require('deferred/lib/async-to-promise').bind
  , requireSilent = require('next/lib/require-silent')(
		require('next/lib/require-in-context'))
  , requireFirst  = require('next/lib/require-first-in-tree')
  , ptrim         = require('next/lib/path/trim')

  , readFile = ba2p(fs.readFile)
  , dirname = path.dirname

  , ctxRequireSilent;

module.exports = function (testeePath, testPath, context, withcoverage) {
	var o, scopes;
	o = {
		testee: requireSilent(testeePath, context),
		test: requireSilent(testPath, context)
	};

	if (!o.test && endsWith.call(testeePath, '/index.js')) {
		o.test = require('./utils/index-test')(dirname(testeePath));
	}

	if (o.test && o.test.__generic) {
		scopes = requireFirst('__scopes', dirname(testPath),
			ptrim(testeePath.slice(0, commonLeft.call(testeePath, testPath))));
		merge.call(o.test, require('./utils/factory')(scopes, o.test.__generic));
		delete o.test.__generic;
	}

	return o;
};
<|endoftext|>


<commit_before>
module.exports = logs;
logs.logs = logs;
logs.usage =  "\nfhc logs [get] <app-id> [log-name] [--live]"
            + "\nfhc logs stream <app-id> [log-name] [output-file] [--live]"
            + "\nfhc logs list <app-id> [--live]"
            + "\nfhc logs delete <app-id> <log-name> [--live]";

var log = require("./utils/log");
var fhc = require("./fhc");
var common = require("./common");
var util = require('util');
var ini = require('./utils/ini');
var fhreq = require("./utils/request");
var Table = require('cli-table');
var datejs = require('datejs');
var request = require('request');
var fs = require('fs');

// main logs entry point
function logs(args, cb) {
  if (args.length < 1) return cb(logs.usage);
  var target = ini.get('live') ? 'live' : 'development';

  // hack for using as a script, check if the last arg is trying to override target
  if (args[args.length -1] === 'live' || args[args.length -1] === 'development') {
    target = args[args.length -1];
    args.pop();
  }

  // Otherwise look for an action
  var action = args[0];
  if (action === "get") {
      if (!args[1]) return cb(logs.usage);
      var appId = fhc.appId(args[1]);
      var logName = args[2];
      return getLogs(appId, logName, target, cb);
  }if (action === "stream") {
      if (!args[3]) return cb(logs.usage);
      var appId = fhc.appId(args[1]);
      var logName = args[2];
      var outputFile = args[3];
      return streamLog(appId, logName, outputFile, target, cb);
  } else if (action === "list") {
    if (!args[1]) return cb(logs.usage);
    var appId = fhc.appId(args[1]);
    return listLogs(appId, target, cb);
  }else if (action === "delete") {
    if (!args[1]) return cb(logs.usage);
    if (!args[2]) return cb(logs.usage);
    var appId = fhc.appId(args[1]);
    return deleteLog(appId, args[2], target, cb);
  }else {
    // assume all params are for get
      var appId = fhc.appId(action);
      if(appId.length !== 24) return cb(logs.usage);
      var logName = args[1];
      return getLogs(appId, logName, target, cb);
  }
};

// get our log files
function listLogs (appId, target, cb) {
  var payload = {payload:{guid: appId, deploytarget: target, action: 'list'}};
  log.verbose(payload, 'Listing logs');
  common.doApiCall(fhreq.getFeedHenryUrl(), "box/srv/1.1/ide/" + fhc.domain + "/app/logs", payload,"Error getting logs: ", function(err, data){
    if(err) return cb(err);
    if(ini.get('table') === true) {
      createTableForLogs(data.logs);
    }
    return cb(err, data);
  });
};

// get list of log files
function getLogs (appId, logName, target, cb) {
  var payload = {payload:{guid: appId, deploytarget: target, logname: logName, 'action': 'get'}};
  log.verbose(payload, 'Getting logs');
  common.doApiCall(fhreq.getFeedHenryUrl(), "box/srv/1.1/ide/" + fhc.domain + "/app/logs", payload, "", function(err, data){
    if(err) return cb(err);
    log.verbose(data, "Response log");
    if(!logName) {
      // backward compatability..
      var lg = data.log ? data.log: data.logs;
      var logData = "\n====> stdout <====\n" + lg.stdout + "\n====> stderr <====\n" + lg.stderr;
      logs.message = logData;
    }else {
      logs.message = data.log.contents === '' ? '<empty>' : data.log.contents;
    }
    return cb(err, data);
  });
};

// delete log file
function deleteLog (appId, logName, target, cb) {
  var payload = {payload:{guid: appId, deploytarget: target, action: 'delete', logname: logName}};
  log.verbose(payload, 'Deleting log');
  common.doApiCall(fhreq.getFeedHenryUrl(), "box/srv/1.1/ide/" + fhc.domain + "/app/logs", payload,"Error deleting log: ", function(err, data){
    if(err) return cb(err);
    logs.message = JSON.parse(data.msg);
    return cb(err, data);
  });
};

// put our logs into table format..
function createTableForLogs(logz) {
  // calculate widths
  var maxName=4, maxSize=4, maxModified=8;
  var dateFormat = "ddd MMM dd yyyy HH:mm:ss";
  for (var l in logz) {
    var log = logz[l];
    var dt = new Date(log.modified);
    if(common.strlen(log.name) > maxName) maxName = common.strlen(log.name);
    if(common.strlen(log.size) > maxSize) maxSize = common.strlen(log.size);
    if(common.strlen(dt.toString()) > maxModified) maxModified = common.strlen(dt.toString(dateFormat));
  }

  // create our table
  logs.table = new Table({
    head: ['Name', 'Size', 'Modified'],
    colWidths: [maxName +2 , maxSize + 2, maxModified + 2],
    style: common.style()
  });

  // populate our table
  for (var l in logz) {
    var log = logz[l];
    logs.table.push([log.name, log.size, new Date(log.modified).toString(dateFormat)]);
  }
}

//
// Stream log file
// Note this purposely doesn't return json or set the .message property (unlike practically all other calls)
// Instead this streams the requested log file straight to another stream (file currently)
//
function streamLog(appId, logName, outputFile, target, cb) {
  if (target !== 'live') return cb("Cannot stream development log files currently, only live logs. Please use the '--live' flag to stream live log files.");

  // first get app endpoints
  common.getAppNameUrl(appId, target, function(err, appName, appUrl) {
    if(err) return cb(err);
    if(!appName) return cb(appId + " not found..");

    // TODO - check if no appName/appUrl found - errors not streaming properly from Request
    var url = appUrl.replace(appName, 'api');
    var fullUrl = url + "/streamlog/" + appName + "/" + logName;
    console.log("Streaming log to file: " + outputFile);

    //
    // Note: although we would like to stream directly to stdout here,
    // there is a bug in Request preventing us:
    // https://github.com/mikeal/request/issues/156
    // We could work around this by not using Request, but for now,
    // we stream to file.
    // request(fullUrl).pipe(process.stdout);
    //
    var str = fs.createWriteStream(outputFile);
    request(fullUrl).pipe(str);

    str.on("end", function(){
      return cb(undefined, 'File downloaded ok..');
    });

    str.on("close", function(){
      return cb(undefined, 'File downloaded ok..');
    });
  });
};

// bash completion
logs.completion = function (opts, cb) {
  var argv = opts.conf.argv.remain;
  if (argv[1] !== "logs") argv.unshift("logs");
  if (argv.length === 2) {
    var cmds = ["get", "list", "delete"];
    return cb(null, cmds);
  }

  var action = argv[2];
  switch (action) {
    case "get":
    case "list":
      common.getAppIds(cb);
      break;
    default: return cb(null, []);
  }
};
<commit_msg>streaming of log files enabled through fhc logs command<commit_after>
module.exports = logs;
logs.logs = logs;
logs.usage =  "\nfhc logs [get] <app-id> [log-name] [--live]"
            + "\nfhc logs stream <app-id> [log-name] [output-file] [--live]"
            + "\nfhc logs list <app-id> [--live]"
            + "\nfhc logs delete <app-id> <log-name> [--live]";

var log = require("./utils/log");
var fhc = require("./fhc");
var common = require("./common");
var util = require('util');
var ini = require('./utils/ini');
var fhreq = require("./utils/request");
var Table = require('cli-table');
var datejs = require('datejs');
var request = require('request');
var fs = require('fs');
var https = require('https');

// main logs entry point
function logs(args, cb) {

  if (args.length < 1) return cb(logs.usage);
  var target = ini.get('live') ? 'live' : 'development';

  // hack for using as a script, check if the last arg is trying to override target
  if (args[args.length -1] === 'live' || args[args.length -1] === 'development') {
    target = args[args.length -1];
    console.log(target);
    args.pop();
  }

  // Otherwise look for an action
  var action = args[0];
  if (action === "get") {
      if (!args[1]) return cb(logs.usage);
      var appId = fhc.appId(args[1]);
      var logName = args[2];
      return getLogs(appId, logName, target, cb);
  }if (action === "stream") {
      //if (!args[3]) return cb(logs.usage);
      var appId = fhc.appId(args[1]);
      var logName = args[2];
      var outputFile = args[3];
      return streamLog(appId, logName, outputFile, target, cb);
  } else if (action === "list") {
    if (!args[1]) return cb(logs.usage);
    var appId = fhc.appId(args[1]);
    return listLogs(appId, target, cb);
  }else if (action === "delete") {
    if (!args[1]) return cb(logs.usage);
    if (!args[2]) return cb(logs.usage);
    var appId = fhc.appId(args[1]);
    return deleteLog(appId, args[2], target, cb);
  }else {
    // assume all params are for get
      var appId = fhc.appId(action);
      if(appId.length !== 24) return cb(logs.usage);
      var logName = args[1];
      return getLogs(appId, logName, target, cb);
  }
};

// get our log files
function listLogs (appId, target, cb) {
  var payload = {payload:{guid: appId, deploytarget: target, action: 'list'}};
  log.verbose(payload, 'Listing logs');
  common.doApiCall(fhreq.getFeedHenryUrl(), "box/srv/1.1/ide/" + fhc.domain + "/app/logs", payload,"Error getting logs: ", function(err, data){
    if(err) return cb(err);
    if(ini.get('table') === true) {
      createTableForLogs(data.logs);
    }
    return cb(err, data);
  });
};

// get list of log files
function getLogs (appId, logName, target, cb) {
  var payload = {payload:{guid: appId, deploytarget: target, logname: logName, 'action': 'get'}};
  log.verbose(payload, 'Getting logs');
  common.doApiCall(fhreq.getFeedHenryUrl(), "box/srv/1.1/ide/" + fhc.domain + "/app/logs", payload, "", function(err, data){
    if(err) return cb(err);
    log.verbose(data, "Response log");
    if(!logName) {
      // backward compatability..
      var lg = data.log ? data.log: data.logs;
      var logData = "\n====> stdout <====\n" + lg.stdout + "\n====> stderr <====\n" + lg.stderr;
      logs.message = logData;
    }else {
      logs.message = data.log.contents === '' ? '<empty>' : data.log.contents;
    }
    return cb(err, data);
  });
};

// delete log file
function deleteLog (appId, logName, target, cb) {
  var payload = {payload:{guid: appId, deploytarget: target, action: 'delete', logname: logName}};
  log.verbose(payload, 'Deleting log');
  common.doApiCall(fhreq.getFeedHenryUrl(), "box/srv/1.1/ide/" + fhc.domain + "/app/logs", payload,"Error deleting log: ", function(err, data){
    if(err) return cb(err);
    logs.message = JSON.parse(data.msg);
    return cb(err, data);
  });
};

// put our logs into table format..
function createTableForLogs(logz) {
  // calculate widths
  var maxName=4, maxSize=4, maxModified=8;
  var dateFormat = "ddd MMM dd yyyy HH:mm:ss";
  for (var l in logz) {
    var log = logz[l];
    var dt = new Date(log.modified);
    if(common.strlen(log.name) > maxName) maxName = common.strlen(log.name);
    if(common.strlen(log.size) > maxSize) maxSize = common.strlen(log.size);
    if(common.strlen(dt.toString()) > maxModified) maxModified = common.strlen(dt.toString(dateFormat));
  }

  // create our table
  logs.table = new Table({
    head: ['Name', 'Size', 'Modified'],
    colWidths: [maxName +2 , maxSize + 2, maxModified + 2],
    style: common.style()
  });

  // populate our table
  for (var l in logz) {
    var log = logz[l];
    logs.table.push([log.name, log.size, new Date(log.modified).toString(dateFormat)]);
  }
}

//
// Stream log file
// Note this purposely doesn't return json or set the .message property (unlike practically all other calls)
// Instead this streams the requested log file straight to another stream (file currently)
//
function streamLog(appId, logName, outputFile, target, cb) {
  if (target !== 'live') return cb("Cannot stream development log files currently, only live logs. Please use the '--live' flag to stream live log files.");
  if(!logName) return cb("please specify which logfile to stream");
  // first get app endpoints
  common.getAppNameUrl(appId, target, function(err, appName, appUrl) {
    if(err) return cb(err);
    if(!appName) return cb(appId + " not found..");

    // TODO - check if no appName/appUrl found - errors not streaming properly from Request

      var url     = appUrl.replace(appName, 'api'),
      fullUrl     = url + "/streamlog/" + appName + "/" + logName,

      hosturl = url.replace("https://","");

       logrequest  = {
         host : hosturl,
         path : "/streamlog/" + appName + "/" + logName,
         method : 'GET',
         port : 443
       },

      sstream = (outputFile) ? fs.createWriteStream(outputFile) : undefined;

      //console.log(fullUrl);

      var req = https.request(logrequest, function(res){

        res.setEncoding('utf8');
        if(res.statusCode === 404){
          return cb("no logfile found");
        }
        res.on('data',function (chunk) {

          if(sstream === undefined){
            process.stdout.write(chunk);
          }else {
            sstream.write(chunk);
          }
        });
        res.on('end',function (){
            if(sstream){
              sstream.end();
              return cb(null, "log written "+outputFile);
            }else{
              return cb(null, "-- END --");
            }
        });
      });

      req.on('error',function(err){
         return cb(err.message);
      });
      req.end();

  });
};

// bash completion
logs.completion = function (opts, cb) {
  var argv = opts.conf.argv.remain;
  if (argv[1] !== "logs") argv.unshift("logs");
  if (argv.length === 2) {
    var cmds = ["get", "list", "delete"];
    return cb(null, cmds);
  }

  var action = argv[2];
  switch (action) {
    case "get":
    case "list":
      common.getAppIds(cb);
      break;
    default: return cb(null, []);
  }
};
<|endoftext|>


<commit_before>import Baobab from 'baobab';

// loads the user from the server state.
const user = window.STATE_FROM_SERVER && window.STATE_FROM_SERVER.user;

// loads the window location from the browser.
const location = window && window.location ? {
  href: window.location.href,
  origin: window.location.origin,
  pathname: window.location.pathname,
} : {};

// tree stores the global state of the application.
export const tree = new Baobab({
  // the user branch of the tree maintains the currently authenticated user
  // information, sourced from the STATE_FROM_SERVER global variable.
  user: user,

  // the location branch of the tree maintains the browser location, sourced
  // from the window.location global variable.
  location: location,

  // the repos branch of the tree maintains an index of repository nodes
  // organized by repository owner and repository name. For example:
  //
  // {
  //   "octocat": {
  //     "hello-world": { ... },
  //     "spoon-knife": { ... },
  //   }
  // }
  //
  repos: {},

  // the build branch of the tree maintains an index of builds nodes organized
  // by repository owner, name, and build number. For example:
  //
  // {
  //   "octocat": {
  //     "hello-world": {
  //       "1": { number: 1, ... },
  //       "2": { number: 2, ... },
  //     }
  //   }
  // }
  //
  builds: {},

  // the feed branch of the tree maintains an activity feed array, consisting
  // of the latest activity per repository.
  feed: [],

  // the selected tree tracks the selected repository, build and job.
  // repo: undefined,
  // build: undefined,
  // job: undefined,

  // the pages branch of the tree maintains miscellanous state for the pages
  // in the application, including dialag state, snackbar state, etc.
  pages: {
    account: {
      token: false,
      syncing: false
    },
    repo: {
      filter: undefined
    },
    build: {
      follow: false
    },
    loading: false,
    toast: undefined
  }
});
<commit_msg>fix lint error<commit_after>import Baobab from 'baobab';

// loads the user from the server state.
const user = window.STATE_FROM_SERVER && window.STATE_FROM_SERVER.user;

// loads the window location from the browser.
const location = window && window.location ? {
  href: window.location.href,
  origin: window.location.origin,
  pathname: window.location.pathname
} : {};

// tree stores the global state of the application.
export const tree = new Baobab({
  // the user branch of the tree maintains the currently authenticated user
  // information, sourced from the STATE_FROM_SERVER global variable.
  user: user,

  // the location branch of the tree maintains the browser location, sourced
  // from the window.location global variable.
  location: location,

  // the repos branch of the tree maintains an index of repository nodes
  // organized by repository owner and repository name. For example:
  //
  // {
  //   "octocat": {
  //     "hello-world": { ... },
  //     "spoon-knife": { ... },
  //   }
  // }
  //
  repos: {},

  // the build branch of the tree maintains an index of builds nodes organized
  // by repository owner, name, and build number. For example:
  //
  // {
  //   "octocat": {
  //     "hello-world": {
  //       "1": { number: 1, ... },
  //       "2": { number: 2, ... },
  //     }
  //   }
  // }
  //
  builds: {},

  // the feed branch of the tree maintains an activity feed array, consisting
  // of the latest activity per repository.
  feed: [],

  // the selected tree tracks the selected repository, build and job.
  // repo: undefined,
  // build: undefined,
  // job: undefined,

  // the pages branch of the tree maintains miscellanous state for the pages
  // in the application, including dialag state, snackbar state, etc.
  pages: {
    account: {
      token: false,
      syncing: false
    },
    repo: {
      filter: undefined
    },
    build: {
      follow: false
    },
    loading: false,
    toast: undefined
  }
});
<|endoftext|>


<commit_before>/* eslint-env mocha */
/* eslint max-nested-callbacks: ["error", 8] */
'use strict'

const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
const isNode = require('detect-node')
const loadFixture = require('aegir/fixtures')

const FactoryClient = require('./ipfs-factory/client')

const testfile = isNode
  ? loadFixture(__dirname, '/fixtures/testfile.txt')
  : loadFixture(__dirname, 'fixtures/testfile.txt')

describe('.files (the MFS API part)', function () {
  this.timeout(120 * 1000)

  let ipfs
  let fc

  before((done) => {
    fc = new FactoryClient()
    fc.spawnNode((err, node) => {
      expect(err).to.not.exist()
      ipfs = node
      done()
    })
  })

  after((done) => fc.dismantle(done))

  describe('Callback API', function () {
    this.timeout(120 * 1000)

    it('add file for testing', (done) => {
      const expectedMultihash = 'Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP'

      ipfs.files.add(testfile, (err, res) => {
        expect(err).to.not.exist()

        expect(res).to.have.length(1)
        expect(res[0].hash).to.equal(expectedMultihash)
        expect(res[0].path).to.equal(expectedMultihash)
        done()
      })
    })

    it('files.add with cid-version=1 and raw-leaves=false', (done) => {
      const expectedHash = 'zdj7Wh9x6gXdg4UAqhRYnjBTw9eJF7hvzUU4HjpnZXHYQz9jK'
      const options = { 'cid-version': 1, 'raw-leaves': false }

      ipfs.files.add(testfile, options, (err, res) => {
        expect(err).to.not.exist()

        expect(res).to.have.length(1)
        expect(res[0].hash).to.equal(expectedHash)
        expect(res[0].path).to.equal(expectedHash)
        done()
      })
    })

    it('files.mkdir', (done) => {
      ipfs.files.mkdir('/test-folder', done)
    })

    it('files.cp', (done) => {
      ipfs.files.cp([
        '/ipfs/Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP',
        '/test-folder/test-file'
      ], (err) => {
        expect(err).to.not.exist()
        done()
      })
    })

    it('files.ls', (done) => {
      ipfs.files.ls('/test-folder', (err, res) => {
        expect(err).to.not.exist()
        expect(res.Entries.length).to.equal(1)
        done()
      })
    })

    it('files.write', (done) => {
      ipfs.files
        .write('/test-folder/test-file-2.txt', Buffer.from('hello world'), {create: true}, (err) => {
          expect(err).to.not.exist()

          ipfs.files.read('/test-folder/test-file-2.txt', (err, stream) => {
            expect(err).to.not.exist()

            let buf = ''
            stream
              .on('error', (err) => expect(err).to.not.exist())
              .on('data', (data) => {
                buf += data
              })
              .on('end', () => {
                expect(buf).to.be.equal('hello world')
                done()
              })
          })
        })
    })

    it('files.write without options', (done) => {
      ipfs.files
        .write('/test-folder/test-file-2.txt', Buffer.from('hello world'), (err) => {
          expect(err).to.not.exist()

          ipfs.files.read('/test-folder/test-file-2.txt', (err, stream) => {
            expect(err).to.not.exist()

            let buf = ''
            stream
              .on('error', (err) => {
                expect(err).to.not.exist()
              })
              .on('data', (data) => {
                buf += data
              })
              .on('end', () => {
                expect(buf).to.be.equal('hello world')
                done()
              })
          })
        })
    })

    it('files.stat', (done) => {
      ipfs.files.stat('/test-folder/test-file', (err, res) => {
        expect(err).to.not.exist()
        expect(res).to.deep.equal({
          Hash: 'Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP',
          Size: 12,
          CumulativeSize: 20,
          Blocks: 0,
          Type: 'file'
        })

        done()
      })
    })

    it('files.stat file that does not exist()', (done) => {
      ipfs.files.stat('/test-folder/does-not-exist()', (err, res) => {
        expect(err).to.exist()
        if (err.code === 0) {
          return done()
        }
        throw err
      })
    })

    it('files.read', (done) => {
      if (!isNode) {
        return done()
      }

      ipfs.files.read('/test-folder/test-file', (err, stream) => {
        expect(err).to.not.exist()
        let buf = ''
        stream
          .on('error', (err) => {
            expect(err).to.not.exist()
          })
          .on('data', (data) => {
            buf += data
          })
          .on('end', () => {
            expect(Buffer.from(buf)).to.deep.equal(testfile)
            done()
          })
      })
    })

    it('files.rm without options', (done) => {
      ipfs.files.rm('/test-folder/test-file-2.txt', done)
    })

    it('files.rm', (done) => {
      ipfs.files.rm('/test-folder', {recursive: true}, done)
    })
  })

  describe('Promise API', function () {
    this.timeout(120 * 1000)

    it('files.add with cid-version=1 and raw-leaves=false', () => {
      const expectedHash = 'zdj7Wh9x6gXdg4UAqhRYnjBTw9eJF7hvzUU4HjpnZXHYQz9jK'
      const options = { 'cid-version': 1, 'raw-leaves': false }

      return ipfs.files.add(testfile, options)
        .then((res) => {
          expect(res).to.have.length(1)
          expect(res[0].hash).to.equal(expectedHash)
          expect(res[0].path).to.equal(expectedHash)
        })
    })

    it('files.mkdir', () => {
      return ipfs.files.mkdir('/test-folder')
    })

    it('files.cp', () => {
      return ipfs.files
        .cp(['/ipfs/Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP', '/test-folder/test-file'])
    })

    it('files.ls', () => {
      return ipfs.files.ls('/test-folder')
        .then((res) => {
          expect(res.Entries.length).to.equal(1)
        })
    })

    it('files.write', (done) => {
      ipfs.files
        .write('/test-folder/test-file-2.txt', Buffer.from('hello world'), {create: true})
        .then(() => {
          return ipfs.files.read('/test-folder/test-file-2.txt')
        })
        .then((stream) => {
          let buf = ''
          stream
            .on('error', (err) => {
              expect(err).to.not.exist()
            })
            .on('data', (data) => {
              buf += data
            })
            .on('end', () => {
              expect(buf).to.be.equal('hello world')
              done()
            })
        })
        .catch(done)
    })

    it('files.write without options', (done) => {
      ipfs.files
        .write('/test-folder/test-file-2.txt', Buffer.from('hello world'))
        .then(() => {
          return ipfs.files.read('/test-folder/test-file-2.txt')
        })
        .then((stream) => {
          let buf = ''
          stream
            .on('error', (err) => {
              expect(err).to.not.exist()
            })
            .on('data', (data) => {
              buf += data
            })
            .on('end', () => {
              expect(buf).to.be.equal('hello world')
              done()
            })
        })
        .catch(done)
    })

    it('files.stat', () => {
      return ipfs.files.stat('/test-folder/test-file')
        .then((res) => {
          expect(res).to.deep.equal({
            Hash: 'Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP',
            Size: 12,
            CumulativeSize: 20,
            Blocks: 0,
            Type: 'file'
          })
        })
    })

    it('files.stat file that does not exist()', () => {
      return ipfs.files.stat('/test-folder/does-not-exist()')
        .catch((err) => {
          expect(err).to.exist()
          expect(err.code).to.be.eql(0)
        })
    })

    it('files.read', (done) => {
      if (!isNode) { return done() }

      ipfs.files.read('/test-folder/test-file')
        .then((stream) => {
          let buf = ''
          stream
            .on('error', (err) => {
              expect(err).to.not.exist()
            })
            .on('data', (data) => {
              buf += data
            })
            .on('end', () => {
              expect(Buffer.from(buf)).to.eql(testfile)
              done()
            })
        })
    })

    it('files.rm without options', () => {
      return ipfs.files.rm('/test-folder/test-file-2.txt')
    })

    it('files.rm', () => {
      return ipfs.files.rm('/test-folder', { recursive: true })
    })
  })
})
<commit_msg>feat: support options for .add / files.add <commit_after>/* eslint-env mocha */
/* eslint max-nested-callbacks: ["error", 8] */
'use strict'

const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
const isNode = require('detect-node')
const loadFixture = require('aegir/fixtures')

const FactoryClient = require('./ipfs-factory/client')

const testfile = isNode
  ? loadFixture(__dirname, '/fixtures/testfile.txt')
  : loadFixture(__dirname, 'fixtures/testfile.txt')

describe('.files (the MFS API part)', function () {
  this.timeout(120 * 1000)

  let ipfs
  let fc

  const expectedMultihash = 'Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP'

  before((done) => {
    fc = new FactoryClient()
    fc.spawnNode((err, node) => {
      expect(err).to.not.exist()
      ipfs = node
      done()
    })
  })

  after((done) => fc.dismantle(done))

  describe('Callback API', function () {
    this.timeout(120 * 1000)

    it('add file for testing', (done) => {
      ipfs.files.add(testfile, (err, res) => {
        expect(err).to.not.exist()

        expect(res).to.have.length(1)
        expect(res[0].hash).to.equal(expectedMultihash)
        expect(res[0].path).to.equal(expectedMultihash)
        done()
      })
    })

    it('files.add with cid-version=1 and raw-leaves=false', (done) => {
      const expectedCid = 'zdj7Wh9x6gXdg4UAqhRYnjBTw9eJF7hvzUU4HjpnZXHYQz9jK'
      const options = { 'cid-version': 1, 'raw-leaves': false }

      ipfs.files.add(testfile, options, (err, res) => {
        expect(err).to.not.exist()

        expect(res).to.have.length(1)
        expect(res[0].hash).to.equal(expectedCid)
        expect(res[0].path).to.equal(expectedCid)
        done()
      })
    })

    it('files.add with options', (done) => {
      ipfs.files.add(testfile, { pin: false }, (err, res) => {
        expect(err).to.not.exist()

        expect(res).to.have.length(1)
        expect(res[0].hash).to.equal(expectedMultihash)
        expect(res[0].path).to.equal(expectedMultihash)
        done()
      })
    })

    it('files.mkdir', (done) => {
      ipfs.files.mkdir('/test-folder', done)
    })

    it('files.cp', (done) => {
      ipfs.files.cp([
        '/ipfs/Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP',
        '/test-folder/test-file'
      ], (err) => {
        expect(err).to.not.exist()
        done()
      })
    })

    it('files.ls', (done) => {
      ipfs.files.ls('/test-folder', (err, res) => {
        expect(err).to.not.exist()
        expect(res.Entries.length).to.equal(1)
        done()
      })
    })

    it('files.write', (done) => {
      ipfs.files
        .write('/test-folder/test-file-2.txt', Buffer.from('hello world'), {create: true}, (err) => {
          expect(err).to.not.exist()

          ipfs.files.read('/test-folder/test-file-2.txt', (err, stream) => {
            expect(err).to.not.exist()

            let buf = ''
            stream
              .on('error', (err) => expect(err).to.not.exist())
              .on('data', (data) => {
                buf += data
              })
              .on('end', () => {
                expect(buf).to.be.equal('hello world')
                done()
              })
          })
        })
    })

    it('files.write without options', (done) => {
      ipfs.files
        .write('/test-folder/test-file-2.txt', Buffer.from('hello world'), (err) => {
          expect(err).to.not.exist()

          ipfs.files.read('/test-folder/test-file-2.txt', (err, stream) => {
            expect(err).to.not.exist()

            let buf = ''
            stream
              .on('error', (err) => {
                expect(err).to.not.exist()
              })
              .on('data', (data) => {
                buf += data
              })
              .on('end', () => {
                expect(buf).to.be.equal('hello world')
                done()
              })
          })
        })
    })

    it('files.stat', (done) => {
      ipfs.files.stat('/test-folder/test-file', (err, res) => {
        expect(err).to.not.exist()
        expect(res).to.deep.equal({
          Hash: 'Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP',
          Size: 12,
          CumulativeSize: 20,
          Blocks: 0,
          Type: 'file'
        })

        done()
      })
    })

    it('files.stat file that does not exist()', (done) => {
      ipfs.files.stat('/test-folder/does-not-exist()', (err, res) => {
        expect(err).to.exist()
        if (err.code === 0) {
          return done()
        }
        throw err
      })
    })

    it('files.read', (done) => {
      if (!isNode) {
        return done()
      }

      ipfs.files.read('/test-folder/test-file', (err, stream) => {
        expect(err).to.not.exist()
        let buf = ''
        stream
          .on('error', (err) => {
            expect(err).to.not.exist()
          })
          .on('data', (data) => {
            buf += data
          })
          .on('end', () => {
            expect(Buffer.from(buf)).to.deep.equal(testfile)
            done()
          })
      })
    })

    it('files.rm without options', (done) => {
      ipfs.files.rm('/test-folder/test-file-2.txt', done)
    })

    it('files.rm', (done) => {
      ipfs.files.rm('/test-folder', {recursive: true}, done)
    })
  })

  describe('Promise API', function () {
    this.timeout(120 * 1000)

    it('files.add', () => {
      return ipfs.files.add(testfile)
        .then((res) => {
          expect(res).to.have.length(1)
          expect(res[0].hash).to.equal(expectedMultihash)
          expect(res[0].path).to.equal(expectedMultihash)
        })
    })

    it('files.add with cid-version=1 and raw-leaves=false', () => {
      const expectedHash = 'zdj7Wh9x6gXdg4UAqhRYnjBTw9eJF7hvzUU4HjpnZXHYQz9jK'
      const options = { 'cid-version': 1, 'raw-leaves': false }

      return ipfs.files.add(testfile, options)
        .then((res) => {
          expect(res).to.have.length(1)
          expect(res[0].hash).to.equal(expectedHash)
          expect(res[0].path).to.equal(expectedHash)
        })
    })

    it('files.add with options', () => {
      return ipfs.files.add(testfile, { pin: false })
        .then((res) => {
          expect(res).to.have.length(1)
          expect(res[0].hash).to.equal(expectedMultihash)
          expect(res[0].path).to.equal(expectedMultihash)
        })
    })

    it('files.mkdir', () => {
      return ipfs.files.mkdir('/test-folder')
    })

    it('files.cp', () => {
      return ipfs.files
        .cp([
          '/ipfs/Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP',
          '/test-folder/test-file'
        ])
    })

    it('files.ls', () => {
      return ipfs.files.ls('/test-folder')
        .then((res) => {
          expect(res.Entries.length).to.equal(1)
        })
    })

    it('files.write', (done) => {
      ipfs.files
        .write('/test-folder/test-file-2.txt', Buffer.from('hello world'), {create: true})
        .then(() => {
          return ipfs.files.read('/test-folder/test-file-2.txt')
        })
        .then((stream) => {
          let buf = ''
          stream
            .on('error', (err) => {
              expect(err).to.not.exist()
            })
            .on('data', (data) => {
              buf += data
            })
            .on('end', () => {
              expect(buf).to.be.equal('hello world')
              done()
            })
        })
        .catch(done)
    })

    it('files.write without options', (done) => {
      ipfs.files
        .write('/test-folder/test-file-2.txt', Buffer.from('hello world'))
        .then(() => {
          return ipfs.files.read('/test-folder/test-file-2.txt')
        })
        .then((stream) => {
          let buf = ''
          stream
            .on('error', (err) => {
              expect(err).to.not.exist()
            })
            .on('data', (data) => {
              buf += data
            })
            .on('end', () => {
              expect(buf).to.be.equal('hello world')
              done()
            })
        })
        .catch(done)
    })

    it('files.stat', () => {
      return ipfs.files.stat('/test-folder/test-file')
        .then((res) => {
          expect(res).to.deep.equal({
            Hash: 'Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP',
            Size: 12,
            CumulativeSize: 20,
            Blocks: 0,
            Type: 'file'
          })
        })
    })

    it('files.stat file that does not exist()', () => {
      return ipfs.files.stat('/test-folder/does-not-exist()')
        .catch((err) => {
          expect(err).to.exist()
          expect(err.code).to.be.eql(0)
        })
    })

    it('files.read', (done) => {
      if (!isNode) { return done() }

      ipfs.files.read('/test-folder/test-file')
        .then((stream) => {
          let buf = ''
          stream
            .on('error', (err) => {
              expect(err).to.not.exist()
            })
            .on('data', (data) => {
              buf += data
            })
            .on('end', () => {
              expect(Buffer.from(buf)).to.eql(testfile)
              done()
            })
        })
    })

    it('files.rm without options', () => {
      return ipfs.files.rm('/test-folder/test-file-2.txt')
    })

    it('files.rm', () => {
      return ipfs.files.rm('/test-folder', { recursive: true })
    })
  })
})
<|endoftext|>