oa_based/src/main.ts

90 lines
2.9 KiB
TypeScript
Raw Normal View History

2024-02-28 17:02:46 +08:00
import cluster from 'node:cluster';
import path from 'node:path';
2024-02-28 08:32:35 +08:00
2024-02-28 17:02:46 +08:00
import { HttpStatus, Logger, UnprocessableEntityException, ValidationPipe } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { NestFactory } from '@nestjs/core';
import { NestFastifyApplication } from '@nestjs/platform-fastify';
2024-02-28 08:32:35 +08:00
2024-02-28 17:02:46 +08:00
import { useContainer } from 'class-validator';
2024-02-28 08:32:35 +08:00
2024-02-28 17:02:46 +08:00
import { AppModule } from './app.module';
2024-02-28 08:32:35 +08:00
2024-02-28 17:02:46 +08:00
import { fastifyApp } from './common/adapters/fastify.adapter';
import { RedisIoAdapter } from './common/adapters/socket.adapter';
import { LoggingInterceptor } from './common/interceptors/logging.interceptor';
import type { ConfigKeyPaths } from './config';
import { isDev, isMainProcess } from './global/env';
import { setupSwagger } from './setup-swagger';
import { LoggerService } from './shared/logger/logger.service';
2024-02-28 08:32:35 +08:00
2024-02-28 17:02:46 +08:00
declare const module: any;
2024-02-28 08:32:35 +08:00
async function bootstrap() {
2024-02-28 17:02:46 +08:00
const app = await NestFactory.create<NestFastifyApplication>(AppModule, fastifyApp, {
bufferLogs: true,
snapshot: true,
// forceCloseConnections: true,
});
2024-02-28 08:32:35 +08:00
2024-02-28 17:02:46 +08:00
const configService = app.get(ConfigService<ConfigKeyPaths>);
2024-02-28 08:32:35 +08:00
2024-02-28 17:02:46 +08:00
const { port, globalPrefix } = configService.get('app', { infer: true });
2024-02-28 08:32:35 +08:00
// class-validator 的 DTO 类中注入 nest 容器的依赖 (用于自定义验证器)
2024-02-28 17:02:46 +08:00
useContainer(app.select(AppModule), { fallbackOnErrors: true });
2024-02-28 08:32:35 +08:00
2024-02-28 17:02:46 +08:00
app.enableCors({ origin: '*', credentials: true });
app.setGlobalPrefix(globalPrefix);
app.useStaticAssets({ root: path.join(__dirname, '..', 'public') });
2024-02-28 08:32:35 +08:00
// Starts listening for shutdown hooks
2024-02-28 17:02:46 +08:00
!isDev && app.enableShutdownHooks();
2024-02-28 08:32:35 +08:00
2024-02-28 17:02:46 +08:00
if (isDev) app.useGlobalInterceptors(new LoggingInterceptor());
2024-02-28 08:32:35 +08:00
app.useGlobalPipes(
new ValidationPipe({
transform: true,
whitelist: true,
transformOptions: { enableImplicitConversion: true },
// forbidNonWhitelisted: true, // 禁止 无装饰器验证的数据通过
errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY,
stopAtFirstError: true,
exceptionFactory: errors =>
new UnprocessableEntityException(
2024-02-28 17:02:46 +08:00
errors.map(e => {
const rule = Object.keys(e.constraints!)[0];
const msg = e.constraints![rule];
return msg;
})[0]
2024-02-28 08:32:35 +08:00
),
2024-02-28 17:02:46 +08:00
})
);
2024-02-28 08:32:35 +08:00
2024-02-28 17:02:46 +08:00
app.useWebSocketAdapter(new RedisIoAdapter(app));
2024-02-28 08:32:35 +08:00
2024-02-28 17:02:46 +08:00
setupSwagger(app, configService);
2024-02-28 08:32:35 +08:00
await app.listen(port, '0.0.0.0', async () => {
2024-02-28 17:02:46 +08:00
app.useLogger(app.get(LoggerService));
const url = await app.getUrl();
const { pid } = process;
const env = cluster.isPrimary;
const prefix = env ? 'P' : 'W';
2024-02-28 08:32:35 +08:00
2024-02-28 17:02:46 +08:00
if (!isMainProcess) return;
2024-02-28 08:32:35 +08:00
2024-02-28 17:02:46 +08:00
const logger = new Logger('NestApplication');
logger.log(`[${prefix + pid}] Server running on ${url}`);
2024-02-28 08:32:35 +08:00
2024-02-28 17:02:46 +08:00
if (isDev) logger.log(`[${prefix + pid}] OpenAPI: ${url}/api-docs`);
});
2024-02-28 08:32:35 +08:00
if (module.hot) {
2024-02-28 17:02:46 +08:00
module.hot.accept();
module.hot.dispose(() => app.close());
2024-02-28 08:32:35 +08:00
}
}
2024-02-28 17:02:46 +08:00
bootstrap();