@powership/server
Version:
289 lines (283 loc) • 9.78 kB
JavaScript
;
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