<commit_before>/*jslint node: true */
"use strict";
var async = require('async');
var _ = require('lodash');
var kvstore = require('./kvstore.js');
var string_utils = require('./string_utils.js');
var storage = require('./storage.js');

function dataFeedExists(arrAddresses, feed_name, relation, value, min_mci, max_mci, bAA, handleResult){
	var start_time = Date.now();
	if (bAA) {
		var bFound = false;
		function relationSatisfied(v1, v2) {
			switch (relation) {
				case '<': return (v1 < v2);
				case '<=': return (v1 <= v2);
				case '>': return (v1 > v2);
				case '>=': return (v1 >= v2);
				default: throw Error("unknown relation: " + relation);
			}
		}
		for (var unit in storage.assocUnstableMessages) {
			var objUnit = storage.assocUnstableUnits[unit];
			if (!objUnit)
				throw Error("unstable unit " + unit + " not in assoc");
			if (!objUnit.bAA)
				continue;
			if (_.intersection(arrAddresses, objUnit.author_addresses).length === 0)
				continue;
			storage.assocUnstableMessages[unit].forEach(function (message) {
				if (message.app !== 'data_feed')
					return;
				var payload = message.payload;
				if (!(feed_name in payload))
					return;
				var feed_value = payload[feed_name];
				if (relation === '=') {
					if (value === feed_value || value.toString() === feed_value.toString())
						bFound = true;
					return;
				}
				if (relation === '!=') {
					if (value.toString() !== feed_value.toString())
						bFound = true;
					return;
				}
				if (typeof value === 'number' && typeof feed_value === 'number') {
					if (relationSatisfied(feed_value, value))
						bFound = true;
					return;
				}
				var f_value = (typeof value === 'string') ? string_utils.getNumericFeedValue(value) : value;
				var f_feed_value = (typeof feed_value === 'string') ? string_utils.getNumericFeedValue(feed_value) : feed_value;
				if (f_value === null && f_feed_value === null) { // both are strings that don't look like numbers
					if (relationSatisfied(feed_value, value))
						bFound = true;
					return;
				}
				if (f_value !== null && f_feed_value !== null) { // both are either numbers or strings that look like numbers
					if (relationSatisfied(f_feed_value, f_value))
						bFound = true;
					return;
				}
				if (typeof value === 'string' && typeof feed_value === 'string') { // only one string looks like a number
					if (relationSatisfied(feed_value, value))
						bFound = true;
					return;
				}
				// else they are incomparable e.g. 'abc' > 123
			});
			if (bFound)
				break;
		}
		if (bFound)
			return handleResult(true);
	}
	async.eachSeries(
		arrAddresses,
		function(address, cb){
			dataFeedByAddressExists(address, feed_name, relation, value, min_mci, max_mci, cb);
		},
		function(bFound){
			console.log('data feed by '+arrAddresses+' '+feed_name+relation+value+': '+bFound+', df took '+(Date.now()-start_time)+'ms');
			handleResult(!!bFound);
		}
	);
}

function dataFeedByAddressExists(address, feed_name, relation, value, min_mci, max_mci, handleResult){
	if (relation === '!='){
		return dataFeedByAddressExists(address, feed_name, '>', value, min_mci, max_mci, function(bFound){
			if (bFound)
				return handleResult(true);
			dataFeedByAddressExists(address, feed_name, '<', value, min_mci, max_mci, handleResult);
		});
	}
	var prefixed_value;
	var type;
	if (typeof value === 'string'){
		var float = string_utils.getNumericFeedValue(value);
		if (float !== null){
			prefixed_value = 'n\n'+string_utils.encodeDoubleInLexicograpicOrder(float);
			type = 'n';
		}
		else{
			prefixed_value = 's\n'+value;
			type = 's';
		}
	}
	else{
		prefixed_value = 'n\n'+string_utils.encodeDoubleInLexicograpicOrder(value);
		type= 'n';
	}
	var strMinMci = string_utils.encodeMci(min_mci);
	var strMaxMci = string_utils.encodeMci(max_mci);
	var key_prefix = 'df\n'+address+'\n'+feed_name+'\n'+prefixed_value;
	var bFound = false;
	var options = {};
	switch (relation){
		case '=':
			options.gte = key_prefix+'\n'+strMaxMci;
			options.lte = key_prefix+'\n'+strMinMci;
			options.limit = 1;
			break;
		case '>=':
			options.gte = key_prefix;
			options.lt = 'df\n'+address+'\n'+feed_name+'\n'+type+'\r';  // \r is next after \n
			break;
		case '>':
			options.gt = key_prefix+'\nffffffff';
			options.lt = 'df\n'+address+'\n'+feed_name+'\n'+type+'\r';  // \r is next after \n
			break;
		case '<=':
			options.lte = key_prefix+'\nffffffff';
			options.gt = 'df\n'+address+'\n'+feed_name+'\n'+type+'\n';
			break;
		case '<':
			options.lt = key_prefix;
			options.gt = 'df\n'+address+'\n'+feed_name+'\n'+type+'\n';
			break;
	}
	var count = 0;
	var count_before_found = 0;
	var handleData;
	if (relation === '=')
		handleData = function(data){
			count++;
			count_before_found++;
			bFound = true;
		};
	else
		handleData = function(data){
			count++;
			if (bFound)
				return;
			count_before_found++;
			var mci = string_utils.getMciFromDataFeedKey(data);
			if (mci >= min_mci && mci <= max_mci){
				bFound = true;
				console.log('destroying stream prematurely');
				stream.destroy();
				onEnd();
			}
		};
	var bOnEndCalled = false;
	function onEnd(){
		if (bOnEndCalled)
			throw Error("second call of onEnd");
		bOnEndCalled = true;
		console.log('data feed by '+address+' '+feed_name+relation+value+': '+bFound+', '+count_before_found+' / '+count+' records inspected');
		handleResult(bFound);
	}
	var stream = kvstore.createKeyStream(options);
	stream.on('data', handleData)
	.on('end', onEnd)
	.on('error', function(error){
		throw Error('error from data stream: '+error);
	});
}

function readDataFeedValue(arrAddresses, feed_name, value, min_mci, max_mci, bAA, ifseveral, handleResult){
	var start_time = Date.now();
	var objResult = { bAbortedBecauseOfSeveral: false, value: undefined, unit: undefined, mci: undefined };
	if (bAA) {
		var arrCandidates = [];
		for (var unit in storage.assocUnstableMessages) {
			var objUnit = storage.assocUnstableUnits[unit];
			if (!objUnit)
				throw Error("unstable unit " + unit + " not in assoc");
			if (!objUnit.bAA)
				continue;
			if (_.intersection(arrAddresses, objUnit.author_addresses).length === 0)
				continue;
			storage.assocUnstableMessages[unit].forEach(function (message) {
				if (message.app !== 'data_feed')
					return;
				var payload = message.payload;
				if (!(feed_name in payload))
					return;
				var feed_value = payload[feed_name];
				if (value === null || value === feed_value || value.toString() === feed_value.toString())
					arrCandidates.push({
						value: feed_value,
						latest_included_mc_index: objUnit.latest_included_mc_index,
						level: objUnit.level,
						unit: objUnit.unit,
						mci: max_mci // it doesn't matter
					});
			});
		}
		if (arrCandidates.length === 1) {
			var feed = arrCandidates[0];
			objResult.value = feed.value;
			objResult.unit = feed.unit;
			objResult.mci = feed.mci;
			if (ifseveral === 'last')
				return handleResult(objResult);
		}
		else if (arrCandidates.length > 1) {
			if (ifseveral === 'abort') {
				objResult.bAbortedBecauseOfSeveral = true;
				return handleResult(objResult);
			}
			arrCandidates.sort(function (a, b) {
				if (a.latest_included_mc_index < b.latest_included_mc_index)
					return -1;
				if (a.latest_included_mc_index > b.latest_included_mc_index)
					return 1;
				if (a.level < b.level)
					return -1;
				if (a.level > b.level)
					return 1;
				throw Error("can't sort candidates "+a+" and "+b);
			});
			var feed = arrCandidates[arrCandidates.length - 1];
			objResult.value = feed.value;
			objResult.unit = feed.unit;
			objResult.mci = feed.mci;
			return handleResult(objResult);
		}
	}
	async.eachSeries(
		arrAddresses,
		function(address, cb){
			readDataFeedByAddress(address, feed_name, value, min_mci, max_mci, ifseveral, objResult, cb);
		},
		function(err){ // err passed here if aborted because of several
			console.log('data feed by '+arrAddresses+' '+feed_name+', val='+value+': '+objResult.value+', dfv took '+(Date.now()-start_time)+'ms');
			handleResult(objResult);
		}
	);
}

function readDataFeedByAddress(address, feed_name, value, min_mci, max_mci, ifseveral, objResult, handleResult){
	var bAbortIfSeveral = (ifseveral === 'abort');
	var key_prefix;
	if (value === null){
		key_prefix = 'dfv\n'+address+'\n'+feed_name;
	}
	else{
		var prefixed_value;
		if (typeof value === 'string'){
			var float = string_utils.getNumericFeedValue(value);
			if (float !== null)
				prefixed_value = 'n\n'+string_utils.encodeDoubleInLexicograpicOrder(float);
			else
				prefixed_value = 's\n'+value;
		}
		else
			prefixed_value = 'n\n'+string_utils.encodeDoubleInLexicograpicOrder(value);
		key_prefix = 'df\n'+address+'\n'+feed_name+'\n'+prefixed_value;
	}
	var options = {
		gte: key_prefix+'\n'+string_utils.encodeMci(max_mci),
		lte: key_prefix+'\n'+string_utils.encodeMci(min_mci),
		limit: bAbortIfSeveral ? 2 : 1
	};
	var handleData = function(data){
		if (bAbortIfSeveral && objResult.value !== undefined){
			objResult.bAbortedBecauseOfSeveral = true;
			return;
		}
		var mci = string_utils.getMciFromDataFeedKey(data.key);
		if (objResult.value === undefined || ifseveral === 'last' && mci > objResult.mci){
			if (value !== null){
				objResult.value = string_utils.getValueFromDataFeedKey(data.key);
				objResult.unit = data.value;
			}
			else{
				var arrParts = data.value.split('\n');
				objResult.value = string_utils.getFeedValue(arrParts[0]); // may convert to number
				objResult.unit = arrParts[1];
			}
			objResult.mci = mci;
		}
	};
	kvstore.createReadStream(options)
	.on('data', handleData)
	.on('end', function(){
		handleResult(objResult.bAbortedBecauseOfSeveral);
	})
	.on('error', function(error){
		throw Error('error from data stream: '+error);
	});
}

exports.dataFeedExists = dataFeedExists;
exports.readDataFeedValue = readDataFeedValue;
<commit_msg>check min/max mci when searching unstable units for data feeds<commit_after>/*jslint node: true */
"use strict";
var async = require('async');
var _ = require('lodash');
var kvstore = require('./kvstore.js');
var string_utils = require('./string_utils.js');
var storage = require('./storage.js');

function dataFeedExists(arrAddresses, feed_name, relation, value, min_mci, max_mci, bAA, handleResult){
	var start_time = Date.now();
	if (bAA) {
		var bFound = false;
		function relationSatisfied(v1, v2) {
			switch (relation) {
				case '<': return (v1 < v2);
				case '<=': return (v1 <= v2);
				case '>': return (v1 > v2);
				case '>=': return (v1 >= v2);
				default: throw Error("unknown relation: " + relation);
			}
		}
		for (var unit in storage.assocUnstableMessages) {
			var objUnit = storage.assocUnstableUnits[unit];
			if (!objUnit)
				throw Error("unstable unit " + unit + " not in assoc");
			if (!objUnit.bAA)
				continue;
			if (objUnit.latest_included_mc_index < min_mci || objUnit.latest_included_mc_index > max_mci)
				continue;
			if (_.intersection(arrAddresses, objUnit.author_addresses).length === 0)
				continue;
			storage.assocUnstableMessages[unit].forEach(function (message) {
				if (message.app !== 'data_feed')
					return;
				var payload = message.payload;
				if (!(feed_name in payload))
					return;
				var feed_value = payload[feed_name];
				if (relation === '=') {
					if (value === feed_value || value.toString() === feed_value.toString())
						bFound = true;
					return;
				}
				if (relation === '!=') {
					if (value.toString() !== feed_value.toString())
						bFound = true;
					return;
				}
				if (typeof value === 'number' && typeof feed_value === 'number') {
					if (relationSatisfied(feed_value, value))
						bFound = true;
					return;
				}
				var f_value = (typeof value === 'string') ? string_utils.getNumericFeedValue(value) : value;
				var f_feed_value = (typeof feed_value === 'string') ? string_utils.getNumericFeedValue(feed_value) : feed_value;
				if (f_value === null && f_feed_value === null) { // both are strings that don't look like numbers
					if (relationSatisfied(feed_value, value))
						bFound = true;
					return;
				}
				if (f_value !== null && f_feed_value !== null) { // both are either numbers or strings that look like numbers
					if (relationSatisfied(f_feed_value, f_value))
						bFound = true;
					return;
				}
				if (typeof value === 'string' && typeof feed_value === 'string') { // only one string looks like a number
					if (relationSatisfied(feed_value, value))
						bFound = true;
					return;
				}
				// else they are incomparable e.g. 'abc' > 123
			});
			if (bFound)
				break;
		}
		if (bFound)
			return handleResult(true);
	}
	async.eachSeries(
		arrAddresses,
		function(address, cb){
			dataFeedByAddressExists(address, feed_name, relation, value, min_mci, max_mci, cb);
		},
		function(bFound){
			console.log('data feed by '+arrAddresses+' '+feed_name+relation+value+': '+bFound+', df took '+(Date.now()-start_time)+'ms');
			handleResult(!!bFound);
		}
	);
}

function dataFeedByAddressExists(address, feed_name, relation, value, min_mci, max_mci, handleResult){
	if (relation === '!='){
		return dataFeedByAddressExists(address, feed_name, '>', value, min_mci, max_mci, function(bFound){
			if (bFound)
				return handleResult(true);
			dataFeedByAddressExists(address, feed_name, '<', value, min_mci, max_mci, handleResult);
		});
	}
	var prefixed_value;
	var type;
	if (typeof value === 'string'){
		var float = string_utils.getNumericFeedValue(value);
		if (float !== null){
			prefixed_value = 'n\n'+string_utils.encodeDoubleInLexicograpicOrder(float);
			type = 'n';
		}
		else{
			prefixed_value = 's\n'+value;
			type = 's';
		}
	}
	else{
		prefixed_value = 'n\n'+string_utils.encodeDoubleInLexicograpicOrder(value);
		type= 'n';
	}
	var strMinMci = string_utils.encodeMci(min_mci);
	var strMaxMci = string_utils.encodeMci(max_mci);
	var key_prefix = 'df\n'+address+'\n'+feed_name+'\n'+prefixed_value;
	var bFound = false;
	var options = {};
	switch (relation){
		case '=':
			options.gte = key_prefix+'\n'+strMaxMci;
			options.lte = key_prefix+'\n'+strMinMci;
			options.limit = 1;
			break;
		case '>=':
			options.gte = key_prefix;
			options.lt = 'df\n'+address+'\n'+feed_name+'\n'+type+'\r';  // \r is next after \n
			break;
		case '>':
			options.gt = key_prefix+'\nffffffff';
			options.lt = 'df\n'+address+'\n'+feed_name+'\n'+type+'\r';  // \r is next after \n
			break;
		case '<=':
			options.lte = key_prefix+'\nffffffff';
			options.gt = 'df\n'+address+'\n'+feed_name+'\n'+type+'\n';
			break;
		case '<':
			options.lt = key_prefix;
			options.gt = 'df\n'+address+'\n'+feed_name+'\n'+type+'\n';
			break;
	}
	var count = 0;
	var count_before_found = 0;
	var handleData;
	if (relation === '=')
		handleData = function(data){
			count++;
			count_before_found++;
			bFound = true;
		};
	else
		handleData = function(data){
			count++;
			if (bFound)
				return;
			count_before_found++;
			var mci = string_utils.getMciFromDataFeedKey(data);
			if (mci >= min_mci && mci <= max_mci){
				bFound = true;
				console.log('destroying stream prematurely');
				stream.destroy();
				onEnd();
			}
		};
	var bOnEndCalled = false;
	function onEnd(){
		if (bOnEndCalled)
			throw Error("second call of onEnd");
		bOnEndCalled = true;
		console.log('data feed by '+address+' '+feed_name+relation+value+': '+bFound+', '+count_before_found+' / '+count+' records inspected');
		handleResult(bFound);
	}
	var stream = kvstore.createKeyStream(options);
	stream.on('data', handleData)
	.on('end', onEnd)
	.on('error', function(error){
		throw Error('error from data stream: '+error);
	});
}

function readDataFeedValue(arrAddresses, feed_name, value, min_mci, max_mci, bAA, ifseveral, handleResult){
	var start_time = Date.now();
	var objResult = { bAbortedBecauseOfSeveral: false, value: undefined, unit: undefined, mci: undefined };
	if (bAA) {
		var arrCandidates = [];
		for (var unit in storage.assocUnstableMessages) {
			var objUnit = storage.assocUnstableUnits[unit];
			if (!objUnit)
				throw Error("unstable unit " + unit + " not in assoc");
			if (!objUnit.bAA)
				continue;
			if (objUnit.latest_included_mc_index < min_mci || objUnit.latest_included_mc_index > max_mci)
				continue;
			if (_.intersection(arrAddresses, objUnit.author_addresses).length === 0)
				continue;
			storage.assocUnstableMessages[unit].forEach(function (message) {
				if (message.app !== 'data_feed')
					return;
				var payload = message.payload;
				if (!(feed_name in payload))
					return;
				var feed_value = payload[feed_name];
				if (value === null || value === feed_value || value.toString() === feed_value.toString())
					arrCandidates.push({
						value: feed_value,
						latest_included_mc_index: objUnit.latest_included_mc_index,
						level: objUnit.level,
						unit: objUnit.unit,
						mci: max_mci // it doesn't matter
					});
			});
		}
		if (arrCandidates.length === 1) {
			var feed = arrCandidates[0];
			objResult.value = feed.value;
			objResult.unit = feed.unit;
			objResult.mci = feed.mci;
			if (ifseveral === 'last')
				return handleResult(objResult);
		}
		else if (arrCandidates.length > 1) {
			if (ifseveral === 'abort') {
				objResult.bAbortedBecauseOfSeveral = true;
				return handleResult(objResult);
			}
			arrCandidates.sort(function (a, b) {
				if (a.latest_included_mc_index < b.latest_included_mc_index)
					return -1;
				if (a.latest_included_mc_index > b.latest_included_mc_index)
					return 1;
				if (a.level < b.level)
					return -1;
				if (a.level > b.level)
					return 1;
				throw Error("can't sort candidates "+a+" and "+b);
			});
			var feed = arrCandidates[arrCandidates.length - 1];
			objResult.value = feed.value;
			objResult.unit = feed.unit;
			objResult.mci = feed.mci;
			return handleResult(objResult);
		}
	}
	async.eachSeries(
		arrAddresses,
		function(address, cb){
			readDataFeedByAddress(address, feed_name, value, min_mci, max_mci, ifseveral, objResult, cb);
		},
		function(err){ // err passed here if aborted because of several
			console.log('data feed by '+arrAddresses+' '+feed_name+', val='+value+': '+objResult.value+', dfv took '+(Date.now()-start_time)+'ms');
			handleResult(objResult);
		}
	);
}

function readDataFeedByAddress(address, feed_name, value, min_mci, max_mci, ifseveral, objResult, handleResult){
	var bAbortIfSeveral = (ifseveral === 'abort');
	var key_prefix;
	if (value === null){
		key_prefix = 'dfv\n'+address+'\n'+feed_name;
	}
	else{
		var prefixed_value;
		if (typeof value === 'string'){
			var float = string_utils.getNumericFeedValue(value);
			if (float !== null)
				prefixed_value = 'n\n'+string_utils.encodeDoubleInLexicograpicOrder(float);
			else
				prefixed_value = 's\n'+value;
		}
		else
			prefixed_value = 'n\n'+string_utils.encodeDoubleInLexicograpicOrder(value);
		key_prefix = 'df\n'+address+'\n'+feed_name+'\n'+prefixed_value;
	}
	var options = {
		gte: key_prefix+'\n'+string_utils.encodeMci(max_mci),
		lte: key_prefix+'\n'+string_utils.encodeMci(min_mci),
		limit: bAbortIfSeveral ? 2 : 1
	};
	var handleData = function(data){
		if (bAbortIfSeveral && objResult.value !== undefined){
			objResult.bAbortedBecauseOfSeveral = true;
			return;
		}
		var mci = string_utils.getMciFromDataFeedKey(data.key);
		if (objResult.value === undefined || ifseveral === 'last' && mci > objResult.mci){
			if (value !== null){
				objResult.value = string_utils.getValueFromDataFeedKey(data.key);
				objResult.unit = data.value;
			}
			else{
				var arrParts = data.value.split('\n');
				objResult.value = string_utils.getFeedValue(arrParts[0]); // may convert to number
				objResult.unit = arrParts[1];
			}
			objResult.mci = mci;
		}
	};
	kvstore.createReadStream(options)
	.on('data', handleData)
	.on('end', function(){
		handleResult(objResult.bAbortedBecauseOfSeveral);
	})
	.on('error', function(error){
		throw Error('error from data stream: '+error);
	});
}

exports.dataFeedExists = dataFeedExists;
exports.readDataFeedValue = readDataFeedValue;
<|endoftext|>


<commit_before>const corePlugins = ['scope', 'router', 'template', 'inline-styles', 'stylus', 'module-map', 'package-config', 'inline-styles-resources'];
var globalPlugins = {};

exports.plugin = function(name, plugin) {
  globalPlugins[name] = plugin;
};

exports.plugin('module-map', require('./plugins/module-map'));
exports.plugin('package-config', require('./plugins/package-config'));
exports.plugin('router', require('./plugins/router'));
exports.plugin('scope', require('./plugins/scope'));
exports.plugin('stylus', require('./plugins/stylus'));
exports.plugin('inline-styles', require('./plugins/inline-styles'));
exports.plugin('inline-styles-resources', require('./plugins/inline-styles-resources'));
exports.plugin('template', require('./plugins/template'));

exports.create = function(options) {
  var plugins = [];
  var modes = []; // all registered modes
  var pluginModes = {}; // map of modes and plugins scoped to the mode
  var modeAll = []; // plugins that are scoped to all modes

  function runPlugins(context, methodName, complete, failOver) {
    var len = 0;
    (function next(complete) {
      var plugin = plugins[len];
      len++;
      if (plugin) {
        // if plugin shouldn't work with current mode, go to next
        if ((pluginModes[context.mode] && pluginModes[context.mode].indexOf(plugin) < 0) && modeAll.indexOf(plugin) < 0) {
          next(complete);
        }

        var method = plugin[methodName];
        if (method) {
          method.call(plugin, context, next, complete);
        } else {
          next(complete);
        }
      } else {
        complete(undefined, failOver && failOver());
      }
    })(complete);
  }

  function registerPlugin(plugin) {
    var _plugin = globalPlugins[plugin] || plugin;

    var mode = _plugin.mode;
    if (mode) {
      if (_.isString(mode)) {
        mode = [mode];
      }
      _.each(mode, function(_mode) {
        if (mode === 'all') {
          // allow plugins to contribute new modes and participate in all modes
          modeAll.push(_plugin);
        } else {
          if (modes.indexOf(_mode) < 0) {
            modes.push(_mode);
            pluginModes[_mode] = [];
          }
          pluginModes[_mode].push(_plugin);
        }
      });
    } else {
      modeAll.push(_plugin);
    }
    plugins.push(_plugin);
  }

  if (!options.ignoreCorePlugins) {
    corePlugins.forEach(registerPlugin);
  }
  if (options.plugins) {
    options.plugins.forEach(registerPlugin);
  }

  return {
    use: registerPlugin,

    generatedFiles: function(context, complete) {
      runPlugins(context, 'generatedFiles', complete, function() {
        // Default to a one to one mapping for a given {platform, package, module, mode} combo
        return [ {} ];
      });
    },
    fileName: function(context, complete) {
      runPlugins(context, 'fileName', complete, function() {
        var name = context.module ? context.module.name : context.package;

        if (context.mode === 'scripts') {
          return {path: context.platformPath + name, extension: 'js'};
        } else if (context.mode === 'styles') {
          return {path: context.platformPath + name, extension: 'css'};
        }
      });
    },

    moduleResources: function(context, complete) {
      runPlugins(context, 'moduleResources', complete, function() {
        var module = context.module;
        if (context.mode === 'scripts') {
          return (module.scripts || module.files || (module.slice && module) || []).slice();
        } else if (context.mode === 'styles') {
          return (module.styles || []).slice();
        }
      });
    },
    resourceList: function(context, complete) {
      runPlugins(context, 'resourceList', complete, function() { return [context.resource]; });
    },

    file: function(context, complete) {
      runPlugins(context, 'file', complete);
    },
    module: function(context, complete) {
      runPlugins(context, 'module', complete);
    },
    resource: function(context, complete) {
      runPlugins(context, 'resource', complete, function() { return context.resource; });
    }
  };
};
<commit_msg>default module resources to the name of the current mode<commit_after>const corePlugins = ['scope', 'router', 'template', 'inline-styles', 'stylus', 'module-map', 'package-config', 'inline-styles-resources'];
var globalPlugins = {};

exports.plugin = function(name, plugin) {
  globalPlugins[name] = plugin;
};

exports.plugin('module-map', require('./plugins/module-map'));
exports.plugin('package-config', require('./plugins/package-config'));
exports.plugin('router', require('./plugins/router'));
exports.plugin('scope', require('./plugins/scope'));
exports.plugin('stylus', require('./plugins/stylus'));
exports.plugin('inline-styles', require('./plugins/inline-styles'));
exports.plugin('inline-styles-resources', require('./plugins/inline-styles-resources'));
exports.plugin('template', require('./plugins/template'));

exports.create = function(options) {
  var plugins = [];
  var modes = []; // all registered modes
  var pluginModes = {}; // map of modes and plugins scoped to the mode
  var modeAll = []; // plugins that are scoped to all modes

  function runPlugins(context, methodName, complete, failOver) {
    var len = 0;
    (function next(complete) {
      var plugin = plugins[len];
      len++;
      if (plugin) {
        // if plugin shouldn't work with current mode, go to next
        if ((pluginModes[context.mode] && pluginModes[context.mode].indexOf(plugin) < 0) && modeAll.indexOf(plugin) < 0) {
          next(complete);
        }

        var method = plugin[methodName];
        if (method) {
          method.call(plugin, context, next, complete);
        } else {
          next(complete);
        }
      } else {
        complete(undefined, failOver && failOver());
      }
    })(complete);
  }

  function registerPlugin(plugin) {
    var _plugin = globalPlugins[plugin] || plugin;

    var mode = _plugin.mode;
    if (mode) {
      if (_.isString(mode)) {
        mode = [mode];
      }
      _.each(mode, function(_mode) {
        if (mode === 'all') {
          // allow plugins to contribute new modes and participate in all modes
          modeAll.push(_plugin);
        } else {
          if (modes.indexOf(_mode) < 0) {
            modes.push(_mode);
            pluginModes[_mode] = [];
          }
          pluginModes[_mode].push(_plugin);
        }
      });
    } else {
      modeAll.push(_plugin);
    }
    plugins.push(_plugin);
  }

  if (!options.ignoreCorePlugins) {
    corePlugins.forEach(registerPlugin);
  }
  if (options.plugins) {
    options.plugins.forEach(registerPlugin);
  }

  return {
    use: registerPlugin,

    generatedFiles: function(context, complete) {
      runPlugins(context, 'generatedFiles', complete, function() {
        // Default to a one to one mapping for a given {platform, package, module, mode} combo
        return [ {} ];
      });
    },
    fileName: function(context, complete) {
      runPlugins(context, 'fileName', complete, function() {
        var name = context.module ? context.module.name : context.package;

        if (context.mode === 'scripts') {
          return {path: context.platformPath + name, extension: 'js'};
        } else if (context.mode === 'styles') {
          return {path: context.platformPath + name, extension: 'css'};
        }
      });
    },

    moduleResources: function(context, complete) {
      runPlugins(context, 'moduleResources', complete, function() {
        var module = context.module;
        return (module[context.mode] || []).slice();
      });
    },
    resourceList: function(context, complete) {
      runPlugins(context, 'resourceList', complete, function() { return [context.resource]; });
    },

    file: function(context, complete) {
      runPlugins(context, 'file', complete);
    },
    module: function(context, complete) {
      runPlugins(context, 'module', complete);
    },
    resource: function(context, complete) {
      runPlugins(context, 'resource', complete, function() { return context.resource; });
    }
  };
};
<|endoftext|>


<commit_before>'use strict';

const URL     = require('url');
const express = require('express');
const router  = express.Router();
const Wechat  = require('../service/Wechat');

module.exports = exports = function () {

  // DEBUG
  router.all('/', (req, res, next) => {
    res.status(403).send('
403 Forbidden
').end();
  });

  // 微信验证
  router.get('/api/wechat/access', require('../controller/wechat/index').wechatValidation);

  // 普通权限
  router.all('/auth/signIn', require('../controller/auth/view').signIn);
  router.all('/auth/signUp', require('../controller/auth/view').signUp);
  router.all('/auth/signOut', require('../controller/auth/view').signOut);

  router.post('/api/auth/signIn', require('../controller/auth/api').signIn);
  router.post('/api/auth/signUp', require('../controller/auth/api').signUp);

  router.get('/api/qiniu/uptoken'     , require('../controller/qiniu/uptoken').get);
  router.get('/api/qiniu/downloadUrl' , require('../controller/qiniu/download_url').get);

  router.get('/asset/:key', require('../controller/asset/image').view);

  // 运营权限
  router.all('/admin*', ensureAuthenticated);
  router.all('/admin/dashboard', require('../controller/admin/dashboard/view').index);
  router.all('/admin/activity', require('../controller/admin/activity/view').index);
  router.all('/admin/activity/:id/asset', require('../controller/admin/activity/asset/view').index);

  router.all('/api/admin*', ensureAuthenticated);
  router.post('/api/admin/activity', require('../controller/admin/activity/api').post);
  router.put('/api/admin/activity/:id', require('../controller/admin/activity/api').put);
  router.delete('/api/admin/activity/:id', require('../controller/admin/activity/api').delete);
  router.get('/api/admin/activity/:id/stat', require('../controller/admin/activity/api').getStat);

  router.post('/api/admin/asset', require('../controller/admin/activity/asset/api').post);
  router.put('/api/admin/asset/:id', require('../controller/admin/activity/asset/api').put);
  router.delete('/api/admin/asset/:id', require('../controller/admin/activity/asset/api').delete);

  // 管理员权限
  router.all('/root*', ensureAuthenticated);
  router.all('/root*', ensureAdmin);
  router.all('/root/user', require('../controller/root/user/view').index);

  router.all('/api/root*', ensureAdmin);
  router.post('/api/root/user', require('../controller/root/user/api').post);
  router.put('/api/root/user/:id', require('../controller/root/user/api').put);
  router.delete('/api/root/user/:id', require('../controller/root/user/api').delete);

  // 微信活动链接
  router.all('/wechat/*', ensureWechat);
  router.all('/wechat/*', ensureOpenId);
  router.get('/wechat/activity/:id/participate', require('../controller/wechat/activity/participate').view);

  // 错误页面
  router.all('/wechat-404.html', require('../controller/error/wechat-404').view);
  router.all('/wechat-500.html', require('../controller/error/wechat-500').view);
  router.all('/wechat-only.html', require('../controller/error/wechat-only').view);

  return router;
};

// 微信客户端检查
function ensureWechat(req, res, next) {
  let ua = req.get('User-Agent');
  if(ua && ua.indexOf('MicroMessenger') >= 0) {
    return next();
  } else {
    res.redirect('/wechat-only.html');
  }
}

// openId检查
function ensureOpenId(req, res, next) {
  let code = req.query['code'];
  if(code) {
    return Wechat.getOpenIdByCode(code).then((openId) => {
      req.query['openId'] = openId;
      next();
    }).catch((err) => {
      console.error(err, err.stack);
      res.status(500);
    });
  }
  let currentUrl = URL.format({
    protocol: req.protocol,
    host: req.get('host'),
    pathname: req.originalUrl
  });
  console.log(currentUrl);
  let redirectUrl = Wechat.getBaseAuthRedirectUrl(currentUrl);
  console.log(redirectUrl);
  res.redirect(redirectUrl);
}

// 登录检查
function ensureAuthenticated(req, res, next) {
  if (req.isAuthenticated()) {
    return next();
  }
  res.set('X-Auth-Required', 'true');
  req.session.returnUrl = req.originalUrl;
  res.redirect('/auth/signIn');
}

// 管理权限检查
function ensureAdmin(req, res, next) {
  if (req.user.canPlayRoleOf('admin')) {
    return next();
  }
  res.status(403).send('您没有权限执行该操作').end();
}<commit_msg>port debug<commit_after>'use strict';

const URL     = require('url');
const express = require('express');
const router  = express.Router();
const Wechat  = require('../service/Wechat');

module.exports = exports = function () {

  // DEBUG
  router.all('/', (req, res, next) => {
    res.status(403).send('
403 Forbidden
').end();
  });

  // 微信验证
  router.get('/api/wechat/access', require('../controller/wechat/index').wechatValidation);

  // 普通权限
  router.all('/auth/signIn', require('../controller/auth/view').signIn);
  router.all('/auth/signUp', require('../controller/auth/view').signUp);
  router.all('/auth/signOut', require('../controller/auth/view').signOut);

  router.post('/api/auth/signIn', require('../controller/auth/api').signIn);
  router.post('/api/auth/signUp', require('../controller/auth/api').signUp);

  router.get('/api/qiniu/uptoken'     , require('../controller/qiniu/uptoken').get);
  router.get('/api/qiniu/downloadUrl' , require('../controller/qiniu/download_url').get);

  router.get('/asset/:key', require('../controller/asset/image').view);

  // 运营权限
  router.all('/admin*', ensureAuthenticated);
  router.all('/admin/dashboard', require('../controller/admin/dashboard/view').index);
  router.all('/admin/activity', require('../controller/admin/activity/view').index);
  router.all('/admin/activity/:id/asset', require('../controller/admin/activity/asset/view').index);

  router.all('/api/admin*', ensureAuthenticated);
  router.post('/api/admin/activity', require('../controller/admin/activity/api').post);
  router.put('/api/admin/activity/:id', require('../controller/admin/activity/api').put);
  router.delete('/api/admin/activity/:id', require('../controller/admin/activity/api').delete);
  router.get('/api/admin/activity/:id/stat', require('../controller/admin/activity/api').getStat);

  router.post('/api/admin/asset', require('../controller/admin/activity/asset/api').post);
  router.put('/api/admin/asset/:id', require('../controller/admin/activity/asset/api').put);
  router.delete('/api/admin/asset/:id', require('../controller/admin/activity/asset/api').delete);

  // 管理员权限
  router.all('/root*', ensureAuthenticated);
  router.all('/root*', ensureAdmin);
  router.all('/root/user', require('../controller/root/user/view').index);

  router.all('/api/root*', ensureAdmin);
  router.post('/api/root/user', require('../controller/root/user/api').post);
  router.put('/api/root/user/:id', require('../controller/root/user/api').put);
  router.delete('/api/root/user/:id', require('../controller/root/user/api').delete);

  // 微信活动链接
  router.all('/wechat/*', ensureWechat);
  router.all('/wechat/*', ensureOpenId);
  router.get('/wechat/activity/:id/participate', require('../controller/wechat/activity/participate').view);

  // 错误页面
  router.all('/wechat-404.html', require('../controller/error/wechat-404').view);
  router.all('/wechat-500.html', require('../controller/error/wechat-500').view);
  router.all('/wechat-only.html', require('../controller/error/wechat-only').view);

  return router;
};

// 微信客户端检查
function ensureWechat(req, res, next) {
  let ua = req.get('User-Agent');
  if(ua && ua.indexOf('MicroMessenger') >= 0) {
    return next();
  } else {
    res.redirect('/wechat-only.html');
  }
}

// openId检查
function ensureOpenId(req, res, next) {
  let code = req.query['code'];
  if(code) {
    return Wechat.getOpenIdByCode(code).then((openId) => {
      req.query['openId'] = openId;
      next();
    }).catch((err) => {
      console.error(err, err.stack);
      res.status(500);
    });
  }
  let currentUrl = URL.format({
    protocol: req.protocol,
    host: req.get('host').replace(':80', ''),
    port: req.get('port'),
    pathname: req.originalUrl
  });
  console.log(req.get('host'),currentUrl);
  let redirectUrl = Wechat.getBaseAuthRedirectUrl(currentUrl);
  console.log(redirectUrl);
  res.redirect(redirectUrl);
}

// 登录检查
function ensureAuthenticated(req, res, next) {
  if (req.isAuthenticated()) {
    return next();
  }
  res.set('X-Auth-Required', 'true');
  req.session.returnUrl = req.originalUrl;
  res.redirect('/auth/signIn');
}

// 管理权限检查
function ensureAdmin(req, res, next) {
  if (req.user.canPlayRoleOf('admin')) {
    return next();
  }
  res.status(403).send('您没有权限执行该操作').end();
}<|endoftext|>


<commit_before>import { _, lazy_require, path, fsAsync } from 'azk';
import { publish } from 'azk/utils/postal';
import { async, originalDefer } from 'azk/utils/promises';
import { DockerBuildError } from 'azk/utils/errors';
import { spawn } from "child_process";

var lazy = lazy_require({
  JStream : 'jstream',
  XRegExp : ['xregexp', 'XRegExp'],
  archiver: 'archiver',
});

var msg_regex = {
  get building_from      () { return new lazy.XRegExp('FROM (?<FROM>.*)'); },
  get building_maintainer() { return new lazy.XRegExp('MAINTAINER (?<MAINTAINER>.*)'); },
  get building_run       () { return new lazy.XRegExp('RUN (.*)'); },
  get building_cmd       () { return new lazy.XRegExp('CMD (.*)'); },
  get building_complete  () { return new lazy.XRegExp('Successfully built (?<IMAGE_ID>.*)'); },
};

function parse_stream(msg) {
  var result = {};
  _.find(msg_regex, (regex, type) => {
    var match  = lazy.XRegExp.exec(msg, regex);

    if (match) {
      result.type = type;
      result.command = match[0];
      result.value = match[1];
      result.input = match.input;

      _.each(regex.xregexp.captureNames, function(key) {
        if (match[key]) {
          result[key] = match[key];
        }
      });
      return true;
    }
  });
  return result;
}

export function build(docker, options) {
  return async(function* () {
    var opts = _.extend({
      cache: true
    }, options);

    // Check if "Dockerfile" exist
    var dockerfile = opts.dockerfile;
    if (!(yield fsAsync.exists(dockerfile))) {
      throw new DockerBuildError('cannot_find_dockerfile', { dockerfile });
    }

    if (_.isEmpty(opts.tag)) {
      throw Error("Not build a image with a empty tag");
    }

    // Create a tar and includes Dockerfile
    var archive = lazy.archiver('tar');
    var src     = ["**", ".*", "**/.*", "!Dockerfile"];
    var cwd     = path.dirname(dockerfile);

    // Filter with .dockerignore
    var ignore  = path.join(cwd, '.dockerignore');
    var exists_ignore = yield fsAsync.exists(ignore);
    if (exists_ignore) {
      var ignore_content = yield fsAsync.readFile(ignore);
      ignore_content = ignore_content.toString()
        .trim()
        .split('\n')
        .map((entry) => {
          entry = entry.trim();
          return (_.isEmpty(entry) || entry.startsWith('#')) ? null : `!${entry}`;
        })
        .filter((entry) => entry);
      src = _.uniq(src.concat(ignore_content));
    }

    // Add files
    archive.bulk([{ expand: true, cwd, src, dest: '/' }]);
    archive.file(dockerfile, { name: 'Dockerfile' });
    if (exists_ignore) {
      archive.file(ignore, { name: '.dockerignore' });
    }
    archive.finalize();

    // Options and defer
    var done = originalDefer();

    var build_options = [ "build", "-t", opts.tag, "--force-rm" ];

    if (opts.nocache) build_options.push("--no-cache");

    if (!opts.verbose) build_options.push("--quiet");

    if (!_.isEmpty(opts.target)) build_options.push("--target", opts.target);

    // "--build-arg key=value" for each item in buildArgs object
    if (opts.buildArgs) {
      Object.keys(opts.buildArgs)
        .filter(key => !_.isEmpty(opts.buildArgs[key]))
        .forEach(key => build_options.push("--build-arg", `${key}=${opts.buildArgs[key]}`));
    }

    // "--secret id=key,src=value" for each item in secrets object
    if (opts.secrets) {
      Object.keys(opts.secrets)
        .filter(key => !_.isEmpty(opts.secrets[key]))
        .forEach(key => build_options.push("--secret", `id=${key},src=${opts.secrets[key]}`));
    }

    // last build arg is the context dir
    build_options.push(cwd);

    // Enable Docker BuildKit features
    process.env.DOCKER_BUILDKIT = 1;

    // minimum stuff.
    var spawn_cmd = spawn('docker', build_options);
    var outputs = [];

    spawn_cmd.stdout.on('data', function (data) {
      outputs.push(data);

      if (opts.verbose && opts.stdout) {
        opts.stdout.write(data);
      }
    });

    spawn_cmd.stderr.on('data', function (data) {
      outputs.push(data);

      if (opts.verbose && opts.stdout) {
        opts.stdout.write(data);
      }
    });

    spawn_cmd.on('close', function (code) {
      if (code !== 0) {
        done.reject('command_error', { output: outputs.join('\n') });

      } else {
        done.resolve(docker.findImage(opts.tag))
      }
    });

    return done.promise;
  });
}
<commit_msg>Fix error output handing if the docker build fails with BUILDKIT<commit_after>import { _, lazy_require, path, fsAsync } from 'azk';
import { publish } from 'azk/utils/postal';
import { async, originalDefer } from 'azk/utils/promises';
import { DockerBuildError } from 'azk/utils/errors';
import { spawn } from "child_process";

var lazy = lazy_require({
  JStream : 'jstream',
  XRegExp : ['xregexp', 'XRegExp'],
  archiver: 'archiver',
});

var msg_regex = {
  get building_from      () { return new lazy.XRegExp('FROM (?<FROM>.*)'); },
  get building_maintainer() { return new lazy.XRegExp('MAINTAINER (?<MAINTAINER>.*)'); },
  get building_run       () { return new lazy.XRegExp('RUN (.*)'); },
  get building_cmd       () { return new lazy.XRegExp('CMD (.*)'); },
  get building_complete  () { return new lazy.XRegExp('Successfully built (?<IMAGE_ID>.*)'); },
};

function parse_stream(msg) {
  var result = {};
  _.find(msg_regex, (regex, type) => {
    var match  = lazy.XRegExp.exec(msg, regex);

    if (match) {
      result.type = type;
      result.command = match[0];
      result.value = match[1];
      result.input = match.input;

      _.each(regex.xregexp.captureNames, function(key) {
        if (match[key]) {
          result[key] = match[key];
        }
      });
      return true;
    }
  });
  return result;
}

export function build(docker, options) {
  return async(function* () {
    var opts = _.extend({
      cache: true
    }, options);

    // Check if "Dockerfile" exist
    var dockerfile = opts.dockerfile;
    if (!(yield fsAsync.exists(dockerfile))) {
      throw new DockerBuildError('cannot_find_dockerfile', { dockerfile });
    }

    if (_.isEmpty(opts.tag)) {
      throw Error("Not build a image with a empty tag");
    }

    // Create a tar and includes Dockerfile
    var archive = lazy.archiver('tar');
    var src     = ["**", ".*", "**/.*", "!Dockerfile"];
    var cwd     = path.dirname(dockerfile);

    // Filter with .dockerignore
    var ignore  = path.join(cwd, '.dockerignore');
    var exists_ignore = yield fsAsync.exists(ignore);
    if (exists_ignore) {
      var ignore_content = yield fsAsync.readFile(ignore);
      ignore_content = ignore_content.toString()
        .trim()
        .split('\n')
        .map((entry) => {
          entry = entry.trim();
          return (_.isEmpty(entry) || entry.startsWith('#')) ? null : `!${entry}`;
        })
        .filter((entry) => entry);
      src = _.uniq(src.concat(ignore_content));
    }

    // Add files
    archive.bulk([{ expand: true, cwd, src, dest: '/' }]);
    archive.file(dockerfile, { name: 'Dockerfile' });
    if (exists_ignore) {
      archive.file(ignore, { name: '.dockerignore' });
    }
    archive.finalize();

    // Options and defer
    var done = originalDefer();

    var build_options = [ "build", "-t", opts.tag, "--force-rm" ];

    if (opts.nocache) build_options.push("--no-cache");

    if (!opts.verbose) build_options.push("--quiet");

    if (!_.isEmpty(opts.target)) build_options.push("--target", opts.target);

    // "--build-arg key=value" for each item in buildArgs object
    if (opts.buildArgs) {
      Object.keys(opts.buildArgs)
        .filter(key => !_.isEmpty(opts.buildArgs[key]))
        .forEach(key => build_options.push("--build-arg", `${key}=${opts.buildArgs[key]}`));
    }

    // "--secret id=key,src=value" for each item in secrets object
    if (opts.secrets) {
      Object.keys(opts.secrets)
        .filter(key => !_.isEmpty(opts.secrets[key]))
        .forEach(key => build_options.push("--secret", `id=${key},src=${opts.secrets[key]}`));
    }

    // last build arg is the context dir
    build_options.push(cwd);

    // Enable Docker BuildKit features
    process.env.DOCKER_BUILDKIT = 1;

    // minimum stuff.
    var spawn_cmd = spawn('docker', build_options);
    var outputs = [];

    // NOTE: most likely there will never be output from docker on stdout when buildkit is enabled
    // and we are not attached to a tty.
    // Its just how BuildKit works. The normal stdout output is really complicated
    spawn_cmd.stdout.on('data', function (data) {
      outputs.push(data);

      if (opts.verbose && opts.stdout) {
        opts.stdout.write(data);
      }
    });

    spawn_cmd.stderr.on('data', function (data) {
      outputs.push(data);

      if (opts.verbose && opts.stdout) {
        opts.stdout.write(data);
      }
    });

    spawn_cmd.on('close', function (code) {
      if (code !== 0) {
        done.reject(new DockerBuildError('command_error', { dockerfile, output: outputs.join("\n") }));
      } else {
        done.resolve(docker.findImage(opts.tag))
      }
    });

    return done.promise;
  });
}
<|endoftext|>


<commit_before>"use strict";

var colors = require('colors/safe');

function log(message) {
	// use console.error as stdout seems swallowed
	console.error(colors.gray("[STREAMLINE-PLUGIN] " + message));
}

function warn(message) {
	// use console.error as stdout seems swallowed
	console.error(colors.yellow("[STREAMLINE-PLUGIN] " + message));
}

function error(message) {
	return new Error(colors.magenta("[STREAMLINE-PLUGIN] " + message));
}

function is_(x) {
	return x.type === 'Identifier' && x.name === '_' && !x.$done;
}

function isTilde_(x) {
	return x.type === 'UnaryExpression' && x.operator === '~' && is_(x.argument);
}

function isCallbackArg(x) {
	return is_(x) || isTilde_(x);
}

function isFutureArg(x) {
	return x.type === 'UnaryExpression' && x.operator === '!' && is_(x.argument);
}

function isRShift_(x) {
	return x.type === 'BinaryExpression' && x.operator === '>>' && is_(x.left);
}

function findIndex(array, pred) {
	for (var i = 0; i < array.length; i++)
		if (pred(array[i])) return i;
	return -1;
}

function runtimeCall(t, state, name, args) {
	return t.CallExpression(
		t.memberExpression(
			t.identifier(state.runtimeVar),
			t.identifier(name)
		),
		args
	)
}

function streamlineCall(t, state, node, method, index) {
	var callee = node.callee;
	var object = callee.type === 'MemberExpression' ? callee.object : t.literal(null);
	var property = callee.type === 'MemberExpression' ?
		(callee.computed ? callee.property : t.literal(callee.property.name)) : callee;

	return t.callExpression(
		runtimeCall(t, state, method, [object, property, t.literal(index)]),
		node.arguments
	);
}

function awaitWrap(t, state, expression) {
	var rt = runtime(state);
	if (rt === "fibers") return expression;
	else return t.awaitExpression(expression);
}

function awaitCall(t, state, node, index) {
	return awaitWrap(t, state, streamlineCall(t, state, node, 'await', index));
}

function future(t, state, node, index) {
	return streamlineCall(t, state, node, 'future', index);
}

function streamlineFunction(t, state, node, index) {
	var params = node.params.slice();
	return t[node.type](
		node.id,
		node.params,
		t.blockStatement(
			[
				t.returnStatement(
					t.callExpression(
						t.memberExpression(
							runtimeCall(t, state,
								'async',
								[
									t.functionExpression(
										t.identifier((node.id || {}).name + '_'),
										params,
										node.body,
										node.generator,
										runtime(state) !== "fibers"
									),
									t.literal(index)
								],
								state
							),
							t.identifier('apply')
						),
						[t.thisExpression(), t.identifier('arguments')]
					)
				)
			]
		),
		node.generator,
		false
	);
}

function streamlineNew(t, state, node, index) {
	return t.callExpression(
		runtimeCall(t, state, 'new', [node.callee, t.literal(index)]),
		node.arguments
	);
}

function runtimeRequires(t, state) {
	function decl(name, mod, path) {
		return
	}
	var vars = [
			t.variableDeclarator(
				t.identifier(state.runtimeVar),
				t.callExpression(
					t.identifier('require'),
					[t.literal('streamline-runtime/lib/runtime-' + runtime(state))]
				)
			)
		];
	if (runtime === "callbacks") {
		vars.push(
			t.variableDeclarator(
				t.identifier('regeneratorRuntime'),
				t.memberExpression(
					t.identifier('runtime'),
					t.identifier('regeneratorRuntime')
				)
			)
		);
	}
	return t.variableDeclaration('var', vars);
}

function runtime(state) {
	var st = state.opts.extra.streamline;
	if (!st.runtime) {
		warn("streamline runtime not configured. Defaulting to await");
		st.runtime = "await";
	}
	return st.runtime;
}

function asyncProgramWrapper(t, state, node) {
	return t.expressionStatement(
		t.callExpression(
			t.memberExpression(
				t.callExpression(
					t.functionExpression(
						t.identifier(''),
						[],
						t.blockStatement(node.body),
						false,
						true),
					[]
				),
				t.identifier('then')
			),
			[
				t.functionDeclaration(
					t.identifier(''),
					[],
					t.blockStatement([])
				),
				t.functionDeclaration(
					t.identifier(''),
					[t.identifier('e')],
					t.blockStatement(
						[
							t.throwStatement(t.identifier('e'))
						]
					)
				)
			]
		)
	)
}

function canTransform(state) {
	return !(state.opts.filename && !/\._js$/.test(state.opts.filename))
}

function verbose(state) {
	var st = state.opts.extra.streamline;
	return st && st.verbose;
}

module.exports = function(pluginArguments) {
	var Plugin = pluginArguments.Plugin;
	var t = pluginArguments.types;
	return new Plugin("streamline", {
		visitor: {
			Identifier: {
				exit: function(node, parent, scope, state) {
					if (!canTransform(state)) return;
					if (is_(node) && !node.done) {
						throw state.errorWithNode(node, "unexpected _");
					}
				}
			},
			Program: {
				enter: function(node, parent, scope, state) {
					if (!state.opts.extra.streamline) state.opts.extra.streamline = {
						verbose: true, // to get diagnose
					}
					if (verbose(state)) log("transforming " + state.opts.filename);
					state.runtimeVar = scope.generateUid('streamline');
				},
				exit: function(node, parent, scope, state) {
					if (!canTransform(state)) return;
					return t.program([runtimeRequires(t, state)].concat(scope.isAsync ? asyncProgramWrapper(t, state, node) : node.body));
				}
			},
			Function: {
				enter: function(node, parent, scope, state) {
					if (!canTransform(state)) return;
					var index;
					if ((index = findIndex(node.params, is_)) >= 0) {
						var param = node.params[index];
						param.$done = true;
						if (node.generator) throw state.errorWithNode(param, "parameter _ not allowed in generator function");
						if (node.async) throw state.errorWithNode(param, "parameter _ not allowed: function already marked `async`");
						return streamlineFunction(t, state, node, index);

					}
				}
			},
			CallExpression: {
				enter: function(node, parent, scope, state) {
					if (!canTransform(state)) return;
					var callee = node.callee;
					var index;
					if ((index = findIndex(node.arguments, isCallbackArg)) >= 0) {
						node.arguments[index] = t.literal(true);
						var funcScope = scope.getFunctionParent();
						if (!funcScope.parent) {
							console.warn(state.errorWithNode(node.arguments[index], "warning: async call at top level").message);
							funcScope.isAsync = true;
						}
						return awaitCall(t, state, node, index);
					}
					if ((index = findIndex(node.arguments, isFutureArg)) >= 0) {
						node.arguments[index] = t.literal(false);
						return future(t, state, node, index);
					}
					if ((index = findIndex(node.arguments, isRShift_)) >= 0) {
						node.arguments[index] = node.arguments[index].right;
						return node;
					}
					if (is_(callee) && node.arguments.length === 2) {
						return node.arguments[0];
					}
				}
			},
			NewExpression: {
				enter: function(node, parent, scope, state) {
					if (!canTransform(state)) return;
					var index;
					if ((index = findIndex(node.arguments, is_)) >= 0) {
						node.arguments[index] = t.literal(true);
						return awaitWrap(t, state, streamlineNew(t, state, node, index));
					}
				}
			}
		}
	});
}
<commit_msg>restructured runtime dispatching<commit_after>"use strict";

var colors = require('colors/safe');

function log(message) {
	// use console.error as stdout seems swallowed
	console.error(colors.gray("[STREAMLINE-PLUGIN] " + message));
}

function warn(message) {
	// use console.error as stdout seems swallowed
	console.error(colors.yellow("[STREAMLINE-PLUGIN] " + message));
}

function error(message) {
	return new Error(colors.magenta("[STREAMLINE-PLUGIN] " + message));
}

function is_(x) {
	return x.type === 'Identifier' && x.name === '_' && !x.$done;
}

function isTilde_(x) {
	return x.type === 'UnaryExpression' && x.operator === '~' && is_(x.argument);
}

function isCallbackArg(x) {
	return is_(x) || isTilde_(x);
}

function isFutureArg(x) {
	return x.type === 'UnaryExpression' && x.operator === '!' && is_(x.argument);
}

function isRShift_(x) {
	return x.type === 'BinaryExpression' && x.operator === '>>' && is_(x.left);
}

function findIndex(array, pred) {
	for (var i = 0; i < array.length; i++)
		if (pred(array[i])) return i;
	return -1;
}

var runtimes = {
	await: {
		name: 'await',
		generator: false,
		async: true,
		extraVars: function(t, state) {
			return t.variableDeclarator(
				t.identifier('regeneratorRuntime'),
				t.memberExpression(
					t.identifier(state.runtimeVar),
					t.identifier('regeneratorRuntime')
				)
			);
		},
	},
	fibers: {
		name: 'fibers',
		generator: false,
		async: false,
	},
	galaxy: {
		name: 'galaxy',
		generator: true,
		async: false,
	}
}

function runtimeCall(t, state, name, args) {
	return t.CallExpression(
		t.memberExpression(
			t.identifier(state.runtimeVar),
			t.identifier(name)
		),
		args
	)
}

function streamlineCall(t, state, node, method, index) {
	var callee = node.callee;
	var object = callee.type === 'MemberExpression' ? callee.object : t.literal(null);
	var property = callee.type === 'MemberExpression' ?
		(callee.computed ? callee.property : t.literal(callee.property.name)) : callee;

	return t.callExpression(
		runtimeCall(t, state, method, [object, property, t.literal(index)]),
		node.arguments
	);
}

function awaitWrap(t, state, expression) {
	var rt = state.runtime;
	if (rt.async) return t.awaitExpression(expression);
	else if (rt.generator) return t.yieldExpression(expression);
	else return expression;
}

function awaitCall(t, state, node, index) {
	return awaitWrap(t, state, streamlineCall(t, state, node, 'await', index));
}

function future(t, state, node, index) {
	return streamlineCall(t, state, node, 'future', index);
}

function streamlineFunction(t, state, node, index) {
	var params = node.params.slice();
	var rt = state.runtime;
	return t[node.type](
		node.id,
		node.params,
		t.blockStatement(
			[
				t.returnStatement(
					t.callExpression(
						t.memberExpression(
							runtimeCall(t, state,
								'async',
								[
									t.functionExpression(
										t.identifier((node.id || {}).name + '_'),
										params,
										node.body,
										rt.generator,
										rt.async
									),
									t.literal(index)
								],
								state
							),
							t.identifier('apply')
						),
						[t.thisExpression(), t.identifier('arguments')]
					)
				)
			]
		),
		node.generator,
		false
	);
}

function streamlineNew(t, state, node, index) {
	return t.callExpression(
		runtimeCall(t, state, 'new', [node.callee, t.literal(index)]),
		node.arguments
	);
}

function runtimeRequires(t, state) {
	function decl(name, mod, path) {
		return
	}
	var vars = [
			t.variableDeclarator(
				t.identifier(state.runtimeVar),
				t.callExpression(
					t.identifier('require'),
					[t.literal('streamline-runtime/lib/runtime-' + state.opts.extra.streamline.runtime)]
				)
			)
		];
	if (state.runtime.extraVars) vars.push(state.runtime.extraVars(t, state));
	return t.variableDeclaration('var', vars);
}

function asyncProgramWrapper(t, state, node) {
	return t.expressionStatement(
		t.callExpression(
			t.memberExpression(
				t.callExpression(
					t.functionExpression(
						t.identifier(''),
						[],
						t.blockStatement(node.body),
						false,
						true),
					[]
				),
				t.identifier('then')
			),
			[
				t.functionDeclaration(
					t.identifier(''),
					[],
					t.blockStatement([])
				),
				t.functionDeclaration(
					t.identifier(''),
					[t.identifier('e')],
					t.blockStatement(
						[
							t.throwStatement(t.identifier('e'))
						]
					)
				)
			]
		)
	)
}

function canTransform(state) {
	return !(state.opts.filename && !/\._js$/.test(state.opts.filename))
}

function verbose(state) {
	var st = state.opts.extra.streamline;
	return st && st.verbose;
}

module.exports = function(pluginArguments) {
	var Plugin = pluginArguments.Plugin;
	var t = pluginArguments.types;
	return new Plugin("streamline", {
		visitor: {
			Identifier: {
				exit: function(node, parent, scope, state) {
					if (!canTransform(state)) return;
					if (is_(node) && !node.done) {
						throw state.errorWithNode(node, "unexpected _");
					}
				}
			},
			Program: {
				enter: function(node, parent, scope, state) {
					if (!state.opts.extra.streamline) state.opts.extra.streamline = {
						verbose: true, // to get diagnose
					}
					var st = state.opts.extra.streamline;
					if (!st.runtime) {
						warn("streamline runtime not configured. Defaulting to await");
						st.runtime = "await";
					}
					state.runtime = runtimes[st.runtime];
					if (!state.runtime) throw new Error("invalid runtime configuration: " + st.runtime);

					if (verbose(state)) log("transforming " + state.opts.filename);
					state.runtimeVar = scope.generateUid('streamline');
				},
				exit: function(node, parent, scope, state) {
					if (!canTransform(state)) return;
					return t.program([runtimeRequires(t, state)].concat(scope.isAsync ? asyncProgramWrapper(t, state, node) : node.body));
				}
			},
			Function: {
				enter: function(node, parent, scope, state) {
					if (!canTransform(state)) return;
					var index;
					if ((index = findIndex(node.params, is_)) >= 0) {
						var param = node.params[index];
						param.$done = true;
						if (node.generator) throw state.errorWithNode(param, "parameter _ not allowed in generator function");
						if (node.async) throw state.errorWithNode(param, "parameter _ not allowed: function already marked `async`");
						return streamlineFunction(t, state, node, index);

					}
				}
			},
			CallExpression: {
				enter: function(node, parent, scope, state) {
					if (!canTransform(state)) return;
					var callee = node.callee;
					var index;
					if ((index = findIndex(node.arguments, isCallbackArg)) >= 0) {
						node.arguments[index] = t.literal(true);
						var funcScope = scope.getFunctionParent();
						if (!funcScope.parent) {
							console.warn(state.errorWithNode(node.arguments[index], "warning: async call at top level").message);
							funcScope.isAsync = true;
						}
						return awaitCall(t, state, node, index);
					}
					if ((index = findIndex(node.arguments, isFutureArg)) >= 0) {
						node.arguments[index] = t.literal(false);
						return future(t, state, node, index);
					}
					if ((index = findIndex(node.arguments, isRShift_)) >= 0) {
						node.arguments[index] = node.arguments[index].right;
						return node;
					}
					if (is_(callee) && node.arguments.length === 2) {
						return node.arguments[0];
					}
				}
			},
			NewExpression: {
				enter: function(node, parent, scope, state) {
					if (!canTransform(state)) return;
					var index;
					if ((index = findIndex(node.arguments, is_)) >= 0) {
						node.arguments[index] = t.literal(true);
						return awaitWrap(t, state, streamlineNew(t, state, node, index));
					}
				}
			}
		}
	});
}
<|endoftext|>


<commit_before>var path = require('path');
var fs = require('fs');

function Commandable() {
	var self = this;
	this.commands = {};
	this.loggedin = {};
	var isDirty = false;

	var storagePath = "storage";
	// Determine if botgroup, or bot
	if (this.isBot) {
		// bot
		storagePath = path.join(storagePath, self.group.alias);

		if (!fs.existsSync(storagePath)) {
			fs.mkdirSync(storagePath);
		}
	}

	storagePath = path.join(storagePath, self.alias);
	if (!fs.existsSync(storagePath)) {
		fs.mkdirSync(storagePath);
	}

	storagePath = path.join(storagePath, "commands.json");
	storagePath = Core.relativeToAbsolute(storagePath);

	this.on('tick', function() {
		if (isDirty) {
			var cmds = {};

			for(var i in self.commands) {
				if (self.commands[i].options.persist) {
					cmds[i] = {};
				    for (var attr in self.commands[i]) {
        				if (self.commands[i].hasOwnProperty(attr)) cmds[i][attr] = self.commands[i][attr];
					}

					cmds[i].callback = cmds[i].callback.toString();
				}
			}

			fs.writeFile(storagePath, JSON.stringify(cmds, null, 4), function (err) {
				if (err) {
					console.log("[Commandable.js] There was an issue saving the config: ", err);
				}

			});

			isDirty = false;
		}
	});

	// Can't always tell who sent this function call. In BotGroup multiple bots could execute this call.
	this.functionCanExecute = function(server, command, message) {
		var timerOverridden = false;

		console.tmp("fce", 1);
		var curdate = message.Timestamp.getTime();

		// Check for channel timer exceptions
		for(var i = 0; i < command.options.exceptions.channels.length; i++) {
			if (command.options.exceptions.users[i].match == message.To.Parts[0]) {
				timerOverridden = true;

				if (curdate - command.options.exceptions.channels[i].time < command.options.timer) {
					return false;
				}
				command.options.exceptions.channels[i].time = curdate;
				break;
			}
		}
		console.tmp("fce", 2);
		// Check for user timer exceptions
		for(var i = 0; i < command.options.exceptions.users.length; i++) {
			if (command.options.exceptions.users[i].match.test(message.Parts[0])) {
				timerOverridden = true;

				if (curdate - command.options.exceptions.users[i].time < command.options.timer) {
					return false;
				}
				command.options.exceptions.users[i].time = curdate;
				break;
			}
		}

		var diff = curdate - command.time;
		console.tmp("fce", 3, diff, command.options.timer);
		if (command.options.timer != 0 && !timerOverridden && diff <= command.options.timer) {
			return false;
		}

		var level = 1;
		if (self.loggedin[server.alias] && self.loggedin[server.alias][message.From.Parts[0]]) {
			level = self.loggedin[server.alias][message.From.Parts[0]].level;
		}
		console.tmp("fce", 4, level, command.options.level);
		if (command.options.level > level) {
			return false;
		}

		console.tmp("fce", 5);

		command.time = curdate;
		return true;
	}

	this.on("OnPrivmsg", function(server, msg, sender) {
		var cmd = msg.Parts[3].substring(1).toLowerCase();

		if (self.commands.hasOwnProperty(cmd)) {

			var bot = self;
			var group = self;

			var channel = server.isChannel(msg.To.Parts[0]) ?
				server.Channels[msg.To.Parts[0]] :
				{"isChannel":false, "Display":msg.From.Parts[0], "Parts":["", "", msg.To.Parts[0]]};

			if (!bot.isBot) {
				bot = sender;
			}
			else {
				group = self.group;
			}

			if (group.botIsExecutor(server.alias, bot.alias, channel) && this.functionCanExecute(server, self.commands[cmd], msg)) {
				var lines = [];

				global.echo = Core.createLogWrapper(lines,  channel.Display);

				bot.lastChannel = (msg.To.Type == "Client" ? msg.From.Parts[0] : msg.To.Parts[0]);
				bot.lastNetwork = server.alias;

				self.commands[cmd].callback(server, channel, msg, bot, group);

				bot.sockets[server.alias].Write(lines);
			}
		}

	});

	this.addCommand = function(string, options, fn) {
		if (!fn) {
			fn = options;
			options = JSON.parse(JSON.stringify(Core.defaultOptions));;
		}
		string = string.toLowerCase();

		if (typeof fn != "function") {
			throw {"message":"Invalid data type passed for function parameter.", "stack":new Error().stack};
		}
		var defaultopt = JSON.parse(JSON.stringify(Core.defaultOptions));

		for(var key in defaultopt) {

			if (defaultopt.hasOwnProperty(key) && undefined === options[key])
				options[key] = defaultopt[key];
		}

		options["timer"] = options["timer"] * 1000;
		if (options["persist"]) {
			isDirty = true;
		}

		self.commands[string] = {
			"command":string,
			"options":options,
			"time":0,
			"callback":fn
		};
	}

	this.setCommand = function(string, options, fn) {
		if ("function" == typeof options) {
			fn = options;
			options = {};
		}
		string = string.toLowerCase();

		// merge user supplied options to our command
		for(var i in options) {
			if (options.hasOwnProperty(i)) {
				if (self.commands[string].options[i]) {
					isDirty = true;
					self.commands[string].options[i] = options[i];
				}
				else {
					return false;
				}
			}
		}

		if (options["timer"])
			self.commands[string].options["timer"] *= 1000;

		if (fn) {
			isDirty = true;
			self.commands[string].callback = fn;
		}

		self.commands[string].time = 0;
		return true;
	}

	this.delCommand = function(string) {
		string = string.toLowerCase();
		if (self.commands[string]) {
			delete self.commands[string];
			isDirty = true;
		}
	}

	this.addException = function(string, type, on, seconds) {
		var exceptionEntry = {
			"type":type, // channel, user, chanmode
			"timer":seconds,
			"time":0,
			"match":on
		};

		string = string.toLowerCase();
		if (!self.commands[string]) return false;
		if (!self.commands[string].options.exceptions[type]) throw "Invalid Exception type provided: " + type;

		self.commands[string].options.exceptions[type].push(exceptionEntry);
		return true;
	}

	this.listExceptions = function(string, type) {
		string = string.toLowerCase();
		if (!self.commands[string]) return null;
		if (!self.commands[string].options.exceptions[type]) throw "Invalid Exception type provided: " + type;

		return self.commands[string].options.exceptions[type];
	}

	this.removeException = function(string, type, on) {

		string = string.toLowerCase();
		if (!self.commands[string]) return false;
		if (!self.commands[string].options.exceptions[type]) throw "Invalid Exception type provided: " + type;

		self.commands[string].options.exceptions[type].splice(on, 1);

		return true;
	}

	// (list/add/remove) Bind the command to server-aliases/prefix#channel. Use * for wildcard. (ie:ggxy or ggxy/#ggxy or ggxy/~#ggxy.*)",
	this.addLocationBind = function(string, svr, channel, mode) {
		string = string.toLowerCase();
		if (!mode) mode = /./;
		if (!channel) channel = /./;
		if (!svr) svr = /./;

		var locationBindEntry = {
			"server": new RegExp(svr.replace(/\*/g, ".*?")),
			"channel":new RegExp(channel.replace(/\*/g, ".*?")),
			"mode":new RegExp(mode.replace(/\*/g, ".*?"))
		};

		self.commands[string].options.locationbind.push(locationBindEntry);

		return true;
	}

	this.listLocationBind = function(string) {
		string = string.toLowerCase();
		if (!self.commands[string]) return null;

		return self.commands[string].options.locationbind;
	}

	this.removeLocationBind = function(string, on) {
		string = string.toLowerCase();
		if (!self.commands[string]) return false;

		self.commands[string].options.locationbind.splice(on, 1);
		return true;
	}

	var USER_REGEX = /[!@]/;

	this.attemptLogin = function(server, groupname, channel, msg) {
		var indx = 0;
		if (!self.networks[server.alias].isChannel(msg.Parts[2])) {
			var auths = Core.config.Auth;

			for(var i = 0; i < auths.length; i++) {
				if (auths[i].BotGroup) {
					if (auths[i].BotGroup.indexOf(groupname) == -1) {
						continue;
					}
				}

				var parts = auths[i].login.replace(/\./g,"\\.").replace(/\*/g, ".*").split(USER_REGEX);

				if (new RegExp(parts[0]).test(msg.From.Parts[0]) && new RegExp(parts[1]).test(msg.From.Parts[1]) &&
						new RegExp(parts[2]).test(msg.From.Parts[2])) {

					eval("function enc(pw) " + auths[i].encryption);

					if (enc(msg.Parts[4]) == auths[i].password) {
						if (!self.loggedin[server.alias]) self.loggedin[server.alias] = {}

						self.loggedin[server.alias][msg.From.Parts[0]] = {"nick":msg.From.Parts[0], "level":auths[i].level};
						return true;
					}
				}
			}
		}

		return false;
	}

	fs.readFile(storagePath, {"encoding":"utf8"}, function (err, data) {
		if (undefined == data) return;

		var svrs = JSON.parse(data);
		for(var i in svrs) {
			self.commands[i] = svrs[i];
			var newcallback = self.commands[i].callback.replace(/function\s*[A-z\-0-9]*\(\s*([^)]*)*\)\s*{((?:.+|\s*)*)\s*}/, "$2");
			self.commands[i].callback = new Function(['server', 'channel', 'msg', 'bot', 'group'], newcallback);
		}
	});
}

module.exports = Commandable;<commit_msg>Fixes #23 also<commit_after>var path = require('path');
var fs = require('fs');

function Commandable() {
	var self = this;
	this.commands = {};
	this.loggedin = {};
	var isDirty = false;

	var storagePath = "storage";
	// Determine if botgroup, or bot
	if (this.isBot) {
		// bot
		storagePath = path.join(storagePath, self.group.alias);

		if (!fs.existsSync(storagePath)) {
			fs.mkdirSync(storagePath);
		}
	}

	storagePath = path.join(storagePath, self.alias);
	if (!fs.existsSync(storagePath)) {
		fs.mkdirSync(storagePath);
	}

	storagePath = path.join(storagePath, "commands.json");
	storagePath = Core.relativeToAbsolute(storagePath);

	this.on('tick', function() {
		if (isDirty) {
			var cmds = {};

			for(var i in self.commands) {
				if (self.commands[i].options.persist) {
					cmds[i] = {};
				    for (var attr in self.commands[i]) {
        				if (self.commands[i].hasOwnProperty(attr)) cmds[i][attr] = self.commands[i][attr];
					}

					cmds[i].callback = cmds[i].callback.toString();
				}
			}

			fs.writeFile(storagePath, JSON.stringify(cmds, null, 4), function (err) {
				if (err) {
					console.log("[Commandable.js] There was an issue saving the config: ", err);
				}

			});

			isDirty = false;
		}
	});

	// Can't always tell who sent this function call. In BotGroup multiple bots could execute this call.
	this.functionCanExecute = function(server, command, message) {
		var timerOverridden = false;

		console.tmp("fce", 1);
		var curdate = message.Timestamp.getTime();

		// Check for channel timer exceptions
		for(var i = 0; i < command.options.exceptions.channels.length; i++) {
			if (command.options.exceptions.users[i].match == message.To.Parts[0]) {
				timerOverridden = true;

				if (curdate - command.options.exceptions.channels[i].time < command.options.timer) {
					return false;
				}
				command.options.exceptions.channels[i].time = curdate;
				break;
			}
		}
		console.tmp("fce", 2);
		// Check for user timer exceptions
		for(var i = 0; i < command.options.exceptions.users.length; i++) {
			if (command.options.exceptions.users[i].match.test(message.Parts[0])) {
				timerOverridden = true;

				if (curdate - command.options.exceptions.users[i].time < command.options.timer) {
					return false;
				}
				command.options.exceptions.users[i].time = curdate;
				break;
			}
		}

		var diff = curdate - command.time;
		console.tmp("fce", 3, diff, command.options.timer);
		if (command.options.timer != 0 && !timerOverridden && diff <= command.options.timer) {
			return false;
		}

		var level = 1;
		if (self.loggedin[server.alias] && self.loggedin[server.alias][message.From.Parts[0]]) {
			level = self.loggedin[server.alias][message.From.Parts[0]].level;
		}
		console.tmp("fce", 4, level, command.options.level);
		if (command.options.level > level) {
			return false;
		}

		console.tmp("fce", 5);

		command.time = curdate;
		return true;
	}

	this.on("OnPrivmsg", function(server, msg, sender) {
		var cmd = msg.Parts[3].substring(1).toLowerCase();

		if (self.commands.hasOwnProperty(cmd)) {

			var bot = self;
			var group = self;

			var channel = server.isChannel(msg.To.Parts[0]) ?
				server.Channels[msg.To.Parts[0]] :
				{"isChannel":false, "Display":msg.From.Parts[0], "Parts":["", "", msg.To.Parts[0]]};

			if (!bot.isBot) {
				bot = sender;
			}
			else {
				group = self.group;
			}

			if ( (self.isBot || group.botIsExecutor(server.alias, bot.alias, channel) ) && this.functionCanExecute(server, self.commands[cmd], msg)) {
				var lines = [];

				global.echo = Core.createLogWrapper(lines,  channel.Display);

				bot.lastChannel = (msg.To.Type == "Client" ? msg.From.Parts[0] : msg.To.Parts[0]);
				bot.lastNetwork = server.alias;

				self.commands[cmd].callback(server, channel, msg, bot, group);

				bot.sockets[server.alias].Write(lines);
			}
		}

	});

	this.addCommand = function(string, options, fn) {
		if (!fn) {
			fn = options;
			options = JSON.parse(JSON.stringify(Core.defaultOptions));;
		}
		string = string.toLowerCase();

		if (typeof fn != "function") {
			throw {"message":"Invalid data type passed for function parameter.", "stack":new Error().stack};
		}
		var defaultopt = JSON.parse(JSON.stringify(Core.defaultOptions));

		for(var key in defaultopt) {

			if (defaultopt.hasOwnProperty(key) && undefined === options[key])
				options[key] = defaultopt[key];
		}

		options["timer"] = options["timer"] * 1000;
		if (options["persist"]) {
			isDirty = true;
		}

		self.commands[string] = {
			"command":string,
			"options":options,
			"time":0,
			"callback":fn
		};
	}

	this.setCommand = function(string, options, fn) {
		if ("function" == typeof options) {
			fn = options;
			options = {};
		}
		string = string.toLowerCase();

		// merge user supplied options to our command
		for(var i in options) {
			if (options.hasOwnProperty(i)) {
				if (self.commands[string].options[i]) {
					isDirty = true;
					self.commands[string].options[i] = options[i];
				}
				else {
					return false;
				}
			}
		}

		if (options["timer"])
			self.commands[string].options["timer"] *= 1000;

		if (fn) {
			isDirty = true;
			self.commands[string].callback = fn;
		}

		self.commands[string].time = 0;
		return true;
	}

	this.delCommand = function(string) {
		string = string.toLowerCase();
		if (self.commands[string]) {
			delete self.commands[string];
			isDirty = true;
		}
	}

	this.addException = function(string, type, on, seconds) {
		var exceptionEntry = {
			"type":type, // channel, user, chanmode
			"timer":seconds,
			"time":0,
			"match":on
		};

		string = string.toLowerCase();
		if (!self.commands[string]) return false;
		if (!self.commands[string].options.exceptions[type]) throw "Invalid Exception type provided: " + type;

		self.commands[string].options.exceptions[type].push(exceptionEntry);
		return true;
	}

	this.listExceptions = function(string, type) {
		string = string.toLowerCase();
		if (!self.commands[string]) return null;
		if (!self.commands[string].options.exceptions[type]) throw "Invalid Exception type provided: " + type;

		return self.commands[string].options.exceptions[type];
	}

	this.removeException = function(string, type, on) {

		string = string.toLowerCase();
		if (!self.commands[string]) return false;
		if (!self.commands[string].options.exceptions[type]) throw "Invalid Exception type provided: " + type;

		self.commands[string].options.exceptions[type].splice(on, 1);

		return true;
	}

	// (list/add/remove) Bind the command to server-aliases/prefix#channel. Use * for wildcard. (ie:ggxy or ggxy/#ggxy or ggxy/~#ggxy.*)",
	this.addLocationBind = function(string, svr, channel, mode) {
		string = string.toLowerCase();
		if (!mode) mode = /./;
		if (!channel) channel = /./;
		if (!svr) svr = /./;

		var locationBindEntry = {
			"server": new RegExp(svr.replace(/\*/g, ".*?")),
			"channel":new RegExp(channel.replace(/\*/g, ".*?")),
			"mode":new RegExp(mode.replace(/\*/g, ".*?"))
		};

		self.commands[string].options.locationbind.push(locationBindEntry);

		return true;
	}

	this.listLocationBind = function(string) {
		string = string.toLowerCase();
		if (!self.commands[string]) return null;

		return self.commands[string].options.locationbind;
	}

	this.removeLocationBind = function(string, on) {
		string = string.toLowerCase();
		if (!self.commands[string]) return false;

		self.commands[string].options.locationbind.splice(on, 1);
		return true;
	}

	var USER_REGEX = /[!@]/;

	this.attemptLogin = function(server, groupname, channel, msg) {
		var indx = 0;
		if (!self.networks[server.alias].isChannel(msg.Parts[2])) {
			var auths = Core.config.Auth;

			for(var i = 0; i < auths.length; i++) {
				if (auths[i].BotGroup) {
					if (auths[i].BotGroup.indexOf(groupname) == -1) {
						continue;
					}
				}

				var parts = auths[i].login.replace(/\./g,"\\.").replace(/\*/g, ".*").split(USER_REGEX);

				if (new RegExp(parts[0]).test(msg.From.Parts[0]) && new RegExp(parts[1]).test(msg.From.Parts[1]) &&
						new RegExp(parts[2]).test(msg.From.Parts[2])) {

					eval("function enc(pw) " + auths[i].encryption);

					if (enc(msg.Parts[4]) == auths[i].password) {
						if (!self.loggedin[server.alias]) self.loggedin[server.alias] = {}

						self.loggedin[server.alias][msg.From.Parts[0]] = {"nick":msg.From.Parts[0], "level":auths[i].level};
						return true;
					}
				}
			}
		}

		return false;
	}

	fs.readFile(storagePath, {"encoding":"utf8"}, function (err, data) {
		if (undefined == data) return;

		var svrs = JSON.parse(data);
		for(var i in svrs) {
			self.commands[i] = svrs[i];
			var newcallback = self.commands[i].callback.replace(/function\s*[A-z\-0-9]*\(\s*([^)]*)*\)\s*{((?:.+|\s*)*)\s*}/, "$2");
			self.commands[i].callback = new Function(['server', 'channel', 'msg', 'bot', 'group'], newcallback);
		}
	});
}

module.exports = Commandable;<|endoftext|>


<commit_before>/**
 * Created by sahara on 2016/12/23.
 */
var jm = require('jm-ms-daorouter');
var async=require('async');
var ms = jm.ms;
var logger = jm.getLogger('jm-acl');
module.exports = function (service, opts) {
    var role = service.role;
    var acl = service.acl;
    var router = ms();
    var roleResources=function (opts, cb) {
        var id=opts.params.id;
        var role=opts.data.code;
        acl.whatResources(role,function (err,doc) {
            if(err){
                 logger.error(err);
                 return cb(err,null);
            }
            cb(null,doc)
        });
    };
    //获取某角色的用户
    var _roleUsers=function (opts, cb) {
        var id=opts.params.id;
        acl.roleUsers(id,function (err,doc) {
            if(err){
                logger.error(err);
                return cb(err,null);
            }
            cb(null,{rows:doc})
        });
    };
    //移除角色的某些资源的某些权限
    var _remove=function (opts, cb) {
        var roles=opts.data.roles;
        var resources=opts.data.resources;
        var permissions=opts.data.permissions;
        if(permissions){
            acl.removeAllow(roles, resources, permissions,cb);
        }else{
            acl.removeAllow(roles, resources,cb);
        }
    };
    //给某些角色增加某些资源的某些权限
    var _setResourcePermission=function (opts, cb) {
        var roles=opts.data.roles;
        var allows=opts.data.addPermission;
        var remove=opts.data.removePermission;
        async.series({
            flag1:function(done){
                async.each(remove,function (item,callback) {
                    if(item.permissions){
                        service.removeAllow(roles,item.resources,item.permissions, function (error,doc) {
                            if(!error){
                                callback();
                            }else {
                                done(error, null);
                            }
                        });
                    }else {
                        callback();
                    }
                },function (error, doc) {
                    if(!error){
                        done(null,doc);
                    }else {
                        done(error, null);
                    }
                });
            },
            flag2:function(done){
                acl.allow([{roles:roles,allows: allows}],function (error,doc) {
                    if(!error){
                        done(null,doc);
                    }else {
                        done(error, null);
                    }
                });
            }
        },function(error,result){
            if(error){
                cb(error, null);
            }else {
               cb(null,{ret:"1"});
            }
        });
    };
    router
        .add('/:id/resources','get',roleResources)
        .add('/:id/user','get',_roleUsers )
        .add('/:id/resource','post',_setResourcePermission)
        .add('/:id/resource','delete',_remove)
        .use(service.routes.filter_creator)
        .use(ms.daorouter(role))
    ;

    role.routes.before_list = function (opts, cb, next) {
        opts.conditions = {};
        if(opts.data.creator){
            opts.conditions['creator']=opts.data.creator;
        }
        next();
    };
    role.routes.after_create = function(opts, cb, next){
        if(opts.doc.parents){
                acl.addRoleParents(opts.doc.code,opts.doc.parents,function (err, doc) {
                    if(err){
                        opts.err = err;
                    }
                    next();
                })
            }else{
                next();
            }
    };
    role.routes.before_update = function(opts, cb, next){
        if(opts.data.parents){
            acl.removeRoleParents(this.role.codeById(opts.params.id), function (err, doc) {
                if(err){
                    opts.err = err;
                }
                next();
            })
        }else{
            next();
        }
    };
    role.routes.after_update = function(opts, cb, next){
        if(opts.data.parents){
            acl.addRoleParents(this.role.codeById(opts.params.id),opts.doc.parents,function (err, doc) {
                if(err){
                    opts.err = err;
                }
                next();
            })
        }else{
            next();
        }
    };
    role.routes.before_remove = function(opts, cb, next){
        var id = opts.params.id;
        var roleId=[id];
        var roleCode = [];
        async.waterfall([
            function(cb){//获取其子角色
                role.findOne({_id:id},function(err,doc){
                    if(err) return cb(err);
                    if(!doc) return cb({err:-1,msg:'角色不存在'});
                    roleCode.push(doc.code);
                    role.find({parents: doc.code },function(err,ary){
                        if(err) return cb(err);
                            ary.forEach(function (item) {
                                roleCode.push(item.code);
                                roleId.push(item._id)
                            });
                        cb(null,roleCode);
                    });
                });
            },
            function(roleCode,cb){//移除角色关系表(包含子角色)
                async.each(roleCode,function(code,callback){
                    acl.removeRole(code,function(err,doc){
                        if(err) return callback(err);
                        callback();
                    });
                },function(err){
                    if(err) return cb(err);
                    cb(null,roleCode);
                });
            },
            function (roleCode,cb) {//获取拥有此角色的用户
                var userIds = [];
                async.each(roleCode,function(code,callback){
                    acl.roleUsers(code,function(err,docs){
                        if(err) return callback(err);
                        docs.forEach(function (item) {
                            if(userIds.indexOf(item)==-1){
                                userIds.push(item);
                            }
                        });
                        callback();
                    });
                },function(err){
                    if(err) return cb(err);
                    cb(null,userIds);
                });
            },
            function (userIds,cb) {//移除用户角色关系
                console.log(roleCode);
                async.each(userIds,function(id,callback){
                    acl.removeUserRoles(id,roleCode,function(err,doc){
                        if(err) return callback(err);
                        callback();
                    });
                },function(err){
                    if(err) return cb(err);
                    cb(null,userIds);
                });
            }
        ], function (err, results) {
                if(err){
                    opts.err=err;
                }
                console.log(roleId);
                opts.params.id=roleId;
                next();
        });
    };
    return router;
};<commit_msg>调整/acl/roles/:id/resources接口逻辑<commit_after>/**
 * Created by sahara on 2016/12/23.
 */
var jm = require('jm-ms-daorouter');
var async=require('async');
var ms = jm.ms;
var logger = jm.getLogger('jm-acl');
var mongoose = require('mongoose');
var ObjectId = mongoose.Types.ObjectId;

module.exports = function (service, opts) {
    var role = service.role;
    var acl = service.acl;
    var router = ms();
    var roleResources=function (opts, cb) {
        var id = opts.params.id;
        var roles = id;
        if (ObjectId.isValid(id)) {
            roles = role.codeById(id);
        }
        roles = opts.data.code || roles;
        roles = Array.isArray(roles) ? roles : roles.toString().split(',');

        acl.whatResources(roles, function (err, doc) {
            if (err) {
                logger.error(err);
                return cb(err, null);
            }
            cb(null, doc)
        });
    };
    //获取某角色的用户
    var _roleUsers=function (opts, cb) {
        var id=opts.params.id;
        acl.roleUsers(id,function (err,doc) {
            if(err){
                logger.error(err);
                return cb(err,null);
            }
            cb(null,{rows:doc})
        });
    };
    //移除角色的某些资源的某些权限
    var _remove=function (opts, cb) {
        var roles=opts.data.roles;
        var resources=opts.data.resources;
        var permissions=opts.data.permissions;
        if(permissions){
            acl.removeAllow(roles, resources, permissions,cb);
        }else{
            acl.removeAllow(roles, resources,cb);
        }
    };
    //给某些角色增加某些资源的某些权限
    var _setResourcePermission=function (opts, cb) {
        var roles=opts.data.roles;
        var allows=opts.data.addPermission;
        var remove=opts.data.removePermission;
        async.series({
            flag1:function(done){
                async.each(remove,function (item,callback) {
                    if(item.permissions){
                        service.removeAllow(roles,item.resources,item.permissions, function (error,doc) {
                            if(!error){
                                callback();
                            }else {
                                done(error, null);
                            }
                        });
                    }else {
                        callback();
                    }
                },function (error, doc) {
                    if(!error){
                        done(null,doc);
                    }else {
                        done(error, null);
                    }
                });
            },
            flag2:function(done){
                acl.allow([{roles:roles,allows: allows}],function (error,doc) {
                    if(!error){
                        done(null,doc);
                    }else {
                        done(error, null);
                    }
                });
            }
        },function(error,result){
            if(error){
                cb(error, null);
            }else {
               cb(null,{ret:"1"});
            }
        });
    };
    router
        .add('/:id/resources','get',roleResources)
        .add('/:id/user','get',_roleUsers )
        .add('/:id/resource','post',_setResourcePermission)
        .add('/:id/resource','delete',_remove)
        .use(service.routes.filter_creator)
        .use(ms.daorouter(role))
    ;

    role.routes.before_list = function (opts, cb, next) {
        opts.conditions = {};
        if(opts.data.creator){
            opts.conditions['creator']=opts.data.creator;
        }
        next();
    };
    role.routes.after_create = function(opts, cb, next){
        if(opts.doc.parents){
                acl.addRoleParents(opts.doc.code,opts.doc.parents,function (err, doc) {
                    if(err){
                        opts.err = err;
                    }
                    next();
                })
            }else{
                next();
            }
    };
    role.routes.before_update = function(opts, cb, next){
        if(opts.data.parents){
            acl.removeRoleParents(this.role.codeById(opts.params.id), function (err, doc) {
                if(err){
                    opts.err = err;
                }
                next();
            })
        }else{
            next();
        }
    };
    role.routes.after_update = function(opts, cb, next){
        if(opts.data.parents){
            acl.addRoleParents(this.role.codeById(opts.params.id),opts.doc.parents,function (err, doc) {
                if(err){
                    opts.err = err;
                }
                next();
            })
        }else{
            next();
        }
    };
    role.routes.before_remove = function(opts, cb, next){
        var id = opts.params.id;
        var roleId=[id];
        var roleCode = [];
        async.waterfall([
            function(cb){//获取其子角色
                role.findOne({_id:id},function(err,doc){
                    if(err) return cb(err);
                    if(!doc) return cb({err:-1,msg:'角色不存在'});
                    roleCode.push(doc.code);
                    role.find({parents: doc.code },function(err,ary){
                        if(err) return cb(err);
                            ary.forEach(function (item) {
                                roleCode.push(item.code);
                                roleId.push(item._id)
                            });
                        cb(null,roleCode);
                    });
                });
            },
            function(roleCode,cb){//移除角色关系表(包含子角色)
                async.each(roleCode,function(code,callback){
                    acl.removeRole(code,function(err,doc){
                        if(err) return callback(err);
                        callback();
                    });
                },function(err){
                    if(err) return cb(err);
                    cb(null,roleCode);
                });
            },
            function (roleCode,cb) {//获取拥有此角色的用户
                var userIds = [];
                async.each(roleCode,function(code,callback){
                    acl.roleUsers(code,function(err,docs){
                        if(err) return callback(err);
                        docs.forEach(function (item) {
                            if(userIds.indexOf(item)==-1){
                                userIds.push(item);
                            }
                        });
                        callback();
                    });
                },function(err){
                    if(err) return cb(err);
                    cb(null,userIds);
                });
            },
            function (userIds,cb) {//移除用户角色关系
                console.log(roleCode);
                async.each(userIds,function(id,callback){
                    acl.removeUserRoles(id,roleCode,function(err,doc){
                        if(err) return callback(err);
                        callback();
                    });
                },function(err){
                    if(err) return cb(err);
                    cb(null,userIds);
                });
            }
        ], function (err, results) {
                if(err){
                    opts.err=err;
                }
                console.log(roleId);
                opts.params.id=roleId;
                next();
        });
    };
    return router;
};<|endoftext|>