@dooboostore/simple-boot-http-server
Version:
back end http server frameworks
313 lines • 22.3 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { SimpleApplication } from '@dooboostore/simple-boot/SimpleApplication';
import { HttpServerOption } from './option/HttpServerOption';
import { IncomingMessage, Server as HttpServer, ServerResponse } from 'http';
import { Server as HttpsServer } from 'https';
import { RequestResponse } from './models/RequestResponse';
import { getUrlMapping, getUrlMappings, UrlMappingSituationType } from './decorators/MethodMapping';
import { HttpStatus } from './codes/HttpStatus';
import { HttpHeaders } from './codes/HttpHeaders';
import { Mimes } from './codes/Mimes';
import { ExceptionHandlerSituationType, targetExceptionHandler } from '@dooboostore/simple-boot/decorators/exception/ExceptionDecorator';
import { getInject, SituationTypeContainer, SituationTypeContainers } from '@dooboostore/simple-boot/decorators/inject/Inject';
import { ReflectUtils } from '@dooboostore/core/reflect/ReflectUtils';
import { ReqFormUrlBody } from './models/datas/body/ReqFormUrlBody';
import { ReqJsonBody } from './models/datas/body/ReqJsonBody';
import { ReqHeader } from './models/datas/ReqHeader';
import { RouterModule } from '@dooboostore/simple-boot/route/RouterModule';
import { ReqMultipartFormBody } from './models/datas/body/ReqMultipartFormBody';
import { execValidationInValid, getValidIndex } from '@dooboostore/simple-boot/decorators/validate/Validation';
import { ValidException } from '@dooboostore/simple-boot/errors/ValidException';
import { HttpError } from './errors/HttpError';
import { getRoute } from '@dooboostore/simple-boot/decorators/route/Router';
import { URLSearchParams } from 'url';
import { HttpMethod } from './codes/HttpMethod';
import { SessionManager } from './session/SessionManager';
import { InjectSituationType } from './inject/InjectSituationType';
export class SimpleBootHttpServer extends SimpleApplication {
constructor(option = new HttpServerOption()) {
super(option);
this.option = option;
this.sessionManager = new SessionManager(this.option);
}
run(otherInstanceSim) {
var _a, _b, _c, _d;
const simstanceManager = super.run(otherInstanceSim);
const targets = [...(_a = this.option.closeEndPoints) !== null && _a !== void 0 ? _a : [], ...(_b = this.option.errorEndPoints) !== null && _b !== void 0 ? _b : [], ...(_c = this.option.requestEndPoints) !== null && _c !== void 0 ? _c : [], ...(_d = this.option.filters) !== null && _d !== void 0 ? _d : []];
Promise.all(targets.map(it => (typeof it === 'function' ? this.simstanceManager.getOrNewSim({ target: it }) : it)).map(it => it.onInit(this))).then(it => {
this.startServer();
});
return simstanceManager;
}
startServer() {
const _super = Object.create(null, {
routing: { get: () => super.routing }
});
if (this.option.serverOption && 'key' in this.option.serverOption && 'cert' in this.option.serverOption) {
this.server = new HttpsServer(this.option.serverOption);
const httpServer = new HttpServer();
httpServer.on('request', (req, res) => {
res.writeHead(301, { Location: `https://${req.headers.host}${req.url}` });
res.end();
});
httpServer.listen(80, this.option.listen.hostname, () => {
console.log('HTTP redirect server running on port 80');
});
}
else if (this.option.serverOption) {
this.server = new HttpServer(this.option.serverOption);
}
else {
this.server = new HttpServer();
}
this.server.on('request', (req, res) => __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z;
const transactionManager = this.option.transactionManagerFactory ? yield this.option.transactionManagerFactory() : undefined;
res.on('close', () => __awaiter(this, void 0, void 0, function* () {
if (this.option.closeEndPoints) {
for (const it of this.option.closeEndPoints) {
try {
const execute = (typeof it === 'function' ? this.simstanceManager.getOrNewSim({ target: it }) : it);
const endPoint = execute === null || execute === void 0 ? void 0 : execute.endPoint(rr, this);
if (endPoint instanceof Promise) {
yield endPoint;
}
}
catch (e) {
}
}
}
if (!rr.resIsDone()) {
rr.resEnd();
}
}));
res.on('error', () => __awaiter(this, void 0, void 0, function* () {
if (this.option.errorEndPoints) {
for (const it of this.option.errorEndPoints) {
try {
const execute = (typeof it === 'function' ? this.simstanceManager.getOrNewSim({ target: it }) : it);
const endPoint = execute === null || execute === void 0 ? void 0 : execute.endPoint(rr, this);
if (endPoint instanceof Promise) {
yield endPoint;
}
}
catch (e) {
}
}
}
if (!rr.resIsDone()) {
rr.resEnd();
}
}));
const rr = new RequestResponse(req, res, { sessionManager: this.sessionManager, option: this.option });
rr.resSetHeader(HttpHeaders.Server, 'simple-boot-http-server');
const cookie = rr.reqCookieGet(this.option.sessionOption.key);
if (!cookie) {
const session = yield this.sessionManager.session();
rr.resSetHeader(HttpHeaders.SetCookie, `${this.option.sessionOption.key}=${session.uuid}; Path=/; HttpOnly`);
}
const otherStorage = new Map();
otherStorage.set(RequestResponse, rr);
otherStorage.set(IncomingMessage, req);
otherStorage.set(ServerResponse, res);
try {
transactionManager === null || transactionManager === void 0 ? void 0 : transactionManager.try();
if (this.option.requestEndPoints) {
for (const it of this.option.requestEndPoints) {
try {
const execute = (typeof it === 'function' ? this.simstanceManager.getOrNewSim({ target: it }) : it);
execute === null || execute === void 0 ? void 0 : execute.endPoint(rr, this);
}
catch (e) {
}
}
}
const filter = {
carrier: new Map(),
filters: []
};
for (let i = 0; this.option.filters && i < this.option.filters.length; i++) {
const it = this.option.filters[i];
const execute = (typeof it === 'function' ? this.simstanceManager.getOrNewSim({ target: it }) : it);
let sw = true;
if (execute === null || execute === void 0 ? void 0 : execute.proceedBefore) {
sw = yield execute.proceedBefore({ rr, app: this, carrier: filter.carrier });
filter.filters.push({ filter: execute, sw });
}
if (!sw) {
break;
}
}
if (!rr.resIsDone()) {
const routerModule = yield _super.routing.call(this, rr.reqIntent);
otherStorage.set(RouterModule, routerModule);
const moduleInstance = (_a = routerModule === null || routerModule === void 0 ? void 0 : routerModule.getModuleInstance) === null || _a === void 0 ? void 0 : _a.call(routerModule);
let methods = [];
if (routerModule && moduleInstance) {
if (routerModule.propertyKeys) {
const map = (_b = routerModule.propertyKeys) === null || _b === void 0 ? void 0 : _b.map((it) => {
return { propertyKey: it, config: getUrlMapping(moduleInstance, it) };
});
methods.push(...(map !== null && map !== void 0 ? map : []));
}
else {
methods.push(...((_c = getUrlMappings(moduleInstance).filter(it => !getRoute(moduleInstance, it.propertyKey))) !== null && _c !== void 0 ? _c : []));
}
if (((_d = rr.reqMethod()) === null || _d === void 0 ? void 0 : _d.toUpperCase()) === HttpMethod.OPTIONS.toUpperCase()) {
rr.resSetHeader(HttpHeaders.Allow, methods.map(it => it.config.method).join(', '));
rr.resStatusCode(HttpStatus.Ok);
}
methods = methods.filter(it => { var _a; return it && it.propertyKey && it.config && ((_a = rr.reqMethod()) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === it.config.method.toUpperCase(); });
methods.sort((a, b) => {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
return (((_d = (_c = (_b = (_a = b.config) === null || _a === void 0 ? void 0 : _a.req) === null || _b === void 0 ? void 0 : _b.contentType) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0) + ((_h = (_g = (_f = (_e = b.config) === null || _e === void 0 ? void 0 : _e.req) === null || _f === void 0 ? void 0 : _f.accept) === null || _g === void 0 ? void 0 : _g.length) !== null && _h !== void 0 ? _h : 0)) - (((_m = (_l = (_k = (_j = a.config) === null || _j === void 0 ? void 0 : _j.req) === null || _k === void 0 ? void 0 : _k.contentType) === null || _l === void 0 ? void 0 : _l.length) !== null && _m !== void 0 ? _m : 0) + ((_r = (_q = (_p = (_o = a.config) === null || _o === void 0 ? void 0 : _o.req) === null || _p === void 0 ? void 0 : _p.accept) === null || _q === void 0 ? void 0 : _q.length) !== null && _r !== void 0 ? _r : 0));
});
methods = methods
.filter(it => { var _a, _b, _c, _d, _e; return ((_b = (_a = it.config) === null || _a === void 0 ? void 0 : _a.req) === null || _b === void 0 ? void 0 : _b.contentType) ? (!!((_e = (_d = (_c = it.config) === null || _c === void 0 ? void 0 : _c.req) === null || _d === void 0 ? void 0 : _d.contentType) === null || _e === void 0 ? void 0 : _e.find(sit => rr.reqHasContentTypeHeader(sit)))) : true; })
.filter(it => { var _a, _b, _c, _d, _e; return ((_b = (_a = it.config) === null || _a === void 0 ? void 0 : _a.req) === null || _b === void 0 ? void 0 : _b.accept) ? (!!((_e = (_d = (_c = it.config) === null || _c === void 0 ? void 0 : _c.req) === null || _d === void 0 ? void 0 : _d.accept) === null || _e === void 0 ? void 0 : _e.find(sit => rr.reqHasAcceptHeader(sit)))) : true; });
if (methods[0]) {
const it = methods[0];
const paramTypes = ReflectUtils.getParameterTypes(moduleInstance, it.propertyKey);
const injects = getInject(moduleInstance, it.propertyKey);
const validIndexs = getValidIndex(moduleInstance, it.propertyKey);
if (injects) {
const isJson = injects.find(it => { var _a; return ((_a = it.config) === null || _a === void 0 ? void 0 : _a.situationType) === UrlMappingSituationType.REQ_JSON_BODY; });
const isFormUrl = injects.find(it => { var _a; return ((_a = it.config) === null || _a === void 0 ? void 0 : _a.situationType) === UrlMappingSituationType.REQ_FORM_URL_BODY; });
const isTransactionManager = injects.find(it => { var _a; return ((_a = it.config) === null || _a === void 0 ? void 0 : _a.situationType) === InjectSituationType.TransactionManager; });
const siturationContainers = new SituationTypeContainers();
if (isJson) {
let data = yield rr.reqBodyJsonData();
if (isJson.type) {
data = Object.assign(new isJson.type(), data);
}
if (validIndexs.includes(isJson.index)) {
const inValid = execValidationInValid(data);
if (((_e = inValid === null || inValid === void 0 ? void 0 : inValid.length) !== null && _e !== void 0 ? _e : 0) > 0) {
throw new ValidException(inValid);
}
}
siturationContainers.push(new SituationTypeContainer({
situationType: UrlMappingSituationType.REQ_JSON_BODY,
data
}));
}
if (isFormUrl) {
let data = yield rr.reqBodyFormUrlData();
if (isFormUrl.type) {
data = Object.assign(new isFormUrl.type(), data);
}
if (validIndexs.includes(isFormUrl.index)) {
const inValid = execValidationInValid(data);
if (((_f = inValid === null || inValid === void 0 ? void 0 : inValid.length) !== null && _f !== void 0 ? _f : 0) > 0) {
throw new ValidException(inValid);
}
}
siturationContainers.push(new SituationTypeContainer({ situationType: UrlMappingSituationType.REQ_FORM_URL_BODY, data }));
}
if (isTransactionManager && isTransactionManager.type && transactionManager && transactionManager.hasTransaction(isTransactionManager.type)) {
let data = yield transactionManager.getTransaction(isTransactionManager.type);
if (data) {
data = yield data.try(isTransactionManager.config.argument);
siturationContainers.push(new SituationTypeContainer({ situationType: InjectSituationType.TransactionManager, data, index: isTransactionManager.index }));
}
}
if (siturationContainers.length) {
otherStorage.set(SituationTypeContainers, siturationContainers);
}
}
for (const paramType of paramTypes) {
if (paramType === ReqFormUrlBody) {
otherStorage.set(ReqFormUrlBody, yield rr.reqBodyReqFormUrlBody());
}
else if (paramType === ReqJsonBody) {
otherStorage.set(ReqJsonBody, yield rr.reqBodyReqJsonBody());
}
else if (paramType === URLSearchParams) {
otherStorage.set(URLSearchParams, rr.reqUrlSearchParams);
}
else if (paramType === ReqMultipartFormBody) {
otherStorage.set(ReqMultipartFormBody, rr.reqBodyMultipartFormData());
}
else if (paramType === ReqHeader) {
otherStorage.set(ReqHeader, rr.reqHeaderObj);
}
}
let data = yield this.simstanceManager.executeBindParameterSimPromise({
target: moduleInstance,
targetKey: it.propertyKey
}, otherStorage);
if ((_g = it.config) === null || _g === void 0 ? void 0 : _g.resolver) {
const execute = typeof it.config.resolver === 'function' ? this.simstanceManager.getOrNewSim({ target: it.config.resolver }) : it.config.resolver;
data = yield ((_h = execute === null || execute === void 0 ? void 0 : execute.resolve) === null || _h === void 0 ? void 0 : _h.call(execute, data, rr));
}
const status = (_l = (_k = (_j = it.config) === null || _j === void 0 ? void 0 : _j.res) === null || _k === void 0 ? void 0 : _k.status) !== null && _l !== void 0 ? _l : HttpStatus.Ok;
const headers = (_p = (_o = (_m = it.config) === null || _m === void 0 ? void 0 : _m.res) === null || _o === void 0 ? void 0 : _o.header) !== null && _p !== void 0 ? _p : {};
if ((_r = (_q = it.config) === null || _q === void 0 ? void 0 : _q.res) === null || _r === void 0 ? void 0 : _r.contentType) {
headers[HttpHeaders.ContentType] = (_t = (_s = it.config) === null || _s === void 0 ? void 0 : _s.res) === null || _t === void 0 ? void 0 : _t.contentType;
}
if (((_x = (_w = (_v = (_u = it.config) === null || _u === void 0 ? void 0 : _u.res) === null || _v === void 0 ? void 0 : _v.contentType) === null || _w === void 0 ? void 0 : _w.toLowerCase().indexOf(Mimes.ApplicationJson.toLowerCase())) !== null && _x !== void 0 ? _x : -1) > -1) {
data = JSON.stringify(data);
}
else if (data && typeof data === 'object') {
data = JSON.stringify(data);
}
rr.resSetHeaders(headers);
rr.resSetStatusCode(status);
rr.resWrite(data);
}
}
if (this.option.noSuchRouteEndPointMappingThrow && methods.length <= 0 && ((_y = rr.reqMethod()) === null || _y === void 0 ? void 0 : _y.toUpperCase()) !== HttpMethod.OPTIONS) {
throw this.option.noSuchRouteEndPointMappingThrow(rr);
}
}
for (const it of filter.filters.reverse()) {
if (((_z = it.filter) === null || _z === void 0 ? void 0 : _z.proceedAfter) && !(yield it.filter.proceedAfter({ rr, app: this, before: it.sw, carrier: filter.carrier }))) {
break;
}
}
}
catch (e) {
transactionManager === null || transactionManager === void 0 ? void 0 : transactionManager.catch(e);
rr.resStatusCode(e instanceof HttpError ? e.status : HttpStatus.InternalServerError);
const execute = typeof this.option.globalAdvice === 'function' ? this.simstanceManager.getOrNewSim(this.option.globalAdvice) : this.option.globalAdvice;
if (!execute) {
rr.resEnd();
return;
}
if (e && typeof e === 'object') {
otherStorage.set(e.constructor, e);
otherStorage.set(SituationTypeContainer, new SituationTypeContainer({
situationType: ExceptionHandlerSituationType.ERROR_OBJECT,
data: e
}));
}
const target = targetExceptionHandler(execute, e);
if (target) {
yield this.simstanceManager.executeBindParameterSimPromise({
target: execute,
targetKey: target.propertyKey
}, otherStorage);
}
}
finally {
transactionManager === null || transactionManager === void 0 ? void 0 : transactionManager.finally();
}
if (!rr.resIsDone()) {
rr.resEnd();
}
}));
this.server.listen(this.option.listen.port, this.option.listen.hostname, this.option.listen.backlog, () => {
var _a, _b;
(_b = (_a = this.option.listen).listeningListener) === null || _b === void 0 ? void 0 : _b.call(_a, this, this.server);
});
}
}
//# sourceMappingURL=SimpleBootHttpServer.js.map