pp-command-bus 1.2.1 → 1.2.2
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/command-bus/command-bus.spec.js +13 -0
- package/dist/command-bus/command-bus.spec.js.map +1 -1
- package/dist/command-bus/index.js +2 -2
- package/dist/command-bus/index.js.map +1 -1
- package/dist/command-bus/job/job-processor.d.ts +1 -0
- package/dist/command-bus/job/job-processor.js +7 -1
- package/dist/command-bus/job/job-processor.js.map +1 -1
- package/dist/command-bus/job/job-processor.spec.js +13 -6
- package/dist/command-bus/job/job-processor.spec.js.map +1 -1
- package/dist/command-bus/rpc/rpc-coordinator.d.ts +48 -26
- package/dist/command-bus/rpc/rpc-coordinator.js +264 -156
- package/dist/command-bus/rpc/rpc-coordinator.js.map +1 -1
- package/dist/command-bus/rpc/rpc-coordinator.spec.js +209 -128
- package/dist/command-bus/rpc/rpc-coordinator.spec.js.map +1 -1
- package/dist/command-bus/types/index.d.ts +13 -2
- package/dist/pp-command-bus-1.2.2.tgz +0 -0
- package/package.json +1 -1
- package/dist/pp-command-bus-1.2.1.tgz +0 -0
|
@@ -9,26 +9,98 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const crypto_1 = require("crypto");
|
|
13
|
+
/**
|
|
14
|
+
* UUID per proces Node.js - współdzielony przez wszystkie instancje CommandBus w tym samym procesie
|
|
15
|
+
* Zapewnia izolację odpowiedzi RPC między różnymi procesami/replikami
|
|
16
|
+
*/
|
|
17
|
+
const PROCESS_INSTANCE_ID = (0, crypto_1.randomUUID)();
|
|
12
18
|
/**
|
|
13
19
|
* Zarządza lifecycle wywołań RPC przez Redis Pub/Sub
|
|
14
|
-
*
|
|
15
|
-
*
|
|
20
|
+
* Używa shared subscriber z pattern matching dla izolacji między procesami
|
|
21
|
+
* Multiplexing odpowiedzi przez Map<correlationId, PendingCall>
|
|
16
22
|
*
|
|
17
|
-
* Architektura:
|
|
18
|
-
* -
|
|
19
|
-
* -
|
|
20
|
-
* -
|
|
23
|
+
* Architektura: Jeden shared subscriber per proces
|
|
24
|
+
* - Eliminuje race conditions (subscriber zawsze gotowy)
|
|
25
|
+
* - Jedno połączenie Redis zamiast N per RPC call
|
|
26
|
+
* - Pattern: rpc:response:{processId}:* dla izolacji między replikami
|
|
27
|
+
* - Multiplexing przez Map dla routingu odpowiedzi do promises
|
|
21
28
|
*/
|
|
22
29
|
class RpcCoordinator {
|
|
23
30
|
constructor(logger, redisConnection, compressionService) {
|
|
24
31
|
this.logger = logger;
|
|
25
32
|
this.redisConnection = redisConnection;
|
|
26
33
|
this.compressionService = compressionService;
|
|
34
|
+
/**
|
|
35
|
+
* UUID procesu Node.js (współdzielony przez wszystkie instancje w procesie)
|
|
36
|
+
*/
|
|
37
|
+
this.processInstanceId = PROCESS_INSTANCE_ID;
|
|
38
|
+
/**
|
|
39
|
+
* Mapa pending RPC calls - routing odpowiedzi do promises
|
|
40
|
+
*/
|
|
41
|
+
this.pendingCalls = new Map();
|
|
42
|
+
/**
|
|
43
|
+
* Czy subscriber jest gotowy (psubscribe zakończony)
|
|
44
|
+
*/
|
|
45
|
+
this.isSubscriberReady = false;
|
|
46
|
+
this.logger.debug('Inicjalizacja RpcCoordinator', {
|
|
47
|
+
processInstanceId: this.processInstanceId,
|
|
48
|
+
timestamp: new Date().toISOString(),
|
|
49
|
+
});
|
|
50
|
+
// Setup shared subscriber z pattern matching
|
|
51
|
+
this.setupSharedSubscriber();
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Konfiguruje shared subscriber dla wszystkich RPC calls
|
|
55
|
+
* Pattern subscribe: rpc:response:{processId}:* dla izolacji między procesami
|
|
56
|
+
* Multiplexing: pmessage handler routuje do odpowiednich pending calls
|
|
57
|
+
*/
|
|
58
|
+
setupSharedSubscriber() {
|
|
59
|
+
this.sharedSubscriber = this.redisConnection.duplicate();
|
|
60
|
+
// Pattern subscribe z processInstanceId - tylko dla tego procesu!
|
|
61
|
+
const pattern = `rpc:response:${this.processInstanceId}:*`;
|
|
62
|
+
this.logger.debug('Tworzenie shared subscriber dla RPC', {
|
|
63
|
+
processInstanceId: this.processInstanceId,
|
|
64
|
+
pattern,
|
|
65
|
+
timestamp: new Date().toISOString(),
|
|
66
|
+
});
|
|
67
|
+
// Promise dla oczekiwania na psubscribe
|
|
68
|
+
this.subscriberReadyPromise = new Promise((resolve) => {
|
|
69
|
+
this.sharedSubscriber.once('psubscribe', (subscribePattern, count) => {
|
|
70
|
+
this.logger.debug('Shared subscriber gotowy', {
|
|
71
|
+
processInstanceId: this.processInstanceId,
|
|
72
|
+
pattern: subscribePattern,
|
|
73
|
+
subscriptionCount: count,
|
|
74
|
+
timestamp: new Date().toISOString(),
|
|
75
|
+
});
|
|
76
|
+
this.isSubscriberReady = true;
|
|
77
|
+
resolve();
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
// Handler dla odpowiedzi RPC - multiplexing do pending calls
|
|
81
|
+
this.sharedSubscriber.on('pmessage', (_pattern, channel, message) => {
|
|
82
|
+
this.handleRpcMessage(channel, message);
|
|
83
|
+
});
|
|
84
|
+
// Handler błędów Redis subscriber
|
|
85
|
+
this.sharedSubscriber.on('error', (error) => {
|
|
86
|
+
this.logger.error('Błąd shared subscriber RPC', {
|
|
87
|
+
processInstanceId: this.processInstanceId,
|
|
88
|
+
error: error.message,
|
|
89
|
+
timestamp: new Date().toISOString(),
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
// Subskrybuj pattern z processInstanceId
|
|
93
|
+
void this.sharedSubscriber.psubscribe(pattern);
|
|
94
|
+
this.logger.debug('Subskrybowanie pattern dla RPC', {
|
|
95
|
+
processInstanceId: this.processInstanceId,
|
|
96
|
+
pattern,
|
|
97
|
+
timestamp: new Date().toISOString(),
|
|
98
|
+
});
|
|
27
99
|
}
|
|
28
100
|
/**
|
|
29
101
|
* Przygotowuje komendę RPC z odpowiednimi metadanymi
|
|
30
102
|
* @param command - Komenda do wysłania
|
|
31
|
-
* @param responseChannel - Nazwa kanału Redis Pub/Sub dla odpowiedzi
|
|
103
|
+
* @param responseChannel - Nazwa kanału Redis Pub/Sub dla odpowiedzi (z processInstanceId)
|
|
32
104
|
* @returns Komenda z metadanymi RPC
|
|
33
105
|
*/
|
|
34
106
|
prepareRpcCommand(command, responseChannel) {
|
|
@@ -40,14 +112,14 @@ class RpcCoordinator {
|
|
|
40
112
|
} });
|
|
41
113
|
}
|
|
42
114
|
/**
|
|
43
|
-
* Rejestruje nowe wywołanie RPC z timeout przez
|
|
44
|
-
*
|
|
45
|
-
*
|
|
115
|
+
* Rejestruje nowe wywołanie RPC z timeout przez shared subscriber
|
|
116
|
+
* Dodaje pending call do Map i zwraca promise
|
|
117
|
+
* Subscriber jest zawsze gotowy (subskrybuje przy konstrukcji) - zero race conditions
|
|
46
118
|
*
|
|
47
|
-
* Architektura:
|
|
48
|
-
* - Brak race conditions
|
|
49
|
-
* -
|
|
50
|
-
* -
|
|
119
|
+
* Architektura: Shared subscriber + multiplexing
|
|
120
|
+
* - Brak race conditions (subscriber gotowy przed pierwszym call)
|
|
121
|
+
* - Jedno połączenie Redis per proces
|
|
122
|
+
* - Routing przez Map<correlationId, PendingCall>
|
|
51
123
|
*
|
|
52
124
|
* @param correlationId - Unikalny ID wywołania
|
|
53
125
|
* @param commandName - Nazwa komendy
|
|
@@ -56,186 +128,222 @@ class RpcCoordinator {
|
|
|
56
128
|
*/
|
|
57
129
|
registerCall(correlationId, commandName, timeout) {
|
|
58
130
|
return __awaiter(this, void 0, void 0, function* () {
|
|
59
|
-
const responseChannel = `rpc:response:${correlationId}`;
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
let timeoutId;
|
|
63
|
-
this.logger.debug('Rejestrowanie wywołania RPC przez Pub/Sub', {
|
|
131
|
+
const responseChannel = `rpc:response:${this.processInstanceId}:${correlationId}`;
|
|
132
|
+
this.logger.debug('Rejestrowanie wywołania RPC przez shared subscriber', {
|
|
133
|
+
processInstanceId: this.processInstanceId,
|
|
64
134
|
correlationId,
|
|
65
135
|
responseChannel,
|
|
66
136
|
commandName,
|
|
67
137
|
timeout: `${timeout}ms`,
|
|
68
138
|
timestamp: new Date().toISOString(),
|
|
69
139
|
});
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
if (channel !== responseChannel)
|
|
75
|
-
return;
|
|
76
|
-
// Dekompresuj i parsuj odpowiedź (async)
|
|
77
|
-
this.compressionService
|
|
78
|
-
.decompress(message, true)
|
|
79
|
-
.then((decompressed) => {
|
|
80
|
-
const { correlationId: responseCorrelationId, result, error, } = decompressed;
|
|
81
|
-
this.logger.debug('Otrzymano odpowiedź RPC przez Pub/Sub', {
|
|
82
|
-
correlationId: responseCorrelationId,
|
|
83
|
-
hasResult: result !== undefined,
|
|
84
|
-
hasError: error !== undefined,
|
|
85
|
-
timestamp: new Date().toISOString(),
|
|
86
|
-
});
|
|
87
|
-
// Usunięcie handlera po otrzymaniu odpowiedzi
|
|
88
|
-
subscriber.off('message', messageHandler);
|
|
89
|
-
if (error) {
|
|
90
|
-
this.logger.error('Wywołanie RPC odrzucone', {
|
|
91
|
-
correlationId: responseCorrelationId,
|
|
92
|
-
error,
|
|
93
|
-
timestamp: new Date().toISOString(),
|
|
94
|
-
});
|
|
95
|
-
reject(new Error(error));
|
|
96
|
-
}
|
|
97
|
-
else {
|
|
98
|
-
this.logger.debug('Wywołanie RPC rozwiązane', {
|
|
99
|
-
correlationId: responseCorrelationId,
|
|
100
|
-
timestamp: new Date().toISOString(),
|
|
101
|
-
});
|
|
102
|
-
resolve(result);
|
|
103
|
-
}
|
|
104
|
-
})
|
|
105
|
-
.catch((decompressError) => {
|
|
106
|
-
this.logger.error('Błąd dekompresji/parsowania odpowiedzi RPC', {
|
|
107
|
-
correlationId,
|
|
108
|
-
error: decompressError instanceof Error
|
|
109
|
-
? decompressError.message
|
|
110
|
-
: String(decompressError),
|
|
111
|
-
timestamp: new Date().toISOString(),
|
|
112
|
-
});
|
|
113
|
-
reject(new Error('Failed to decompress/parse RPC response'));
|
|
114
|
-
});
|
|
115
|
-
};
|
|
116
|
-
// Obsługa błędów Redis
|
|
117
|
-
const errorHandler = (error) => {
|
|
118
|
-
this.logger.error('Błąd Redis subscriber podczas RPC', {
|
|
119
|
-
correlationId,
|
|
120
|
-
error: error.message,
|
|
121
|
-
timestamp: new Date().toISOString(),
|
|
122
|
-
});
|
|
123
|
-
subscriber.off('message', messageHandler);
|
|
124
|
-
subscriber.off('error', errorHandler);
|
|
125
|
-
reject(new Error(`Redis subscriber error: ${error.message}`));
|
|
126
|
-
};
|
|
127
|
-
subscriber.on('message', messageHandler);
|
|
128
|
-
subscriber.on('error', errorHandler);
|
|
129
|
-
});
|
|
130
|
-
// Subskrybuj kanał PRZED wysłaniem komendy (zapobiega race condition)
|
|
131
|
-
yield subscriber.subscribe(responseChannel);
|
|
132
|
-
this.logger.debug('Subskrybowano kanał RPC', {
|
|
140
|
+
// Czekaj aż subscriber będzie gotowy (tylko przy pierwszym call)
|
|
141
|
+
if (!this.isSubscriberReady) {
|
|
142
|
+
this.logger.debug('Oczekiwanie na gotowość shared subscriber', {
|
|
143
|
+
processInstanceId: this.processInstanceId,
|
|
133
144
|
correlationId,
|
|
134
|
-
responseChannel,
|
|
135
145
|
timestamp: new Date().toISOString(),
|
|
136
146
|
});
|
|
137
|
-
|
|
138
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
139
|
-
timeoutId = setTimeout(() => {
|
|
140
|
-
this.logger.error('RPC timeout', {
|
|
141
|
-
commandName,
|
|
142
|
-
commandId: correlationId,
|
|
143
|
-
timeout: `${timeout}ms`,
|
|
144
|
-
timestamp: new Date().toISOString(),
|
|
145
|
-
});
|
|
146
|
-
reject(new Error(`RPC timeout for command ${commandName}`));
|
|
147
|
-
}, timeout);
|
|
148
|
-
});
|
|
149
|
-
// Czekaj na odpowiedź lub timeout (co nastąpi pierwsze)
|
|
150
|
-
return yield Promise.race([responsePromise, timeoutPromise]);
|
|
147
|
+
yield this.subscriberReadyPromise;
|
|
151
148
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
149
|
+
// Utwórz promise i dodaj do pending calls
|
|
150
|
+
return new Promise((resolve, reject) => {
|
|
151
|
+
const startTime = Date.now();
|
|
152
|
+
// Timeout handler
|
|
153
|
+
const timeoutId = setTimeout(() => {
|
|
154
|
+
this.pendingCalls.delete(correlationId);
|
|
155
|
+
this.logger.error('RPC timeout', {
|
|
156
|
+
processInstanceId: this.processInstanceId,
|
|
157
|
+
commandName,
|
|
160
158
|
correlationId,
|
|
161
|
-
|
|
159
|
+
responseChannel,
|
|
160
|
+
timeout: `${timeout}ms`,
|
|
161
|
+
pendingCallsCount: this.pendingCalls.size,
|
|
162
162
|
timestamp: new Date().toISOString(),
|
|
163
163
|
});
|
|
164
|
+
reject(new Error(`RPC timeout for command ${commandName}`));
|
|
165
|
+
}, timeout);
|
|
166
|
+
// Zapisz pending call w Map
|
|
167
|
+
this.pendingCalls.set(correlationId, {
|
|
168
|
+
resolve: resolve,
|
|
169
|
+
reject,
|
|
170
|
+
timeoutId,
|
|
171
|
+
commandName,
|
|
172
|
+
startTime,
|
|
164
173
|
});
|
|
165
|
-
|
|
174
|
+
this.logger.debug('Pending RPC call zarejestrowany', {
|
|
175
|
+
processInstanceId: this.processInstanceId,
|
|
176
|
+
correlationId,
|
|
177
|
+
responseChannel,
|
|
178
|
+
pendingCallsCount: this.pendingCalls.size,
|
|
179
|
+
timestamp: new Date().toISOString(),
|
|
180
|
+
});
|
|
181
|
+
});
|
|
166
182
|
});
|
|
167
183
|
}
|
|
168
184
|
/**
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
* Fail-safe - nie rzuca błędów, tylko loguje
|
|
185
|
+
* Obsługuje wiadomość RPC z Redis Pub/Sub (pmessage handler)
|
|
186
|
+
* Ekstraktuje correlationId, znajduje pending call, dekompresuje i resolve/reject
|
|
172
187
|
*
|
|
173
|
-
* @param
|
|
174
|
-
* @param
|
|
175
|
-
* @param correlationId - ID wywołania (dla logowania)
|
|
188
|
+
* @param channel - Pełna nazwa kanału: rpc:response:{processId}:{correlationId}
|
|
189
|
+
* @param message - Skompresowana odpowiedź RPC (JSON)
|
|
176
190
|
*/
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
191
|
+
handleRpcMessage(channel, message) {
|
|
192
|
+
// Ekstraktuj correlationId z channel: rpc:response:{processId}:{correlationId}
|
|
193
|
+
const parts = channel.split(':');
|
|
194
|
+
if (parts.length !== 4 || parts[0] !== 'rpc' || parts[1] !== 'response') {
|
|
195
|
+
this.logger.warn('Nieprawidłowy format kanału RPC', {
|
|
196
|
+
processInstanceId: this.processInstanceId,
|
|
197
|
+
channel,
|
|
198
|
+
timestamp: new Date().toISOString(),
|
|
199
|
+
});
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
const receivedProcessId = parts[2];
|
|
203
|
+
const correlationId = parts[3];
|
|
204
|
+
// Weryfikacja processInstanceId (dodatkowe bezpieczeństwo)
|
|
205
|
+
if (receivedProcessId !== this.processInstanceId) {
|
|
206
|
+
this.logger.warn('Otrzymano wiadomość dla innego procesu', {
|
|
207
|
+
processInstanceId: this.processInstanceId,
|
|
208
|
+
receivedProcessId,
|
|
180
209
|
correlationId,
|
|
181
|
-
|
|
210
|
+
channel,
|
|
182
211
|
timestamp: new Date().toISOString(),
|
|
183
212
|
});
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
this.
|
|
191
|
-
|
|
192
|
-
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
// Znajdź pending call w Map
|
|
216
|
+
const pendingCall = this.pendingCalls.get(correlationId);
|
|
217
|
+
if (!pendingCall) {
|
|
218
|
+
this.logger.warn('Otrzymano odpowiedź dla nieistniejącego RPC call', {
|
|
219
|
+
processInstanceId: this.processInstanceId,
|
|
220
|
+
correlationId,
|
|
221
|
+
channel,
|
|
222
|
+
pendingCallsCount: this.pendingCalls.size,
|
|
223
|
+
timestamp: new Date().toISOString(),
|
|
224
|
+
});
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
// Dekompresuj i parsuj odpowiedź (async)
|
|
228
|
+
// Message zawiera wrapper: {data: string, compressed: boolean}
|
|
229
|
+
let wrapper;
|
|
230
|
+
try {
|
|
231
|
+
wrapper = JSON.parse(message);
|
|
232
|
+
}
|
|
233
|
+
catch (parseError) {
|
|
234
|
+
this.logger.error('Błąd parsowania wrapper odpowiedzi RPC', {
|
|
235
|
+
processInstanceId: this.processInstanceId,
|
|
236
|
+
correlationId,
|
|
237
|
+
commandName: pendingCall.commandName,
|
|
238
|
+
error: parseError instanceof Error ? parseError.message : String(parseError),
|
|
239
|
+
timestamp: new Date().toISOString(),
|
|
240
|
+
});
|
|
241
|
+
clearTimeout(pendingCall.timeoutId);
|
|
242
|
+
this.pendingCalls.delete(correlationId);
|
|
243
|
+
pendingCall.reject(new Error('Failed to parse RPC response wrapper'));
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
this.compressionService
|
|
247
|
+
.decompress(wrapper.data, wrapper.compressed)
|
|
248
|
+
.then((decompressed) => {
|
|
249
|
+
const { correlationId: responseCorrelationId, result, error, } = decompressed;
|
|
250
|
+
const duration = Date.now() - pendingCall.startTime;
|
|
251
|
+
this.logger.debug('Otrzymano odpowiedź RPC przez shared subscriber', {
|
|
252
|
+
processInstanceId: this.processInstanceId,
|
|
253
|
+
correlationId: responseCorrelationId,
|
|
254
|
+
commandName: pendingCall.commandName,
|
|
255
|
+
duration: `${duration}ms`,
|
|
256
|
+
hasResult: result !== undefined,
|
|
257
|
+
hasError: error !== undefined,
|
|
258
|
+
pendingCallsCount: this.pendingCalls.size - 1,
|
|
259
|
+
timestamp: new Date().toISOString(),
|
|
260
|
+
});
|
|
261
|
+
// Cleanup
|
|
262
|
+
clearTimeout(pendingCall.timeoutId);
|
|
263
|
+
this.pendingCalls.delete(correlationId);
|
|
264
|
+
// Resolve/reject promise
|
|
265
|
+
if (error) {
|
|
266
|
+
this.logger.error('Wywołanie RPC odrzucone', {
|
|
267
|
+
processInstanceId: this.processInstanceId,
|
|
268
|
+
correlationId: responseCorrelationId,
|
|
269
|
+
commandName: pendingCall.commandName,
|
|
270
|
+
error,
|
|
193
271
|
timestamp: new Date().toISOString(),
|
|
194
272
|
});
|
|
273
|
+
pendingCall.reject(new Error(error));
|
|
195
274
|
}
|
|
196
|
-
|
|
197
|
-
this.logger.
|
|
275
|
+
else {
|
|
276
|
+
this.logger.debug('Wywołanie RPC rozwiązane', {
|
|
277
|
+
processInstanceId: this.processInstanceId,
|
|
278
|
+
correlationId: responseCorrelationId,
|
|
279
|
+
commandName: pendingCall.commandName,
|
|
280
|
+
duration: `${duration}ms`,
|
|
281
|
+
timestamp: new Date().toISOString(),
|
|
282
|
+
});
|
|
283
|
+
pendingCall.resolve(result);
|
|
284
|
+
}
|
|
285
|
+
})
|
|
286
|
+
.catch((decompressError) => {
|
|
287
|
+
this.logger.error('Błąd dekompresji/parsowania odpowiedzi RPC', {
|
|
288
|
+
processInstanceId: this.processInstanceId,
|
|
289
|
+
correlationId,
|
|
290
|
+
commandName: pendingCall.commandName,
|
|
291
|
+
error: decompressError instanceof Error ? decompressError.message : String(decompressError),
|
|
292
|
+
timestamp: new Date().toISOString(),
|
|
293
|
+
});
|
|
294
|
+
// Cleanup
|
|
295
|
+
clearTimeout(pendingCall.timeoutId);
|
|
296
|
+
this.pendingCalls.delete(correlationId);
|
|
297
|
+
pendingCall.reject(new Error('Failed to decompress/parse RPC response'));
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Zamyka RpcCoordinator i czyści zasoby
|
|
302
|
+
* Reject wszystkie pending calls i zamknij shared subscriber
|
|
303
|
+
*/
|
|
304
|
+
close() {
|
|
305
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
306
|
+
this.logger.debug('Zamykanie RpcCoordinator', {
|
|
307
|
+
processInstanceId: this.processInstanceId,
|
|
308
|
+
pendingCallsCount: this.pendingCalls.size,
|
|
309
|
+
timestamp: new Date().toISOString(),
|
|
310
|
+
});
|
|
311
|
+
// Reject wszystkie pending calls
|
|
312
|
+
for (const [correlationId, pendingCall] of this.pendingCalls.entries()) {
|
|
313
|
+
clearTimeout(pendingCall.timeoutId);
|
|
314
|
+
pendingCall.reject(new Error('RpcCoordinator is closing'));
|
|
315
|
+
this.logger.debug('Odrzucono pending RPC call przy zamykaniu', {
|
|
316
|
+
processInstanceId: this.processInstanceId,
|
|
198
317
|
correlationId,
|
|
199
|
-
|
|
200
|
-
error: error instanceof Error ? error.message : String(error),
|
|
318
|
+
commandName: pendingCall.commandName,
|
|
201
319
|
timestamp: new Date().toISOString(),
|
|
202
320
|
});
|
|
203
321
|
}
|
|
204
|
-
|
|
205
|
-
subscriber
|
|
206
|
-
subscriber.removeAllListeners('error');
|
|
207
|
-
// Zamknij dedykowany subscriber
|
|
322
|
+
this.pendingCalls.clear();
|
|
323
|
+
// Zamknij shared subscriber
|
|
208
324
|
try {
|
|
209
|
-
|
|
210
|
-
this.
|
|
211
|
-
|
|
325
|
+
const pattern = `rpc:response:${this.processInstanceId}:*`;
|
|
326
|
+
yield this.sharedSubscriber.punsubscribe(pattern);
|
|
327
|
+
this.sharedSubscriber.removeAllListeners('pmessage');
|
|
328
|
+
this.sharedSubscriber.removeAllListeners('psubscribe');
|
|
329
|
+
this.sharedSubscriber.removeAllListeners('error');
|
|
330
|
+
yield this.sharedSubscriber.quit();
|
|
331
|
+
this.logger.debug('Shared subscriber zamknięty', {
|
|
332
|
+
processInstanceId: this.processInstanceId,
|
|
212
333
|
timestamp: new Date().toISOString(),
|
|
213
334
|
});
|
|
214
335
|
}
|
|
215
336
|
catch (error) {
|
|
216
|
-
this.logger.warn('Błąd podczas zamykania subscriber', {
|
|
217
|
-
|
|
337
|
+
this.logger.warn('Błąd podczas zamykania shared subscriber', {
|
|
338
|
+
processInstanceId: this.processInstanceId,
|
|
218
339
|
error: error instanceof Error ? error.message : String(error),
|
|
219
340
|
timestamp: new Date().toISOString(),
|
|
220
341
|
});
|
|
221
342
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
* Wywołane przy zamykaniu CommandBus
|
|
227
|
-
*
|
|
228
|
-
* Uwaga: Dedykowane subscribers są automatycznie zamykane w finally block registerCall()
|
|
229
|
-
* Ta metoda nie musi już zamykać puli subscribers (pool został usunięty)
|
|
230
|
-
*/
|
|
231
|
-
close() {
|
|
232
|
-
this.logger.debug('Zamykanie RpcCoordinator', {
|
|
233
|
-
timestamp: new Date().toISOString(),
|
|
234
|
-
});
|
|
235
|
-
// Brak zasobów do wyczyszczenia - subscribers są zamykane per-call
|
|
236
|
-
// Główne połączenie Redis (redisConnection) jest zarządzane przez CommandBus
|
|
237
|
-
this.logger.debug('RpcCoordinator zamknięty', {
|
|
238
|
-
timestamp: new Date().toISOString(),
|
|
343
|
+
this.logger.debug('RpcCoordinator zamknięty', {
|
|
344
|
+
processInstanceId: this.processInstanceId,
|
|
345
|
+
timestamp: new Date().toISOString(),
|
|
346
|
+
});
|
|
239
347
|
});
|
|
240
348
|
}
|
|
241
349
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpc-coordinator.js","sourceRoot":"","sources":["../../../src/command-bus/rpc/rpc-coordinator.ts"],"names":[],"mappings":";;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"rpc-coordinator.js","sourceRoot":"","sources":["../../../src/command-bus/rpc/rpc-coordinator.ts"],"names":[],"mappings":";;;;;;;;;;;AAAA,mCAAoC;AAOpC;;;GAGG;AACH,MAAM,mBAAmB,GAAG,IAAA,mBAAU,GAAE,CAAC;AAEzC;;;;;;;;;;GAUG;AACH,MAAqB,cAAc;IA0BjC,YACmB,MAAe,EACf,eAAsB,EACtB,kBAA6C;QAF7C,WAAM,GAAN,MAAM,CAAS;QACf,oBAAe,GAAf,eAAe,CAAO;QACtB,uBAAkB,GAAlB,kBAAkB,CAA2B;QA5BhE;;WAEG;QACc,sBAAiB,GAAW,mBAAmB,CAAC;QAOjE;;WAEG;QACK,iBAAY,GAAgC,IAAI,GAAG,EAAE,CAAC;QAE9D;;WAEG;QACK,sBAAiB,GAAY,KAAK,CAAC;QAYzC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,8BAA8B,EAAE;YAChD,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;YACzC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC,CAAC;QAEH,6CAA6C;QAC7C,IAAI,CAAC,qBAAqB,EAAE,CAAC;IAC/B,CAAC;IAED;;;;OAIG;IACK,qBAAqB;QAC3B,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,eAAe,CAAC,SAAS,EAAE,CAAC;QAEzD,kEAAkE;QAClE,MAAM,OAAO,GAAG,gBAAgB,IAAI,CAAC,iBAAiB,IAAI,CAAC;QAE3D,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,qCAAqC,EAAE;YACvD,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;YACzC,OAAO;YACP,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC,CAAC;QAEH,wCAAwC;QACxC,IAAI,CAAC,sBAAsB,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YAC1D,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,gBAAwB,EAAE,KAAa,EAAE,EAAE;gBACnF,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,EAAE;oBAC5C,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;oBACzC,OAAO,EAAE,gBAAgB;oBACzB,iBAAiB,EAAE,KAAK;oBACxB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;iBACpC,CAAC,CAAC;gBACH,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC;gBAC9B,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,6DAA6D;QAC7D,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC,QAAgB,EAAE,OAAe,EAAE,OAAe,EAAE,EAAE;YAC1F,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC1C,CAAC,CAAC,CAAC;QAEH,kCAAkC;QAClC,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAY,EAAE,EAAE;YACjD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,4BAA4B,EAAE;gBAC9C,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;gBACzC,KAAK,EAAE,KAAK,CAAC,OAAO;gBACpB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,yCAAyC;QACzC,KAAK,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAE/C,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,gCAAgC,EAAE;YAClD,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;YACzC,OAAO;YACP,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC,CAAC;IACL,CAAC;IAED;;;;;OAKG;IACI,iBAAiB,CACtB,OAAU,EACV,eAAuB;QAEvB,uCACK,OAAO,KACV,aAAa,EAAE;gBACb,aAAa,EAAE,OAAO,CAAC,IAAI;gBAC3B,eAAe;gBACf,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;gBACrB,UAAU,EAAE,IAAI,EAAE,mDAAmD;aACtE,IACD;IACJ,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACU,YAAY,CACvB,aAAqB,EACrB,WAAmB,EACnB,OAAe;;YAEf,MAAM,eAAe,GAAG,gBAAgB,IAAI,CAAC,iBAAiB,IAAI,aAAa,EAAE,CAAC;YAElF,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,qDAAqD,EAAE;gBACvE,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;gBACzC,aAAa;gBACb,eAAe;gBACf,WAAW;gBACX,OAAO,EAAE,GAAG,OAAO,IAAI;gBACvB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC,CAAC;YAEH,iEAAiE;YACjE,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,CAAC;gBAC5B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,2CAA2C,EAAE;oBAC7D,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;oBACzC,aAAa;oBACb,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;iBACpC,CAAC,CAAC;gBACH,MAAM,IAAI,CAAC,sBAAsB,CAAC;YACpC,CAAC;YAED,0CAA0C;YAC1C,OAAO,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBACxC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBAE7B,kBAAkB;gBAClB,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;oBAChC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;oBACxC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,EAAE;wBAC/B,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;wBACzC,WAAW;wBACX,aAAa;wBACb,eAAe;wBACf,OAAO,EAAE,GAAG,OAAO,IAAI;wBACvB,iBAAiB,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI;wBACzC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;qBACpC,CAAC,CAAC;oBACH,MAAM,CAAC,IAAI,KAAK,CAAC,2BAA2B,WAAW,EAAE,CAAC,CAAC,CAAC;gBAC9D,CAAC,EAAE,OAAO,CAAC,CAAC;gBAEZ,4BAA4B;gBAC5B,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,aAAa,EAAE;oBACnC,OAAO,EAAE,OAAmC;oBAC5C,MAAM;oBACN,SAAS;oBACT,WAAW;oBACX,SAAS;iBACV,CAAC,CAAC;gBAEH,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,iCAAiC,EAAE;oBACnD,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;oBACzC,aAAa;oBACb,eAAe;oBACf,iBAAiB,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI;oBACzC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;iBACpC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC;KAAA;IAED;;;;;;OAMG;IACK,gBAAgB,CAAC,OAAe,EAAE,OAAe;QACvD,+EAA+E;QAC/E,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,UAAU,EAAE,CAAC;YACxE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,iCAAiC,EAAE;gBAClD,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;gBACzC,OAAO;gBACP,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,MAAM,iBAAiB,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,aAAa,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAE/B,2DAA2D;QAC3D,IAAI,iBAAiB,KAAK,IAAI,CAAC,iBAAiB,EAAE,CAAC;YACjD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,wCAAwC,EAAE;gBACzD,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;gBACzC,iBAAiB;gBACjB,aAAa;gBACb,OAAO;gBACP,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,4BAA4B;QAC5B,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QACzD,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,kDAAkD,EAAE;gBACnE,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;gBACzC,aAAa;gBACb,OAAO;gBACP,iBAAiB,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI;gBACzC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,yCAAyC;QACzC,+DAA+D;QAC/D,IAAI,OAA8C,CAAC;QACnD,IAAI,CAAC;YACH,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAChC,CAAC;QAAC,OAAO,UAAU,EAAE,CAAC;YACpB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,wCAAwC,EAAE;gBAC1D,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;gBACzC,aAAa;gBACb,WAAW,EAAE,WAAW,CAAC,WAAW;gBACpC,KAAK,EAAE,UAAU,YAAY,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC;gBAC5E,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC,CAAC;YACH,YAAY,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;YACpC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;YACxC,WAAW,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC,CAAC;YACtE,OAAO;QACT,CAAC;QAED,IAAI,CAAC,kBAAkB;aACpB,UAAU,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC;aAC5C,IAAI,CAAC,CAAC,YAAqB,EAAE,EAAE;YAC9B,MAAM,EACJ,aAAa,EAAE,qBAAqB,EACpC,MAAM,EACN,KAAK,GACN,GAAG,YAIH,CAAC;YAEF,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,WAAW,CAAC,SAAS,CAAC;YAEpD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,iDAAiD,EAAE;gBACnE,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;gBACzC,aAAa,EAAE,qBAAqB;gBACpC,WAAW,EAAE,WAAW,CAAC,WAAW;gBACpC,QAAQ,EAAE,GAAG,QAAQ,IAAI;gBACzB,SAAS,EAAE,MAAM,KAAK,SAAS;gBAC/B,QAAQ,EAAE,KAAK,KAAK,SAAS;gBAC7B,iBAAiB,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC;gBAC7C,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC,CAAC;YAEH,UAAU;YACV,YAAY,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;YACpC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;YAExC,yBAAyB;YACzB,IAAI,KAAK,EAAE,CAAC;gBACV,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,yBAAyB,EAAE;oBAC3C,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;oBACzC,aAAa,EAAE,qBAAqB;oBACpC,WAAW,EAAE,WAAW,CAAC,WAAW;oBACpC,KAAK;oBACL,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;iBACpC,CAAC,CAAC;gBACH,WAAW,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;YACvC,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,EAAE;oBAC5C,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;oBACzC,aAAa,EAAE,qBAAqB;oBACpC,WAAW,EAAE,WAAW,CAAC,WAAW;oBACpC,QAAQ,EAAE,GAAG,QAAQ,IAAI;oBACzB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;iBACpC,CAAC,CAAC;gBACH,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAC9B,CAAC;QACH,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,eAAe,EAAE,EAAE;YACzB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,4CAA4C,EAAE;gBAC9D,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;gBACzC,aAAa;gBACb,WAAW,EAAE,WAAW,CAAC,WAAW;gBACpC,KAAK,EACH,eAAe,YAAY,KAAK,CAAC,CAAC,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC;gBACtF,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC,CAAC;YAEH,UAAU;YACV,YAAY,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;YACpC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;YAExC,WAAW,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC,CAAC;QAC3E,CAAC,CAAC,CAAC;IACP,CAAC;IAED;;;OAGG;IACU,KAAK;;YAChB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,EAAE;gBAC5C,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;gBACzC,iBAAiB,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI;gBACzC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC,CAAC;YAEH,iCAAiC;YACjC,KAAK,MAAM,CAAC,aAAa,EAAE,WAAW,CAAC,IAAI,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,EAAE,CAAC;gBACvE,YAAY,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;gBACpC,WAAW,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC,CAAC;gBAE3D,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,2CAA2C,EAAE;oBAC7D,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;oBACzC,aAAa;oBACb,WAAW,EAAE,WAAW,CAAC,WAAW;oBACpC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;iBACpC,CAAC,CAAC;YACL,CAAC;YAED,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;YAE1B,4BAA4B;YAC5B,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,gBAAgB,IAAI,CAAC,iBAAiB,IAAI,CAAC;gBAC3D,MAAM,IAAI,CAAC,gBAAgB,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;gBAElD,IAAI,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,UAAU,CAAC,CAAC;gBACrD,IAAI,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC;gBACvD,IAAI,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;gBAElD,MAAM,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,CAAC;gBAEnC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,6BAA6B,EAAE;oBAC/C,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;oBACzC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;iBACpC,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,0CAA0C,EAAE;oBAC3D,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;oBACzC,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;oBAC7D,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;iBACpC,CAAC,CAAC;YACL,CAAC;YAED,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,EAAE;gBAC5C,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;gBACzC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC,CAAC;QACL,CAAC;KAAA;CACF;AAhYD,iCAgYC"}
|