@naman_deep_singh/communication-core 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 +345 -0
- package/dist/cjs/abstract/BaseCircuitBreaker.js +253 -0
- package/dist/cjs/abstract/BaseClient.js +298 -0
- package/dist/cjs/abstract/BaseCompressionManager.js +377 -0
- package/dist/cjs/abstract/BaseConnectionPool.js +543 -0
- package/dist/cjs/abstract/BaseInterceptor.js +235 -0
- package/dist/cjs/abstract/BaseLoadBalancer.js +269 -0
- package/dist/cjs/abstract/BaseProtocol.js +269 -0
- package/dist/cjs/abstract/BaseRetryStrategy.js +255 -0
- package/dist/cjs/abstract/BaseSerializer.js +341 -0
- package/dist/cjs/abstract/BaseServiceDiscoverer.js +254 -0
- package/dist/cjs/abstract/BaseTimeoutManager.js +295 -0
- package/dist/cjs/abstract/index.js +25 -0
- package/dist/cjs/errors/CircuitBreakerError.js +16 -0
- package/dist/cjs/errors/CommunicationError.js +15 -0
- package/dist/cjs/errors/ConnectionError.js +15 -0
- package/dist/cjs/errors/DiscoveryError.js +15 -0
- package/dist/cjs/errors/LoadBalancerError.js +15 -0
- package/dist/cjs/errors/ProtocolError.js +15 -0
- package/dist/cjs/errors/RetryError.js +16 -0
- package/dist/cjs/errors/SerializationError.js +15 -0
- package/dist/cjs/errors/ServiceUnavailableError.js +15 -0
- package/dist/cjs/errors/TimeoutError.js +16 -0
- package/dist/cjs/errors/communicationErrorCodes.js +35 -0
- package/dist/cjs/errors/index.js +31 -0
- package/dist/cjs/index.js +38 -0
- package/dist/cjs/interfaces/CircuitBreaker.interface.js +6 -0
- package/dist/cjs/interfaces/Client.interface.js +6 -0
- package/dist/cjs/interfaces/Compression.interface.js +6 -0
- package/dist/cjs/interfaces/ConnectionPool.interface.js +6 -0
- package/dist/cjs/interfaces/Interceptor.interface.js +6 -0
- package/dist/cjs/interfaces/LoadBalancer.interface.js +2 -0
- package/dist/cjs/interfaces/Protocol.interface.js +6 -0
- package/dist/cjs/interfaces/RetryStrategy.interface.js +6 -0
- package/dist/cjs/interfaces/Serializer.interface.js +2 -0
- package/dist/cjs/interfaces/ServiceDiscovery.interface.js +6 -0
- package/dist/cjs/interfaces/Timeout.interface.js +6 -0
- package/dist/cjs/interfaces/index.js +6 -0
- package/dist/cjs/types/config.js +6 -0
- package/dist/cjs/types/events.js +6 -0
- package/dist/cjs/types/index.js +6 -0
- package/dist/cjs/types/request.js +6 -0
- package/dist/cjs/types/response.js +6 -0
- package/dist/cjs/types/service.js +6 -0
- package/dist/cjs/utils.js +200 -0
- package/dist/esm/abstract/BaseCircuitBreaker.js +249 -0
- package/dist/esm/abstract/BaseClient.js +294 -0
- package/dist/esm/abstract/BaseCompressionManager.js +373 -0
- package/dist/esm/abstract/BaseConnectionPool.js +539 -0
- package/dist/esm/abstract/BaseInterceptor.js +231 -0
- package/dist/esm/abstract/BaseLoadBalancer.js +265 -0
- package/dist/esm/abstract/BaseProtocol.js +265 -0
- package/dist/esm/abstract/BaseRetryStrategy.js +251 -0
- package/dist/esm/abstract/BaseSerializer.js +337 -0
- package/dist/esm/abstract/BaseServiceDiscoverer.js +250 -0
- package/dist/esm/abstract/BaseTimeoutManager.js +291 -0
- package/dist/esm/abstract/index.js +11 -0
- package/dist/esm/errors/CircuitBreakerError.js +12 -0
- package/dist/esm/errors/CommunicationError.js +11 -0
- package/dist/esm/errors/ConnectionError.js +11 -0
- package/dist/esm/errors/DiscoveryError.js +11 -0
- package/dist/esm/errors/LoadBalancerError.js +11 -0
- package/dist/esm/errors/ProtocolError.js +11 -0
- package/dist/esm/errors/RetryError.js +12 -0
- package/dist/esm/errors/SerializationError.js +11 -0
- package/dist/esm/errors/ServiceUnavailableError.js +11 -0
- package/dist/esm/errors/TimeoutError.js +12 -0
- package/dist/esm/errors/communicationErrorCodes.js +32 -0
- package/dist/esm/errors/index.js +17 -0
- package/dist/esm/index.js +18 -0
- package/dist/esm/interfaces/CircuitBreaker.interface.js +5 -0
- package/dist/esm/interfaces/Client.interface.js +5 -0
- package/dist/esm/interfaces/Compression.interface.js +5 -0
- package/dist/esm/interfaces/ConnectionPool.interface.js +5 -0
- package/dist/esm/interfaces/Interceptor.interface.js +5 -0
- package/dist/esm/interfaces/LoadBalancer.interface.js +1 -0
- package/dist/esm/interfaces/Protocol.interface.js +5 -0
- package/dist/esm/interfaces/RetryStrategy.interface.js +5 -0
- package/dist/esm/interfaces/Serializer.interface.js +1 -0
- package/dist/esm/interfaces/ServiceDiscovery.interface.js +5 -0
- package/dist/esm/interfaces/Timeout.interface.js +5 -0
- package/dist/esm/interfaces/index.js +5 -0
- package/dist/esm/types/config.js +5 -0
- package/dist/esm/types/events.js +5 -0
- package/dist/esm/types/index.js +5 -0
- package/dist/esm/types/request.js +5 -0
- package/dist/esm/types/response.js +5 -0
- package/dist/esm/types/service.js +5 -0
- package/dist/esm/utils.js +193 -0
- package/dist/types/abstract/BaseCircuitBreaker.d.ts +167 -0
- package/dist/types/abstract/BaseClient.d.ts +197 -0
- package/dist/types/abstract/BaseCompressionManager.d.ts +180 -0
- package/dist/types/abstract/BaseConnectionPool.d.ts +210 -0
- package/dist/types/abstract/BaseInterceptor.d.ts +150 -0
- package/dist/types/abstract/BaseLoadBalancer.d.ts +167 -0
- package/dist/types/abstract/BaseProtocol.d.ts +163 -0
- package/dist/types/abstract/BaseRetryStrategy.d.ts +130 -0
- package/dist/types/abstract/BaseSerializer.d.ts +181 -0
- package/dist/types/abstract/BaseServiceDiscoverer.d.ts +161 -0
- package/dist/types/abstract/BaseTimeoutManager.d.ts +145 -0
- package/dist/types/abstract/index.d.ts +11 -0
- package/dist/types/errors/CircuitBreakerError.d.ts +8 -0
- package/dist/types/errors/CommunicationError.d.ts +10 -0
- package/dist/types/errors/ConnectionError.d.ts +9 -0
- package/dist/types/errors/DiscoveryError.d.ts +9 -0
- package/dist/types/errors/LoadBalancerError.d.ts +9 -0
- package/dist/types/errors/ProtocolError.d.ts +9 -0
- package/dist/types/errors/RetryError.d.ts +11 -0
- package/dist/types/errors/SerializationError.d.ts +9 -0
- package/dist/types/errors/ServiceUnavailableError.d.ts +12 -0
- package/dist/types/errors/TimeoutError.d.ts +11 -0
- package/dist/types/errors/communicationErrorCodes.d.ts +27 -0
- package/dist/types/errors/index.d.ts +11 -0
- package/dist/types/index.d.ts +13 -0
- package/dist/types/interfaces/CircuitBreaker.interface.d.ts +150 -0
- package/dist/types/interfaces/Client.interface.d.ts +153 -0
- package/dist/types/interfaces/Compression.interface.d.ts +190 -0
- package/dist/types/interfaces/ConnectionPool.interface.d.ts +191 -0
- package/dist/types/interfaces/Interceptor.interface.d.ts +220 -0
- package/dist/types/interfaces/LoadBalancer.interface.d.ts +153 -0
- package/dist/types/interfaces/Protocol.interface.d.ts +117 -0
- package/dist/types/interfaces/RetryStrategy.interface.d.ts +160 -0
- package/dist/types/interfaces/Serializer.interface.d.ts +176 -0
- package/dist/types/interfaces/ServiceDiscovery.interface.d.ts +189 -0
- package/dist/types/interfaces/Timeout.interface.d.ts +135 -0
- package/dist/types/interfaces/index.d.ts +15 -0
- package/dist/types/types/config.d.ts +540 -0
- package/dist/types/types/events.d.ts +204 -0
- package/dist/types/types/index.d.ts +9 -0
- package/dist/types/types/request.d.ts +143 -0
- package/dist/types/types/response.d.ts +155 -0
- package/dist/types/types/service.d.ts +279 -0
- package/dist/types/utils.d.ts +179 -0
- package/package.json +88 -0
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Abstract base serializer implementation
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
*/
|
|
5
|
+
import { CommunicationError } from '../errors/CommunicationError.js';
|
|
6
|
+
import { COMMUNICATION_ERROR_CODES } from '../errors/communicationErrorCodes.js';
|
|
7
|
+
/**
|
|
8
|
+
* Abstract base serializer implementation
|
|
9
|
+
* Provides common functionality for all serializer implementations
|
|
10
|
+
*/
|
|
11
|
+
export class BaseSerializer {
|
|
12
|
+
/**
|
|
13
|
+
* Create a new base serializer instance
|
|
14
|
+
* @param name Serializer name
|
|
15
|
+
* @param config Serializer configuration
|
|
16
|
+
*/
|
|
17
|
+
constructor(name, config) {
|
|
18
|
+
/** Format handlers registry */
|
|
19
|
+
this.formatHandlers = new Map();
|
|
20
|
+
/** Serializer statistics */
|
|
21
|
+
this.stats = {
|
|
22
|
+
totalSerializations: 0,
|
|
23
|
+
totalDeserializations: 0,
|
|
24
|
+
serializationErrors: 0,
|
|
25
|
+
deserializationErrors: 0,
|
|
26
|
+
averageSerializationTime: 0,
|
|
27
|
+
averageDeserializationTime: 0,
|
|
28
|
+
formatUsage: {},
|
|
29
|
+
};
|
|
30
|
+
this.name = name;
|
|
31
|
+
this.config = { ...config };
|
|
32
|
+
this.supportedFormats = this.initializeSupportedFormats();
|
|
33
|
+
this.defaultFormat = this.supportedFormats[0] || 'json';
|
|
34
|
+
this.initialize();
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Initialize serializer
|
|
38
|
+
*/
|
|
39
|
+
initialize() {
|
|
40
|
+
// Register default format handlers
|
|
41
|
+
this.registerDefaultHandlers();
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Perform serialization with timing and error handling
|
|
45
|
+
* @param data Data to serialize
|
|
46
|
+
* @param context Serialization context
|
|
47
|
+
* @param handler Serialization handler
|
|
48
|
+
* @returns Serialized data
|
|
49
|
+
*/
|
|
50
|
+
performSerialization(data, context, handler) {
|
|
51
|
+
const startTime = Date.now();
|
|
52
|
+
const format = context.format;
|
|
53
|
+
try {
|
|
54
|
+
// Transform data if needed
|
|
55
|
+
const transformedData = this.transformData(data, 'serialize');
|
|
56
|
+
// Perform serialization
|
|
57
|
+
const result = handler(transformedData, context);
|
|
58
|
+
// Update statistics
|
|
59
|
+
this.updateSerializationStats(true, Date.now() - startTime, format);
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
// Update error statistics
|
|
64
|
+
this.updateSerializationStats(false, Date.now() - startTime, format);
|
|
65
|
+
throw new CommunicationError(COMMUNICATION_ERROR_CODES.SERIALIZATION_ERROR, 500, {
|
|
66
|
+
message: `Serialization failed for format: ${format}`,
|
|
67
|
+
format,
|
|
68
|
+
originalError: error instanceof Error ? error.message : String(error),
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Perform deserialization with timing and error handling
|
|
74
|
+
* @param data Data to deserialize
|
|
75
|
+
* @param context Deserialization context
|
|
76
|
+
* @param handler Deserialization handler
|
|
77
|
+
* @returns Deserialized data
|
|
78
|
+
*/
|
|
79
|
+
performDeserialization(data, context, handler) {
|
|
80
|
+
const startTime = Date.now();
|
|
81
|
+
const format = context.format;
|
|
82
|
+
try {
|
|
83
|
+
// Perform deserialization
|
|
84
|
+
const result = handler(data, context);
|
|
85
|
+
// Transform data if needed
|
|
86
|
+
const transformedResult = this.transformData(result, 'deserialize');
|
|
87
|
+
// Update statistics
|
|
88
|
+
this.updateDeserializationStats(true, Date.now() - startTime, format);
|
|
89
|
+
return transformedResult;
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
// Update error statistics
|
|
93
|
+
this.updateDeserializationStats(false, Date.now() - startTime, format);
|
|
94
|
+
throw new CommunicationError(COMMUNICATION_ERROR_CODES.DESERIALIZATION_ERROR, 500, {
|
|
95
|
+
message: `Deserialization failed for format: ${format}`,
|
|
96
|
+
format,
|
|
97
|
+
originalError: error instanceof Error ? error.message : String(error),
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Transform data (e.g., date parsing, bigint handling)
|
|
103
|
+
* @param data Data to transform
|
|
104
|
+
* @param direction 'serialize' or 'deserialize'
|
|
105
|
+
*/
|
|
106
|
+
transformData(data, direction) {
|
|
107
|
+
if (data === null || data === undefined) {
|
|
108
|
+
return data;
|
|
109
|
+
}
|
|
110
|
+
// Handle dates based on configuration
|
|
111
|
+
if (this.config.dateParsing) {
|
|
112
|
+
data = this.transformDates(data, direction);
|
|
113
|
+
}
|
|
114
|
+
// Handle bigints based on configuration
|
|
115
|
+
if (this.config.bigIntParsing) {
|
|
116
|
+
data = this.transformBigInts(data, direction);
|
|
117
|
+
}
|
|
118
|
+
// Apply custom transformations
|
|
119
|
+
data = this.applyCustomTransformations(data, direction);
|
|
120
|
+
return data;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Transform dates based on configuration
|
|
124
|
+
* @param data Data containing dates
|
|
125
|
+
* @param direction Transformation direction
|
|
126
|
+
*/
|
|
127
|
+
transformDates(data, direction) {
|
|
128
|
+
if (data instanceof Date) {
|
|
129
|
+
switch (this.config.dateParsing) {
|
|
130
|
+
case 'string':
|
|
131
|
+
return direction === 'serialize' ? data.toISOString() : data;
|
|
132
|
+
case 'timestamp':
|
|
133
|
+
return direction === 'serialize' ? data.getTime() : data;
|
|
134
|
+
default:
|
|
135
|
+
return data;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (Array.isArray(data)) {
|
|
139
|
+
return data.map(item => this.transformDates(item, direction));
|
|
140
|
+
}
|
|
141
|
+
if (typeof data === 'object' && data !== null) {
|
|
142
|
+
const transformed = {};
|
|
143
|
+
for (const [key, value] of Object.entries(data)) {
|
|
144
|
+
transformed[key] = this.transformDates(value, direction);
|
|
145
|
+
}
|
|
146
|
+
return transformed;
|
|
147
|
+
}
|
|
148
|
+
return data;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Transform bigints based on configuration
|
|
152
|
+
* @param data Data containing bigints
|
|
153
|
+
* @param direction Transformation direction
|
|
154
|
+
*/
|
|
155
|
+
transformBigInts(data, direction) {
|
|
156
|
+
if (typeof data === 'bigint') {
|
|
157
|
+
switch (this.config.bigIntParsing) {
|
|
158
|
+
case 'string':
|
|
159
|
+
return direction === 'serialize' ? data.toString() : data;
|
|
160
|
+
case 'number':
|
|
161
|
+
return direction === 'serialize' ? Number(data) : BigInt(data);
|
|
162
|
+
default:
|
|
163
|
+
return data;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (Array.isArray(data)) {
|
|
167
|
+
return data.map(item => this.transformBigInts(item, direction));
|
|
168
|
+
}
|
|
169
|
+
if (typeof data === 'object' && data !== null) {
|
|
170
|
+
const transformed = {};
|
|
171
|
+
for (const [key, value] of Object.entries(data)) {
|
|
172
|
+
transformed[key] = this.transformBigInts(value, direction);
|
|
173
|
+
}
|
|
174
|
+
return transformed;
|
|
175
|
+
}
|
|
176
|
+
return data;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Apply custom transformations
|
|
180
|
+
* @param data Data to transform
|
|
181
|
+
* @param direction Transformation direction
|
|
182
|
+
*/
|
|
183
|
+
applyCustomTransformations(data, direction) {
|
|
184
|
+
// Can be overridden by subclasses
|
|
185
|
+
return data;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Update serialization statistics
|
|
189
|
+
* @param success Whether serialization succeeded
|
|
190
|
+
* @param duration Serialization duration in milliseconds
|
|
191
|
+
* @param format Format used
|
|
192
|
+
*/
|
|
193
|
+
updateSerializationStats(success, duration, format) {
|
|
194
|
+
this.stats.totalSerializations++;
|
|
195
|
+
this.stats.averageSerializationTime = ((this.stats.averageSerializationTime * (this.stats.totalSerializations - 1) + duration) /
|
|
196
|
+
this.stats.totalSerializations);
|
|
197
|
+
if (!success) {
|
|
198
|
+
this.stats.serializationErrors++;
|
|
199
|
+
}
|
|
200
|
+
// Update format usage
|
|
201
|
+
this.stats.formatUsage[format] = (this.stats.formatUsage[format] || 0) + 1;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Update deserialization statistics
|
|
205
|
+
* @param success Whether deserialization succeeded
|
|
206
|
+
* @param duration Deserialization duration in milliseconds
|
|
207
|
+
* @param format Format used
|
|
208
|
+
*/
|
|
209
|
+
updateDeserializationStats(success, duration, format) {
|
|
210
|
+
this.stats.totalDeserializations++;
|
|
211
|
+
this.stats.averageDeserializationTime = ((this.stats.averageDeserializationTime * (this.stats.totalDeserializations - 1) + duration) /
|
|
212
|
+
this.stats.totalDeserializations);
|
|
213
|
+
if (!success) {
|
|
214
|
+
this.stats.deserializationErrors++;
|
|
215
|
+
}
|
|
216
|
+
// Update format usage
|
|
217
|
+
this.stats.formatUsage[format] = (this.stats.formatUsage[format] || 0) + 1;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Check if a format is supported
|
|
221
|
+
* @param format Format to check
|
|
222
|
+
*/
|
|
223
|
+
supportsFormat(format) {
|
|
224
|
+
return this.supportedFormats.includes(format);
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Get content type for a format
|
|
228
|
+
* @param format Format
|
|
229
|
+
* @returns Content type string
|
|
230
|
+
*/
|
|
231
|
+
getContentType(format) {
|
|
232
|
+
const handler = this.formatHandlers.get(format);
|
|
233
|
+
if (handler?.contentType) {
|
|
234
|
+
return handler.contentType;
|
|
235
|
+
}
|
|
236
|
+
// Default content types
|
|
237
|
+
switch (format) {
|
|
238
|
+
case 'json':
|
|
239
|
+
return 'application/json';
|
|
240
|
+
case 'xml':
|
|
241
|
+
return 'application/xml';
|
|
242
|
+
case 'yaml':
|
|
243
|
+
return 'application/yaml';
|
|
244
|
+
case 'protobuf':
|
|
245
|
+
return 'application/protobuf';
|
|
246
|
+
case 'msgpack':
|
|
247
|
+
return 'application/msgpack';
|
|
248
|
+
default:
|
|
249
|
+
return 'application/octet-stream';
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Get format from content type
|
|
254
|
+
* @param contentType Content type
|
|
255
|
+
* @returns Format or undefined if not recognized
|
|
256
|
+
*/
|
|
257
|
+
getFormatFromContentType(contentType) {
|
|
258
|
+
const normalized = contentType.toLowerCase().split(';')[0].trim();
|
|
259
|
+
for (const [format, handler] of this.formatHandlers.entries()) {
|
|
260
|
+
if (handler.contentType && handler.contentType.toLowerCase() === normalized) {
|
|
261
|
+
return format;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
// Check common content types
|
|
265
|
+
if (normalized.includes('json')) {
|
|
266
|
+
return 'json';
|
|
267
|
+
}
|
|
268
|
+
else if (normalized.includes('xml')) {
|
|
269
|
+
return 'xml';
|
|
270
|
+
}
|
|
271
|
+
else if (normalized.includes('yaml') || normalized.includes('yml')) {
|
|
272
|
+
return 'yaml';
|
|
273
|
+
}
|
|
274
|
+
else if (normalized.includes('protobuf')) {
|
|
275
|
+
return 'protobuf';
|
|
276
|
+
}
|
|
277
|
+
else if (normalized.includes('msgpack')) {
|
|
278
|
+
return 'msgpack';
|
|
279
|
+
}
|
|
280
|
+
return undefined;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Register a custom format handler
|
|
284
|
+
* @param format Format name
|
|
285
|
+
* @param handler Serialization/deserialization functions
|
|
286
|
+
*/
|
|
287
|
+
registerFormat(format, handler) {
|
|
288
|
+
this.formatHandlers.set(format, handler);
|
|
289
|
+
if (!this.supportedFormats.includes(format)) {
|
|
290
|
+
this.supportedFormats.push(format);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Update serializer configuration
|
|
295
|
+
* @param config New configuration
|
|
296
|
+
*/
|
|
297
|
+
updateConfig(config) {
|
|
298
|
+
this.config = { ...this.config, ...config };
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Get serializer statistics
|
|
302
|
+
*/
|
|
303
|
+
getStats() {
|
|
304
|
+
return { ...this.stats };
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Reset serializer statistics
|
|
308
|
+
*/
|
|
309
|
+
resetStats() {
|
|
310
|
+
this.stats = {
|
|
311
|
+
totalSerializations: 0,
|
|
312
|
+
totalDeserializations: 0,
|
|
313
|
+
serializationErrors: 0,
|
|
314
|
+
deserializationErrors: 0,
|
|
315
|
+
averageSerializationTime: 0,
|
|
316
|
+
averageDeserializationTime: 0,
|
|
317
|
+
formatUsage: {},
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Health check for the serializer
|
|
322
|
+
*/
|
|
323
|
+
healthCheck() {
|
|
324
|
+
const healthy = this.supportedFormats.length > 0;
|
|
325
|
+
return {
|
|
326
|
+
healthy,
|
|
327
|
+
message: healthy ? 'Serializer is operational' : 'No supported formats configured',
|
|
328
|
+
details: {
|
|
329
|
+
name: this.name,
|
|
330
|
+
supportedFormats: this.supportedFormats,
|
|
331
|
+
defaultFormat: this.defaultFormat,
|
|
332
|
+
registeredFormats: Array.from(this.formatHandlers.keys()),
|
|
333
|
+
statistics: this.getStats(),
|
|
334
|
+
},
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Abstract base service discoverer implementation
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Abstract base service discoverer implementation
|
|
7
|
+
* Provides common functionality for all service discovery implementations
|
|
8
|
+
*/
|
|
9
|
+
export class BaseServiceDiscoverer {
|
|
10
|
+
/**
|
|
11
|
+
* Create a new base service discoverer instance
|
|
12
|
+
* @param type Discovery type
|
|
13
|
+
* @param config Discovery configuration
|
|
14
|
+
*/
|
|
15
|
+
constructor(type, config) {
|
|
16
|
+
/** Whether discovery is currently active */
|
|
17
|
+
this.isActive = false;
|
|
18
|
+
/** Total services discovered */
|
|
19
|
+
this.totalServicesDiscovered = 0;
|
|
20
|
+
/** Total instances discovered */
|
|
21
|
+
this.totalInstancesDiscovered = 0;
|
|
22
|
+
/** Service cache */
|
|
23
|
+
this.cache = new Map();
|
|
24
|
+
/** Cache timestamps */
|
|
25
|
+
this.cacheTimestamps = new Map();
|
|
26
|
+
/** Watch callbacks */
|
|
27
|
+
this.watchers = new Map();
|
|
28
|
+
/** Discovery statistics */
|
|
29
|
+
this.stats = {
|
|
30
|
+
totalResolves: 0,
|
|
31
|
+
totalWatches: 0,
|
|
32
|
+
cacheHits: 0,
|
|
33
|
+
cacheMisses: 0,
|
|
34
|
+
cacheHitRate: 0,
|
|
35
|
+
averageResolveTime: 0,
|
|
36
|
+
totalResolveTime: 0,
|
|
37
|
+
uptime: 0,
|
|
38
|
+
startTime: Date.now(),
|
|
39
|
+
};
|
|
40
|
+
this.type = type;
|
|
41
|
+
this.config = { ...config };
|
|
42
|
+
this.initialize();
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Initialize service discoverer
|
|
46
|
+
*/
|
|
47
|
+
initialize() {
|
|
48
|
+
// Can be overridden by subclasses
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Resolve all instances for multiple services
|
|
52
|
+
* @param serviceNames Array of service names
|
|
53
|
+
* @returns Promise resolving to map of service names to instances
|
|
54
|
+
*/
|
|
55
|
+
async resolveAll(serviceNames) {
|
|
56
|
+
const results = new Map();
|
|
57
|
+
for (const serviceName of serviceNames) {
|
|
58
|
+
try {
|
|
59
|
+
const result = await this.resolve(serviceName);
|
|
60
|
+
results.set(serviceName, result.instances);
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
results.set(serviceName, []);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return results;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Watch for changes to service instances
|
|
70
|
+
* @param serviceName Service name to watch
|
|
71
|
+
* @param callback Callback function for changes
|
|
72
|
+
* @returns Unwatch function
|
|
73
|
+
*/
|
|
74
|
+
watch(serviceName, callback) {
|
|
75
|
+
let watchers = this.watchers.get(serviceName);
|
|
76
|
+
if (!watchers) {
|
|
77
|
+
watchers = new Set();
|
|
78
|
+
this.watchers.set(serviceName, watchers);
|
|
79
|
+
}
|
|
80
|
+
watchers.add(callback);
|
|
81
|
+
this.stats.totalWatches++;
|
|
82
|
+
return () => {
|
|
83
|
+
watchers?.delete(callback);
|
|
84
|
+
if (watchers?.size === 0) {
|
|
85
|
+
this.watchers.delete(serviceName);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Stop watching a service
|
|
91
|
+
* @param serviceName Service name to stop watching
|
|
92
|
+
*/
|
|
93
|
+
unwatch(serviceName) {
|
|
94
|
+
this.watchers.delete(serviceName);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Stop watching all services
|
|
98
|
+
*/
|
|
99
|
+
unwatchAll() {
|
|
100
|
+
this.watchers.clear();
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Get cached service instances
|
|
104
|
+
* @param serviceName Service name
|
|
105
|
+
* @returns Cached instances or empty array
|
|
106
|
+
*/
|
|
107
|
+
getCachedInstances(serviceName) {
|
|
108
|
+
return this.cache.get(serviceName) || [];
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Clear cache for a service
|
|
112
|
+
* @param serviceName Service name
|
|
113
|
+
*/
|
|
114
|
+
clearCache(serviceName) {
|
|
115
|
+
if (serviceName) {
|
|
116
|
+
this.cache.delete(serviceName);
|
|
117
|
+
this.cacheTimestamps.delete(serviceName);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
this.cache.clear();
|
|
121
|
+
this.cacheTimestamps.clear();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Refresh cache for a service
|
|
126
|
+
* @param serviceName Service name
|
|
127
|
+
* @returns Promise resolving when cache is refreshed
|
|
128
|
+
*/
|
|
129
|
+
async refreshCache(serviceName) {
|
|
130
|
+
if (serviceName) {
|
|
131
|
+
this.clearCache(serviceName);
|
|
132
|
+
await this.resolve(serviceName);
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
const serviceNames = Array.from(this.cache.keys());
|
|
136
|
+
this.clearCache();
|
|
137
|
+
await this.resolveAll(serviceNames);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Check if cache is valid for a service
|
|
142
|
+
* @param serviceName Service name
|
|
143
|
+
* @returns True if cache is valid
|
|
144
|
+
*/
|
|
145
|
+
isCacheValid(serviceName) {
|
|
146
|
+
if (!this.config.cache?.enabled)
|
|
147
|
+
return false;
|
|
148
|
+
const timestamp = this.cacheTimestamps.get(serviceName);
|
|
149
|
+
if (!timestamp)
|
|
150
|
+
return false;
|
|
151
|
+
const ttl = this.config.cache.ttl;
|
|
152
|
+
return (Date.now() - timestamp) < ttl;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Update cache for a service
|
|
156
|
+
* @param serviceName Service name
|
|
157
|
+
* @param instances Service instances
|
|
158
|
+
*/
|
|
159
|
+
updateCache(serviceName, instances) {
|
|
160
|
+
if (this.config.cache?.enabled) {
|
|
161
|
+
this.cache.set(serviceName, instances);
|
|
162
|
+
this.cacheTimestamps.set(serviceName, Date.now());
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Notify watchers of service changes
|
|
167
|
+
* @param serviceName Service name
|
|
168
|
+
* @param instances Updated instances
|
|
169
|
+
*/
|
|
170
|
+
notifyWatchers(serviceName, instances) {
|
|
171
|
+
const watchers = this.watchers.get(serviceName);
|
|
172
|
+
if (watchers) {
|
|
173
|
+
for (const callback of watchers) {
|
|
174
|
+
try {
|
|
175
|
+
callback(instances);
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
// Log error but continue
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Get service discovery statistics
|
|
185
|
+
*/
|
|
186
|
+
getStats() {
|
|
187
|
+
this.stats.uptime = Date.now() - this.stats.startTime;
|
|
188
|
+
this.stats.cacheHitRate = this.stats.totalResolves > 0
|
|
189
|
+
? this.stats.cacheHits / this.stats.totalResolves
|
|
190
|
+
: 0;
|
|
191
|
+
return { ...this.stats };
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Reset service discovery statistics
|
|
195
|
+
*/
|
|
196
|
+
resetStats() {
|
|
197
|
+
this.stats = {
|
|
198
|
+
totalResolves: 0,
|
|
199
|
+
totalWatches: 0,
|
|
200
|
+
cacheHits: 0,
|
|
201
|
+
cacheMisses: 0,
|
|
202
|
+
cacheHitRate: 0,
|
|
203
|
+
averageResolveTime: 0,
|
|
204
|
+
totalResolveTime: 0,
|
|
205
|
+
uptime: 0,
|
|
206
|
+
startTime: Date.now(),
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Update service discovery configuration
|
|
211
|
+
* @param config New configuration
|
|
212
|
+
*/
|
|
213
|
+
updateConfig(config) {
|
|
214
|
+
this.config = { ...this.config, ...config };
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Health check for the service discoverer itself
|
|
218
|
+
*/
|
|
219
|
+
async healthCheckSelf() {
|
|
220
|
+
const healthy = this.isActive;
|
|
221
|
+
return {
|
|
222
|
+
healthy,
|
|
223
|
+
message: healthy ? 'Service discoverer is operational' : 'Service discoverer is not active',
|
|
224
|
+
details: {
|
|
225
|
+
type: this.type,
|
|
226
|
+
isActive: this.isActive,
|
|
227
|
+
totalServices: this.totalServicesDiscovered,
|
|
228
|
+
totalInstances: this.totalInstancesDiscovered,
|
|
229
|
+
cacheSize: this.cache.size,
|
|
230
|
+
watchersCount: this.watchers.size,
|
|
231
|
+
stats: this.getStats(),
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Close/cleanup service discovery resources
|
|
237
|
+
*/
|
|
238
|
+
async close() {
|
|
239
|
+
this.isActive = false;
|
|
240
|
+
this.unwatchAll();
|
|
241
|
+
this.clearCache();
|
|
242
|
+
await this.onClose();
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Hook for cleanup logic
|
|
246
|
+
*/
|
|
247
|
+
async onClose() {
|
|
248
|
+
// Can be overridden by subclasses
|
|
249
|
+
}
|
|
250
|
+
}
|