<commit_before>var fs = require('fs'),
    util = require('util'),
    union = require('union'),
    ecstatic = require('ecstatic'),
	fs = require('fs'),
	path = require('path'),
	qs = require('querystring');
	exec = require('child_process').exec;

var HTTPServer = exports.HTTPServer = function (options) {
  options = options || {};

  if (options.root) {
    this.root = options.root;
  }
  else {
    try {
      fs.lstatSync('./public');
      this.root = './public';
    }
    catch (err) {
      this.root = './';
    }
  }

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

  this.cache = options.cache || 3600; // in seconds.
  this.autoIndex = options.autoIndex !== false;

  if (options.ext) {
    this.ext = options.ext === true
      ? 'html'
      : options.ext;
  }

  this.server = union.createServer({
    before: (options.before || []).concat([
	  function (req, res) {
		/* REV EDIT */
		console.log( "url: "+ req['url'] +"\n");
		if( req['url'].match(/\.cgi/) !== null ) {
			process.cgi_res = res;
			var old_dir = process.cwd();
			var dir = req['url'].match(/(cgi|cgi-bin|scripts)\/[\w|-]+\.cgi/);
		    var script;
			dir = ( dir !== null )? './'+ dir[1] + '/' : './';
			if( fs.existsSync(dir) ) {
				script = path.resolve( dir, req['url'].match(/[\w|-]+\.cgi/)[0] );
				console.log( dir +"exists ? "+ fs.existsSync(dir) );
				process.chdir(dir);
			} else {
				old_dir = '.';
				script = path.resolve( dir, req['url'].match(/[\w|-]+\.cgi/)[0] );
			}
			console.log( "Current dir: "+ process.cwd() );
			console.log( script );
			var q = '', body = '';
			if (req.method == 'POST') {

				req.on('data', function (data) {
					//console.log(data);
					body += data;
				});

				req.on('end', function () {
					q = qs.parse(body);
					//q = body;
					process.env['QUERY_STRING'] = q;
					for( var qparts in q ) {
						if( (qparts.match(/multipart\/form-data/) !== null) ||
							(q[qparts].toString().match(/multipart\/form-data/) !== null) ){
							process.cgi_res.writeHead(200, {
								'Content-Length': stdout.length,
								'Content-Type': "text/html"
							});
							console.log( "multipart/form-data is NOT supported" );
							process.cgi_res.end( "multipart/form-data is NOT supported" );
							return false;
						}
						script += " "+ qparts +"="+ q[qparts];
					}
				//console.log(script +"\n");
				var prc = exec( 'perl -T '+ script,
					function( err, stdout, stderr ) {
						console.log(stdout);
						if(stdout) {
							var rgx = /[C|c]ontent-[T|t]ype\:\s([\w|\+|-|\/]+).*[\n|\r|\f]+/;
							var content_type = stdout.match( rgx );
							if( content_type !== null ) {
								content_type = content_type[1];
								stdout = stdout.replace( rgx, '' );
								stdout = stdout.replace(
									/[S|s]tatus\:.*[\n|\r|\f]+/,
									''
								);
							} else content_type = 'text/plain';
							process.cgi_res.writeHead(200, {
								'Content-Length': stdout.length,
								'Content-Type': content_type
							});
							process.cgi_res.end( stdout );
						}
						if(stderr) {
							console.log( "CGI warnings...\n"+ stderr);
							process.cgi_res.end( stderr );
						}
						if( err !== null ) {
							console.log( "CGI errors...\n"+ err );
							process.cgi_res.end( err );
						}
					}
				);
				});
			} else {
				q = req['url'].match(/[\w|-]+\.cgi\?(.+)/);
				process.env['QUERY_STRING'] = (q !== null) ? q[1] : '';
				q = (q !== null) ? q[1].split("&") : [];

				var query = {};
				for(var i=0, z=q.length; i<z; i++) {
					var qkeys = q[i].split("=")[0];
					var qvalues = q[i].split("=")[1];
					query[qkeys] = qvalues;
					script += " "+ q[i];
				}
				console.log(script +"\n");
				var prc = exec( 'perl -T '+ script,
					function( err, stdout, stderr ) {
						console.log(stdout);
						if(stdout) {
							var rgx = /[C|c]ontent-[T|t]ype\:\s([\w|\+|-|\/]+).*[\n|\r|\f]+/;
							var content_type = stdout.match( rgx );
							if( content_type !== null ) {
								content_type = content_type[1];
								stdout = stdout.replace( rgx, '' );
								stdout = stdout.replace(
									/[S|s]tatus\:.*[\n|\r|\f]+/,
									''
								);
							} else content_type = 'text/plain';
							process.cgi_res.writeHead(200, {
								'Content-Length': stdout.length,
								'Content-Type': content_type
							});
							process.cgi_res.end( stdout );
						}
						if(stderr) {
							console.log( "CGI warnings...\n"+ stderr);
							process.cgi_res.end( stderr );
						}
						if( err !== null ) {
							console.log( "CGI errors...\n"+ err );
							process.cgi_res.end( err );
						}
					}
				);
			}
			process.chdir(old_dir);
		} else res.emit('next');
		/* END EDIT */
	  },
      ecstatic(this.root, {
        autoIndex: this.autoIndex,
        cache: this.cache,
        defaultExt: this.ext
      })
    ]),
    headers: this.headers || {}
  });
};

HTTPServer.prototype.listen = function () {
  this.server.listen.apply(this.server, arguments);
};

HTTPServer.prototype.close = function () {
  return this.server.close();
};

exports.createServer = function (options) {
  return new HTTPServer(options);
};
<commit_msg>fix POST params<commit_after>var fs = require('fs'),
    util = require('util'),
    union = require('union'),
    ecstatic = require('ecstatic'),
	fs = require('fs'),
	path = require('path'),
	qs = require('querystring');
	exec = require('child_process').exec;

var HTTPServer = exports.HTTPServer = function (options) {
  options = options || {};

  if (options.root) {
    this.root = options.root;
  }
  else {
    try {
      fs.lstatSync('./public');
      this.root = './public';
    }
    catch (err) {
      this.root = './';
    }
  }

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

  this.cache = options.cache || 3600; // in seconds.
  this.autoIndex = options.autoIndex !== false;

  if (options.ext) {
    this.ext = options.ext === true
      ? 'html'
      : options.ext;
  }

  this.server = union.createServer({
    before: (options.before || []).concat([
	  function (req, res) {
		/* REV EDIT */
		console.log( "url: "+ req['url'] +"\n");
		if( req['url'].match(/\.cgi/) !== null ) {
			process.cgi_res = res;
			var old_dir = process.cwd();
			var dir = req['url'].match(/(cgi|cgi-bin|scripts)\/[\w|-]+\.cgi/);
		    var script;
			dir = ( dir !== null )? './'+ dir[1] + '/' : './';
			if( fs.existsSync(dir) ) {
				script = path.resolve( dir, req['url'].match(/[\w|-]+\.cgi/)[0] );
				console.log( dir +"exists ? "+ fs.existsSync(dir) );
				process.chdir(dir);
			} else {
				old_dir = '.';
				script = path.resolve( dir, req['url'].match(/[\w|-]+\.cgi/)[0] );
			}
			console.log( "Current dir: "+ process.cwd() );
			console.log( script );
			console.log( req.method );
			var q = '', body = '';
			if (req.method == 'POST') {

				req.on('data', function (data) {
					//console.log(data);
					body += data;
				});

				req.on('end', function () {
					var script_args = '';
					q = qs.parse(body);
					//q = body;
					process.env['QUERY_STRING'] = q;
					for( var qparts in q ) {
						if( (qparts.match(/multipart\/form-data/) !== null) ||
							(q[qparts].toString().match(/multipart\/form-data/) !== null) ){
							process.cgi_res.writeHead(200, {
								'Content-Length': stdout.length,
								'Content-Type': "text/html"
							});
							console.log( "multipart/form-data is NOT supported" );
							process.cgi_res.end( "multipart/form-data is NOT supported" );
							return false;
						}
						script_args += ' '+ qparts +"="+ ( (!q[qparts]) ? "_" : q[qparts] );
					}
					script_args = script_args.replace( /"/g, '"\\\"' );
					script = 'perl -T '+ script +' '+ script_args;
					console.log(script +"\n");

					var prc = exec( script,
						function( err, stdout, stderr ) {
							console.log(stdout);
							if(stdout) {
								var rgx = /[C|c]ontent-[T|t]ype\:\s([\w|\+|-|\/]+).*[\n|\r|\f]+/;
								var content_type = stdout.match( rgx );
								if( content_type !== null ) {
									content_type = content_type[1];
									stdout = stdout.replace( rgx, '' );
									stdout = stdout.replace(
										/[S|s]tatus\:.*[\n|\r|\f]+/,
										''
									);
								} else content_type = 'text/plain';
								process.cgi_res.writeHead(200, {
									'Content-Length': stdout.length,
									'Content-Type': content_type
								});
								process.cgi_res.end( stdout );
							}
							if(stderr) {
								console.log( "CGI warnings...\n"+ stderr);
								process.cgi_res.end( stderr );
							}
							if( err !== null ) {
								console.log( "CGI errors...\n"+ err );
								process.cgi_res.end( err );
							}
						}
					);
				} );

			} else {
				q = req['url'].match(/[\w|-]+\.cgi\?(.+)/);
				process.env['QUERY_STRING'] = (q !== null) ? q[1] : '';
				q = (q !== null) ? q[1].split("&") : [];

				var query = {};
				for(var i=0, z=q.length; i<z; i++) {
					var qkeys = q[i].split("=")[0];
					var qvalues = q[i].split("=")[1];
					query[qkeys] = qvalues;
					script += " "+ q[i];
					script = 'perl -T '+ script;
				}
				console.log(script +"\n");
				var prc = exec( script,
					function( err, stdout, stderr ) {
						console.log(stdout);
						if(stdout) {
							var rgx = /[C|c]ontent-[T|t]ype\:\s([\w|\+|-|\/]+).*[\n|\r|\f]+/;
							var content_type = stdout.match( rgx );
							if( content_type !== null ) {
								content_type = content_type[1];
								stdout = stdout.replace( rgx, '' );
								stdout = stdout.replace(
									/[S|s]tatus\:.*[\n|\r|\f]+/,
									''
								);
							} else content_type = 'text/plain';
							process.cgi_res.writeHead(200, {
								'Content-Length': stdout.length,
								'Content-Type': content_type
							});
							process.cgi_res.end( stdout );
						}
						if(stderr) {
							console.log( "CGI warnings...\n"+ stderr);
							process.cgi_res.end( stderr );
						}
						if( err !== null ) {
							console.log( "CGI errors...\n"+ err );
							process.cgi_res.end( err );
						}
					}
				);
			}
			process.chdir(old_dir);
		} else res.emit('next');
		/* END EDIT */
	  },
      ecstatic(this.root, {
        autoIndex: this.autoIndex,
        cache: this.cache,
        defaultExt: this.ext
      })
    ]),
    headers: this.headers || {}
  });
};

HTTPServer.prototype.listen = function () {
  this.server.listen.apply(this.server, arguments);
};

HTTPServer.prototype.close = function () {
  return this.server.close();
};

exports.createServer = function (options) {
  return new HTTPServer(options);
};
<|endoftext|>


<commit_before>var net = require('net');
var tls = require('tls');
var url = require('url');
var path = require('path');
var EventEmitter = require('events').EventEmitter;
var util = require('../util');
var rules = require('../rules');
var serverAgent = require('./util').serverAgent;
var LOCALHOST = '127.0.0.1';
var ports = {};
var config, app;

function getFullUrl(socket, wss) {
	return (wss ? 'wss:' : 'ws:') + '//' + socket.headers.host + socket.url;
}

function getRequestEmitter(socket, wss) {
	var reqEmitter = new EventEmitter();
	reqEmitter.url = getFullUrl(socket, wss);
	reqEmitter.ip = socket.remoteAddress;
	reqEmitter.method = socket.method;
	reqEmitter.headers = socket.headers;
	reqEmitter.httpVersion = socket.httpVersion;
	socket.fullUrl = getFullUrl(socket, wss);
	reqEmitter.rules = rules.resolveRules(socket.fullUrl);
	reqEmitter.hide = reqEmitter.rules.filter && reqEmitter.rules.filter.hide;
	return reqEmitter;
}

function handleWebsocket(socket, wss, callback) {
	var reqEmitter = app.reqEmitter;
	var headers = socket.headers;
	var host = headers.host;
	var fullUrl = socket.fullUrl;
	var options = url.parse(fullUrl);
	var _rules = reqEmitter.rules;
	var proxyUrl = util.rule.getMatcher(_rules.proxy);
	var reqSocket, options, matchedUrl;
	var now = Date.now();
	var timeout, done;
	var mustRemoteHost = reqEmitter.rules.filter && reqEmitter.rules.filter.host;

	function destroy(err) {
		clearTimeout(timeout);
		socket.destroy();
		reqSocket && reqSocket.destroy();
		util.emitError(reqEmitter, err || new Error('aborted'));
	}

	function abortIfUnavailable(socket) {
		return socket.on('error', destroy)
			.on('close', destroy);
	}

	function execCallback(err, socket) {
		if (done) {
			return;
		}
		done = true;
		err && util.emitError(reqEmitter, err);
		callback(err, socket);
	}

	timeout = util.setTimeout(function() {
		destroy(new Error('timeout'));
	});

	if (proxyUrl) {
		var isSocks = /^socks:\/\//.test(proxyUrl);
		proxyUrl = (wss ? 'wss:' : 'ws:') + util.removeProtocol(proxyUrl);
		rules.resolveHost(proxyUrl, function(err, ip, customHost) {
			reqEmitter.customHost = customHost;
			if (err) {
				return execCallback(err);
			}

			options = url.parse(proxyUrl);
			reqEmitter.host = ip;
			reqEmitter.dnsTime = Date.now() - now;
			reqEmitter.emit('send');
			if (util.isLocalAddress(ip) && (!options.port || options.port == config.port)) {
				return execCallback(new Error('Unable to agent to itself (' + ip + ':' + config.port + ')'));
			}
			util.connect({
				isSocks: isSocks,
				host: ip,
				port: options.port,
				isHttps: wss,
				url: fullUrl,
				auth: options.auth,
				headers: {
					host: headers.host,
					'proxy-connection': 'keep-alive',
					'user-agent': headers['user-agent']
				}
			}, function(err, proxySocket) {
				if (err) {
					return execCallback(err);
				}

				reqSocket = proxySocket;
				abortIfUnavailable(reqSocket);
				pipeData();
			});

		}, mustRemoteHost);
	} else {
		matchedUrl = util.rule.getUrl(_rules.rule);
		if (/^wss?:\/\//.test(matchedUrl)) {
			reqEmitter.realUrl = fullUrl = matchedUrl;
		} else {
			matchedUrl = null;
		}

		options = url.parse(fullUrl);

		rules.resolveHost(fullUrl, function(err, ip, customHost) {
			reqEmitter.customHost = customHost;
			if (err) {
				return execCallback(err);
			}
			reqEmitter.host = ip;
			reqEmitter.dnsTime = Date.now() - now;
			reqEmitter.emit('send');

			var isWss = options.protocol == 'wss';
			reqSocket = (isWss ? tls : net).connect({
				rejectUnauthorized: false,
				host: ip,
				port: options.port || (isWss ? 443 : 80)
			}, pipeData);
			abortIfUnavailable(reqSocket);
		}, mustRemoteHost);
	}

	function pipeData() {
		clearTimeout(timeout);
		var headers = socket.headers;
		var origin;
		if (matchedUrl) {
			headers.host = options.host;
			origin = headers.origin;
			headers.origin = (options.protocol == 'wss' ? 'https://' : 'http://') + options.host;
		}

		reqSocket.write(socket.getBuffer(matchedUrl ? headers : null));
		socket.pipe(reqSocket);
		util.parseReq(reqSocket, function(err, res) {
			if (err) {
				return execCallback(err);
			}

			headers = res.headers;
			if (matchedUrl) {
				headers['access-control-allow-origin'] = origin;
			}
			socket.write(res.getBuffer(matchedUrl ? headers : null));
			res.pipe(socket);
			reqEmitter.emit('response', {
				headers: headers,
				realUrl: matchedUrl,
				statusCode: res.statusCode
			});
			execCallback(null, reqSocket);
		}, true);
	}
}

function handleTlsSocket(socket) {
	var reqSocket;
	function destroy() {
		socket.destroy();
		reqSocket && reqSocket.destroy();
	}

	function abortIfUnavailable(socket) {
		return socket.on('error', destroy)
			.on('close', destroy);
	}

	abortIfUnavailable(socket);
	util.parseReq(socket, function(err, socket) {
		if (err) {
			return destroy();
		}
		//wss
		var clientIp = ports[socket.remotePort];
		var headers = socket.headers;
		if (headers.upgrade && headers.upgrade.toLowerCase() == 'websocket') {
			var reqEmitter = getRequestEmitter(socket, true);
			reqEmitter.ip = clientIp;
			!reqEmitter.hide && app.emit('websocket', reqEmitter);
			app.reqEmitter = reqEmitter;
			handleWebsocket(socket, true, function(err, req) {
				if (err) {
					return destroy();
				}
				reqSocket = req;
				abortIfUnavailable(reqSocket);
			});
		} else {
			//https
			reqSocket = net.connect(config.port, LOCALHOST, function() {
				headers[util.HTTPS_FIELD] = 1;
				headers[util.CLIENT_IP_HEAD] = clientIp;
				reqSocket.write(socket.getBuffer(headers));
				socket.pipe(reqSocket).pipe(socket);
	        });
			abortIfUnavailable(reqSocket);
		}
	}, true);

}

module.exports = function dispatch(socket, hostname, _app) {
	app = _app;
	config = app.config;

	var reqSocket, buffer;
	function destroy() {
		socket.destroy();
		reqSocket && reqSocket.destroy();
	}

	function abortIfUnavailable(socket) {
		return socket.on('error', destroy)
			.on('close', destroy);
	}

	abortIfUnavailable(socket);
	socket.on('data', request);
	socket.on('end', request);

	function request(chunk) {
		socket.removeListener('data', request);
		socket.removeListener('end', request);
		if (!chunk) {//没有数据
			return destroy();
		}

		buffer = buffer ? Buffer.concat([buffer, chunk]) : chunk;
		if (/upgrade\s*:\s*websocket/i.test(buffer && buffer.toString())) { //ws
			util.parseReq(socket, function(err, socket) {
				if (err) {
					return destroy();
				}
				var reqEmitter = getRequestEmitter(socket);
				!reqEmitter.hide && app.emit('websocket', reqEmitter);
				app.reqEmitter = reqEmitter;
				handleWebsocket(socket, false, function(err, req) {
					if (err) {
						return destroy();
					}
					abortIfUnavailable(reqSocket = req);
				});
			}, buffer, true);
			buffer = null;
		} else {
			serverAgent.createServer(hostname, handleTlsSocket, function(port) {
				reqSocket = net.connect(port, LOCALHOST, function() {
					ports[reqSocket.localPort] = socket.remoteAddress;
					reqSocket.write(buffer);
		            reqSocket.pipe(socket).pipe(reqSocket);
		            buffer = null;
		        });
				abortIfUnavailable(reqSocket);
			});
		}
	}

};

<commit_msg>refine code<commit_after>var net = require('net');
var tls = require('tls');
var url = require('url');
var path = require('path');
var EventEmitter = require('events').EventEmitter;
var util = require('../util');
var rules = require('../rules');
var serverAgent = require('./util').serverAgent;
var LOCALHOST = '127.0.0.1';
var ports = {};
var config, app;

function getFullUrl(socket, wss) {
	return (wss ? 'wss:' : 'ws:') + '//' + socket.headers.host + socket.url;
}

function getRequestEmitter(socket, wss) {
	var reqEmitter = new EventEmitter();
	reqEmitter.url = getFullUrl(socket, wss);
	reqEmitter.ip = socket.remoteAddress;
	reqEmitter.method = socket.method;
	reqEmitter.headers = socket.headers;
	reqEmitter.httpVersion = socket.httpVersion;
	socket.fullUrl = getFullUrl(socket, wss);
	reqEmitter.rules = rules.resolveRules(socket.fullUrl);
	reqEmitter.hide = reqEmitter.rules.filter && reqEmitter.rules.filter.hide;
	return reqEmitter;
}

function handleWebsocket(socket, wss, callback) {
	var reqEmitter = app.reqEmitter;
	var headers = socket.headers;
	var host = headers.host;
	var fullUrl = socket.fullUrl;
	var options = url.parse(fullUrl);
	var _rules = reqEmitter.rules;
	var proxyUrl = util.rule.getMatcher(_rules.proxy);
	var reqSocket, options, matchedUrl;
	var now = Date.now();
	var timeout, done;
	var mustRemoteHost = reqEmitter.rules.filter && reqEmitter.rules.filter.host;

	function destroy(err) {
		clearTimeout(timeout);
		socket.destroy();
		reqSocket && reqSocket.destroy();
		util.emitError(reqEmitter, err || new Error('aborted'));
	}

	function abortIfUnavailable(socket) {
		return socket.on('error', destroy)
			.on('close', destroy);
	}

	function execCallback(err, socket) {
		if (done) {
			return;
		}
		done = true;
		err && util.emitError(reqEmitter, err);
		callback(err, socket);
	}

	timeout = util.setTimeout(function() {
		destroy(new Error('timeout'));
	});

	function resolveHost(url, callback) {
		rules.resolveHost(proxyUrl, function(err, ip, customHost) {
			if (err) {
				return execCallback(err);
			}

			reqEmitter.customHost = customHost;
			reqEmitter.host = ip;
			reqEmitter.dnsTime = Date.now() - now;
			reqEmitter.emit('send');
			callback(ip);
		}, mustRemoteHost);
	}

	if (proxyUrl) {
		var isSocks = /^socks:\/\//.test(proxyUrl);
		proxyUrl = (wss ? 'wss:' : 'ws:') + util.removeProtocol(proxyUrl);
		resolveHost(proxyUrl, function(ip) {
			options = url.parse(proxyUrl);
			if (util.isLocalAddress(ip) && (!options.port || options.port == config.port)) {
				return execCallback(new Error('Unable to agent to itself (' + ip + ':' + config.port + ')'));
			}
			util.connect({
				isSocks: isSocks,
				host: ip,
				port: options.port,
				isHttps: wss,
				url: fullUrl,
				auth: options.auth,
				headers: {
					host: headers.host,
					'proxy-connection': 'keep-alive',
					'user-agent': headers['user-agent']
				}
			}, function(err, proxySocket) {
				if (err) {
					return execCallback(err);
				}

				reqSocket = proxySocket;
				abortIfUnavailable(reqSocket);
				pipeData();
			});
		});
	} else {
		matchedUrl = util.rule.getUrl(_rules.rule);
		if (/^wss?:\/\//.test(matchedUrl)) {
			reqEmitter.realUrl = fullUrl = matchedUrl;
		} else {
			matchedUrl = null;
		}

		options = url.parse(fullUrl);
		resolveHost(fullUrl, function(ip) {
			var isWss = options.protocol == 'wss';
			reqSocket = (isWss ? tls : net).connect({
				rejectUnauthorized: false,
				host: ip,
				port: options.port || (isWss ? 443 : 80)
			}, pipeData);
			abortIfUnavailable(reqSocket);
		});
	}

	function pipeData() {
		clearTimeout(timeout);
		var headers = socket.headers;
		var origin;
		if (matchedUrl) {
			headers.host = options.host;
			origin = headers.origin;
			headers.origin = (options.protocol == 'wss' ? 'https://' : 'http://') + options.host;
		}

		reqSocket.write(socket.getBuffer(matchedUrl ? headers : null));
		socket.pipe(reqSocket);
		util.parseReq(reqSocket, function(err, res) {
			if (err) {
				return execCallback(err);
			}

			headers = res.headers;
			if (matchedUrl) {
				headers['access-control-allow-origin'] = origin;
			}
			socket.write(res.getBuffer(matchedUrl ? headers : null));
			res.pipe(socket);
			reqEmitter.emit('response', {
				headers: headers,
				realUrl: matchedUrl,
				statusCode: res.statusCode
			});
			execCallback(null, reqSocket);
		}, true);
	}
}

function handleTlsSocket(socket) {
	var reqSocket;
	function destroy() {
		socket.destroy();
		reqSocket && reqSocket.destroy();
	}

	function abortIfUnavailable(socket) {
		return socket.on('error', destroy)
			.on('close', destroy);
	}

	abortIfUnavailable(socket);
	util.parseReq(socket, function(err, socket) {
		if (err) {
			return destroy();
		}
		//wss
		var clientIp = ports[socket.remotePort];
		var headers = socket.headers;
		if (headers.upgrade && headers.upgrade.toLowerCase() == 'websocket') {
			var reqEmitter = getRequestEmitter(socket, true);
			reqEmitter.ip = clientIp;
			!reqEmitter.hide && app.emit('websocket', reqEmitter);
			app.reqEmitter = reqEmitter;
			handleWebsocket(socket, true, function(err, req) {
				if (err) {
					return destroy();
				}
				reqSocket = req;
				abortIfUnavailable(reqSocket);
			});
		} else {
			//https
			reqSocket = net.connect(config.port, LOCALHOST, function() {
				headers[util.HTTPS_FIELD] = 1;
				headers[util.CLIENT_IP_HEAD] = clientIp;
				reqSocket.write(socket.getBuffer(headers));
				socket.pipe(reqSocket).pipe(socket);
	        });
			abortIfUnavailable(reqSocket);
		}
	}, true);

}

module.exports = function dispatch(socket, hostname, _app) {
	app = _app;
	config = app.config;

	var reqSocket, buffer;
	function destroy() {
		socket.destroy();
		reqSocket && reqSocket.destroy();
	}

	function abortIfUnavailable(socket) {
		return socket.on('error', destroy)
			.on('close', destroy);
	}

	abortIfUnavailable(socket);
	socket.on('data', request);
	socket.on('end', request);

	function request(chunk) {
		socket.removeListener('data', request);
		socket.removeListener('end', request);
		if (!chunk) {//没有数据
			return destroy();
		}

		buffer = buffer ? Buffer.concat([buffer, chunk]) : chunk;
		if (/upgrade\s*:\s*websocket/i.test(buffer && buffer.toString())) { //ws
			util.parseReq(socket, function(err, socket) {
				if (err) {
					return destroy();
				}
				var reqEmitter = getRequestEmitter(socket);
				!reqEmitter.hide && app.emit('websocket', reqEmitter);
				app.reqEmitter = reqEmitter;
				handleWebsocket(socket, false, function(err, req) {
					if (err) {
						return destroy();
					}
					abortIfUnavailable(reqSocket = req);
				});
			}, buffer, true);
			buffer = null;
		} else {
			serverAgent.createServer(hostname, handleTlsSocket, function(port) {
				reqSocket = net.connect(port, LOCALHOST, function() {
					ports[reqSocket.localPort] = socket.remoteAddress;
					reqSocket.write(buffer);
		            reqSocket.pipe(socket).pipe(reqSocket);
		            buffer = null;
		        });
				abortIfUnavailable(reqSocket);
			});
		}
	}

};

<|endoftext|>


<commit_before>var net = require('net');
var tls = require('tls');
var url = require('url');
var path = require('path');
var EventEmitter = require('events').EventEmitter;
var connect = require('../proxy/connect');
var util = require('../../util');
var rules = require('../rules');
var parseReq = require('../proxy/parse-req');
var cert = require('./cert');
var serverAgent = require('./util').serverAgent;
var DEFAULT_CERT = cert.DEFAULT_CERT;
var LOCALHOST = '127.0.0.1';
var ports = {};
var config, app;

function getFullUrl(socket, wss) {
	return (wss ? 'wss:' : 'ws:') + '//' + socket.headers.host + socket.url;
}

function getRequestEmitter(socket, wss) {
	var reqEmitter = new EventEmitter();
	reqEmitter.url = getFullUrl(socket, wss);
	reqEmitter.ip = socket.remoteAddress;
	reqEmitter.method = socket.method;
	reqEmitter.headers = socket.headers;
	reqEmitter.httpVersion = socket.httpVersion;
	return reqEmitter;
}

function handleWebsocket(socket, wss, callback) {
	var reqEmitter = app.reqEmitter;
	var headers = socket.headers;
	var host = headers.host;
	var fullUrl = socket.fullUrl = getFullUrl(socket, wss);
	var options = url.parse(fullUrl);
	var _rules = reqEmitter.rules = rules.resolveRules(fullUrl);
	var proxyUrl = util.rule.getMatcher(_rules.proxy);
	var reqSocket, options, matchedUrl;
	var now = Date.now();
	var timeout, done;

	function destroy(err) {
		clearTimeout(timeout);
		socket.destroy();
		reqSocket && reqSocket.destroy();
		util.emitError(reqEmitter, err || new Error('aborted'));
	}

	function abortIfUnavailable(socket) {
		return socket.on('error', destroy)
			.on('close', destroy);
	}

	function execCallback(err, socket) {
		if (done) {
			return;
		}
		done = true;
		err && util.emitError(reqEmitter, err);
		callback(err, socket);
	}

	timeout = setTimeout(function() {
		destroy(new Error('timeout'));
	}, config.timeout);

	if (proxyUrl) {
		proxyUrl = (wss ? 'wss:' : 'ws:') + util.removeProtocol(proxyUrl);
		rules.resolveHost(proxyUrl, function(err, ip, customHost) {
			reqEmitter.customHost = customHost;
			if (err || !ip) {
				return execCallback(err || new Error('lookup DNS faild: ' + proxyUrl));
			}

			options = url.parse(proxyUrl);
			socket.options = {
					host: ip,
					port: options.port,
					isWs: !wss
			};
			reqEmitter.host = ip;
			reqEmitter.dnsTime = Date.now() - now;
			reqEmitter.emit('send');
			connect(socket, function(err, proxySocket) {
				if (err) {
					return execCallback(err);
				}

				if (wss) {
					reqSocket = tls.connect({
				        rejectUnauthorized: false,
				        socket: proxySocket
				    }, pipeData);
					abortIfUnavailable(reqSocket);
				} else {
					reqSocket = proxySocket;
					pipeData();
				}

			});

		}, true);
	} else {
		matchedUrl = util.rule.getUrl(_rules.rule);
		if (/^wss?:\/\//.test(matchedUrl)) {
			reqEmitter.realUrl = fullUrl = matchedUrl;
		} else {
			matchedUrl = null;
		}

		options = url.parse(fullUrl);

		rules.resolveHost(fullUrl, function(err, ip, customHost) {
			reqEmitter.customHost = customHost;
			if (err || !ip) {
				return execCallback(err || new Error('lookup DNS faild: ' + fullUrl));
			}
			reqEmitter.host = ip;
			reqEmitter.dnsTime = Date.now() - now;
			reqEmitter.emit('send');

			var isWss = options.protocol == 'wss';
			reqSocket = (isWss ? tls : net).connect({
				rejectUnauthorized: false,
				host: ip,
				port: options.port || (isWss ? 443 : 80)
			}, pipeData);
			abortIfUnavailable(reqSocket);
		}, true);
	}

	function pipeData() {
		clearTimeout(timeout);
		var headers = socket.headers;
		var origin;
		if (matchedUrl) {
			headers.host = options.host;
			origin = headers.origin;
			headers.origin = (options.protocol == 'wss' ? 'https://' : 'http://') + options.host;
		}

		reqSocket.write(socket.getBuffer(matchedUrl ? headers : null));
		socket.pipe(reqSocket);
		parseReq(reqSocket, function(err, res) {
			if (err) {
				return execCallback(err);
			}

			headers = res.headers;
			if (matchedUrl) {
				headers['access-control-allow-origin'] = origin;
			}
			socket.write(res.getBuffer(matchedUrl ? headers : null));
			res.pipe(socket);
			reqEmitter.emit('response', {
				headers: headers,
				realUrl: matchedUrl,
				statusCode: res.statusCode
			});
			execCallback(null, reqSocket);
		}, true);
	}
}

function handleTlsSocket(socket) {
	var reqSocket;
	function destroy() {
		socket.destroy();
		reqSocket && reqSocket.destroy();
	}

	function abortIfUnavailable(socket) {
		return socket.on('error', destroy)
			.on('close', destroy);
	}

	abortIfUnavailable(socket);
	parseReq(socket, function(err, socket) {
		if (err) {
			return destroy();
		}
		//wss
		var clientIp = ports[socket.remotePort];
		var headers = socket.headers;
		if (headers.upgrade && headers.upgrade.toLowerCase() == 'websocket') {
			var reqEmitter = getRequestEmitter(socket, true);
			reqEmitter.ip = clientIp;
			app.emit('websocket', reqEmitter);
			app.reqEmitter = reqEmitter;
			handleWebsocket(socket, true, function(err, req) {
				if (err) {
					return destroy();
				}
				reqSocket = req;
				abortIfUnavailable(reqSocket);
			});
		} else {
			//https
			reqSocket = net.connect(config.port, LOCALHOST, function() {
				headers[util.HTTPS_FIELD] = 1;
				headers[util.CLIENT_IP_HEAD] = clientIp;
				reqSocket.write(socket.getBuffer(headers));
				socket.pipe(reqSocket).pipe(socket);
	        });
			abortIfUnavailable(reqSocket);
		}
	}, true);

}

module.exports = function dispatch(socket, hostname, _app) {
	app = _app;
	config = app.config;

	var reqSocket, buffer;
	function destroy() {
		socket.destroy();
		reqSocket && reqSocket.destroy();
	}

	function abortIfUnavailable(socket) {
		return socket.on('error', destroy)
			.on('close', destroy);
	}

	abortIfUnavailable(socket);
	socket.on('data', request);
	socket.on('end', request);

	function request(chunk) {
		socket.removeListener('data', request);
		socket.removeListener('end', request);
		if (!chunk) {//没有数据
			return destroy();
		}

		buffer = buffer ? Buffer.concat([buffer, chunk]) : chunk;
		if (/upgrade\s*:\s*websocket/i.test(buffer && buffer.toString())) { //ws
			parseReq(socket, function(err, socket) {
				if (err) {
					return destroy();
				}
				var reqEmitter = getRequestEmitter(socket);
				app.emit('websocket', reqEmitter);
				app.reqEmitter = reqEmitter;
				handleWebsocket(socket, false, function(err, req) {
					if (err) {
						return destroy();
					}
					abortIfUnavailable(reqSocket = req);
				});
			}, buffer, true);
			buffer = null;
		} else {
			cert.createCert(hostname, function(err) {
				serverAgent.createServer(hostname, handleTlsSocket, function(port) {
					reqSocket = net.connect(port, LOCALHOST, function() {
						ports[reqSocket.localPort] = socket.remoteAddress;
						reqSocket.write(buffer);
			            reqSocket.pipe(socket).pipe(reqSocket);
			            buffer = null;
			        });
					abortIfUnavailable(reqSocket);
				});
			});
		}
	}

};

<commit_msg>can not proxy to self<commit_after>var net = require('net');
var tls = require('tls');
var url = require('url');
var path = require('path');
var EventEmitter = require('events').EventEmitter;
var connect = require('../proxy/connect');
var util = require('../../util');
var rules = require('../rules');
var parseReq = require('../proxy/parse-req');
var cert = require('./cert');
var serverAgent = require('./util').serverAgent;
var DEFAULT_CERT = cert.DEFAULT_CERT;
var LOCALHOST = '127.0.0.1';
var ports = {};
var config, app;

function getFullUrl(socket, wss) {
	return (wss ? 'wss:' : 'ws:') + '//' + socket.headers.host + socket.url;
}

function getRequestEmitter(socket, wss) {
	var reqEmitter = new EventEmitter();
	reqEmitter.url = getFullUrl(socket, wss);
	reqEmitter.ip = socket.remoteAddress;
	reqEmitter.method = socket.method;
	reqEmitter.headers = socket.headers;
	reqEmitter.httpVersion = socket.httpVersion;
	return reqEmitter;
}

function handleWebsocket(socket, wss, callback) {
	var reqEmitter = app.reqEmitter;
	var headers = socket.headers;
	var host = headers.host;
	var fullUrl = socket.fullUrl = getFullUrl(socket, wss);
	var options = url.parse(fullUrl);
	var _rules = reqEmitter.rules = rules.resolveRules(fullUrl);
	var proxyUrl = util.rule.getMatcher(_rules.proxy);
	var reqSocket, options, matchedUrl;
	var now = Date.now();
	var timeout, done;

	function destroy(err) {
		clearTimeout(timeout);
		socket.destroy();
		reqSocket && reqSocket.destroy();
		util.emitError(reqEmitter, err || new Error('aborted'));
	}

	function abortIfUnavailable(socket) {
		return socket.on('error', destroy)
			.on('close', destroy);
	}

	function execCallback(err, socket) {
		if (done) {
			return;
		}
		done = true;
		err && util.emitError(reqEmitter, err);
		callback(err, socket);
	}

	timeout = setTimeout(function() {
		destroy(new Error('timeout'));
	}, config.timeout);

	if (proxyUrl) {
		proxyUrl = (wss ? 'wss:' : 'ws:') + util.removeProtocol(proxyUrl);
		rules.resolveHost(proxyUrl, function(err, ip, customHost) {
			reqEmitter.customHost = customHost;
			if (err || !ip) {
				return execCallback(err || new Error('lookup DNS faild: ' + proxyUrl));
			}

			options = url.parse(proxyUrl);
			socket.options = {
					host: ip,
					port: options.port,
					isWs: !wss
			};
			reqEmitter.host = ip;
			reqEmitter.dnsTime = Date.now() - now;
			reqEmitter.emit('send');
			if (util.isLocalAddress(ip) && (!options.port || options.port == config.port)) {
				return execCallback('can not proxy to self. ' + ip + ':' + config.port);
			}
			connect(socket, function(err, proxySocket) {
				if (err) {
					return execCallback(err);
				}

				if (wss) {
					reqSocket = tls.connect({
				        rejectUnauthorized: false,
				        socket: proxySocket
				    }, pipeData);
					abortIfUnavailable(reqSocket);
				} else {
					reqSocket = proxySocket;
					pipeData();
				}

			});

		}, true);
	} else {
		matchedUrl = util.rule.getUrl(_rules.rule);
		if (/^wss?:\/\//.test(matchedUrl)) {
			reqEmitter.realUrl = fullUrl = matchedUrl;
		} else {
			matchedUrl = null;
		}

		options = url.parse(fullUrl);

		rules.resolveHost(fullUrl, function(err, ip, customHost) {
			reqEmitter.customHost = customHost;
			if (err || !ip) {
				return execCallback(err || new Error('lookup DNS faild: ' + fullUrl));
			}
			reqEmitter.host = ip;
			reqEmitter.dnsTime = Date.now() - now;
			reqEmitter.emit('send');

			var isWss = options.protocol == 'wss';
			reqSocket = (isWss ? tls : net).connect({
				rejectUnauthorized: false,
				host: ip,
				port: options.port || (isWss ? 443 : 80)
			}, pipeData);
			abortIfUnavailable(reqSocket);
		}, true);
	}

	function pipeData() {
		clearTimeout(timeout);
		var headers = socket.headers;
		var origin;
		if (matchedUrl) {
			headers.host = options.host;
			origin = headers.origin;
			headers.origin = (options.protocol == 'wss' ? 'https://' : 'http://') + options.host;
		}

		reqSocket.write(socket.getBuffer(matchedUrl ? headers : null));
		socket.pipe(reqSocket);
		parseReq(reqSocket, function(err, res) {
			if (err) {
				return execCallback(err);
			}

			headers = res.headers;
			if (matchedUrl) {
				headers['access-control-allow-origin'] = origin;
			}
			socket.write(res.getBuffer(matchedUrl ? headers : null));
			res.pipe(socket);
			reqEmitter.emit('response', {
				headers: headers,
				realUrl: matchedUrl,
				statusCode: res.statusCode
			});
			execCallback(null, reqSocket);
		}, true);
	}
}

function handleTlsSocket(socket) {
	var reqSocket;
	function destroy() {
		socket.destroy();
		reqSocket && reqSocket.destroy();
	}

	function abortIfUnavailable(socket) {
		return socket.on('error', destroy)
			.on('close', destroy);
	}

	abortIfUnavailable(socket);
	parseReq(socket, function(err, socket) {
		if (err) {
			return destroy();
		}
		//wss
		var clientIp = ports[socket.remotePort];
		var headers = socket.headers;
		if (headers.upgrade && headers.upgrade.toLowerCase() == 'websocket') {
			var reqEmitter = getRequestEmitter(socket, true);
			reqEmitter.ip = clientIp;
			app.emit('websocket', reqEmitter);
			app.reqEmitter = reqEmitter;
			handleWebsocket(socket, true, function(err, req) {
				if (err) {
					return destroy();
				}
				reqSocket = req;
				abortIfUnavailable(reqSocket);
			});
		} else {
			//https
			reqSocket = net.connect(config.port, LOCALHOST, function() {
				headers[util.HTTPS_FIELD] = 1;
				headers[util.CLIENT_IP_HEAD] = clientIp;
				reqSocket.write(socket.getBuffer(headers));
				socket.pipe(reqSocket).pipe(socket);
	        });
			abortIfUnavailable(reqSocket);
		}
	}, true);

}

module.exports = function dispatch(socket, hostname, _app) {
	app = _app;
	config = app.config;

	var reqSocket, buffer;
	function destroy() {
		socket.destroy();
		reqSocket && reqSocket.destroy();
	}

	function abortIfUnavailable(socket) {
		return socket.on('error', destroy)
			.on('close', destroy);
	}

	abortIfUnavailable(socket);
	socket.on('data', request);
	socket.on('end', request);

	function request(chunk) {
		socket.removeListener('data', request);
		socket.removeListener('end', request);
		if (!chunk) {//没有数据
			return destroy();
		}

		buffer = buffer ? Buffer.concat([buffer, chunk]) : chunk;
		if (/upgrade\s*:\s*websocket/i.test(buffer && buffer.toString())) { //ws
			parseReq(socket, function(err, socket) {
				if (err) {
					return destroy();
				}
				var reqEmitter = getRequestEmitter(socket);
				app.emit('websocket', reqEmitter);
				app.reqEmitter = reqEmitter;
				handleWebsocket(socket, false, function(err, req) {
					if (err) {
						return destroy();
					}
					abortIfUnavailable(reqSocket = req);
				});
			}, buffer, true);
			buffer = null;
		} else {
			cert.createCert(hostname, function(err) {
				serverAgent.createServer(hostname, handleTlsSocket, function(port) {
					reqSocket = net.connect(port, LOCALHOST, function() {
						ports[reqSocket.localPort] = socket.remoteAddress;
						reqSocket.write(buffer);
			            reqSocket.pipe(socket).pipe(reqSocket);
			            buffer = null;
			        });
					abortIfUnavailable(reqSocket);
				});
			});
		}
	}

};

<|endoftext|>


<commit_before>"use strict";

/*global nodeca, _*/

// 3rd-party
var Async = require('nlib').Vendor.Async;

////////////////////////////////////////////////////////////////////////////////

// helper that starts http server and waits for it to bind to specified host and
// port (see configuration listen section).
//
function start_server(next) {
  var server, host, port, err_handler;

  try {
    // add support for webkit devtools
    require('webkit-devtools-agent');
    nodeca.logger.info('webkit-devtools-agent enabled');
  } catch (err) {
    // do nothing
    nodeca.logger.warn('webkit-devtools-agent disabled');
  }

  // TODO: start server on all requested points

  // create server
  host    = nodeca.config.router.bind['default'].listen.split(':').shift() || 'localhost';
  port    = nodeca.config.router.bind['default'].listen.split(':').pop() || 3000;
  server  = require('http').createServer();

  err_handler = function (err) {
    var err_prefix = "Can't bind to <" + host + "> with port <" + port + ">: ";

    if ('EADDRINUSE' === err.code) {
      next(err_prefix + 'Address in use...');
      return;
    }

    if ('EADDRNOTAVAIL' === err.code) {
      // system has no such ip address
      next(err_prefix + 'Address is not available...');
      return;
    }

    if ('ENOENT' === err.code) {
      // failed resolve hostname to ip address
      next(err_prefix + "Failed to resolve IP address...");
      return;
    }

    // unexpected / unknown error
    next(err_prefix + err);
  };

  server.on('error', err_handler);

  // start server
  server.listen(port, host, function () {
    server.removeListener('error', err_handler);
    next(null, server);
  });
}

// MODULE EXPORTS //////////////////////////////////////////////////////////////

// starts http server and attach application HTTP server and Faye realtime
// servers to it
//
module.exports = function (next) {
  start_server(function (err, server) {
    if (err) {
      next(err);
      return;
    }

    Async.series([
      function (next) { require('./server/http').attach(server, next); }
    ], next);
  });
};
<commit_msg>Start server init refactoring<commit_after>"use strict";

/*global nodeca, _*/

// stdlib
var createHttpServer = require('http').createServer;

// 3rd-party
var Async = require('nlib').Vendor.Async;

// internal
var listener = require('./server/http');

////////////////////////////////////////////////////////////////////////////////

// helper that starts http server and waits for it to bind to specified host and
// port (see configuration listen section).
//
function startServer(host, port, next) {
  var server = createHttpServer();

  function handle_server_error(err) {
    var err_prefix = "Can't bind to <" + host + "> with port <" + port + ">: ";

    if ('EADDRINUSE' === err.code) {
      next(err_prefix + 'Address in use...');
      return;
    }

    if ('EADDRNOTAVAIL' === err.code) {
      // system has no such ip address
      next(err_prefix + 'Address is not available...');
      return;
    }

    if ('ENOENT' === err.code) {
      // failed resolve hostname to ip address
      next(err_prefix + "Failed to resolve IP address...");
      return;
    }

    // unexpected / unknown error
    next(err_prefix + err);
  }

  server.on('error', handle_server_error);

  // start server
  server.listen(port, host, function () {
    server.removeListener('error', handle_server_error);
    next(null, server);
  });
}

// MODULE EXPORTS //////////////////////////////////////////////////////////////

// starts http server and attach application HTTP server and Faye realtime
// servers to it
//
module.exports = function (next) {
  // create server
  var host = nodeca.config.router.bind['default'].listen.split(':').shift() || 'localhost';
  var port = nodeca.config.router.bind['default'].listen.split(':').pop() || 3000;

  try {
    // add support for webkit devtools
    require('webkit-devtools-agent');
    nodeca.logger.info('webkit-devtools-agent enabled');
  } catch (err) {
    // do nothing
    nodeca.logger.warn('webkit-devtools-agent disabled');
  }

  startServer(host, port, function (err, server) {
    if (err) {
      next(err);
      return;
    }

    listener.attach(server, next);
  });
};
<|endoftext|>


<commit_before>var async  = require('async'),
    crypto = require('crypto'),
    pg     = require('pg'),

    config = require('../config'),

    INVITATIONS       = 'SELECT * FROM invitations ORDER BY id',
    INVITATION_BY_ID  = 'SELECT * FROM invitations WHERE id=$1 LIMIT 1',
    INVITATION_GUESTS = 'SELECT * FROM guests WHERE invitation_id=$1 ORDER BY id',
    UPDATE_INVITATION = 'UPDATE invitations SET $UPDATES WHERE id=$1',

    UPDATE_SCHEMEA = {
        address: true,
        rsvpd  : true
    };

exports.encipherId = encipherId;
exports.decipherId = decipherId;

exports.loadInvitation   = loadInvitation;
exports.loadInvitations  = loadInvitations;
exports.updateInvitation = updateInvitation;

function encipherId(id) {
    var cipher = crypto.createCipher('bf', config.invitationSecret);
    cipher.update(String(id), 'utf8', 'hex');
    return cipher.final('hex');
}

function decipherId(encipheredId) {
    var decipher = crypto.createDecipher('bf', config.invitationSecret);

    // TODO: Remove Buffer once bug is fixed:
    // https://github.com/joyent/node/pull/5725
    decipher.update(new Buffer(encipheredId, 'hex'), 'utf8');

    return decipher.final('utf8');
}

function loadInvitation(id, callback) {
    function processResults(results, callback) {
        var invitation = results.invitation.rows[0];

        if (invitation) {
            invitation.guests = results.guests.rows;
        }

        callback(null, invitation);
    }

    pg.connect(config.database, function (err, db, done) {
        if (err) { return callback(err); }

        async.waterfall([
            async.parallel.bind(null, {
                invitation: db.query.bind(db, INVITATION_BY_ID, [id]),
                guests    : db.query.bind(db, INVITATION_GUESTS, [id])
            }),

            processResults
        ], function () {
            done();
            callback.apply(null, arguments);
        });
    });
}

function loadInvitations(callback) {
    function processInvitation(db, invitation, callback) {
        db.query(INVITATION_GUESTS, [invitation.id], function (err, results) {
            if (err) { return callback(err); }

            invitation.guests = results.rows;
            callback(null, invitation);
        });
    }

    function processInvitations(db, results, callback) {
        async.map(results.rows, processInvitation.bind(null, db), callback);
    }

    pg.connect(config.database, function (err, db, done) {
        if (err) { return callback(err); }

        async.waterfall([
            db.query.bind(db, INVITATIONS),
            processInvitations.bind(null, db)
        ], function () {
            done();
            callback.apply(null, arguments);
        });
    });
}

function updateInvitation(id, changes, callback) {
    var values  = [id],
        updates = [],
        query;

    Object.keys(UPDATE_SCHEMEA).forEach(function (col) {
        if (col in changes) {
            updates.push(col + '=$' + values.push(changes[col]));
        }
    });

    query = UPDATE_INVITATION.replace('$UPDATES', updates.join(', '));

    pg.connect(config.database, function (err, db, done) {
        if (err) { return callback(err); }

        db.query(query, values, function (err, results) {
            done();
            callback(err, results && results.rows[0]);
        });
    });
}
<commit_msg>test emails<commit_after>var async  = require('async'),
    crypto = require('crypto'),
    pg     = require('pg'),

    config = require('../config'),

    INVITATIONS       = 'SELECT * FROM invitations WHERE rsvpd=f ORDER BY id',
    INVITATION_BY_ID  = 'SELECT * FROM invitations WHERE id=$1 LIMIT 1',
    INVITATION_GUESTS = 'SELECT * FROM guests WHERE invitation_id=$1 ORDER BY id',
    UPDATE_INVITATION = 'UPDATE invitations SET $UPDATES WHERE id=$1',

    UPDATE_SCHEMEA = {
        address: true,
        rsvpd  : true
    };

exports.encipherId = encipherId;
exports.decipherId = decipherId;

exports.loadInvitation   = loadInvitation;
exports.loadInvitations  = loadInvitations;
exports.updateInvitation = updateInvitation;

function encipherId(id) {
    var cipher = crypto.createCipher('bf', config.invitationSecret);
    cipher.update(String(id), 'utf8', 'hex');
    return cipher.final('hex');
}

function decipherId(encipheredId) {
    var decipher = crypto.createDecipher('bf', config.invitationSecret);

    // TODO: Remove Buffer once bug is fixed:
    // https://github.com/joyent/node/pull/5725
    decipher.update(new Buffer(encipheredId, 'hex'), 'utf8');

    return decipher.final('utf8');
}

function loadInvitation(id, callback) {
    function processResults(results, callback) {
        var invitation = results.invitation.rows[0];

        if (invitation) {
            invitation.guests = results.guests.rows;
        }

        callback(null, invitation);
    }

    pg.connect(config.database, function (err, db, done) {
        if (err) { return callback(err); }

        async.waterfall([
            async.parallel.bind(null, {
                invitation: db.query.bind(db, INVITATION_BY_ID, [id]),
                guests    : db.query.bind(db, INVITATION_GUESTS, [id])
            }),

            processResults
        ], function () {
            done();
            callback.apply(null, arguments);
        });
    });
}

function loadInvitations(callback) {
    function processInvitation(db, invitation, callback) {
        db.query(INVITATION_GUESTS, [invitation.id], function (err, results) {
            if (err) { return callback(err); }

            invitation.guests = results.rows;
            callback(null, invitation);
        });
    }

    function processInvitations(db, results, callback) {
        async.map(results.rows, processInvitation.bind(null, db), callback);
    }

    pg.connect(config.database, function (err, db, done) {
        if (err) { return callback(err); }

        async.waterfall([
            db.query.bind(db, INVITATIONS),
            processInvitations.bind(null, db)
        ], function () {
            done();
            callback.apply(null, arguments);
        });
    });
}

function updateInvitation(id, changes, callback) {
    var values  = [id],
        updates = [],
        query;

    Object.keys(UPDATE_SCHEMEA).forEach(function (col) {
        if (col in changes) {
            updates.push(col + '=$' + values.push(changes[col]));
        }
    });

    query = UPDATE_INVITATION.replace('$UPDATES', updates.join(', '));

    pg.connect(config.database, function (err, db, done) {
        if (err) { return callback(err); }

        db.query(query, values, function (err, results) {
            done();
            callback(err, results && results.rows[0]);
        });
    });
}
<|endoftext|>


<commit_before>var path = require('path');
var Promise = require('bluebird');
var fs = Promise.promisifyAll(require('fs'));

var FileListener = require('./file-listener');
var JobProcessor = require('./processor');
var serviceLocator = require('../service-locator');
var JobHandlerRegistry = require('./handler-registry');
Promise.config({cancellation: true});

/**
 * @param {String} jobDirectory, an Absolute one!
 * @param {String} tempFilesDir, an Absolute one!
 * @param {Array} [handlers]
 * @constructor
 */
function JobManager(jobDirectory, tempFilesDir, handlers) {
  if (!fs.statSync(jobDirectory).isDirectory()) {
    throw new Error('`jobDirectory` must be a directory');
  }
  this.handlerRegistry = new JobHandlerRegistry();
  if (handlers) {
    handlers.forEach(function(handler) {
      this.handlerRegistry.register(handler);
    }.bind(this));
  }
  this._processor = new JobProcessor(tempFilesDir);

  this._fileListener = new FileListener(jobDirectory);
  this._fileListener.on('file', function(file) {
    this._processJobFile(file);
  }.bind(this));
}

JobManager.prototype.start = function() {
  this._processor.start();
  this._fileListener.start();
};

/**
 * @return {Promise}
 */
JobManager.prototype.stop = function() {
  return Promise.all([this._fileListener.stop(), this._processor.stop()]);
};

/**
 * @param {String} filePath
 * @returns {Promise}
 */
JobManager.prototype._processJobFile = function(filePath) {
  var self = this;
  return self._readJobFile(filePath)
    .then(function(jobDescription) {
      var jobId = path.basename(filePath, '.json');
      var handler = self.handlerRegistry.get(jobDescription['plugin'], jobDescription['event']);
      var job = handler.instantiateJob(jobId, jobDescription['data']);
      return self._processor.processUntilSuccessful(job);
    })
    .then(function() {
      serviceLocator.get('logger').info('Removing ' + filePath);
      return fs.unlinkAsync(filePath);
    })
    .catch(function(error) {
      var logMessage = error.stack || error.message || error;
      serviceLocator.get('logger').error(logMessage);
    });
};

/**
 * @param {String} filePath
 * @returns {Promise}
 */
JobManager.prototype._readJobFile = function(filePath) {
  return fs.readFileAsync(filePath)
    .then(function(content) {
      return Promise.try(function() {
        return JSON.parse(content);
      });
    })
    .catch(function(error) {
      throw new Error('Invalid job file: ' + error.message)
    });
};

module.exports = JobManager;
<commit_msg>Return promise on JobManager.start()<commit_after>var path = require('path');
var Promise = require('bluebird');
var fs = Promise.promisifyAll(require('fs'));

var FileListener = require('./file-listener');
var JobProcessor = require('./processor');
var serviceLocator = require('../service-locator');
var JobHandlerRegistry = require('./handler-registry');
Promise.config({cancellation: true});

/**
 * @param {String} jobDirectory, an Absolute one!
 * @param {String} tempFilesDir, an Absolute one!
 * @param {Array} [handlers]
 * @constructor
 */
function JobManager(jobDirectory, tempFilesDir, handlers) {
  if (!fs.statSync(jobDirectory).isDirectory()) {
    throw new Error('`jobDirectory` must be a directory');
  }
  this.handlerRegistry = new JobHandlerRegistry();
  if (handlers) {
    handlers.forEach(function(handler) {
      this.handlerRegistry.register(handler);
    }.bind(this));
  }
  this._processor = new JobProcessor(tempFilesDir);

  this._fileListener = new FileListener(jobDirectory);
  this._fileListener.on('file', function(file) {
    this._processJobFile(file);
  }.bind(this));
}

/**
 * @returns {Promise}
 */
JobManager.prototype.start = function() {
  this._processor.start();
  this._fileListener.start();
  return Promise.resolve();
};

/**
 * @return {Promise}
 */
JobManager.prototype.stop = function() {
  return Promise.all([this._fileListener.stop(), this._processor.stop()]);
};

/**
 * @param {String} filePath
 * @returns {Promise}
 */
JobManager.prototype._processJobFile = function(filePath) {
  var self = this;
  return self._readJobFile(filePath)
    .then(function(jobDescription) {
      var jobId = path.basename(filePath, '.json');
      var handler = self.handlerRegistry.get(jobDescription['plugin'], jobDescription['event']);
      var job = handler.instantiateJob(jobId, jobDescription['data']);
      return self._processor.processUntilSuccessful(job);
    })
    .then(function() {
      serviceLocator.get('logger').info('Removing ' + filePath);
      return fs.unlinkAsync(filePath);
    })
    .catch(function(error) {
      var logMessage = error.stack || error.message || error;
      serviceLocator.get('logger').error(logMessage);
    });
};

/**
 * @param {String} filePath
 * @returns {Promise}
 */
JobManager.prototype._readJobFile = function(filePath) {
  return fs.readFileAsync(filePath)
    .then(function(content) {
      return Promise.try(function() {
        return JSON.parse(content);
      });
    })
    .catch(function(error) {
      throw new Error('Invalid job file: ' + error.message)
    });
};

module.exports = JobManager;
<|endoftext|>


<commit_before>'use strict';

const squad = require('squad/legacy');
const currify = require('currify/legacy');

const parenthesize = require('./parenthesize');
const tokenize = require('./tokenize');
const bracketsCheck = require('./brackets-check');
const check = require('../check');

const checkExpression = currify(check, 'string', 'expression');

module.exports = squad(
    parenthesize,
    bracketsCheck,
    tokenize,
    checkExpression,
);

<commit_msg>fix(lexer) rm column<commit_after>'use strict';

const squad = require('squad/legacy');
const currify = require('currify/legacy');

const parenthesize = require('./parenthesize');
const tokenize = require('./tokenize');
const bracketsCheck = require('./brackets-check');
const check = require('../check');

const checkExpression = currify(check, 'string', 'expression');

module.exports = squad(
    parenthesize,
    bracketsCheck,
    tokenize,
    checkExpression
);

<|endoftext|>


<commit_before>
module.exports.float_length = 16

module.exports.float_length = 16

module.exports.float_length = 16

module.exports.float_length = 16
<commit_msg>Removed old dir<commit_after><|endoftext|>


<commit_before>var path = require('path');
var url = require('url');
var messages = require('./messages');
var ports = {};

var getSnippet = function (hostIp, socketIoPort, scriptPort) {
    return messages.scriptTags(hostIp, socketIoPort, scriptPort, false);
};

module.exports.setVars = function (hostIp, socketIoPort, scriptPort) {
    ports.hostIp = hostIp;
    ports.socketIoPort = socketIoPort;
    ports.scriptPort = scriptPort;
};

module.exports.middleWare = function (req, res, next) {

    var write = res.write;

    var filepath = url.parse(req.url).pathname;
    filepath = filepath.slice(-1) === '/' ? filepath + 'index.html' : filepath;

    // Exit if the path is not for an html file.
    if (path.extname(filepath) !== '.html') {
        return next();
    }

    res.write = function (string, encoding) {
        var body = string instanceof Buffer ? string.toString() : string;

        body = body.replace(/<\/body>/, function (w) {
            return getSnippet(ports.hostIp, ports.socketIoPort, ports.scriptPort) + w;
        });

        if (string instanceof Buffer) {
            string = new Buffer(body);
        } else {
            string = body;
        }

        // Remove content-length to allow snippets to inserted to any body length
        if (!this.headerSent) {
            delete this._headers['content-length'];
            this._implicitHeader();
        }

        write.call(res, string, encoding);
    };

    next();
};<commit_msg>Add hasOwnProperty check before trying to delete<commit_after>var path = require('path');
var url = require('url');
var messages = require('./messages');
var ports = {};

var getSnippet = function (hostIp, socketIoPort, scriptPort) {
    return messages.scriptTags(hostIp, socketIoPort, scriptPort, false);
};

module.exports.setVars = function (hostIp, socketIoPort, scriptPort) {
    ports.hostIp = hostIp;
    ports.socketIoPort = socketIoPort;
    ports.scriptPort = scriptPort;
};

module.exports.middleWare = function (req, res, next) {

    var write = res.write;

    var filepath = url.parse(req.url).pathname;
    filepath = filepath.slice(-1) === '/' ? filepath + 'index.html' : filepath;

    // Exit if the path is not for an html file.
    if (path.extname(filepath) !== '.html') {
        return next();
    }

    res.write = function (string, encoding) {
        var body = string instanceof Buffer ? string.toString() : string;

        body = body.replace(/<\/body>/, function (w) {
            return getSnippet(ports.hostIp, ports.socketIoPort, ports.scriptPort) + w;
        });

        if (string instanceof Buffer) {
            string = new Buffer(body);
        } else {
            string = body;
        }

        // Remove content-length to allow snippets to inserted to any body length
        if (!this.headerSent) {
            if (this._headers.hasOwnProperty('content-length')) {
                delete this._headers['content-length'];
            }
            this._implicitHeader();
        }

        write.call(res, string, encoding);
    };

    next();
};<|endoftext|>


<commit_before>'use strict';

var loggerModel;
exports.addModel = function(app) {

    loggerModel = app.loopback.PersistedModel.extend('Logger', {
        'name': {
            'type': 'string',
            'required': true,
            'id': true
        },
        'level': {
            'type': 'number',
            'required': true
        }
    });

    // loggerModel.disableRemoteMethod('create', true);
    // loggerModel.disableRemoteMethod('deleteById', true);
    // loggerModel.disableRemoteMethod('upsert', true);
    // loggerModel.disableRemoteMethod('exists', true);
    // loggerModel.disableRemoteMethod('findOne', true);
    // loggerModel.disableRemoteMethod('createChangeStream',true);

    app.model(loggerModel,{
      'public' : true,
      'dataSource' : null
    });

    var memory = app.loopback.createDataSource({
        connector: app.loopback.Memory
    });

    loggerModel.attachTo(memory);
};

exports.attachLoggerMap = function(loggerMap) {

    loggerMap = loggerMap || {};
    Object.keys(loggerMap).forEach(function(moduleName){
        var moduleLevel = loggerMap[moduleName].level();

        loggerModel.create({
            'name': moduleName,
            'level': moduleLevel
        },function(err){
            if(err)
                console.log(err);
        });
    });

    // Adding after save hook on loggerModel
    loggerModel.observe('after save', function(ctx, next) {

        if (ctx.instance) {
            console.log('Updating level for logger with name',
                        ctx.instance.name, ', New level is',ctx.instance.level);
            loggerMap[ctx.instance.name].level(ctx.instance.level);
        }

        next();
    });
};

exports.addChild = function(moduleName,childLogger) {
    loggerModel.create({
        'name': moduleName,
        'level': childLogger.level()
    },function(err){
        if(err)
            console.log(err);
    });
};
<commit_msg>Adding flag and fixing bug for eventEmitter limit<commit_after>'use strict';

var loggerModel;
exports.addModel = function(app) {

    loggerModel = app.loopback.PersistedModel.extend('Logger', {
        'name': {
            'type': 'string',
            'required': true,
            'id': true
        },
        'level': {
            'type': 'number',
            'required': true
        }
    });

    loggerModel.disableRemoteMethod('create', true);
    loggerModel.disableRemoteMethod('deleteById', true);
    loggerModel.disableRemoteMethod('upsert', true);
    loggerModel.disableRemoteMethod('exists', true);
    loggerModel.disableRemoteMethod('findOne', true);
    loggerModel.disableRemoteMethod('createChangeStream',true);

    app.model(loggerModel,{
      'public' : true,
      'dataSource' : null
    });

    var memory = app.loopback.createDataSource({
        connector: app.loopback.Memory
    });

    loggerModel.attachTo(memory);
};

exports.attachLoggerMap = function(loggerMap) {

    loggerMap = loggerMap || {};
    Object.keys(loggerMap).forEach(function(moduleName){
        var moduleLevel = loggerMap[moduleName].level();

        loggerModel.create({
            'name': moduleName,
            'level': moduleLevel
        },function(err){
            if(err)
                console.log(err);
        });
    });

    // Adding after save hook on loggerModel
    loggerModel.observe('after save', function(ctx, next) {

        if (ctx.instance) {
            console.log('Updating level for logger with name',
                        ctx.instance.name, ', New level is',ctx.instance.level);
            loggerMap[ctx.instance.name].level(ctx.instance.level);
        }

        next();
    });
};

exports.addChild = function(moduleName,childLogger) {
    loggerModel.create({
        'name': moduleName,
        'level': childLogger.level()
    },function(err){
        if(err)
            console.log(err);
    });
};
<|endoftext|>


<commit_before>/*
 * Geddy JavaScript Web development framework
 * 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.
 *
*/

/*
Example model file, would be app/models/user.js:

var User = function () {
  this.property('login', 'string', {required: true});
  this.property('password', 'string', {required: true});
  this.property('lastName', 'string');
  this.property('firstName', 'string');

  this.validatesPresent('login');
  this.validatesFormat('login', /[a-z]+/, {message: 'Subdivisions!'});
  this.validatesLength('login', {min: 3});
  this.validatesConfirmed('password', 'confirmPassword');
  this.validatesWithFunction('password',
      function (s) { return s.length > 0; // Could be anything
  });
};

User.prototype.someMethod = function () {
  // Do some stuff on a User instance
};

User = geddy.model.register('User', User);
*/

var model = {}
  , utils = require('../utils');

model.datatypes = require('./datatypes.js');
model.validators = require('./validators.js');
model.formatters = require('./formatters.js');

utils.mixin(model, new (function () {

  var _createModelItemConstructor = function (def) {
    // Base constructor function for all model items
    var ModelItemConstructor = function (params) {
      this.type = def.name;
      // Items fetched from an API should have this flag set to true
      this.saved = params.saved || false;

      // If fetched and instantiated from an API-call, give the
      // instance the appropriate ID -- newly created objects won't
      // have one until saved
      if (params.saved) {
        this.id = params.id;
      }

      this.isValid = function () {
        return !this.errors;
      };

      // Callback should be in the format of function (err, result) {}
      this.save = function (opts, callback) {
        if (this.errors) {
          callback(this.errors, null);
        }
        else {
          if (model.useTimestamps && this.saved) {
            this.updatedAt = new Date();
          }
          model.adapter[this.type].save(this, opts, callback);
        }
      };

      this.updateAttributes = function (params, opts, callback) {
        geddy.model.updateItem(this, params);
        if (opts.remote) {
          this.save(opts, callback);
        }
      };

      this.toString = function () {
        var obj = {};
        obj.id = this.id;
        obj.type = this.type;
        var props = this.properties;
        var formatter;
        for (var p in props) {
          formatter = model.formatters[props[p].datatype];
          obj[p] = typeof formatter == 'function' ? formatter(this[p]) : this[p];
        }
        return JSON.stringify(obj);
      };

      this.toJson = this.toString;
    };

    return ModelItemConstructor;
  };

  var _createStaticMethodsMixin = function (name) {
    var obj = {}
      , createAPIMethod = function (method) {
          return function () {
            if (!model.adapter) {
              throw new Error('geddy.model.adapter is not defined.');
            }
            return model.adapter[name][method].apply(model.adapter,
                arguments);
          };
        };

    obj.create = function () {
      var args = Array.prototype.slice.call(arguments);
      args.unshift(name);
      return model.createItem.apply(model, args);
    };

    // Create statics that invoke the same model-name/method
    // combination on the model.adapter, e.g.:
    // FooBar.load => geddy.model.adapter.FooBar.load
    ['load', 'update', 'remove', 'save'].forEach(function (method) {
      obj[method] = createAPIMethod(method);
    });

    return obj;
  };

  this.adapter = null;
  this.descriptionRegistry = {};
  this.useTimestamps = false;
  this.forceCamel = true;

  this.register = function (name, ModelDefinition) {
    var origProto = ModelDefinition.prototype
      , defined
      , ModelCtor;

    // Create the place to store the metadata about the model structure
    // to use to do validations, etc. when constructing
    model.descriptionRegistry[name] = new model.ModelDescription(name);
    // Execute all the definition methods to create that metadata
    ModelDefinition.prototype = new model.ModelDefinitionBase(name);
    defined = new ModelDefinition();

    // Create the constructor function to use when calling static
    // ModelCtor.create. Gives them the proper instanceof value,
    // and .valid, etc. instance-methods.
    ModelCtor = _createModelItemConstructor(defined);

    // Mix in the static methods like .create and .load
    utils.mixin(ModelCtor, _createStaticMethodsMixin(name));
    // Same with statics
    utils.mixin(ModelCtor, defined);

    // Mix any functions defined directly in the model-item definition
    // 'constructor' into the original prototype, and set it as the prototype of the
    // actual constructor
    utils.mixin(origProto, defined);

    ModelCtor.prototype = origProto;

    model[name] = ModelCtor;

    return ModelCtor;
  };

  this.createItem = function (name, params) {
    var item = new model[name](params);
    item = this.validateAndUpdateFromParams(item, params);

    if (this.useTimestamps && !item.createdAt) {
      item.createdAt = new Date();
    }

    // After-create hook
    if (typeof item.afterCreate == 'function') {
      item.afterCreate();
    }
    return item;
  };

  this.updateItem = function (item, params) {
    item = this.validateAndUpdateFromParams(item, params);

    // After-update hook
    if (typeof item.afterUpdate == 'function') {
      item.afterUpdate();
    }
    return item;
  };

  this.validateAndUpdateFromParams = function (item, passedParams) {
    var params
      , type = model.descriptionRegistry[item.type]
      , properties = type.properties
      , validated = null
      , errs = null
      , val

    // May be revalidating, clear errors
    delete item.errors;

    if (this.forceCamel) {
      params = {};
      for (var p in passedParams) {
        params[geddy.string.camelize(p)] = passedParams[p];
      }
    }
    else {
      params = passedParams;
    }

    // User-input should never contain these -- but we still want
    // to validate them
    if (typeof item.createdAt != 'undefined') {
      params.createdAt = item.createdAt;
    }
    if (typeof item.updatedAt != 'undefined') {
      params.updatedAt = item.updatedAt;
    }

    for (var p in properties) {
      validated = this.validateProperty(properties[p], params);
      // If there are any failed validations, the errs param
      // contains an Object literal keyed by field name, and the
      // error message for the first failed validation for that
      // property
      if (validated.err) {
        errs = errs || {};
        errs[p] = validated.err;
      }
      // Otherwise add this property the the return item
      else {
        item[p] = validated.val;
      }
    }

    // Should never be incuded in user input
    delete params.createdAt;
    delete params.updatedAt;

    if (errs) {
      item.errors = errs;
    }

    return item;
  };

  this.validateProperty = function (prop, params) {
    var name = prop.name
      , val = params[name];

    // Validate for the base datatype only if there actually is a value --
    // e.g., undefined will fail the validation for Number, even if the
    // field is optional
    if (val) {
      var result = model.datatypes[prop.datatype.toLowerCase()](prop.name, val);
      if (result.err) {
        return {
          err: result.err,
          val: null
        };
      }
      // Value may have been modified in the datatype check -- e.g.,
      // 'false' changed to false, '8.0' changed to 8, '2112' changed to
      // 2112, etc.
      val = result.val;
    }

    // Now go through all the base validations for this property
    var validations = prop.validations;
    var validator;
    var err;
    for (var p in validations) {
      validator = model.validators[p]
      if (typeof validator != 'function') {
        throw new Error(p + ' is not a valid validator');
      }
      err = validator(name, val, params, validations[p]);
      // If there's an error for a validation, don't bother
      // trying to continue with more validations -- just return
      // this first error message
      if (err) {
        return {
          err: err,
          val: null
        };
      }
    }

    // If there weren't any errors, return the value for this property
    // and no error
    return {
      err: null,
      val: val
    };
  };

})());

model.ModelDefinitionBase = function (name) {
  var self = this
    , _getValidator = function (p) {
    return function () {
      var args = Array.prototype.slice.call(arguments);
      args.unshift(p);
      return self.validates.apply(self, args);
    };
  };

  this.name = name;
  this.property = function (name, datatype, o) {
    model.descriptionRegistry[this.name].properties[name] =
      new model.PropertyDescription(name, datatype, o);
  };

  this.validates = function (condition, name, qualifier, opts) {
    var rule = utils.mixin({}, opts, true);
    rule.qualifier = qualifier;
    model.descriptionRegistry[this.name].properties[name]
        .validations[condition] = rule;
  };

  // For each of the validators, create a validatesFooBar from
  // validates('fooBar' ...
  for (var p in model.validators) {
    this['validates' + utils.string.capitalize(p)] = _getValidator(p);
  }

  // Add the base model properties -- these should not be handled by user input
  if (model.useTimestamps) {
    this.property('createdAt', 'datetime');
    this.property('updatedAt', 'datetime');
  }

};

model.ModelDescription = function (name) {
  this.name = name;
  this.properties = {};
};

model.PropertyDescription = function (name, datatype, o) {
  var opts = o || {};
  this.name = name;
  this.datatype = datatype;
  this.options = opts;
  var validations = {};
  for (var p in opts) {
    if (opts.required || opts.length) {
      validations.present = true;
    }
    if (opts.length) {
      validations.length = opts.length;
    }
    if (opts.format) {
      validations.format = opts.format;
    }
  }
  this.validations = validations;
};

module.exports = model;

<commit_msg>Allow an "any" (*) datatype in model-props.<commit_after>/*
 * Geddy JavaScript Web development framework
 * 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.
 *
*/

/*
Example model file, would be app/models/user.js:

var User = function () {
  this.property('login', 'string', {required: true});
  this.property('password', 'string', {required: true});
  this.property('lastName', 'string');
  this.property('firstName', 'string');

  this.validatesPresent('login');
  this.validatesFormat('login', /[a-z]+/, {message: 'Subdivisions!'});
  this.validatesLength('login', {min: 3});
  this.validatesConfirmed('password', 'confirmPassword');
  this.validatesWithFunction('password',
      function (s) { return s.length > 0; // Could be anything
  });
};

User.prototype.someMethod = function () {
  // Do some stuff on a User instance
};

User = geddy.model.register('User', User);
*/

var model = {}
  , utils = require('../utils');

model.datatypes = require('./datatypes.js');
model.validators = require('./validators.js');
model.formatters = require('./formatters.js');

utils.mixin(model, new (function () {

  var _createModelItemConstructor = function (def) {
    // Base constructor function for all model items
    var ModelItemConstructor = function (params) {
      this.type = def.name;
      // Items fetched from an API should have this flag set to true
      this.saved = params.saved || false;

      // If fetched and instantiated from an API-call, give the
      // instance the appropriate ID -- newly created objects won't
      // have one until saved
      if (params.saved) {
        this.id = params.id;
      }

      this.isValid = function () {
        return !this.errors;
      };

      // Callback should be in the format of function (err, result) {}
      this.save = function (opts, callback) {
        if (this.errors) {
          callback(this.errors, null);
        }
        else {
          if (model.useTimestamps && this.saved) {
            this.updatedAt = new Date();
          }
          model.adapter[this.type].save(this, opts, callback);
        }
      };

      this.updateAttributes = function (params, opts, callback) {
        geddy.model.updateItem(this, params);
        if (opts.remote) {
          this.save(opts, callback);
        }
      };

      this.toString = function () {
        var obj = {};
        obj.id = this.id;
        obj.type = this.type;
        var props = this.properties;
        var formatter;
        for (var p in props) {
          formatter = model.formatters[props[p].datatype];
          obj[p] = typeof formatter == 'function' ? formatter(this[p]) : this[p];
        }
        return JSON.stringify(obj);
      };

      this.toJson = this.toString;
    };

    return ModelItemConstructor;
  };

  var _createStaticMethodsMixin = function (name) {
    var obj = {}
      , createAPIMethod = function (method) {
          return function () {
            if (!model.adapter) {
              throw new Error('geddy.model.adapter is not defined.');
            }
            return model.adapter[name][method].apply(model.adapter,
                arguments);
          };
        };

    obj.create = function () {
      var args = Array.prototype.slice.call(arguments);
      args.unshift(name);
      return model.createItem.apply(model, args);
    };

    // Create statics that invoke the same model-name/method
    // combination on the model.adapter, e.g.:
    // FooBar.load => geddy.model.adapter.FooBar.load
    ['load', 'update', 'remove', 'save'].forEach(function (method) {
      obj[method] = createAPIMethod(method);
    });

    return obj;
  };

  this.adapter = null;
  this.descriptionRegistry = {};
  this.useTimestamps = false;
  this.forceCamel = true;

  this.register = function (name, ModelDefinition) {
    var origProto = ModelDefinition.prototype
      , defined
      , ModelCtor;

    // Create the place to store the metadata about the model structure
    // to use to do validations, etc. when constructing
    model.descriptionRegistry[name] = new model.ModelDescription(name);
    // Execute all the definition methods to create that metadata
    ModelDefinition.prototype = new model.ModelDefinitionBase(name);
    defined = new ModelDefinition();

    // Create the constructor function to use when calling static
    // ModelCtor.create. Gives them the proper instanceof value,
    // and .valid, etc. instance-methods.
    ModelCtor = _createModelItemConstructor(defined);

    // Mix in the static methods like .create and .load
    utils.mixin(ModelCtor, _createStaticMethodsMixin(name));
    // Same with statics
    utils.mixin(ModelCtor, defined);

    // Mix any functions defined directly in the model-item definition
    // 'constructor' into the original prototype, and set it as the prototype of the
    // actual constructor
    utils.mixin(origProto, defined);

    ModelCtor.prototype = origProto;

    model[name] = ModelCtor;

    return ModelCtor;
  };

  this.createItem = function (name, params) {
    var item = new model[name](params);
    item = this.validateAndUpdateFromParams(item, params);

    if (this.useTimestamps && !item.createdAt) {
      item.createdAt = new Date();
    }

    // After-create hook
    if (typeof item.afterCreate == 'function') {
      item.afterCreate();
    }
    return item;
  };

  this.updateItem = function (item, params) {
    item = this.validateAndUpdateFromParams(item, params);

    // After-update hook
    if (typeof item.afterUpdate == 'function') {
      item.afterUpdate();
    }
    return item;
  };

  this.validateAndUpdateFromParams = function (item, passedParams) {
    var params
      , type = model.descriptionRegistry[item.type]
      , properties = type.properties
      , validated = null
      , errs = null
      , val

    // May be revalidating, clear errors
    delete item.errors;

    if (this.forceCamel) {
      params = {};
      for (var p in passedParams) {
        params[geddy.string.camelize(p)] = passedParams[p];
      }
    }
    else {
      params = passedParams;
    }

    // User-input should never contain these -- but we still want
    // to validate them
    if (typeof item.createdAt != 'undefined') {
      params.createdAt = item.createdAt;
    }
    if (typeof item.updatedAt != 'undefined') {
      params.updatedAt = item.updatedAt;
    }

    for (var p in properties) {
      validated = this.validateProperty(properties[p], params);
      // If there are any failed validations, the errs param
      // contains an Object literal keyed by field name, and the
      // error message for the first failed validation for that
      // property
      if (validated.err) {
        errs = errs || {};
        errs[p] = validated.err;
      }
      // Otherwise add this property the the return item
      else {
        item[p] = validated.val;
      }
    }

    // Should never be incuded in user input
    delete params.createdAt;
    delete params.updatedAt;

    if (errs) {
      item.errors = errs;
    }

    return item;
  };

  this.validateProperty = function (prop, params) {
    var name = prop.name
      , val = params[name]
      , result;

    // Validate for the base datatype only if there actually is a value --
    // e.g., undefined will fail the validation for Number, even if the
    // field is optional
    if (val) {
      if (prop.datatype == '*') {
        result = {
          val: val
        };
      }
      else {
        result = model.datatypes[prop.datatype.toLowerCase()](prop.name, val);
        if (result.err) {
          return {
            err: result.err,
            val: null
          };
        }
      }
      // Value may have been modified in the datatype check -- e.g.,
      // 'false' changed to false, '8.0' changed to 8, '2112' changed to
      // 2112, etc.
      val = result.val;
    }

    // Now go through all the base validations for this property
    var validations = prop.validations;
    var validator;
    var err;
    for (var p in validations) {
      validator = model.validators[p]
      if (typeof validator != 'function') {
        throw new Error(p + ' is not a valid validator');
      }
      err = validator(name, val, params, validations[p]);
      // If there's an error for a validation, don't bother
      // trying to continue with more validations -- just return
      // this first error message
      if (err) {
        return {
          err: err,
          val: null
        };
      }
    }

    // If there weren't any errors, return the value for this property
    // and no error
    return {
      err: null,
      val: val
    };
  };

})());

model.ModelDefinitionBase = function (name) {
  var self = this
    , _getValidator = function (p) {
    return function () {
      var args = Array.prototype.slice.call(arguments);
      args.unshift(p);
      return self.validates.apply(self, args);
    };
  };

  this.name = name;
  this.property = function (name, datatype, o) {
    model.descriptionRegistry[this.name].properties[name] =
      new model.PropertyDescription(name, datatype, o);
  };

  this.validates = function (condition, name, qualifier, opts) {
    var rule = utils.mixin({}, opts, true);
    rule.qualifier = qualifier;
    model.descriptionRegistry[this.name].properties[name]
        .validations[condition] = rule;
  };

  // For each of the validators, create a validatesFooBar from
  // validates('fooBar' ...
  for (var p in model.validators) {
    this['validates' + utils.string.capitalize(p)] = _getValidator(p);
  }

  // Add the base model properties -- these should not be handled by user input
  if (model.useTimestamps) {
    this.property('createdAt', 'datetime');
    this.property('updatedAt', 'datetime');
  }

};

model.ModelDescription = function (name) {
  this.name = name;
  this.properties = {};
};

model.PropertyDescription = function (name, datatype, o) {
  var opts = o || {};
  this.name = name;
  this.datatype = datatype;
  this.options = opts;
  var validations = {};
  for (var p in opts) {
    if (opts.required || opts.length) {
      validations.present = true;
    }
    if (opts.length) {
      validations.length = opts.length;
    }
    if (opts.format) {
      validations.format = opts.format;
    }
  }
  this.validations = validations;
};

module.exports = model;

<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

module.exports = function( environment, mongoInstance ) {

  var mongoosastic = require( "mongoosastic" ),
      validate = require( "mongoose-validator" ).validate,
      deferred = require( "deferred" ),
      env = environment,
      url = require( "url" ),
      mongoose = mongoInstance,
      elasticSearchURL = env.get( "FOUNDELASTICSEARCH_URL" ) ||
                         env.get( "BONSAI_URL" ) ||
                         env.get( "ELASTIC_SEARCH_URL" );

      elasticSearchURL = url.parse( elasticSearchURL );

  var Timestamp = {
    type: Number,
    "default": Date.now(),
    es_type: "long",
    es_indexed: true,
    es_index: "not_analyzed"
  };

  // Schema
  var schema = new mongoose.Schema({
    url: {
      type: String,
      required: true,
      es_indexed: true,
      validate: validate( "isUrl" ),
      unique: true,
      es_index: "not_analyzed"
    },
    contentType: {
      type: String,
      es_indexed: true,
      required: true,
      es_index: "not_analyzed"
    },
    locale: {
      type: String,
      "default": "en_us",
      es_indexed: true,
      es_index: "not_analyzed"
    },
    title: {
      type: String,
      es_indexed: true,
      required: true,
      es_index: "not_analyzed"
    },
    description: {
      type: String,
      es_indexed: true,
      es_index: "not_analyzed"
    },
    thumbnail: {
      type: String,
      es_indexed: true,
      es_index: "not_analyzed"
    },
    author: {
      type: String,
      required: false,
      es_indexed: true,
      es_index: "not_analyzed"
    },
    email: {
      type: String,
      required: true,
      validate: validate( "isEmail" ),
      es_indexed: true,
      es_index: "not_analyzed"
    },
    published: {
      type: Boolean,
      "default": true,
      es_index: "not_analyzed"
    },
    tags: {
      type: [ String ],
      es_indexed: true,
      es_index: "not_analyzed",
      es_type: "String"
    },
    remixedFrom: {
      type: String,
      "default": null,
      es_indexed: true,
      es_index: "not_analyzed"
    },
    createdAt: Timestamp,
    updatedAt: Timestamp,
    deletedAt: {
      type: Number,
      "default": null,
      es_indexed: true,
      es_type: "long"
    }
  });

  schema.set( "toJSON", { virtuals: true } );

  schema.virtual( "id" ).get(function() {
    return this._id;
  });

  // Hooks
  schema.pre( "save", function ( next ) {
    this.updatedAt = Date.now();
    next();
  });

  schema.plugin( mongoosastic, {
    port: elasticSearchURL.port || 80,
    host: ( elasticSearchURL.auth ? elasticSearchURL.auth + "@" : "" ) + elasticSearchURL.hostname,
    hydrate: true
  });

  var Make = mongoose.model( "Make", schema );

  Make.createMapping(function( err, mapping ) {
    if ( err ) {
      console.log( "failed to create mapping", err.toString() );
    }
  });

  Make.publicFields = [ "url", "contentType", "locale", "locales",
                        "title", "description", "author", "published", "tags",
                        "thumbnail", "remixedFrom" ];

  return Make;
};
<commit_msg>Fix Bug 878779 - createdAt was defaulting to a date based on when server was last started<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

module.exports = function( environment, mongoInstance ) {

  var mongoosastic = require( "mongoosastic" ),
      validate = require( "mongoose-validator" ).validate,
      deferred = require( "deferred" ),
      env = environment,
      url = require( "url" ),
      mongoose = mongoInstance,
      elasticSearchURL = env.get( "FOUNDELASTICSEARCH_URL" ) ||
                         env.get( "BONSAI_URL" ) ||
                         env.get( "ELASTIC_SEARCH_URL" );

      elasticSearchURL = url.parse( elasticSearchURL );

  var Timestamp = {
    type: Number,
    es_type: "long",
    es_indexed: true,
    es_index: "not_analyzed"
  };

  // Schema
  var schema = new mongoose.Schema({
    url: {
      type: String,
      required: true,
      es_indexed: true,
      validate: validate( "isUrl" ),
      unique: true,
      es_index: "not_analyzed"
    },
    contentType: {
      type: String,
      es_indexed: true,
      required: true,
      es_index: "not_analyzed"
    },
    locale: {
      type: String,
      "default": "en_us",
      es_indexed: true,
      es_index: "not_analyzed"
    },
    title: {
      type: String,
      es_indexed: true,
      required: true,
      es_index: "not_analyzed"
    },
    description: {
      type: String,
      es_indexed: true,
      es_index: "not_analyzed"
    },
    thumbnail: {
      type: String,
      es_indexed: true,
      es_index: "not_analyzed"
    },
    author: {
      type: String,
      required: false,
      es_indexed: true,
      es_index: "not_analyzed"
    },
    email: {
      type: String,
      required: true,
      validate: validate( "isEmail" ),
      es_indexed: true,
      es_index: "not_analyzed"
    },
    published: {
      type: Boolean,
      "default": true,
      es_index: "not_analyzed"
    },
    tags: {
      type: [ String ],
      es_indexed: true,
      es_index: "not_analyzed",
      es_type: "String"
    },
    remixedFrom: {
      type: String,
      "default": null,
      es_indexed: true,
      es_index: "not_analyzed"
    },
    createdAt: Timestamp,
    updatedAt: Timestamp,
    deletedAt: {
      type: Number,
      "default": null,
      es_indexed: true,
      es_type: "long"
    }
  });

  schema.set( "toJSON", { virtuals: true } );

  schema.virtual( "id" ).get(function() {
    return this._id;
  });

  // Hooks
  schema.pre( "save", function ( next ) {
    this.updatedAt = Date.now();
    next();
  });

  schema.plugin( mongoosastic, {
    port: elasticSearchURL.port || 80,
    host: ( elasticSearchURL.auth ? elasticSearchURL.auth + "@" : "" ) + elasticSearchURL.hostname,
    hydrate: true
  });

  var Make = mongoose.model( "Make", schema );

  Make.createMapping(function( err, mapping ) {
    if ( err ) {
      console.log( "failed to create mapping", err.toString() );
    }
  });

  Make.publicFields = [ "url", "contentType", "locale", "locales",
                        "title", "description", "author", "published", "tags",
                        "thumbnail", "remixedFrom" ];

  return Make;
};
<|endoftext|>


<commit_before>
/**
 * Module dependencies
 */

var config    = require('./config.js');
var log       = require('logule').init(module, 'user');
var mandrill  = require('node-mandrill')(config.mandrillApiKey);

/**
 * User model
 *
 * @param sequelize
 * @param DataTypes
 * @returns {*}
 */

module.exports = function(sequelize, DataTypes) {

  log.info('importing..');

  return sequelize.define('User', {
    id        : DataTypes.INTEGER,
    balance   : DataTypes.DECIMAL,
    email     : DataTypes.STRING,
    nfcID     : DataTypes.STRING,
    usbSerial : DataTypes.STRING,
    username  : DataTypes.STRING
  },
    {
    instanceMethods: {
      /**
       *
       * @param amount
       * @returns {boolean}
       */
      withdraw : function(amount) {
        if (this.balance < amount) {
          return false;
        }

        this.decrement('balance', { by: amount });

      },
      /**
       *
       */
      notifyBalance : function() {

      }
      // ..
    }
  });
};
<commit_msg>adding notify balance to user model<commit_after>
/**
 * Module dependencies
 */

var config    = require('./config.js');
var log       = require('logule').init(module, 'user');
var mandrill  = require('node-mandrill')(config.mandrillApiKey);

/**
 * User model
 *
 * @param sequelize
 * @param DataTypes
 * @returns {*}
 */

module.exports = function(sequelize, DataTypes) {

  log.info('importing..');

  return sequelize.define('User', {
    id        : DataTypes.INTEGER,
    balance   : DataTypes.DECIMAL,
    email     : DataTypes.STRING,
    nfcID     : DataTypes.STRING,
    usbSerial : DataTypes.STRING,
    username  : DataTypes.STRING
  },
    {
    instanceMethods: {
      /**
       *
       * @param amount
       * @returns {boolean}
       */
      withdraw : function(amount) {
        if (this.balance < amount) {
          return false;
        }

        this.decrement('balance', { by: amount });

      },
      /**
       *
       */
      notifyBalance : function() {
        mandrill('/messages/send', {
          message: {
            to: [{email: user.email, name: user.username}],
            from_email: 'no-reply@makerslocal.org',
            subject: "[Cascade] Receipt",
            text: "Hi " + user.username + ", your current balance is: " + user.balance.toFixed(2)
          }
        }, function(err) {
          if (err) {
            log.error(err);
          }
          // ..
        });
      }
      // ..
    }
  });
};
<|endoftext|>