create-dp-koa 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -0
- package/index.mjs +97 -0
- package/package.json +33 -0
- package/template/.env.development +9 -0
- package/template/.env.production +12 -0
- package/template/.github/workflows/ci-cd.yml +182 -0
- package/template/.trae/documents/controller_development_plan.md +386 -0
- package/template/.trae/skills/00-backend-core.skill.md +50 -0
- package/template/.trae/skills/01-backend-skill-router.skill.md +55 -0
- package/template/.trae/skills/10-backend-api.skill.md +54 -0
- package/template/.trae/skills/11-backend-controller-recipes.skill.md +107 -0
- package/template/.trae/skills/20-backend-repository.skill.md +25 -0
- package/template/.trae/skills/21-backend-service.skill.md +135 -0
- package/template/.trae/skills/25-backend-comments-and-doc.skill.md +97 -0
- package/template/.trae/skills/30-backend-validation.skill.md +320 -0
- package/template/.trae/skills/40-backend-error-logging.skill.md +21 -0
- package/template/.trae/skills/50-backend-bootstrap-lifecycle.skill.md +90 -0
- package/template/.trae/skills/60-backend-router-registration.skill.md +71 -0
- package/template/.trae/skills/70-backend-middleware.skill.md +98 -0
- package/template/.trae/skills/80-backend-utils-and-libs.skill.md +90 -0
- package/template/.trae/skills/85-backend-plugins.rule.md +64 -0
- package/template/.trae/skills/90-backend-testing.skill.md +29 -0
- package/template/.trae/skills/README.md +49 -0
- package/template/.vscode/launch.json +38 -0
- package/template/.vscode/settings.json +1 -0
- package/template/Dockerfile +36 -0
- package/template/README.md +229 -0
- package/template/docker-compose.yml +135 -0
- package/template/docs/API_DOCUMENTATION.md +837 -0
- package/template/docs/ARCHITECTURE_REFACTOR.md +109 -0
- package/template/docs/CACHE_MIGRATION_GUIDE.md +142 -0
- package/template/docs/DEPLOYMENT_GUIDE.md +1062 -0
- package/template/docs/DEVELOPMENT_GUIDE.md +1097 -0
- package/template/docs/DOCUMENTATION_CLEANUP_REPORT.md +166 -0
- package/template/docs/DOCUMENTATION_COMPLETION_REPORT.md +223 -0
- package/template/docs/DOCUMENTATION_INDEX.md +294 -0
- package/template/docs/DOCUMENTATION_STRUCTURE.md +221 -0
- package/template/docs/ENTERPRISE_ANNOTATION_SYSTEM_GUIDE.md +2069 -0
- package/template/docs/ENTERPRISE_DATABASE_ARCHITECTURE.md +318 -0
- package/template/docs/ENTERPRISE_DEPLOYMENT_GUIDE.md +547 -0
- package/template/docs/ENTERPRISE_ERROR_HANDLING_GUIDE.md +357 -0
- package/template/docs/ENTERPRISE_LOGGING_SYSTEM_GUIDE.md +494 -0
- package/template/docs/ENVIRONMENT_CONFIG_EXAMPLE.md +69 -0
- package/template/docs/FINAL_IMPLEMENTATION_SUMMARY.md +206 -0
- package/template/docs/HEALTH_CHECK_ROUTE_FIX.md +134 -0
- package/template/docs/IMPLEMENTATION_CHECKLIST.md +204 -0
- package/template/docs/INSTALLATION_GUIDE.md +611 -0
- package/template/docs/INTERCEPTOR_TESTING_REPORT.md +226 -0
- package/template/docs/INTERCEPTOR_TESTING_SCRIPTS.md +143 -0
- package/template/docs/LOGGING_OPTIMIZATION_GUIDE.md +126 -0
- package/template/docs/MEMORY_DATABASE_GUIDE.md +212 -0
- package/template/docs/NEW_ROUTER_INTEGRATION_GUIDE.md +345 -0
- package/template/docs/NEW_ROUTER_INTEGRATION_SUMMARY.md +259 -0
- package/template/docs/NEW_ROUTER_USAGE_GUIDE.md +364 -0
- package/template/docs/QUICK_START.md +268 -0
- package/template/docs/ROUTE_SLASH_COMPATIBILITY_FIX.md +191 -0
- package/template/docs/SERVICE_INTERCEPTOR_GUIDE.md +243 -0
- package/template/docs/SERVICE_LAYER_INDEX.md +205 -0
- package/template/docs/SERVICE_PATTERN_GUIDE.md +270 -0
- package/template/docs/SERVICE_RETURN_VALUE_SPECIFICATION.md +466 -0
- package/template/docs/SWAGGER_DEBUG_MODE_GUIDE.md +80 -0
- package/template/docs/SWAGGER_INTEGRATION_GUIDE.md +416 -0
- package/template/docs/TRANSACTION_MANAGER_USAGE.md +360 -0
- package/template/docs/TROUBLESHOOTING.md +869 -0
- package/template/env.production.example +62 -0
- package/template/jest.config.js +34 -0
- package/template/package-lock.json +13240 -0
- package/template/package.json +119 -0
- package/template/patches/typeorm+0.3.25.patch +22 -0
- package/template/scripts/sync-template.mjs +84 -0
- package/template/scripts/test-annotation-system.sh +48 -0
- package/template/scripts/test-core-functionality.sh +28 -0
- package/template/src/annotations/decorators/ConfigManagement.ts +9 -0
- package/template/src/annotations/decorators/DistributedTracing.ts +9 -0
- package/template/src/annotations/decorators/EnterprisePerformance.ts +9 -0
- package/template/src/annotations/decorators/PerformanceMonitor.ts +32 -0
- package/template/src/annotations/decorators/SecurityAudit.ts +9 -0
- package/template/src/annotations/index.ts +50 -0
- package/template/src/annotations/processors/ConfigManagementProcessor.ts +369 -0
- package/template/src/annotations/processors/DistributedTracingProcessor.ts +288 -0
- package/template/src/annotations/processors/EnterprisePerformanceProcessor.ts +189 -0
- package/template/src/annotations/processors/PerformanceMonitorProcessor.ts +101 -0
- package/template/src/annotations/processors/SecurityAuditProcessor.ts +345 -0
- package/template/src/annotations/processors/SwaggerProcessor.ts +612 -0
- package/template/src/annotations/processors/index.ts +10 -0
- package/template/src/app.ts +123 -0
- package/template/src/controllers/base.controller.ts +41 -0
- package/template/src/controllers/cacheManagement.controller.ts +131 -0
- package/template/src/controllers/captcha.controller.ts +57 -0
- package/template/src/controllers/demo/AnnotationDemoController.ts +118 -0
- package/template/src/controllers/example/EnterpriseExampleController.ts +297 -0
- package/template/src/controllers/example/ExampleController.ts +110 -0
- package/template/src/controllers/example/NewAnnotationExampleController.ts +159 -0
- package/template/src/controllers/example/SwaggerExampleController.ts +205 -0
- package/template/src/controllers/example/TransactionExample.controller.ts +336 -0
- package/template/src/controllers/health.controller.ts +235 -0
- package/template/src/controllers/home/register.controller.ts +58 -0
- package/template/src/controllers/home/ytGoods.controller.ts +92 -0
- package/template/src/controllers/home/ytShop.controller.ts +135 -0
- package/template/src/controllers/home/ytUser.controller.ts +89 -0
- package/template/src/controllers/logManagement.controller.ts +396 -0
- package/template/src/controllers/public/emailSend.controller.ts +65 -0
- package/template/src/controllers/public/ytUserAuth.controller.ts +174 -0
- package/template/src/controllers/testData.controller.ts +253 -0
- package/template/src/dto/controller/example/NewAnnotationExampleController.dto.ts +73 -0
- package/template/src/dto/controller/home/emailSend.controller.dto.ts +40 -0
- package/template/src/dto/controller/home/register.controller.dto.ts +45 -0
- package/template/src/dto/controller/home/ytGoods.controller.dto.ts +55 -0
- package/template/src/dto/controller/home/ytShop.controller.dto.ts +69 -0
- package/template/src/dto/controller/home/ytUser.controller.dto.ts +44 -0
- package/template/src/dto/controller/public/ytUserAuth.controller.dto.ts +63 -0
- package/template/src/dto/goods.dto.ts +212 -0
- package/template/src/dto/service/ytService.dto.ts +13 -0
- package/template/src/dto/user.dto.ts +177 -0
- package/template/src/entity/base.entity.ts +13 -0
- package/template/src/entity/columnTypes.ts +13 -0
- package/template/src/entity/goodsImagesUnlockKey.entity.ts +33 -0
- package/template/src/entity/goodsUnlocker.entity.ts +34 -0
- package/template/src/entity/index.ts +15 -0
- package/template/src/entity/shop.entity.ts +52 -0
- package/template/src/entity/shopUser.entity.ts +41 -0
- package/template/src/entity/ytGoods.entity.ts +94 -0
- package/template/src/entity/ytUser.entity.ts +96 -0
- package/template/src/examples/InterceptorExampleRunner.ts +284 -0
- package/template/src/examples/ServiceInterceptorExample.ts +214 -0
- package/template/src/examples/SwaggerProcessorExample.ts +169 -0
- package/template/src/examples/TransactionManagerDemo.ts +377 -0
- package/template/src/examples/cacheExamples.ts +155 -0
- package/template/src/framework/decorator/controller.ts +311 -0
- package/template/src/framework/decorator/processor/AnnotationDecorators.ts +100 -0
- package/template/src/framework/decorator/processor/AnnotationProcessor.ts +156 -0
- package/template/src/framework/decorator/processor/AnnotationProcessorConfig.ts +45 -0
- package/template/src/framework/decorator/processor/AnnotationRegistry.ts +117 -0
- package/template/src/framework/decorator/processor/AnnotationSystemInitializer.ts +95 -0
- package/template/src/framework/decorator/processor/ProcessorManager.ts +76 -0
- package/template/src/framework/decorator/processor/processors/CustomProcessors.ts +126 -0
- package/template/src/framework/decorator/processor/processors/DefaultProcessors.ts +207 -0
- package/template/src/framework/decorator/refactored/DecoratorFactory.ts +99 -0
- package/template/src/framework/decorator/refactored/DecoratorMetadataManager.ts +125 -0
- package/template/src/framework/decorator/refactored/DecoratorValidator.ts +128 -0
- package/template/src/framework/decorator/refactored/TypeSafeDecorators.ts +139 -0
- package/template/src/framework/decorator/refactored/index.ts +98 -0
- package/template/src/framework/decorator/swagger.ts +150 -0
- package/template/src/framework/interceptors/AdvancedServiceCallInterceptor.ts +375 -0
- package/template/src/framework/interceptors/ServiceCallInterceptor.ts +348 -0
- package/template/src/framework/interceptors/index.ts +19 -0
- package/template/src/framework/plugins/registry.ts +63 -0
- package/template/src/framework/plugins/types.ts +15 -0
- package/template/src/framework/types/ServiceResult.ts +151 -0
- package/template/src/framework/types/index.ts +16 -0
- package/template/src/framework/utils/CacheManager.ts +430 -0
- package/template/src/framework/utils/CacheService.ts +248 -0
- package/template/src/framework/utils/DtoValidator.ts +164 -0
- package/template/src/framework/utils/MigrationHelper.ts +179 -0
- package/template/src/framework/utils/MigrationManager.ts +256 -0
- package/template/src/framework/utils/NewRouter.ts +207 -0
- package/template/src/framework/utils/TransactionManager.ts +172 -0
- package/template/src/framework/utils/bootstrap.ts +445 -0
- package/template/src/framework/utils/cache.ts +269 -0
- package/template/src/framework/utils/databaseConfig.ts +148 -0
- package/template/src/framework/utils/db.ts +39 -0
- package/template/src/framework/utils/dbMonitor.ts +106 -0
- package/template/src/framework/utils/dynamicSwagger.ts +410 -0
- package/template/src/framework/utils/function.ts +61 -0
- package/template/src/framework/utils/gracefulShutdown.ts +131 -0
- package/template/src/framework/utils/logger.ts +388 -0
- package/template/src/framework/utils/metrics.ts +182 -0
- package/template/src/framework/utils/router.ts +417 -0
- package/template/src/framework/utils/swagger.ts +184 -0
- package/template/src/framework/utils/testDb.ts +19 -0
- package/template/src/framework/utils/token.ts +23 -0
- package/template/src/framework/utils/transform.ts +17 -0
- package/template/src/libs/aokEmailSender.ts +42 -0
- package/template/src/libs/captcha.ts +37 -0
- package/template/src/libs/cos.ts +45 -0
- package/template/src/libs/mCache.ts +7 -0
- package/template/src/libs/serviceValidate.ts +3 -0
- package/template/src/libs/tecentSms.ts +51 -0
- package/template/src/middlewares/a.middleware.ts +6 -0
- package/template/src/middlewares/error.middleware.ts +14 -0
- package/template/src/middlewares/logging.middleware.ts +187 -0
- package/template/src/middlewares/static.middleware.ts +79 -0
- package/template/src/middlewares/swagger.middleware.ts +70 -0
- package/template/src/middlewares/token.middleware.ts +32 -0
- package/template/src/migrations/1700000000000-InitialDatabaseStructure.ts +172 -0
- package/template/src/migrations/index.ts +6 -0
- package/template/src/plugins/weboffice/core/context.ts +47 -0
- package/template/src/plugins/weboffice/core/errors.ts +51 -0
- package/template/src/plugins/weboffice/core/types.ts +63 -0
- package/template/src/plugins/weboffice/core/utils.ts +7 -0
- package/template/src/plugins/weboffice/entities/index.ts +3 -0
- package/template/src/plugins/weboffice/entities/webofficeFile.entity.ts +28 -0
- package/template/src/plugins/weboffice/entities/webofficeFileVersion.entity.ts +29 -0
- package/template/src/plugins/weboffice/http/routes.ts +179 -0
- package/template/src/plugins/weboffice/index.ts +23 -0
- package/template/src/plugins/weboffice/services/webofficeCallback.service.ts +274 -0
- package/template/src/repository/UserRepository.ts +122 -0
- package/template/src/repository/base/BaseRepository.ts +124 -0
- package/template/src/repository/interfaces/IBaseRepository.ts +67 -0
- package/template/src/routers/index.ts +49 -0
- package/template/src/service/base.service.ts +116 -0
- package/template/src/service/paramValidateTest.service.ts +139 -0
- package/template/src/service/ytGoods.service.ts +42 -0
- package/template/src/service/ytShop.service.ts +90 -0
- package/template/src/service/ytUser.service.ts +451 -0
- package/template/src/test/swaggerParameterTest.ts +90 -0
- package/template/src/utils/testDataInitializer.ts +296 -0
- package/template/static/output.json +15203 -0
- package/template/test/controllers/controllers.test.ts +173 -0
- package/template/test/controllers/example/ExampleController.test.ts +222 -0
- package/template/test/controllers/example/NewAnnotationExampleController.test.ts +200 -0
- package/template/test/framework/TransactionManagerDemo.test.ts +363 -0
- package/template/test/framework/annotation/AnnotationDecorators.test.ts +222 -0
- package/template/test/framework/annotation/AnnotationExecutor.test.ts +246 -0
- package/template/test/framework/annotation/AnnotationProcessor.test.ts +179 -0
- package/template/test/framework/annotation/CustomProcessors.test.ts +313 -0
- package/template/test/framework/annotation/DefaultProcessors.test.ts +371 -0
- package/template/test/framework/annotation/NewRouter.test.ts +272 -0
- package/template/test/framework/annotation/ProcessorManager.test.ts +248 -0
- package/template/test/framework/annotation/setup.ts +26 -0
- package/template/test/framework/cache.test.ts +101 -0
- package/template/test/framework/databaseConfig.test.ts +142 -0
- package/template/test/integration/integration.test.ts +153 -0
- package/template/test/plugins/weboffice/http.routes.int.test.ts +61 -0
- package/template/test/service/business.test.ts +87 -0
- package/template/test/service/paramValidateTest.service.test.ts +184 -0
- package/template/test/service/ytUser.service.test.ts +566 -0
- package/template/test/setup.ts +20 -0
- package/template/test/setupAfterEnv.ts +14 -0
- package/template/test/utils/testHelpers.ts +220 -0
- package/template/test_output.txt +0 -0
- package/template/tsconfig.build.json +17 -0
- package/template/tsconfig.json +31 -0
- package/template/webpack.config.js +71 -0
- package/template/yarn.lock +7354 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { logger } from '@src/framework/utils/logger';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Prometheus指标收集器
|
|
5
|
+
*/
|
|
6
|
+
export class MetricsCollector {
|
|
7
|
+
private static instance: MetricsCollector;
|
|
8
|
+
private metrics: Map<string, any> = new Map();
|
|
9
|
+
|
|
10
|
+
private constructor() {
|
|
11
|
+
this.initializeMetrics();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
static getInstance(): MetricsCollector {
|
|
15
|
+
if (!MetricsCollector.instance) {
|
|
16
|
+
MetricsCollector.instance = new MetricsCollector();
|
|
17
|
+
}
|
|
18
|
+
return MetricsCollector.instance;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 初始化指标
|
|
23
|
+
*/
|
|
24
|
+
private initializeMetrics(): void {
|
|
25
|
+
// HTTP请求指标
|
|
26
|
+
this.metrics.set('http_requests_total', {
|
|
27
|
+
type: 'counter',
|
|
28
|
+
help: 'Total number of HTTP requests',
|
|
29
|
+
labels: ['method', 'route', 'status_code']
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// HTTP请求持续时间
|
|
33
|
+
this.metrics.set('http_request_duration_seconds', {
|
|
34
|
+
type: 'histogram',
|
|
35
|
+
help: 'HTTP request duration in seconds',
|
|
36
|
+
labels: ['method', 'route'],
|
|
37
|
+
buckets: [0.1, 0.5, 1, 2, 5, 10]
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// 活跃连接数
|
|
41
|
+
this.metrics.set('http_active_connections', {
|
|
42
|
+
type: 'gauge',
|
|
43
|
+
help: 'Number of active HTTP connections'
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// 数据库连接数
|
|
47
|
+
this.metrics.set('database_connections_active', {
|
|
48
|
+
type: 'gauge',
|
|
49
|
+
help: 'Number of active database connections'
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// 缓存命中率
|
|
53
|
+
this.metrics.set('cache_hits_total', {
|
|
54
|
+
type: 'counter',
|
|
55
|
+
help: 'Total number of cache hits',
|
|
56
|
+
labels: ['cache_name']
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
this.metrics.set('cache_misses_total', {
|
|
60
|
+
type: 'counter',
|
|
61
|
+
help: 'Total number of cache misses',
|
|
62
|
+
labels: ['cache_name']
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// 错误计数
|
|
66
|
+
this.metrics.set('errors_total', {
|
|
67
|
+
type: 'counter',
|
|
68
|
+
help: 'Total number of errors',
|
|
69
|
+
labels: ['error_type', 'severity']
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// 内存使用
|
|
73
|
+
this.metrics.set('memory_usage_bytes', {
|
|
74
|
+
type: 'gauge',
|
|
75
|
+
help: 'Memory usage in bytes',
|
|
76
|
+
labels: ['type']
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// CPU使用率
|
|
80
|
+
this.metrics.set('cpu_usage_percent', {
|
|
81
|
+
type: 'gauge',
|
|
82
|
+
help: 'CPU usage percentage'
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* 记录HTTP请求
|
|
88
|
+
*/
|
|
89
|
+
recordHttpRequest(method: string, route: string, statusCode: number, duration: number): void {
|
|
90
|
+
// 这里可以集成实际的Prometheus客户端
|
|
91
|
+
logger.debug('HTTP请求指标', {
|
|
92
|
+
method,
|
|
93
|
+
route,
|
|
94
|
+
statusCode,
|
|
95
|
+
duration
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* 记录错误
|
|
101
|
+
*/
|
|
102
|
+
recordError(errorType: string, severity: string): void {
|
|
103
|
+
logger.debug('错误指标', {
|
|
104
|
+
errorType,
|
|
105
|
+
severity
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* 记录缓存操作
|
|
111
|
+
*/
|
|
112
|
+
recordCacheOperation(cacheName: string, hit: boolean): void {
|
|
113
|
+
logger.debug('缓存指标', {
|
|
114
|
+
cacheName,
|
|
115
|
+
hit
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* 记录数据库连接
|
|
121
|
+
*/
|
|
122
|
+
recordDatabaseConnection(active: number): void {
|
|
123
|
+
logger.debug('数据库连接指标', {
|
|
124
|
+
active
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* 获取系统指标
|
|
130
|
+
*/
|
|
131
|
+
getSystemMetrics(): any {
|
|
132
|
+
const memUsage = process.memoryUsage();
|
|
133
|
+
const cpuUsage = process.cpuUsage();
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
memory: {
|
|
137
|
+
rss: memUsage.rss,
|
|
138
|
+
heapTotal: memUsage.heapTotal,
|
|
139
|
+
heapUsed: memUsage.heapUsed,
|
|
140
|
+
external: memUsage.external
|
|
141
|
+
},
|
|
142
|
+
cpu: {
|
|
143
|
+
user: cpuUsage.user,
|
|
144
|
+
system: cpuUsage.system
|
|
145
|
+
},
|
|
146
|
+
uptime: process.uptime(),
|
|
147
|
+
pid: process.pid
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* 生成Prometheus格式的指标
|
|
153
|
+
*/
|
|
154
|
+
generatePrometheusMetrics(): string {
|
|
155
|
+
const metrics: string[] = [];
|
|
156
|
+
const systemMetrics = this.getSystemMetrics();
|
|
157
|
+
|
|
158
|
+
// 内存指标
|
|
159
|
+
metrics.push(`# HELP memory_usage_bytes Memory usage in bytes`);
|
|
160
|
+
metrics.push(`# TYPE memory_usage_bytes gauge`);
|
|
161
|
+
metrics.push(`memory_usage_bytes{type="rss"} ${systemMetrics.memory.rss}`);
|
|
162
|
+
metrics.push(`memory_usage_bytes{type="heap_total"} ${systemMetrics.memory.heapTotal}`);
|
|
163
|
+
metrics.push(`memory_usage_bytes{type="heap_used"} ${systemMetrics.memory.heapUsed}`);
|
|
164
|
+
metrics.push(`memory_usage_bytes{type="external"} ${systemMetrics.memory.external}`);
|
|
165
|
+
|
|
166
|
+
// CPU指标
|
|
167
|
+
metrics.push(`# HELP cpu_usage_seconds CPU usage in seconds`);
|
|
168
|
+
metrics.push(`# TYPE cpu_usage_seconds gauge`);
|
|
169
|
+
metrics.push(`cpu_usage_seconds{type="user"} ${systemMetrics.cpu.user / 1000000}`);
|
|
170
|
+
metrics.push(`cpu_usage_seconds{type="system"} ${systemMetrics.cpu.system / 1000000}`);
|
|
171
|
+
|
|
172
|
+
// 进程指标
|
|
173
|
+
metrics.push(`# HELP process_uptime_seconds Process uptime in seconds`);
|
|
174
|
+
metrics.push(`# TYPE process_uptime_seconds gauge`);
|
|
175
|
+
metrics.push(`process_uptime_seconds ${systemMetrics.uptime}`);
|
|
176
|
+
|
|
177
|
+
return metrics.join('\n');
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// 导出单例实例
|
|
182
|
+
export const metricsCollector = MetricsCollector.getInstance();
|
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
import koaRouter from 'koa-router'
|
|
2
|
+
import path from "path"
|
|
3
|
+
import { IParamTypeEnum } from "@src/framework/decorator/controller"
|
|
4
|
+
import { getRandoNumer, isPromise } from "@src/framework/utils/function"
|
|
5
|
+
const _router = new koaRouter()
|
|
6
|
+
import { Provider } from "dp-ioc2"
|
|
7
|
+
import { validate } from "class-validator"
|
|
8
|
+
import { Context } from "koa"
|
|
9
|
+
import { logger } from '@src/framework/utils/logger'
|
|
10
|
+
import { createCache, CacheType } from "@src/framework/utils/cache";
|
|
11
|
+
|
|
12
|
+
// 导入新的路由系统
|
|
13
|
+
import { callControllerWithProcessors } from '@src/framework/utils/NewRouter';
|
|
14
|
+
|
|
15
|
+
// 配置开关:是否使用新的注解处理器系统
|
|
16
|
+
// 动态检查环境变量,而不是在模块加载时固定
|
|
17
|
+
function isNewAnnotationSystemEnabled(): boolean {
|
|
18
|
+
return process.env.USE_NEW_ANNOTATION_SYSTEM === '1';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// 使用统一的缓存管理创建控制器结果缓存
|
|
22
|
+
const controllerResultCacheStore = createCache('controller-result', CacheType.CONTROLLER, {
|
|
23
|
+
stdTTL: 20, // 20秒过期
|
|
24
|
+
maxKeys: 2000 // 控制器缓存可以更多
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const responseValidate = async function (controller: any, methods: string, res: any) {
|
|
28
|
+
if (controller.$_ResponseValidateIf && controller.$_ResponseValidateIf.get(methods)) {
|
|
29
|
+
const { fn, clas } = controller.$_ResponseValidateIf.get(methods);
|
|
30
|
+
let _callResult = fn(res);
|
|
31
|
+
if (isPromise(_callResult)) {
|
|
32
|
+
_callResult = await _callResult;
|
|
33
|
+
}
|
|
34
|
+
if (_callResult && (_callResult instanceof Object)) {
|
|
35
|
+
const _dto = new clas;
|
|
36
|
+
let dataObject = _callResult;
|
|
37
|
+
// for (let i in dataObject) {
|
|
38
|
+
// _dto[i] = dataObject[i]
|
|
39
|
+
// }
|
|
40
|
+
Object.assign(_dto, dataObject);
|
|
41
|
+
return await validate(_dto, {
|
|
42
|
+
skipMissingProperties: false,
|
|
43
|
+
forbidNonWhitelisted: true,
|
|
44
|
+
whitelist: true,
|
|
45
|
+
});
|
|
46
|
+
// return await validate(_dto);
|
|
47
|
+
}
|
|
48
|
+
} else if (controller.$_ResponseValidator && controller.$_ResponseValidator.get(methods)) {
|
|
49
|
+
const { clas, objectKey } = controller.$_ResponseValidator.get(methods);
|
|
50
|
+
if (res instanceof Object) {
|
|
51
|
+
const _dto = new clas;
|
|
52
|
+
let dataObject = res;
|
|
53
|
+
if (objectKey && res[objectKey] && (res[objectKey] instanceof Object)) {
|
|
54
|
+
dataObject = res[objectKey];
|
|
55
|
+
}
|
|
56
|
+
// 严格验证所有字段
|
|
57
|
+
Object.assign(_dto, dataObject);
|
|
58
|
+
return await validate(_dto, {
|
|
59
|
+
skipMissingProperties: false,
|
|
60
|
+
forbidNonWhitelisted: true,
|
|
61
|
+
whitelist: true,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return []
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
async function callController(ctx: Context, controller: any, methods: string) {
|
|
70
|
+
if (isNewAnnotationSystemEnabled()) {
|
|
71
|
+
// 使用新的注解处理器系统
|
|
72
|
+
return await callControllerWithProcessors(ctx, controller, methods);
|
|
73
|
+
} else {
|
|
74
|
+
// 使用原有的逻辑
|
|
75
|
+
return await callControllerLegacy(ctx, controller, methods);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function callControllerLegacy(ctx: Context, controller: any, methods: string) {
|
|
80
|
+
const callParam: any[] = [];
|
|
81
|
+
if (controller.$_MethdosParamInfo) {
|
|
82
|
+
const paramsInfo: undefined | { type: IParamTypeEnum, validate: any }[] = controller.$_MethdosParamInfo.get(methods);
|
|
83
|
+
if (paramsInfo && paramsInfo.length > 0) {
|
|
84
|
+
// console.log(paramsInfo,"参数信息")
|
|
85
|
+
for (let paramInfo of paramsInfo) {
|
|
86
|
+
|
|
87
|
+
let data = undefined;
|
|
88
|
+
if (paramInfo.type == IParamTypeEnum.Body) {
|
|
89
|
+
data = ctx.request.body;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
switch (paramInfo.type) {
|
|
93
|
+
case IParamTypeEnum.Body:
|
|
94
|
+
data = ctx.request.body;
|
|
95
|
+
break;
|
|
96
|
+
case IParamTypeEnum.Query:
|
|
97
|
+
data = ctx.query;
|
|
98
|
+
break;
|
|
99
|
+
case IParamTypeEnum.Params:
|
|
100
|
+
data = ctx.params;
|
|
101
|
+
break;
|
|
102
|
+
case IParamTypeEnum.Headers:
|
|
103
|
+
data = ctx.request.headers;
|
|
104
|
+
break;
|
|
105
|
+
case IParamTypeEnum.State:
|
|
106
|
+
data = ctx.state;
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
//这里可以统一做参数校验(仅当 validate 为 DTO 类构造函数时)
|
|
110
|
+
if (paramInfo.validate && typeof paramInfo.validate === 'function') {
|
|
111
|
+
const waitToValidateObject = new paramInfo.validate();
|
|
112
|
+
|
|
113
|
+
for (let i in data) {
|
|
114
|
+
if (waitToValidateObject.$_Transform && waitToValidateObject.$_Transform.get(i)) {
|
|
115
|
+
const func = waitToValidateObject.$_Transform.get(i);
|
|
116
|
+
const result = func(data[i]);
|
|
117
|
+
if (isPromise(result)) {
|
|
118
|
+
waitToValidateObject[i] = await result;
|
|
119
|
+
} else {
|
|
120
|
+
waitToValidateObject[i] = result;
|
|
121
|
+
}
|
|
122
|
+
} else {
|
|
123
|
+
waitToValidateObject[i] = data[i]
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const validateErrors = await validate(waitToValidateObject);
|
|
128
|
+
|
|
129
|
+
if (validateErrors.length > 0) {
|
|
130
|
+
ctx.status = 400;
|
|
131
|
+
return ctx.body = validateErrors;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
callParam.push(data);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// 调用controller
|
|
139
|
+
try {
|
|
140
|
+
|
|
141
|
+
let controllerCacheInfo: any = null;
|
|
142
|
+
if (controller.$_ControllerCache && controller.$_ControllerCache.get(methods)) {
|
|
143
|
+
const { cacheyFn, options } = controller.$_ControllerCache.get(methods);
|
|
144
|
+
if (options && (options.enable === undefined || options.enable)) {
|
|
145
|
+
const cacheKey = cacheyFn(...callParam);
|
|
146
|
+
if (cacheKey) {
|
|
147
|
+
const cacheResult = controllerResultCacheStore.get(cacheKey);
|
|
148
|
+
if (cacheResult) {
|
|
149
|
+
return ctx.body = cacheResult;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
controllerCacheInfo = {
|
|
153
|
+
cacheyFn, options, cacheKey,
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const callResult = controller[methods].apply(controller, callParam);
|
|
164
|
+
if (controller.$_ResponseCode) {
|
|
165
|
+
const code = controller.$_ResponseCode.get(methods) ?? 200;
|
|
166
|
+
ctx.status = code;
|
|
167
|
+
}
|
|
168
|
+
if (controller.$_ResponseHeader) {
|
|
169
|
+
const responseHeaders = controller.$_ResponseHeader.get(methods);
|
|
170
|
+
if (responseHeaders) {
|
|
171
|
+
responseHeaders.keys().forEach((key: string) => {
|
|
172
|
+
const value = responseHeaders.get(key);
|
|
173
|
+
if (value) {
|
|
174
|
+
ctx.set(key, value);
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
if (isPromise(callResult)) {
|
|
183
|
+
const res = await callResult;
|
|
184
|
+
const resValidateResult = await responseValidate(controller, methods, res);
|
|
185
|
+
if (resValidateResult.length > 0) {
|
|
186
|
+
ctx.status = 400;
|
|
187
|
+
logger.error(resValidateResult.join(', '))
|
|
188
|
+
return ctx.body = `接口${methods}返回数据参数校验异常`;
|
|
189
|
+
}
|
|
190
|
+
ctx.body = res;
|
|
191
|
+
} else {
|
|
192
|
+
const resValidateResult = await responseValidate(controller, methods, callResult);
|
|
193
|
+
if (resValidateResult.length > 0) {
|
|
194
|
+
ctx.status = 400;
|
|
195
|
+
return ctx.body = resValidateResult;
|
|
196
|
+
}
|
|
197
|
+
ctx.body = callResult;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// 可以在这里 加入 控制器方法缓存的数据
|
|
201
|
+
if (controllerCacheInfo) {
|
|
202
|
+
// 创建缓存
|
|
203
|
+
const { options, cacheKey, } = controllerCacheInfo;
|
|
204
|
+
if (options && (options.enable === undefined || options.enable)) {
|
|
205
|
+
let ttl = 20;
|
|
206
|
+
if (options && options.ttl) {
|
|
207
|
+
if (options.ttl instanceof Object) {
|
|
208
|
+
ttl = getRandoNumer(options.ttl.min, options.ttl.max)
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
controllerResultCacheStore.set(cacheKey, ctx.body, ttl)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
} catch (err) {
|
|
217
|
+
throw err;
|
|
218
|
+
// 这里要抛出异常,并且以更详细的信息抛出来
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* 绑定路由
|
|
223
|
+
* @param path 路由路径
|
|
224
|
+
* @param controller 控制器
|
|
225
|
+
*/
|
|
226
|
+
export const bindRouter = (...args: any[]) => {
|
|
227
|
+
if (args.length < 2) {
|
|
228
|
+
throw new Error("路由绑定至少2个参数");
|
|
229
|
+
}
|
|
230
|
+
const _path: string = args[0];
|
|
231
|
+
const Controller: any = args[args.length - 1];
|
|
232
|
+
|
|
233
|
+
const middlewares: any = [];
|
|
234
|
+
//表示有中间件
|
|
235
|
+
if (args.length > 2) {
|
|
236
|
+
for (let i in args) {
|
|
237
|
+
let index = Number(i);
|
|
238
|
+
if (index != 0 && index != args.length - 1) {
|
|
239
|
+
middlewares.push(args[i]);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const controller = Provider<any>(Controller);
|
|
245
|
+
// 绑定post方法
|
|
246
|
+
if (controller.$_PostMethods) {
|
|
247
|
+
const postMethods: Array<{ methodName: string, url: string }> = Array.from(controller.$_PostMethods);
|
|
248
|
+
postMethods.forEach(_methods => {
|
|
249
|
+
const { methodName, url } = _methods;
|
|
250
|
+
const methods = methodName;
|
|
251
|
+
if (controller[methods]) {
|
|
252
|
+
const _url = path.join(_path, url).replace(/\\/g, "/");
|
|
253
|
+
|
|
254
|
+
const cb = async (ctx: any) => {
|
|
255
|
+
// 读取该方法的参数注解信息
|
|
256
|
+
await callController(ctx, controller, methods);
|
|
257
|
+
}
|
|
258
|
+
if (middlewares.length > 0) {
|
|
259
|
+
for (const middleware of middlewares) {
|
|
260
|
+
_router.use(_url, middleware);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
_router.post(_url, cb)
|
|
264
|
+
|
|
265
|
+
// 如果URL以斜杠结尾,同时注册无斜杠版本
|
|
266
|
+
if (_url.endsWith('/') && _url !== '/') {
|
|
267
|
+
const urlWithoutSlash = _url.slice(0, -1);
|
|
268
|
+
if (middlewares.length > 0) {
|
|
269
|
+
for (const middleware of middlewares) {
|
|
270
|
+
_router.use(urlWithoutSlash, middleware);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
_router.post(urlWithoutSlash, cb)
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
})
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// 绑定 get方法
|
|
280
|
+
if (controller.$_GetMethods) {
|
|
281
|
+
const postMethods: Array<{ methodName: string, url: string }> = Array.from(controller.$_GetMethods);
|
|
282
|
+
postMethods.forEach(_methods => {
|
|
283
|
+
const { methodName, url } = _methods;
|
|
284
|
+
const methods = methodName;
|
|
285
|
+
if (controller[methods]) {
|
|
286
|
+
const _url = path.join(_path, url).replace(/\\/g, "/");
|
|
287
|
+
const cb = async (ctx: any) => {
|
|
288
|
+
// 读取该方法的参数注解信息
|
|
289
|
+
await callController(ctx, controller, methods);
|
|
290
|
+
}
|
|
291
|
+
if (middlewares.length > 0) {
|
|
292
|
+
for (const middleware of middlewares) {
|
|
293
|
+
_router.use(_url, middleware);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
_router.get(_url, cb)
|
|
297
|
+
|
|
298
|
+
// 如果URL以斜杠结尾,同时注册无斜杠版本
|
|
299
|
+
if (_url.endsWith('/') && _url !== '/') {
|
|
300
|
+
const urlWithoutSlash = _url.slice(0, -1);
|
|
301
|
+
if (middlewares.length > 0) {
|
|
302
|
+
for (const middleware of middlewares) {
|
|
303
|
+
_router.use(urlWithoutSlash, middleware);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
_router.get(urlWithoutSlash, cb)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
}
|
|
310
|
+
})
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// 绑定 put 方法
|
|
314
|
+
if (controller.$_PutMethods) {
|
|
315
|
+
const postMethods: Array<{ methodName: string, url: string }> = Array.from(controller.$_PutMethods);
|
|
316
|
+
postMethods.forEach(_methods => {
|
|
317
|
+
const { methodName, url } = _methods;
|
|
318
|
+
const methods = methodName;
|
|
319
|
+
if (controller[methods]) {
|
|
320
|
+
const _url = path.join(_path, url).replace(/\\/g, "/");
|
|
321
|
+
|
|
322
|
+
const cb = async (ctx: any) => {
|
|
323
|
+
// 读取该方法的参数注解信息
|
|
324
|
+
await callController(ctx, controller, methods);
|
|
325
|
+
}
|
|
326
|
+
if (middlewares.length > 0) {
|
|
327
|
+
for (const middleware of middlewares) {
|
|
328
|
+
_router.use(_url, middleware);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
_router.put(_url, cb)
|
|
332
|
+
|
|
333
|
+
// 如果URL以斜杠结尾,同时注册无斜杠版本
|
|
334
|
+
if (_url.endsWith('/') && _url !== '/') {
|
|
335
|
+
const urlWithoutSlash = _url.slice(0, -1);
|
|
336
|
+
if (middlewares.length > 0) {
|
|
337
|
+
for (const middleware of middlewares) {
|
|
338
|
+
_router.use(urlWithoutSlash, middleware);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
_router.put(urlWithoutSlash, cb)
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
})
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// 绑定 del 方法
|
|
348
|
+
if (controller.$_DelMethods) {
|
|
349
|
+
const postMethods: Array<{ methodName: string, url: string }> = Array.from(controller.$_DelMethods);
|
|
350
|
+
postMethods.forEach(_methods => {
|
|
351
|
+
const { methodName, url } = _methods;
|
|
352
|
+
const methods = methodName;
|
|
353
|
+
if (controller[methods]) {
|
|
354
|
+
const _url = path.join(_path, url).replace(/\\/g, "/");
|
|
355
|
+
const cb = async (ctx: any) => {
|
|
356
|
+
// 读取该方法的参数注解信息
|
|
357
|
+
await callController(ctx, controller, methods);
|
|
358
|
+
}
|
|
359
|
+
if (middlewares.length > 0) {
|
|
360
|
+
for (const middleware of middlewares) {
|
|
361
|
+
_router.use(_url, middleware);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
_router.del(_url, cb)
|
|
365
|
+
|
|
366
|
+
// 如果URL以斜杠结尾,同时注册无斜杠版本
|
|
367
|
+
if (_url.endsWith('/') && _url !== '/') {
|
|
368
|
+
const urlWithoutSlash = _url.slice(0, -1);
|
|
369
|
+
if (middlewares.length > 0) {
|
|
370
|
+
for (const middleware of middlewares) {
|
|
371
|
+
_router.use(urlWithoutSlash, middleware);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
_router.del(urlWithoutSlash, cb)
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
})
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
// 绑定 all 方法
|
|
382
|
+
if (controller.$_AllMethods) {
|
|
383
|
+
const postMethods: Array<{ methodName: string, url: string }> = Array.from(controller.$_AllMethods);
|
|
384
|
+
postMethods.forEach(_methods => {
|
|
385
|
+
const { methodName, url } = _methods;
|
|
386
|
+
const methods = methodName;
|
|
387
|
+
if (controller[methods]) {
|
|
388
|
+
const _url = path.join(_path, url).replace(/\\/g, "/");
|
|
389
|
+
const cb = async (ctx: any) => {
|
|
390
|
+
// 读取该方法的参数注解信息
|
|
391
|
+
await callController(ctx, controller, methods);
|
|
392
|
+
}
|
|
393
|
+
if (middlewares.length > 0) {
|
|
394
|
+
for (const middleware of middlewares) {
|
|
395
|
+
_router.use(_url, middleware);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
_router.all(_url, cb)
|
|
399
|
+
|
|
400
|
+
// 如果URL以斜杠结尾,同时注册无斜杠版本
|
|
401
|
+
if (_url.endsWith('/') && _url !== '/') {
|
|
402
|
+
const urlWithoutSlash = _url.slice(0, -1);
|
|
403
|
+
if (middlewares.length > 0) {
|
|
404
|
+
for (const middleware of middlewares) {
|
|
405
|
+
_router.use(urlWithoutSlash, middleware);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
_router.all(urlWithoutSlash, cb)
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
})
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// 导出路由对象
|
|
417
|
+
export const router = _router;
|