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();
|