'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var _toConsumableArray = require('@babel/runtime/helpers/toConsumableArray');
var _regeneratorRuntime = require('@babel/runtime/regenerator');
var _asyncToGenerator = require('@babel/runtime/helpers/asyncToGenerator');
var _slicedToArray = require('@babel/runtime/helpers/slicedToArray');
var _classCallCheck = require('@babel/runtime/helpers/classCallCheck');
var _createClass = require('@babel/runtime/helpers/createClass');
var _defineProperty = require('@babel/runtime/helpers/defineProperty');
var _server = require('../.server');
var BodyParser = require('./BodyParser');
var Engine = require('./Engine');
var FileServer = require('./FileServer');
var Logger = require('./Logger');
var Router = require('./Router');
var fs = require('fs');
var http = require('http');
var https = require('https');
var path = require('path');
var Response = require('./Response');
var Request = require('./Request');
var utils = require('@teclone/utils');
var Wrapper = require('./Wrapper');
var EntityTooLargeException = require('../Exceptions/EntityTooLargeException');
var Utils = require('./Utils');
var dotenv = require('dotenv');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

function _interopNamespace(e) {
  if (e && e.__esModule) return e;
  var n = Object.create(null);
  if (e) {
    Object.keys(e).forEach(function (k) {
      if (k !== 'default') {
        var d = Object.getOwnPropertyDescriptor(e, k);
        Object.defineProperty(n, k, d.get ? d : {
          enumerable: true,
          get: function () {
            return e[k];
          }
        });
      }
    });
  }
  n['default'] = e;
  return Object.freeze(n);
}

var _toConsumableArray__default = /*#__PURE__*/_interopDefaultLegacy(_toConsumableArray);
var _regeneratorRuntime__default = /*#__PURE__*/_interopDefaultLegacy(_regeneratorRuntime);
var _asyncToGenerator__default = /*#__PURE__*/_interopDefaultLegacy(_asyncToGenerator);
var _slicedToArray__default = /*#__PURE__*/_interopDefaultLegacy(_slicedToArray);
var _classCallCheck__default = /*#__PURE__*/_interopDefaultLegacy(_classCallCheck);
var _createClass__default = /*#__PURE__*/_interopDefaultLegacy(_createClass);
var _defineProperty__default = /*#__PURE__*/_interopDefaultLegacy(_defineProperty);
var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
var path__namespace = /*#__PURE__*/_interopNamespace(path);

function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }

function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }

function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
var App = /*#__PURE__*/function () {
  function App(options) {
    _classCallCheck__default['default'](this, App);

    _defineProperty__default['default'](this, "constructOptions", void 0);

    _defineProperty__default['default'](this, "httpServer", null);

    _defineProperty__default['default'](this, "httpsServer", null);

    _defineProperty__default['default'](this, "entryPath", '');

    _defineProperty__default['default'](this, "config", void 0);

    _defineProperty__default['default'](this, "router", new Router.Router(false));

    _defineProperty__default['default'](this, "mountedRouters", []);

    _defineProperty__default['default'](this, "logger", void 0);

    _defineProperty__default['default'](this, "bodyParser", void 0);

    _defineProperty__default['default'](this, "errorCallback", null);

    var _ref = options || {},
        configFile = _ref.configFile,
        _ref$config = _ref.config,
        config = _ref$config === void 0 ? {} : _ref$config;

    this.constructOptions = options || {};
    /* istanbul ignore else */

    this.entryPath = process.cwd();
    this.config = this.resolveConfig(this.entryPath, configFile, config);
    this.loadEnv(this.entryPath, this.config.env);
    this.logger = new Logger.Logger(this.config);
    this.bodyParser = new BodyParser.BodyParser(this.config);
    this.createServers();
  }

  _createClass__default['default'](App, [{
    key: "createServers",
    value: function createServers() {
      var _this = this;

      var _this$constructOption = this.constructOptions,
          _this$constructOption2 = _this$constructOption.Request,
          RequestToUse = _this$constructOption2 === void 0 ? Request.Request : _this$constructOption2,
          _this$constructOption3 = _this$constructOption.Response,
          ResponseToUse = _this$constructOption3 === void 0 ? Response.Response : _this$constructOption3;
      this.httpServer = http.createServer({
        ServerResponse: ResponseToUse,
        IncomingMessage: RequestToUse
      }, null); //setup https server if it is enabled

      var httpsConfig = this.config.https;

      if (httpsConfig.enabled) {
        var options = {
          ServerResponse: ResponseToUse,
          IncomingMessage: RequestToUse
        };
        Object.entries(httpsConfig.credentials).reduce(function (result, _ref2) {
          var _ref3 = _slicedToArray__default['default'](_ref2, 2),
              key = _ref3[0],
              value = _ref3[1];

          result[key] = key === 'passphrase' ? key : fs__namespace.readFileSync(path__namespace.resolve(_this.entryPath, value));
          return result;
        }, options);
        this.httpsServer = https.createServer(options, null);
      }
    }
    /**
     * returns the env variable
     */

  }, {
    key: "env",
    get: function get() {
      return this.config.env;
    }
    /**
     * load env settings
     */

  }, {
    key: "loadEnv",
    value: function loadEnv(entryPath, env) {
      try {
        dotenv.config();
        dotenv.config({
          path: path__namespace.resolve(entryPath, ".".concat(env))
        });
      } catch (ex) {}
    }
    /**
     * resolves and merges the configuration objects
     */

  }, {
    key: "resolveConfig",
    value: function resolveConfig(entryPath, configFile, config) {
      var configFromFile;

      if (configFile) {
        var absPath = path__namespace.resolve(entryPath, configFile);

        if (fs__namespace.existsSync(absPath)) {
          configFromFile = require(absPath);
        }
      }

      var resolvedConfig = utils.copy({}, _server.rServerConfig, configFromFile, config);
      resolvedConfig.env = resolvedConfig.env || process.env.NODE_ENV || 'development'; // resolve to numeric value

      resolvedConfig.maxMemory = utils.expandToNumeric(resolvedConfig.maxMemory); // resolve ports

      if (!resolvedConfig.port) {
        resolvedConfig.port = Number.parseInt(process.env.PORT || '8000');
      }

      if (!resolvedConfig.https.port) {
        resolvedConfig.https.port = Number.parseInt(process.env.HTTPS_PORT || '9000');
      }

      resolvedConfig.entryPath = entryPath;
      return resolvedConfig;
    }
    /**
     * returns server intro
     */

  }, {
    key: "getServerIntro",
    value: function getServerIntro(server) {
      var result = {
        name: server instanceof https.Server ? 'Https' : 'Http',
        address: ''
      };

      if (server.listening) {
        var _ref4 = server.address(),
            address = _ref4.address,
            port = _ref4.port;
        /* istanbul ignore else */


        if (address === '::') {
          result.address = "".concat(result.name.toLowerCase(), "://localhost:").concat(port, "/");
        } else {
          result.address = "".concat(result.name.toLowerCase(), "://").concat(address, ":").concat(port, "/");
        }
      }

      return result;
    }
    /**
     * runs the array of route instances until a matched route is found
     */

  }, {
    key: "runRoutes",
    value: function () {
      var _runRoutes = _asyncToGenerator__default['default']( /*#__PURE__*/_regeneratorRuntime__default['default'].mark(function _callee(method, engine, router) {
        var routes, _iterator, _step, route;

        return _regeneratorRuntime__default['default'].wrap(function _callee$(_context) {
          while (1) {
            switch (_context.prev = _context.next) {
              case 0:
                routes = router.getRoutes()[method];
                _iterator = _createForOfIteratorHelper(routes);
                _context.prev = 2;

                _iterator.s();

              case 4:
                if ((_step = _iterator.n()).done) {
                  _context.next = 12;
                  break;
                }

                route = _step.value;
                _context.next = 8;
                return engine.process(route);

              case 8:
                if (!_context.sent) {
                  _context.next = 10;
                  break;
                }

                return _context.abrupt("return", true);

              case 10:
                _context.next = 4;
                break;

              case 12:
                _context.next = 17;
                break;

              case 14:
                _context.prev = 14;
                _context.t0 = _context["catch"](2);

                _iterator.e(_context.t0);

              case 17:
                _context.prev = 17;

                _iterator.f();

                return _context.finish(17);

              case 20:
                return _context.abrupt("return", false);

              case 21:
              case "end":
                return _context.stop();
            }
          }
        }, _callee, null, [[2, 14, 17, 20]]);
      }));

      function runRoutes(_x, _x2, _x3) {
        return _runRoutes.apply(this, arguments);
      }

      return runRoutes;
    }()
    /**
     * cordinates how routes are executed, including mounted routes
     */

  }, {
    key: "cordinateRoutes",
    value: function () {
      var _cordinateRoutes = _asyncToGenerator__default['default']( /*#__PURE__*/_regeneratorRuntime__default['default'].mark(function _callee2(url, method, request, response) {
        var engine, _iterator2, _step2, mountedRouter, middlewares;

        return _regeneratorRuntime__default['default'].wrap(function _callee2$(_context2) {
          while (1) {
            switch (_context2.prev = _context2.next) {
              case 0:
                method = method.toLowerCase(); //create the engine

                engine = new Engine.Engine(url, method, request, response); //run main router

                engine.use(this.router.getMiddlewares());
                _context2.next = 5;
                return this.runRoutes(method, engine, this.router);

              case 5:
                if (!_context2.sent) {
                  _context2.next = 7;
                  break;
                }

                return _context2.abrupt("return", true);

              case 7:
                //run mounted routers
                _iterator2 = _createForOfIteratorHelper(this.mountedRouters);
                _context2.prev = 8;

                _iterator2.s();

              case 10:
                if ((_step2 = _iterator2.n()).done) {
                  _context2.next = 20;
                  break;
                }

                mountedRouter = _step2.value;
                middlewares = mountedRouter.shouldInheritMiddlewares() ? [].concat(_toConsumableArray__default['default'](this.router.getMiddlewares()), _toConsumableArray__default['default'](mountedRouter.getMiddlewares())) : mountedRouter.getMiddlewares();
                engine.use(middlewares);
                /* istanbul ignore else */

                _context2.next = 16;
                return this.runRoutes(method, engine, mountedRouter);

              case 16:
                if (!_context2.sent) {
                  _context2.next = 18;
                  break;
                }

                return _context2.abrupt("return", true);

              case 18:
                _context2.next = 10;
                break;

              case 20:
                _context2.next = 25;
                break;

              case 22:
                _context2.prev = 22;
                _context2.t0 = _context2["catch"](8);

                _iterator2.e(_context2.t0);

              case 25:
                _context2.prev = 25;

                _iterator2.f();

                return _context2.finish(25);

              case 28:
                return _context2.abrupt("return", false);

              case 29:
              case "end":
                return _context2.stop();
            }
          }
        }, _callee2, this, [[8, 22, 25, 28]]);
      }));

      function cordinateRoutes(_x4, _x5, _x6, _x7) {
        return _cordinateRoutes.apply(this, arguments);
      }

      return cordinateRoutes;
    }()
    /**
     * perform house keeping
     */

  }, {
    key: "onResponseFinish",
    value: function onResponseFinish(request, response) {
      response.endedAt = new Date();
      this.bodyParser.cleanUpTempFiles(request.files);
      this.logger.profile(request, response);
    }
    /**
     * parse all request data
     */

  }, {
    key: "parseRequestData",
    value: function parseRequestData(request, url) {
      //parse query
      request.query = this.bodyParser.parseQueryString(url); //parse the request body

      if (request.buffer.length > 0) {
        var contentType = 'text/plain';
        /* istanbul ignore else */

        if (request.headers['content-type']) {
          contentType = request.headers['content-type'];
        } //TODO: add support for content encoding


        var result = this.bodyParser.parse(request.buffer, contentType);
        request.body = result.body;
        request.files = result.files;
      }

      utils.copy(request.data, request.query, request.body);
    }
    /**
     * handle onrequest end event
     */

  }, {
    key: "onRequestEnd",
    value: function onRequestEnd(request, response) {
      var _this2 = this;

      if (request.error) {
        return;
      }

      request.endedAt = response.startedAt = new Date();
      response.logger = this.logger;
      response.config = this.config;
      response.request = request;
      response.errorCallback = this.errorCallback;
      var url = request.url,
          method = request.method;
      this.parseRequestData(request, url);
      return this.cordinateRoutes(url, method, request, response).then(function (status) {
        if (!status) {
          var fileServer = new FileServer.FileServer(_this2.config, request, response);
          return fileServer.serve(url).then(function (status) {
            if (!status) {
              return fileServer.serveHttpErrorFile(404);
            }

            return true;
          });
        }

        return true;
      });
    }
    /**
     * handle on request error event
     */

  }, {
    key: "onRequestError",
    value: function onRequestError(err, request, response) {
      request.error = true;
      Utils.handleError(err, response, 400);
    }
    /**
     * handle request data event
     */

  }, {
    key: "onRequestData",
    value: function onRequestData(chunk, request) {
      if (!request.entityTooLarge) {
        var newEntityLength = request.buffer.length + chunk.length;

        if (newEntityLength <= this.config.maxMemory) {
          request.buffer = Buffer.concat([request.buffer, chunk]);
        } else {
          request.entityTooLarge = true;
          request.emit('error', new EntityTooLargeException.EntityTooLargeException());
        }
      }
    }
    /**
     * handles onrequest events
     */

  }, {
    key: "onRequest",
    value: function onRequest(request, response, server) {
      request.method = request.method.toLowerCase();
      request.startedAt = new Date();
      request.hostname = request.headers['host'].replace(/:\d+$/, '');
      request.encrypted = server instanceof https.Server;
      response.config = this.config;
      response.logger = this.logger;
      response.request = request;
      response.errorCallback = this.errorCallback; //enforce https if set

      var httpsConfig = this.config.https;

      if (httpsConfig.enabled && !request.encrypted && httpsConfig.enforce) {
        response.redirect("https://".concat(path__namespace.join(request.hostname + ':' + httpsConfig.port, request.url)));
      } else {
        //handle on request error
        request.on('error', utils.scopeCallback(this.onRequestError, this, [request, response])); //handle on data event

        request.on('data', utils.scopeCallback(this.onRequestData, this, request)); //handle on end event

        request.on('end', utils.scopeCallback(this.onRequestEnd, this, [request, response])); //clean up resources once the response has been sent out

        response.on('finish', utils.scopeCallback(this.onResponseFinish, this, [request, response]));
      }
    }
    /**
     * binds all event handlers on the server
     */

  }, {
    key: "closeServer",
    value: function closeServer(server, resolve, reject) {
      if (server && server.listening) {
        server.close(function (err) {
          resolve(true);
        });
      } else {
        resolve(true);
      }
    }
    /**
     * binds all event handlers on the server
     */

  }, {
    key: "initServer",
    value: function initServer(server, resolve, reject) {
      var _this3 = this;

      //handle error event
      server.on('error', function (err) {
        var intro = _this3.getServerIntro(server);

        _this3.logger.warn("".concat(intro.name, " Server Error: ").concat(err.code, " ").concat(err.message));

        server.close(function () {
          return reject(err);
        });
      }) // handle client error
      .on('clientError', function (err, socket) {
        if (err && err.code === 'ECONNRESET' || !socket || !socket.writable) {
          return;
        }

        socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
      }) //handle server listening event
      .on('listening', function () {
        var intro = _this3.getServerIntro(server);

        _this3.logger.info("".concat(intro.name, " server started at ").concat(intro.address));

        resolve(true);
      }) // handle close event
      .on('close', function () {
        var intro = _this3.getServerIntro(server);

        _this3.logger.info("".concat(intro.name, " connection closed successfully"));
      }) //handle server request
      .on('request', utils.scopeCallback(this.onRequest, this, server));
    }
    /**
     * returns boolean indicating if the server is listening
     */

  }, {
    key: "listening",
    get: function get() {
      return this.httpsServer && this.httpsServer.listening || this.httpServer.listening;
    }
    /**
     * returns the server instance router
     */

  }, {
    key: "getRouter",
    value: function getRouter() {
      return this.router;
    }
    /**
     * returns the server instance mounted routers
     */

  }, {
    key: "getMountedRouters",
    value: function getMountedRouters() {
      return this.mountedRouters;
    }
    /**
     * returns the resolved server config object
     */

  }, {
    key: "getConfig",
    value: function getConfig() {
      return this.config;
    }
    /**
     * sets routing base path that gets prepended to all route and middleware urls
     */

  }, {
    key: "setBasePath",
    value: function setBasePath(basePath) {
      this.router.setBasePath(basePath);
    }
    /**
     * sets the app intance callback error handler
     * @param errorCallback app instance error callback
     */

  }, {
    key: "setErrorCallback",
    value: function setErrorCallback(errorCallback) {
      this.errorCallback = errorCallback;
    }
    /**
     * stores route rules for http OPTIONS method
     *
     * @param url - route url
     * @param callback - route callback handler
     * @param options - route configuration object or middleware or array of middlewares
     */

  }, {
    key: "options",
    value: function options(url, callback, _options) {
      return this.router.options(url, callback, _options);
    }
    /**
     * stores route rules for http HEAD method
     *
     * @param url - route url
     * @param callback - route callback handler
     * @param options - route configuration object or middleware or array of middlewares
     */

  }, {
    key: "head",
    value: function head(url, callback, options) {
      return this.router.head(url, callback, options);
    }
    /**
     * stores route rules for http GET method
     *
     * @param url - route url
     * @param callback - route callback handler
     * @param options - route configuration object or middleware or array of middlewares
     */

  }, {
    key: "get",
    value: function get(url, callback, options) {
      return this.router.get(url, callback, options);
    }
    /**
     * stores route rules for http POST method
     *
     * @param url - route url
     * @param callback - route callback handler
     * @param options - route configuration object or middleware or array of middlewares
     */

  }, {
    key: "post",
    value: function post(url, callback, options) {
      return this.router.post(url, callback, options);
    }
    /**
     * stores route rules for http PUT method
     * @param url - route url
     * @param callback - route callback handler
     * @param options - route configuration object or middleware or array of middlewares
     */

  }, {
    key: "put",
    value: function put(url, callback, options) {
      return this.router.put(url, callback, options);
    }
    /**
     * stores route rules for http DELETE method
     *
     * @param url - route url
     * @param callback - route callback handler
     * @param options - route configuration object or middleware or array of middlewares
     */

  }, {
    key: "delete",
    value: function _delete(url, callback, options) {
      return this.router["delete"](url, callback, options);
    }
    /**
     * stores route rules for all http methods
     *
     * @param url - route url
     * @param callback - route callback handler
     * @param options - route configuration object or middleware or array of middlewares
     */

  }, {
    key: "any",
    value: function any(url, callback, options) {
      this.router.any(url, callback, options);
    }
    /**
     * returns a route wrapper for the given url
     */

  }, {
    key: "route",
    value: function route(url) {
      return new Wrapper.Wrapper(this.router, url);
    }
    /**
     * removes a given route
     * @param id route id
     */

  }, {
    key: "removeRoute",
    value: function removeRoute(id) {
      if (!this.router.removeRoute(id)) {
        var _iterator3 = _createForOfIteratorHelper(this.mountedRouters),
            _step3;

        try {
          for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
            var mountedRouter = _step3.value;

            if (mountedRouter.removeRoute(id)) {
              return true;
            }
          }
        } catch (err) {
          _iterator3.e(err);
        } finally {
          _iterator3.f();
        }

        return false;
      } else {
        return true;
      }
    }
    /**
     * removes a given middleware
     * @param id middleware id
     */

  }, {
    key: "removeMiddleware",
    value: function removeMiddleware(id) {
      if (!this.router.removeMiddleware(id)) {
        var _iterator4 = _createForOfIteratorHelper(this.mountedRouters),
            _step4;

        try {
          for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
            var mountedRouter = _step4.value;

            if (mountedRouter.removeMiddleware(id)) {
              return true;
            }
          }
        } catch (err) {
          _iterator4.e(err);
        } finally {
          _iterator4.f();
        }

        return false;
      } else {
        return true;
      }
    }
    /**
     * registers a middleware to be called whenever the given url is visited
     *
     * @param url - url to apply middleware to. use * to appy to all urls
     * @param middleware - the middleware or array of middlewares
     * @param options - middleware configuration option. here, you can specify the http method
     * that the middleware will run against
     */

  }, {
    key: "use",
    value: function use(url, middleware, options) {
      return this.router.use(url, middleware, options);
    }
    /**
     * mounts a router to the server instance
     */

  }, {
    key: "mount",
    value: function mount(baseUrl, router) {
      var mainRouterBasePath = this.router.getBasePath();

      var resolve = function resolve(instance) {
        instance[1] = path.join(mainRouterBasePath, baseUrl, instance[1]);
      }; //resolve all routes, each apiRoutes is of the form [url, callback, options]


      var routes = router.getRoutes();

      for (var _i = 0, _Object$keys = Object.keys(routes); _i < _Object$keys.length; _i++) {
        var api = _Object$keys[_i];
        var apiRoutes = routes[api];
        apiRoutes.forEach(resolve, this);
      } //resolve all middlewares. each middleware is of the format [url, callback, options]


      var middlewares = router.getMiddlewares();
      middlewares.forEach(resolve);
      this.mountedRouters.push(router);
    }
    /**
     * starts the server at a given port
     */

  }, {
    key: "listen",
    value: function listen(port) {
      var _this4 = this;

      if (this.listening) {
        this.logger.warn('Server already started. You must close the server first');
        return Promise.resolve(true);
      }

      this.createServers();
      var resolvedPortConfig = {};

      if (utils.isObject(port)) {
        resolvedPortConfig = port;
      } else if (port) {
        resolvedPortConfig = {
          httpPort: port
        };
      }

      var _resolvedPortConfig = resolvedPortConfig,
          _resolvedPortConfig$h = _resolvedPortConfig.httpPort,
          httpPort = _resolvedPortConfig$h === void 0 ? this.config.port : _resolvedPortConfig$h,
          _resolvedPortConfig$h2 = _resolvedPortConfig.httpsPort,
          httpsPort = _resolvedPortConfig$h2 === void 0 ? this.config.https.port : _resolvedPortConfig$h2;
      return new Promise(function (resolve, reject) {
        _this4.initServer(_this4.httpServer, resolve, reject);

        _this4.httpServer.listen(httpPort);
      }).then(function () {
        if (_this4.httpsServer !== null) {
          return new Promise(function (resolve, reject) {
            _this4.initServer(_this4.httpsServer, resolve, reject);

            _this4.httpsServer.listen(httpsPort);
          });
        }

        return true;
      });
    }
    /**
     * closes server
     * @param callback callback function to execute when connection closes
     */

  }, {
    key: "close",
    value: function close() {
      var _this5 = this;

      if (!this.listening) {
        return Promise.resolve(true);
      }

      return Promise.all([new Promise(function (resolve, reject) {
        _this5.closeServer(_this5.httpServer, resolve, reject);
      }), new Promise(function (resolve, reject) {
        _this5.closeServer(_this5.httpsServer, resolve, reject);
      })]).then(function () {
        return true;
      });
    }
    /**
     * returns http and https server address
     */

  }, {
    key: "address",
    value: function address() {
      var result = {
        http: null,
        https: null
      };

      if (this.httpServer.listening) {
        result.http = this.httpServer.address();
      }

      if (this.httpsServer && this.httpsServer.listening) {
        result.https = this.httpsServer.address();
      }

      return result;
    }
  }]);

  return App;
}();

exports.App = App;
//# sourceMappingURL=App.js.map
