Skip to content

Commit

Permalink
feat: multi host decorator (#68)
Browse files Browse the repository at this point in the history
  • Loading branch information
elrrrrrrr authored Dec 15, 2022
1 parent 4bba399 commit f6679de
Show file tree
Hide file tree
Showing 15 changed files with 184 additions and 60 deletions.
17 changes: 11 additions & 6 deletions core/controller-decorator/src/decorator/http/Host.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,31 @@ import ControllerInfoUtil from '../../util/ControllerInfoUtil';
import { EggProtoImplClass } from '@eggjs/core-decorator';
import MethodInfoUtil from '../../util/MethodInfoUtil';
import assert from 'assert';
import { HostType } from '../../model';

export function Host(host: HostType) {

function parseHost(): string[] {
return Array.isArray(host) ? host : [ host ];
}

export function Host(host: string) {
function classHost(constructor: EggProtoImplClass) {
ControllerInfoUtil.addControllerHost(host, constructor);
ControllerInfoUtil.addControllerHosts(parseHost(), constructor);
}

function methodHOst(target: any, propertyKey: PropertyKey) {
function methodHost(target: any, propertyKey: PropertyKey) {
assert(typeof propertyKey === 'string',
`[controller/${target.name}] expect method name be typeof string, but now is ${String(propertyKey)}`);
const controllerClazz = target.constructor as EggProtoImplClass;
const methodName = propertyKey as string;

MethodInfoUtil.setMethodHost(host, controllerClazz, methodName);
MethodInfoUtil.setMethodHosts(parseHost(), controllerClazz, methodName);
}

return function(target: any, propertyKey?: PropertyKey) {
if (propertyKey === undefined) {
classHost(target);
} else {
methodHOst(target, propertyKey);
methodHost(target, propertyKey);
}
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ export class HTTPControllerMetaBuilder {
const protoName = property!.name as string;
const needAcl = ControllerInfoUtil.hasControllerAcl(this.clazz);
const aclCode = ControllerInfoUtil.getControllerAcl(this.clazz);
const host = ControllerInfoUtil.getControllerHost(this.clazz);
const hosts = ControllerInfoUtil.getControllerHosts(this.clazz);
const metadata = new HTTPControllerMeta(
clazzName, protoName, controllerName, httpPath, httpMiddlewares, methods, needAcl, aclCode, host);
clazzName, protoName, controllerName, httpPath, httpMiddlewares, methods, needAcl, aclCode, hosts);
ControllerMetadataUtil.setControllerMetadata(this.clazz, metadata);
for (const method of metadata.methods) {
const realPath = metadata.getMethodRealPath(method);
Expand All @@ -63,4 +63,3 @@ export class HTTPControllerMetaBuilder {
}

ControllerMetaBuilderFactory.registerControllerMetaBuilder(ControllerType.HTTP, HTTPControllerMetaBuilder.create);

Original file line number Diff line number Diff line change
Expand Up @@ -105,13 +105,13 @@ export class HTTPControllerMethodMetaBuilder {
const middlewares = MethodInfoUtil.getMethodMiddlewares(this.clazz, this.methodName);
const needAcl = MethodInfoUtil.hasMethodAcl(this.clazz, this.methodName);
const aclCode = MethodInfoUtil.getMethodAcl(this.clazz, this.methodName);
const host = MethodInfoUtil.getMethodHost(this.clazz, this.methodName);
const hosts = MethodInfoUtil.getMethodHosts(this.clazz, this.methodName);
const realPath = parentPath
? path.posix.join(parentPath, httpPath)
: httpPath;
const paramTypeMap = this.buildParamType(realPath);
const priority = this.getPriority();
return new HTTPMethodMeta(
this.methodName, httpPath!, httpMethod!, middlewares, contextIndex, paramTypeMap, priority, needAcl, aclCode, host);
this.methodName, httpPath!, httpMethod!, middlewares, contextIndex, paramTypeMap, priority, needAcl, aclCode, hosts);
}
}
14 changes: 7 additions & 7 deletions core/controller-decorator/src/model/HTTPControllerMeta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export class HTTPControllerMeta implements ControllerMetadata {
public readonly methods: readonly HTTPMethodMeta[];
public readonly needAcl: boolean;
public readonly aclCode?: string;
public readonly host?: string;
public readonly hosts?: string[];

constructor(
className: string,
Expand All @@ -25,7 +25,7 @@ export class HTTPControllerMeta implements ControllerMetadata {
methods: HTTPMethodMeta[],
needAcl: boolean,
aclCode: string | undefined,
host: string | undefined,
hosts: string[] | undefined,
) {
this.protoName = protoName;
this.controllerName = controllerName;
Expand All @@ -35,7 +35,7 @@ export class HTTPControllerMeta implements ControllerMetadata {
this.methods = methods;
this.needAcl = needAcl;
this.aclCode = aclCode;
this.host = host;
this.hosts = hosts;
}

getMethodRealPath(method: HTTPMethodMeta) {
Expand All @@ -45,11 +45,11 @@ export class HTTPControllerMeta implements ControllerMetadata {
return method.path;
}

getMethodHost(method: HTTPMethodMeta): string | undefined {
if (this.host) {
return this.host;
getMethodHosts(method: HTTPMethodMeta): string[] | undefined {
if (this.hosts) {
return this.hosts;
}
return method.host;
return method.hosts;
}

getMethodName(method: HTTPMethodMeta) {
Expand Down
6 changes: 3 additions & 3 deletions core/controller-decorator/src/model/HTTPMethodMeta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export class HTTPMethodMeta implements MethodMeta {
public readonly priority: number;
public readonly needAcL: boolean;
public readonly aclCode: string | undefined;
public readonly host: string | undefined;
public readonly hosts: string[] | undefined;

constructor(
name: string,
Expand All @@ -85,7 +85,7 @@ export class HTTPMethodMeta implements MethodMeta {
priority: number,
needAcl: boolean,
aclCode: string | undefined,
host: string | undefined,
hosts: string[] | undefined,
) {
this.name = name;
this.path = path;
Expand All @@ -96,7 +96,7 @@ export class HTTPMethodMeta implements MethodMeta {
this.priority = priority;
this.needAcL = needAcl;
this.aclCode = aclCode;
this.host = host;
this.hosts = hosts;
}
}

Expand Down
2 changes: 2 additions & 0 deletions core/controller-decorator/src/model/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ export enum ControllerType {
MGW_RPC = 'MGW_RPC',
}

export type HostType = string | string [];

export type ControllerTypeLike = ControllerType | string;

export enum MethodType {
Expand Down
6 changes: 3 additions & 3 deletions core/controller-decorator/src/util/ControllerInfoUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,11 @@ export default class ControllerInfoUtil {
return MetadataUtil.getMetaData(CONTROLLER_ACL, clazz);
}

static addControllerHost(host: string, clazz: EggProtoImplClass) {
MetadataUtil.defineMetaData(CONTROLLER_HOST, host, clazz);
static addControllerHosts(hosts: string[], clazz: EggProtoImplClass) {
MetadataUtil.defineMetaData(CONTROLLER_HOST, hosts, clazz);
}

static getControllerHost(clazz: EggProtoImplClass): string | undefined {
static getControllerHosts(clazz: EggProtoImplClass): string[] | undefined {
return MetadataUtil.getMetaData(CONTROLLER_HOST, clazz);
}
}
12 changes: 6 additions & 6 deletions core/controller-decorator/src/util/MethodInfoUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const METHOD_CONTEXT_INDEX = Symbol.for('EggPrototype#controller#method#context'
const METHOD_MIDDLEWARES = Symbol.for('EggPrototype#method#middlewares');
const METHOD_ACL = Symbol.for('EggPrototype#method#acl');

type METHOD_MAP = Map<string, ControllerTypeLike>;
type METHOD_MAP = Map<string, ControllerTypeLike | string[]>;
type MethodContextIndexMap = Map<string, number>;
type MethodMiddlewareMap = Map<string, MiddlewareFunc[]>;
type MethodAclMap = Map<string, string | undefined>;
Expand All @@ -21,7 +21,7 @@ export default class MethodInfoUtil {

static getMethodControllerType(clazz: EggProtoImplClass, methodName: string): ControllerTypeLike | undefined {
const methodControllerMap: METHOD_MAP | undefined = MetadataUtil.getMetaData(METHOD_CONTROLLER_TYPE_MAP, clazz);
return methodControllerMap?.get(methodName);
return methodControllerMap?.get(methodName) as ControllerTypeLike | undefined;
}

static setMethodContextIndexInArgs(index: number, clazz: EggProtoImplClass, methodName: string) {
Expand Down Expand Up @@ -60,13 +60,13 @@ export default class MethodInfoUtil {
return methodAclMap?.get(methodName);
}

static setMethodHost(host: string, clazz: EggProtoImplClass, methodName: string) {
static setMethodHosts(hosts: string[], clazz: EggProtoImplClass, methodName: string) {
const methodControllerMap: METHOD_MAP = MetadataUtil.initOwnMapMetaData(METHOD_CONTROLLER_HOST, clazz, new Map());
methodControllerMap.set(methodName, host);
methodControllerMap.set(methodName, hosts);
}

static getMethodHost(clazz: EggProtoImplClass, methodName: string): string | undefined {
static getMethodHosts(clazz: EggProtoImplClass, methodName: string): string[] | undefined {
const methodControllerMap: METHOD_MAP | undefined = MetadataUtil.getMetaData(METHOD_CONTROLLER_HOST, clazz);
return methodControllerMap?.get(methodName);
return methodControllerMap?.get(methodName) as string[] | undefined;
}
}
2 changes: 1 addition & 1 deletion core/controller-decorator/test/Acl.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import assert from 'assert';
import { AclController } from './fixtures/AclController';
import { ControllerMetaBuilderFactory } from '../src/builder/ControllerMetaBuilderFactory';
import { ControllerType } from '../src/model';
import { ControllerType, HTTPControllerMeta } from '../src/model';

describe('test/Context.test.ts', () => {
it('should work', () => {
Expand Down
8 changes: 4 additions & 4 deletions core/controller-decorator/test/http/Host.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import MethodInfoUtil from '../../src/util/MethodInfoUtil';

describe('test/Host.test.ts', () => {
it('controller Host work', () => {
const controllerHost = ControllerInfoUtil.getControllerHost(HostController);
assert(controllerHost === 'foo.eggjs.com');
const controllerHost = ControllerInfoUtil.getControllerHosts(HostController);
assert(controllerHost![0] === 'foo.eggjs.com');
});

it('method Host work', () => {
const methodHost = MethodInfoUtil.getMethodHost(HostController, 'bar');
assert(methodHost === 'bar.eggjs.com');
const methodHost = MethodInfoUtil.getMethodHosts(HostController, 'bar');
assert(methodHost![0] === 'bar.eggjs.com');
});
});
51 changes: 27 additions & 24 deletions plugin/controller/lib/impl/http/HTTPMethodRegister.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,18 +118,20 @@ export class HTTPMethodRegister {

// 2. check duplicate with host tegg controller
let hostRouter;
const host = this.controllerMeta.getMethodHost(this.methodMeta);
if (host) {
hostRouter = this.checkRouters.get(host);
if (!hostRouter) {
hostRouter = new EggRouter({ sensitive: true }, {});
this.checkRouters.set(host, hostRouter!);
const hosts = this.controllerMeta.getMethodHosts(this.methodMeta) || [];
hosts.forEach(h => {
if (h) {
hostRouter = this.checkRouters.get(h);
if (!hostRouter) {
hostRouter = new EggRouter({ sensitive: true }, {});
this.checkRouters.set(h, hostRouter!);
}
}
}
if (hostRouter) {
this.checkDuplicateInRouter(hostRouter);
this.registerToRouter(hostRouter);
}
if (hostRouter) {
this.checkDuplicateInRouter(hostRouter);
this.registerToRouter(hostRouter);
}
});
}

private registerToRouter(router: KoaRouter<any, Context>) {
Expand Down Expand Up @@ -159,19 +161,20 @@ export class HTTPMethodRegister {
if (aclMiddleware) {
methodMiddlewares.push(aclMiddleware);
}
const host = this.controllerMeta.getMethodHost(this.methodMeta);
const handler = this.createHandler(this.methodMeta, host);
Reflect.apply(routerFunc, this.router,
[ methodName, methodRealPath, ...methodMiddlewares, handler ]);

// https://github.com/eggjs/egg-core/blob/0af6178022e7734c4a8b17bb56d592b315207883/lib/egg.js#L279
const regExp = pathToRegexp(methodRealPath, {
sensitive: true,
const hosts = this.controllerMeta.getMethodHosts(this.methodMeta) || [ undefined ];
hosts.forEach(h => {
const handler = this.createHandler(this.methodMeta, h);
Reflect.apply(routerFunc, this.router,
[ methodName, methodRealPath, ...methodMiddlewares, handler ]);
// https://github.com/eggjs/egg-core/blob/0af6178022e7734c4a8b17bb56d592b315207883/lib/egg.js#L279
const regExp = pathToRegexp(methodRealPath, {
sensitive: true,
});
rootProtoManager.registerRootProto(this.methodMeta.method, (ctx: EggContext) => {
if (regExp.test(ctx.path)) {
return this.proto;
}
}, h || '');
});
rootProtoManager.registerRootProto(this.methodMeta.method, (ctx: EggContext) => {
if (regExp.test(ctx.path)) {
return this.proto;
}
}, host || '');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
Host,
} from '@eggjs/tegg';

@Host('bar.eggjs.com')
@HTTPController({
path: '/apps',
})
Expand All @@ -14,6 +13,7 @@ export class AppController2 {
method: HTTPMethodEnum.GET,
path: '/:id',
})
@Host('bar.eggjs.com')
async get() {
return 'bar';
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {
HTTPController,
HTTPMethod,
HTTPMethodEnum,
Host,
} from '@eggjs/tegg';

@Host([ 'apple.eggjs.com', 'a.eggjs.com' ])
@HTTPController({
controllerName: 'MultiHostController',
path: '/apps',
})
export class MultiHostController {
@HTTPMethod({
method: HTTPMethodEnum.GET,
path: '/apple',
})
async apple() {
return 'apple';
}

@HTTPMethod({
method: HTTPMethodEnum.GET,
path: '/a',
})
async a() {
return 'a';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import {
HTTPController,
HTTPMethod,
HTTPMethodEnum,
Host,
} from '@eggjs/tegg';

@HTTPController({
controllerName: 'MultiMethodHostController',
path: '/apps',
})
export class MultiMethodHostController {
@HTTPMethod({
method: HTTPMethodEnum.GET,
path: '/orange',
})
@Host([ 'orange.eggjs.com', 'o.eggjs.com' ])
async orange() {
return 'orange';
}

@HTTPMethod({
method: HTTPMethodEnum.GET,
path: '/juice',
})
@Host('juice.eggjs.com')
async juice() {
return 'juice';
}
}
Loading

0 comments on commit f6679de

Please sign in to comment.