UNPKG

dalao-proxy

Version:

An expandable HTTP proxy based on the plug-in system for frontend developers with request caching request mock and development!

295 lines (244 loc) 8.46 kB
const { Command, Option } = require('commander'); const Context = require('./context'); const ConfigParser = require('./parser/config-parser'); const { register } = require('./plugin'); const Runtime = require('./runtime'); const originCommandFn = Command.prototype.command; const originOptionFn = Command.prototype.option; const originActionFn = Command.prototype.action; Command.DALAO_ENV = { development: 'DEV' }; Command.DALAO_WORKER = { worker: 'DALAO_WORKER', master: 'DALAO_MASTER' }; // Expose states so plugins can access Command.prototype.context = Command.context = new Context(); /** * @public */ Command.prototype.reload = function reloadProgram(...args) { Runtime.reloadProgram(this.context.program, ...args); }; /** * @public */ Command.prototype.use = function use(command) { command.call(this, this, register); return this; }; /** * @public * Find subcommand by name */ Command.prototype.findCommand = function findCommand(subcommandName) { return subcommandName && this.commands.find(it => it.name() === subcommandName || it.alias() === subcommandName); }; /** * @public * Overwrite command action function */ Command.prototype.overwriteAction = function (overwriteFn) { const self = this; removeActionListener(this._name); if (this._alias) { removeActionListener(this._alias); } this.action(overwriteFn); function removeActionListener(name) { const listenerName = 'command:' + name; const parent = self.parent || self; const listeners = parent.listeners(listenerName); if (listeners.length > 1) { parent.removeListener(listenerName, listeners.pop()); } } }; /** * @public * Enable the program read user input and emit 'input' event */ Command.prototype.enableInput = function () { this.context.program._enableInput = true; }; /** * @public * Enable the server collect each real proxy request's data and response's data */ Command.prototype.enableCollectData = function () { this.context.program._collectingData = true; }; /** * @public * Enable the server collect each client request's data and response's data */ Command.prototype.enableCollectProxyData = function () { this.context.program._collectingProxyData = true; }; /** * @public * Return whether the server is collecting real proxy data * * @returns {Boolean} */ Command.prototype.isCollectingData = function () { return this.context.program._collectingData; }; /** * @public * Return whether the server is collecting client data * * @returns {Boolean} */ Command.prototype.isCollectingProxyData = function () { return this.context.program._collectingProxyData; }; /** * @public * The program is a worker process * @returns {Boolean} */ Command.prototype.isWorker = function () { return process.env.DALAO_WORKER === Command.DALAO_WORKER.worker; }; /** * @public * Overwrite original method and adding extra features */ Command.prototype.command = function commandWrapper() { const commandName = arguments[0].split(/ +/).shift(); this.on('command:' + commandName, () => { this.context.command = this.findCommand(commandName); this.context.commandName = commandName; register.emit('command:' + commandName, arguments); }); return originCommandFn.apply(this, arguments); }; Command.prototype.option = function optionWrapper(flags, description, fn, defaultValue) { originOptionFn.call(this, flags, description, fn, defaultValue); const option = new Option(flags, description); const optionName = option.name(); const optionAttributeName = option.attributeName(); this.on('option:' + optionName, val => { this.context.options[optionAttributeName] = val || this[optionAttributeName]; }); return this; }; Command.prototype.action = function actionWrapper(callback) { this._actionFn = callback; return originActionFn.call(this, (...args) => { this.options.forEach(option => { const optionAttributeName = option.attributeName(); this.context.options[optionAttributeName] = this[optionAttributeName]; }); return callback.call(this, ...args); }) }; /** * forward subcommand * @description the `fn` parameter is called just like `#action` method when no subcommand called * @param {Function} [fn] */ Command.prototype.forwardSubcommands = function (fn) { var self = this; var listener = function (args, unknown) { // Parse any so-far unknown options args = args || []; unknown = unknown || []; let command; if (args.length || unknown.length) { // whether the first command is the registered command command = self.findCommand(args[0]); if (command) { // parse subcommand if ((unknown.includes('--help') || unknown.includes('-h'))) { command.outputHelp(); process.exit(0); } else { var parsed = command.parseOptions(unknown); // if (parsed.args.length) args = parsed.args.concat(args); if (parsed.args.length) args = args.concat(parsed.args); unknown = parsed.unknown; } } else { command = self; var parsed = self.parseOptions(unknown); unknown = parsed.unknown; if (unknown.length > 0) { if ((unknown.includes('--help') || unknown.includes('-h'))) { command.outputHelp(); process.exit(0); } else { command.unknownOption(unknown[0]); } } if (typeof (fn) !== 'function') { console.warn('error: unknown subcommand \'' + args[0] + '\'\n'); command.help(); return; } if (parsed.args.length) args = parsed.args.concat(args); self._args.forEach(function (arg, i) { if (arg.required && args[i] == null) { self.missingArgument(arg.name); } else if (arg.variadic) { if (i !== self._args.length - 1) { self.variadicArgNotLast(arg.name); } args[i] = args.splice(i); } }); // The .forwardSubcommands callback takes an extra parameter which is the command itself. var expectedArgsCount = self._args.length; var actionArgs = args.slice(0, expectedArgsCount); actionArgs[expectedArgsCount] = self; // Add the extra arguments so available too. if (args.length > expectedArgsCount) { actionArgs.push(args.slice(expectedArgsCount)); } fn.apply(self, actionArgs); return; } } else { command = self; if ((unknown.includes('--help') || unknown.includes('-h'))) { self.outputHelp(); process.exit(0); } else if (fn) { fn.call(self); return; } else { self.outputHelp(); process.exit(0); } } self.parseArgs(args, unknown); }; var parent = this.parent || this; var name = parent === this ? '*' : this._name; parent.on('command:' + name, listener); if (this._alias) parent.on('command:' + this._alias, listener); this.on('command:*', function () { this.help(); }); return this; }; const entryProgram = new Command(); entryProgram.context.program = entryProgram; exports.program = entryProgram; exports.Runtime = Runtime; exports.Context = Context; exports.ConfigParser = ConfigParser; exports.parserEmitter = ConfigParser.emitter; // Commands exports.commands = { start: require('./commands/start.command'), ca: require('./commands/ca.command'), init: require('./commands/init.command'), pluginManager: require('./commands/plugin-manager.command') };