UNPKG

@powership/server

Version:
289 lines (283 loc) 9.78 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Server = void 0; var HTTP = _interopRequireWildcard(require("http")); var _utils = require("@powership/utils"); var _httpErrors = _interopRequireDefault(require("http-errors")); var _pluginHooks = require("plugin-hooks"); var _BaseRequestHandler = require("./BaseRequestHandler.cjs"); var _ServerLogs = require("./ServerLogs.cjs"); var _ServerRequest = require("./ServerRequest.cjs"); var _ServerResponse = require("./ServerResponse.cjs"); var _ = require("./_404.cjs"); var _bodyParserHandler = require("./bodyParserHandler.cjs"); var _createHandler = require("./createHandler.cjs"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } const { InternalServerError, NotFound } = _httpErrors.default; class Server { defaultHandlers = [(0, _createHandler.createHandler)('defaultErrorHandler', { // Handling errors onError(_response, { close, error }) { if (this.handledCount) return; // initial Response _ServerLogs.ServerLogs.error(error); const httpError = (0, _BaseRequestHandler.isHttpError)(error) ? error : new InternalServerError(); const errorResponse = _ServerResponse.ServerResponse.create(httpError); close(errorResponse); } }), (0, _createHandler.createHandler)('notFoundHandler', { onResponse(_request, { close }) { if (this.handledCount) return; // TODO should be the last handler. check const httpError = new NotFound(); httpError.body = (0, _._404)(); const errorResponse = _ServerResponse.ServerResponse.create(httpError); close(errorResponse); } })]; constructor(definition) { this.definitionInput = definition; this.handlers = [...definition.handlers, ...this.defaultHandlers]; } static create = definition => { return new Server(definition); }; hooks = createHooks(); closeServer = async () => { const server = this.server; if (!server) return 'NOT_STARTED'; return new Promise((resolve, reject) => { server.close(err => { if (err) return reject(err); resolve('CLOSED'); }); }); }; hasStarted = false; handleRequest = request => { let closed = false; const app = this; const hopeForResponse = (0, _utils.hope)(); (async () => { try { if (!app.hasStarted) { await this.start(); } const hooks = app.hooks; await (async () => { const close = function close(...args) { // const finalResponse = (() => { const arg0 = args[0]; if (!arg0) return appResponse; if (typeof arg0 === 'object') return arg0; appResponse.statusCode = arg0; return appResponse; })(); if (closed || hopeForResponse.result || hopeForResponse.error) { closed = true; return; } else { closed = true; } if (!finalResponse) { closed = true; hopeForResponse.resolve(appResponse); return; } try { hopeForResponse.resolve(finalResponse); } catch (e) { if (!(hopeForResponse.result || hopeForResponse.error)) { onError(e).catch(_ServerLogs.ServerLogs.error); } } }; let appResponse = _ServerResponse.ServerResponse.create(); request.body = await hooks.onParseBody.dispatch(request.body, { req: request, res: appResponse, app, close }); request = await hooks.onRequest.dispatch(request, { app, response: appResponse, close }); appResponse = await hooks.onResponse.dispatch(appResponse, { app, request, close }); async function onError(error) { const errorResponse = await hooks.onError.dispatch(appResponse, { request, error, close }); close(errorResponse); } if (!closed) { close(appResponse); } })(); } catch (e) { hopeForResponse.reject(e); } })(); return hopeForResponse; }; withServer = false; async start(port) { const app = this; if (!app.hasStarted) { this._startHandlers(); } if (app.hasStarted) { _ServerLogs.ServerLogs.info('RESTARTING_APP'); await this.closeServer(); } app.hasStarted = true; this.usedDefinition = await (() => { if (typeof this.definitionInput === 'function') { return this.definitionInput(this); } return this.definitionInput; })(); const hooks = this.hooks; if (port === undefined) return app; if (!hooks.onResponse.middlewares.length) { _utils.NodeLogger.logWarning(`⚠️ No handlers listening to onResponse.`); } let server = HTTP.createServer(async function _requestListener(httpServerRequest, httpServerResponse) { try { const { httpMethod } = (0, _utils.nonNullValues)({ httpMethod: httpServerRequest.method }); const requestBody = await (0, _bodyParserHandler.parseHTTPBody)(httpServerRequest, httpServerResponse); const appRequest = _ServerRequest.ServerRequest.create({ body: requestBody, headers: httpServerRequest.headers, locals: {}, url: httpServerRequest.url, method: httpMethod }); const response = await app.handleRequest(appRequest); const { statusCode, body, headersNamed, streamBody } = response.toHttpResponse(); httpServerResponse.statusCode = statusCode; headersNamed.forEach(({ name, value }) => { httpServerResponse.setHeader(name, value); }); if (streamBody) { streamBody.on('error', error => { _ServerLogs.ServerLogs.error(error); httpServerResponse.statusCode = 500; httpServerResponse.end(); }); streamBody.pipe(httpServerResponse); } else { httpServerResponse.end(body); } } catch (error) { console.trace(error); _ServerLogs.ServerLogs.error(error); if (httpServerResponse.headersSent) { _ServerLogs.ServerLogs.error(`ERROR_AFTER_HEADERS_SENT`, error); } else { const error = new InternalServerError(); httpServerResponse.statusCode = error.statusCode; if (error.headers) { Object.entries(error.headers).forEach(([k, v]) => { httpServerResponse.setHeader(k, v); }); } httpServerResponse.end(error.message); } } }); // server = await this.hooks.willStartServer.dispatch(server, { app: this }); return new Promise(async (resolve, reject) => { try { server.listen(port, () => { const addressInfo = server.address(); if (!addressInfo || typeof addressInfo !== 'object') { _ServerLogs.ServerLogs.info({ addressInfo }); throw new Error(`Failed to recovery server addressInfo.`); } app.withServer = { server, ...addressInfo }; resolve(Object.assign(app, { server, ...addressInfo })); }); await this.hooks.started.dispatch(server, { app: this }); } catch (e) { reject(e); } }); } _startHandlers = () => { const handlerByName = {}; this.handlers.forEach(appHandler => { const { hooks, name } = appHandler; if (handlerByName[name] && handlerByName[name] !== appHandler) { console.warn(`Handler with name "${name}" already registered.`); } else { handlerByName[name] = appHandler; } Object.entries(hooks).forEach(([hookName, handler]) => { try { Object.defineProperty(handler, 'name', { value: `${name}_${hookName}` }); } catch (e) {} this.hooks[hookName].pushMiddleware(handler); }); }); return handlerByName; }; } exports.Server = Server; function createHooks() { return { willStartServer: (0, _pluginHooks.createAsyncPlugin)(), started: (0, _pluginHooks.createAsyncPlugin)(), onParseBody: (0, _pluginHooks.createAsyncPlugin)(), onRequest: (0, _pluginHooks.createAsyncPlugin)(), onResponse: (0, _pluginHooks.createAsyncPlugin)(), onError: (0, _pluginHooks.createAsyncPlugin)() }; } //# sourceMappingURL=Server.cjs.map