@rsdk/core 4.2.0-next.0 → 4.2.0-next.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/CHANGELOG.md +10 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/platform.context.js +5 -5
- package/dist/platform.context.js.map +1 -1
- package/dist/platform.module.js +6 -1
- package/dist/platform.module.js.map +1 -1
- package/dist/tracing/auto-instrumentations.config.js +2 -3
- package/dist/tracing/auto-instrumentations.config.js.map +1 -1
- package/dist/tracing/grpc.headers.d.ts +11 -0
- package/dist/tracing/grpc.headers.js +24 -0
- package/dist/tracing/grpc.headers.js.map +1 -0
- package/dist/tracing/http.headers.d.ts +11 -0
- package/dist/tracing/http.headers.js +22 -0
- package/dist/tracing/http.headers.js.map +1 -0
- package/dist/tracing/index.d.ts +0 -1
- package/dist/tracing/index.js +0 -1
- package/dist/tracing/index.js.map +1 -1
- package/dist/tracing/open-telemetry.interceptor.d.ts +5 -0
- package/dist/tracing/open-telemetry.interceptor.js +83 -0
- package/dist/tracing/open-telemetry.interceptor.js.map +1 -0
- package/dist/tracing/request-metadata.module.js +1 -5
- package/dist/tracing/request-metadata.module.js.map +1 -1
- package/dist/tracing/services/instrumentation.service.d.ts +0 -1
- package/dist/tracing/services/instrumentation.service.js +0 -7
- package/dist/tracing/services/instrumentation.service.js.map +1 -1
- package/dist/tracing/services/request-id.provider.d.ts +11 -0
- package/dist/tracing/services/request-id.provider.js +13 -0
- package/dist/tracing/services/request-id.provider.js.map +1 -0
- package/dist/tracing/services/trace.injector.d.ts +4 -4
- package/dist/tracing/services/trace.injector.js +1 -132
- package/dist/tracing/services/trace.injector.js.map +1 -1
- package/dist/tracing/tracing.interceptor.d.ts +6 -5
- package/dist/tracing/tracing.interceptor.js +92 -7
- package/dist/tracing/tracing.interceptor.js.map +1 -1
- package/dist/tracing/tracing.module.d.ts +2 -2
- package/dist/tracing/tracing.module.js +8 -9
- package/dist/tracing/tracing.module.js.map +1 -1
- package/package.json +11 -10
- package/src/index.ts +1 -3
- package/src/platform.context.ts +5 -5
- package/src/platform.module.ts +7 -1
- package/src/tracing/auto-instrumentations.config.ts +2 -3
- package/src/tracing/grpc.headers.ts +29 -0
- package/src/tracing/http.headers.ts +32 -0
- package/src/tracing/index.ts +0 -1
- package/src/tracing/open-telemetry.interceptor.ts +114 -0
- package/src/tracing/request-metadata.module.ts +1 -6
- package/src/tracing/services/instrumentation.service.ts +0 -11
- package/src/tracing/services/request-id.provider.ts +21 -0
- package/src/tracing/services/trace.injector.ts +4 -170
- package/src/tracing/tracing.interceptor.ts +131 -5
- package/src/tracing/tracing.module.ts +10 -12
- package/dist/tracing/services/request-metadata.injector.d.ts +0 -6
- package/dist/tracing/services/request-metadata.injector.js +0 -123
- package/dist/tracing/services/request-metadata.injector.js.map +0 -1
- package/dist/tracing/services/request-metadata.storage.d.ts +0 -32
- package/dist/tracing/services/request-metadata.storage.js +0 -64
- package/dist/tracing/services/request-metadata.storage.js.map +0 -1
- package/src/tracing/services/request-metadata.injector.ts +0 -157
- package/src/tracing/services/request-metadata.storage.ts +0 -69
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.RequestMetadataInjector = void 0;
|
|
7
|
-
const decorators_1 = require("@rsdk/decorators");
|
|
8
|
-
const logging_1 = require("@rsdk/logging");
|
|
9
|
-
const node_assert_1 = __importDefault(require("node:assert"));
|
|
10
|
-
const node_crypto_1 = require("node:crypto");
|
|
11
|
-
const constants_1 = require("../constants");
|
|
12
|
-
const request_metadata_storage_1 = require("./request-metadata.storage");
|
|
13
|
-
const logger = logging_1.LoggerFactory.create('RequestMetadataInjector');
|
|
14
|
-
class RequestMetadataInjector {
|
|
15
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
16
|
-
static wrap(cls,
|
|
17
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
18
|
-
original) {
|
|
19
|
-
/**
|
|
20
|
-
* Означает, что данный метод уже обёрнут
|
|
21
|
-
*/
|
|
22
|
-
if (RequestMetadataInjector.isWrapped(original)) {
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
logger.trace(`Wrapping method: ${cls.constructor.name}.${original.name}()`);
|
|
26
|
-
const wrapped = RequestMetadataInjector.createWrapper(original);
|
|
27
|
-
(0, decorators_1.redecorate)(original, wrapped);
|
|
28
|
-
cls[original.name] = wrapped;
|
|
29
|
-
/**
|
|
30
|
-
* Отмечает метод, как обёрнутый (чтобы избежать повторного оборачивания)
|
|
31
|
-
*/
|
|
32
|
-
RequestMetadataInjector.setWrapped(wrapped);
|
|
33
|
-
}
|
|
34
|
-
static createWrapper(original) {
|
|
35
|
-
return {
|
|
36
|
-
[original.name](...args) {
|
|
37
|
-
const executionContext = args[0];
|
|
38
|
-
/**
|
|
39
|
-
* Переменный для хранения значений
|
|
40
|
-
*/
|
|
41
|
-
let requestId;
|
|
42
|
-
/**
|
|
43
|
-
* Переменная для хранения Request/виртуального Request
|
|
44
|
-
*/
|
|
45
|
-
let req;
|
|
46
|
-
/**
|
|
47
|
-
* В зависимости от типа контекста запускаем парсинг переданной Metadata
|
|
48
|
-
*/
|
|
49
|
-
if (executionContext.getType() === 'rpc') {
|
|
50
|
-
const metadata = executionContext.switchToRpc().getContext();
|
|
51
|
-
/**
|
|
52
|
-
* Если мы пришли в GRPC и у нас есть методы для работы с Metadata
|
|
53
|
-
* то мы конвертируем Metadata в некий виртуальный request с заголовками (заголовки выбраны как общий стандарт проброса мета информации)
|
|
54
|
-
*/
|
|
55
|
-
if (metadata?.get) {
|
|
56
|
-
req = {
|
|
57
|
-
headers: {
|
|
58
|
-
/**
|
|
59
|
-
* Пробрасываем текущий ид запроса
|
|
60
|
-
*/
|
|
61
|
-
...(metadata.get(constants_1.X_REQUEST_ID).length > 0
|
|
62
|
-
? {
|
|
63
|
-
[constants_1.X_REQUEST_ID]: metadata.get(constants_1.X_REQUEST_ID)[0],
|
|
64
|
-
}
|
|
65
|
-
: {}),
|
|
66
|
-
},
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
if (executionContext.getType() === 'http') {
|
|
71
|
-
req = executionContext.switchToHttp().getRequest();
|
|
72
|
-
}
|
|
73
|
-
if (executionContext.getType() === 'graphql') {
|
|
74
|
-
req = executionContext.getArgs()[2]?.req; // аналог GqlExecutionContext.create(executionContext).getContext().req
|
|
75
|
-
if (req.connectionInitReceived) {
|
|
76
|
-
/**
|
|
77
|
-
* При работе с сабскрипшен через веб сокет, заголовки передаются в опции подключения к сабскрипшен в переменную connectionParams
|
|
78
|
-
* и мы перегоняем эти данные в request заголовки
|
|
79
|
-
*/
|
|
80
|
-
req.headers = {
|
|
81
|
-
...req?.headers,
|
|
82
|
-
...Object.entries(req?.connectionParams?.headers || {}).reduce((acc, [key, value]) => {
|
|
83
|
-
acc[key] = value;
|
|
84
|
-
return acc;
|
|
85
|
-
}, {}),
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
if (req?.headers) {
|
|
90
|
-
/**
|
|
91
|
-
* Мы приводим все ключи заголовков к одному **lower_case** регистру, так как у разных транспортов разные регистры в именовании ключей для заголовков
|
|
92
|
-
*/
|
|
93
|
-
req.headers = {
|
|
94
|
-
...Object.entries(req.headers).reduce((acc, [key, value]) => {
|
|
95
|
-
acc[key.toLowerCase()] =
|
|
96
|
-
req.headers[key.toLowerCase()] || value;
|
|
97
|
-
return acc;
|
|
98
|
-
}, {}),
|
|
99
|
-
};
|
|
100
|
-
/**
|
|
101
|
-
* Идентификатор запроса, если не передали то генерируем рандомный
|
|
102
|
-
*/
|
|
103
|
-
requestId = req.headers[constants_1.X_REQUEST_ID] || (0, node_crypto_1.randomUUID)();
|
|
104
|
-
}
|
|
105
|
-
return (request_metadata_storage_1.RequestMetadataStorage.getInstance()?.run({ requestId }, async () => {
|
|
106
|
-
return original.apply(this, args);
|
|
107
|
-
}) ?? original.apply(this, args));
|
|
108
|
-
},
|
|
109
|
-
}[original.name];
|
|
110
|
-
}
|
|
111
|
-
static isWrapped(prototype) {
|
|
112
|
-
node_assert_1.default.ok(prototype);
|
|
113
|
-
return Reflect.hasMetadata(constants_1.Constants.REQUEST_METADATA_ASYNC_LOCAL_STORAGE_ACTIVE, prototype);
|
|
114
|
-
}
|
|
115
|
-
static setWrapped(prototype) {
|
|
116
|
-
node_assert_1.default.ok(prototype);
|
|
117
|
-
// Value doesn't matter
|
|
118
|
-
const NOOP = 1;
|
|
119
|
-
Reflect.defineMetadata(constants_1.Constants.REQUEST_METADATA_ASYNC_LOCAL_STORAGE_ACTIVE, NOOP, prototype);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
exports.RequestMetadataInjector = RequestMetadataInjector;
|
|
123
|
-
//# sourceMappingURL=request-metadata.injector.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"request-metadata.injector.js","sourceRoot":"","sources":["../../../src/tracing/services/request-metadata.injector.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
export type RequestMetadata = {
|
|
2
|
-
requestId: string | undefined;
|
|
3
|
-
};
|
|
4
|
-
/**
|
|
5
|
-
* Обертка вокруг `AsyncLocalStorage`
|
|
6
|
-
* В теории можно запустить с пустым `payload`, для того чтобы добавлять
|
|
7
|
-
* значения в процессе
|
|
8
|
-
*/
|
|
9
|
-
export declare class RequestMetadataStorage {
|
|
10
|
-
/**
|
|
11
|
-
* Так как этот сервис используется в разных местах, чтобы не усложнять существующий код путем проксирования модулей и сервисов
|
|
12
|
-
* после создания ложим инстанс в эту статик переменную
|
|
13
|
-
*/
|
|
14
|
-
private static instance;
|
|
15
|
-
private asyncLocalStorage;
|
|
16
|
-
constructor();
|
|
17
|
-
static getInstance(): RequestMetadataStorage | undefined;
|
|
18
|
-
/**
|
|
19
|
-
* Получает новое значение из контекста
|
|
20
|
-
*/
|
|
21
|
-
getRequestMetadata(): RequestMetadata;
|
|
22
|
-
/**
|
|
23
|
-
* Запускает переданную фунцию в контексте
|
|
24
|
-
* @template TResult
|
|
25
|
-
* @template TArgs
|
|
26
|
-
* @param context Контекст исполнения (данные)
|
|
27
|
-
* @param fn Функция для запуска
|
|
28
|
-
* @param args Аргументы функции
|
|
29
|
-
* @returns Результат выполнения функции
|
|
30
|
-
*/
|
|
31
|
-
run<TResult, TArgs extends any[]>(requestMetadata: RequestMetadata, fn: (...args: TArgs) => TResult, ...args: TArgs): TResult;
|
|
32
|
-
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
-
};
|
|
8
|
-
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
-
};
|
|
11
|
-
var RequestMetadataStorage_1;
|
|
12
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
-
exports.RequestMetadataStorage = void 0;
|
|
14
|
-
const common_1 = require("@nestjs/common");
|
|
15
|
-
const node_async_hooks_1 = require("node:async_hooks");
|
|
16
|
-
/**
|
|
17
|
-
* Обертка вокруг `AsyncLocalStorage`
|
|
18
|
-
* В теории можно запустить с пустым `payload`, для того чтобы добавлять
|
|
19
|
-
* значения в процессе
|
|
20
|
-
*/
|
|
21
|
-
let RequestMetadataStorage = class RequestMetadataStorage {
|
|
22
|
-
static { RequestMetadataStorage_1 = this; }
|
|
23
|
-
/**
|
|
24
|
-
* Так как этот сервис используется в разных местах, чтобы не усложнять существующий код путем проксирования модулей и сервисов
|
|
25
|
-
* после создания ложим инстанс в эту статик переменную
|
|
26
|
-
*/
|
|
27
|
-
static instance;
|
|
28
|
-
asyncLocalStorage = new node_async_hooks_1.AsyncLocalStorage();
|
|
29
|
-
constructor() {
|
|
30
|
-
if (!RequestMetadataStorage_1.instance) {
|
|
31
|
-
RequestMetadataStorage_1.instance = this;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
static getInstance() {
|
|
35
|
-
return RequestMetadataStorage_1.instance;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Получает новое значение из контекста
|
|
39
|
-
*/
|
|
40
|
-
getRequestMetadata() {
|
|
41
|
-
return (RequestMetadataStorage_1.instance?.asyncLocalStorage.getStore()
|
|
42
|
-
?.requestMetadata ?? {
|
|
43
|
-
requestId: undefined,
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Запускает переданную фунцию в контексте
|
|
48
|
-
* @template TResult
|
|
49
|
-
* @template TArgs
|
|
50
|
-
* @param context Контекст исполнения (данные)
|
|
51
|
-
* @param fn Функция для запуска
|
|
52
|
-
* @param args Аргументы функции
|
|
53
|
-
* @returns Результат выполнения функции
|
|
54
|
-
*/
|
|
55
|
-
run(requestMetadata, fn, ...args) {
|
|
56
|
-
return (RequestMetadataStorage_1?.instance?.asyncLocalStorage.run({ requestMetadata }, fn, ...args) ?? fn(...args));
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
exports.RequestMetadataStorage = RequestMetadataStorage;
|
|
60
|
-
exports.RequestMetadataStorage = RequestMetadataStorage = RequestMetadataStorage_1 = __decorate([
|
|
61
|
-
(0, common_1.Injectable)(),
|
|
62
|
-
__metadata("design:paramtypes", [])
|
|
63
|
-
], RequestMetadataStorage);
|
|
64
|
-
//# sourceMappingURL=request-metadata.storage.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"request-metadata.storage.js","sourceRoot":"","sources":["../../../src/tracing/services/request-metadata.storage.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,2CAA4C;AAC5C,uDAAqD;AAMrD;;;;GAIG;AAEI,IAAM,sBAAsB,GAA5B,MAAM,sBAAsB;;IACjC;;;OAGG;IACK,MAAM,CAAC,QAAQ,CAAqC;IAEpD,iBAAiB,GAAG,IAAI,oCAAiB,EAE7C,CAAC;IAEL;QACE,IAAI,CAAC,wBAAsB,CAAC,QAAQ,EAAE,CAAC;YACrC,wBAAsB,CAAC,QAAQ,GAAG,IAAI,CAAC;QACzC,CAAC;IACH,CAAC;IAED,MAAM,CAAC,WAAW;QAChB,OAAO,wBAAsB,CAAC,QAAQ,CAAC;IACzC,CAAC;IAED;;OAEG;IACH,kBAAkB;QAChB,OAAO,CACL,wBAAsB,CAAC,QAAQ,EAAE,iBAAiB,CAAC,QAAQ,EAAE;YAC3D,EAAE,eAAe,IAAI;YACrB,SAAS,EAAE,SAAS;SACrB,CACF,CAAC;IACJ,CAAC;IAED;;;;;;;;OAQG;IACH,GAAG,CACD,eAAgC,EAChC,EAA+B,EAC/B,GAAG,IAAW;QAEd,OAAO,CACL,wBAAsB,EAAE,QAAQ,EAAE,iBAAiB,CAAC,GAAG,CACrD,EAAE,eAAe,EAAE,EACnB,EAAE,EACF,GAAG,IAAI,CACR,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,CACjB,CAAC;IACJ,CAAC;CACF,CAAA;AAvDY,wDAAsB;iCAAtB,sBAAsB;IADlC,IAAA,mBAAU,GAAE;;GACA,sBAAsB,CAuDlC"}
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import type { ExecutionContext } from '@nestjs/common';
|
|
2
|
-
import { redecorate } from '@rsdk/decorators';
|
|
3
|
-
import { LoggerFactory } from '@rsdk/logging';
|
|
4
|
-
import assert from 'node:assert';
|
|
5
|
-
import { randomUUID } from 'node:crypto';
|
|
6
|
-
|
|
7
|
-
import { Constants, X_REQUEST_ID } from '../constants';
|
|
8
|
-
|
|
9
|
-
import { RequestMetadataStorage } from './request-metadata.storage';
|
|
10
|
-
|
|
11
|
-
const logger = LoggerFactory.create('RequestMetadataInjector');
|
|
12
|
-
|
|
13
|
-
export class RequestMetadataInjector {
|
|
14
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
15
|
-
static wrap(
|
|
16
|
-
cls: any,
|
|
17
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
18
|
-
original: Function,
|
|
19
|
-
): void {
|
|
20
|
-
/**
|
|
21
|
-
* Означает, что данный метод уже обёрнут
|
|
22
|
-
*/
|
|
23
|
-
if (RequestMetadataInjector.isWrapped(original)) {
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
logger.trace(`Wrapping method: ${cls.constructor.name}.${original.name}()`);
|
|
28
|
-
|
|
29
|
-
const wrapped = RequestMetadataInjector.createWrapper(original);
|
|
30
|
-
|
|
31
|
-
redecorate(original, wrapped);
|
|
32
|
-
|
|
33
|
-
cls[original.name] = wrapped;
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Отмечает метод, как обёрнутый (чтобы избежать повторного оборачивания)
|
|
37
|
-
*/
|
|
38
|
-
RequestMetadataInjector.setWrapped(wrapped);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
private static createWrapper(original: any): any {
|
|
42
|
-
return {
|
|
43
|
-
[original.name](...args: any[]): any {
|
|
44
|
-
const executionContext: ExecutionContext = args[0];
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Переменный для хранения значений
|
|
48
|
-
*/
|
|
49
|
-
let requestId: string | undefined;
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Переменная для хранения Request/виртуального Request
|
|
53
|
-
*/
|
|
54
|
-
let req: any;
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* В зависимости от типа контекста запускаем парсинг переданной Metadata
|
|
58
|
-
*/
|
|
59
|
-
if (executionContext.getType() === 'rpc') {
|
|
60
|
-
const metadata = executionContext.switchToRpc().getContext();
|
|
61
|
-
/**
|
|
62
|
-
* Если мы пришли в GRPC и у нас есть методы для работы с Metadata
|
|
63
|
-
* то мы конвертируем Metadata в некий виртуальный request с заголовками (заголовки выбраны как общий стандарт проброса мета информации)
|
|
64
|
-
*/
|
|
65
|
-
if (metadata?.get) {
|
|
66
|
-
req = {
|
|
67
|
-
headers: {
|
|
68
|
-
/**
|
|
69
|
-
* Пробрасываем текущий ид запроса
|
|
70
|
-
*/
|
|
71
|
-
...(metadata.get(X_REQUEST_ID).length > 0
|
|
72
|
-
? {
|
|
73
|
-
[X_REQUEST_ID]: metadata.get(X_REQUEST_ID)[0],
|
|
74
|
-
}
|
|
75
|
-
: {}),
|
|
76
|
-
},
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (executionContext.getType() === 'http') {
|
|
82
|
-
req = executionContext.switchToHttp().getRequest();
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (executionContext.getType<string>() === 'graphql') {
|
|
86
|
-
req = executionContext.getArgs()[2]?.req; // аналог GqlExecutionContext.create(executionContext).getContext().req
|
|
87
|
-
|
|
88
|
-
if (req.connectionInitReceived) {
|
|
89
|
-
/**
|
|
90
|
-
* При работе с сабскрипшен через веб сокет, заголовки передаются в опции подключения к сабскрипшен в переменную connectionParams
|
|
91
|
-
* и мы перегоняем эти данные в request заголовки
|
|
92
|
-
*/
|
|
93
|
-
req.headers = {
|
|
94
|
-
...req?.headers,
|
|
95
|
-
...Object.entries(req?.connectionParams?.headers || {}).reduce(
|
|
96
|
-
(acc, [key, value]) => {
|
|
97
|
-
acc[key] = value;
|
|
98
|
-
return acc;
|
|
99
|
-
},
|
|
100
|
-
<Record<string, unknown>>{},
|
|
101
|
-
),
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
if (req?.headers) {
|
|
107
|
-
/**
|
|
108
|
-
* Мы приводим все ключи заголовков к одному **lower_case** регистру, так как у разных транспортов разные регистры в именовании ключей для заголовков
|
|
109
|
-
*/
|
|
110
|
-
req.headers = {
|
|
111
|
-
...Object.entries(req.headers).reduce(
|
|
112
|
-
(acc, [key, value]) => {
|
|
113
|
-
acc[key.toLowerCase()] =
|
|
114
|
-
req.headers[key.toLowerCase()] || value;
|
|
115
|
-
return acc;
|
|
116
|
-
},
|
|
117
|
-
<Record<string, unknown>>{},
|
|
118
|
-
),
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Идентификатор запроса, если не передали то генерируем рандомный
|
|
123
|
-
*/
|
|
124
|
-
requestId = req.headers[X_REQUEST_ID] || randomUUID();
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
return (
|
|
128
|
-
RequestMetadataStorage.getInstance()?.run({ requestId }, async () => {
|
|
129
|
-
return original.apply(this, args);
|
|
130
|
-
}) ?? original.apply(this, args)
|
|
131
|
-
);
|
|
132
|
-
},
|
|
133
|
-
}[original.name];
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
private static isWrapped(prototype: object): boolean {
|
|
137
|
-
assert.ok(prototype);
|
|
138
|
-
|
|
139
|
-
return Reflect.hasMetadata(
|
|
140
|
-
Constants.REQUEST_METADATA_ASYNC_LOCAL_STORAGE_ACTIVE,
|
|
141
|
-
prototype,
|
|
142
|
-
);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
private static setWrapped(prototype: object): void {
|
|
146
|
-
assert.ok(prototype);
|
|
147
|
-
|
|
148
|
-
// Value doesn't matter
|
|
149
|
-
const NOOP = 1;
|
|
150
|
-
|
|
151
|
-
Reflect.defineMetadata(
|
|
152
|
-
Constants.REQUEST_METADATA_ASYNC_LOCAL_STORAGE_ACTIVE,
|
|
153
|
-
NOOP,
|
|
154
|
-
prototype,
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import { Injectable } from '@nestjs/common';
|
|
2
|
-
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
3
|
-
|
|
4
|
-
export type RequestMetadata = {
|
|
5
|
-
requestId: string | undefined;
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Обертка вокруг `AsyncLocalStorage`
|
|
10
|
-
* В теории можно запустить с пустым `payload`, для того чтобы добавлять
|
|
11
|
-
* значения в процессе
|
|
12
|
-
*/
|
|
13
|
-
@Injectable()
|
|
14
|
-
export class RequestMetadataStorage {
|
|
15
|
-
/**
|
|
16
|
-
* Так как этот сервис используется в разных местах, чтобы не усложнять существующий код путем проксирования модулей и сервисов
|
|
17
|
-
* после создания ложим инстанс в эту статик переменную
|
|
18
|
-
*/
|
|
19
|
-
private static instance: RequestMetadataStorage | undefined;
|
|
20
|
-
|
|
21
|
-
private asyncLocalStorage = new AsyncLocalStorage<{
|
|
22
|
-
requestMetadata: RequestMetadata;
|
|
23
|
-
}>();
|
|
24
|
-
|
|
25
|
-
constructor() {
|
|
26
|
-
if (!RequestMetadataStorage.instance) {
|
|
27
|
-
RequestMetadataStorage.instance = this;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
static getInstance(): RequestMetadataStorage | undefined {
|
|
32
|
-
return RequestMetadataStorage.instance;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Получает новое значение из контекста
|
|
37
|
-
*/
|
|
38
|
-
getRequestMetadata(): RequestMetadata {
|
|
39
|
-
return (
|
|
40
|
-
RequestMetadataStorage.instance?.asyncLocalStorage.getStore()
|
|
41
|
-
?.requestMetadata ?? {
|
|
42
|
-
requestId: undefined,
|
|
43
|
-
}
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Запускает переданную фунцию в контексте
|
|
49
|
-
* @template TResult
|
|
50
|
-
* @template TArgs
|
|
51
|
-
* @param context Контекст исполнения (данные)
|
|
52
|
-
* @param fn Функция для запуска
|
|
53
|
-
* @param args Аргументы функции
|
|
54
|
-
* @returns Результат выполнения функции
|
|
55
|
-
*/
|
|
56
|
-
run<TResult, TArgs extends any[]>(
|
|
57
|
-
requestMetadata: RequestMetadata,
|
|
58
|
-
fn: (...args: TArgs) => TResult,
|
|
59
|
-
...args: TArgs
|
|
60
|
-
): TResult {
|
|
61
|
-
return (
|
|
62
|
-
RequestMetadataStorage?.instance?.asyncLocalStorage.run(
|
|
63
|
-
{ requestMetadata },
|
|
64
|
-
fn,
|
|
65
|
-
...args,
|
|
66
|
-
) ?? fn(...args)
|
|
67
|
-
);
|
|
68
|
-
}
|
|
69
|
-
}
|