@morojs/moro 1.6.0 → 1.6.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/core/config/config-sources.js +4 -0
- package/dist/core/config/config-sources.js.map +1 -1
- package/dist/core/config/config-validator.js +3 -0
- package/dist/core/config/config-validator.js.map +1 -1
- package/dist/core/config/file-loader.js +3 -1
- package/dist/core/config/file-loader.js.map +1 -1
- package/dist/core/config/schema.js +4 -1
- package/dist/core/config/schema.js.map +1 -1
- package/dist/core/events/event-bus.js +1 -1
- package/dist/core/events/event-bus.js.map +1 -1
- package/dist/core/framework.d.ts +1 -1
- package/dist/core/framework.js +13 -7
- package/dist/core/framework.js.map +1 -1
- package/dist/core/http/http-server.d.ts +55 -15
- package/dist/core/http/http-server.js +70 -146
- package/dist/core/http/http-server.js.map +1 -1
- package/dist/core/http/index.d.ts +1 -1
- package/dist/core/http/index.js +1 -1
- package/dist/core/http/index.js.map +1 -1
- package/dist/core/http/uws-http-server.d.ts +4 -22
- package/dist/core/http/uws-http-server.js +43 -208
- package/dist/core/http/uws-http-server.js.map +1 -1
- package/dist/core/networking/adapters/uws-adapter.d.ts +1 -1
- package/dist/core/networking/adapters/uws-adapter.js +1 -1
- package/dist/core/pooling/object-pool-manager.d.ts +140 -0
- package/dist/core/pooling/object-pool-manager.js +502 -0
- package/dist/core/pooling/object-pool-manager.js.map +1 -0
- package/dist/core/routing/app-integration.d.ts +12 -10
- package/dist/core/routing/app-integration.js +43 -74
- package/dist/core/routing/app-integration.js.map +1 -1
- package/dist/core/routing/index.d.ts +15 -29
- package/dist/core/routing/index.js +43 -390
- package/dist/core/routing/index.js.map +1 -1
- package/dist/core/routing/path-matcher.d.ts +67 -0
- package/dist/core/routing/path-matcher.js +182 -0
- package/dist/core/routing/path-matcher.js.map +1 -0
- package/dist/core/{http → routing}/router.d.ts +21 -9
- package/dist/core/routing/router.js +68 -0
- package/dist/core/routing/router.js.map +1 -0
- package/dist/core/routing/unified-router.d.ts +148 -0
- package/dist/core/routing/unified-router.js +684 -0
- package/dist/core/routing/unified-router.js.map +1 -0
- package/dist/moro.d.ts +10 -7
- package/dist/moro.js +90 -41
- package/dist/moro.js.map +1 -1
- package/dist/types/config.d.ts +3 -0
- package/package.json +1 -1
- package/src/core/config/config-sources.ts +4 -0
- package/src/core/config/config-validator.ts +3 -0
- package/src/core/config/file-loader.ts +4 -1
- package/src/core/config/schema.ts +4 -1
- package/src/core/events/event-bus.ts +1 -1
- package/src/core/framework.ts +14 -9
- package/src/core/http/http-server.ts +76 -161
- package/src/core/http/index.ts +1 -1
- package/src/core/http/uws-http-server.ts +43 -246
- package/src/core/networking/adapters/uws-adapter.ts +1 -1
- package/src/core/pooling/object-pool-manager.ts +630 -0
- package/src/core/routing/app-integration.ts +57 -109
- package/src/core/routing/index.ts +62 -473
- package/src/core/routing/path-matcher.ts +222 -0
- package/src/core/routing/router.ts +97 -0
- package/src/core/routing/unified-router.ts +870 -0
- package/src/moro.ts +107 -57
- package/src/types/config.ts +3 -0
- package/dist/core/http/router.js +0 -183
- package/dist/core/http/router.js.map +0 -1
- package/src/core/http/router.ts +0 -230
|
@@ -6,18 +6,11 @@ export declare class MoroHttpServer {
|
|
|
6
6
|
private globalMiddleware;
|
|
7
7
|
private compressionEnabled;
|
|
8
8
|
private compressionThreshold;
|
|
9
|
+
private requestTrackingEnabled;
|
|
9
10
|
private logger;
|
|
10
11
|
private hookManager;
|
|
11
12
|
private requestCounter;
|
|
12
|
-
private
|
|
13
|
-
private bufferPool;
|
|
14
|
-
private readonly maxPoolSize;
|
|
15
|
-
private middlewareExecutionCache;
|
|
16
|
-
private responseCache;
|
|
17
|
-
private responseCacheHits;
|
|
18
|
-
private responseCacheMisses;
|
|
19
|
-
private static readonly INTERNED_METHODS;
|
|
20
|
-
private static readonly INTERNED_HEADERS;
|
|
13
|
+
private poolManager;
|
|
21
14
|
private static readonly RESPONSE_TEMPLATES;
|
|
22
15
|
private static readonly BUFFER_SIZES;
|
|
23
16
|
private static readonly BUFFER_POOLS;
|
|
@@ -31,6 +24,7 @@ export declare class MoroHttpServer {
|
|
|
31
24
|
};
|
|
32
25
|
minimal?: boolean;
|
|
33
26
|
}): void;
|
|
27
|
+
setRequestTracking(enabled: boolean): void;
|
|
34
28
|
use(middleware: Middleware): void;
|
|
35
29
|
setHookManager(hookManager: any): void;
|
|
36
30
|
get(path: string, ...handlers: (Middleware | HttpHandler)[]): void;
|
|
@@ -57,6 +51,7 @@ export declare class MoroHttpServer {
|
|
|
57
51
|
private parseMultipart;
|
|
58
52
|
private parseUrlEncoded;
|
|
59
53
|
private parseQueryString;
|
|
54
|
+
private parseQueryStringPooled;
|
|
60
55
|
private routeCache;
|
|
61
56
|
private staticRoutes;
|
|
62
57
|
private dynamicRoutes;
|
|
@@ -71,14 +66,59 @@ export declare class MoroHttpServer {
|
|
|
71
66
|
close(): Promise<void>;
|
|
72
67
|
forceCleanup(): void;
|
|
73
68
|
getServer(): Server;
|
|
74
|
-
private getResponseCacheKey;
|
|
75
69
|
getPerformanceStats(): {
|
|
76
|
-
responseCacheHits: number;
|
|
77
|
-
responseCacheMisses: number;
|
|
78
|
-
responseCacheSize: number;
|
|
79
70
|
paramObjectPoolSize: number;
|
|
80
|
-
|
|
81
|
-
|
|
71
|
+
queryObjectPoolSize: number;
|
|
72
|
+
headerObjectPoolSize: number;
|
|
73
|
+
poolManager: {
|
|
74
|
+
paramPool: {
|
|
75
|
+
poolSize: number;
|
|
76
|
+
maxSize: number;
|
|
77
|
+
acquireCount: number;
|
|
78
|
+
releaseCount: number;
|
|
79
|
+
createCount: number;
|
|
80
|
+
utilization: number;
|
|
81
|
+
};
|
|
82
|
+
headerPool: {
|
|
83
|
+
poolSize: number;
|
|
84
|
+
maxSize: number;
|
|
85
|
+
acquireCount: number;
|
|
86
|
+
releaseCount: number;
|
|
87
|
+
createCount: number;
|
|
88
|
+
utilization: number;
|
|
89
|
+
};
|
|
90
|
+
queryPool: {
|
|
91
|
+
poolSize: number;
|
|
92
|
+
maxSize: number;
|
|
93
|
+
acquireCount: number;
|
|
94
|
+
releaseCount: number;
|
|
95
|
+
createCount: number;
|
|
96
|
+
utilization: number;
|
|
97
|
+
};
|
|
98
|
+
bufferPools: Record<string, any>;
|
|
99
|
+
routeCache: {
|
|
100
|
+
size: number;
|
|
101
|
+
maxSize: number;
|
|
102
|
+
hits: number;
|
|
103
|
+
misses: number;
|
|
104
|
+
hitRate: number;
|
|
105
|
+
};
|
|
106
|
+
responseCache: {
|
|
107
|
+
size: number;
|
|
108
|
+
maxSize: number;
|
|
109
|
+
hits: number;
|
|
110
|
+
misses: number;
|
|
111
|
+
hitRate: number;
|
|
112
|
+
};
|
|
113
|
+
totalMemory: {
|
|
114
|
+
params: number;
|
|
115
|
+
headers: number;
|
|
116
|
+
queries: number;
|
|
117
|
+
buffers: number;
|
|
118
|
+
routes: number;
|
|
119
|
+
responses: number;
|
|
120
|
+
};
|
|
121
|
+
};
|
|
82
122
|
};
|
|
83
123
|
}
|
|
84
124
|
export declare const middleware: {
|
|
@@ -5,6 +5,8 @@ import { createReadStream } from 'fs';
|
|
|
5
5
|
import * as crypto from 'crypto';
|
|
6
6
|
import { promisify } from 'util';
|
|
7
7
|
import { createFrameworkLogger } from '../logger/index.js';
|
|
8
|
+
import { PathMatcher } from '../routing/path-matcher.js';
|
|
9
|
+
import { ObjectPoolManager } from '../pooling/object-pool-manager.js';
|
|
8
10
|
const gzip = promisify(zlib.gzip);
|
|
9
11
|
const deflate = promisify(zlib.deflate);
|
|
10
12
|
export class MoroHttpServer {
|
|
@@ -13,40 +15,13 @@ export class MoroHttpServer {
|
|
|
13
15
|
globalMiddleware = [];
|
|
14
16
|
compressionEnabled = true;
|
|
15
17
|
compressionThreshold = 1024;
|
|
18
|
+
requestTrackingEnabled = true; // Generate request IDs
|
|
16
19
|
logger = createFrameworkLogger('HttpServer');
|
|
17
20
|
hookManager;
|
|
18
21
|
requestCounter = 0;
|
|
19
|
-
//
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
maxPoolSize = 50;
|
|
23
|
-
// Request handler pooling to avoid function creation overhead
|
|
24
|
-
middlewareExecutionCache = new Map();
|
|
25
|
-
// Response caching for ultra-fast common responses
|
|
26
|
-
responseCache = new Map();
|
|
27
|
-
responseCacheHits = 0;
|
|
28
|
-
responseCacheMisses = 0;
|
|
29
|
-
// String interning for common values (massive memory savings)
|
|
30
|
-
static INTERNED_METHODS = new Map([
|
|
31
|
-
['GET', 'GET'],
|
|
32
|
-
['POST', 'POST'],
|
|
33
|
-
['PUT', 'PUT'],
|
|
34
|
-
['DELETE', 'DELETE'],
|
|
35
|
-
['PATCH', 'PATCH'],
|
|
36
|
-
['HEAD', 'HEAD'],
|
|
37
|
-
['OPTIONS', 'OPTIONS'],
|
|
38
|
-
]);
|
|
39
|
-
static INTERNED_HEADERS = new Map([
|
|
40
|
-
['content-type', 'content-type'],
|
|
41
|
-
['content-length', 'content-length'],
|
|
42
|
-
['authorization', 'authorization'],
|
|
43
|
-
['accept', 'accept'],
|
|
44
|
-
['user-agent', 'user-agent'],
|
|
45
|
-
['host', 'host'],
|
|
46
|
-
['connection', 'connection'],
|
|
47
|
-
['cache-control', 'cache-control'],
|
|
48
|
-
]);
|
|
49
|
-
// Pre-compiled response templates for ultra-common responses
|
|
22
|
+
// Use shared object pool manager
|
|
23
|
+
poolManager = ObjectPoolManager.getInstance();
|
|
24
|
+
// Pre-compiled response templates for common responses
|
|
50
25
|
static RESPONSE_TEMPLATES = {
|
|
51
26
|
notFound: Buffer.from('{"success":false,"error":"Not found"}'),
|
|
52
27
|
unauthorized: Buffer.from('{"success":false,"error":"Unauthorized"}'),
|
|
@@ -55,7 +30,7 @@ export class MoroHttpServer {
|
|
|
55
30
|
methodNotAllowed: Buffer.from('{"success":false,"error":"Method not allowed"}'),
|
|
56
31
|
rateLimited: Buffer.from('{"success":false,"error":"Rate limit exceeded"}'),
|
|
57
32
|
};
|
|
58
|
-
//
|
|
33
|
+
// Buffer pool for zero-copy operations
|
|
59
34
|
static BUFFER_SIZES = [64, 256, 1024, 4096, 16384];
|
|
60
35
|
static BUFFER_POOLS = new Map();
|
|
61
36
|
static {
|
|
@@ -110,6 +85,10 @@ export class MoroHttpServer {
|
|
|
110
85
|
this.compressionThreshold = Infinity; // Never compress
|
|
111
86
|
}
|
|
112
87
|
}
|
|
88
|
+
// Configure request tracking (ID generation)
|
|
89
|
+
setRequestTracking(enabled) {
|
|
90
|
+
this.requestTrackingEnabled = enabled;
|
|
91
|
+
}
|
|
113
92
|
// Middleware management
|
|
114
93
|
use(middleware) {
|
|
115
94
|
this.globalMiddleware.push(middleware);
|
|
@@ -165,39 +144,33 @@ export class MoroHttpServer {
|
|
|
165
144
|
}
|
|
166
145
|
}
|
|
167
146
|
pathToRegex(path) {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const regexPattern = path
|
|
171
|
-
.replace(/\/:([^/]+)/g, (match, paramName) => {
|
|
172
|
-
paramNames.push(paramName);
|
|
173
|
-
return '/([^/]+)';
|
|
174
|
-
})
|
|
175
|
-
.replace(/\//g, '\\/');
|
|
147
|
+
// Use shared PathMatcher for consistent path compilation
|
|
148
|
+
const compiled = PathMatcher.compile(path);
|
|
176
149
|
return {
|
|
177
|
-
pattern: new RegExp(`^${
|
|
178
|
-
paramNames,
|
|
150
|
+
pattern: compiled.pattern || new RegExp(`^${path.replace(/\//g, '\\/')}$`),
|
|
151
|
+
paramNames: compiled.paramNames,
|
|
179
152
|
};
|
|
180
153
|
}
|
|
181
154
|
async handleRequest(req, res) {
|
|
182
155
|
const httpReq = this.enhanceRequest(req);
|
|
183
|
-
const httpRes = this.enhanceResponse(res);
|
|
156
|
+
const httpRes = this.enhanceResponse(res, httpReq);
|
|
184
157
|
// Store original params for efficient cleanup
|
|
185
158
|
const originalParams = httpReq.params;
|
|
186
159
|
try {
|
|
187
|
-
// Optimized URL and query parsing
|
|
160
|
+
// Optimized URL and query parsing with object pooling
|
|
188
161
|
const urlString = req.url;
|
|
189
162
|
const queryIndex = urlString.indexOf('?');
|
|
190
163
|
if (queryIndex === -1) {
|
|
191
|
-
// No query string
|
|
164
|
+
// No query string
|
|
192
165
|
httpReq.path = urlString;
|
|
193
166
|
httpReq.query = {};
|
|
194
167
|
}
|
|
195
168
|
else {
|
|
196
|
-
// Has query string - parse efficiently
|
|
169
|
+
// Has query string - parse efficiently with pooled object
|
|
197
170
|
httpReq.path = urlString.substring(0, queryIndex);
|
|
198
|
-
httpReq.query = this.
|
|
171
|
+
httpReq.query = this.parseQueryStringPooled(urlString.substring(queryIndex + 1));
|
|
199
172
|
}
|
|
200
|
-
//
|
|
173
|
+
// Method checking - avoid array includes
|
|
201
174
|
const method = req.method;
|
|
202
175
|
if (method === 'POST' || method === 'PUT' || method === 'PATCH') {
|
|
203
176
|
httpReq.body = await this.parseBody(req);
|
|
@@ -218,7 +191,7 @@ export class MoroHttpServer {
|
|
|
218
191
|
// Find matching route
|
|
219
192
|
const route = this.findRoute(req.method, httpReq.path);
|
|
220
193
|
if (!route) {
|
|
221
|
-
//
|
|
194
|
+
// 404 response with pre-compiled buffer
|
|
222
195
|
httpRes.statusCode = 404;
|
|
223
196
|
httpRes.setHeader('Content-Type', 'application/json; charset=utf-8');
|
|
224
197
|
httpRes.setHeader('Content-Length', MoroHttpServer.RESPONSE_TEMPLATES.notFound.length);
|
|
@@ -264,7 +237,7 @@ export class MoroHttpServer {
|
|
|
264
237
|
});
|
|
265
238
|
}
|
|
266
239
|
else {
|
|
267
|
-
//
|
|
240
|
+
// Defensive fallback - check each method individually
|
|
268
241
|
if (typeof httpRes.setHeader === 'function') {
|
|
269
242
|
httpRes.statusCode = 500;
|
|
270
243
|
httpRes.setHeader('Content-Type', 'application/json');
|
|
@@ -313,50 +286,27 @@ export class MoroHttpServer {
|
|
|
313
286
|
}
|
|
314
287
|
});
|
|
315
288
|
}
|
|
316
|
-
//
|
|
289
|
+
// Use shared object pool for parameter objects
|
|
317
290
|
acquireParamObject() {
|
|
318
|
-
|
|
319
|
-
if (obj) {
|
|
320
|
-
// ES2022: Use Object.hasOwn for safer property checks and faster clearing
|
|
321
|
-
// Clear existing properties more efficiently
|
|
322
|
-
for (const key in obj) {
|
|
323
|
-
if (Object.hasOwn(obj, key)) {
|
|
324
|
-
delete obj[key];
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
return obj;
|
|
328
|
-
}
|
|
329
|
-
return {};
|
|
291
|
+
return this.poolManager.acquireParams();
|
|
330
292
|
}
|
|
331
293
|
releaseParamObject(params) {
|
|
332
|
-
|
|
333
|
-
this.paramObjectPool.push(params);
|
|
334
|
-
}
|
|
294
|
+
this.poolManager.releaseParams(params);
|
|
335
295
|
}
|
|
336
296
|
// Force cleanup of all pooled objects
|
|
337
297
|
forceCleanupPools() {
|
|
338
|
-
//
|
|
339
|
-
this.
|
|
340
|
-
this.bufferPool.splice(0);
|
|
298
|
+
// Use shared pool manager cleanup
|
|
299
|
+
this.poolManager.clearAll();
|
|
341
300
|
// Force garbage collection if available
|
|
342
|
-
// Use modern globalThis check with optional chaining
|
|
343
301
|
if (globalThis?.gc) {
|
|
344
302
|
globalThis.gc();
|
|
345
303
|
}
|
|
346
304
|
}
|
|
347
305
|
acquireBuffer(size) {
|
|
348
|
-
|
|
349
|
-
const index = this.bufferPool.findIndex(b => b.length >= size);
|
|
350
|
-
if (index !== -1) {
|
|
351
|
-
const buffer = this.bufferPool.splice(index, 1)[0];
|
|
352
|
-
return buffer.subarray(0, size);
|
|
353
|
-
}
|
|
354
|
-
return Buffer.allocUnsafe(size);
|
|
306
|
+
return this.poolManager.acquireBuffer(size);
|
|
355
307
|
}
|
|
356
308
|
releaseBuffer(buffer) {
|
|
357
|
-
|
|
358
|
-
this.bufferPool.push(buffer);
|
|
359
|
-
}
|
|
309
|
+
this.poolManager.releaseBuffer(buffer);
|
|
360
310
|
}
|
|
361
311
|
streamLargeResponse(res, data) {
|
|
362
312
|
res.setHeader('Content-Type', 'application/json; charset=utf-8');
|
|
@@ -375,7 +325,7 @@ export class MoroHttpServer {
|
|
|
375
325
|
if (this.pathNormalizationCache.has(path)) {
|
|
376
326
|
return this.pathNormalizationCache.get(path);
|
|
377
327
|
}
|
|
378
|
-
//
|
|
328
|
+
// Normalization: remove trailing slash (except root), decode once
|
|
379
329
|
let normalized = path;
|
|
380
330
|
if (normalized.length > 1 && normalized.endsWith('/')) {
|
|
381
331
|
normalized = normalized.slice(0, -1);
|
|
@@ -393,8 +343,8 @@ export class MoroHttpServer {
|
|
|
393
343
|
httpReq.body = null;
|
|
394
344
|
httpReq.path = '';
|
|
395
345
|
httpReq.ip = req.socket.remoteAddress || '';
|
|
396
|
-
//
|
|
397
|
-
httpReq.requestId =
|
|
346
|
+
// Request ID generation using pool manager (if enabled)
|
|
347
|
+
httpReq.requestId = this.requestTrackingEnabled ? this.poolManager.generateRequestId() : '';
|
|
398
348
|
httpReq.headers = req.headers;
|
|
399
349
|
// Parse cookies
|
|
400
350
|
httpReq.cookies = this.parseCookies(req.headers.cookie || '');
|
|
@@ -412,8 +362,10 @@ export class MoroHttpServer {
|
|
|
412
362
|
});
|
|
413
363
|
return cookies;
|
|
414
364
|
}
|
|
415
|
-
enhanceResponse(res) {
|
|
365
|
+
enhanceResponse(res, req) {
|
|
416
366
|
const httpRes = res;
|
|
367
|
+
// Store request reference for access to headers (needed for compression, logging, etc.)
|
|
368
|
+
httpRes.req = req;
|
|
417
369
|
// BULLETPROOF status method - always works
|
|
418
370
|
httpRes.status = (code) => {
|
|
419
371
|
httpRes.statusCode = code;
|
|
@@ -422,20 +374,7 @@ export class MoroHttpServer {
|
|
|
422
374
|
httpRes.json = async (data) => {
|
|
423
375
|
if (httpRes.headersSent)
|
|
424
376
|
return;
|
|
425
|
-
//
|
|
426
|
-
const cacheKey = this.getResponseCacheKey(data);
|
|
427
|
-
if (cacheKey) {
|
|
428
|
-
const cachedBuffer = this.responseCache.get(cacheKey);
|
|
429
|
-
if (cachedBuffer) {
|
|
430
|
-
this.responseCacheHits++;
|
|
431
|
-
httpRes.setHeader('Content-Type', 'application/json; charset=utf-8');
|
|
432
|
-
httpRes.setHeader('Content-Length', cachedBuffer.length);
|
|
433
|
-
httpRes.end(cachedBuffer);
|
|
434
|
-
return;
|
|
435
|
-
}
|
|
436
|
-
this.responseCacheMisses++;
|
|
437
|
-
}
|
|
438
|
-
// Ultra-fast JSON serialization with zero-copy buffers
|
|
377
|
+
// JSON serialization with zero-copy buffers
|
|
439
378
|
let jsonString;
|
|
440
379
|
// Enhanced JSON optimization for common API patterns
|
|
441
380
|
if (data && typeof data === 'object' && 'success' in data) {
|
|
@@ -512,10 +451,6 @@ export class MoroHttpServer {
|
|
|
512
451
|
httpRes.setHeader(key, value);
|
|
513
452
|
});
|
|
514
453
|
httpRes.end(finalBuffer);
|
|
515
|
-
// PERFORMANCE OPTIMIZATION: Cache small, common responses
|
|
516
|
-
if (cacheKey && finalBuffer.length < 1024 && this.responseCache.size < 100) {
|
|
517
|
-
this.responseCache.set(cacheKey, Buffer.from(finalBuffer));
|
|
518
|
-
}
|
|
519
454
|
// Return buffer to pool after response (zero-copy achievement!)
|
|
520
455
|
process.nextTick(() => MoroHttpServer.returnBuffer(buffer));
|
|
521
456
|
};
|
|
@@ -785,12 +720,18 @@ export class MoroHttpServer {
|
|
|
785
720
|
}
|
|
786
721
|
return result;
|
|
787
722
|
}
|
|
723
|
+
// Legacy method for backward compatibility
|
|
788
724
|
parseQueryString(queryString) {
|
|
789
|
-
|
|
725
|
+
return this.parseQueryStringPooled(queryString);
|
|
726
|
+
}
|
|
727
|
+
// Optimized query string parser with object pooling
|
|
728
|
+
parseQueryStringPooled(queryString) {
|
|
790
729
|
if (!queryString)
|
|
791
|
-
return
|
|
730
|
+
return {};
|
|
731
|
+
const result = this.poolManager.acquireQuery();
|
|
792
732
|
const pairs = queryString.split('&');
|
|
793
|
-
for (
|
|
733
|
+
for (let i = 0; i < pairs.length; i++) {
|
|
734
|
+
const pair = pairs[i];
|
|
794
735
|
const equalIndex = pair.indexOf('=');
|
|
795
736
|
if (equalIndex === -1) {
|
|
796
737
|
result[decodeURIComponent(pair)] = '';
|
|
@@ -809,7 +750,7 @@ export class MoroHttpServer {
|
|
|
809
750
|
dynamicRoutes = [];
|
|
810
751
|
routesBySegmentCount = new Map();
|
|
811
752
|
pathNormalizationCache = new Map();
|
|
812
|
-
//
|
|
753
|
+
// CPU cache-friendly optimizations
|
|
813
754
|
routeHitCount = new Map(); // Track route popularity for cache optimization
|
|
814
755
|
static HOT_ROUTE_THRESHOLD = 100; // Routes accessed 100+ times get hot path treatment
|
|
815
756
|
findRoute(method, path) {
|
|
@@ -854,35 +795,43 @@ export class MoroHttpServer {
|
|
|
854
795
|
}
|
|
855
796
|
return route;
|
|
856
797
|
}
|
|
798
|
+
// Optimized middleware execution with reduced Promise allocation
|
|
857
799
|
async executeMiddleware(middleware, req, res) {
|
|
858
|
-
for (
|
|
800
|
+
for (let i = 0; i < middleware.length; i++) {
|
|
859
801
|
// Short-circuit if response already sent
|
|
860
802
|
if (res.headersSent)
|
|
861
803
|
return;
|
|
804
|
+
const mw = middleware[i];
|
|
862
805
|
await new Promise((resolve, reject) => {
|
|
863
|
-
let
|
|
806
|
+
let resolved = false;
|
|
807
|
+
// Reuse next function to reduce allocations
|
|
864
808
|
const next = () => {
|
|
865
|
-
if (
|
|
809
|
+
if (resolved)
|
|
866
810
|
return;
|
|
867
|
-
|
|
811
|
+
resolved = true;
|
|
868
812
|
resolve();
|
|
869
813
|
};
|
|
870
814
|
try {
|
|
871
815
|
const result = mw(req, res, next);
|
|
872
816
|
// Handle async middleware
|
|
873
|
-
if (result
|
|
817
|
+
if (result && typeof result.then === 'function') {
|
|
874
818
|
result
|
|
875
819
|
.then(() => {
|
|
876
|
-
if (!
|
|
820
|
+
if (!resolved)
|
|
877
821
|
next();
|
|
878
822
|
})
|
|
879
|
-
.catch(
|
|
880
|
-
|
|
881
|
-
|
|
823
|
+
.catch(reject);
|
|
824
|
+
}
|
|
825
|
+
else if (!resolved) {
|
|
826
|
+
// Sync middleware that didn't call next
|
|
827
|
+
next();
|
|
882
828
|
}
|
|
883
829
|
}
|
|
884
830
|
catch (error) {
|
|
885
|
-
|
|
831
|
+
if (!resolved) {
|
|
832
|
+
resolved = true;
|
|
833
|
+
reject(error);
|
|
834
|
+
}
|
|
886
835
|
}
|
|
887
836
|
});
|
|
888
837
|
}
|
|
@@ -912,39 +861,14 @@ export class MoroHttpServer {
|
|
|
912
861
|
getServer() {
|
|
913
862
|
return this.server;
|
|
914
863
|
}
|
|
915
|
-
// PERFORMANCE OPTIMIZATION: Generate cache key for common response patterns
|
|
916
|
-
getResponseCacheKey(data) {
|
|
917
|
-
// Only cache simple, common responses
|
|
918
|
-
if (!data || typeof data !== 'object') {
|
|
919
|
-
// Simple primitives or strings - generate key
|
|
920
|
-
const key = JSON.stringify(data);
|
|
921
|
-
return key.length < 100 ? key : null;
|
|
922
|
-
}
|
|
923
|
-
// Common API response patterns
|
|
924
|
-
if ('hello' in data && Object.keys(data).length <= 2) {
|
|
925
|
-
// Hello world type responses
|
|
926
|
-
return `hello:${JSON.stringify(data)}`;
|
|
927
|
-
}
|
|
928
|
-
if ('status' in data && Object.keys(data).length <= 3) {
|
|
929
|
-
// Status responses like {status: "ok", version: "1.0.0"}
|
|
930
|
-
return `status:${JSON.stringify(data)}`;
|
|
931
|
-
}
|
|
932
|
-
if ('success' in data && 'message' in data && Object.keys(data).length <= 3) {
|
|
933
|
-
// Simple success/error responses
|
|
934
|
-
return `msg:${data.success}:${data.message}`;
|
|
935
|
-
}
|
|
936
|
-
// Don't cache complex objects
|
|
937
|
-
return null;
|
|
938
|
-
}
|
|
939
864
|
// Performance statistics
|
|
940
865
|
getPerformanceStats() {
|
|
866
|
+
const poolStats = this.poolManager.getStats();
|
|
941
867
|
return {
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
bufferPoolSize: this.bufferPool.length,
|
|
947
|
-
middlewareExecutionCacheSize: this.middlewareExecutionCache.size,
|
|
868
|
+
paramObjectPoolSize: poolStats.paramPool.poolSize,
|
|
869
|
+
queryObjectPoolSize: poolStats.queryPool.poolSize,
|
|
870
|
+
headerObjectPoolSize: poolStats.headerPool.poolSize,
|
|
871
|
+
poolManager: poolStats,
|
|
948
872
|
};
|
|
949
873
|
}
|
|
950
874
|
}
|