'use strict';

Object.defineProperty(exports, "__esModule", {
	value: true
});
exports.CatProxy = undefined;

var _typeof2 = require('babel-runtime/helpers/typeof');

var _typeof3 = _interopRequireDefault(_typeof2);

var _toConsumableArray2 = require('babel-runtime/helpers/toConsumableArray');

var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2);

var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');

var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);

var _createClass2 = require('babel-runtime/helpers/createClass');

var _createClass3 = _interopRequireDefault(_createClass2);

var _regenerator = require('babel-runtime/regenerator');

var _regenerator2 = _interopRequireDefault(_regenerator);

var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator');

var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);

var _http = require('http');

var _http2 = _interopRequireDefault(_http);

var _https = require('https');

var _https2 = _interopRequireDefault(_https);

var _extendMime = require('./extendMime');

var _extendMime2 = _interopRequireDefault(_extendMime);

var _defCfg = require('./config/defCfg');

var _defCfg2 = _interopRequireDefault(_defCfg);

var _config = require('./config/config');

var config = _interopRequireWildcard(_config);

var _merge = require('merge');

var _merge2 = _interopRequireDefault(_merge);

var _promise = require('promise');

var _promise2 = _interopRequireDefault(_promise);

var _log = require('./log');

var _log2 = _interopRequireDefault(_log);

var _requestSerives = require('./requestSerives');

var _events = require('events');

var _events2 = _interopRequireDefault(_events);

var _cert2 = require('./cert/cert.js');

var _httpsProxySer = require('./httpsProxySer');

var _app = require('./web/app');

var _app2 = _interopRequireDefault(_app);

var _getLocalIps = require('./getLocalIps');

var _tools = require('./tools');

var _requestMiddleware = require('./requestMiddleware');

var requestMiddleware = _interopRequireWildcard(_requestMiddleware);

var _configProps = require('./config/configProps');

var _configProps2 = _interopRequireDefault(_configProps);

var _util = require('util');

var _util2 = _interopRequireDefault(_util);

var _rule = require('./config/rule');

var rule = _interopRequireWildcard(_rule);

var _express = require('express');

var _express2 = _interopRequireDefault(_express);

var _webCfg = require('./config/webCfg');

var _webCfg2 = _interopRequireDefault(_webCfg);

var _path = require('path');

var _path2 = _interopRequireDefault(_path);

var _ws = require('./ws/ws');

var _ws2 = _interopRequireDefault(_ws);

function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

//	process.env.NODE_ENV
var getLocalUiReg = function getLocalUiReg(port) {
	var ips = _getLocalIps.localIps.slice(0);
	ips.push('localhost');
	var l = ips.length;
	return ips.reduce(function (result, cur, index) {
		if (index > 0) {
			result += "|";
		}
		result += '(?:' + cur;
		if (port !== 80 || port !== 443) {
			result += ':' + port + ')';
		} else {
			result += ")";
		}
		// 最后一次
		if (index === l - 1) {
			return new RegExp(result, "i");
		}
		return result;
	}, "^(?:http|ws)(?:s?)://");
};
/**
 * 按顺序调用数组，每个步骤返回promise
 * @arr 表示要执行的数据
 * @result表示执行的结果，结果会进行合并，结果必须是一个object
 * @context 表示执行的上下文
 */
var execArrByStep = function () {
	var _ref = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee(arr, result, context) {
		var _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, cur, newRes;

		return _regenerator2.default.wrap(function _callee$(_context) {
			while (1) {
				switch (_context.prev = _context.next) {
					case 0:
						result = result || {};

						if (!(!arr || !arr.length)) {
							_context.next = 3;
							break;
						}

						return _context.abrupt('return', result);

					case 3:
						_iteratorNormalCompletion = true;
						_didIteratorError = false;
						_iteratorError = undefined;
						_context.prev = 6;
						_iterator = arr[Symbol.iterator]();

					case 8:
						if (_iteratorNormalCompletion = (_step = _iterator.next()).done) {
							_context.next = 17;
							break;
						}

						cur = _step.value;
						_context.next = 12;
						return cur.call(context, result);

					case 12:
						newRes = _context.sent;

						// 修改了引用
						if (newRes !== result) {
							result = (0, _merge2.default)(result, newRes);
						}

					case 14:
						_iteratorNormalCompletion = true;
						_context.next = 8;
						break;

					case 17:
						_context.next = 23;
						break;

					case 19:
						_context.prev = 19;
						_context.t0 = _context['catch'](6);
						_didIteratorError = true;
						_iteratorError = _context.t0;

					case 23:
						_context.prev = 23;
						_context.prev = 24;

						if (!_iteratorNormalCompletion && _iterator.return) {
							_iterator.return();
						}

					case 26:
						_context.prev = 26;

						if (!_didIteratorError) {
							_context.next = 29;
							break;
						}

						throw _iteratorError;

					case 29:
						return _context.finish(26);

					case 30:
						return _context.finish(23);

					case 31:
						return _context.abrupt('return', result);

					case 32:
					case 'end':
						return _context.stop();
				}
			}
		}, _callee, this, [[6, 19, 23, 31], [24,, 26, 30]]);
	}));

	return function execArrByStep(_x, _x2, _x3) {
		return _ref.apply(this, arguments);
	};
}();

var CatProxy = function () {
	/**
  * 
  * @param  {[type]} option 
  *  {
  *  	type: "当前服务器类型"
  *		port: "当前http端口",
  *    httpsPort: "当前https服务器端口",
  *		certHost: "https证书生成默认host代理",
  *		crackHttps 是否解开 https请求，在 http代理模式下,
  *		log: '日志级别',
  *		uiPort 端口
  *	}
  *	@param servers 自定义服务器,最多同时开启2个服务器，一个http一个https, 2个服务器的时候顺序是http,https  	如果只有一个则没有顺序问题
  *
  *  @param saveProps 要同步到文件的字段 为空则全部同步
  *
  */
	function CatProxy(opt, saveProps) {
		(0, _classCallCheck3.default)(this, CatProxy);

		this.option = {};
		// 初始化配置文件
		(0, config.default)();
		var certDir = (0, _cert2.getCertDir)();
		_log2.default.info('\u5F53\u524D\u8BC1\u4E66\u76EE\u5F55\uFF1A ' + certDir);
		// 读取缓存配置文件
		var fileCfg = {};
		_configProps2.default.forEach(function (current) {
			var val = config.get(current);
			if (val !== undefined && val !== null) {
				fileCfg[current] = val;
			}
		});
		// 混合三种配置
		var cfg = _merge2.default.recursive({}, _defCfg2.default, fileCfg, opt);
		if (saveProps && saveProps.length) {
			this.option.saveProps = saveProps;
			// 配置了保存字段，则只保存这些字段
			config.setSaveProp.apply(config, (0, _toConsumableArray3.default)(saveProps));
		}
		// 将用户当前设置保存到缓存配置文件
		_configProps2.default.forEach(function (current) {
			if (cfg[current] !== null && cfg[current] !== undefined) {
				// 为‘’表示要删除这个字段
				if (cfg[current] === '' && config.get(current)) {
					config.del(current);
				} else {
					config.set(current, cfg[current]);
				}
			}
		});
		config.save();
		this._beforeReqEvt = [];
		this._beforeResEvt = [];
		this._afterResEvt = [];
		this._pipeRequestEvt = [];
	}

	(0, _createClass3.default)(CatProxy, [{
		key: 'init',
		value: function init() {
			var _this = this;

			var com = this;
			// 'hosts', "log", 'breakHttps', 'excludeHttps', 'sni' 可以通过 进程修改的字段
			// 别的进程发送的消息
			process.on('message', function (message) {
				if (!message.result || !(0, _typeof3.default)(message.result) === 'object') {
					return;
				}
				_log2.default.debug('receive message');
				if (message.type) {
					switch (message.type) {
						case "config":
							var data = {};
							config.set(message.result);
							// 所有配置均不保存
							config.save([]);
							com.setLogLevel();
							break;
						default:
							_log2.default.error('收到未知的消息', message);
					}
				}
			});
			this.setLogLevel();
			// dangerous options
			process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0;
			return _promise2.default.resolve().then(this.createCache.bind(this)).then(this.checkParam.bind(this)).then(this.checkEnv.bind(this)).then(this.createServer.bind(this)).then(this.uiInit.bind(this)).then(null, function (err) {
				_this.errorHandle(err);
				process.exit(1);
			});
		}
		// 创建缓存，创建请求保存

	}, {
		key: 'createCache',
		value: function createCache() {}
	}, {
		key: 'checkParam',
		value: function checkParam() {}
		// 设置 日志级别

	}, {
		key: 'setLogLevel',
		value: function setLogLevel(logLevel) {
			if (logLevel) {
				config.set('log', logLevel);
				_log2.default.transports.console.level = config.get('log');
				config.save('log');
			} else {
				_log2.default.transports.console.level = config.get('log');
			}
		}
		// 设置服务器类别

	}, {
		key: 'setServerType',
		value: function setServerType(type) {
			config.set('type', type);
			config.save('type');
		}
		// 设置服务器端口

	}, {
		key: 'setHttpPort',
		value: function setHttpPort(port) {
			port = +port;
			config.set('port', port);
			config.save('port');
		}
	}, {
		key: 'setHttpsPort',
		value: function setHttpsPort(port) {
			port = +port;
			config.set('httpsPort', port);
			config.save('httpsPort');
		}
		// 设置ui端口

	}, {
		key: 'setUiPort',
		value: function setUiPort(port) {
			port = +port;
			config.set('uiPort', port);
			config.save('uiPort');
		}
		// 设置sni类型

	}, {
		key: 'setSniType',
		value: function setSniType(type) {
			config.set("sni", type);
			config.save('sni');
		}
		// 设置破解https

	}, {
		key: 'setBreakHttps',
		value: function setBreakHttps(list) {
			config.set('breakHttps', list);
			config.save('breakHttps');
		}
		// 设置排除https列表

	}, {
		key: 'setExcludeHttps',
		value: function setExcludeHttps(list) {
			config.set('excludeHttps', list);
			config.save('excludeHttps');
		}
	}, {
		key: 'setRules',
		value: function setRules(rules) {
			rule.saveRules(rules);
		}
		// 获取配置

	}, {
		key: 'getConfig',
		value: function getConfig(key) {
			if (typeof key === 'string') {
				return config.get(key);
			}
			return config.get();
		}
	}, {
		key: 'setConfig',
		value: function setConfig() {
			config.set.apply(config, arguments);
			config.save();
		}
		// 环境检测

	}, {
		key: 'checkEnv',
		value: function checkEnv() {}
	}, {
		key: 'uiInit',
		value: function uiInit() {
			var _this2 = this;

			var port = config.get('uiPort');
			var isAutoOpen = config.get('autoOpen');
			var p = port;
			// 如果port是0 则只提供下载链接的server
			return _promise2.default.resolve(p || (0, _tools.getPort)()).then(function (p) {
				// 内置服务器初始化
				var host = 'http://' + _getLocalIps.localIps[0] + ':' + p;
				var uiOption = {
					port: p,
					hostname: _getLocalIps.localIps[0],
					host: host,
					wsServerUrl: host + _webCfg2.default.wsPath,
					cdnBasePath: _path2.default.join('/c', _webCfg2.default.cdnBasePath),
					env: _webCfg2.default.env
				};
				// 写成正则，判断是否是ui的一个访问地址
				_this2.localUiReg = getLocalUiReg(p);
				var uiApp = (0, _app2.default)(!!port);
				var app = (0, _express2.default)();
				var uiServer = app.listen(p, function () {
					_log2.default.info('catproxy 规则配置地址：' + host + "/c/index");
					_log2.default.info('catproxy 监控界面地址：' + host + "/c/m");
					if (port && isAutoOpen) {
						(0, _tools.openCmd)(host + "/c/index");
					}
				});
				uiApp.locals.uiOption = uiOption;
				uiServer.on('error', function (err) {
					(0, _tools.error)(err);
					process.exit(1);
				});
				// 字app
				app.use("/c", uiApp);
				_this2.ui = {
					app: app,
					uiServer: uiServer
				};
			}).then(function () {
				if (port) {
					return (0, _ws2.default)(_this2.ui.uiServer, _this2);
				}
			}).then(function (wsServer) {
				if (wsServer) {
					_this2.ui.wsServer = wsServer;
				}
			});
		}
		// 出错处理

	}, {
		key: 'errorHandle',
		value: function errorHandle(err) {
			if (err) {
				_log2.default.error(err);
			}
			return _promise2.default.reject(err);
		}
		// 根据配置创建服务器

	}, {
		key: 'createServer',
		value: function createServer() {
			var opt = config.get();
			var servers = this.servers || [];
			var com = this;
			// 可以自定义server或者用系统内置的server
			if (opt.type === 'http' && !servers[0]) {
				servers[0] = _http2.default.createServer();
			} else if (opt.type === 'https' && !servers[0]) {
				// 找到证书，创建https的服务器
				var _getCert = (0, _cert2.getCert)(opt.certHost),
				    key = _getCert.privateKey,
				    cert = _getCert.cert;

				servers[0] = _https2.default.createServer({ key: key, cert: cert, rejectUnauthorized: false, SNICallback: _httpsProxySer.SNICallback });
			} else if (opt.type === 'all' && !servers[0] && !servers[1]) {
				servers[0] = _http2.default.createServer();

				var _getCert2 = (0, _cert2.getCert)(opt.certHost),
				    _key = _getCert2.privateKey,
				    _cert = _getCert2.cert;

				servers[1] = _https2.default.createServer({ key: _key, cert: _cert, rejectUnauthorized: false, SNICallback: _httpsProxySer.SNICallback });
			}
			var requestFun = requestMiddleware.middleWare(_requestSerives.requestHandler);
			servers.forEach(function (server) {
				server.catProxy = com;
				// 如果在http下代理https，则需要过度下请求
				if (server instanceof _http2.default.Server) {
					server.on('connect', _requestSerives.requestConnectHandler);
				}
				server.on('upgrade', _requestSerives.requestUpgradeHandler);
				server.on('request', function (req, res) {
					if (req.headers.upgrade) {
						return;
					}
					requestFun.call(this, req, res);
				});
				server.on('clientError', function (err, con) {
					_log2.default.error('ser-clientError' + err);
				});
				var serverType = server instanceof _http2.default.Server ? 'http' : 'https';
				var port = serverType === 'http' ? opt.port : opt.httpsPort;
				// 如果server没有被监听，则调用默认端口监听
				if (!server.listening) {
					// 根据server的类型调用不同的端口
					server.listen(port, function () {
						_log2.default.info('代理服务器启动于：' + (serverType + '://' + _getLocalIps.localIps[0] + ':' + port));
					});
				}
				server.on('error', function (err) {
					(0, _tools.error)(err);
					process.exit(1);
				});
			});
			this.servers = servers;
		}
		// 想服务器添加request事件

	}, {
		key: 'use',
		value: function use(fun) {
			requestMiddleware.use(fun);
			return this;
		}
		// 在中转请求前，可以用于修改reqInfo

	}, {
		key: 'onBeforeReq',
		value: function onBeforeReq() {
			var _this3 = this;

			for (var _len = arguments.length, fun = Array(_len), _key2 = 0; _key2 < _len; _key2++) {
				fun[_key2] = arguments[_key2];
			}

			fun.forEach(function (f) {
				return _util2.default.isFunction(f) && _this3._beforeReqEvt.push(f);
			});
		}
		// 请求结束，可以用于产看请求结果

	}, {
		key: 'onAfterRes',
		value: function onAfterRes() {
			var _this4 = this;

			for (var _len2 = arguments.length, fun = Array(_len2), _key3 = 0; _key3 < _len2; _key3++) {
				fun[_key3] = arguments[_key3];
			}

			fun.forEach(function (f) {
				return _util2.default.isFunction(f) && _this4._afterResEvt.push(f);
			});
		}
		// 获得中转请求前，可以用于修改resInfo

	}, {
		key: 'onBeforeRes',
		value: function onBeforeRes() {
			var _this5 = this;

			for (var _len3 = arguments.length, fun = Array(_len3), _key4 = 0; _key4 < _len3; _key4++) {
				fun[_key4] = arguments[_key4];
			}

			fun.forEach(function (f) {
				return _util2.default.isFunction(f) && _this5._beforeResEvt.push(f);
			});
		}
	}, {
		key: 'onPipeRequest',
		value: function onPipeRequest() {
			var _this6 = this;

			for (var _len4 = arguments.length, fun = Array(_len4), _key5 = 0; _key5 < _len4; _key5++) {
				fun[_key5] = arguments[_key5];
			}

			fun.forEach(function (f) {
				return _util2.default.isFunction(f) && _this6._pipeRequestEvt.push(f);
			});
		}
		/**
   * 触发req事件，result表示参数，context表示上下文
   * result 格式看evt中的格式
   */

	}, {
		key: 'triggerBeforeReq',
		value: function triggerBeforeReq(result, context) {
			return execArrByStep(this._beforeReqEvt, result, context);
		}
		/**
   * 触发 请求前事件
   *  result 格式看evt中的格式
   *  context为上下文
   */

	}, {
		key: 'triggerBeforeRes',
		value: function triggerBeforeRes(result, context) {
			return execArrByStep(this._beforeResEvt, result, context);
		}
		/**
   * 触发请求后事件
   *  result 格式看evt中的格式
   *  context为上下文
   */

	}, {
		key: 'triggerAfterRes',
		value: function triggerAfterRes(result, context) {
			if (this._afterResEvt.length) {
				this._afterResEvt.forEach(function (current) {
					try {
						current.call(context, result);
					} catch (e) {
						_log2.default.error(e);
					}
				});
			}
		}
		/**
   * 触发穿过请求
   *  result 格式看evt中的格式
   *  context为上下文
   */

	}, {
		key: 'triggerPipeReq',
		value: function triggerPipeReq(result, context) {
			if (this._pipeRequestEvt.length) {
				this._pipeRequestEvt.forEach(function (current) {
					try {
						current.call(context, result);
					} catch (e) {
						_log2.default.error(e);
					}
				});
			}
		}
	}]);
	return CatProxy;
}();

exports.default = CatProxy;
exports.CatProxy = CatProxy;