@dangao/bun-server 1.2.0 → 1.4.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 +15 -0
- package/dist/config/config-module.d.ts +17 -0
- package/dist/config/config-module.d.ts.map +1 -1
- package/dist/config/service.d.ts +18 -1
- package/dist/config/service.d.ts.map +1 -1
- package/dist/config/types.d.ts +25 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/controller/controller.d.ts +5 -0
- package/dist/controller/controller.d.ts.map +1 -1
- package/dist/controller/decorators.d.ts +30 -1
- package/dist/controller/decorators.d.ts.map +1 -1
- package/dist/controller/index.d.ts +2 -2
- package/dist/controller/index.d.ts.map +1 -1
- package/dist/controller/param-binder.d.ts +12 -0
- package/dist/controller/param-binder.d.ts.map +1 -1
- package/dist/core/application.d.ts +15 -0
- package/dist/core/application.d.ts.map +1 -1
- package/dist/core/context.d.ts +1 -0
- package/dist/core/context.d.ts.map +1 -1
- package/dist/core/server.d.ts +8 -0
- package/dist/core/server.d.ts.map +1 -1
- package/dist/index.d.ts +8 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6487 -4178
- package/dist/microservice/config-center/config-center-module.d.ts +43 -0
- package/dist/microservice/config-center/config-center-module.d.ts.map +1 -0
- package/dist/microservice/config-center/decorators.d.ts +58 -0
- package/dist/microservice/config-center/decorators.d.ts.map +1 -0
- package/dist/microservice/config-center/index.d.ts +9 -0
- package/dist/microservice/config-center/index.d.ts.map +1 -0
- package/dist/microservice/config-center/nacos-config-center.d.ts +37 -0
- package/dist/microservice/config-center/nacos-config-center.d.ts.map +1 -0
- package/dist/microservice/config-center/nacos-decorators.d.ts +24 -0
- package/dist/microservice/config-center/nacos-decorators.d.ts.map +1 -0
- package/dist/microservice/config-center/types.d.ts +63 -0
- package/dist/microservice/config-center/types.d.ts.map +1 -0
- package/dist/microservice/governance/circuit-breaker.d.ts +54 -0
- package/dist/microservice/governance/circuit-breaker.d.ts.map +1 -0
- package/dist/microservice/governance/decorators.d.ts +51 -0
- package/dist/microservice/governance/decorators.d.ts.map +1 -0
- package/dist/microservice/governance/index.d.ts +9 -0
- package/dist/microservice/governance/index.d.ts.map +1 -0
- package/dist/microservice/governance/rate-limiter.d.ts +26 -0
- package/dist/microservice/governance/rate-limiter.d.ts.map +1 -0
- package/dist/microservice/governance/redis-rate-limiter.d.ts +76 -0
- package/dist/microservice/governance/redis-rate-limiter.d.ts.map +1 -0
- package/dist/microservice/governance/retry-strategy.d.ts +21 -0
- package/dist/microservice/governance/retry-strategy.d.ts.map +1 -0
- package/dist/microservice/governance/types.d.ts +212 -0
- package/dist/microservice/governance/types.d.ts.map +1 -0
- package/dist/microservice/index.d.ts +10 -0
- package/dist/microservice/index.d.ts.map +1 -0
- package/dist/microservice/monitoring/index.d.ts +4 -0
- package/dist/microservice/monitoring/index.d.ts.map +1 -0
- package/dist/microservice/monitoring/metrics-collector.d.ts +54 -0
- package/dist/microservice/monitoring/metrics-collector.d.ts.map +1 -0
- package/dist/microservice/monitoring/metrics-integration.d.ts +24 -0
- package/dist/microservice/monitoring/metrics-integration.d.ts.map +1 -0
- package/dist/microservice/monitoring/types.d.ts +99 -0
- package/dist/microservice/monitoring/types.d.ts.map +1 -0
- package/dist/microservice/service-client/call-decorators.d.ts +52 -0
- package/dist/microservice/service-client/call-decorators.d.ts.map +1 -0
- package/dist/microservice/service-client/decorators.d.ts +35 -0
- package/dist/microservice/service-client/decorators.d.ts.map +1 -0
- package/dist/microservice/service-client/index.d.ts +7 -0
- package/dist/microservice/service-client/index.d.ts.map +1 -0
- package/dist/microservice/service-client/interceptors.d.ts +96 -0
- package/dist/microservice/service-client/interceptors.d.ts.map +1 -0
- package/dist/microservice/service-client/load-balancer.d.ts +59 -0
- package/dist/microservice/service-client/load-balancer.d.ts.map +1 -0
- package/dist/microservice/service-client/service-client.d.ts +74 -0
- package/dist/microservice/service-client/service-client.d.ts.map +1 -0
- package/dist/microservice/service-client/types.d.ts +155 -0
- package/dist/microservice/service-client/types.d.ts.map +1 -0
- package/dist/microservice/service-registry/decorators.d.ts +84 -0
- package/dist/microservice/service-registry/decorators.d.ts.map +1 -0
- package/dist/microservice/service-registry/discovery-decorators.d.ts +58 -0
- package/dist/microservice/service-registry/discovery-decorators.d.ts.map +1 -0
- package/dist/microservice/service-registry/health-integration.d.ts +32 -0
- package/dist/microservice/service-registry/health-integration.d.ts.map +1 -0
- package/dist/microservice/service-registry/index.d.ts +10 -0
- package/dist/microservice/service-registry/index.d.ts.map +1 -0
- package/dist/microservice/service-registry/nacos-service-registry.d.ts +68 -0
- package/dist/microservice/service-registry/nacos-service-registry.d.ts.map +1 -0
- package/dist/microservice/service-registry/service-registry-module.d.ts +48 -0
- package/dist/microservice/service-registry/service-registry-module.d.ts.map +1 -0
- package/dist/microservice/service-registry/types.d.ts +121 -0
- package/dist/microservice/service-registry/types.d.ts.map +1 -0
- package/dist/microservice/tracing/collectors.d.ts +27 -0
- package/dist/microservice/tracing/collectors.d.ts.map +1 -0
- package/dist/microservice/tracing/index.d.ts +4 -0
- package/dist/microservice/tracing/index.d.ts.map +1 -0
- package/dist/microservice/tracing/tracer.d.ts +59 -0
- package/dist/microservice/tracing/tracer.d.ts.map +1 -0
- package/dist/microservice/tracing/types.d.ts +179 -0
- package/dist/microservice/tracing/types.d.ts.map +1 -0
- package/dist/request/request.d.ts +1 -0
- package/dist/request/request.d.ts.map +1 -1
- package/docs/microservice-config-center.md +258 -0
- package/docs/microservice-nacos.md +346 -0
- package/docs/microservice-service-registry.md +306 -0
- package/docs/microservice.md +680 -0
- package/docs/troubleshooting.md +41 -0
- package/docs/zh/troubleshooting.md +41 -0
- package/package.json +5 -4
- package/src/config/config-module.ts +210 -0
- package/src/config/service.ts +52 -1
- package/src/config/types.ts +31 -0
- package/src/controller/controller.ts +8 -0
- package/src/controller/decorators.ts +55 -0
- package/src/controller/index.ts +16 -2
- package/src/controller/param-binder.ts +87 -1
- package/src/core/application.ts +100 -2
- package/src/core/context.ts +1 -0
- package/src/core/server.ts +14 -0
- package/src/index.ts +98 -2
- package/src/microservice/config-center/config-center-module.ts +98 -0
- package/src/microservice/config-center/decorators.ts +159 -0
- package/src/microservice/config-center/index.ts +13 -0
- package/src/microservice/config-center/nacos-config-center.ts +126 -0
- package/src/microservice/config-center/nacos-decorators.ts +34 -0
- package/src/microservice/config-center/types.ts +80 -0
- package/src/microservice/governance/circuit-breaker.ts +229 -0
- package/src/microservice/governance/decorators.ts +113 -0
- package/src/microservice/governance/index.ts +18 -0
- package/src/microservice/governance/rate-limiter.ts +72 -0
- package/src/microservice/governance/redis-rate-limiter.ts +154 -0
- package/src/microservice/governance/retry-strategy.ts +74 -0
- package/src/microservice/governance/types.ts +247 -0
- package/src/microservice/index.ts +12 -0
- package/src/microservice/monitoring/index.ts +8 -0
- package/src/microservice/monitoring/metrics-collector.ts +223 -0
- package/src/microservice/monitoring/metrics-integration.ts +154 -0
- package/src/microservice/monitoring/types.ts +118 -0
- package/src/microservice/service-client/call-decorators.ts +107 -0
- package/src/microservice/service-client/decorators.ts +87 -0
- package/src/microservice/service-client/index.ts +37 -0
- package/src/microservice/service-client/interceptors.ts +182 -0
- package/src/microservice/service-client/load-balancer.ts +205 -0
- package/src/microservice/service-client/service-client.ts +488 -0
- package/src/microservice/service-client/types.ts +186 -0
- package/src/microservice/service-registry/decorators.ts +238 -0
- package/src/microservice/service-registry/discovery-decorators.ts +156 -0
- package/src/microservice/service-registry/health-integration.ts +146 -0
- package/src/microservice/service-registry/index.ts +20 -0
- package/src/microservice/service-registry/nacos-service-registry.ts +259 -0
- package/src/microservice/service-registry/service-registry-module.ts +105 -0
- package/src/microservice/service-registry/types.ts +149 -0
- package/src/microservice/tracing/collectors.ts +50 -0
- package/src/microservice/tracing/index.ts +15 -0
- package/src/microservice/tracing/tracer.ts +293 -0
- package/src/microservice/tracing/types.ts +213 -0
- package/src/request/request.ts +1 -0
- package/tests/config/set-value-by-path.test.ts +53 -0
- package/tests/controller/param-map.test.ts +237 -0
- package/tests/microservice/config-center.test.ts +77 -0
- package/tests/microservice/governance.test.ts +157 -0
- package/tests/microservice/monitoring.test.ts +75 -0
- package/tests/microservice/service-client.test.ts +136 -0
- package/tests/microservice/service-registry.test.ts +80 -0
- package/tests/microservice/tracing.test.ts +143 -0
- package/tests/utils/test-port.ts +29 -19
package/src/core/application.ts
CHANGED
|
@@ -13,6 +13,9 @@ import { ModuleRegistry } from '../di/module-registry';
|
|
|
13
13
|
import type { ModuleClass } from '../di/module';
|
|
14
14
|
import type { Constructor } from './types';
|
|
15
15
|
import { InterceptorRegistry, INTERCEPTOR_REGISTRY_TOKEN } from '../interceptor';
|
|
16
|
+
import { CONFIG_SERVICE_TOKEN } from '../config/types';
|
|
17
|
+
import { ConfigService } from '../config/service';
|
|
18
|
+
import { ConfigModule } from '../config/config-module';
|
|
16
19
|
|
|
17
20
|
/**
|
|
18
21
|
* 应用配置选项
|
|
@@ -81,15 +84,24 @@ export class Application {
|
|
|
81
84
|
// 初始化所有扩展(包括数据库连接等)
|
|
82
85
|
await this.initializeExtensions();
|
|
83
86
|
|
|
87
|
+
// 初始化配置中心集成(在所有模块注册完成后)
|
|
88
|
+
await this.initializeConfigCenter();
|
|
89
|
+
|
|
90
|
+
const finalPort = port ?? this.options.port ?? 3000;
|
|
91
|
+
const finalHostname = hostname ?? this.options.hostname;
|
|
92
|
+
|
|
84
93
|
const serverOptions: ServerOptions = {
|
|
85
|
-
port:
|
|
86
|
-
hostname:
|
|
94
|
+
port: finalPort,
|
|
95
|
+
hostname: finalHostname,
|
|
87
96
|
fetch: this.handleRequest.bind(this),
|
|
88
97
|
websocketRegistry: this.websocketRegistry,
|
|
89
98
|
};
|
|
90
99
|
|
|
91
100
|
this.server = new BunServer(serverOptions);
|
|
92
101
|
this.server.start();
|
|
102
|
+
|
|
103
|
+
// 自动注册服务到注册中心(如果使用了 @ServiceRegistry 装饰器)
|
|
104
|
+
await this.registerServices(finalPort, finalHostname);
|
|
93
105
|
}
|
|
94
106
|
|
|
95
107
|
/**
|
|
@@ -116,10 +128,42 @@ export class Application {
|
|
|
116
128
|
// 所以上面的循环已经处理了
|
|
117
129
|
}
|
|
118
130
|
|
|
131
|
+
/**
|
|
132
|
+
* 初始化配置中心集成
|
|
133
|
+
* 在所有模块注册完成后调用,确保 ConfigCenterModule 已注册
|
|
134
|
+
*/
|
|
135
|
+
private async initializeConfigCenter(): Promise<void> {
|
|
136
|
+
const container = this.getContainer();
|
|
137
|
+
// ConfigModule 可能未注册(很多测试/应用不使用配置模块),此时不要抛错
|
|
138
|
+
if (!container.isRegistered(CONFIG_SERVICE_TOKEN)) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const configService = container.resolve<ConfigService>(CONFIG_SERVICE_TOKEN);
|
|
143
|
+
|
|
144
|
+
// 检查是否有待初始化的配置中心选项
|
|
145
|
+
const configCenterOptions = (configService as any)._configCenterOptions;
|
|
146
|
+
if (configCenterOptions) {
|
|
147
|
+
try {
|
|
148
|
+
await ConfigModule.initializeConfigCenter(configService, configCenterOptions);
|
|
149
|
+
// 清除临时选项
|
|
150
|
+
delete (configService as any)._configCenterOptions;
|
|
151
|
+
} catch (error) {
|
|
152
|
+
console.error(
|
|
153
|
+
'[Application] Failed to initialize config center:',
|
|
154
|
+
error,
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
119
160
|
/**
|
|
120
161
|
* 停止应用
|
|
121
162
|
*/
|
|
122
163
|
public async stop(): Promise<void> {
|
|
164
|
+
// 自动注销服务(如果使用了 @ServiceRegistry 装饰器)
|
|
165
|
+
await this.deregisterServices();
|
|
166
|
+
|
|
123
167
|
// 关闭所有扩展(包括数据库连接等)
|
|
124
168
|
await this.closeExtensions();
|
|
125
169
|
this.server?.stop();
|
|
@@ -235,6 +279,60 @@ export class Application {
|
|
|
235
279
|
return this.server;
|
|
236
280
|
}
|
|
237
281
|
|
|
282
|
+
/**
|
|
283
|
+
* 自动注册服务到注册中心
|
|
284
|
+
* 扫描所有使用 @ServiceRegistry 装饰器的控制器,自动注册服务
|
|
285
|
+
*/
|
|
286
|
+
private async registerServices(port: number, hostname?: string): Promise<void> {
|
|
287
|
+
try {
|
|
288
|
+
// 动态导入服务注册装饰器(避免循环依赖)
|
|
289
|
+
const { registerServiceInstance } = await import(
|
|
290
|
+
'../microservice/service-registry/decorators'
|
|
291
|
+
);
|
|
292
|
+
|
|
293
|
+
const registry = ControllerRegistry.getInstance();
|
|
294
|
+
const controllers = registry.getRegisteredControllers();
|
|
295
|
+
|
|
296
|
+
for (const controllerClass of controllers) {
|
|
297
|
+
await registerServiceInstance(controllerClass, port, hostname);
|
|
298
|
+
}
|
|
299
|
+
} catch (error) {
|
|
300
|
+
// 如果服务注册失败,不影响应用启动(可能是没有配置 ServiceRegistryModule)
|
|
301
|
+
// 只在调试模式下输出警告
|
|
302
|
+
if (process.env.NODE_ENV === 'development') {
|
|
303
|
+
console.warn('[Application] Failed to register services:', error);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* 自动注销服务
|
|
310
|
+
* 注销所有使用 @ServiceRegistry 装饰器的服务
|
|
311
|
+
*/
|
|
312
|
+
private async deregisterServices(): Promise<void> {
|
|
313
|
+
try {
|
|
314
|
+
// 动态导入服务注册装饰器(避免循环依赖)
|
|
315
|
+
const { deregisterServiceInstance } = await import(
|
|
316
|
+
'../microservice/service-registry/decorators'
|
|
317
|
+
);
|
|
318
|
+
|
|
319
|
+
const registry = ControllerRegistry.getInstance();
|
|
320
|
+
const controllers = registry.getRegisteredControllers();
|
|
321
|
+
|
|
322
|
+
const port = this.server?.getPort() ?? this.options.port ?? 3000;
|
|
323
|
+
const hostname = this.server?.getHostname() ?? this.options.hostname;
|
|
324
|
+
|
|
325
|
+
for (const controllerClass of controllers) {
|
|
326
|
+
await deregisterServiceInstance(controllerClass, port, hostname);
|
|
327
|
+
}
|
|
328
|
+
} catch (error) {
|
|
329
|
+
// 如果服务注销失败,不影响应用关闭
|
|
330
|
+
if (process.env.NODE_ENV === 'development') {
|
|
331
|
+
console.warn('[Application] Failed to deregister services:', error);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
238
336
|
/**
|
|
239
337
|
* 获取 DI 容器(用于注册服务)
|
|
240
338
|
* @returns DI 容器
|
package/src/core/context.ts
CHANGED
package/src/core/server.ts
CHANGED
|
@@ -125,4 +125,18 @@ export class BunServer {
|
|
|
125
125
|
public isRunning(): boolean {
|
|
126
126
|
return this.server !== undefined;
|
|
127
127
|
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* 获取服务器端口
|
|
131
|
+
*/
|
|
132
|
+
public getPort(): number {
|
|
133
|
+
return this.options.port ?? 3000;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* 获取服务器主机名
|
|
138
|
+
*/
|
|
139
|
+
public getHostname(): string | undefined {
|
|
140
|
+
return this.options.hostname;
|
|
141
|
+
}
|
|
128
142
|
}
|
package/src/index.ts
CHANGED
|
@@ -6,9 +6,24 @@ export { Route, Router, RouteRegistry } from './router';
|
|
|
6
6
|
export { GET, POST, PUT, DELETE, PATCH } from './router/decorators';
|
|
7
7
|
export type { HttpMethod, RouteHandler, RouteMatch } from './router/types';
|
|
8
8
|
export { BodyParser, RequestWrapper, ResponseBuilder } from './request';
|
|
9
|
-
export {
|
|
9
|
+
export {
|
|
10
|
+
Body,
|
|
11
|
+
Query,
|
|
12
|
+
QueryMap,
|
|
13
|
+
Param,
|
|
14
|
+
Header,
|
|
15
|
+
HeaderMap,
|
|
16
|
+
ParamBinder,
|
|
17
|
+
Controller,
|
|
18
|
+
ControllerRegistry,
|
|
19
|
+
} from './controller';
|
|
10
20
|
export { Context as ContextParam } from './controller';
|
|
11
|
-
export type {
|
|
21
|
+
export type {
|
|
22
|
+
ParamMetadata,
|
|
23
|
+
QueryMapOptions,
|
|
24
|
+
HeaderMapOptions,
|
|
25
|
+
ControllerMetadata,
|
|
26
|
+
} from './controller';
|
|
12
27
|
export { Container } from './di/container';
|
|
13
28
|
export { Injectable, Inject } from './di/decorators';
|
|
14
29
|
export { Lifecycle, type ProviderConfig, type DependencyMetadata } from './di/types';
|
|
@@ -291,4 +306,85 @@ export type {
|
|
|
291
306
|
SessionData,
|
|
292
307
|
RedisSessionStoreOptions,
|
|
293
308
|
} from './session';
|
|
309
|
+
// Microservice 模块
|
|
310
|
+
export {
|
|
311
|
+
ConfigCenterModule,
|
|
312
|
+
NacosConfigCenter,
|
|
313
|
+
CONFIG_CENTER_TOKEN,
|
|
314
|
+
type ConfigCenterModuleOptions,
|
|
315
|
+
type ConfigCenterProvider,
|
|
316
|
+
type NacosConfigCenterOptions,
|
|
317
|
+
type ConfigCenter,
|
|
318
|
+
type ConfigChangeListener,
|
|
319
|
+
type ConfigResult,
|
|
320
|
+
} from './microservice';
|
|
321
|
+
export {
|
|
322
|
+
ServiceRegistryModule,
|
|
323
|
+
NacosServiceRegistry,
|
|
324
|
+
SERVICE_REGISTRY_TOKEN,
|
|
325
|
+
type ServiceRegistryModuleOptions,
|
|
326
|
+
type ServiceRegistryProvider,
|
|
327
|
+
type NacosServiceRegistryOptions,
|
|
328
|
+
type ServiceRegistry,
|
|
329
|
+
type GetInstancesOptions,
|
|
330
|
+
type InstancesChangeListener,
|
|
331
|
+
type ServiceInstance,
|
|
332
|
+
} from './microservice';
|
|
333
|
+
// Service Client 模块
|
|
334
|
+
export {
|
|
335
|
+
ServiceClient,
|
|
336
|
+
LoadBalancerFactory,
|
|
337
|
+
RandomLoadBalancer,
|
|
338
|
+
RoundRobinLoadBalancer,
|
|
339
|
+
WeightedRoundRobinLoadBalancer,
|
|
340
|
+
ConsistentHashLoadBalancer,
|
|
341
|
+
LeastActiveLoadBalancer,
|
|
342
|
+
TraceIdRequestInterceptor,
|
|
343
|
+
UserInfoRequestInterceptor,
|
|
344
|
+
RequestLogInterceptor,
|
|
345
|
+
ResponseLogInterceptor,
|
|
346
|
+
ResponseTransformInterceptor,
|
|
347
|
+
ErrorHandlerInterceptor,
|
|
348
|
+
type LoadBalanceStrategy,
|
|
349
|
+
type LoadBalancer,
|
|
350
|
+
type ServiceCallOptions,
|
|
351
|
+
type ServiceCallResponse,
|
|
352
|
+
type ServiceRequestInterceptor,
|
|
353
|
+
type ServiceResponseInterceptor,
|
|
354
|
+
type ServiceCallError,
|
|
355
|
+
} from './microservice';
|
|
356
|
+
// Governance 模块
|
|
357
|
+
export {
|
|
358
|
+
CircuitBreaker,
|
|
359
|
+
CircuitBreakerState,
|
|
360
|
+
RateLimiter,
|
|
361
|
+
RetryStrategyImpl,
|
|
362
|
+
type CircuitBreakerOptions,
|
|
363
|
+
type CircuitBreakerStats,
|
|
364
|
+
type RateLimiterOptions,
|
|
365
|
+
type RetryStrategy,
|
|
366
|
+
} from './microservice';
|
|
367
|
+
// Tracing 模块
|
|
368
|
+
export {
|
|
369
|
+
Tracer,
|
|
370
|
+
ConsoleTraceCollector,
|
|
371
|
+
MemoryTraceCollector,
|
|
372
|
+
SpanStatus,
|
|
373
|
+
SpanKind,
|
|
374
|
+
type TraceId,
|
|
375
|
+
type SpanId,
|
|
376
|
+
type SpanContext,
|
|
377
|
+
type Span,
|
|
378
|
+
type SpanTags,
|
|
379
|
+
type SpanEvent,
|
|
380
|
+
type TracingOptions,
|
|
381
|
+
type TraceCollector,
|
|
382
|
+
} from './microservice';
|
|
383
|
+
// Monitoring 模块
|
|
384
|
+
export {
|
|
385
|
+
ServiceMetricsCollector,
|
|
386
|
+
type ServiceCallMetrics,
|
|
387
|
+
type ServiceInstanceHealth,
|
|
388
|
+
type MonitoringOptions,
|
|
389
|
+
} from './microservice';
|
|
294
390
|
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { Module, MODULE_METADATA_KEY, type ModuleProvider } from '../../di/module';
|
|
2
|
+
import { NacosClient } from '@dangao/nacos-client';
|
|
3
|
+
import type { NacosClientOptions } from '@dangao/nacos-client';
|
|
4
|
+
import { NacosConfigCenter } from './nacos-config-center';
|
|
5
|
+
import { CONFIG_CENTER_TOKEN, type ConfigCenter } from './types';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 配置中心 Provider 类型
|
|
9
|
+
*/
|
|
10
|
+
export type ConfigCenterProvider = 'nacos' | 'consul' | 'etcd' | 'apollo';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Nacos 配置中心选项
|
|
14
|
+
*/
|
|
15
|
+
export interface NacosConfigCenterOptions {
|
|
16
|
+
/**
|
|
17
|
+
* Nacos 客户端配置
|
|
18
|
+
*/
|
|
19
|
+
client: NacosClientOptions;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 配置监听轮询间隔(毫秒)
|
|
23
|
+
* @default 3000
|
|
24
|
+
*/
|
|
25
|
+
watchInterval?: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 配置中心模块选项
|
|
30
|
+
*/
|
|
31
|
+
export interface ConfigCenterModuleOptions {
|
|
32
|
+
/**
|
|
33
|
+
* Provider 类型
|
|
34
|
+
*/
|
|
35
|
+
provider: ConfigCenterProvider;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Nacos 配置(当 provider 为 'nacos' 时使用)
|
|
39
|
+
*/
|
|
40
|
+
nacos?: NacosConfigCenterOptions;
|
|
41
|
+
|
|
42
|
+
// 未来可以添加其他 provider 的配置
|
|
43
|
+
// consul?: ConsulConfigCenterOptions;
|
|
44
|
+
// etcd?: EtcdConfigCenterOptions;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 配置中心模块
|
|
49
|
+
*/
|
|
50
|
+
@Module({
|
|
51
|
+
providers: [],
|
|
52
|
+
})
|
|
53
|
+
export class ConfigCenterModule {
|
|
54
|
+
/**
|
|
55
|
+
* 创建配置中心模块
|
|
56
|
+
* @param options - 模块配置
|
|
57
|
+
*/
|
|
58
|
+
public static forRoot(options: ConfigCenterModuleOptions): typeof ConfigCenterModule {
|
|
59
|
+
const providers: ModuleProvider[] = [];
|
|
60
|
+
|
|
61
|
+
let configCenter: ConfigCenter;
|
|
62
|
+
|
|
63
|
+
switch (options.provider) {
|
|
64
|
+
case 'nacos':
|
|
65
|
+
if (!options.nacos) {
|
|
66
|
+
throw new Error('Nacos configuration is required when provider is "nacos"');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const nacosClient = new NacosClient(options.nacos.client);
|
|
70
|
+
configCenter = new NacosConfigCenter(nacosClient, {
|
|
71
|
+
watchInterval: options.nacos.watchInterval,
|
|
72
|
+
});
|
|
73
|
+
break;
|
|
74
|
+
|
|
75
|
+
default:
|
|
76
|
+
throw new Error(`Unsupported config center provider: ${options.provider}`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
providers.push({
|
|
80
|
+
provide: CONFIG_CENTER_TOKEN,
|
|
81
|
+
useValue: configCenter,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const existingMetadata = Reflect.getMetadata(MODULE_METADATA_KEY, ConfigCenterModule) || {};
|
|
85
|
+
const metadata = {
|
|
86
|
+
...existingMetadata,
|
|
87
|
+
providers: [...(existingMetadata.providers || []), ...providers],
|
|
88
|
+
exports: [
|
|
89
|
+
...(existingMetadata.exports || []),
|
|
90
|
+
CONFIG_CENTER_TOKEN,
|
|
91
|
+
],
|
|
92
|
+
};
|
|
93
|
+
Reflect.defineMetadata(MODULE_METADATA_KEY, metadata, ConfigCenterModule);
|
|
94
|
+
|
|
95
|
+
return ConfigCenterModule;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import type { ConfigCenter } from './types';
|
|
3
|
+
import { CONFIG_CENTER_TOKEN } from './types';
|
|
4
|
+
import { ControllerRegistry } from '../../controller/controller';
|
|
5
|
+
import type { Constructor } from '../../core/types';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 配置中心值装饰器元数据键
|
|
9
|
+
*/
|
|
10
|
+
const CONFIG_CENTER_VALUE_METADATA_KEY = Symbol('config-center:value');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 配置中心值元数据
|
|
14
|
+
*/
|
|
15
|
+
export interface ConfigCenterValueMetadata {
|
|
16
|
+
/**
|
|
17
|
+
* 配置 dataId
|
|
18
|
+
*/
|
|
19
|
+
dataId: string;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 配置分组
|
|
23
|
+
*/
|
|
24
|
+
groupName: string;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 命名空间(可选)
|
|
28
|
+
*/
|
|
29
|
+
namespaceId?: string;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 默认值(可选)
|
|
33
|
+
*/
|
|
34
|
+
defaultValue?: string;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* 是否监听配置变更
|
|
38
|
+
*/
|
|
39
|
+
watch?: boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* ConfigCenterValue 装饰器
|
|
44
|
+
* 用于自动注入配置中心的值
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* @Injectable()
|
|
49
|
+
* class MyService {
|
|
50
|
+
* @ConfigCenterValue('my-config', 'DEFAULT_GROUP')
|
|
51
|
+
* public configValue: string = '';
|
|
52
|
+
*
|
|
53
|
+
* @ConfigCenterValue('app-name', 'DEFAULT_GROUP', { defaultValue: 'MyApp' })
|
|
54
|
+
* public appName: string = '';
|
|
55
|
+
* }
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export function ConfigCenterValue(
|
|
59
|
+
dataId: string,
|
|
60
|
+
groupName: string = 'DEFAULT_GROUP',
|
|
61
|
+
options?: {
|
|
62
|
+
namespaceId?: string;
|
|
63
|
+
defaultValue?: string;
|
|
64
|
+
watch?: boolean;
|
|
65
|
+
},
|
|
66
|
+
): PropertyDecorator {
|
|
67
|
+
return function (target: object, propertyKey: string | symbol) {
|
|
68
|
+
const metadata: ConfigCenterValueMetadata = {
|
|
69
|
+
dataId,
|
|
70
|
+
groupName,
|
|
71
|
+
namespaceId: options?.namespaceId,
|
|
72
|
+
defaultValue: options?.defaultValue,
|
|
73
|
+
watch: options?.watch ?? false,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// 保存元数据
|
|
77
|
+
const existingMetadata: Map<string | symbol, ConfigCenterValueMetadata> =
|
|
78
|
+
Reflect.getMetadata(CONFIG_CENTER_VALUE_METADATA_KEY, target.constructor) ||
|
|
79
|
+
new Map();
|
|
80
|
+
existingMetadata.set(propertyKey, metadata);
|
|
81
|
+
Reflect.defineMetadata(
|
|
82
|
+
CONFIG_CENTER_VALUE_METADATA_KEY,
|
|
83
|
+
existingMetadata,
|
|
84
|
+
target.constructor,
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
// 定义属性描述符,实现自动注入
|
|
88
|
+
// 注意:属性 getter 必须是同步的,不能是 async
|
|
89
|
+
// 实际值通过 initializeConfigCenterValues 在实例化时预加载
|
|
90
|
+
let value: string | undefined = options?.defaultValue;
|
|
91
|
+
|
|
92
|
+
Object.defineProperty(target, propertyKey, {
|
|
93
|
+
get: () => {
|
|
94
|
+
// 同步返回已加载的值(如果还未加载,返回默认值)
|
|
95
|
+
return value ?? options?.defaultValue ?? '';
|
|
96
|
+
},
|
|
97
|
+
set: (newValue: string) => {
|
|
98
|
+
value = newValue;
|
|
99
|
+
},
|
|
100
|
+
enumerable: true,
|
|
101
|
+
configurable: true,
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* 获取类的所有配置中心值元数据
|
|
108
|
+
*/
|
|
109
|
+
export function getConfigCenterValueMetadata(
|
|
110
|
+
target: Constructor<unknown>,
|
|
111
|
+
): Map<string | symbol, ConfigCenterValueMetadata> {
|
|
112
|
+
return (
|
|
113
|
+
Reflect.getMetadata(CONFIG_CENTER_VALUE_METADATA_KEY, target) || new Map()
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* 初始化类的配置中心值
|
|
119
|
+
* 在类实例化后调用,自动加载配置值
|
|
120
|
+
*/
|
|
121
|
+
export async function initializeConfigCenterValues(
|
|
122
|
+
instance: object,
|
|
123
|
+
target: Constructor<unknown>,
|
|
124
|
+
): Promise<void> {
|
|
125
|
+
const metadata = getConfigCenterValueMetadata(target);
|
|
126
|
+
const container = ControllerRegistry.getInstance().getContainer();
|
|
127
|
+
const configCenter = container.resolve<ConfigCenter>(CONFIG_CENTER_TOKEN);
|
|
128
|
+
|
|
129
|
+
if (!configCenter) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
for (const [propertyKey, meta] of metadata.entries()) {
|
|
134
|
+
try {
|
|
135
|
+
const result = await configCenter.getConfig(
|
|
136
|
+
meta.dataId,
|
|
137
|
+
meta.groupName,
|
|
138
|
+
meta.namespaceId,
|
|
139
|
+
);
|
|
140
|
+
(instance as any)[propertyKey] = result.content;
|
|
141
|
+
|
|
142
|
+
// 如果启用监听,设置监听器
|
|
143
|
+
if (meta.watch) {
|
|
144
|
+
configCenter.watchConfig(meta.dataId, meta.groupName, (newResult: any) => {
|
|
145
|
+
(instance as any)[propertyKey] = newResult.content;
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
} catch (error) {
|
|
149
|
+
console.error(
|
|
150
|
+
`[ConfigCenterValue] Failed to initialize config ${meta.dataId}:`,
|
|
151
|
+
error,
|
|
152
|
+
);
|
|
153
|
+
if (meta.defaultValue !== undefined) {
|
|
154
|
+
(instance as any)[propertyKey] = meta.defaultValue;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { ConfigCenterModule } from './config-center-module';
|
|
2
|
+
export type { ConfigCenterModuleOptions, ConfigCenterProvider, NacosConfigCenterOptions } from './config-center-module';
|
|
3
|
+
export { NacosConfigCenter } from './nacos-config-center';
|
|
4
|
+
export { CONFIG_CENTER_TOKEN } from './types';
|
|
5
|
+
export type { ConfigCenter, ConfigChangeListener, ConfigResult } from './types';
|
|
6
|
+
export {
|
|
7
|
+
ConfigCenterValue,
|
|
8
|
+
getConfigCenterValueMetadata,
|
|
9
|
+
initializeConfigCenterValues,
|
|
10
|
+
} from './decorators';
|
|
11
|
+
export { NacosValue } from './nacos-decorators';
|
|
12
|
+
export type { ConfigCenterValueMetadata } from './decorators';
|
|
13
|
+
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { NacosClient, NacosConfigClient } from '@dangao/nacos-client';
|
|
2
|
+
import type { ConfigResult, ConfigChangeListener, ConfigCenter } from './types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Nacos 配置中心实现
|
|
6
|
+
* 实现 ConfigCenter 接口,内部使用 @dangao/nacos-client
|
|
7
|
+
*/
|
|
8
|
+
export class NacosConfigCenter implements ConfigCenter {
|
|
9
|
+
private readonly client: NacosClient;
|
|
10
|
+
private readonly configClient: NacosConfigClient;
|
|
11
|
+
private readonly watchers: Map<string, { listener: ConfigChangeListener; intervalId: number }> = new Map();
|
|
12
|
+
private readonly watchInterval: number = 3000; // 默认 3 秒轮询一次
|
|
13
|
+
|
|
14
|
+
public constructor(
|
|
15
|
+
client: NacosClient,
|
|
16
|
+
options?: {
|
|
17
|
+
/**
|
|
18
|
+
* 配置监听轮询间隔(毫秒)
|
|
19
|
+
* @default 3000
|
|
20
|
+
*/
|
|
21
|
+
watchInterval?: number;
|
|
22
|
+
},
|
|
23
|
+
) {
|
|
24
|
+
this.client = client;
|
|
25
|
+
this.configClient = new NacosConfigClient(client);
|
|
26
|
+
this.watchInterval = options?.watchInterval ?? 3000;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 获取配置
|
|
31
|
+
*/
|
|
32
|
+
public async getConfig(
|
|
33
|
+
dataId: string,
|
|
34
|
+
groupName: string,
|
|
35
|
+
namespaceId?: string,
|
|
36
|
+
): Promise<ConfigResult> {
|
|
37
|
+
const result = await this.configClient.getConfig({
|
|
38
|
+
dataId,
|
|
39
|
+
groupName,
|
|
40
|
+
namespaceId,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
content: result.content,
|
|
45
|
+
md5: result.md5,
|
|
46
|
+
lastModified: result.lastModified,
|
|
47
|
+
contentType: result.contentType,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* 监听配置变更
|
|
53
|
+
* 通过轮询和 md5 比对实现配置热更新
|
|
54
|
+
*/
|
|
55
|
+
public watchConfig(
|
|
56
|
+
dataId: string,
|
|
57
|
+
groupName: string,
|
|
58
|
+
listener: ConfigChangeListener,
|
|
59
|
+
namespaceId?: string,
|
|
60
|
+
): () => void {
|
|
61
|
+
const key = this.getWatchKey(dataId, groupName, namespaceId);
|
|
62
|
+
|
|
63
|
+
// 如果已经存在监听器,先取消
|
|
64
|
+
const existing = this.watchers.get(key);
|
|
65
|
+
if (existing) {
|
|
66
|
+
clearInterval(existing.intervalId);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
let lastMd5: string | undefined;
|
|
70
|
+
|
|
71
|
+
const intervalId = setInterval(async () => {
|
|
72
|
+
try {
|
|
73
|
+
const result = await this.getConfig(dataId, groupName, namespaceId);
|
|
74
|
+
|
|
75
|
+
// 通过 md5 判断配置是否变更
|
|
76
|
+
if (lastMd5 === undefined || lastMd5 !== result.md5) {
|
|
77
|
+
lastMd5 = result.md5;
|
|
78
|
+
listener(result);
|
|
79
|
+
}
|
|
80
|
+
} catch (error) {
|
|
81
|
+
// 监听错误不抛出,避免影响其他监听器
|
|
82
|
+
console.error(`[NacosConfigCenter] Failed to watch config ${dataId}:`, error);
|
|
83
|
+
}
|
|
84
|
+
}, this.watchInterval) as unknown as number;
|
|
85
|
+
|
|
86
|
+
// 立即获取一次配置
|
|
87
|
+
this.getConfig(dataId, groupName, namespaceId)
|
|
88
|
+
.then((result) => {
|
|
89
|
+
lastMd5 = result.md5;
|
|
90
|
+
listener(result);
|
|
91
|
+
})
|
|
92
|
+
.catch((error) => {
|
|
93
|
+
console.error(`[NacosConfigCenter] Failed to get initial config ${dataId}:`, error);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
this.watchers.set(key, { listener, intervalId });
|
|
97
|
+
|
|
98
|
+
// 返回取消监听的函数
|
|
99
|
+
return () => {
|
|
100
|
+
const watcher = this.watchers.get(key);
|
|
101
|
+
if (watcher) {
|
|
102
|
+
clearInterval(watcher.intervalId);
|
|
103
|
+
this.watchers.delete(key);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* 关闭配置中心连接
|
|
110
|
+
*/
|
|
111
|
+
public async close(): Promise<void> {
|
|
112
|
+
// 清除所有监听器
|
|
113
|
+
for (const watcher of this.watchers.values()) {
|
|
114
|
+
clearInterval(watcher.intervalId);
|
|
115
|
+
}
|
|
116
|
+
this.watchers.clear();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* 生成监听器 key
|
|
121
|
+
*/
|
|
122
|
+
private getWatchKey(dataId: string, groupName: string, namespaceId?: string): string {
|
|
123
|
+
return `${namespaceId ?? 'default'}:${groupName}:${dataId}`;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|