@grupodiariodaregiao/bunstone 0.4.1 → 0.4.3
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/dist/index.d.ts +1 -0
- package/dist/index.js +126 -4
- package/dist/lib/app-startup.d.ts +9 -0
- package/dist/lib/on-module/index.d.ts +2 -0
- package/dist/lib/on-module/on-module-destroy.d.ts +3 -0
- package/dist/lib/on-module/on-module-init.d.ts +3 -0
- package/lib/app-startup.ts +160 -4
- package/lib/on-module/index.ts +2 -0
- package/lib/on-module/on-module-destroy.ts +3 -0
- package/lib/on-module/on-module-init.ts +3 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -55,6 +55,7 @@ export * from "./lib/jwt";
|
|
|
55
55
|
export * from "./lib/jwt/jwt-module";
|
|
56
56
|
export { JwtService } from "./lib/jwt/jwt.service";
|
|
57
57
|
export * from "./lib/module";
|
|
58
|
+
export * from "./lib/on-module";
|
|
58
59
|
export * from "./lib/openapi";
|
|
59
60
|
export * from "./lib/render";
|
|
60
61
|
export * from "./lib/types/options";
|
package/dist/index.js
CHANGED
|
@@ -116627,6 +116627,14 @@ function Head2(pathname = "") {
|
|
|
116627
116627
|
return HttpMethodDecorator("HEAD", pathname);
|
|
116628
116628
|
}
|
|
116629
116629
|
|
|
116630
|
+
// lib/on-module/on-module-destroy.ts
|
|
116631
|
+
class OnModuleDestroy {
|
|
116632
|
+
}
|
|
116633
|
+
|
|
116634
|
+
// lib/on-module/on-module-init.ts
|
|
116635
|
+
class OnModuleInit {
|
|
116636
|
+
}
|
|
116637
|
+
|
|
116630
116638
|
// lib/openapi.ts
|
|
116631
116639
|
var import_reflect_metadata13 = __toESM(require_Reflect(), 1);
|
|
116632
116640
|
var API_TAGS_METADATA = "dip:openapi:tags";
|
|
@@ -117086,12 +117094,22 @@ class AppStartup {
|
|
|
117086
117094
|
static elysia = new Elysia;
|
|
117087
117095
|
static logger = new Logger(AppStartup.name);
|
|
117088
117096
|
static registeredSagas = new WeakSet;
|
|
117097
|
+
static initializedModuleHooks = new WeakSet;
|
|
117098
|
+
static destroyedModuleHooks = new WeakSet;
|
|
117099
|
+
static destroyPromise = null;
|
|
117100
|
+
static hasBeenDestroyed = false;
|
|
117101
|
+
static rootModule;
|
|
117089
117102
|
static viewBundles = new Map;
|
|
117090
117103
|
static globalRateLimitConfig;
|
|
117091
117104
|
static rateLimitService = new RateLimitService;
|
|
117092
117105
|
static async create(module, options) {
|
|
117093
117106
|
try {
|
|
117094
117107
|
AppStartup.elysia = new Elysia;
|
|
117108
|
+
AppStartup.rootModule = module;
|
|
117109
|
+
AppStartup.initializedModuleHooks = new WeakSet;
|
|
117110
|
+
AppStartup.destroyedModuleHooks = new WeakSet;
|
|
117111
|
+
AppStartup.destroyPromise = null;
|
|
117112
|
+
AppStartup.hasBeenDestroyed = false;
|
|
117095
117113
|
const publicExists = await Bun.file("public").exists();
|
|
117096
117114
|
if (!publicExists)
|
|
117097
117115
|
await mkdir("./public", { recursive: true });
|
|
@@ -117144,6 +117162,9 @@ class AppStartup {
|
|
|
117144
117162
|
message: error48 instanceof Error ? error48.message : "Internal Server Error"
|
|
117145
117163
|
};
|
|
117146
117164
|
});
|
|
117165
|
+
AppStartup.elysia.onStop(async () => {
|
|
117166
|
+
await AppStartup.executeDestroyLifecycle();
|
|
117167
|
+
});
|
|
117147
117168
|
if (options?.cors) {
|
|
117148
117169
|
AppStartup.elysia.use(cors(options.cors));
|
|
117149
117170
|
}
|
|
@@ -117181,7 +117202,7 @@ class AppStartup {
|
|
|
117181
117202
|
}));
|
|
117182
117203
|
}
|
|
117183
117204
|
AppStartup.globalRateLimitConfig = options?.rateLimit;
|
|
117184
|
-
AppStartup.registerModules(module);
|
|
117205
|
+
await AppStartup.registerModules(module);
|
|
117185
117206
|
return {
|
|
117186
117207
|
listen: AppStartup.listen,
|
|
117187
117208
|
getElysia: () => AppStartup.elysia
|
|
@@ -117293,6 +117314,28 @@ if (document.readyState === 'loading') {
|
|
|
117293
117314
|
AppStartup.logger.log(`App is running at http://localhost:${port}`);
|
|
117294
117315
|
AppStartup.elysia.listen(port);
|
|
117295
117316
|
}
|
|
117317
|
+
static async executeDestroyLifecycle() {
|
|
117318
|
+
if (!AppStartup.rootModule) {
|
|
117319
|
+
return;
|
|
117320
|
+
}
|
|
117321
|
+
if (AppStartup.hasBeenDestroyed) {
|
|
117322
|
+
return;
|
|
117323
|
+
}
|
|
117324
|
+
if (AppStartup.destroyPromise) {
|
|
117325
|
+
await AppStartup.destroyPromise;
|
|
117326
|
+
return;
|
|
117327
|
+
}
|
|
117328
|
+
AppStartup.destroyPromise = (async () => {
|
|
117329
|
+
await AppStartup.destroyModules(AppStartup.rootModule);
|
|
117330
|
+
AppStartup.hasBeenDestroyed = true;
|
|
117331
|
+
})().catch((error48) => {
|
|
117332
|
+
AppStartup.logger.error(`Error while executing OnModuleDestroy hooks: ${error48?.message || error48}`);
|
|
117333
|
+
throw error48;
|
|
117334
|
+
}).finally(() => {
|
|
117335
|
+
AppStartup.destroyPromise = null;
|
|
117336
|
+
});
|
|
117337
|
+
await AppStartup.destroyPromise;
|
|
117338
|
+
}
|
|
117296
117339
|
static async executeControllerMethod(context, controller, method) {
|
|
117297
117340
|
const args = await processParameters(context, controller, method);
|
|
117298
117341
|
const result = await controller[method](...args);
|
|
@@ -117336,7 +117379,7 @@ if (document.readyState === 'loading') {
|
|
|
117336
117379
|
}
|
|
117337
117380
|
return result;
|
|
117338
117381
|
}
|
|
117339
|
-
static registerModules(module) {
|
|
117382
|
+
static async registerModules(module) {
|
|
117340
117383
|
const isGlobal = Reflect.getMetadata("dip:module:global", module);
|
|
117341
117384
|
if (isGlobal) {
|
|
117342
117385
|
const injectables = Reflect.getMetadata("dip:injectables", module);
|
|
@@ -117355,7 +117398,47 @@ if (document.readyState === 'loading') {
|
|
|
117355
117398
|
AppStartup.registerRabbitMQConsumers(module);
|
|
117356
117399
|
const modules = Reflect.getMetadata("dip:modules", module) || [];
|
|
117357
117400
|
for (const mod of modules) {
|
|
117358
|
-
AppStartup.registerModules(mod);
|
|
117401
|
+
await AppStartup.registerModules(mod);
|
|
117402
|
+
}
|
|
117403
|
+
await AppStartup.executeOnModuleInit(module);
|
|
117404
|
+
}
|
|
117405
|
+
static async destroyModules(module) {
|
|
117406
|
+
const modules = Reflect.getMetadata("dip:modules", module) || [];
|
|
117407
|
+
for (const mod of modules) {
|
|
117408
|
+
await AppStartup.destroyModules(mod);
|
|
117409
|
+
}
|
|
117410
|
+
await AppStartup.executeOnModuleDestroy(module);
|
|
117411
|
+
}
|
|
117412
|
+
static async executeOnModuleInit(module) {
|
|
117413
|
+
const injectables = Reflect.getMetadata("dip:injectables", module);
|
|
117414
|
+
if (!injectables) {
|
|
117415
|
+
return;
|
|
117416
|
+
}
|
|
117417
|
+
for (const provider of injectables.values()) {
|
|
117418
|
+
if (!(provider instanceof OnModuleInit)) {
|
|
117419
|
+
continue;
|
|
117420
|
+
}
|
|
117421
|
+
if (AppStartup.initializedModuleHooks.has(provider)) {
|
|
117422
|
+
continue;
|
|
117423
|
+
}
|
|
117424
|
+
AppStartup.initializedModuleHooks.add(provider);
|
|
117425
|
+
await provider.onModuleInit();
|
|
117426
|
+
}
|
|
117427
|
+
}
|
|
117428
|
+
static async executeOnModuleDestroy(module) {
|
|
117429
|
+
const injectables = Reflect.getMetadata("dip:injectables", module);
|
|
117430
|
+
if (!injectables) {
|
|
117431
|
+
return;
|
|
117432
|
+
}
|
|
117433
|
+
for (const provider of injectables.values()) {
|
|
117434
|
+
if (!(provider instanceof OnModuleDestroy)) {
|
|
117435
|
+
continue;
|
|
117436
|
+
}
|
|
117437
|
+
if (AppStartup.destroyedModuleHooks.has(provider)) {
|
|
117438
|
+
continue;
|
|
117439
|
+
}
|
|
117440
|
+
AppStartup.destroyedModuleHooks.add(provider);
|
|
117441
|
+
await provider.onModuleDestroy();
|
|
117359
117442
|
}
|
|
117360
117443
|
}
|
|
117361
117444
|
static registerRoutes(module) {
|
|
@@ -117583,6 +117666,33 @@ if (document.readyState === 'loading') {
|
|
|
117583
117666
|
return;
|
|
117584
117667
|
}
|
|
117585
117668
|
const injectables = Reflect.getMetadata("dip:injectables", module);
|
|
117669
|
+
function matchRoutingKey(pattern, routingKey) {
|
|
117670
|
+
if (pattern === routingKey)
|
|
117671
|
+
return true;
|
|
117672
|
+
if (!pattern.includes("*") && !pattern.includes("#"))
|
|
117673
|
+
return false;
|
|
117674
|
+
const pp = pattern.split(".");
|
|
117675
|
+
const kp = routingKey.split(".");
|
|
117676
|
+
function go2(pi3, ki3) {
|
|
117677
|
+
if (pi3 === pp.length && ki3 === kp.length)
|
|
117678
|
+
return true;
|
|
117679
|
+
if (pi3 === pp.length)
|
|
117680
|
+
return false;
|
|
117681
|
+
if (pp[pi3] === "#") {
|
|
117682
|
+
for (let j4 = ki3;j4 <= kp.length; j4++) {
|
|
117683
|
+
if (go2(pi3 + 1, j4))
|
|
117684
|
+
return true;
|
|
117685
|
+
}
|
|
117686
|
+
return false;
|
|
117687
|
+
}
|
|
117688
|
+
if (ki3 === kp.length)
|
|
117689
|
+
return false;
|
|
117690
|
+
if (pp[pi3] === "*" || pp[pi3] === kp[ki3])
|
|
117691
|
+
return go2(pi3 + 1, ki3 + 1);
|
|
117692
|
+
return false;
|
|
117693
|
+
}
|
|
117694
|
+
return go2(0, 0);
|
|
117695
|
+
}
|
|
117586
117696
|
(async () => {
|
|
117587
117697
|
try {
|
|
117588
117698
|
await RabbitMQConnection.initialise();
|
|
@@ -117652,7 +117762,10 @@ if (document.readyState === 'loading') {
|
|
|
117652
117762
|
}
|
|
117653
117763
|
for (const [queue2, handlers] of queueMap.entries()) {
|
|
117654
117764
|
const noAck = handlers.every((h3) => h3.noAck);
|
|
117655
|
-
const handlerList = handlers.map((h3) =>
|
|
117765
|
+
const handlerList = handlers.map((h3) => {
|
|
117766
|
+
const rk = h3.descriptor.options.routingKey;
|
|
117767
|
+
return `${h3.providerName}.${h3.descriptor.methodName}()${rk ? ` [${rk}]` : ""}`;
|
|
117768
|
+
}).join(", ");
|
|
117656
117769
|
AppStartup.logger.log(`Registering RabbitMQ consumer for queue: "${queue2}" \u2192 [${handlerList}]`);
|
|
117657
117770
|
try {
|
|
117658
117771
|
const channel = await RabbitMQConnection.getConsumerChannel(queue2);
|
|
@@ -117686,6 +117799,10 @@ if (document.readyState === 'loading') {
|
|
|
117686
117799
|
noAck: handlerNoAck,
|
|
117687
117800
|
providerName
|
|
117688
117801
|
} of handlers) {
|
|
117802
|
+
const handlerRoutingKey = descriptor.options.routingKey;
|
|
117803
|
+
if (handlerRoutingKey && !matchRoutingKey(handlerRoutingKey, raw.fields.routingKey)) {
|
|
117804
|
+
continue;
|
|
117805
|
+
}
|
|
117689
117806
|
try {
|
|
117690
117807
|
await instance[descriptor.methodName](msg);
|
|
117691
117808
|
} catch (err) {
|
|
@@ -117695,6 +117812,9 @@ if (document.readyState === 'loading') {
|
|
|
117695
117812
|
}
|
|
117696
117813
|
}
|
|
117697
117814
|
}
|
|
117815
|
+
if (!noAck && !settled) {
|
|
117816
|
+
settle(() => channel.ack(raw));
|
|
117817
|
+
}
|
|
117698
117818
|
}, { noAck });
|
|
117699
117819
|
} catch (err) {
|
|
117700
117820
|
AppStartup.logger.error(`Failed to register consumer for queue "${queue2}": ${err.message}`);
|
|
@@ -119939,6 +120059,8 @@ export {
|
|
|
119939
120059
|
ParamType,
|
|
119940
120060
|
Param,
|
|
119941
120061
|
Options,
|
|
120062
|
+
OnModuleInit,
|
|
120063
|
+
OnModuleDestroy,
|
|
119942
120064
|
OkResponse,
|
|
119943
120065
|
NotFoundException,
|
|
119944
120066
|
NoContentResponse,
|
|
@@ -9,6 +9,11 @@ export declare class AppStartup {
|
|
|
9
9
|
private static elysia;
|
|
10
10
|
private static readonly logger;
|
|
11
11
|
private static readonly registeredSagas;
|
|
12
|
+
private static initializedModuleHooks;
|
|
13
|
+
private static destroyedModuleHooks;
|
|
14
|
+
private static destroyPromise;
|
|
15
|
+
private static hasBeenDestroyed;
|
|
16
|
+
private static rootModule;
|
|
12
17
|
private static readonly viewBundles;
|
|
13
18
|
private static globalRateLimitConfig;
|
|
14
19
|
private static rateLimitService;
|
|
@@ -67,8 +72,12 @@ export declare class AppStartup {
|
|
|
67
72
|
* @param port The port number to listen on.
|
|
68
73
|
*/
|
|
69
74
|
static listen(port: number): void;
|
|
75
|
+
private static executeDestroyLifecycle;
|
|
70
76
|
private static executeControllerMethod;
|
|
71
77
|
private static registerModules;
|
|
78
|
+
private static destroyModules;
|
|
79
|
+
private static executeOnModuleInit;
|
|
80
|
+
private static executeOnModuleDestroy;
|
|
72
81
|
private static registerRoutes;
|
|
73
82
|
/**
|
|
74
83
|
* Builds effective rate limit configuration by merging global config with method config
|
package/lib/app-startup.ts
CHANGED
|
@@ -28,6 +28,8 @@ import { ConfigurationError } from "./errors";
|
|
|
28
28
|
import { HttpException } from "./http-exceptions";
|
|
29
29
|
import { HTTP_HEADERS_METADATA } from "./http-methods";
|
|
30
30
|
import { ParamType, processParameters } from "./http-params";
|
|
31
|
+
import { OnModuleDestroy } from "./on-module/on-module-destroy";
|
|
32
|
+
import { OnModuleInit } from "./on-module/on-module-init";
|
|
31
33
|
import {
|
|
32
34
|
API_HEADERS_METADATA,
|
|
33
35
|
API_OPERATION_METADATA,
|
|
@@ -57,6 +59,11 @@ export class AppStartup {
|
|
|
57
59
|
private static elysia: Elysia = new Elysia();
|
|
58
60
|
private static readonly logger = new Logger(AppStartup.name);
|
|
59
61
|
private static readonly registeredSagas = new WeakSet<any>();
|
|
62
|
+
private static initializedModuleHooks = new WeakSet<OnModuleInit>();
|
|
63
|
+
private static destroyedModuleHooks = new WeakSet<OnModuleDestroy>();
|
|
64
|
+
private static destroyPromise: Promise<void> | null = null;
|
|
65
|
+
private static hasBeenDestroyed = false;
|
|
66
|
+
private static rootModule: any;
|
|
60
67
|
private static readonly viewBundles = new Map<string, string>();
|
|
61
68
|
private static globalRateLimitConfig: RateLimitGlobalConfig | undefined;
|
|
62
69
|
private static rateLimitService: RateLimitService = new RateLimitService();
|
|
@@ -71,6 +78,11 @@ export class AppStartup {
|
|
|
71
78
|
static async create(module: any, options?: Options) {
|
|
72
79
|
try {
|
|
73
80
|
AppStartup.elysia = new Elysia(); // Reset for each creation
|
|
81
|
+
AppStartup.rootModule = module;
|
|
82
|
+
AppStartup.initializedModuleHooks = new WeakSet<OnModuleInit>();
|
|
83
|
+
AppStartup.destroyedModuleHooks = new WeakSet<OnModuleDestroy>();
|
|
84
|
+
AppStartup.destroyPromise = null;
|
|
85
|
+
AppStartup.hasBeenDestroyed = false;
|
|
74
86
|
|
|
75
87
|
const publicExists = await Bun.file("public").exists();
|
|
76
88
|
// Ensure public directory exists before static plugin uses it
|
|
@@ -149,6 +161,10 @@ export class AppStartup {
|
|
|
149
161
|
};
|
|
150
162
|
});
|
|
151
163
|
|
|
164
|
+
AppStartup.elysia.onStop(async () => {
|
|
165
|
+
await AppStartup.executeDestroyLifecycle();
|
|
166
|
+
});
|
|
167
|
+
|
|
152
168
|
if (options?.cors) {
|
|
153
169
|
AppStartup.elysia.use(cors(options.cors));
|
|
154
170
|
}
|
|
@@ -202,7 +218,7 @@ export class AppStartup {
|
|
|
202
218
|
// Store global rate limit config
|
|
203
219
|
AppStartup.globalRateLimitConfig = options?.rateLimit;
|
|
204
220
|
|
|
205
|
-
AppStartup.registerModules(module);
|
|
221
|
+
await AppStartup.registerModules(module);
|
|
206
222
|
return {
|
|
207
223
|
/**
|
|
208
224
|
* Starts the server on the specified port.
|
|
@@ -352,6 +368,37 @@ if (document.readyState === 'loading') {
|
|
|
352
368
|
AppStartup.elysia.listen(port);
|
|
353
369
|
}
|
|
354
370
|
|
|
371
|
+
private static async executeDestroyLifecycle() {
|
|
372
|
+
if (!AppStartup.rootModule) {
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (AppStartup.hasBeenDestroyed) {
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
if (AppStartup.destroyPromise) {
|
|
381
|
+
await AppStartup.destroyPromise;
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
AppStartup.destroyPromise = (async () => {
|
|
386
|
+
await AppStartup.destroyModules(AppStartup.rootModule);
|
|
387
|
+
AppStartup.hasBeenDestroyed = true;
|
|
388
|
+
})()
|
|
389
|
+
.catch((error) => {
|
|
390
|
+
AppStartup.logger.error(
|
|
391
|
+
`Error while executing OnModuleDestroy hooks: ${error?.message || error}`,
|
|
392
|
+
);
|
|
393
|
+
throw error;
|
|
394
|
+
})
|
|
395
|
+
.finally(() => {
|
|
396
|
+
AppStartup.destroyPromise = null;
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
await AppStartup.destroyPromise;
|
|
400
|
+
}
|
|
401
|
+
|
|
355
402
|
private static async executeControllerMethod(
|
|
356
403
|
context: any,
|
|
357
404
|
controller: any,
|
|
@@ -436,7 +483,7 @@ if (document.readyState === 'loading') {
|
|
|
436
483
|
return result;
|
|
437
484
|
}
|
|
438
485
|
|
|
439
|
-
private static registerModules(module: any) {
|
|
486
|
+
private static async registerModules(module: any) {
|
|
440
487
|
const isGlobal = Reflect.getMetadata("dip:module:global", module);
|
|
441
488
|
if (isGlobal) {
|
|
442
489
|
const injectables: Map<any, any> = Reflect.getMetadata(
|
|
@@ -461,7 +508,67 @@ if (document.readyState === 'loading') {
|
|
|
461
508
|
const modules = Reflect.getMetadata("dip:modules", module) || [];
|
|
462
509
|
|
|
463
510
|
for (const mod of modules) {
|
|
464
|
-
AppStartup.registerModules(mod);
|
|
511
|
+
await AppStartup.registerModules(mod);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
await AppStartup.executeOnModuleInit(module);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
private static async destroyModules(module: any) {
|
|
518
|
+
const modules = Reflect.getMetadata("dip:modules", module) || [];
|
|
519
|
+
|
|
520
|
+
for (const mod of modules) {
|
|
521
|
+
await AppStartup.destroyModules(mod);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
await AppStartup.executeOnModuleDestroy(module);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
private static async executeOnModuleInit(module: any) {
|
|
528
|
+
const injectables: Map<any, any> | undefined = Reflect.getMetadata(
|
|
529
|
+
"dip:injectables",
|
|
530
|
+
module,
|
|
531
|
+
);
|
|
532
|
+
|
|
533
|
+
if (!injectables) {
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
for (const provider of injectables.values()) {
|
|
538
|
+
if (!(provider instanceof OnModuleInit)) {
|
|
539
|
+
continue;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
if (AppStartup.initializedModuleHooks.has(provider)) {
|
|
543
|
+
continue;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
AppStartup.initializedModuleHooks.add(provider);
|
|
547
|
+
await provider.onModuleInit();
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
private static async executeOnModuleDestroy(module: any) {
|
|
552
|
+
const injectables: Map<any, any> | undefined = Reflect.getMetadata(
|
|
553
|
+
"dip:injectables",
|
|
554
|
+
module,
|
|
555
|
+
);
|
|
556
|
+
|
|
557
|
+
if (!injectables) {
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
for (const provider of injectables.values()) {
|
|
562
|
+
if (!(provider instanceof OnModuleDestroy)) {
|
|
563
|
+
continue;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
if (AppStartup.destroyedModuleHooks.has(provider)) {
|
|
567
|
+
continue;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
AppStartup.destroyedModuleHooks.add(provider);
|
|
571
|
+
await provider.onModuleDestroy();
|
|
465
572
|
}
|
|
466
573
|
}
|
|
467
574
|
|
|
@@ -879,6 +986,34 @@ if (document.readyState === 'loading') {
|
|
|
879
986
|
module,
|
|
880
987
|
);
|
|
881
988
|
|
|
989
|
+
/**
|
|
990
|
+
* Matches a RabbitMQ topic routing key pattern against a concrete routing key.
|
|
991
|
+
* Supports `*` (exactly one word) and `#` (zero or more words).
|
|
992
|
+
*/
|
|
993
|
+
function matchRoutingKey(pattern: string, routingKey: string): boolean {
|
|
994
|
+
if (pattern === routingKey) return true;
|
|
995
|
+
if (!pattern.includes("*") && !pattern.includes("#")) return false;
|
|
996
|
+
|
|
997
|
+
const pp = pattern.split(".");
|
|
998
|
+
const kp = routingKey.split(".");
|
|
999
|
+
|
|
1000
|
+
function go(pi: number, ki: number): boolean {
|
|
1001
|
+
if (pi === pp.length && ki === kp.length) return true;
|
|
1002
|
+
if (pi === pp.length) return false;
|
|
1003
|
+
if (pp[pi] === "#") {
|
|
1004
|
+
for (let j = ki; j <= kp.length; j++) {
|
|
1005
|
+
if (go(pi + 1, j)) return true;
|
|
1006
|
+
}
|
|
1007
|
+
return false;
|
|
1008
|
+
}
|
|
1009
|
+
if (ki === kp.length) return false;
|
|
1010
|
+
if (pp[pi] === "*" || pp[pi] === kp[ki]) return go(pi + 1, ki + 1);
|
|
1011
|
+
return false;
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
return go(0, 0);
|
|
1015
|
+
}
|
|
1016
|
+
|
|
882
1017
|
type QueueHandler = {
|
|
883
1018
|
instance: any;
|
|
884
1019
|
descriptor: RabbitMQMethodDescriptor;
|
|
@@ -995,7 +1130,10 @@ if (document.readyState === 'loading') {
|
|
|
995
1130
|
const noAck = handlers.every((h) => h.noAck);
|
|
996
1131
|
|
|
997
1132
|
const handlerList = handlers
|
|
998
|
-
.map((h) =>
|
|
1133
|
+
.map((h) => {
|
|
1134
|
+
const rk = h.descriptor.options.routingKey;
|
|
1135
|
+
return `${h.providerName}.${h.descriptor.methodName}()${rk ? ` [${rk}]` : ""}`;
|
|
1136
|
+
})
|
|
999
1137
|
.join(", ");
|
|
1000
1138
|
|
|
1001
1139
|
AppStartup.logger.log(
|
|
@@ -1043,6 +1181,17 @@ if (document.readyState === 'loading') {
|
|
|
1043
1181
|
noAck: handlerNoAck,
|
|
1044
1182
|
providerName,
|
|
1045
1183
|
} of handlers) {
|
|
1184
|
+
// ── Routing-key filter ─────────────────────────────────────────────
|
|
1185
|
+
// When { queue, routingKey } is set without exchange, only dispatch
|
|
1186
|
+
// if the message's routing key matches the declared pattern.
|
|
1187
|
+
const handlerRoutingKey = descriptor.options.routingKey;
|
|
1188
|
+
if (
|
|
1189
|
+
handlerRoutingKey &&
|
|
1190
|
+
!matchRoutingKey(handlerRoutingKey, raw.fields.routingKey)
|
|
1191
|
+
) {
|
|
1192
|
+
continue;
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1046
1195
|
try {
|
|
1047
1196
|
await instance[descriptor.methodName](msg);
|
|
1048
1197
|
} catch (err: any) {
|
|
@@ -1054,6 +1203,13 @@ if (document.readyState === 'loading') {
|
|
|
1054
1203
|
}
|
|
1055
1204
|
}
|
|
1056
1205
|
}
|
|
1206
|
+
|
|
1207
|
+
// ── Auto-ack if no handler consumed the message ────────────────
|
|
1208
|
+
// All handlers were filtered out by routingKey – ack silently
|
|
1209
|
+
// to prevent the message from piling up as unacked.
|
|
1210
|
+
if (!noAck && !settled) {
|
|
1211
|
+
settle(() => channel.ack(raw));
|
|
1212
|
+
}
|
|
1057
1213
|
},
|
|
1058
1214
|
{ noAck },
|
|
1059
1215
|
);
|