Skip to content

Commit

Permalink
refactor(common): refactoring PlatformBuilder fo Fastify
Browse files Browse the repository at this point in the history
  • Loading branch information
Romakita committed Jan 3, 2024
1 parent c20c655 commit 32384bb
Show file tree
Hide file tree
Showing 13 changed files with 91 additions and 246 deletions.
2 changes: 2 additions & 0 deletions packages/core/src/utils/http/getHostInfoFromPort.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ export function getHostInfoFromPort(protocol: string, addressPort: any) {
}
};
}

export type ReturnHostInfoFromPort = ReturnType<typeof getHostInfoFromPort>;
4 changes: 2 additions & 2 deletions packages/platform/common/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ module.exports = {
coverageThreshold: {
global: {
statements: 98.3,
branches: 91.71,
functions: 95.8,
branches: 91.52,
functions: 95.78,
lines: 98.3
}
}
Expand Down
86 changes: 48 additions & 38 deletions packages/platform/common/src/builder/PlatformBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,12 @@ export class PlatformBuilder<App = TsED.Application> {
settings: configuration
});

this.log(`Loading ${adapterKlass.NAME.toUpperCase()} platform adapter...`);

this.#adapter = this.#injector.get<PlatformAdapter<App>>(PlatformAdapter)!;

this.createHttpServers();

this.#adapter.onInit();

this.log("Injector created...");
}

Expand Down Expand Up @@ -178,15 +178,56 @@ export class PlatformBuilder<App = TsED.Application> {
}

public async runLifecycle() {
// init adapter (Express, Koa, etc...)
await this.#adapter.onInit();

setLoggerConfiguration(this.injector);

// create the middleware mapping to be executed to the expected hook
await this.mapTokenMiddlewares();

await this.loadInjector();

// add the context middleware to the application
this.log("Mount app context");
this.#adapter.useContext();

await this.loadRoutes();
// init routes (controllers, middlewares, etc...)
this.log("Load routes");
await this.#adapter.beforeLoadRoutes();

// istanbul ignore next
if (this.settings.get("logger.level") !== "off") {
const {PlatformLogMiddleware} = await import("@tsed/platform-log-middleware");
this.app.use(PlatformLogMiddleware);
}

if (this.rootModule.$beforeRoutesInit) {
await this.rootModule.$beforeRoutesInit();
// remove method to avoid multiple call and preserve hook order
this.rootModule.$beforeRoutesInit = () => {};
}

// Hooks execution (adding middlewares, controllers, services, etc...)
await this.loadStatics("$beforeRoutesInit");
await this.callHook("$beforeRoutesInit");

const routes = this.injector.settings.get<Route[]>("routes");

this.platform.addRoutes(routes);

await this.callHook("$onRoutesInit");

await this.loadStatics("$afterRoutesInit");
await this.callHook("$afterRoutesInit");

await this.#adapter.afterLoadRoutes();

// map routers are loaded after all hooks because it contains all added middlewares/controllers in the virtual Ts.ED layers
// This step will convert all Ts.ED layers to the platform layer (Express or Koa)
await this.mapRouters();

// Server is bootstrapped and ready to listen

return this;
}
Expand Down Expand Up @@ -270,40 +311,6 @@ export class PlatformBuilder<App = TsED.Application> {
return this.#promise;
}

protected async loadRoutes() {
await this.#adapter.beforeLoadRoutes();

// istanbul ignore next
if (this.settings.get("logger.level") !== "off") {
const {PlatformLogMiddleware} = await import("@tsed/platform-log-middleware");
this.app.use(PlatformLogMiddleware);
}

this.log("Load routes");

if (this.rootModule.$beforeRoutesInit) {
await this.rootModule.$beforeRoutesInit();
this.rootModule.$beforeRoutesInit = () => {};
}

await this.loadStatics("$beforeRoutesInit");
await this.callHook("$beforeRoutesInit");

const routes = this.injector.settings.get<Route[]>("routes");

this.platform.addRoutes(routes);

await this.callHook("$onRoutesInit");

await this.loadStatics("$afterRoutesInit");

await this.callHook("$afterRoutesInit");

await this.#adapter.afterLoadRoutes();

await this.mapRouters();
}

protected mapRouters() {
const layers = this.platform.getLayers();

Expand Down Expand Up @@ -412,6 +419,9 @@ export class PlatformBuilder<App = TsED.Application> {

middlewares = await Promise.all(promises);

this.injector.settings.set("middlewares", middlewares);
this.injector.settings.set(
"middlewares",
middlewares.filter((middleware) => middleware.use)
);
}
}
24 changes: 12 additions & 12 deletions packages/platform/common/src/services/PlatformAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,21 @@ export abstract class PlatformAdapter<App = TsED.Application> {
return this.injector.get<PlatformApplication<App>>("PlatformApplication")!;
}

/**
* Called after the injector instantiation
*/
onInit(): any {}
getServers(): CreateServerReturn[] {
return [createHttpServer(this.injector, this.app.callback()), createHttpsServer(this.injector, this.app.callback())].filter(
Boolean
) as any[];
}

onInit(): Promise<void> | void {
return Promise.resolve();
}

beforeLoadRoutes(): Promise<any> {
beforeLoadRoutes(): Promise<void> | void {
return Promise.resolve();
}

afterLoadRoutes(): Promise<any> {
afterLoadRoutes(): Promise<void> | void {
return Promise.resolve();
}

Expand All @@ -51,12 +56,6 @@ export abstract class PlatformAdapter<App = TsED.Application> {
*/
abstract mapHandler(handler: Function, layer: PlatformHandlerMetadata): Function;

getServers(): CreateServerReturn[] {
return [createHttpServer(this.injector, this.app.callback()), createHttpsServer(this.injector, this.app.callback())].filter(
Boolean
) as any[];
}

/**
* Return the app instance
*/
Expand Down Expand Up @@ -89,6 +88,7 @@ export interface PlatformBuilderSettings<App = TsED.Application> extends Partial

export class FakeAdapter extends PlatformAdapter<any> {
providers: ProviderOpts[] = [];
static readonly NAME: string = "FAKE_ADAPTER";

static createFakeRawDriver() {
// istanbul ignore next
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe("createHttpServer", () => {
jest.spyOn(injector.logger, "info").mockReturnValue(undefined);
jest.spyOn(injector.logger, "debug").mockReturnValue(undefined);
jest.spyOn(server, "listen").mockReturnValue(undefined);
jest.spyOn(server, "address").mockReturnValue({port: 8089});
jest.spyOn(server, "address").mockReturnValue({port: 8089, address: "0.0.0.0"});
jest.spyOn(server, "on").mockImplementation((event: string, cb: any) => {
if (event === "listening") {
cb();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ describe("createHttpsServer", () => {
jest.spyOn(injector.logger, "info").mockReturnValue(undefined);
jest.spyOn(injector.logger, "debug").mockReturnValue(undefined);
jest.spyOn(server, "listen").mockReturnValue(undefined);
jest.spyOn(server, "address").mockReturnValue({port: 8089});
jest.spyOn(server, "address").mockReturnValue({port: 8089, address: "0.0.0.0"});
jest.spyOn(server, "on").mockImplementation((event: string, cb: any) => {
if (event === "listening") {
cb();
Expand Down
22 changes: 18 additions & 4 deletions packages/platform/common/src/utils/createServer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {getHostInfoFromPort} from "@tsed/core";
import {getHostInfoFromPort, ReturnHostInfoFromPort} from "@tsed/core";
import {InjectorService, ProviderScope, TokenProvider} from "@tsed/di";
import Http from "http";
import Http2 from "http2";
Expand All @@ -9,14 +9,15 @@ export interface CreateServerOptions {
token: TokenProvider;
type: "http" | "https";
port: string | false;
listen?: (hostInfo: ReturnHostInfoFromPort) => Promise<any>;
server: () => Http.Server | Https.Server | Http2.Http2Server;
}

export type CreateServerReturn = () => Promise<Http.Server | Https.Server | Http2.Http2Server>;

export function createServer(
injector: InjectorService,
{token, type, port, server: get}: CreateServerOptions
{token, type, port, server: get, listen}: CreateServerOptions
): undefined | CreateServerReturn {
const {settings} = injector;
const server = port !== false ? get() : null;
Expand All @@ -32,8 +33,21 @@ export function createServer(
const hostInfo = getHostInfoFromPort(type, port);

return async () => {
const resolvedHostInfo = await listenServer(injector, server, hostInfo);
settings.set(`${type}Port`, `${resolvedHostInfo.address}:${resolvedHostInfo.port}`);
const url = `${hostInfo.protocol}://${hostInfo.address}:${port}`;
injector.logger.debug(`Start server on ${url}`);

await (listen ? listen(hostInfo) : listenServer(server, hostInfo));

const address = server.address();

if (address && typeof address !== "string") {
hostInfo.address = address.address;
hostInfo.port = address.port;
}

injector.logger.info(`Listen server on ${hostInfo.toString()}`);
settings.set(`${type}Port`, `${hostInfo.address}:${hostInfo.port}`);

return server;
};
}
Expand Down
22 changes: 4 additions & 18 deletions packages/platform/common/src/utils/listenServer.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,14 @@
import {getHostInfoFromPort} from "@tsed/core";
import type Http from "http";
import type Https from "https";
import type Http2 from "http2";
import {InjectorService} from "@tsed/di";
import {getHostInfoFromPort} from "@tsed/core";
import type Https from "https";

export function listenServer(
injector: InjectorService,
server: Http.Server | Https.Server | Http2.Http2Server,
hostInfo: ReturnType<typeof getHostInfoFromPort>
): Promise<ReturnType<typeof getHostInfoFromPort>> {
const {protocol, address, port} = hostInfo;
const url = `${protocol}://${address}:${port}`;
injector.logger.debug(`Start server on ${url}`);
export function listenServer(server: Http.Server | Https.Server | Http2.Http2Server, hostInfo: ReturnType<typeof getHostInfoFromPort>) {
const {address, port} = hostInfo;

const promise = new Promise((resolve, reject) => {
server.on("listening", resolve);
server.on("error", reject);
}).then(() => {
const port = (server.address() as any).port;
const info = {...hostInfo, port};

injector.logger.info(`Listen server on ${info.toString()}`);

return info;
});

server.listen(port, address as any);
Expand Down
4 changes: 2 additions & 2 deletions packages/platform/platform-express/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ module.exports = {
},
coverageThreshold: {
global: {
statements: 98.27,
statements: 98.26,
branches: 92.45,
functions: 100,
lines: 98.27
lines: 98.26
}
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,6 @@ export class PlatformExpress extends PlatformAdapter<Express.Application> {
const {app} = this;
const invoke = createContext(this.injector);

this.injector.logger.debug("Mount app context");

app.use(async (request: any, response: any, next: any) => {
const $ctx = invoke({request, response});
await $ctx.start();
Expand Down
2 changes: 0 additions & 2 deletions packages/platform/platform-koa/src/components/PlatformKoa.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,6 @@ export class PlatformKoa extends PlatformAdapter<Koa> {
const invoke = createContext(this.injector);
const platformExceptions = this.injector.get<PlatformExceptions>(PlatformExceptions);

this.injector.logger.debug("Mount app context");

app.use((koaContext: Context, next: Next) => {
const $ctx = invoke({
request: koaContext.request as any,
Expand Down
2 changes: 1 addition & 1 deletion tsdoc.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ module.exports = {
"!<rootDir>/packages/platform/platform-test-sdk",
"!**/node_modules"
],
outputDir: "<rootDir>/docs/api",
outputDir: "<rootDir>/docs-references/api",
baseUrl: "/api",
jsonOutputDir: "<rootDir>/docs/.vuepress/public",
scope: "@tsed",
Expand Down
Loading

0 comments on commit 32384bb

Please sign in to comment.