<commit_before>var querystring = require("querystring");
var exec = require('child_process').exec;
var events = require('events');
var eventEmitter = new events.EventEmitter();

module.exports = function(name, pwd, hostname) {

  var apiURL = 'https://' + hostname + ':8006/api2/json';
  var authString = 'username=' + name + '&password=' + pwd;

  var token = {};
    token.CSRF = '';
    token.PVEAuth = '';
    token.timeStamp = 0;

  function curlCom() {

    var command = '';

    this.get = function(url) {
	command = 'curl -k ';
        command += ('-b ' + 'PVEAuthCookie='+token.PVEAuth);
	command += (' ' + apiURL + url);
	return this;
    };
    this.post = function(url, data, header, cookie) {
	command = 'curl -XPOST -k '
	if (typeof cookie === 'string') command += ('-b '+ 'PVEAuthCookie='+cookie + ' ');
	if (typeof header === 'string') command += ('-H ' +'"'+'CSRFPreventionToken:' + header + '"'+' ');
	command += ('-d '+'"'+data+'"'+' ');
	command += (apiURL + url);
	return this;
    };
    this.put = function(url, data, header, cookie) {
	command = 'curl -X PUT -k '
        command += ('-b ' + 'PVEAuthCookie='+cookie + ' ');
	command += ('-H ' +'"'+'CSRFPreventionToken:' + header + '"'+' ');
	command += ('-d ' + data);
	return this;
    };
    this.delete = function(url, data, header, cookie) {
	command = 'curl -X DELETE -k ';
        command += ('-b ' + 'PVEAuthCookie='+cookie + ' ');
	command += ('-H ' +'"'+'CSRFPreventionToken:' + header + '"'+' ');
	command += ('-d ' + data);
	return this;
    };
    this.command = function() {
	return command;
    };
    return this;
  };

  function curl(command, callback) {
    exec(command, function(err, stdout, stderr) {
        var data = stdout;
        callback(err, data);
    });
  };

  function authorize(path, data, callback, cb) {
    command = curlCom().post('/access/ticket',authString).command();

    curl(command, function(err, response) {
	if (err) throw err
	else {
	  response = JSON.parse(response);
	    token.CSRF = response.data.CSRFPreventionToken;
	    token.PVEAuth = response.data.ticket;
	    token.timeStamp = new Date().getTime();
	    if (typeof cb === 'function') cb(path, data, callback);
	}
    });
  };

  function makeRequest(method, path, data, callback){
    if (method == 'GET') {
      command = curlCom().get(path).command();
    }
    else if (method == 'POST') {
      command = curlCom().post(path, data, token.CSRF, token.PVEAuth).command();
    }
    else if (method == 'DEL') {
      command = curlCom().del().command();
    }
    else {
      command = curlCom().put().command();
    }

    curl(command, callback);
  };

  function get(path, data, callback) {
    if ( (token.timeStamp + 7200) < new Date().getTime() ) authorize(path, data, callback, get);
    else makeRequest('GET', path, data, callback);
  };

  function post(path, data, callback) {
    if ( (token.timeStamp + 7200) < new Date().getTime() ) authorize(path, data, callback, post);
    else {
	data = querystring.stringify(data);
	makeRequest('POST', path, data, callback);
    };
  };

  function del(path, data, callback) {
    if ( (token.timeStamp + 7200) < new Date().getTime() ) authorize(path, data, callback, del);
    else makeRequest('DEL', path, data, callback);
  };

  function put(path, data, callback) {
    if ( (token.timeStamp + 7200) < new Date().getTime() ) authorize(path, data, callback, put);
    else {
	data = querystring.stringify(data);
    	makeRequest('PUT', path, data, callback);
    }
  };

  return {
	  getClusterStatus: function(callback) {
		data = {};
         	get('/cluster/status', data, callback);
	   },
 	  getClusterBackupSchedule: function(callback) {
		data = {};
		get('/cluster/backup', data, callback);
	  },
	  getNodeNetworks: function(node,callback) {
		data = {};
		url = '/nodes/'+node+'/network';
		get(url, data, callback);
	  },
	  getNodeInterface: function(node, interface, callback) {
		data = {};
		url = '/nodes/'+node+'/network/'+interface;
		get(url, data, callback);
	  },
	  getNodeContainerIndex: function(node, callback) {
		data = {};
		url = '/nodes/'+node+'/openvz/';
		get(url, data, callback);
	  },
	  getNodeVirtualIndex: function(node, callback) {
		data = {};
		url = '/nodes/'+node+'/qemu';
		get(url, data, callback);
	  },
	  getNodeServiceState: function(node, service, callback) {
		data = {};
		url = '/nodes/'+node+'/services/'+service+'/state';
	    	get(url, data, callback);
	  },
	  getNodeStorage: function(node, callback) {
		data = {};
		url = '/nodes/'+node+'/storage';
	 	get(url, data, callback);
	  },
	  getNodeFinishedTasks: function(node, callback) {
		data = {};
		url = '/nodes/'+node+'/tasks';
		get(url, data, callback);
	  },
	  getNodeDNS: function(node, callback) {
		data = {};
		url = '/nodes/'+node+'/dns';
		get(url, data, callback);
	  },
	  getNodeSyslog: function(node, callback) {
		data = {};
		url = '/nodes/'+node+'/syslog';
		get(url, data, callback);
	  },
	  getNodeRRD: function(node, callback) {
		data = {};
		url = '/nodes/'+node+'/rrd';
		get(url, data, callback);
	  },
	  getNodeRRData: function(node, callback) {
		data = {};
		url = '/nodes/'+node+'/rrddata';
		get(url, data, callback);
	  },
	  getNodeBeans: function(node, callback) {
		data = {};
		url = '/nodes/'+node+'/ubfailcnt';
		get(url, data, callback);
	  },
	  getNodeTaskByUPID: function(node, upid, callback) {
		data = {};
		url = '/nodes/'+node+'/tasks/'+upid;
		get(url, data, callback);
	  },
	  getNodeTaskLogByUPID: function(node, upid, callback) {
		data = {};
		url = '/nodes/'+node+'/tasks/'+upid+'/log';
		get(url, data, callback);
	  },
	  getNodeTaskStatusByUPID: function(node, upid, callback) {
		data = {};
		url = '/nodes/'+node+'/tasks/'+upid+'/status';
		get(url, data, callback);
	  },
	  getNodeScanMethods: function(node, callback) {
		data = {};
		url = '/nodes/'+node+'/scan';
		get(url, data, callback);
	  },
	  getRemoteiSCSI: function(node, callback) {
		data = {};
		url = '/nodes/'+node+'/scan/iscsi';
		get(url, data, callback);
	  },
	  getNodeLVMGroups: function(node, callback) {
		data = {};
		url = '/nodes/'+node+'/scan/lvm';
		get(url, data, callback);
	  },
	  getRemoteNFS: function(node, callback) {
		data = {};
		url = '/nodes/'+node+'/scan/nfs';
		get(url, data, callback);
	  },
  	  getNodeUSB: function(node, callback) {
		data = {};
		url = '/nodes/'+node+'/scan/usb';
	  },
	  getStorageVolumeData: function(node, storage, volume, callback) {
		data = {};
		url = '/nodes/'+node+'/storage/'+storage+'/content/'+volume;
		get(url, data, callback);
	  },
	  getStorageConfig: function(storage, callback) {
		data = {};
		url = '/storage/'+storage;
		get(url, data, callback);
	  },
	  getNodeStorageContent: function(node, storage, callback) {
		data = {};
		url = '/nodes/'+node+'/storage/'+storage+'/content';
		get(url, data, callback);
	  },
	  getNodeStorageRRD: function(node, storage, callback) {
		data = {};
		url = '/nodes/'+node+'/storage/'+storage+'/rrd';
		get(url, data, callback);
	  },
	  getNodeStorageRRDData: function(node, storage, callback) {
		data = {};
		url = '/nodes/'+node+'/storage/'+storage+'/rrddata';
		get(url, data, callback);
	  },
          openvz: {
		createOpenvzContainer: function(node, data, callback) {
		  url = '/nodes/' + node + '/openvz'
		  post(url, data, callback);
		},
		mountOpenvzPrivate: function(node, vmid, callback) {
		  data = {};
		  url = '/nodes/' + node + '/openvz/' + vmid + '/status/mount';
		  post(url, data, callback);
		},
		shutdownOpenvzContainer: function(node, vmid, callback) {
		  data = {};
		  url = '/nodes/' + node + '/openvz/' + vmid + '/status/shutdown';
		  post(url, data, callback);
		},
		startOpenvzContainer: function(node, vmid, callback) {
		  data = {};
		  url = '/nodes/' + node + '/openvz/' + vmid + '/status/start';
		  post(url, data, callback);
		},
	 	stopOpenvzContainer: function(node, vmid, callback) {
		  data = {};
		  url = '/nodes/' + node + '/openvz/' + vmid + '/status/stop';
		  post(url, data, callback);
		},
		unmountOpenvzContainer: function(node, vmid, callback) {
		  data = {};
		  url = '/nodes/' + node + '/openvz/' + vmid + '/status/unmount';
		  post(url, data, callback);
		},
		migrateOpenvzContainer: function(node, vmid, target, callback) {
		  data = {'target': target};
		  url = '/nodes/' + node + '/openvz/' + vmid + '/migrate';
		  post(url, data, callback);
		},
		getContainerIndex: function(node, vmid, callback) {
		  data = {};
		  url = '/nodes/'+node+'/openvz/'+vmid;
		  get(url, data, callback);
		},
		getContainerStatus: function(node, vmid, callback) {
		  data = {};
		  url = '/nodes/'+node+'/openvz/'+node+'/status/current';
		  get(url, data, callback);
		},
		getContainerBeans: function(node, vmid, callback) {
		  data = {};
		  url = '/nodes/'+node+'/openvz/'+vmid+'/status/ubc';
		  get(url, data, callback);
		},
		getContainerConfig: function(node, vmid, callback) {
		  data = {};
		  url = '/nodes/'+node+'/openvz/'+vmid+'/config';
		  get(url, data, callback);
		},
		getContainerInitLog: function(node, vmid, callback) {
		  data = {};
		  url = '/nodes/'+node+'/openvz/'+vmid+'/initlog';
		  get(url, data, callback);
		},
		getContainerRRD: function(node, vmid, callback) {
		  data = {};
		  url = '/nodes/'+node+'/openvz/'+vmid+'/rrd';
		  get(url, data, callback);
		},
		getContainerRRDData: function(node, vmid, callback) {
		  data = {};
		  url = '/nodes/'+node+'/openvz/'+vmid+'/rrddata';
		  get(url, data, callback);
		},
		deleteOpenvzContainer: function(node, vmid, callback) {
		  data = {};
		  url = '/nodes/'+node+'/openvz'+vmid;
		  del(url, data, callback);
		},
		setOpenvzContainerOptions: function(node, vmid, data, calback) {
		  url = '/nodes/'+node+'/openvz/'+vmid+'/config';
		  put(url, data, callback);
		}
	  }
  }
};
<commit_msg>added more methods<commit_after>var querystring = require("querystring");
var exec = require('child_process').exec;
var events = require('events');
var eventEmitter = new events.EventEmitter();

module.exports = function(name, pwd, hostname) {

  var apiURL = 'https://' + hostname + ':8006/api2/json';
  var authString = 'username=' + name + '&password=' + pwd;

  var token = {};
    token.CSRF = '';
    token.PVEAuth = '';
    token.timeStamp = 0;

  function curlCom() {

    var command = '';

    this.get = function(url) {
	command = 'curl -k ';
        command += ('-b ' + 'PVEAuthCookie='+token.PVEAuth);
	command += (' ' + apiURL + url);
	return this;
    };
    this.post = function(url, data, header, cookie) {
	command = 'curl -XPOST -k '
	if (typeof cookie === 'string') command += ('-b '+ 'PVEAuthCookie='+cookie + ' ');
	if (typeof header === 'string') command += ('-H ' +'"'+'CSRFPreventionToken:' + header + '"'+' ');
	command += ('-d '+'"'+data+'"'+' ');
	command += (apiURL + url);
	return this;
    };
    this.put = function(url, data, header, cookie) {
	command = 'curl -X PUT -k '
        command += ('-b ' + 'PVEAuthCookie='+cookie + ' ');
	command += ('-H ' +'"'+'CSRFPreventionToken:' + header + '"'+' ');
	command += ('-d ' + data);
	return this;
    };
    this.delete = function(url, data, header, cookie) {
	command = 'curl -X DELETE -k ';
        command += ('-b ' + 'PVEAuthCookie='+cookie + ' ');
	command += ('-H ' +'"'+'CSRFPreventionToken:' + header + '"'+' ');
	command += ('-d ' + data);
	return this;
    };
    this.command = function() {
	return command;
    };
    return this;
  };

  function curl(command, callback) {
    exec(command, function(err, stdout, stderr) {
        var data = stdout;
        callback(err, data);
    });
  };

  function authorize(path, data, callback, cb) {
    command = curlCom().post('/access/ticket',authString).command();

    curl(command, function(err, response) {
	if (err) throw err
	else {
	  response = JSON.parse(response);
	    token.CSRF = response.data.CSRFPreventionToken;
	    token.PVEAuth = response.data.ticket;
	    token.timeStamp = new Date().getTime();
	    if (typeof cb === 'function') cb(path, data, callback);
	}
    });
  };

  function makeRequest(method, path, data, callback){
    if (method == 'GET') {
      command = curlCom().get(path).command();
    }
    else if (method == 'POST') {
      command = curlCom().post(path, data, token.CSRF, token.PVEAuth).command();
    }
    else if (method == 'DEL') {
      command = curlCom().del().command();
    }
    else {
      command = curlCom().put().command();
    }

    curl(command, callback);
  };

  function get(path, data, callback) {
    if ( (token.timeStamp + 7200) < new Date().getTime() ) authorize(path, data, callback, get);
    else makeRequest('GET', path, data, callback);
  };

  function post(path, data, callback) {
    if ( (token.timeStamp + 7200) < new Date().getTime() ) authorize(path, data, callback, post);
    else {
	data = querystring.stringify(data);
	makeRequest('POST', path, data, callback);
    };
  };

  function del(path, data, callback) {
    if ( (token.timeStamp + 7200) < new Date().getTime() ) authorize(path, data, callback, del);
    else makeRequest('DEL', path, data, callback);
  };

  function put(path, data, callback) {
    if ( (token.timeStamp + 7200) < new Date().getTime() ) authorize(path, data, callback, put);
    else {
	data = querystring.stringify(data);
    	makeRequest('PUT', path, data, callback);
    }
  };

  return {
	  getClusterStatus: function(callback) {
		data = {};
         	get('/cluster/status', data, callback);
	   },
 	  getClusterBackupSchedule: function(callback) {
		data = {};
		get('/cluster/backup', data, callback);
	  },
	  getNodeNetworks: function(node,callback) {
		data = {};
		url = '/nodes/'+node+'/network';
		get(url, data, callback);
	  },
	  getNodeInterface: function(node, interface, callback) {
		data = {};
		url = '/nodes/'+node+'/network/'+interface;
		get(url, data, callback);
	  },
	  getNodeContainerIndex: function(node, callback) {
		data = {};
		url = '/nodes/'+node+'/openvz/';
		get(url, data, callback);
	  },
	  getNodeVirtualIndex: function(node, callback) {
		data = {};
		url = '/nodes/'+node+'/qemu';
		get(url, data, callback);
	  },
	  getNodeServiceState: function(node, service, callback) {
		data = {};
		url = '/nodes/'+node+'/services/'+service+'/state';
	    	get(url, data, callback);
	  },
	  getNodeStorage: function(node, callback) {
		data = {};
		url = '/nodes/'+node+'/storage';
	 	get(url, data, callback);
	  },
	  getNodeFinishedTasks: function(node, callback) {
		data = {};
		url = '/nodes/'+node+'/tasks';
		get(url, data, callback);
	  },
	  getNodeDNS: function(node, callback) {
		data = {};
		url = '/nodes/'+node+'/dns';
		get(url, data, callback);
	  },
	  getNodeSyslog: function(node, callback) {
		data = {};
		url = '/nodes/'+node+'/syslog';
		get(url, data, callback);
	  },
	  getNodeRRD: function(node, callback) {
		data = {};
		url = '/nodes/'+node+'/rrd';
		get(url, data, callback);
	  },
	  getNodeRRData: function(node, callback) {
		data = {};
		url = '/nodes/'+node+'/rrddata';
		get(url, data, callback);
	  },
	  getNodeBeans: function(node, callback) {
		data = {};
		url = '/nodes/'+node+'/ubfailcnt';
		get(url, data, callback);
	  },
	  getNodeTaskByUPID: function(node, upid, callback) {
		data = {};
		url = '/nodes/'+node+'/tasks/'+upid;
		get(url, data, callback);
	  },
	  getNodeTaskLogByUPID: function(node, upid, callback) {
		data = {};
		url = '/nodes/'+node+'/tasks/'+upid+'/log';
		get(url, data, callback);
	  },
	  getNodeTaskStatusByUPID: function(node, upid, callback) {
		data = {};
		url = '/nodes/'+node+'/tasks/'+upid+'/status';
		get(url, data, callback);
	  },
	  getNodeScanMethods: function(node, callback) {
		data = {};
		url = '/nodes/'+node+'/scan';
		get(url, data, callback);
	  },
	  getRemoteiSCSI: function(node, callback) {
		data = {};
		url = '/nodes/'+node+'/scan/iscsi';
		get(url, data, callback);
	  },
	  getNodeLVMGroups: function(node, callback) {
		data = {};
		url = '/nodes/'+node+'/scan/lvm';
		get(url, data, callback);
	  },
	  getRemoteNFS: function(node, callback) {
		data = {};
		url = '/nodes/'+node+'/scan/nfs';
		get(url, data, callback);
	  },
  	  getNodeUSB: function(node, callback) {
		data = {};
		url = '/nodes/'+node+'/scan/usb';
	  },
	  getStorageVolumeData: function(node, storage, volume, callback) {
		data = {};
		url = '/nodes/'+node+'/storage/'+storage+'/content/'+volume;
		get(url, data, callback);
	  },
	  getStorageConfig: function(storage, callback) {
		data = {};
		url = '/storage/'+storage;
		get(url, data, callback);
	  },
	  getNodeStorageContent: function(node, storage, callback) {
		data = {};
		url = '/nodes/'+node+'/storage/'+storage+'/content';
		get(url, data, callback);
	  },
	  getNodeStorageRRD: function(node, storage, callback) {
		data = {};
		url = '/nodes/'+node+'/storage/'+storage+'/rrd';
		get(url, data, callback);
	  },
	  getNodeStorageRRDData: function(node, storage, callback) {
		data = {};
		url = '/nodes/'+node+'/storage/'+storage+'/rrddata';
		get(url, data, callback);
	  },
          openvz: {
		createOpenvzContainer: function(node, data, callback) {
		  url = '/nodes/' + node + '/openvz'
		  post(url, data, callback);
		},
		mountOpenvzPrivate: function(node, vmid, callback) {
		  data = {};
		  url = '/nodes/' + node + '/openvz/' + vmid + '/status/mount';
		  post(url, data, callback);
		},
		shutdownOpenvzContainer: function(node, vmid, callback) {
		  data = {};
		  url = '/nodes/' + node + '/openvz/' + vmid + '/status/shutdown';
		  post(url, data, callback);
		},
		startOpenvzContainer: function(node, vmid, callback) {
		  data = {};
		  url = '/nodes/' + node + '/openvz/' + vmid + '/status/start';
		  post(url, data, callback);
		},
	 	stopOpenvzContainer: function(node, vmid, callback) {
		  data = {};
		  url = '/nodes/' + node + '/openvz/' + vmid + '/status/stop';
		  post(url, data, callback);
		},
		unmountOpenvzContainer: function(node, vmid, callback) {
		  data = {};
		  url = '/nodes/' + node + '/openvz/' + vmid + '/status/unmount';
		  post(url, data, callback);
		},
		migrateOpenvzContainer: function(node, vmid, target, callback) {
		  data = {'target': target};
		  url = '/nodes/' + node + '/openvz/' + vmid + '/migrate';
		  post(url, data, callback);
		},
		getContainerIndex: function(node, vmid, callback) {
		  data = {};
		  url = '/nodes/'+node+'/openvz/'+vmid;
		  get(url, data, callback);
		},
		getContainerStatus: function(node, vmid, callback) {
		  data = {};
		  url = '/nodes/'+node+'/openvz/'+node+'/status/current';
		  get(url, data, callback);
		},
		getContainerBeans: function(node, vmid, callback) {
		  data = {};
		  url = '/nodes/'+node+'/openvz/'+vmid+'/status/ubc';
		  get(url, data, callback);
		},
		getContainerConfig: function(node, vmid, callback) {
		  data = {};
		  url = '/nodes/'+node+'/openvz/'+vmid+'/config';
		  get(url, data, callback);
		},
		getContainerInitLog: function(node, vmid, callback) {
		  data = {};
		  url = '/nodes/'+node+'/openvz/'+vmid+'/initlog';
		  get(url, data, callback);
		},
		getContainerRRD: function(node, vmid, callback) {
		  data = {};
		  url = '/nodes/'+node+'/openvz/'+vmid+'/rrd';
		  get(url, data, callback);
		},
		getContainerRRDData: function(node, vmid, callback) {
		  data = {};
		  url = '/nodes/'+node+'/openvz/'+vmid+'/rrddata';
		  get(url, data, callback);
		},
		deleteOpenvzContainer: function(node, vmid, callback) {
		  data = {};
		  url = '/nodes/'+node+'/openvz'+vmid;
		  del(url, data, callback);
		},
		setOpenvzContainerOptions: function(node, vmid, data, calback) {
		  url = '/nodes/'+node+'/openvz/'+vmid+'/config';
		  put(url, data, callback);
		}
	  },
	  deleteNodeNetworkConfig: function(node, callback) {
	    data = {};
	    url = '/nodes/'+node+'/network';
	    del(url, data, callback);
	  },
	  deleteNodeInterface: function(node, interface, callback) {
	    data = {};
	    url = '/nodes/'+node+'/network/'+interface;
	    del(url, data, callback);
	  },
	  deletePool: function(poolid, callback){
	    data = {};
	    url = '/pools/'+poolid;
	    del(url, data, callback);
	  },
	  setNodeDNSDomain: function(node, domain, callback) {
	    data = {'search': domain};
	    url = '/nodes/'+node+'/dns';
	    put(url, data, callback);
	  },
	  setNodeSubscriptionKey: function(node, key, callback) {
	    data = {'key': key};
	    url = '/nodes/'+node+'/subscription';
	    put(url, data, callback);
	  },
	  setNodeTimeZone: function(node, timezone, callback) {
	    data = {'timezone':timezone};
	    url = '/nodes/'+node+'/time';
	    put(url, data, callback);
	  },
	  setPoolData: function(poolid, data, callback) {
	    url = '/pools/'+poolid;
	    put(url, data, callback);
	  },
	  updateStorageConfiguration: function(storageid, data, callback) {
	    url = '/storage/'+storageid;
	    put(url, data, callback);
	  }
  }
};
<|endoftext|>


<commit_before>/*
 * Utilities: A classic collection of JavaScript utilities
 * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/
var http = require('http')
  , https = require('https')
  , url = require('url')
  , uri = require('./uri')
  , log = require('./log')
  , core = require('./core');

var formatters = {
  xml: function (data) {
    return data;
  }
, html: function (data) {
    return data;
  }
, txt: function (data) {
    return data;
  }
, json: function (data) {
    return JSON.parse(data);
  }
}

/**
  @name request
  @namespace request
  @public
  @function
  @description Sends requests to the given url sending any data if the method is POST or PUT
  @param {Object} opts The options to use for the request
    @param {String} [opts.url] The URL to send the request to
    @param {String} [opts.method=GET] The method to use for the request
    @param {Object} [opts.headers] Headers to send on requests
    @param {String} [opts.data] Data to send on POST and PUT requests
    @param {String} [opts.dataType] The type of data to send
  @param {Function} callback the function to call after, args are `error, data`
*/
var request = function (opts, callback) {
  var client
    , options = opts || {}
    , parsed = url.parse(options.url)
    , path
    , requester = parsed.protocol == 'http:' ? http : https
    , method = (options.method && options.method.toUpperCase()) || 'GET'
    , headers = core.mixin({}, options.headers || {})
    , contentLength
    , port
    , clientOpts;

  if (parsed.port) {
    port = parsed.port;
  }
  else {
    port = parsed.protocol == 'http:' ? '80' : '443';
  }

  path = parsed.pathname;
  if (parsed.search) {
    path += parsed.search;
  }

  if (method == 'POST' || method == 'PUT') {
    if (options.data) {
      contentLength = options.data.length;
    }
    else {
      contentLength = 0
    }
    headers['Content-Length'] = contentLength;
  }

  clientOpts = {
    host: parsed.hostname
  , port: port
  , method: method
  , agent: false
  , path: path
  , headers: headers
  };
  client = requester.request(clientOpts);

  client.addListener('response', function (resp) {
    var data = ''
      , dataType;
    resp.addListener('data', function (chunk) {
      data += chunk.toString();
    });
    resp.addListener('end', function () {
      var stat = resp.statusCode
        , err;
      // Successful response
      if ((stat > 199 && stat < 300) || stat == 304) {
        dataType = options.dataType || uri.getFileExtension(parsed.pathname);
        if (formatters[dataType]) {
          try {
            if (data) {
              data = formatters[dataType](data);
            }
          }
          catch (e) {
            callback(e, null);
          }
        }
        callback(null, data);
      }
      // Something failed
      else {
        err = new Error(data);
        err.statusCode = resp.statusCode;
        callback(err, null);
      }

    });
  });

  client.addListener('error', function (e) {
    callback(e, null);
  });

  if ((method == 'POST' || method == 'PUT') && options.data) {
    client.write(options.data);
  }

  client.end();
};

module.exports = request;
<commit_msg>Not everything is ASCII<commit_after>/*
 * Utilities: A classic collection of JavaScript utilities
 * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/
var http = require('http')
  , https = require('https')
  , url = require('url')
  , uri = require('./uri')
  , log = require('./log')
  , core = require('./core');

var formatters = {
  xml: function (data) {
    return data;
  }
, html: function (data) {
    return data;
  }
, txt: function (data) {
    return data;
  }
, json: function (data) {
    return JSON.parse(data);
  }
}

/**
  @name request
  @namespace request
  @public
  @function
  @description Sends requests to the given url sending any data if the method is POST or PUT
  @param {Object} opts The options to use for the request
    @param {String} [opts.url] The URL to send the request to
    @param {String} [opts.method=GET] The method to use for the request
    @param {Object} [opts.headers] Headers to send on requests
    @param {String} [opts.data] Data to send on POST and PUT requests
    @param {String} [opts.dataType] The type of data to send
  @param {Function} callback the function to call after, args are `error, data`
*/
var request = function (opts, callback) {
  var client
    , options = opts || {}
    , parsed = url.parse(options.url)
    , path
    , requester = parsed.protocol == 'http:' ? http : https
    , method = (options.method && options.method.toUpperCase()) || 'GET'
    , headers = core.mixin({}, options.headers || {})
    , contentLength
    , port
    , clientOpts;

  if (parsed.port) {
    port = parsed.port;
  }
  else {
    port = parsed.protocol == 'http:' ? '80' : '443';
  }

  path = parsed.pathname;
  if (parsed.search) {
    path += parsed.search;
  }

  if (method == 'POST' || method == 'PUT') {
    if (options.data) {
      contentLength = Buffer.byteLength(options.data);
    }
    else {
      contentLength = 0
    }
    headers['Content-Length'] = contentLength;
  }

  clientOpts = {
    host: parsed.hostname
  , port: port
  , method: method
  , agent: false
  , path: path
  , headers: headers
  };
  client = requester.request(clientOpts);

  client.addListener('response', function (resp) {
    var data = ''
      , dataType;
    resp.addListener('data', function (chunk) {
      data += chunk.toString();
    });
    resp.addListener('end', function () {
      var stat = resp.statusCode
        , err;
      // Successful response
      if ((stat > 199 && stat < 300) || stat == 304) {
        dataType = options.dataType || uri.getFileExtension(parsed.pathname);
        if (formatters[dataType]) {
          try {
            if (data) {
              data = formatters[dataType](data);
            }
          }
          catch (e) {
            callback(e, null);
          }
        }
        callback(null, data);
      }
      // Something failed
      else {
        err = new Error(data);
        err.statusCode = resp.statusCode;
        callback(err, null);
      }

    });
  });

  client.addListener('error', function (e) {
    callback(e, null);
  });

  if ((method == 'POST' || method == 'PUT') && options.data) {
    client.write(options.data);
  }

  client.end();
};

module.exports = request;
<|endoftext|>


<commit_before>var parse = require('url').parse;
var defaultHeader = {'content-type': 'text/plain'};

/**
 * Handle http requests.
 *
 * @public
 * @param {object} The session object.
 * @param {object} The http request object.
 * @param {object} The http response object.
 */
module.exports = function handler (session, req, res) {

    var url = parse(req.url, true);

    // clean up pathname
    url.pathname = url.pathname.replace(/\%7C/g, '|');

    // create path array
    var path = url.pathname.replace(/\/$|^\//g, "").split("/", 42);

    if (path[0] === engine.operation_id) {

        // create the link object
        var link = {
            req: req,
            res: res,
            end: end,
            session: session,
            pathname: url.pathname,
            path: path.slice(3),
            query: url.query
        };

        if (path.length < 3 || !path[1] || !path[2]) {
            return link.end(400, 'Invalid operation url.');
        }

        var instance;
        var role = session[engine.session_role];

        // set engine as instance (core module)
        if (path[1] === '0') {

            switch (path[2]) {
                case 'script':
                    instance = engine;
                    break;
            }

        // get cached instance and check access
        } else {
            instance = engine.module.access(role, path[1], path[2]);
        }

        // check if instance an operation exists
        if (instance) {

            // extend link object
            link._ = instance;
            link.path = path.slice(3);
            link.name = path[2];

            // save session in link
            link[engine.session_role] = role;
            link[engine.session_user] = session[engine.session_user];
            link[engine.session_locale] = session[engine.session_locale];

            // set a empty response header object
            link.headers = {};

            // emit operation
            instance.emit(link.name, link);

            // resume request
            return req.resume();
        }

        // send a "not found" if instance is not found or access denied
        return link.end(404, 'Instance or operation not found.');

    }

    // pass request to the static module
    engine.static(url.pathname, req, res);
    req.resume();
};

/**
 * Send a http response (end the connection).
 *
 * @public
 * @param {number} The http status code.
 * @param {object} The response data.
 */
function end (code, data) {
    var self = this;

    var headers = self.headers || defaultHeader;
    headers.Server = 'JCES';

    data = convertToBuffer(data, headers);

    if (data === false) {
        code = 500;
        data = 'JSON stringify error';
    }

    headers['Content-Length'] = data.length;

    self.res.writeHead(code, headers);
    self.res.end(data);
}

/**
 * Convert data to a data buffer.
 *
 * @private
 * @param {object} The data to convert.
 * @param {object} The http headers.
 */
function convertToBuffer (data, headers) {

    if (data === undefined) {
        return new Buffer(0);
    }

    if (typeof data === 'string') {
        return new Buffer(data);
    }

    if (data instanceof Buffer) {
        return data;
    }

    try {
        data = JSON.stringify(data);

        if (headers) {
            headers['content-type'] = 'application/json; charset=utf-8';
        }
    } catch (err) {
        if (headers) {
            headers['content-type'] = 'text/plain';
        }
        return false;
    }

    if (data === undefined) {
        return false;
    }

    return new Buffer(data);
}
<commit_msg>"module.access" is now "module.eventAccess"<commit_after>var parse = require('url').parse;
var defaultHeader = {'content-type': 'text/plain'};

/**
 * Handle http requests.
 *
 * @public
 * @param {object} The session object.
 * @param {object} The http request object.
 * @param {object} The http response object.
 */
module.exports = function handler (session, req, res) {

    var url = parse(req.url, true);

    // clean up pathname
    url.pathname = url.pathname.replace(/\%7C/g, '|');

    // create path array
    var path = url.pathname.replace(/\/$|^\//g, "").split("/", 42);

    if (path[0] === engine.operation_id) {

        // create the link object
        var link = {
            req: req,
            res: res,
            end: end,
            session: session,
            pathname: url.pathname,
            path: path.slice(3),
            query: url.query
        };

        if (path.length < 3 || !path[1] || !path[2]) {
            return link.end(400, 'Invalid operation url.');
        }

        var instance;
        var role = session[engine.session_role];

        // set engine as instance (core module)
        if (path[1] === '0') {

            switch (path[2]) {
                case 'script':
                    instance = engine;
                    break;
            }

        // get cached instance and check access
        } else {
            instance = engine.module.eventAccess(role, path[1], path[2]);
        }

        // check if instance an operation exists
        if (instance) {

            // extend link object
            link._ = instance;
            link.path = path.slice(3);
            link.name = path[2];

            // save session in link
            link[engine.session_role] = role;
            link[engine.session_user] = session[engine.session_user];
            link[engine.session_locale] = session[engine.session_locale];

            // set a empty response header object
            link.headers = {};

            // emit operation
            instance.emit(link.name, link);

            // resume request
            return req.resume();
        }

        // send a "not found" if instance is not found or access denied
        return link.end(404, 'Instance or operation not found.');

    }

    // pass request to the static module
    engine.static(url.pathname, req, res);
    req.resume();
};

/**
 * Send a http response (end the connection).
 *
 * @public
 * @param {number} The http status code.
 * @param {object} The response data.
 */
function end (code, data) {
    var self = this;

    var headers = self.headers || defaultHeader;
    headers.Server = 'JCES';

    data = convertToBuffer(data, headers);

    if (data === false) {
        code = 500;
        data = 'JSON stringify error';
    }

    headers['Content-Length'] = data.length;

    self.res.writeHead(code, headers);
    self.res.end(data);
}

/**
 * Convert data to a data buffer.
 *
 * @private
 * @param {object} The data to convert.
 * @param {object} The http headers.
 */
function convertToBuffer (data, headers) {

    if (data === undefined) {
        return new Buffer(0);
    }

    if (typeof data === 'string') {
        return new Buffer(data);
    }

    if (data instanceof Buffer) {
        return data;
    }

    try {
        data = JSON.stringify(data);

        if (headers) {
            headers['content-type'] = 'application/json; charset=utf-8';
        }
    } catch (err) {
        if (headers) {
            headers['content-type'] = 'text/plain';
        }
        return false;
    }

    if (data === undefined) {
        return false;
    }

    return new Buffer(data);
}
<|endoftext|>


<commit_before>'use strict';

var phantomJS = require('phantomjs');
var childProcess = require('child_process');
var config = require('../bin/config');
var requestQueue = require('./queue');
var logger = require('./logger');
var openedProcesses = 0;
var maxProcesses = config.maxProcesses || 1;

function responseTime(start) {
  var diff = process.hrtime(start);
  var ms = diff[0] * 1e3 + diff[1] * 1e-6;
  return Math.round(ms);
}

function reportOnProcesses() {
  logger.info('Currently ' + openedProcesses + ' processes running of a maximum of ' + maxProcesses + '.');
}

function getContent(url, callback) {
  var startAt = process.hrtime(),
      code = 200,
      phantom;

  function spawnLog(message, info, level) {
    info = info || {};
    if (!level && info.error) {
      level = 'error';
    }
    if (phantom) {
      info.pid = phantom.pid;
    }
    info.url = url;
    logger[level || 'info'](message, info);
  }

  openedProcesses++;
  spawnLog('Launching PhantomJS process to handle request...');
  reportOnProcesses();

  phantom = childProcess.execFile(
    phantomJS.path,
    [
      '--ignore-ssl-errors=' + config.ignoreSSLErrors,
      '--load-images=' + config.loadImages,
      __dirname + '/phantom-server.js',
      url
    ],
    {
      maxBuffer: config.phantomMaxBuffer,
      timeout: config.phantomTimeout,
      killSignal: 'SIGKILL'
    },
    function (error, stdout) {
      if (error) {
        spawnLog('PhantomJS returned with error.', {error: String(error), stack: error.stack});
        callback(stdout, 504);
      } else {
        spawnLog('PhantomJS returned successfully.');
        callback(stdout, code);
      }
    }
  );

  spawnLog('PhantomJS process spawned.');

  phantom.stdout.setEncoding('utf8');

  phantom.stderr.on('data', function (data) {
    if (data === '404') {
      code = 404;
    } else if (data === '500') {
      code = 500;
    } else {
      spawnLog(data);
    }
  });

  phantom.on('exit', function(code) {
    var appTime = responseTime(startAt);
    var info = {exitCode: code, httpApplicationTime: appTime};
    if (code !== 0) {
      spawnLog('PhantomJS exited with error code ' + code + '.', info, 'critical');
    }
    spawnLog('PhantomJS returned in ' + appTime + 'ms.', info);
  });
}

function next() {
  openedProcesses--;
  reportOnProcesses();

  requestQueue.report();

  var nextItem = requestQueue.next();

  if (nextItem !== undefined) {
    logger.info('Picking up request from queue.', next.url);
    getContent(next.url, next.callback);
  }
}

function makeRequest(data) {
  reportOnProcesses();

  if (maxProcesses > openedProcesses) {
    getContent(data.url, data.callback);
  }
  else {
    logger.info('Maximum processes exceeded, adding request to queue.', {url: data.url});
    requestQueue.add(data);
  }
}

module.exports = {
  makeRequest: makeRequest,
  next: next
};
<commit_msg>Allow any SSL protocol.<commit_after>'use strict';

var phantomJS = require('phantomjs');
var childProcess = require('child_process');
var config = require('../bin/config');
var requestQueue = require('./queue');
var logger = require('./logger');
var openedProcesses = 0;
var maxProcesses = config.maxProcesses || 1;

function responseTime(start) {
  var diff = process.hrtime(start);
  var ms = diff[0] * 1e3 + diff[1] * 1e-6;
  return Math.round(ms);
}

function reportOnProcesses() {
  logger.info('Currently ' + openedProcesses + ' processes running of a maximum of ' + maxProcesses + '.');
}

function getContent(url, callback) {
  var startAt = process.hrtime(),
      code = 200,
      phantom;

  function spawnLog(message, info, level) {
    info = info || {};
    if (!level && info.error) {
      level = 'error';
    }
    if (phantom) {
      info.pid = phantom.pid;
    }
    info.url = url;
    logger[level || 'info'](message, info);
  }

  openedProcesses++;
  spawnLog('Launching PhantomJS process to handle request...');
  reportOnProcesses();

  phantom = childProcess.execFile(
    phantomJS.path,
    [
      '--ignore-ssl-errors=' + config.ignoreSSLErrors,
      '--ssl-protocol=any',
      '--load-images=' + config.loadImages,
      __dirname + '/phantom-server.js',
      url
    ],
    {
      maxBuffer: config.phantomMaxBuffer,
      timeout: config.phantomTimeout,
      killSignal: 'SIGKILL'
    },
    function (error, stdout) {
      if (error) {
        spawnLog('PhantomJS returned with error.', {error: String(error), stack: error.stack});
        callback(stdout, 504);
      } else {
        spawnLog('PhantomJS returned successfully.');
        callback(stdout, code);
      }
    }
  );

  spawnLog('PhantomJS process spawned.');

  phantom.stdout.setEncoding('utf8');

  phantom.stderr.on('data', function (data) {
    if (data === '404') {
      code = 404;
    } else if (data === '500') {
      code = 500;
    } else {
      spawnLog(data);
    }
  });

  phantom.on('exit', function(code) {
    var appTime = responseTime(startAt);
    var info = {exitCode: code, httpApplicationTime: appTime};
    if (code !== 0) {
      spawnLog('PhantomJS exited with error code ' + code + '.', info, 'critical');
    }
    spawnLog('PhantomJS returned in ' + appTime + 'ms.', info);
  });
}

function next() {
  openedProcesses--;
  reportOnProcesses();

  requestQueue.report();

  var nextItem = requestQueue.next();

  if (nextItem !== undefined) {
    logger.info('Picking up request from queue.', next.url);
    getContent(next.url, next.callback);
  }
}

function makeRequest(data) {
  reportOnProcesses();

  if (maxProcesses > openedProcesses) {
    getContent(data.url, data.callback);
  }
  else {
    logger.info('Maximum processes exceeded, adding request to queue.', {url: data.url});
    requestQueue.add(data);
  }
}

module.exports = {
  makeRequest: makeRequest,
  next: next
};
<|endoftext|>


<commit_before>var util = require('util'),
	http = require('http'),
	ApiHttpError = require('./errors').ApiHttpError,
	cache = require('./cache'),
	querystring = require('querystring'),
	underscore = require('underscore'),
	helpers = require('./helpers'),
	oauthHelper = require('./oauth-helper'),
	USER_AGENT = 'Node.js HTTP Client';

// Formats request parameters as expected by the API.
//
// - @param {Object} data - hash of pararameters
// - @param {String} consumerkey - consumer key
// - @return {String} - Encoded parameter string
function prepare(data, consumerkey) {
	var prop;
	data = data || {};

	for (prop in data) {
		if (data.hasOwnProperty(prop)) {
			if (underscore.isDate(data[prop])) {
				data[prop] = helpers.toYYYYMMDD(data[prop]);
			}
		}
	}

	data.oauth_consumer_key = consumerkey;

	return data;
}

// Generates the default request headers
//
// - @return {Object}
function createHeaders(host) {
	return {
		'host': host,
		'User-Agent' : USER_AGENT
	};
}

// Makes a GET request to the API.
//
// - @param {Object} endpointInfo - Generic metadata about the endpoint to hit.
// - @param {Object} requestData - Parameters for this specific request.
// - @param {Object} credentials - OAuth consumerkey and consumersecret.
// - @param {Object} logger - An object implementing the npm log levels.
// - @param {Object} theCache - A response cache.
// - @param {Function} callback - The callback to call with the response.
function get(endpointInfo, requestData, credentials, logger, theCache,
	callback) {

	var normalisedData = prepare(requestData, credentials.consumerkey),
		fullUrl = endpointInfo.url + '?' +
			querystring.stringify(normalisedData),
		cacheKey = cache.generateCacheKeyFromUrl(fullUrl),
		hostInfo = {
			host: endpointInfo.host,
			port: endpointInfo.port
		};

	theCache.get(cacheKey, function checkCacheResult(err, res) {
		if (err) {
			logger.error('Error checking cache for %s', cacheKey);
			logger.error(err);
			return callback(err);
		}

		if (res) {
			logger.info('Cache hit for %s', cacheKey);
			return callback(null, res);
		}

		// Decide whether to make an oauth signed request or not
		if (endpointInfo.authtype) {
			dispatchSecure(endpointInfo.url, 'GET', requestData,
				endpointInfo.authtype, hostInfo, credentials, logger,
				cacheAndCallback);
		} else {
			dispatch(endpointInfo.url, 'GET', requestData, hostInfo,
				credentials, logger, cacheAndCallback);
		}

		function cacheAndCallback(err, requestData, response) {
			if (err) {
				return callback(err);
			}

			var ttl = cache.parseMaxAgeHeader(response);

			if (ttl) {
				theCache.set(cacheKey, requestData, ttl, callbackWithResult);
			} else {
				return callback(null, requestData, response);
			}

			function callbackWithResult(err) {
				if (err) {
					logger.error('Error setting %s to cache', cacheKey);
					logger.error(err);
					return callback(err);
				}

				logger.info('Cached %s for %s seconds', cacheKey, ttl);
				return callback(null, requestData, response);
			}
		}
	});
}

// Makes a POST request to the API.
//
// - @param {Object} endpointInfo - Generic metadata about the endpoint to hit.
// - @param {Object} requestData - Parameters for this specific request.
// - @param {Object} credentials - OAuth consumerkey and consumersecret.
// - @param {Object} logger - An object implementing the npm log levels.
// - @param {Function} callback - The callback to call with the response.
function post(endpointInfo, requestData, credentials, logger, callback) {
	var hostInfo = {
		host: endpointInfo.host,
		port: endpointInfo.port
	};

	if (endpointInfo.authtype) {
		dispatchSecure(endpointInfo.url, 'POST', requestData,
			endpointInfo.authtype, hostInfo, credentials, logger, callback);
	} else {
		dispatch(endpointInfo.url, 'POST', requestData, hostInfo, credentials,
			logger, callback);
	}
}

// Dispatches an oauth signed request to the API
//
// - @param {String} url - the path of the API url to request.
// - @param {String} httpMethod
// - @param {Object} requestData - hash of the parameters for the request.
// - @param {String} authType - OAuth request type: '2-legged' or '3-legged'
// - @param {Object} hostInfo - API host information
// - @param {Function} callback - The callback to call with the response.
function dispatchSecure(url, httpMethod, requestData, authtype, hostInfo,
		credentials, logger, callback) {

	var fullUrl = 'https://' + hostInfo.host + url,
		is2Legged = authtype === '2-legged',
		token = is2Legged ? null : requestData.accesstoken,
		secret = is2Legged ? null : requestData.accesssecret,
		oauthClient = oauthHelper.createOAuthWrapper(
			credentials.consumerkey, credentials.consumersecret);

	requestData = prepare(requestData, credentials.consumerkey);

	logger.info(httpMethod + ': ' + fullUrl + ' (' + authtype + ' oauth)');

	if (!is2Legged) {
		delete requestData.accesstoken;
		delete requestData.accesssecret;
	}

	if (httpMethod === 'GET') {
		logger.info('token: ' + token + ' secret: ' + secret);
		fullUrl = fullUrl + '?' + querystring.stringify(requestData);

		oauthClient.get(fullUrl, token, secret, function (err, data,
			response) {
			if (err) {
				logger.error(JSON.stringify(err));
				callback(err);
				return;
			}

			callback(null, data, response);
		});
	} else {
		oauthClient[httpMethod.toLowerCase()](fullUrl, token, secret,
			requestData, 'application/x-www-form-urlencoded',
			function (err, data, response) {

			if (err) {
				logger.error(err);
				callback(err);
				return;
			}

			callback(null, data, response);
		});
	}
	logger.info('DATA: ' + querystring.stringify(requestData));
}

// Dispatches requests to the API.  Serializes the data in keeping with the API
// specification and applies approriate HTTP headers.
//
// - @param {String} url - the URL on the API to make the request to.
// - @param {String} httpMethod
// - @param {Object} data - hash of the parameters for the request.
// - @param {Object} hostInfo - hash of host, port and version
// - @param {Object} credentials - hash of oauth consumer key and secret
// - @param {Object} logger - an object implementing the npm log levels
// - @param {Function} callback
function dispatch(url, httpMethod, data, hostInfo, credentials, logger,
	callback) {

	var apiRequest, headers, prop, hasErrored;

	data = prepare(data, credentials.consumerkey);

	// Special case for track previews: we explicitly request to be given
	// the XML response back instead of a redirect to the track download.
	if (url.indexOf('track/preview') >= 0) {
		data.redirect = "false";
	}

	if (httpMethod === 'GET') {
		url = url + '?' + querystring.stringify(data);
	}

	logger.info(util.format('%s: http://%s:%s%s', httpMethod,
		hostInfo.host, hostInfo.port, url));

	// Make the request
	apiRequest = http.request({
		method: httpMethod,
		hostname: hostInfo.host,
		// Force scheme to http for browserify otherwise it will pick up the
		// scheme from window.location.protocol which is app:// in firefoxos
		scheme: 'http',
		// Set this so browserify doesn't set it to true on the xhr, which
		// causes an http status of 0 and empty response text as it forces
		// the XHR to do a pre-flight access-control check and the API
		// currently does not set CORS headers.
		withCredentials: false,
		path: url,
		port: hostInfo.port,
		headers: createHeaders(hostInfo.host)
	}, function handleResponse(response) {
		var responseBuffer = '';

		if (typeof response.setEncoding === 'function') {
			response.setEncoding("utf8");
		}

		response.on("data", function bufferData(chunk) {
			responseBuffer += chunk;
		});

		response.on("end", function endResponse() {
			if (+response.statusCode >= 400) {
				return callback(new ApiHttpError(
					response.statusCode, responseBuffer));
			}

			if (!hasErrored) {
				callback(null, responseBuffer, response);
			}
		});
	});

	apiRequest.on('error', function logErrorAndCallback(data) {
		// Flag that we've errored so we don't call the callback twice
		// if we get an end event on the response.
		hasErrored = true;
		logger.info('Error fetching [' + url + ']. Body:\n' + data);

		return callback(new Error('Error connecting to ' + url));
	});

	if (httpMethod === 'GET') {
		apiRequest.end();
	} else {
		apiRequest.end(data);
	}
}

module.exports.get = get;
module.exports.post = post;
module.exports.createHeaders = createHeaders;
module.exports.prepare = prepare;
module.exports.dispatch = dispatch;
module.exports.dispatchSecure = dispatchSecure;
<commit_msg>Tidies up request<commit_after>var util = require('util'),
	http = require('http'),
	ApiHttpError = require('./errors').ApiHttpError,
	cache = require('./cache'),
	querystring = require('querystring'),
	underscore = require('underscore'),
	helpers = require('./helpers'),
	oauthHelper = require('./oauth-helper'),
	USER_AGENT = 'Node.js HTTP Client';

// Formats request parameters as expected by the API.
//
// - @param {Object} data - hash of pararameters
// - @param {String} consumerkey - consumer key
// - @return {String} - Encoded parameter string
function prepare(data, consumerkey) {
	var prop;
	data = data || {};

	for (prop in data) {
		if (data.hasOwnProperty(prop)) {
			if (underscore.isDate(data[prop])) {
				data[prop] = helpers.toYYYYMMDD(data[prop]);
			}
		}
	}

	data.oauth_consumer_key = consumerkey;

	return data;
}

// Generates the default request headers
//
// - @return {Object}
function createHeaders(host) {
	return {
		'host': host,
		'User-Agent' : USER_AGENT
	};
}

// Makes a GET request to the API.
//
// - @param {Object} endpointInfo - Generic metadata about the endpoint to hit.
// - @param {Object} requestData - Parameters for this specific request.
// - @param {Object} credentials - OAuth consumerkey and consumersecret.
// - @param {Object} logger - An object implementing the npm log levels.
// - @param {Object} theCache - A response cache.
// - @param {Function} callback - The callback to call with the response.
function get(endpointInfo, requestData, credentials, logger, theCache,
	callback) {

	var normalisedData = prepare(requestData, credentials.consumerkey),
		fullUrl = endpointInfo.url + '?' +
			querystring.stringify(normalisedData),
		cacheKey = cache.generateCacheKeyFromUrl(fullUrl),
		hostInfo = {
			host: endpointInfo.host,
			port: endpointInfo.port
		};

	theCache.get(cacheKey, checkCacheResult);
	function checkCacheResult(err, res) {
		if (err) {
			logger.error('Error checking cache for %s', cacheKey);
			logger.error(err);
			return callback(err);
		}

		if (res) {
			logger.info('Cache hit for %s', cacheKey);
			return callback(null, res);
		}

		// Decide whether to make an oauth signed request or not
		if (endpointInfo.authtype) {
			dispatchSecure(endpointInfo.url, 'GET', requestData,
				endpointInfo.authtype, hostInfo, credentials, logger,
				cacheAndCallback);
		} else {
			dispatch(endpointInfo.url, 'GET', requestData, hostInfo,
				credentials, logger, cacheAndCallback);
		}

		function cacheAndCallback(err, requestData, response) {
			if (err) {
				return callback(err);
			}

			var ttl = cache.parseMaxAgeHeader(response);

			if (ttl) {
				theCache.set(cacheKey, requestData, ttl, callbackWithResult);
			} else {
				return callback(null, requestData, response);
			}

			function callbackWithResult(err) {
				if (err) {
					logger.error('Error setting %s to cache', cacheKey);
					logger.error(err);
					return callback(err);
				}

				logger.info('Cached %s for %s seconds', cacheKey, ttl);
				return callback(null, requestData, response);
			}
		}
	}
}

// Makes a POST request to the API.
//
// - @param {Object} endpointInfo - Generic metadata about the endpoint to hit.
// - @param {Object} requestData - Parameters for this specific request.
// - @param {Object} credentials - OAuth consumerkey and consumersecret.
// - @param {Object} logger - An object implementing the npm log levels.
// - @param {Function} callback - The callback to call with the response.
function post(endpointInfo, requestData, credentials, logger, callback) {
	var hostInfo = {
		host: endpointInfo.host,
		port: endpointInfo.port
	};

	if (endpointInfo.authtype) {
		dispatchSecure(endpointInfo.url, 'POST', requestData,
			endpointInfo.authtype, hostInfo, credentials, logger, callback);
	} else {
		dispatch(endpointInfo.url, 'POST', requestData, hostInfo, credentials,
			logger, callback);
	}
}

// Dispatches an oauth signed request to the API
//
// - @param {String} url - the path of the API url to request.
// - @param {String} httpMethod
// - @param {Object} requestData - hash of the parameters for the request.
// - @param {String} authType - OAuth request type: '2-legged' or '3-legged'
// - @param {Object} hostInfo - API host information
// - @param {Function} callback - The callback to call with the response.
function dispatchSecure(url, httpMethod, requestData, authtype, hostInfo,
		credentials, logger, callback) {

	var fullUrl = 'https://' + hostInfo.host + url,
		is2Legged = authtype === '2-legged',
		token = is2Legged ? null : requestData.accesstoken,
		secret = is2Legged ? null : requestData.accesssecret,
		oauthClient = oauthHelper.createOAuthWrapper(
			credentials.consumerkey, credentials.consumersecret);

	requestData = prepare(requestData, credentials.consumerkey);

	logger.info(httpMethod + ': ' + fullUrl + ' (' + authtype + ' oauth)');

	if (!is2Legged) {
		delete requestData.accesstoken;
		delete requestData.accesssecret;
	}

	if (httpMethod === 'GET') {
		logger.info('token: ' + token + ' secret: ' + secret);
		fullUrl = fullUrl + '?' + querystring.stringify(requestData);

		oauthClient.get(fullUrl, token, secret, callbackWithDataAndResponse);
	} else {
		// FIXME: This will not work with the playlist API which expects a
		// JSON payload
		oauthClient[httpMethod.toLowerCase()](fullUrl, token, secret,
			requestData, 'application/x-www-form-urlencoded',
			callbackWithDataAndResponse);
	}

	function callbackWithDataAndResponse(err, data, response) {
		if (err) {
			logger.error(err);
			return callback(err);
		}

		callback(null, data, response);
	}

	logger.info('DATA: ' + querystring.stringify(requestData));
}

// Dispatches requests to the API.  Serializes the data in keeping with the API
// specification and applies approriate HTTP headers.
//
// - @param {String} url - the URL on the API to make the request to.
// - @param {String} httpMethod
// - @param {Object} data - hash of the parameters for the request.
// - @param {Object} hostInfo - hash of host, port and version
// - @param {Object} credentials - hash of oauth consumer key and secret
// - @param {Object} logger - an object implementing the npm log levels
// - @param {Function} callback
function dispatch(url, httpMethod, data, hostInfo, credentials, logger,
	callback) {

	var apiRequest, headers, prop, hasErrored;

	data = prepare(data, credentials.consumerkey);

	// Special case for track previews: we explicitly request to be given
	// the XML response back instead of a redirect to the track download.
	if (url.indexOf('track/preview') >= 0) {
		data.redirect = "false";
	}

	if (httpMethod === 'GET') {
		url = url + '?' + querystring.stringify(data);
	}

	logger.info(util.format('%s: http://%s:%s%s', httpMethod,
		hostInfo.host, hostInfo.port, url));

	// Make the request
	apiRequest = http.request({
		method: httpMethod,
		hostname: hostInfo.host,
		// Force scheme to http for browserify otherwise it will pick up the
		// scheme from window.location.protocol which is app:// in firefoxos
		scheme: 'http',
		// Set this so browserify doesn't set it to true on the xhr, which
		// causes an http status of 0 and empty response text as it forces
		// the XHR to do a pre-flight access-control check and the API
		// currently does not set CORS headers.
		withCredentials: false,
		path: url,
		port: hostInfo.port,
		headers: createHeaders(hostInfo.host)
	}, function handleResponse(response) {
		var responseBuffer = '';

		if (typeof response.setEncoding === 'function') {
			response.setEncoding("utf8");
		}

		response.on("data", function bufferData(chunk) {
			responseBuffer += chunk;
		});

		response.on("end", function endResponse() {
			if (+response.statusCode >= 400) {
				return callback(new ApiHttpError(
					response.statusCode, responseBuffer));
			}

			if (!hasErrored) {
				return callback(null, responseBuffer, response);
			}
		});
	});

	apiRequest.on('error', function logErrorAndCallback(data) {
		// Flag that we've errored so we don't call the callback twice
		// if we get an end event on the response.
		hasErrored = true;
		logger.info('Error fetching [' + url + ']. Body:\n' + data);

		return callback(new Error('Error connecting to ' + url));
	});

	if (httpMethod === 'GET') {
		apiRequest.end();
	} else {
		apiRequest.end(data);
	}
}

module.exports.get = get;
module.exports.post = post;
module.exports.createHeaders = createHeaders;
module.exports.prepare = prepare;
module.exports.dispatch = dispatch;
module.exports.dispatchSecure = dispatchSecure;
<|endoftext|>


<commit_before>'use strict';

const
	$C = require('collection.js'),
	Sugar = require('sugar'),
	fs = require('fs-extra-promise'),
	path = require('path'),
	glob = require('glob-promise');

const
	config = require('./config'),
	cwd = process.cwd();

const
	depMap = {},
	dependencies = [],
	rootDependencies = [],
	ignore = [];

const
	types = [config.projectType];

$C(config.dependencies).forEach((obj) => {
	const
		isStr = Sugar.Object.isString(obj),
		baseSrc = isStr ? obj : obj.src;

	if (depMap[baseSrc]) {
		return;
	}

	depMap[baseSrc] = isStr ?
		{
			src: baseSrc,
			exclude: new Set()
		} :

		{
			...obj,
			exclude: new Set(obj.exclude)
		}
	;

	ignore.push(
		depMap[baseSrc].exclude
	);

	const
		src = path.join(cwd, 'node_modules', Sugar.Object.isString(obj) ? obj : obj.src);

	let
		cfg = path.join(src, '.pzlrrc');

	if (fs.existsSync(cfg)) {
		cfg = $C.extend(true, {}, require('./pzrlrc-default.json'), fs.readJsonSync(cfg));

		const
			base = path.join(src, cfg.sourceDir);

		dependencies.push(path.join(base, cfg.blockDir));
		rootDependencies.push(base);

	} else {
		dependencies.push(src);
		rootDependencies.push(src);
	}

	types.push(cfg.projectType || 'js');
});

const
	sourceDir = path.join(cwd, config.sourceDir),
	sourceDirs = [sourceDir].concat(dependencies);

/**
 * Returns an absolute path to a block by the specified name
 *
 * @param {string=} [name]
 * @param {number=} [skip]
 * @returns {!Promise<(string|Array<string>|{path: (string|Array<string>), lvl: number}|null)>}
 */
async function block(name = '', skip = 0) {
	const
		baseRoot = path.join(sourceDirs[0], config.blockDir);

	if (!name) {
		return baseRoot;
	}

	const
		baseExt = path.extname(name),
		advExt = baseExt ? '' : 'index.js';

	const
		wrap = (path, lvl) => skip ? {path, from: lvl + 1} : path;

	for (let i = skip; i < sourceDirs.length; i++) {
		if (i && baseExt && ignore[i - 1].has(baseExt)) {
			continue;
		}

		const
			root = sourceDirs[i],
			file = path.join(name, advExt).replace(/\.logic$/, `.${types[i]}`);

		let
			src = path.join(root, name);

		if (!glob.hasMagic(file) && await fs.existsAsync(path.join(root, file))) {
			return wrap(src, i);
		}

		const
			components = `/**/${file}`,
			virtualComponents = !baseExt && `/**/${name}.index.js`;

		const files = await Promise.all([
			glob(path.join(root, components)),
			virtualComponents ? glob(path.join(root, virtualComponents)) : []
		]);

		src = files[0][0] || files[1][0];

		if (src) {
			return wrap(advExt ? path.dirname(src) : src, i);
		}
	}

	return baseExt || skip ? null : path.join(baseRoot, name);
}

/**
 * Returns an absolute path to an entry by the specified name
 * @param {string=} [name] - entry name (if empty, returns path to the entries folder)
 */
function entry(name = '') {
	return path.normalize(path.join(sourceDir, config.entriesDir, name ? `${name}.js` : ''));
}

module.exports = {
	depMap,
	sourceDir,
	sourceDirs,
	dependencies,
	rootDependencies,
	block,
	entry
};
<commit_msg>Added entries; Improved devMap<commit_after>'use strict';

const
	$C = require('collection.js'),
	Sugar = require('sugar'),
	fs = require('fs-extra-promise'),
	path = require('path'),
	glob = require('glob-promise');

const
	config = require('./config'),
	cwd = process.cwd();

const
	depMap = {},
	entries = [],
	dependencies = [],
	rootDependencies = [],
	ignore = [];

const
	types = [config.projectType];

$C(config.dependencies).forEach((obj) => {
	const
		isStr = Sugar.Object.isString(obj),
		baseSrc = isStr ? obj : obj.src;

	if (depMap[baseSrc]) {
		return;
	}

	const decl = depMap[baseSrc] = isStr ?
		{
			src: baseSrc,
			exclude: new Set()
		} :

		{
			...obj,
			exclude: new Set(obj.exclude)
		}
	;

	ignore.push(
		decl.exclude
	);

	const
		src = path.join(cwd, 'node_modules', Sugar.Object.isString(obj) ? obj : obj.src);

	let
		cfg = path.join(src, '.pzlrrc');

	if (fs.existsSync(cfg)) {
		cfg = $C.extend(true, {}, require('./pzrlrc-default.json'), fs.readJsonSync(cfg));

		const
			base = path.join(src, cfg.sourceDir);

		decl.config = cfg;
		entries.push(path.join(base, cfg.entriesDir));
		dependencies.push(path.join(base, cfg.blockDir));
		rootDependencies.push(base);

	} else {
		decl.config = $C.extend(true, {}, config);
		entries.push(path.join(src, config.entriesDir));
		dependencies.push(path.join(src, config.blockDir));
		rootDependencies.push(src);
	}

	types.push(cfg.projectType || 'js');
});

entries.push(entry());

const
	sourceDir = path.join(cwd, config.sourceDir),
	sourceDirs = [sourceDir].concat(dependencies);

/**
 * Returns an absolute path to a block by the specified name
 *
 * @param {string=} [name]
 * @param {number=} [skip]
 * @returns {!Promise<(string|Array<string>|{path: (string|Array<string>), lvl: number}|null)>}
 */
async function block(name = '', skip = 0) {
	const
		baseRoot = path.join(sourceDirs[0], config.blockDir);

	if (!name) {
		return baseRoot;
	}

	const
		baseExt = path.extname(name),
		advExt = baseExt ? '' : 'index.js';

	const
		wrap = (path, lvl) => skip ? {path, from: lvl + 1} : path;

	for (let i = skip; i < sourceDirs.length; i++) {
		if (i && baseExt && ignore[i - 1].has(baseExt)) {
			continue;
		}

		const
			root = sourceDirs[i],
			file = path.join(name, advExt).replace(/\.logic$/, `.${types[i]}`);

		let
			src = path.join(root, name);

		if (!glob.hasMagic(file) && await fs.existsAsync(path.join(root, file))) {
			return wrap(src, i);
		}

		const
			components = `/**/${file}`,
			virtualComponents = !baseExt && `/**/${name}.index.js`;

		const files = await Promise.all([
			glob(path.join(root, components)),
			virtualComponents ? glob(path.join(root, virtualComponents)) : []
		]);

		src = files[0][0] || files[1][0];

		if (src) {
			return wrap(advExt ? path.dirname(src) : src, i);
		}
	}

	return baseExt || skip ? null : path.join(baseRoot, name);
}

/**
 * Returns an absolute path to an entry by the specified name
 * @param {string=} [name] - entry name (if empty, returns path to the entries folder)
 */
function entry(name = '') {
	return path.normalize(path.join(sourceDir, config.entriesDir, name ? `${name}.js` : ''));
}

module.exports = {
	depMap,
	sourceDir,
	sourceDirs,
	dependencies,
	rootDependencies,
	entries,
	block,
	entry
};
<|endoftext|>


<commit_before>'use strict';

module.exports = function resolve(dirname) {
	var path = require('path');

	// Check for environmental variable
	if (process.env.APP_ROOT_PATH) {
		return path.resolve(process.env.APP_ROOT_PATH);
	}

	var globalPaths = require('module').globalPaths;
	var resolved = path.resolve(dirname);
	var alternateMethod = false;
	var appRootPath = null;

	// Make sure that we're not loaded from a global include path
	// Eg. $HOME/.node_modules
	//     $HOME/.node_libraries
	//     $PREFIX/lib/node
	globalPaths.forEach(function(globalPath) {
		if (!alternateMethod && 0 === resolved.indexOf(globalPath)) {
			alternateMethod = true;
		}
	});

	// If the app-root-path library isn't loaded globally,
	// and node_modules exists in the path, just split __dirname
	if (!alternateMethod && -1 !== resolved.indexOf('/node_modules')) {
		var parts = resolved.split('/node_modules');
		if (parts.length) {
			appRootPath = parts[0];
			parts = null;
		}
	}

	// If the above didn't work, or this module is loaded globally, then
	// resort to require.main.filename (See http://nodejs.org/api/modules.html)
	if (alternateMethod || null == appRootPath) {
		appRootPath = path.dirname(require.main.filename);
	}

	// Return
	return appRootPath;
};<commit_msg>Now a little more cross-platform-friendly<commit_after>'use strict';

module.exports = function resolve(dirname) {
	var path = require('path');

	// Check for environmental variable
	if (process.env.APP_ROOT_PATH) {
		return path.resolve(process.env.APP_ROOT_PATH);
	}

	var globalPaths = require('module').globalPaths;
	var resolved = path.resolve(dirname);
	var alternateMethod = false;
	var appRootPath = null;

	// Make sure that we're not loaded from a global include path
	// Eg. $HOME/.node_modules
	//     $HOME/.node_libraries
	//     $PREFIX/lib/node
	globalPaths.forEach(function(globalPath) {
		if (!alternateMethod && 0 === resolved.indexOf(globalPath)) {
			alternateMethod = true;
		}
	});

	// If the app-root-path library isn't loaded globally,
	// and node_modules exists in the path, just split __dirname
	var nodeModulesDir = path.sep + 'node_modules';
	if (!alternateMethod && -1 !== resolved.indexOf(nodeModulesDir)) {
		var parts = resolved.split(nodeModulesDir);
		if (parts.length) {
			appRootPath = parts[0];
			parts = null;
		}
	}

	// If the above didn't work, or this module is loaded globally, then
	// resort to require.main.filename (See http://nodejs.org/api/modules.html)
	if (alternateMethod || null == appRootPath) {
		appRootPath = path.dirname(require.main.filename);
	}

	// Return
	return appRootPath;
};<|endoftext|>


<commit_before>var ws, runtime, evaluate, getProperties;

runtime = function runtime(_ws) {
  ws = _ws;

  return {
    evaluate: evaluate,
    getProperties: getProperties
  }
};

evaluate = function evaluate(expression, returnByValue, callback) {
  if (typeof returnByValue === 'function') {
    callback = returnByValue;
    returnByValue = null;
  }

  var req = {
    method: 'Runtime.evaluate',
    params: {
      expression: expression,
    }
  };

  if (returnByValue) {
    req.params.returnByValue = returnByValue;
  }

  ws.send(req, function(res) {
    console.log('eval', res);
    callback && callback(res.wasThrown, res.result);
  });
};

getProperties = function getProperties(remoteObjectId, ownProperties, callback) {
  if (typeof ownProperties === 'function') {
    callback = ownProperties;
    ownProperties = null;
  }

  var req = {
    method: 'Runtime.getProperties',
    params: {
      objectId: remoteObjectId
    }
  };

  if (ownProperties) {
    req.params.ownProperties = ownProperties;
  }

  ws.send(req, function(res) {
    console.log('getProps', res);
    if (callback) {
      if (res.error) {
        callback(true, res.error);
      } else {
        callback(false, res.result)
      }
    }
  });
}

module.exports = runtime;
<commit_msg>make runtime callbacks have err arguments. Pass errs to callbacks<commit_after>var ws, runtime, evaluate, getProperties;

runtime = function runtime(_ws) {
  ws = _ws;

  return {
    evaluate: evaluate,
    getProperties: getProperties
  }
};

evaluate = function evaluate(expression, returnByValue, callback) {
  if (typeof returnByValue === 'function') {
    callback = returnByValue;
    returnByValue = null;
  }

  var req = {
    method: 'Runtime.evaluate',
    params: {
      expression: expression,
    }
  };

  if (returnByValue) {
    req.params.returnByValue = returnByValue;
  }

  ws.send(req, function(err, res) {
    console.log('eval', res);

    if (callback) {
      if (err) {
        callback(err, res);
      } else {
        callback(res.wasThrown, res.result);
      }
    }
  });
};

getProperties = function getProperties(remoteObjectId, ownProperties, callback) {
  if (typeof ownProperties === 'function') {
    callback = ownProperties;
    ownProperties = null;
  }

  var req = {
    method: 'Runtime.getProperties',
    params: {
      objectId: remoteObjectId
    }
  };

  if (ownProperties) {
    req.params.ownProperties = ownProperties;
  }

  ws.send(req, function(err, res) {
    console.log('getProps', res);

    if (callback) {
      if (err) {
        callback(err, res);
      } else if (res.error) {
        callback(true, res.error);
      } else {
        callback(false, res.result)
      }
    }
  });
}

module.exports = runtime;
<|endoftext|>


<commit_before>var db = require("./db");
var util = require("./util");
var srv = require("./server");
var api = require("./api");
var async = require("async");

var constraints = {pre:{}, post:{}};
var plugins = {};
var plugouts = {};

/*
 * Load doc and user from db.
 */
function load_objects(ctx, ret_handler){

	async.series(
		[function(next){//load document

			if(ctx.params && ctx.params.wid){

				db.select(ctx.params.catalog, ctx.params.wid, function(err,doc){

					if(err)
						next(err,null);
					else if(!err && !doc)
						next({code:-1, message:"Document not found: #" + ctx.params.catalog + "/" + ctx.params.wid }, null);
					else{
						ctx.doc = doc;
						next();
					}
				});
			}else
				next();
		},

		function(next){//load user

			if(ctx.params && ctx.params.uid){

				db.criteria("users",{uid:ctx.params.uid},{},function(err,users){

					if(err)
						next(err,null);
					else if( !err && !users)
						next({code:-1, message:"User not found: " + ctx.params.uid }, null);
					else{
						ctx.user = users[0];
						next();
					}
				});
			}else
				next();

		}],function(err){

			ret_handler(err);
		}
	);

}

/*
 * Add a plugin
 */
exports.add_plugin = function(proc_name, plugin_name, func_handler){

	if(!plugins[proc_name])
		plugins[proc_name] = {};

	if(func_handler == undefined && typeof plugin_name == "function"){

		func_handler = plugin_name;
		plugin_name = util.generate_rstring(10);
	}

	plugins[proc_name][plugin_name] = function(ctx, end_handler){

		func_handler(ctx, end_handler);
	}

	return exports;
}

/*
 * Add a plugout
 */
exports.add_plugout = function(proc_name, plugout_name, func_handler){

	if(!plugouts[proc_name])
		plugouts[proc_name] = {};

	if(func_handler == undefined && typeof plugout_name == "function"){

		func_handler = plugout_name;
		plugout_name = util.generate_rstring(10);

		plugouts[proc_name][plugout_name] = function(ctx, end_handler){

			func_handler(ctx, end_handler);
		}
		return exports;
	}
}
/*
 * Add constraint as a pre or post constraint.
 */
function add_constraint( constraints, proc_name, cons_name, func_handler){

	if(!constraints[proc_name])
		constraints[proc_name] = {};

	if(func_handler == undefined && typeof cons_name == "function"){

		func_handler = cons_name;
		cons_name = util.generate_rstring(10);
	}

	constraints[proc_name][cons_name] = function(ctx){

		return func_handler(ctx);

	};

	return exports;

}

/*
 * Plug constraint after the document load.
 */
exports.add_constraint_post =  function( proc_name, cons_name, func_handler ){

	return add_constraint(constraints.post, proc_name, cons_name, func_handler);
}

/*
 * Plug constraint before the document load.
 */
exports.add_constraint_pre =  function( proc_name, cons_name, func_handler ){

	return add_constraint(constraints.pre, proc_name, cons_name, func_handler);
}

/*
 * Execute all constaints for proc_name procedure, if no constraints returns an error object execution continues
 * calling api.remote[proc_name].
 */
exports.execute = function( proc_name, params, ret_handler){

	if( !api.remote[proc_name] ){

		ret_handler({code:-32601, message:"Method not found."},null);
		return;
    }else if(!srv.api.config.procedures[proc_name] ){

    	ret_handler({code:-32604, message:"Method not available."},null);
    	return;
    }else if(!srv.config.app || !srv.config.app.status){

    	ret_handler({code:-32603, message:"Server not started"});
    	return;
    }

    //params may come from another function, in that case params refers to ctx.
	var ctx = (params && params.params && params.config && params.doc)? params: { params:params||{},  config:{save:1, emit:1} };
	ctx.params.catalog = ctx.params.catalog || srv.config.db.default_catalog;

	//Execute plugins to transform ctx some way.
	async.forEachSeries(Object.keys(plugins[proc_name]||{}),function(plugin_name,end_handler){

		plugins[proc_name][plugin_name](ctx, end_handler);

	},function(){//plugins executed

		//constraints pre document load.
	    for( key in constraints.pre[proc_name] ){

			var err = constraints.pre[proc_name][key](ctx);
			if(err){

				ret_handler(err,null);
				return;
			}
		}

		load_objects(ctx, function(err){//document and user load

			ctx.doc = ctx.doc || {};

			if(err){
				ret_handler(err,null);
				return;
			}else{

				//constraints post document load
				for( key in constraints.post[proc_name] ){

					var err = constraints.post[proc_name][key](ctx);
					if(err){

						ret_handler(err,null);
						return;
					}
				}

				//All constraints satisfied and plugins executed, so execute procedure.
				api.remote[proc_name](ctx, function(err,val){

					ctx.retval = util.clone(val);//return value returned over ctx.
					async.series([
					function(next){//execute plugouts: may modify ctx.doc, ctx.retval and ctx.payload
						async.forEachSeries(Object.keys(plugouts[proc_name]||{}),function(plugout_name,end_handler){

							plugouts[proc_name][plugout_name](ctx, end_handler);

						},function(){
							next();
						});
					},
					function(next){
						if(err){
							ret_handler(err,null);
							return;
						}else if(ctx.config.save){

							async.series([

								function(next){
									db.save("users", ctx.user, function(err){

										if(err)
											next(err);
										else
											next();
									});
								},
								function(next){
									db.save(ctx.params.catalog, ctx.doc, function(err){

										if(err)
											next(err);
										else
											next();
									});
								}
							],function(err){
								if(err)
									ret_handler(err,null);
								else{
									if(ctx.config.emit){

										ctx.payload = ctx.payload || ctx.params;

										api.emit("ev_api_" + proc_name, ctx);
									}
									ret_handler(null,ctx);
								}
							});
						}else
							ret_handler(null,ctx);
					}
					]);

				});//end execute

			}

		});
	});

}

exports.constraints = {

	is_owner: function(ctx){

			if( ctx.params.uid != ctx.doc.uid ){

				return {code:-2, message:"No access permission: not owner"};
			}
	},

	has_joined: function(ctx){

		if( !ctx.doc.rcpts || ctx.doc.rcpts.indexOf(ctx.params.uid) == -1 ){

			return {code:-3, message:"No access permission: not joined"};
		}
	},

	not_joined: function(ctx){

		if( ctx.doc.rcpts.indexOf(ctx.params.uid) != -1 ){

			return {code:-4, message:"No access permission: already joined"};
		}
	},

	not_system_catalog: function(ctx){

		if( srv.config.db.system_catalogs.indexOf(ctx.params.catalog) != -1 ){

			return {code:-5, message:"No access permission: system catalog"};
		}
	},

	user_catalog: function(ctx){

		if( srv.config.db.user_catalogs.indexOf(ctx.params.catalog) == -1 ){

			return {code:-6, message:"No access permission: not user catalog"};
		}
	},

	is_joinable: function(ctx){

		if(!ctx.doc.rcpts){

			return {code:-7, message:"No access permission: not joinable/unjoinable"};
		}
	},

	is_reserved: function(ctx){

		if(ctx.params.fname == "rcpts" || ctx.params.fname == "_id" || ctx.params.fname == "uid" || ctx.params.fname == "ctime" || ctx.params.fname == "etime" || ctx.params.fname == "catalog"){

			return {code:-8, message:"Reserved word not allowed as field name: " + ctx.params.fname };
		}
	},

	field_exists: function(ctx){

		if(ctx.params.fname){
			if(!util.get_field(ctx.doc,ctx.params.fname)){

				return {code:-9, message:"Not exists: #" + ctx.params.catalog + "/" + ctx.params.wid + ":" + ctx.params.fname};
			}
		}
	},

	field_type: function(type){

			return function(ctx){

				var obj = util.get_field(ctx.doc,ctx.params.fname);

				if(type == "array"){

					if(typeof obj != "object" || !obj.push || !obj.pop || !obj.shift || !obj.unshift  ){

						return {code:-10, message:"Wrong type: #" + ctx.params.catalog + "/" + ctx.params.wid + ":" + ctx.params.fname + " not array"};
					}
				}else{

					if(typeof obj != type ){

						return {code:-10, message:"Wrong type: #" + ctx.params.catalog + "/" + ctx.params.wid + ":" + ctx.params.fname + " not " + type};
					}
				}
		}
	},

	param_type : function(param_name, type){

			return function(ctx){

				if(typeof ctx.params[param_name] != type ){

					return {code:-11, message:"Wrong parameter type: "+ param_name +" not " + type };
				}
		}
	},

	is_required: function(field){

			return function(ctx){

				if(!ctx.params[field]){

					return {code:-12, message:field  + " parameter required"};
				}
		}
	},

	user_exist: function(ctx){

	}

};

exports.plugins = {

	url_transform : function(ctx,next){

		util.parse_url(ctx);
		next();
	},

	notifying_doc : function(ctx,next){

		if(ctx.params.notifiable == undefined){
			if(ctx.params.catalog == srv.config.db.default_catalog)
				ctx.params.rcpts = [ctx.params.uid];
		}else if(ctx.params.notifiable){
			ctx.params.rcpts = [ctx.params.uid];
		}
		next();
	},

	notifying_catalog:function(catalog){

		return function(ctx,next){

			if(ctx.params.catalog == catalog)
				ctx.params.rcpts = [ctx.params.uid];
			next();
		}
	},

	external_config: function(ctx,next){

		if(ctx.params.config){

			for(key in ctx.params.config){

				ctx.config[key] = ctx.params.config[key];
			}
			delete ctx.params.config;
		}

		next();
	}
}
<commit_msg>minor bug fixed: not detected when no user was found.<commit_after>var db = require("./db");
var util = require("./util");
var srv = require("./server");
var api = require("./api");
var async = require("async");

var constraints = {pre:{}, post:{}};
var plugins = {};
var plugouts = {};

/*
 * Load doc and user from db.
 */
function load_objects(ctx, ret_handler){

	async.series(
		[function(next){//load document

			if(ctx.params && ctx.params.wid){

				db.select(ctx.params.catalog, ctx.params.wid, function(err,doc){

					if(err)
						next(err,null);
					else if(!err && !doc)
						next({code:-1, message:"Document not found: #" + ctx.params.catalog + "/" + ctx.params.wid }, null);
					else{
						ctx.doc = doc;
						next();
					}
				});
			}else
				next();
		},

		function(next){//load user

			if(ctx.params && ctx.params.uid){

				db.criteria("users",{uid:ctx.params.uid},{},function(err,users){

					if(err)
						next(err);
					else if( !err && !users[0]){
						next({code:-1, message:"User not found: #users[uid == " + ctx.params.uid +"]" });
					}else{
						ctx.user = users[0];
						next();
					}
				});
			}else
				next();

		}],function(err){
			ret_handler(err);
		}
	);

}

/*
 * Add a plugin
 */
exports.add_plugin = function(proc_name, plugin_name, func_handler){

	if(!plugins[proc_name])
		plugins[proc_name] = {};

	if(func_handler == undefined && typeof plugin_name == "function"){

		func_handler = plugin_name;
		plugin_name = util.generate_rstring(10);
	}

	plugins[proc_name][plugin_name] = function(ctx, end_handler){

		func_handler(ctx, end_handler);
	}

	return exports;
}

/*
 * Add a plugout
 */
exports.add_plugout = function(proc_name, plugout_name, func_handler){

	if(!plugouts[proc_name])
		plugouts[proc_name] = {};

	if(func_handler == undefined && typeof plugout_name == "function"){

		func_handler = plugout_name;
		plugout_name = util.generate_rstring(10);

		plugouts[proc_name][plugout_name] = function(ctx, end_handler){

			func_handler(ctx, end_handler);
		}
		return exports;
	}
}
/*
 * Add constraint as a pre or post constraint.
 */
function add_constraint( constraints, proc_name, cons_name, func_handler){

	if(!constraints[proc_name])
		constraints[proc_name] = {};

	if(func_handler == undefined && typeof cons_name == "function"){

		func_handler = cons_name;
		cons_name = util.generate_rstring(10);
	}

	constraints[proc_name][cons_name] = function(ctx){

		return func_handler(ctx);

	};

	return exports;

}

/*
 * Plug constraint after the document load.
 */
exports.add_constraint_post =  function( proc_name, cons_name, func_handler ){

	return add_constraint(constraints.post, proc_name, cons_name, func_handler);
}

/*
 * Plug constraint before the document load.
 */
exports.add_constraint_pre =  function( proc_name, cons_name, func_handler ){

	return add_constraint(constraints.pre, proc_name, cons_name, func_handler);
}

/*
 * Execute all constaints for proc_name procedure, if no constraints returns an error object execution continues
 * calling api.remote[proc_name].
 */
exports.execute = function( proc_name, params, ret_handler){

	if( !api.remote[proc_name] ){

		ret_handler({code:-32601, message:"Method not found."},null);
		return;
    }else if(!srv.api.config.procedures[proc_name] ){

    	ret_handler({code:-32604, message:"Method not available."},null);
    	return;
    }else if(!srv.config.app || !srv.config.app.status){

    	ret_handler({code:-32603, message:"Server not started"});
    	return;
    }

    //params may come from another function, in that case params refers to ctx.
	var ctx = (params && params.params && params.config && params.doc)? params: { params:params||{},  config:{save:1, emit:1} };
	ctx.params.catalog = ctx.params.catalog || srv.config.db.default_catalog;

	//Execute plugins to transform ctx some way.
	async.forEachSeries(Object.keys(plugins[proc_name]||{}),function(plugin_name,end_handler){

		plugins[proc_name][plugin_name](ctx, end_handler);

	},function(){//plugins executed

		//constraints pre document load.
	    for( key in constraints.pre[proc_name] ){

			var err = constraints.pre[proc_name][key](ctx);
			if(err){

				ret_handler(err,null);
				return;
			}
		}

		load_objects(ctx, function(err){//document and user load

			ctx.doc = ctx.doc || {};

			if(err){
				ret_handler(err,null);
				return;
			}else{

				//constraints post document load
				for( key in constraints.post[proc_name] ){

					var err = constraints.post[proc_name][key](ctx);
					if(err){

						ret_handler(err,null);
						return;
					}
				}

				//All constraints satisfied and plugins executed, so execute procedure.
				api.remote[proc_name](ctx, function(err,val){

					ctx.retval = util.clone(val);//return value returned over ctx.
					async.series([
					function(next){//execute plugouts: may modify ctx.doc, ctx.retval and ctx.payload
						async.forEachSeries(Object.keys(plugouts[proc_name]||{}),function(plugout_name,end_handler){

							plugouts[proc_name][plugout_name](ctx, end_handler);

						},function(){
							next();
						});
					},
					function(next){
						if(err){
							ret_handler(err,null);
							return;
						}else if(ctx.config.save){

							async.series([

								function(next){
									db.save("users", ctx.user, function(err){

										if(err)
											next(err);
										else
											next();
									});
								},
								function(next){
									db.save(ctx.params.catalog, ctx.doc, function(err){

										if(err)
											next(err);
										else
											next();
									});
								}
							],function(err){
								if(err)
									ret_handler(err,null);
								else{
									if(ctx.config.emit){

										ctx.payload = ctx.payload || ctx.params;

										api.emit("ev_api_" + proc_name, ctx);
									}
									ret_handler(null,ctx);
								}
							});
						}else
							ret_handler(null,ctx);
					}
					]);

				});//end execute

			}

		});
	});

}

exports.constraints = {

	is_owner: function(ctx){

			if( ctx.params.uid != ctx.doc.uid ){

				return {code:-2, message:"No access permission: not owner"};
			}
	},

	has_joined: function(ctx){

		if( !ctx.doc.rcpts || ctx.doc.rcpts.indexOf(ctx.params.uid) == -1 ){

			return {code:-3, message:"No access permission: not joined"};
		}
	},

	not_joined: function(ctx){

		if( ctx.doc.rcpts.indexOf(ctx.params.uid) != -1 ){

			return {code:-4, message:"No access permission: already joined"};
		}
	},

	not_system_catalog: function(ctx){

		if( srv.config.db.system_catalogs.indexOf(ctx.params.catalog) != -1 ){

			return {code:-5, message:"No access permission: system catalog"};
		}
	},

	user_catalog: function(ctx){

		if( srv.config.db.user_catalogs.indexOf(ctx.params.catalog) == -1 ){

			return {code:-6, message:"No access permission: not user catalog"};
		}
	},

	is_joinable: function(ctx){

		if(!ctx.doc.rcpts){

			return {code:-7, message:"No access permission: not joinable/unjoinable"};
		}
	},

	is_reserved: function(ctx){

		if(ctx.params.fname == "rcpts" || ctx.params.fname == "_id" || ctx.params.fname == "uid" || ctx.params.fname == "ctime" || ctx.params.fname == "etime" || ctx.params.fname == "catalog"){

			return {code:-8, message:"Reserved word not allowed as field name: " + ctx.params.fname };
		}
	},

	field_exists: function(ctx){

		if(ctx.params.fname){
			if(!util.get_field(ctx.doc,ctx.params.fname)){

				return {code:-9, message:"Not exists: #" + ctx.params.catalog + "/" + ctx.params.wid + ":" + ctx.params.fname};
			}
		}
	},

	field_type: function(type){

			return function(ctx){

				var obj = util.get_field(ctx.doc,ctx.params.fname);

				if(type == "array"){

					if(typeof obj != "object" || !obj.push || !obj.pop || !obj.shift || !obj.unshift  ){

						return {code:-10, message:"Wrong type: #" + ctx.params.catalog + "/" + ctx.params.wid + ":" + ctx.params.fname + " not array"};
					}
				}else{

					if(typeof obj != type ){

						return {code:-10, message:"Wrong type: #" + ctx.params.catalog + "/" + ctx.params.wid + ":" + ctx.params.fname + " not " + type};
					}
				}
		}
	},

	param_type : function(param_name, type){

			return function(ctx){

				if(typeof ctx.params[param_name] != type ){

					return {code:-11, message:"Wrong parameter type: "+ param_name +" not " + type };
				}
		}
	},

	is_required: function(field){

			return function(ctx){

				if(!ctx.params[field]){

					return {code:-12, message:field  + " parameter required"};
				}
		}
	},

	user_exist: function(ctx){

	}

};

exports.plugins = {

	url_transform : function(ctx,next){

		util.parse_url(ctx);
		next();
	},

	notifying_doc : function(ctx,next){

		if(ctx.params.notifiable == undefined){
			if(ctx.params.catalog == srv.config.db.default_catalog)
				ctx.params.rcpts = [ctx.params.uid];
		}else if(ctx.params.notifiable){
			ctx.params.rcpts = [ctx.params.uid];
		}
		next();
	},

	notifying_catalog:function(catalog){

		return function(ctx,next){

			if(ctx.params.catalog == catalog)
				ctx.params.rcpts = [ctx.params.uid];
			next();
		}
	},

	external_config: function(ctx,next){

		if(ctx.params.config){

			for(key in ctx.params.config){

				ctx.config[key] = ctx.params.config[key];
			}
			delete ctx.params.config;
		}

		next();
	}
}
<|endoftext|>


<commit_before>/**
 * The fake sandbox of browser environment
 */

exports.document = {

  getElementById: function(id) {
    // Return the fake loader script node
    if (id === "seajsnode") {
      return {
        hasAttribute: true,
        getAttribute: function() {},
        src: __filename
      }
    }
  },

  getElementsByTagName: function(tag) {
    // Return the fake head node
    if (tag === "head") {
      return [{
          getElementsByTagName: function() {
            return []
          }
      }]
    }

    return []
  }
}

exports.location = {
  href: __filename,
  search: ""
}

exports.navigator = {
  userAgent: ""
}

exports.console = console

exports.process = process

<commit_msg>Make pageUri equal to process.cwd() in Node.js<commit_after>/**
 * The fake sandbox of browser environment
 */

exports.document = {

  getElementById: function(id) {
    // Return the fake loader script node
    if (id === "seajsnode") {
      return {
        hasAttribute: true,
        getAttribute: function() {},
        src: __filename
      }
    }
  },

  getElementsByTagName: function(tag) {
    // Return the fake head node
    if (tag === "head") {
      return [{
          getElementsByTagName: function() {
            return []
          }
      }]
    }

    return []
  }
}

exports.location = {
  href: process.cwd() + "/index.js",
  search: ""
}

exports.navigator = {
  userAgent: ""
}

exports.console = console

exports.process = process

<|endoftext|>