@mvx/mvc
Version:
@mvx/mvc is mvc framework on server, base on koa, @tsdi frameworks
328 lines (326 loc) • 14.4 kB
JavaScript
"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