Skip to content

Commit

Permalink
Merge e323476 into f4d761c
Browse files Browse the repository at this point in the history
  • Loading branch information
Romakita committed Nov 19, 2021
2 parents f4d761c + e323476 commit ee59d1d
Show file tree
Hide file tree
Showing 11 changed files with 176 additions and 51 deletions.
2 changes: 1 addition & 1 deletion .nycrc
Expand Up @@ -39,5 +39,5 @@
"lines": 99.55,
"statements": 99.52,
"functions": 99.17,
"branches": 89.36
"branches": 89.3
}
40 changes: 39 additions & 1 deletion packages/platform/common/src/builder/PlatformBuilder.spec.ts
Expand Up @@ -6,6 +6,7 @@ import {
BeforeListen,
BeforeRoutesInit,
Controller,
Injectable,
InjectorService,
Module,
normalizePath,
Expand All @@ -32,8 +33,12 @@ describe("PlatformBuilder", () => {
}
];

static create(module: Type<any>, settings: Partial<TsED.Configuration> = {}) {
return PlatformBuilder.build<PlatformCustom>(this, module, settings);
}

static async bootstrap(module: Type<any>, settings: Partial<TsED.Configuration> = {}) {
return PlatformBuilder.build<PlatformCustom>(this).bootstrap(module, settings);
return PlatformBuilder.build<PlatformCustom>(this, module, settings).bootstrap();
}

async loadStatics(): Promise<void> {
Expand Down Expand Up @@ -146,6 +151,39 @@ describe("PlatformBuilder", () => {
expect(server.injector.emit).to.have.been.calledWithExactly("$onDestroy");
});
});

describe("callback()", () => {
it("should return the callback", async () => {
// WHEN
const server = await PlatformCustom.bootstrap(ServerModule, {
httpPort: false,
httpsPort: false
});

expect(server.callback()).to.deep.eq(server.app.raw);

server.callback({} as any, {} as any);
});
});

describe("useProvider()", () => {
it("should add provider", async () => {
// WHEN
const server = PlatformCustom.create(ServerModule, {
httpPort: false,
httpsPort: false
});

@Injectable()
class Token {}

server.useProvider(Token, {});

await server.bootstrap();

expect(server.injector.get(Token)).to.be.instanceof(Token);
});
});
describe("addComponents", () => {
it("should add components", async () => {
// GIVEN
Expand Down
86 changes: 53 additions & 33 deletions packages/platform/common/src/builder/PlatformBuilder.ts
@@ -1,5 +1,5 @@
import {deepMerge, Env, nameOf, Store, toMap, Type} from "@tsed/core";
import {colors, Container, createContainer, InjectorService, IProvider, ProviderScope, ProviderType, setLoggerLevel} from "@tsed/di";
import {nameOf, toMap, Type} from "@tsed/core";
import {colors, createContainer, InjectorService, IProvider, ProviderScope, setLoggerLevel} from "@tsed/di";
import {importProviders} from "@tsed/components-scan";
import {getMiddlewaresForHook} from "@tsed/platform-middlewares";
import {GlobalAcceptMimesMiddleware} from "../middlewares";
Expand All @@ -22,6 +22,16 @@ import {PlatformStaticsSettings} from "../config/interfaces/PlatformStaticsSetti
import {getStaticsOptions} from "../utils/getStaticsOptions";
import {Route} from "../interfaces/Route";
import {getConfiguration} from "../utils/getConfiguration";
import {IncomingMessage, ServerResponse} from "http";

const DEFAULT_PROVIDERS = [
{provide: PlatformHandler},
{provide: PlatformResponse},
{provide: PlatformRequest},
{provide: PlatformRouter},
{provide: PlatformApplication},
{provide: Platform}
];

/**
* @ignore
Expand All @@ -34,35 +44,36 @@ export interface PlatformType<T = any> extends Type<T> {
* @ignore
*/
export interface PlatformBootstrap {
create(module: Type<any>, settings?: Partial<TsED.Configuration>): PlatformBuilder;

bootstrap(module: Type<any>, settings?: Partial<TsED.Configuration>): Promise<PlatformBuilder>;
}

export interface PlatformBuilderOptions {
name: string;
providers: IProvider[];
settings: any;
module: Type<any>;
}

/**
* @platform
*/
export abstract class PlatformBuilder<App = TsED.Application, Router = TsED.Router> {
static currentPlatform: Type<PlatformBuilder<any, any>> & PlatformBootstrap;

readonly name: string = "";
protected startedAt = new Date();
protected current = new Date();
protected locals: Container;

#injector: InjectorService;
#providers: Map<Type, IProvider>;
#rootModule: Type<any>;

constructor({name, providers}: {name: string; providers: IProvider[]}) {
constructor({name, providers, settings, module}: PlatformBuilderOptions) {
this.name = name;
this.#providers = toMap<any, IProvider>(providers, "provide");

this.locals = new Container();
this.#rootModule = module;

this.useProvider(PlatformHandler, this.#providers.get(PlatformHandler))
.useProvider(PlatformResponse, this.#providers.get(PlatformResponse))
.useProvider(PlatformRequest, this.#providers.get(PlatformRequest))
.useProvider(PlatformRouter, this.#providers.get(PlatformRouter))
.useProvider(PlatformApplication, this.#providers.get(PlatformApplication))
.useProvider(Platform, this.#providers.get(Platform));
this.createInjector(module, providers, settings);
}

get injector(): InjectorService {
Expand Down Expand Up @@ -114,13 +125,29 @@ export abstract class PlatformBuilder<App = TsED.Application, Router = TsED.Rout
return this.settings.logger?.disableBootstrapLog;
}

static build<T extends PlatformBuilder<any, any>>(platformBuildClass: PlatformType<T>): T {
static build<T extends PlatformBuilder<any, any>>(
platformBuildClass: PlatformType<T>,
module: Type<any>,
settings: Partial<TsED.Configuration> = {}
): T {
return new platformBuildClass({
name: nameOf(platformBuildClass).replace("Platform", "").toLowerCase(),
module,
settings,
providers: platformBuildClass.providers
});
}

callback(): (req: IncomingMessage, res: ServerResponse) => void;
callback(req: IncomingMessage, res: ServerResponse): void;
callback(req?: IncomingMessage, res?: ServerResponse) {
if (req && res) {
return this.app.callback()(req, res);
}

return this.app.callback();
}

log(...data: any[]) {
return !this.disableBootstrapLog && this.logger.info(...data, this.diff());
}
Expand Down Expand Up @@ -241,11 +268,15 @@ export abstract class PlatformBuilder<App = TsED.Application, Router = TsED.Rout
}

useProvider(token: Type<any>, settings?: Partial<IProvider>) {
this.locals.addProvider(token, settings);
this.injector.addProvider(token, settings);

return this;
}

async bootstrap() {
return this.runLifecycle();
}

protected diff() {
const ms = colors.yellow(`+${new Date().getTime() - this.current.getTime()}ms`);
this.current = new Date();
Expand Down Expand Up @@ -281,17 +312,6 @@ export abstract class PlatformBuilder<App = TsED.Application, Router = TsED.Rout
return this;
}

protected async bootstrap(module: Type<any>, settings: Partial<TsED.Configuration> = {}) {
this.createInjector(module, {
...settings,
PLATFORM_NAME: this.name
});

await this.runLifecycle();

return this;
}

protected async listenServers(): Promise<void> {
await Promise.all([listenHttpServer(this.injector), listenHttpsServer(this.injector)]);
}
Expand Down Expand Up @@ -333,16 +353,16 @@ export abstract class PlatformBuilder<App = TsED.Application, Router = TsED.Rout
await this.callHook("$afterRoutesInit");
}

protected createInjector(module: Type<any>, settings: any) {
this.#rootModule = module;

protected createInjector(module: Type<any>, providers: IProvider[], settings: any) {
const configuration = getConfiguration(settings, module);
configuration.PLATFORM_NAME = this.name;

this.#injector = createInjector(configuration);

// configure locals providers
this.locals.forEach((provider) => {
this.injector.addProvider(provider.token, provider);
providers = [...DEFAULT_PROVIDERS, ...providers];

toMap<any, IProvider>(providers, "provide").forEach((provider, token) => {
this.injector.addProvider(token, provider);
});

createPlatformApplication(this.injector);
Expand Down
3 changes: 2 additions & 1 deletion packages/platform/common/src/services/PlatformTest.ts
Expand Up @@ -47,7 +47,8 @@ export class PlatformTest extends DITest {
}

// @ts-ignore
instance = await PlatformBuilder.build(platform).bootstrap(mod, DITest.configure(settings));
settings = DITest.configure(settings);
instance = await PlatformBuilder.build(platform, mod, settings).bootstrap();

if (!settings.listen) {
await instance.callHook("$beforeListen");
Expand Down
6 changes: 4 additions & 2 deletions packages/platform/platform-aws/src/components/PlatformAws.ts
Expand Up @@ -45,7 +45,9 @@ export class PlatformAws {
// istanbul ignore next
PlatformBuilder.currentPlatform = settings.platform || PlatformBuilder.currentPlatform;

this.promise = PlatformBuilder.currentPlatform.bootstrap(module, {...settings, disableComponentScan: true}).then(PlatformAws.onInit);
const platform = PlatformBuilder.currentPlatform.create(module, settings);

this.promise = platform.bootstrap().then(PlatformAws.onInit);

return PlatformAws;
}
Expand All @@ -66,7 +68,7 @@ export class PlatformAws {
await platform.callHook("$beforeListen");

// create Aws server
PlatformAws.awsServer = createServer(platform.app.callback(), PlatformAws.onListen, binaryMimeTypes);
PlatformAws.awsServer = createServer(platform.callback(), PlatformAws.onListen, binaryMimeTypes);
}

protected static async onListen() {
Expand Down
5 changes: 3 additions & 2 deletions packages/platform/platform-express/package.json
Expand Up @@ -42,7 +42,8 @@
},
"scripts": {
"build": "tsc --build tsconfig.compile.json",
"start": "ts-node -r tsconfig-paths/register test/app/index.ts"
"start": "ts-node -r tsconfig-paths/register test/app/index.ts",
"start:emulate": "ts-node -r tsconfig-paths/register test/app/emulate.ts"
},
"dependencies": {
"express": "^4.17.1",
Expand Down Expand Up @@ -79,4 +80,4 @@
"@types/multer": "^1.4.5",
"body-parser": "1.19.0"
}
}
}
Expand Up @@ -30,8 +30,8 @@ describe("PlatformExpress", () => {
await PlatformExpress.bootstrap(Test, {});
await PlatformExpress.bootstrap(Test);

expect(PlatformExpress.build).to.have.been.calledWithExactly(PlatformExpress);
expect(platform.bootstrap).to.have.been.calledWithExactly(Test, {});
expect(PlatformExpress.build).to.have.been.calledWithExactly(PlatformExpress, Test, {});
expect(platform.bootstrap).to.have.been.calledWithExactly();
expect(PlatformExpress.providers).to.deep.equal([
{
provide: PlatformApplication,
Expand Down
Expand Up @@ -48,8 +48,27 @@ export class PlatformExpress extends PlatformBuilder<Express.Application, Expres
}
];

/**
* Create new serverless application. In this mode, the component scan are disabled.
* @param module
* @param settings
*/
static create(module: Type<any>, settings: Partial<TsED.Configuration> = {}) {
return this.build<PlatformExpress>(PlatformExpress, module, {
httpsPort: false,
httpPort: false,
...settings,
disableComponentsScan: true
});
}

/**
* Bootstrap a server application
* @param module
* @param settings
*/
static async bootstrap(module: Type<any>, settings: Partial<TsED.Configuration> = {}): Promise<PlatformExpress> {
return this.build<PlatformExpress>(PlatformExpress).bootstrap(module, settings);
return this.build<PlatformExpress>(PlatformExpress, module, settings).bootstrap();
}

protected useRouter(): this {
Expand Down
27 changes: 27 additions & 0 deletions packages/platform/platform-express/test/app/emulate.ts
@@ -0,0 +1,27 @@
import http from "http";
import {PlatformExpress} from "@tsed/platform-express";
import {Server} from "./Server";
import {Controller} from "@tsed/di";
import {Get} from "@tsed/schema";
import {QueryParams} from "@tsed/platform-params";

@Controller("/hello")
class HelloWorld {
@Get("/")
get(@QueryParams("q") query: string[]) {
return { test: "Hello world" };
}
}

const platform = PlatformExpress.create(Server, {
mount: { "/rest": [HelloWorld] }
});

const promise = platform.bootstrap()

const server = http.createServer(async (req, res) => {
await promise;
platform.callback(req, res);
});

server.listen(3002);
Expand Up @@ -24,8 +24,8 @@ describe("PlatformKoa", () => {
await PlatformKoa.bootstrap(Test, {});
await PlatformKoa.bootstrap(Test);

expect(PlatformKoa.build).to.have.been.calledWithExactly(PlatformKoa);
expect(platform.bootstrap).to.have.been.calledWithExactly(Test, {});
expect(PlatformKoa.build).to.have.been.calledWithExactly(PlatformKoa, Test, {});
expect(platform.bootstrap).to.have.been.calledWithExactly();
expect(PlatformKoa.providers).to.deep.equal([
{
provide: PlatformResponse,
Expand Down

0 comments on commit ee59d1d

Please sign in to comment.