UNPKG

@mvx/mvc

Version:

@mvx/mvc is mvc framework on server, base on koa, @tsdi frameworks

328 lines (326 loc) 14.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ControllerRoute = exports.RouteControllerMiddlewaresToken = exports.RouteControllerArgToken = exports.isBuffer = void 0; const tslib_1 = require("tslib"); const ioc_1 = require("@tsdi/ioc"); const boot_1 = require("@tsdi/boot"); const IContext_1 = require("../IContext"); const RequestMethod_1 = require("../RequestMethod"); const errors_1 = require("../errors"); const ResultValue_1 = require("../results/ResultValue"); const decorators_1 = require("../decorators"); const AuthorizationService_1 = require("../services/AuthorizationService"); const Route_1 = require("./Route"); const MvcMiddleware_1 = require("../middlewares/MvcMiddleware"); const MvcMiddlewares_1 = require("../middlewares/MvcMiddlewares"); const vary = require('vary'); function isBuffer(target) { if (typeof Buffer === 'undefined') { return false; } else { return ioc_1.lang.getClass(target) === Buffer; } } exports.isBuffer = isBuffer; const emptyNext = async () => { }; exports.RouteControllerArgToken = ioc_1.tokenId('ROUTE_CONTRL_ARGS'); exports.RouteControllerMiddlewaresToken = ioc_1.tokenId('ROUTE_CONTRL_MIDDLEWARES'); const restParms = /^\S*:/; const isRest = /\/:/; let ControllerRoute = class ControllerRoute extends Route_1.MvcRoute { constructor(url, controller, middlewares) { super(url); this.controller = controller; this.middlewares = middlewares; } navigate(ctx, next) { if (ctx._isCors) { return this.options(ctx, next); } else { return this.navigating(ctx, next); } } async navigating(ctx, next) { let meta = this.getRouteMetaData(ctx, RequestMethod_1.parseRequestMethod(ctx.method)); if (!meta) { return await next(); } let middlewares = this.getRouteMiddleware(ctx, meta); if (middlewares.length) { await this.execFuncs(ctx, middlewares.map(m => this.toHandle(m)).filter(f => !!f)); } await this.invoke(ctx, meta); return await next(); } getRouteMiddleware(ctx, meta) { let auths = ctx.getInjector().getServices(AuthorizationService_1.AuthorizationService); let middlewares = this.middlewares || []; if (auths) { middlewares = auths.map(auth => auth.getAuthMiddlewares(ctx, this.controller)).reduce((p, c) => p.concat(c), []) .concat(middlewares) .concat(auths.map(a => a.getAuthMiddlewares(ctx, this.controller, meta.propertyKey)).reduce((p, c) => p.concat(c), [])); } if (meta.middlewares) { middlewares = middlewares.concat(meta.middlewares); } return middlewares; } async options(ctx, next) { var _a, _b; let requestOrigin = ctx.get('Origin'); ctx.vary('Origin'); if (!requestOrigin) { return await next(); } let config = ctx.mvcContext.getConfiguration(); let options = config.corsOptions || {}; let origin; if (ioc_1.isFunction(options.origin)) { origin = options.origin(ctx); if (ioc_1.isPromise(origin)) { origin = await origin; } if (!origin) { return await next(); } } else { origin = options.origin || requestOrigin; } let headersSet = {}; let set = (key, value) => { ctx.set(key, value); headersSet[key] = value; }; if (ctx.method !== 'OPTIONS') { set('Access-Control-Allow-Origin', origin); if (options.credentials === true) { set('Access-Control-Allow-Credentials', 'true'); } if (options.exposeHeaders) { set('Access-Control-Expose-Headers', options.exposeHeaders); } if (!options.keepHeadersOnError) { return await next(); } try { await next(); } catch (err) { const errHeadersSet = err.headers || {}; const varyWithOrigin = vary.append(errHeadersSet.vary || errHeadersSet.Vary || '', 'Origin'); delete errHeadersSet.Vary; err.headers = Object.assign(Object.assign(Object.assign({}, errHeadersSet), headersSet), { vary: varyWithOrigin }); ctx.status = err instanceof errors_1.HttpError ? err.status || 500 : 500; ctx.message = err.message || err.toString() || ''; (_b = (_a = ctx.mvcContext.getLogManager()) === null || _a === void 0 ? void 0 : _a.getLogger()) === null || _b === void 0 ? void 0 : _b.error(err); } ; } else { const coremeta = this.getCorsMeta(ctx, ctx.get('Access-Control-Request-Method')); if (!coremeta) { ctx.status = 403; return await next(); } options = Object.assign(Object.assign({}, options), coremeta); ctx.set('Access-Control-Allow-Origin', origin); if (options.credentials === true) { ctx.set('Access-Control-Allow-Credentials', 'true'); } let maxAge = String(options.maxAge); if (maxAge) { ctx.set('Access-Control-Max-Age', maxAge); } let allowsM = ioc_1.isArray(options.allowMethods) ? options.allowMethods.map(m => RequestMethod_1.methodToString(m)).filter(m => !!m).join(',') : options.allowMethods; if (allowsM) { ctx.set('Access-Control-Allow-Methods', allowsM); } let allowH = ioc_1.isArray(options.allowHeaders) ? options.allowHeaders.filter(m => !!m).join(',') : options.allowHeaders; if (!allowH) { allowH = ctx.get('Access-Control-Request-Headers'); } if (allowH) { ctx.set('Access-Control-Allow-Headers', allowH); } ctx.status = 204; } } getCorsMeta(ctx, reqMethod) { if (!reqMethod) { return null; } let method = RequestMethod_1.parseRequestMethod(reqMethod); let meta = this.getRouteMetaData(ctx, method); if (meta && meta.propertyKey) { let corsmetas = ioc_1.getMethodMetadata(decorators_1.Cors, this.controller)[meta.propertyKey.toString()] || []; if (corsmetas.length < 1) { corsmetas = ioc_1.getTypeMetadata(decorators_1.Cors, this.controller); } if (corsmetas.length) { return corsmetas.find(cor => { if (!cor.allowMethods) { return true; } if (cor.allowMethods) { if (ioc_1.isString(cor.allowMethods)) { return cor.allowMethods.toUpperCase().indexOf(reqMethod) >= 0; } else if (ioc_1.isArray(cor.allowMethods)) { return cor.allowMethods.some(c => RequestMethod_1.methodToString(c) === reqMethod); } } return false; }); } } return null; } async invoke(ctx, meta) { let injector = ctx.mvcContext.injector; if (meta && meta.propertyKey) { let ctrl = injector.getInstance(this.controller, { provide: IContext_1.ContextToken, useValue: ctx }); let reflects = ctx.mvcContext.reflects; let providers = await this.createProvider(ctx, ctrl, meta, reflects.getParameters(this.controller, ctrl, meta.propertyKey)); let result = await injector.invoke(ctrl, meta.propertyKey, ...providers); if (ioc_1.isPromise(result)) { result = await result; } // middleware. if (ioc_1.isFunction(result)) { await result(ctx); } else if (result instanceof MvcMiddleware_1.MvcMiddleware || result instanceof MvcMiddlewares_1.MvcMiddlewares) { await result.execute(ctx, emptyNext); } else if (ioc_1.isBaseType(result) || ioc_1.isArray(result) || isBuffer(result)) { if (isBuffer(result)) { if (typeof Buffer !== 'undefined') { ctx.body = Buffer.from(result); } else { ctx.body = result; } } else { ctx.body = result; } ctx.status = 200; } else if (ioc_1.isObject(result)) { if (result instanceof ResultValue_1.ResultValue) { await result.sendValue(ctx); } else { ctx.body = result; ctx.status = 200; } } else { ctx.body = result; ctx.status = 200; } } } async createProvider(ctx, ctrl, meta, params) { let injector = ctx.getInjector(); let providers = [{ provide: IContext_1.ContextToken, useValue: ctx }]; if (params && params.length) { let restParams = {}; if (this.isRestUri(meta.route)) { let routes = meta.route.split('/').map(r => r.trim()); let restParamNames = routes.filter(d => restParms.test(d)); let baseURL = this.vaildify(this.url, true); let routeUrls = this.vaildify(ctx.url.replace(baseURL, '')).split('/'); restParamNames.forEach(pname => { let val = routeUrls[routes.indexOf(pname)]; restParams[pname.substring(1)] = val; }); } let body = ctx.request.body || {}; let parser = injector.get(boot_1.BaseTypeParserToken); let ppds = await Promise.all(params.map(async (param) => { let ptype = param.provider ? injector.getTokenProvider(param.provider) : param.type; let val; if (ioc_1.isFunction(ptype)) { if (ioc_1.isBaseType(ptype)) { let paramVal = restParams[param.name]; if (ioc_1.isUndefined(paramVal)) { paramVal = ctx.request.query[param.name]; } val = parser.parse(ptype, paramVal); } if (ioc_1.isNullOrUndefined(val) && ioc_1.lang.hasField(body)) { if (ioc_1.isArray(ptype) && ioc_1.isArray(body)) { val = body; } else if (ioc_1.isBaseType(ptype)) { val = parser.parse(ptype, body[param.name]); } else if (ioc_1.isClass(ptype)) { let mdparser = injector.getService({ token: boot_1.ModelParser, target: [ptype, ...ctx.mvcContext.reflects.getDecorators(ptype)], defaultToken: boot_1.DefaultModelParserToken }); if (mdparser) { val = mdparser.parseModel(ptype, body); } else { val = await injector.getInstance(boot_1.BuilderServiceToken).resolve({ type: ptype, template: body }); } } } } if (ioc_1.isNullOrUndefined(val)) { return null; } return { provide: param.name || ptype, useValue: val }; })); providers = providers.concat(ppds.filter(p => p !== null)); } return providers; } isRestUri(uri) { return isRest.test(uri || ''); } getRouteMetaData(ctx, requestMethod) { let decoratorName = decorators_1.Route.toString(); let subRoute = this.vaildify(this.getReqRoute(ctx).replace(this.url, ''), true); let methodMaps = ioc_1.getMethodMetadata(decoratorName, this.controller); let meta; let allMethods = []; for (let name in methodMaps) { allMethods = allMethods.concat(methodMaps[name]); } allMethods = allMethods.filter(m => m && m.method === requestMethod); allMethods = allMethods.sort((ra, rb) => (rb.route || '').length - (ra.route || '').length); meta = allMethods.find(route => this.vaildify(route.route || '', true) === subRoute); if (!meta) { meta = allMethods.find(route => { let uri = this.vaildify(route.route || '', true); if (this.isRestUri(uri)) { let idex = uri.indexOf('/:'); let url = uri.substring(0, idex); if (url !== subRoute && subRoute.indexOf(url) === 0) { return true; } } return false; }); } return meta; } static ρAnn() { return { "name": "ControllerRoute", "params": { "constructor": ["url", "controller", "middlewares"], "navigate": ["ctx", "next"], "navigating": ["ctx", "next"], "getRouteMiddleware": ["ctx", "meta"], "options": ["ctx", "next"], "getCorsMeta": ["ctx", "reqMethod"], "invoke": ["ctx", "meta"], "createProvider": ["ctx", "ctrl", "meta", "params"], "isRestUri": ["uri"], "getRouteMetaData": ["ctx", "requestMethod"] } }; } }; ControllerRoute = tslib_1.__decorate([ ioc_1.Injectable(), tslib_1.__param(0, ioc_1.Inject(Route_1.RouteUrlArgToken)), tslib_1.__param(1, ioc_1.Inject(exports.RouteControllerArgToken)), tslib_1.__param(2, ioc_1.Inject(exports.RouteControllerMiddlewaresToken)), tslib_1.__metadata("design:paramtypes", [String, Object, Array]) ], ControllerRoute); exports.ControllerRoute = ControllerRoute; //# sourceMappingURL=../sourcemaps/router/ControllerRoute.js.map