@rsdk/grpc.server 4.0.0-next.3 → 4.0.0-next.5
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 +14 -0
- package/dist/controllers/index.d.ts +2 -0
- package/dist/controllers/index.js +2 -0
- package/dist/controllers/index.js.map +1 -1
- package/dist/controllers/reflection/v1.base.controller.d.ts +32 -0
- package/dist/controllers/reflection/v1.base.controller.js +177 -0
- package/dist/controllers/reflection/v1.base.controller.js.map +1 -0
- package/dist/controllers/reflection/v1.controller.d.ts +10 -0
- package/dist/controllers/reflection/v1.controller.js +25 -0
- package/dist/controllers/reflection/v1.controller.js.map +1 -0
- package/dist/controllers/reflection/v1alpha.controller.d.ts +10 -0
- package/dist/controllers/reflection/v1alpha.controller.js +25 -0
- package/dist/controllers/reflection/v1alpha.controller.js.map +1 -0
- package/dist/grpc.config.d.ts +1 -0
- package/dist/grpc.config.js +8 -0
- package/dist/grpc.config.js.map +1 -1
- package/dist/grpc.transport.d.ts +13 -1
- package/dist/grpc.transport.js +40 -9
- package/dist/grpc.transport.js.map +1 -1
- package/dist/grpc.utils.d.ts +9 -0
- package/dist/grpc.utils.js +18 -0
- package/dist/grpc.utils.js.map +1 -0
- package/dist/reflection.module.d.ts +5 -0
- package/dist/reflection.module.js +33 -0
- package/dist/reflection.module.js.map +1 -0
- package/dist/reflection.service.d.ts +43 -0
- package/dist/reflection.service.js +151 -0
- package/dist/reflection.service.js.map +1 -0
- package/jest.config.js +11 -0
- package/package.json +7 -6
- package/src/controllers/index.ts +2 -0
- package/src/controllers/reflection/v1.base.controller.ts +173 -0
- package/src/controllers/reflection/v1.controller.ts +25 -0
- package/src/controllers/reflection/v1alpha.controller.ts +25 -0
- package/src/grpc.config.ts +7 -0
- package/src/grpc.transport.ts +51 -15
- package/src/grpc.utils.ts +20 -0
- package/src/reflection.module.ts +26 -0
- package/src/reflection.service.spec.ts +86 -0
- package/src/reflection.service.ts +210 -0
|
@@ -0,0 +1,151 @@
|
|
|
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 __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
15
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
16
|
+
};
|
|
17
|
+
var ReflectionService_1;
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.ReflectionService = void 0;
|
|
20
|
+
const protobuf_1 = require("@bufbuild/protobuf");
|
|
21
|
+
const common_1 = require("@nestjs/common");
|
|
22
|
+
const grpc_health_v1_1 = __importDefault(require("@rsdk/builtin-contract/dist/grpc.health.v1"));
|
|
23
|
+
const grpc_metrics_v1_1 = __importDefault(require("@rsdk/builtin-contract/dist/grpc.metrics.v1"));
|
|
24
|
+
const grpc_reflection_v1_1 = __importDefault(require("@rsdk/builtin-contract/dist/grpc.reflection.v1"));
|
|
25
|
+
const grpc_reflection_v1alpha_1 = __importDefault(require("@rsdk/builtin-contract/dist/grpc.reflection.v1alpha"));
|
|
26
|
+
const logging_1 = require("@rsdk/logging");
|
|
27
|
+
let ReflectionService = ReflectionService_1 = class ReflectionService {
|
|
28
|
+
packages;
|
|
29
|
+
services = new Set();
|
|
30
|
+
files = [];
|
|
31
|
+
logger = logging_1.LoggerFactory.create(ReflectionService_1);
|
|
32
|
+
constructor(packages) {
|
|
33
|
+
this.packages = packages;
|
|
34
|
+
}
|
|
35
|
+
onModuleInit() {
|
|
36
|
+
const allPackages = [
|
|
37
|
+
...this.packages,
|
|
38
|
+
grpc_health_v1_1.default,
|
|
39
|
+
grpc_metrics_v1_1.default,
|
|
40
|
+
grpc_reflection_v1_1.default,
|
|
41
|
+
grpc_reflection_v1alpha_1.default,
|
|
42
|
+
];
|
|
43
|
+
const allPackagesNames = new Set(allPackages.map((pkg) => pkg.name));
|
|
44
|
+
for (const pkg of allPackages) {
|
|
45
|
+
if (pkg.descriptor) {
|
|
46
|
+
for (const service of Object.keys(pkg.definitions['grpc-js'])) {
|
|
47
|
+
this.logger.info(`GRPC descriptor loaded for service: ${pkg.name}.${service}`);
|
|
48
|
+
}
|
|
49
|
+
for (const file of protobuf_1.FileDescriptorSet.fromBinary(pkg.descriptor).file) {
|
|
50
|
+
this.files.push(file);
|
|
51
|
+
if (allPackagesNames.has(`${file.package}`)) {
|
|
52
|
+
for (const service of file.service) {
|
|
53
|
+
this.services.add(`${file.package}.${service.name}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* List the full names of registered gRPC services
|
|
62
|
+
*
|
|
63
|
+
* note: the spec is unclear as to what the 'listServices' param can be; most
|
|
64
|
+
* clients seem to only pass '*' but unsure if this should behave like a
|
|
65
|
+
* filter. Until we know how this should behave with different inputs this
|
|
66
|
+
* just always returns *all* services.
|
|
67
|
+
*
|
|
68
|
+
* @returns full-qualified service names (eg. 'sample.SampleService')
|
|
69
|
+
*/
|
|
70
|
+
listServices() {
|
|
71
|
+
return [...this.services];
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Find the proto file(s) that declares the given fully-qualified symbol name
|
|
75
|
+
*
|
|
76
|
+
* @param symbol fully-qualified name of the symbol to lookup
|
|
77
|
+
* (e.g. package.service[.method] or package.type)
|
|
78
|
+
*
|
|
79
|
+
* @returns descriptors of the file which contains this symbol and its imports
|
|
80
|
+
*/
|
|
81
|
+
fileBySymbol(symbol) {
|
|
82
|
+
const file = this.files.find((file) => this.findSymbol(symbol, file));
|
|
83
|
+
if (file) {
|
|
84
|
+
return Buffer.from(file.toBinary());
|
|
85
|
+
}
|
|
86
|
+
throw new Error(`symbol: ${symbol} not found`);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Find a proto file by the file name
|
|
90
|
+
* @returns descriptors of the file which contains this symbol and its imports
|
|
91
|
+
*/
|
|
92
|
+
fileByName(filename) {
|
|
93
|
+
const file = this.files.find((file) => file.name === filename);
|
|
94
|
+
if (file) {
|
|
95
|
+
return Buffer.from(file.toBinary());
|
|
96
|
+
}
|
|
97
|
+
throw new Error(`file: ${filename} not found`);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Find a proto file containing an extension to a message type
|
|
101
|
+
* @returns descriptors of the file which contains this symbol and its imports
|
|
102
|
+
*/
|
|
103
|
+
fileContainingExtension(containingType, extensionNumber) {
|
|
104
|
+
const extension = this.files.find((file) => {
|
|
105
|
+
const descriptor = this.findSymbol(containingType, file);
|
|
106
|
+
return (descriptor instanceof protobuf_1.DescriptorProto &&
|
|
107
|
+
descriptor.extension.some((extension) => extensionNumber === extension.number));
|
|
108
|
+
});
|
|
109
|
+
if (extension) {
|
|
110
|
+
return Buffer.from(extension.toBinary());
|
|
111
|
+
}
|
|
112
|
+
throw new Error(`containingType: ${containingType}, extensionNumber: ${extensionNumber} not found`);
|
|
113
|
+
}
|
|
114
|
+
allExtensionNumbersOfType(symbol) {
|
|
115
|
+
return [
|
|
116
|
+
...new Set(this.files.flatMap((file) => file.extension.flatMap((_fqn, _file, ext) => ext
|
|
117
|
+
.filter((e) => e.extendee === symbol)
|
|
118
|
+
.flatMap((e) => Number(e.number))))),
|
|
119
|
+
];
|
|
120
|
+
}
|
|
121
|
+
findSymbol(symbol, descriptor, prefix = '') {
|
|
122
|
+
if (descriptor instanceof protobuf_1.FileDescriptorProto) {
|
|
123
|
+
const packageName = descriptor.package;
|
|
124
|
+
const packagePrefix = packageName ? `${packageName}.` : '';
|
|
125
|
+
return (descriptor.messageType.find((type) => this.findSymbol(symbol, type, packagePrefix)) ??
|
|
126
|
+
descriptor.enumType.find((type) => this.findSymbol(symbol, type, packagePrefix)) ??
|
|
127
|
+
descriptor.service.find((type) => this.findSymbol(symbol, type, packagePrefix)));
|
|
128
|
+
}
|
|
129
|
+
const fullName = prefix + descriptor.name;
|
|
130
|
+
if (symbol === fullName) {
|
|
131
|
+
return descriptor;
|
|
132
|
+
}
|
|
133
|
+
if (descriptor instanceof protobuf_1.DescriptorProto) {
|
|
134
|
+
const messagePrefix = `${fullName}.`;
|
|
135
|
+
return (descriptor.nestedType.find((type) => this.findSymbol(symbol, type, messagePrefix)) ??
|
|
136
|
+
descriptor.enumType.find((type) => this.findSymbol(symbol, type, messagePrefix)));
|
|
137
|
+
}
|
|
138
|
+
if (descriptor instanceof protobuf_1.ServiceDescriptorProto) {
|
|
139
|
+
const servicePrefix = `${fullName}.`;
|
|
140
|
+
return descriptor.method.find((method) => this.findSymbol(symbol, method, servicePrefix));
|
|
141
|
+
}
|
|
142
|
+
return undefined;
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
exports.ReflectionService = ReflectionService;
|
|
146
|
+
exports.ReflectionService = ReflectionService = ReflectionService_1 = __decorate([
|
|
147
|
+
(0, common_1.Injectable)(),
|
|
148
|
+
__param(0, (0, common_1.Inject)('GRPC_PACKAGES')),
|
|
149
|
+
__metadata("design:paramtypes", [Array])
|
|
150
|
+
], ReflectionService);
|
|
151
|
+
//# sourceMappingURL=reflection.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reflection.service.js","sourceRoot":"","sources":["../src/reflection.service.ts"],"names":[],"mappings":"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"}
|
package/jest.config.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
2
|
+
const { resolve } = require('node:path');
|
|
3
|
+
|
|
4
|
+
/** @type {import('ts-jest').JestConfigWithTsJest} */
|
|
5
|
+
module.exports = {
|
|
6
|
+
preset: 'ts-jest',
|
|
7
|
+
testEnvironment: 'node',
|
|
8
|
+
|
|
9
|
+
setupFiles: ['dotenv/config'],
|
|
10
|
+
rootDir: resolve(__dirname, 'src'),
|
|
11
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rsdk/grpc.server",
|
|
3
|
-
"version": "4.0.0-next.
|
|
3
|
+
"version": "4.0.0-next.5",
|
|
4
4
|
"description": "Grpc transport for platform, clients and common grpc stuff",
|
|
5
5
|
"license": "Apache License 2.0",
|
|
6
6
|
"publishConfig": {
|
|
@@ -18,18 +18,19 @@
|
|
|
18
18
|
"@nestjs/common": "^10.0.0",
|
|
19
19
|
"@nestjs/core": "^10.0.0",
|
|
20
20
|
"@nestjs/microservices": "^10.0.0",
|
|
21
|
-
"@rsdk/builtin-contract": "^4.0.0-next.
|
|
21
|
+
"@rsdk/builtin-contract": "^4.0.0-next.5",
|
|
22
22
|
"@rsdk/common": "^4.0.0-next.3",
|
|
23
|
-
"@rsdk/core": "^4.0.0-next.
|
|
24
|
-
"@rsdk/grpc.common": "^4.0.0-next.
|
|
25
|
-
"@rsdk/grpc.loader": "^4.0.0-next.
|
|
23
|
+
"@rsdk/core": "^4.0.0-next.5",
|
|
24
|
+
"@rsdk/grpc.common": "^4.0.0-next.5",
|
|
25
|
+
"@rsdk/grpc.loader": "^4.0.0-next.5",
|
|
26
26
|
"@rsdk/logging": "^4.0.0-next.3",
|
|
27
27
|
"nice-grpc": "^2.1.4",
|
|
28
28
|
"reflect-metadata": "^0.1.13",
|
|
29
29
|
"rxjs": "^7.8.1"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
+
"@bufbuild/protobuf": "^1.4.2",
|
|
32
33
|
"nice-grpc-opentelemetry": "^0.1.2"
|
|
33
34
|
},
|
|
34
|
-
"gitHead": "
|
|
35
|
+
"gitHead": "aaccdd91f43b75ceb64b03595e830f558f5aa30c"
|
|
35
36
|
}
|
package/src/controllers/index.ts
CHANGED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import * as grpc from '@grpc/grpc-js';
|
|
2
|
+
import { Inject, NotImplementedException } from '@nestjs/common';
|
|
3
|
+
import type {
|
|
4
|
+
ServerReflectionGrpcController,
|
|
5
|
+
ServerReflectionRequest,
|
|
6
|
+
ServerReflectionResponse,
|
|
7
|
+
} from '@rsdk/builtin-contract/dist/grpc.reflection.v1';
|
|
8
|
+
import { InjectLogger } from '@rsdk/core';
|
|
9
|
+
import { ILogger } from '@rsdk/logging';
|
|
10
|
+
import type { Observable } from 'rxjs';
|
|
11
|
+
import { Subject } from 'rxjs';
|
|
12
|
+
|
|
13
|
+
import { GRPCConfig } from '../../grpc.config';
|
|
14
|
+
import { ReflectionService } from '../../reflection.service';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Base class for alpha and final 'v1' versions of the gRPC reflection API
|
|
18
|
+
*
|
|
19
|
+
* note: the final version of the v1 spec was identical to the alpha version, so
|
|
20
|
+
* this common class is used in order to share logic across multiple controllers
|
|
21
|
+
* (this class itself is *not* a controller). See child classes for actual APIs
|
|
22
|
+
*
|
|
23
|
+
* @see {@link https://github.com/grpc/grpc/blob/master/doc/server-reflection.md}
|
|
24
|
+
*/
|
|
25
|
+
export class BaseV1GrpcReflectionController
|
|
26
|
+
implements ServerReflectionGrpcController
|
|
27
|
+
{
|
|
28
|
+
constructor(
|
|
29
|
+
private readonly config: GRPCConfig,
|
|
30
|
+
@InjectLogger(ReflectionService) private readonly logger: ILogger,
|
|
31
|
+
@Inject(ReflectionService) private readonly service: ReflectionService,
|
|
32
|
+
) {}
|
|
33
|
+
|
|
34
|
+
/** Main method for providing information about the running gRPC server
|
|
35
|
+
*
|
|
36
|
+
* The spec defines this as a single streaming method so that the connection
|
|
37
|
+
* stays open to the same running instance of the server for all follow-up
|
|
38
|
+
* requests. This means that we can keep some kind of state about what we've
|
|
39
|
+
* already to that client or not if we need to.
|
|
40
|
+
*/
|
|
41
|
+
serverReflectionInfo(
|
|
42
|
+
request$: Observable<ServerReflectionRequest>,
|
|
43
|
+
): Observable<ServerReflectionResponse> {
|
|
44
|
+
const response$ = new Subject<ServerReflectionResponse>();
|
|
45
|
+
|
|
46
|
+
request$.subscribe({
|
|
47
|
+
next: this.config.reflection
|
|
48
|
+
? this.resolveReflection(response$)
|
|
49
|
+
: this.reflectionIsDisabled(response$),
|
|
50
|
+
complete: (): void => response$.complete(),
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
return response$.asObservable();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private makeResponse(
|
|
57
|
+
request: ServerReflectionRequest,
|
|
58
|
+
): ServerReflectionResponse {
|
|
59
|
+
if (request.messageRequest?.$case === 'listServices') {
|
|
60
|
+
return this.createServerReflectionResponse(request, {
|
|
61
|
+
$case: 'listServicesResponse',
|
|
62
|
+
listServicesResponse: {
|
|
63
|
+
service: this.service.listServices().map((name) => ({ name })),
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (request.messageRequest?.$case === 'fileContainingSymbol') {
|
|
69
|
+
return this.createServerReflectionResponse(request, {
|
|
70
|
+
$case: 'fileDescriptorResponse',
|
|
71
|
+
fileDescriptorResponse: {
|
|
72
|
+
fileDescriptorProto: [
|
|
73
|
+
this.service.fileBySymbol(
|
|
74
|
+
request.messageRequest.fileContainingSymbol,
|
|
75
|
+
),
|
|
76
|
+
],
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (request.messageRequest?.$case === 'fileByFilename') {
|
|
82
|
+
return this.createServerReflectionResponse(request, {
|
|
83
|
+
$case: 'fileDescriptorResponse',
|
|
84
|
+
fileDescriptorResponse: {
|
|
85
|
+
fileDescriptorProto: [
|
|
86
|
+
this.service.fileByName(request.messageRequest.fileByFilename),
|
|
87
|
+
],
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (request.messageRequest?.$case === 'fileContainingExtension') {
|
|
93
|
+
return this.createServerReflectionResponse(request, {
|
|
94
|
+
$case: 'fileDescriptorResponse',
|
|
95
|
+
fileDescriptorResponse: {
|
|
96
|
+
fileDescriptorProto: [
|
|
97
|
+
this.service.fileContainingExtension(
|
|
98
|
+
request.messageRequest.fileContainingExtension.containingType,
|
|
99
|
+
request.messageRequest.fileContainingExtension.extensionNumber,
|
|
100
|
+
),
|
|
101
|
+
],
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (request.messageRequest?.$case === 'allExtensionNumbersOfType') {
|
|
107
|
+
return this.createServerReflectionResponse(request, {
|
|
108
|
+
$case: 'allExtensionNumbersResponse',
|
|
109
|
+
allExtensionNumbersResponse: {
|
|
110
|
+
baseTypeName: request.messageRequest.allExtensionNumbersOfType,
|
|
111
|
+
extensionNumber: this.service.allExtensionNumbersOfType(
|
|
112
|
+
request.messageRequest.allExtensionNumbersOfType,
|
|
113
|
+
),
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
this.logger.error('NotImplementedException', { request });
|
|
119
|
+
|
|
120
|
+
throw new NotImplementedException(request.messageRequest);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
private createServerReflectionResponse(
|
|
124
|
+
request: ServerReflectionRequest,
|
|
125
|
+
message: ServerReflectionResponse['messageResponse'],
|
|
126
|
+
): ServerReflectionResponse {
|
|
127
|
+
return {
|
|
128
|
+
validHost: request.host,
|
|
129
|
+
originalRequest: request,
|
|
130
|
+
messageResponse: message,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
private resolveReflection(
|
|
135
|
+
response$: Subject<ServerReflectionResponse>,
|
|
136
|
+
): (message: ServerReflectionRequest) => void {
|
|
137
|
+
return (message: ServerReflectionRequest): void => {
|
|
138
|
+
try {
|
|
139
|
+
response$.next(this.makeResponse(message));
|
|
140
|
+
} catch (error) {
|
|
141
|
+
if (error instanceof Error) {
|
|
142
|
+
this.logger.error(error);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const response = this.createServerReflectionResponse(message, {
|
|
146
|
+
$case: 'errorResponse',
|
|
147
|
+
errorResponse: {
|
|
148
|
+
errorCode: grpc.status.UNKNOWN,
|
|
149
|
+
errorMessage: `Failed to process gRPC reflection request: ${error}`,
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
response$.next(response);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
private reflectionIsDisabled(
|
|
159
|
+
response$: Subject<ServerReflectionResponse>,
|
|
160
|
+
): (message: ServerReflectionRequest) => void {
|
|
161
|
+
return (message: ServerReflectionRequest): void => {
|
|
162
|
+
const response = this.createServerReflectionResponse(message, {
|
|
163
|
+
$case: 'errorResponse',
|
|
164
|
+
errorResponse: {
|
|
165
|
+
errorCode: grpc.status.UNAVAILABLE,
|
|
166
|
+
errorMessage: `Reflection is disabled by config`,
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
return response$.next(response);
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ServerReflectionGrpcController,
|
|
3
|
+
ServerReflectionRequest,
|
|
4
|
+
ServerReflectionResponse,
|
|
5
|
+
} from '@rsdk/builtin-contract/dist/grpc.reflection.v1';
|
|
6
|
+
import { ServerReflectionGrpcMethods } from '@rsdk/builtin-contract/dist/grpc.reflection.v1';
|
|
7
|
+
import type { Observable } from 'rxjs';
|
|
8
|
+
|
|
9
|
+
import { BaseV1GrpcReflectionController } from './v1.base.controller';
|
|
10
|
+
|
|
11
|
+
/** Implements the 'v1' (final) version of the gRPC Reflection API spec
|
|
12
|
+
*
|
|
13
|
+
* @see {@link https://github.com/grpc/grpc/blob/master/doc/server-reflection.md}
|
|
14
|
+
*/
|
|
15
|
+
@ServerReflectionGrpcMethods()
|
|
16
|
+
export class ReflectionV1Controller
|
|
17
|
+
extends BaseV1GrpcReflectionController
|
|
18
|
+
implements ServerReflectionGrpcController
|
|
19
|
+
{
|
|
20
|
+
override serverReflectionInfo(
|
|
21
|
+
request: Observable<ServerReflectionRequest>,
|
|
22
|
+
): Observable<ServerReflectionResponse> {
|
|
23
|
+
return super.serverReflectionInfo(request);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ServerReflectionGrpcMethods } from '@rsdk/builtin-contract/dist/grpc.reflection.v1';
|
|
2
|
+
import type {
|
|
3
|
+
ServerReflectionGrpcController,
|
|
4
|
+
ServerReflectionRequest,
|
|
5
|
+
ServerReflectionResponse,
|
|
6
|
+
} from '@rsdk/builtin-contract/dist/grpc.reflection.v1alpha';
|
|
7
|
+
import type { Observable } from 'rxjs';
|
|
8
|
+
|
|
9
|
+
import { BaseV1GrpcReflectionController } from './v1.base.controller';
|
|
10
|
+
|
|
11
|
+
/** Implements the 'v1alpha' version of the gRPC Reflection API spec
|
|
12
|
+
*
|
|
13
|
+
* @see {@link https://github.com/grpc/grpc/blob/master/doc/server-reflection.md}
|
|
14
|
+
*/
|
|
15
|
+
@ServerReflectionGrpcMethods()
|
|
16
|
+
export class ReflectionV1alphaController
|
|
17
|
+
extends BaseV1GrpcReflectionController
|
|
18
|
+
implements ServerReflectionGrpcController
|
|
19
|
+
{
|
|
20
|
+
override serverReflectionInfo(
|
|
21
|
+
request: Observable<ServerReflectionRequest>,
|
|
22
|
+
): Observable<ServerReflectionResponse> {
|
|
23
|
+
return super.serverReflectionInfo(request);
|
|
24
|
+
}
|
|
25
|
+
}
|
package/src/grpc.config.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
} from '@grpc/grpc-js/build/src/constants';
|
|
5
5
|
import { text } from '@rsdk/common';
|
|
6
6
|
import {
|
|
7
|
+
BoolParser,
|
|
7
8
|
Config,
|
|
8
9
|
ConfigSection,
|
|
9
10
|
ConfigTag,
|
|
@@ -36,4 +37,10 @@ export class GRPCConfig extends Config {
|
|
|
36
37
|
description: 'Max gRPC message size (send)',
|
|
37
38
|
})
|
|
38
39
|
readonly maxSend!: number;
|
|
40
|
+
|
|
41
|
+
@Property('GRPC_REFLECTION', new BoolParser(), {
|
|
42
|
+
defaultValue: false,
|
|
43
|
+
description: 'Enable reflection',
|
|
44
|
+
})
|
|
45
|
+
readonly reflection!: boolean;
|
|
39
46
|
}
|
package/src/grpc.transport.ts
CHANGED
|
@@ -2,6 +2,8 @@ import type { Controller } from '@nestjs/common/interfaces';
|
|
|
2
2
|
import type { MicroserviceOptions } from '@nestjs/microservices';
|
|
3
3
|
import HealthGrpcPackage from '@rsdk/builtin-contract/dist/grpc.health.v1';
|
|
4
4
|
import MetricsGrpcPackage from '@rsdk/builtin-contract/dist/grpc.metrics.v1';
|
|
5
|
+
import ReflectionGrpcPackageV1 from '@rsdk/builtin-contract/dist/grpc.reflection.v1';
|
|
6
|
+
import ReflectionGrpcPackageV1alpha from '@rsdk/builtin-contract/dist/grpc.reflection.v1alpha';
|
|
5
7
|
import type { Constructor } from '@rsdk/common';
|
|
6
8
|
import type {
|
|
7
9
|
ConfigContext,
|
|
@@ -9,6 +11,7 @@ import type {
|
|
|
9
11
|
IErrorsSender,
|
|
10
12
|
IErrorsTransformer,
|
|
11
13
|
IMicroserviceTransport,
|
|
14
|
+
NestModuleDefinitions,
|
|
12
15
|
} from '@rsdk/core';
|
|
13
16
|
import { SequenceException } from '@rsdk/core';
|
|
14
17
|
import type { Package } from '@rsdk/grpc.loader';
|
|
@@ -17,10 +20,19 @@ import { LoggerFactory } from '@rsdk/logging';
|
|
|
17
20
|
|
|
18
21
|
import { HealthController, MetricsController } from './controllers';
|
|
19
22
|
import { GRPCConfig } from './grpc.config';
|
|
23
|
+
import { isPackageNotIncluded } from './grpc.utils';
|
|
20
24
|
import { GrpcErrorsFormatter } from './grpc-errors.formatter';
|
|
21
25
|
import { GrpcErrorsSender } from './grpc-errors.sender';
|
|
26
|
+
import { ReflectionModule } from './reflection.module';
|
|
22
27
|
|
|
23
28
|
export class GrpcTransport implements IMicroserviceTransport {
|
|
29
|
+
private readonly systemPackages: Package[] = [
|
|
30
|
+
HealthGrpcPackage,
|
|
31
|
+
MetricsGrpcPackage,
|
|
32
|
+
ReflectionGrpcPackageV1,
|
|
33
|
+
ReflectionGrpcPackageV1alpha,
|
|
34
|
+
];
|
|
35
|
+
|
|
24
36
|
private readonly logger = LoggerFactory.create(GrpcTransport);
|
|
25
37
|
private readonly packages: Package[];
|
|
26
38
|
|
|
@@ -72,17 +84,7 @@ export class GrpcTransport implements IMicroserviceTransport {
|
|
|
72
84
|
}
|
|
73
85
|
|
|
74
86
|
createMicroserviceOptions(): MicroserviceOptions {
|
|
75
|
-
this.
|
|
76
|
-
|
|
77
|
-
const packages = [...this.packages];
|
|
78
|
-
|
|
79
|
-
if (!packages.some((x) => x.name === HealthGrpcPackage.name)) {
|
|
80
|
-
packages.push(HealthGrpcPackage);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (!packages.some((x) => x.name === MetricsGrpcPackage.name)) {
|
|
84
|
-
packages.push(MetricsGrpcPackage);
|
|
85
|
-
}
|
|
87
|
+
const packages = this.getUniquePackages();
|
|
86
88
|
|
|
87
89
|
for (const pkg of packages) {
|
|
88
90
|
for (const service of Object.keys(pkg.definitions['grpc-js'])) {
|
|
@@ -90,14 +92,22 @@ export class GrpcTransport implements IMicroserviceTransport {
|
|
|
90
92
|
}
|
|
91
93
|
}
|
|
92
94
|
|
|
95
|
+
this.checkIsInitialized();
|
|
96
|
+
this.assertIsDefined(this.address);
|
|
97
|
+
this.assertIsDefined(this.maxRecv);
|
|
98
|
+
this.assertIsDefined(this.maxSend);
|
|
99
|
+
|
|
93
100
|
return createGrpcOptions(packages, {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
maxSend: this.maxSend!,
|
|
101
|
+
address: this.address,
|
|
102
|
+
maxRecv: this.maxRecv,
|
|
103
|
+
maxSend: this.maxSend,
|
|
98
104
|
});
|
|
99
105
|
}
|
|
100
106
|
|
|
107
|
+
modules(): NestModuleDefinitions {
|
|
108
|
+
return [ReflectionModule.forRoot(this.packages)];
|
|
109
|
+
}
|
|
110
|
+
|
|
101
111
|
onStart(): void {
|
|
102
112
|
this.checkIsInitialized();
|
|
103
113
|
|
|
@@ -109,4 +119,30 @@ export class GrpcTransport implements IMicroserviceTransport {
|
|
|
109
119
|
throw new SequenceException('You should call init() method first!');
|
|
110
120
|
}
|
|
111
121
|
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Checks the value must be defined and not null
|
|
125
|
+
* @param value any value
|
|
126
|
+
*/
|
|
127
|
+
private assertIsDefined<T>(value: T): asserts value is NonNullable<T> {
|
|
128
|
+
if (value === undefined || value === null) {
|
|
129
|
+
throw new Error(`${value} is not defined`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Merge user packages with system packages
|
|
135
|
+
* @returns array of unique packages
|
|
136
|
+
*/
|
|
137
|
+
private getUniquePackages(): Package[] {
|
|
138
|
+
const packages = [...this.packages];
|
|
139
|
+
|
|
140
|
+
for (const pkg of this.systemPackages) {
|
|
141
|
+
if (isPackageNotIncluded(packages, pkg)) {
|
|
142
|
+
packages.push(pkg);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return packages;
|
|
147
|
+
}
|
|
112
148
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Match packages name
|
|
3
|
+
* @param pkg
|
|
4
|
+
* @returns true if names is equal
|
|
5
|
+
*/
|
|
6
|
+
const isEqualPackageName =
|
|
7
|
+
<T extends { name: string }>(pkg: T) =>
|
|
8
|
+
(x: T): boolean =>
|
|
9
|
+
x.name === pkg.name;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Checks whether a pkg is in the array
|
|
13
|
+
* @param packages array of packages
|
|
14
|
+
* @param pkg package you are looking for
|
|
15
|
+
* @returns true if pkg exists in packages
|
|
16
|
+
*/
|
|
17
|
+
export const isPackageNotIncluded = <T extends { name: string }>(
|
|
18
|
+
packages: T[],
|
|
19
|
+
pkg: T,
|
|
20
|
+
): boolean => !packages.some(isEqualPackageName(pkg));
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { DynamicModule } from '@nestjs/common';
|
|
2
|
+
import { Module } from '@nestjs/common';
|
|
3
|
+
import type { Package } from '@rsdk/grpc.loader';
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
ReflectionV1alphaController,
|
|
7
|
+
ReflectionV1Controller,
|
|
8
|
+
} from './controllers';
|
|
9
|
+
import { ReflectionService } from './reflection.service';
|
|
10
|
+
|
|
11
|
+
@Module({})
|
|
12
|
+
export class ReflectionModule {
|
|
13
|
+
static forRoot(packages: Package[]): DynamicModule {
|
|
14
|
+
return {
|
|
15
|
+
module: ReflectionModule,
|
|
16
|
+
controllers: [ReflectionV1alphaController, ReflectionV1Controller],
|
|
17
|
+
providers: [
|
|
18
|
+
ReflectionService,
|
|
19
|
+
{
|
|
20
|
+
provide: 'GRPC_PACKAGES',
|
|
21
|
+
useValue: packages,
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
}
|