<commit_before>var _ = require('underscore')
	,fs = require('fs')
	,path = require('path')
	,util = require('util')
	,spawn = require('child_process').spawn;
	
exports.createService = function(name, controller, options) {
	return new exports.nginx(name, controller, options);
};

exports.nginx = function(name, controller, options) {
	var me = this;
	
	// call parent constructor
	exports.nginx.super_.apply(me, arguments);
	
	// default options
	me.options.bootstrapDir = me.options.bootstrapDir || path.resolve(__dirname, '../../php-bootstrap');
	me.options.configPath = me.options.configPath || controller.options.configDir + '/nginx.conf';
	me.options.execPath = me.options.execPath || '/usr/sbin/nginx';
	me.options.bindHost = me.options.bindHost || '127.0.0.1';
	me.options.bindPort = me.options.bindPort || 80;
	me.options.runDir = me.options.runDir || controller.options.runDir + '/nginx';
	me.options.logsDir = me.options.logsDir || controller.options.logsDir + '/nginx';
	me.options.pidPath = me.options.pidPath || me.options.runDir + '/nginx.pid';
	me.options.errorLogPath = me.options.errorLogPath || me.options.logsDir + '/errors.log';
	me.options.miscConfigDir = me.options.miscConfigDir || (process.platform=='darwin'?'/usr/local/etc/nginx':'/etc/nginx')
	
	me.options.phpLogsDir = me.options.phpLogsDir || controller.options.logsDir + '/php';
	me.options.phpErrorLogPath = me.options.phpErrorLogPath || me.options.phpLogsDir + '/errors.log';
	
	// create required directories
	if(!fs.existsSync(me.options.runDir))
		fs.mkdirSync(me.options.runDir, 0775);
	
	if(!fs.existsSync(me.options.logsDir))
		fs.mkdirSync(me.options.logsDir, 0775);
	
	if(!fs.existsSync(me.options.phpLogsDir))
		fs.mkdirSync(me.options.phpLogsDir, 0775);
	
	// check for existing master process
	if(fs.existsSync(me.options.pidPath))
	{
		me.pid = parseInt(fs.readFileSync(me.options.pidPath));
		console.log(me.name+': found existing PID: '+me.pid);
		me.status = 'online';
	}
	
	// listen for site creation
	controller.sites.on('siteCreated', _.bind(me.onSiteCreated, me));
}
util.inherits(exports.nginx, require('./abstract.js').AbstractService);



exports.nginx.prototype.start = function() {
	var me = this;
	
	console.log(me.name+': spawning daemon: '+me.options.execPath);

	if(me.pid)
	{
		console.log(me.name+': already running with PID '+me.pid);
		return false;
	}
	
	this.writeConfig();
	
	me.proc = spawn(me.options.execPath, ['-c', me.options.configPath]);

	me.proc.on('exit', function (code) {
	
		if (code !== 0)
		{
			me.status = 'offline';
			me.exitCode = code;
			console.log(me.name+': exited with code: '+code);
		}
		
		// look for pid
		if(fs.existsSync(me.options.pidPath))
		{
			me.pid = parseInt(fs.readFileSync(me.options.pidPath));
			console.log(me.name+': found new PID: '+me.pid);
			me.status = 'online';
		}
		else
		{
			console.log(me.name+': failed to find pid after launching');
			me.status = 'unknown';
			me.pid = null;
		}
	});
	
	me.proc.stdout.on('data', function (data) {
		console.log(me.name+': stdout:\n\t' + data.toString().replace(/\n/g,'\n\t'));
	});
	
	me.proc.stderr.on('data', function (data) {
		console.log(me.name+': stderr:\n\t' + data.toString().replace(/\n/g,'\n\t'));
		
		if (/^execvp\(\)/.test(data)) {
			console.log('Failed to start child process.');
			me.status = 'offline';
		}
  	});
	
	this.status = 'online';
	return true;
}


exports.nginx.prototype.stop = function() {
	var me = this;

	if(!me.pid)
		return false;
		
	try
	{
		process.kill(me.pid, 'SIGQUIT');
	}
	catch(error)
	{
		console.log(me.name+': failed to stop process: '+error);
		return false;
	}
	
	me.status = 'offline';
	me.pid = null;
	return true;
}


exports.nginx.prototype.restart = function() {
	var me = this;

	if(!me.pid)
		return false;
		
	this.writeConfig();

	try
	{
		process.kill(me.pid, 'SIGHUP');
	}
	catch(error)
	{
		console.log(me.name+': failed to restart process: '+error);
		return false;
	}
	
	console.log(me.name+': reloaded config for process '+me.pid);
	
	return true;
}


exports.nginx.prototype.writeConfig = function() {
	fs.writeFileSync(this.options.configPath, this.makeConfig());
};

exports.nginx.prototype.makeConfig = function() {
	var me = this
		,c = '';
		
	c += 'user nobody nobody;\n';
	c += 'worker_processes 1;\n';
	c += 'pid '+me.options.pidPath+';\n';
	c += 'error_log '+me.options.errorLogPath+' info;\n';

	c += 'events {\n';
	c += '	worker_connections 1024;\n';
	
	if(process.platform == 'linux')
		c += '	use epoll;\n';
		
	c += '}\n';

	c += 'http {\n';
	c += '	include '+me.options.miscConfigDir+'/mime.types;\n';
	c += '	default_type application/octet-stream;\n';

	c += '	log_format main\n';
	c += '		\'$host $remote_addr - $remote_user [$time_local] \'\n';
	c += '		\'"$request" $status $bytes_sent \'\n';
	c += '		\'"$http_referer" "$http_user_agent" \'\n';
	c += '		\'"$gzip_ratio"\';\n';

	c += '	client_header_timeout 10m;\n';
	c += '	client_body_timeout 10m;\n';
	c += '	send_timeout 10m;\n';

	c += '	connection_pool_size 256;\n';
	c += '	client_max_body_size 50M;\n';
	c += '	client_header_buffer_size 1k;\n';
	c += '	large_client_header_buffers 4 2k;\n';
	c += '	request_pool_size 4k;\n';
	c += '	server_names_hash_bucket_size 1024;\n';

	c += '	gzip on;\n';
	c += '	gzip_min_length 1100;\n';
	c += '	gzip_buffers 4 8k;\n';
	c += '	gzip_types text/plain;\n';

	c += '	output_buffers 1 32k;\n';
	c += '	postpone_output 1460;\n';

	c += '	sendfile on;\n';
	c += '	tcp_nopush on;\n';
	c += '	tcp_nodelay on;\n';

	c += '	keepalive_timeout 75 20;\n';

	c += '	ignore_invalid_headers on;\n';

	c += '	index index.php;\n';

/*

	c += '	server {\n';
	c += '		server_name _;\n';
	c += '		access_log /emergence/logs/access.log main;\n';
	c += '		error_log /emergence/logs/error.log info;\n';	
	c += '	}\n';
*/

	_.each(me.controller.sites.sites, function(site, handle) {
	
		// process hostnames
		var hostnames = site.hostnames.slice();
		if(_.indexOf(hostnames, site.primary_hostname) == -1)
			hostnames.unshift(site.primary_hostname);
			
		// process directories
		var siteDir = me.controller.sites.options.sitesDir+'/'+handle
			,logsDir = siteDir+'/logs';
			
		if(!fs.existsSync(logsDir))
			fs.mkdirSync(logsDir, 0775);

		var siteCfg = '		server_name '+hostnames.join(' ')+';\n';
		siteCfg += '		access_log '+logsDir+'/access.log main;\n';
		siteCfg += '		error_log '+logsDir+'/error.log info;\n';
	
		siteCfg += '		location / {\n';
		siteCfg += '			root '+me.options.bootstrapDir+'/root;\n';
		siteCfg += '			index index.php;\n';
		siteCfg += '			rewrite ^(.+)$ /index.php last;\n';
		siteCfg += '		}\n';
	
		siteCfg += '		location ~ ^/index.php {\n';
		siteCfg += '			include '+me.options.miscConfigDir+'/fastcgi_params;\n';
		siteCfg += '			fastcgi_pass 127.0.0.1:9000;\n';
		siteCfg += '			fastcgi_param PATH_INFO $fastcgi_script_name;\n';
		siteCfg += '			fastcgi_param SITE_ROOT '+siteDir+';\n';
		siteCfg += '			fastcgi_param SCRIPT_FILENAME '+me.options.bootstrapDir+'/root$fastcgi_script_name;\n';
		siteCfg += '			fastcgi_param PHP_VALUE	"auto_prepend_file='+me.options.bootstrapDir+'/bootstrap.php\n';
		siteCfg += '						 include_path='+me.options.bootstrapDir+'/lib:'+siteDir+'\n';
		siteCfg += '						 error_log='+me.options.phpErrorLogPath+'\n';
		siteCfg += '						 error_reporting = E_ALL & ~E_NOTICE\n';
		siteCfg += '						 date.timezone = America/New_York";\n';
		siteCfg += '			fastcgi_index index.php;\n';
		siteCfg += '			fastcgi_read_timeout 120s;\n';
		siteCfg += '		}\n';


	
		// append config
		c += '	server {\n';
		c += '		listen '+me.options.bindHost+':'+me.options.bindPort+';\n';
		c +=            siteCfg;
		c += '	}\n';
		
		if(site.ssl)
		{
			c += '	server {\n';
			c += '		listen '+me.options.bindHost+':443;\n';
			
			c += '		ssl on;\n';
			c += '		ssl_certificate '+site.ssl.certificate+';\n';
			c += '		ssl_certificate_key '+site.ssl.certificate_key+';\n';
			c +=            siteCfg;
			c += '	}\n';
		}
	});
	
	c += '}\n';

	return c;
};


exports.nginx.prototype.onSiteCreated = function(siteData) {
	this.restart();
};
<commit_msg>added delayed retry for detecting nginx PID<commit_after>var _ = require('underscore')
	,fs = require('fs')
	,path = require('path')
	,util = require('util')
	,spawn = require('child_process').spawn;
	
exports.createService = function(name, controller, options) {
	return new exports.nginx(name, controller, options);
};

exports.nginx = function(name, controller, options) {
	var me = this;
	
	// call parent constructor
	exports.nginx.super_.apply(me, arguments);
	
	// default options
	me.options.bootstrapDir = me.options.bootstrapDir || path.resolve(__dirname, '../../php-bootstrap');
	me.options.configPath = me.options.configPath || controller.options.configDir + '/nginx.conf';
	me.options.execPath = me.options.execPath || '/usr/sbin/nginx';
	me.options.bindHost = me.options.bindHost || '127.0.0.1';
	me.options.bindPort = me.options.bindPort || 80;
	me.options.runDir = me.options.runDir || controller.options.runDir + '/nginx';
	me.options.logsDir = me.options.logsDir || controller.options.logsDir + '/nginx';
	me.options.pidPath = me.options.pidPath || me.options.runDir + '/nginx.pid';
	me.options.errorLogPath = me.options.errorLogPath || me.options.logsDir + '/errors.log';
	me.options.miscConfigDir = me.options.miscConfigDir || (process.platform=='darwin'?'/usr/local/etc/nginx':'/etc/nginx')
	
	me.options.phpLogsDir = me.options.phpLogsDir || controller.options.logsDir + '/php';
	me.options.phpErrorLogPath = me.options.phpErrorLogPath || me.options.phpLogsDir + '/errors.log';
	
	// create required directories
	if(!fs.existsSync(me.options.runDir))
		fs.mkdirSync(me.options.runDir, 0775);
	
	if(!fs.existsSync(me.options.logsDir))
		fs.mkdirSync(me.options.logsDir, 0775);
	
	if(!fs.existsSync(me.options.phpLogsDir))
		fs.mkdirSync(me.options.phpLogsDir, 0775);
	
	// check for existing master process
	if(fs.existsSync(me.options.pidPath))
	{
		me.pid = parseInt(fs.readFileSync(me.options.pidPath));
		console.log(me.name+': found existing PID: '+me.pid);
		me.status = 'online';
	}
	
	// listen for site creation
	controller.sites.on('siteCreated', _.bind(me.onSiteCreated, me));
}
util.inherits(exports.nginx, require('./abstract.js').AbstractService);



exports.nginx.prototype.start = function() {
	var me = this;
	
	console.log(me.name+': spawning daemon: '+me.options.execPath);

	if(me.pid)
	{
		console.log(me.name+': already running with PID '+me.pid);
		return false;
	}
	
	this.writeConfig();
	
	me.proc = spawn(me.options.execPath, ['-c', me.options.configPath]);

	me.proc.on('exit', function (code) {
	
		if (code !== 0)
		{
			me.status = 'offline';
			me.exitCode = code;
			console.log(me.name+': exited with code: '+code);
		}
		
		// look for pid
		if(fs.existsSync(me.options.pidPath))
		{
			me.pid = parseInt(fs.readFileSync(me.options.pidPath));
			console.log(me.name+': found new PID: '+me.pid);
			me.status = 'online';
		}
		else
		{
			console.log(me.name+': failed to find pid after launching, waiting 1000ms and trying again...');
			setTimeout(function() {

				if(fs.existsSync(me.options.pidPath))
				{
					me.pid = parseInt(fs.readFileSync(me.options.pidPath));
					console.log(me.name+': found new PID: '+me.pid);
					me.status = 'online';
				}
				else
				{
					console.log(me.name+': failed to find pid after launching');
					me.status = 'unknown';
					me.pid = null;
				}
			}, 1000);
		}
	});
	
	me.proc.stdout.on('data', function (data) {
		console.log(me.name+': stdout:\n\t' + data.toString().replace(/\n/g,'\n\t'));
	});
	
	me.proc.stderr.on('data', function (data) {
		console.log(me.name+': stderr:\n\t' + data.toString().replace(/\n/g,'\n\t'));
		
		if (/^execvp\(\)/.test(data)) {
			console.log('Failed to start child process.');
			me.status = 'offline';
		}
  	});
	
	this.status = 'online';
	return true;
}


exports.nginx.prototype.stop = function() {
	var me = this;

	if(!me.pid)
		return false;
		
	try
	{
		process.kill(me.pid, 'SIGQUIT');
	}
	catch(error)
	{
		console.log(me.name+': failed to stop process: '+error);
		return false;
	}
	
	me.status = 'offline';
	me.pid = null;
	return true;
}


exports.nginx.prototype.restart = function() {
	var me = this;

	if(!me.pid)
		return false;
		
	this.writeConfig();

	try
	{
		process.kill(me.pid, 'SIGHUP');
	}
	catch(error)
	{
		console.log(me.name+': failed to restart process: '+error);
		return false;
	}
	
	console.log(me.name+': reloaded config for process '+me.pid);
	
	return true;
}


exports.nginx.prototype.writeConfig = function() {
	fs.writeFileSync(this.options.configPath, this.makeConfig());
};

exports.nginx.prototype.makeConfig = function() {
	var me = this
		,c = '';
		
	c += 'user nobody nobody;\n';
	c += 'worker_processes 1;\n';
	c += 'pid '+me.options.pidPath+';\n';
	c += 'error_log '+me.options.errorLogPath+' info;\n';

	c += 'events {\n';
	c += '	worker_connections 1024;\n';
	
	if(process.platform == 'linux')
		c += '	use epoll;\n';
		
	c += '}\n';

	c += 'http {\n';
	c += '	include '+me.options.miscConfigDir+'/mime.types;\n';
	c += '	default_type application/octet-stream;\n';

	c += '	log_format main\n';
	c += '		\'$host $remote_addr - $remote_user [$time_local] \'\n';
	c += '		\'"$request" $status $bytes_sent \'\n';
	c += '		\'"$http_referer" "$http_user_agent" \'\n';
	c += '		\'"$gzip_ratio"\';\n';

	c += '	client_header_timeout 10m;\n';
	c += '	client_body_timeout 10m;\n';
	c += '	send_timeout 10m;\n';

	c += '	connection_pool_size 256;\n';
	c += '	client_max_body_size 50M;\n';
	c += '	client_header_buffer_size 1k;\n';
	c += '	large_client_header_buffers 4 2k;\n';
	c += '	request_pool_size 4k;\n';
	c += '	server_names_hash_bucket_size 1024;\n';

	c += '	gzip on;\n';
	c += '	gzip_min_length 1100;\n';
	c += '	gzip_buffers 4 8k;\n';
	c += '	gzip_types text/plain;\n';

	c += '	output_buffers 1 32k;\n';
	c += '	postpone_output 1460;\n';

	c += '	sendfile on;\n';
	c += '	tcp_nopush on;\n';
	c += '	tcp_nodelay on;\n';

	c += '	keepalive_timeout 75 20;\n';

	c += '	ignore_invalid_headers on;\n';

	c += '	index index.php;\n';

/*

	c += '	server {\n';
	c += '		server_name _;\n';
	c += '		access_log /emergence/logs/access.log main;\n';
	c += '		error_log /emergence/logs/error.log info;\n';	
	c += '	}\n';
*/

	_.each(me.controller.sites.sites, function(site, handle) {
	
		// process hostnames
		var hostnames = site.hostnames.slice();
		if(_.indexOf(hostnames, site.primary_hostname) == -1)
			hostnames.unshift(site.primary_hostname);
			
		// process directories
		var siteDir = me.controller.sites.options.sitesDir+'/'+handle
			,logsDir = siteDir+'/logs';
			
		if(!fs.existsSync(logsDir))
			fs.mkdirSync(logsDir, 0775);

		var siteCfg = '		server_name '+hostnames.join(' ')+';\n';
		siteCfg += '		access_log '+logsDir+'/access.log main;\n';
		siteCfg += '		error_log '+logsDir+'/error.log info;\n';
	
		siteCfg += '		location / {\n';
		siteCfg += '			root '+me.options.bootstrapDir+'/root;\n';
		siteCfg += '			index index.php;\n';
		siteCfg += '			rewrite ^(.+)$ /index.php last;\n';
		siteCfg += '		}\n';
	
		siteCfg += '		location ~ ^/index.php {\n';
		siteCfg += '			include '+me.options.miscConfigDir+'/fastcgi_params;\n';
		siteCfg += '			fastcgi_pass 127.0.0.1:9000;\n';
		siteCfg += '			fastcgi_param PATH_INFO $fastcgi_script_name;\n';
		siteCfg += '			fastcgi_param SITE_ROOT '+siteDir+';\n';
		siteCfg += '			fastcgi_param SCRIPT_FILENAME '+me.options.bootstrapDir+'/root$fastcgi_script_name;\n';
		siteCfg += '			fastcgi_param PHP_VALUE	"auto_prepend_file='+me.options.bootstrapDir+'/bootstrap.php\n';
		siteCfg += '						 include_path='+me.options.bootstrapDir+'/lib:'+siteDir+'\n';
		siteCfg += '						 error_log='+me.options.phpErrorLogPath+'\n';
		siteCfg += '						 error_reporting = E_ALL & ~E_NOTICE\n';
		siteCfg += '						 date.timezone = America/New_York";\n';
		siteCfg += '			fastcgi_index index.php;\n';
		siteCfg += '			fastcgi_read_timeout 120s;\n';
		siteCfg += '		}\n';


	
		// append config
		c += '	server {\n';
		c += '		listen '+me.options.bindHost+':'+me.options.bindPort+';\n';
		c +=            siteCfg;
		c += '	}\n';
		
		if(site.ssl)
		{
			c += '	server {\n';
			c += '		listen '+me.options.bindHost+':443;\n';
			
			c += '		ssl on;\n';
			c += '		ssl_certificate '+site.ssl.certificate+';\n';
			c += '		ssl_certificate_key '+site.ssl.certificate_key+';\n';
			c +=            siteCfg;
			c += '	}\n';
		}
	});
	
	c += '}\n';

	return c;
};


exports.nginx.prototype.onSiteCreated = function(siteData) {
	this.restart();
};

{'fraction_non_alphanumeric': 0.19614361702127658, 'fraction_numerical': 0.010517408123791103, 'mean_word_length': 3.4947025264873677, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 4, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1180633', 'n_tokens_mistral': 7081, 'n_tokens_neox': 6298, 'n_words': 1109}