@conduitplatform/module-tools 0.16.5 → 0.16.6
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/classes/ConduitServiceModule.d.ts +1 -1
- package/dist/index.cjs +1776 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.esm.js +1749 -0
- package/dist/index.esm.js.map +1 -0
- package/package.json +24 -5
- package/dist/ManagedModule.js +0 -221
- package/dist/ManagedModule.js.map +0 -1
- package/dist/classes/ConduitActiveSchema.js +0 -44
- package/dist/classes/ConduitActiveSchema.js.map +0 -1
- package/dist/classes/ConduitServiceModule.js +0 -110
- package/dist/classes/ConduitServiceModule.js.map +0 -1
- package/dist/classes/ConfigController.js +0 -16
- package/dist/classes/ConfigController.js.map +0 -1
- package/dist/classes/GrpcServer.js +0 -121
- package/dist/classes/GrpcServer.js.map +0 -1
- package/dist/classes/index.js +0 -5
- package/dist/classes/index.js.map +0 -1
- package/dist/helpers/GrpcHelper.js +0 -38
- package/dist/helpers/GrpcHelper.js.map +0 -1
- package/dist/helpers/GrpcToParsedRouterRequest.js +0 -15
- package/dist/helpers/GrpcToParsedRouterRequest.js.map +0 -1
- package/dist/helpers/TypeHelpers.js +0 -79
- package/dist/helpers/TypeHelpers.js.map +0 -1
- package/dist/helpers/index.js +0 -5
- package/dist/helpers/index.js.map +0 -1
- package/dist/helpers/wrapGrpcFunctions.js +0 -48
- package/dist/helpers/wrapGrpcFunctions.js.map +0 -1
- package/dist/index.js +0 -7
- package/dist/index.js.map +0 -1
- package/dist/interfaces/ConduitService.js +0 -2
- package/dist/interfaces/ConduitService.js.map +0 -1
- package/dist/interfaces/ModuleLifecycleStage.js +0 -9
- package/dist/interfaces/ModuleLifecycleStage.js.map +0 -1
- package/dist/interfaces/index.js +0 -3
- package/dist/interfaces/index.js.map +0 -1
- package/dist/logging/index.js +0 -124
- package/dist/logging/index.js.map +0 -1
- package/dist/metrics/MetricsServer.js +0 -42
- package/dist/metrics/MetricsServer.js.map +0 -1
- package/dist/metrics/clientMiddleware.js +0 -120
- package/dist/metrics/clientMiddleware.js.map +0 -1
- package/dist/metrics/config/defaults.js +0 -91
- package/dist/metrics/config/defaults.js.map +0 -1
- package/dist/metrics/index.js +0 -109
- package/dist/metrics/index.js.map +0 -1
- package/dist/routing/ProxyRouteBuilder.js +0 -74
- package/dist/routing/ProxyRouteBuilder.js.map +0 -1
- package/dist/routing/RouteBuilder.js +0 -100
- package/dist/routing/RouteBuilder.js.map +0 -1
- package/dist/routing/RoutingController.js +0 -21
- package/dist/routing/RoutingController.js.map +0 -1
- package/dist/routing/RoutingManager.js +0 -140
- package/dist/routing/RoutingManager.js.map +0 -1
- package/dist/routing/RoutingUtilities.js +0 -9
- package/dist/routing/RoutingUtilities.js.map +0 -1
- package/dist/routing/index.js +0 -6
- package/dist/routing/index.js.map +0 -1
- package/dist/routing/wrapRouterFunctions.js +0 -120
- package/dist/routing/wrapRouterFunctions.js.map +0 -1
- package/dist/utilities/convictConfigParser.js +0 -14
- package/dist/utilities/convictConfigParser.js.map +0 -1
- package/dist/utilities/index.js +0 -4
- package/dist/utilities/index.js.map +0 -1
- package/dist/utilities/initializeSdk.js +0 -35
- package/dist/utilities/initializeSdk.js.map +0 -1
- package/dist/utilities/linearBackoffTimeout.js +0 -57
- package/dist/utilities/linearBackoffTimeout.js.map +0 -1
- package/dist/utilities/merge.js +0 -11
- package/dist/utilities/merge.js.map +0 -1
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,1776 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var ConduitGrpcSdk = require('@conduitplatform/grpc-sdk');
|
|
4
|
+
var grpcJs = require('@grpc/grpc-js');
|
|
5
|
+
var protoLoader = require('@grpc/proto-loader');
|
|
6
|
+
var fastJwt = require('fast-jwt');
|
|
7
|
+
var lodashEs = require('lodash-es');
|
|
8
|
+
var path = require('path');
|
|
9
|
+
var events = require('events');
|
|
10
|
+
var node_url = require('node:url');
|
|
11
|
+
var convict = require('convict');
|
|
12
|
+
var winston = require('winston');
|
|
13
|
+
var http = require('http');
|
|
14
|
+
var LokiTransport = require('winston-loki');
|
|
15
|
+
var timers = require('timers');
|
|
16
|
+
var promClient = require('prom-client');
|
|
17
|
+
var express = require('express');
|
|
18
|
+
var abortControllerX = require('abort-controller-x');
|
|
19
|
+
var niceGrpcCommon = require('nice-grpc-common');
|
|
20
|
+
|
|
21
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
22
|
+
class ConduitActiveSchema extends ConduitGrpcSdk.ConduitSchema {
|
|
23
|
+
dbInstance;
|
|
24
|
+
constructor(dbInstance, name, fields, modelOptions, collectionName) {
|
|
25
|
+
super(name, fields ?? {}, modelOptions, collectionName);
|
|
26
|
+
this.dbInstance = dbInstance;
|
|
27
|
+
}
|
|
28
|
+
findOne(query, select, populate, userId, scope) {
|
|
29
|
+
return this.dbInstance.findOne(this.name, query, select, populate, userId, scope);
|
|
30
|
+
}
|
|
31
|
+
findMany(query, select, skip, limit, sort, populate, userId, scope) {
|
|
32
|
+
return this.dbInstance.findMany(this.name, query, select, skip, limit, sort, populate, userId, scope);
|
|
33
|
+
}
|
|
34
|
+
create(query, userId, scope) {
|
|
35
|
+
return this.dbInstance.create(this.name, query, userId, scope);
|
|
36
|
+
}
|
|
37
|
+
createMany(query, userId, scope) {
|
|
38
|
+
return this.dbInstance.createMany(this.name, query, userId, scope);
|
|
39
|
+
}
|
|
40
|
+
findByIdAndUpdate(id, document, populate, userId, scope) {
|
|
41
|
+
return this.dbInstance.findByIdAndUpdate(this.name, id, document, populate, userId, scope);
|
|
42
|
+
}
|
|
43
|
+
findByIdAndReplace(id, document, populate, userId, scope) {
|
|
44
|
+
return this.dbInstance.findByIdAndReplace(this.name, id, document, populate, userId, scope);
|
|
45
|
+
}
|
|
46
|
+
replaceOne(filterQuery, query, populate, userId, scope) {
|
|
47
|
+
return this.dbInstance.replaceOne(this.name, filterQuery, query, populate, userId, scope);
|
|
48
|
+
}
|
|
49
|
+
updateOne(filterQuery, query, populate, userId, scope) {
|
|
50
|
+
return this.dbInstance.updateOne(this.name, filterQuery, query, populate, userId, scope);
|
|
51
|
+
}
|
|
52
|
+
updateMany(filterQuery, query, populate, userId, scope) {
|
|
53
|
+
return this.dbInstance.updateMany(this.name, filterQuery, query, populate, userId, scope);
|
|
54
|
+
}
|
|
55
|
+
deleteOne(query, userId, scope) {
|
|
56
|
+
return this.dbInstance.deleteOne(this.name, query, userId, scope);
|
|
57
|
+
}
|
|
58
|
+
deleteMany(query, userId, scope) {
|
|
59
|
+
return this.dbInstance.deleteMany(this.name, query, userId, scope);
|
|
60
|
+
}
|
|
61
|
+
countDocuments(query, userId, scope) {
|
|
62
|
+
return this.dbInstance.countDocuments(this.name, query, userId, scope);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
class ConduitStringConstructor {
|
|
67
|
+
// private to disallow creating other instances of this type
|
|
68
|
+
constructor() { }
|
|
69
|
+
static get Optional() {
|
|
70
|
+
return ConduitGrpcSdk.TYPE.String;
|
|
71
|
+
}
|
|
72
|
+
static get Required() {
|
|
73
|
+
return { type: ConduitGrpcSdk.TYPE.String, required: true };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const ConduitString = ConduitStringConstructor;
|
|
77
|
+
class ConduitNumberConstructor {
|
|
78
|
+
// private to disallow creating other instances of this type
|
|
79
|
+
constructor() { }
|
|
80
|
+
static get Optional() {
|
|
81
|
+
return ConduitGrpcSdk.TYPE.Number;
|
|
82
|
+
}
|
|
83
|
+
static get Required() {
|
|
84
|
+
return { type: ConduitGrpcSdk.TYPE.Number, required: true };
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const ConduitNumber = ConduitNumberConstructor;
|
|
88
|
+
class ConduitBooleanConstructor {
|
|
89
|
+
// private to disallow creating other instances of this type
|
|
90
|
+
constructor() { }
|
|
91
|
+
static get Optional() {
|
|
92
|
+
return ConduitGrpcSdk.TYPE.Boolean;
|
|
93
|
+
}
|
|
94
|
+
static get Required() {
|
|
95
|
+
return { type: ConduitGrpcSdk.TYPE.Boolean, required: true };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const ConduitBoolean = ConduitBooleanConstructor;
|
|
99
|
+
class ConduitDateConstructor {
|
|
100
|
+
// private to disallow creating other instances of this type
|
|
101
|
+
constructor() { }
|
|
102
|
+
static get Optional() {
|
|
103
|
+
return ConduitGrpcSdk.TYPE.Date;
|
|
104
|
+
}
|
|
105
|
+
static get Required() {
|
|
106
|
+
return { type: ConduitGrpcSdk.TYPE.Date, required: true };
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const ConduitDate = ConduitDateConstructor;
|
|
110
|
+
class ConduitObjectIdConstructor {
|
|
111
|
+
// private to disallow creating other instances of this type
|
|
112
|
+
constructor() { }
|
|
113
|
+
static get Optional() {
|
|
114
|
+
return ConduitGrpcSdk.TYPE.ObjectId;
|
|
115
|
+
}
|
|
116
|
+
static get Required() {
|
|
117
|
+
return { type: ConduitGrpcSdk.TYPE.ObjectId, required: true };
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const ConduitObjectId = ConduitObjectIdConstructor;
|
|
121
|
+
class ConduitJSONConstructor {
|
|
122
|
+
// private to disallow creating other instances of this type
|
|
123
|
+
constructor() { }
|
|
124
|
+
static get Optional() {
|
|
125
|
+
return ConduitGrpcSdk.TYPE.JSON;
|
|
126
|
+
}
|
|
127
|
+
static get Required() {
|
|
128
|
+
return { type: ConduitGrpcSdk.TYPE.JSON, required: true };
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const ConduitJson = ConduitJSONConstructor;
|
|
132
|
+
class ConduitRelationConstructor {
|
|
133
|
+
// private to disallow creating other instances of this type
|
|
134
|
+
constructor() { }
|
|
135
|
+
static Optional(model) {
|
|
136
|
+
return { type: ConduitGrpcSdk.TYPE.Relation, model, required: false };
|
|
137
|
+
}
|
|
138
|
+
static Required(model) {
|
|
139
|
+
return { type: ConduitGrpcSdk.TYPE.Relation, model, required: true };
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
const ConduitRelation = ConduitRelationConstructor;
|
|
143
|
+
|
|
144
|
+
function createServer(port) {
|
|
145
|
+
const grpcServer = new grpcJs.Server({
|
|
146
|
+
'grpc.max_receive_message_length': 1024 * 1024 * 100,
|
|
147
|
+
'grpc.max_send_message_length': 1024 * 1024 * 100,
|
|
148
|
+
});
|
|
149
|
+
return new Promise((resolve, reject) => {
|
|
150
|
+
grpcServer.bindAsync(port, grpcJs.ServerCredentials.createInsecure(), (err, port) => {
|
|
151
|
+
if (err) {
|
|
152
|
+
reject(err);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
resolve({
|
|
156
|
+
server: grpcServer,
|
|
157
|
+
port,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
function addServiceToServer(server, protoPath, descriptorObject, functions) {
|
|
164
|
+
const packageDefinition = protoLoader.loadSync(protoPath, {
|
|
165
|
+
keepCase: true,
|
|
166
|
+
longs: String,
|
|
167
|
+
enums: String,
|
|
168
|
+
defaults: true,
|
|
169
|
+
oneofs: true,
|
|
170
|
+
});
|
|
171
|
+
const protoDescriptor = grpcJs.loadPackageDefinition(packageDefinition);
|
|
172
|
+
const objs = descriptorObject.split('.');
|
|
173
|
+
let descObj = protoDescriptor;
|
|
174
|
+
objs.forEach((r) => {
|
|
175
|
+
descObj = descObj[r];
|
|
176
|
+
});
|
|
177
|
+
server.addService(descObj.service, functions);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function wrapGrpcFunctions(functions, postponeRestart) {
|
|
181
|
+
const grpcKey = process.env.GRPC_KEY;
|
|
182
|
+
const wrappedFunctions = {};
|
|
183
|
+
Object.keys(functions).forEach(name => {
|
|
184
|
+
wrappedFunctions[name] = (call, callback) => {
|
|
185
|
+
ConduitGrpcSdk.Metrics?.increment('internal_grpc_requests_total');
|
|
186
|
+
postponeRestart();
|
|
187
|
+
if (grpcKey) {
|
|
188
|
+
const verify = fastJwt.createVerifier({ key: grpcKey });
|
|
189
|
+
const grpcToken = call.metadata.get('grpc-token')[0];
|
|
190
|
+
if (!grpcToken) {
|
|
191
|
+
return throwError(callback, 'No gRPC protection token provided', grpcJs.status.PERMISSION_DENIED);
|
|
192
|
+
}
|
|
193
|
+
try {
|
|
194
|
+
const jwt = verify(grpcToken);
|
|
195
|
+
call.metadata.set('module-name', jwt.moduleName);
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
return throwError(callback, 'Failed to verify gRPC protection token. GRPC_KEY value differs', grpcJs.status.PERMISSION_DENIED);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
let invoked;
|
|
202
|
+
try {
|
|
203
|
+
invoked = functions[name](call, callback);
|
|
204
|
+
}
|
|
205
|
+
catch (error) {
|
|
206
|
+
return throwError(callback, error.message);
|
|
207
|
+
}
|
|
208
|
+
if (typeof invoked?.then === 'function') {
|
|
209
|
+
invoked.then().catch((error) => {
|
|
210
|
+
return throwError(callback, error.message);
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
});
|
|
215
|
+
return wrappedFunctions;
|
|
216
|
+
}
|
|
217
|
+
function throwError(callback, message, code = grpcJs.status.INTERNAL) {
|
|
218
|
+
// Aborting server streams is not yet implemented!
|
|
219
|
+
if (callback) {
|
|
220
|
+
callback({ code, message });
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function createParsedRouterRequest(params, urlParams, queryParams, bodyParams, path, headers, context, cookies) {
|
|
225
|
+
return {
|
|
226
|
+
request: {
|
|
227
|
+
params,
|
|
228
|
+
urlParams: urlParams ?? {},
|
|
229
|
+
queryParams: queryParams ?? {},
|
|
230
|
+
bodyParams: bodyParams ?? {},
|
|
231
|
+
path: path ?? '',
|
|
232
|
+
headers: headers,
|
|
233
|
+
context: context ?? {},
|
|
234
|
+
cookies: cookies ?? {},
|
|
235
|
+
},
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
class GrpcServer {
|
|
240
|
+
grpcServer;
|
|
241
|
+
started = false;
|
|
242
|
+
startedOnce = false;
|
|
243
|
+
_serviceNames = [];
|
|
244
|
+
scheduledRestart;
|
|
245
|
+
_postponeRequests = 0;
|
|
246
|
+
_useForce;
|
|
247
|
+
_services = [];
|
|
248
|
+
constructor(port) {
|
|
249
|
+
this._url = `0.0.0.0:${port ?? '5000'}`;
|
|
250
|
+
}
|
|
251
|
+
async waitForReady() {
|
|
252
|
+
while (!lodashEs.isNil(this.scheduledRestart)) {
|
|
253
|
+
await this.wait(200);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
_url;
|
|
257
|
+
get url() {
|
|
258
|
+
return this._url;
|
|
259
|
+
}
|
|
260
|
+
async createNewServer(useForce = false) {
|
|
261
|
+
if (lodashEs.isNil(this._useForce)) {
|
|
262
|
+
this._useForce = useForce;
|
|
263
|
+
}
|
|
264
|
+
const serverResult = await createServer(this._url);
|
|
265
|
+
this.grpcServer = serverResult.server;
|
|
266
|
+
this._url = this._url.split(':')[0] + ':' + serverResult.port.toString();
|
|
267
|
+
return serverResult.port;
|
|
268
|
+
}
|
|
269
|
+
async addService(protoPath, protoDescription, functions) {
|
|
270
|
+
functions = wrapGrpcFunctions(functions, this.postponeRestart.bind(this));
|
|
271
|
+
if (this._serviceNames.indexOf(protoDescription) !== -1) {
|
|
272
|
+
ConduitGrpcSdk.Logger.log('Service already exists, performing replace');
|
|
273
|
+
this._services[this._serviceNames.indexOf(protoDescription)] = {
|
|
274
|
+
protoPath,
|
|
275
|
+
protoDescription,
|
|
276
|
+
functions,
|
|
277
|
+
};
|
|
278
|
+
this.scheduleRefresh();
|
|
279
|
+
return this;
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
this._services.push({ protoPath, protoDescription, functions });
|
|
283
|
+
this._serviceNames.push(protoDescription);
|
|
284
|
+
if (this.started) {
|
|
285
|
+
ConduitGrpcSdk.Logger.log('Server already started, scheduling refresh..');
|
|
286
|
+
this.scheduleRefresh();
|
|
287
|
+
return this;
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
if (!this.grpcServer) {
|
|
291
|
+
await this.wait(1000);
|
|
292
|
+
}
|
|
293
|
+
addServiceToServer(this.grpcServer, protoPath, protoDescription, functions);
|
|
294
|
+
return this;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
async wait(time) {
|
|
299
|
+
return new Promise((resolve, reject) => {
|
|
300
|
+
const timeout = setTimeout(() => {
|
|
301
|
+
clearTimeout(timeout);
|
|
302
|
+
resolve();
|
|
303
|
+
}, time);
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
async refresh() {
|
|
307
|
+
if (this.started) {
|
|
308
|
+
this.started = false;
|
|
309
|
+
if (this._useForce) {
|
|
310
|
+
this.grpcServer.forceShutdown();
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
//gracefully shutdown so that there are no service disruption
|
|
314
|
+
await new Promise(resolve => this.grpcServer.tryShutdown(() => resolve()));
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
await this.createNewServer();
|
|
318
|
+
this._services.forEach(service => {
|
|
319
|
+
addServiceToServer(this.grpcServer, service.protoPath, service.protoDescription, service.functions);
|
|
320
|
+
});
|
|
321
|
+
if (!this.started && this.startedOnce) {
|
|
322
|
+
this.grpcServer.start();
|
|
323
|
+
this.started = true;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
scheduleRefresh() {
|
|
327
|
+
if (this.scheduledRestart) {
|
|
328
|
+
clearTimeout(this.scheduledRestart);
|
|
329
|
+
}
|
|
330
|
+
const self = this;
|
|
331
|
+
this.scheduledRestart = setTimeout(async () => {
|
|
332
|
+
ConduitGrpcSdk.Logger.log('Begin refresh');
|
|
333
|
+
await self.refresh();
|
|
334
|
+
ConduitGrpcSdk.Logger.log('Refresh complete');
|
|
335
|
+
clearTimeout(self.scheduledRestart);
|
|
336
|
+
self.scheduledRestart = undefined;
|
|
337
|
+
self._postponeRequests = 0;
|
|
338
|
+
}, 2000);
|
|
339
|
+
}
|
|
340
|
+
start() {
|
|
341
|
+
if (this.started) {
|
|
342
|
+
ConduitGrpcSdk.Logger.error('gRPC server is already running!');
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
else if (!this.started && this.startedOnce) {
|
|
346
|
+
ConduitGrpcSdk.Logger.error('gRPC server is down for refresh!');
|
|
347
|
+
}
|
|
348
|
+
this.started = true;
|
|
349
|
+
this.startedOnce = true;
|
|
350
|
+
this.grpcServer?.start();
|
|
351
|
+
}
|
|
352
|
+
postponeRestart() {
|
|
353
|
+
if (!this.scheduledRestart || this._postponeRequests > 5)
|
|
354
|
+
return;
|
|
355
|
+
this._postponeRequests++;
|
|
356
|
+
this.scheduleRefresh();
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
class RouteBuilder {
|
|
361
|
+
manager;
|
|
362
|
+
_options;
|
|
363
|
+
_returns;
|
|
364
|
+
_handler;
|
|
365
|
+
constructor(manager) {
|
|
366
|
+
this.manager = manager;
|
|
367
|
+
this._options = {};
|
|
368
|
+
}
|
|
369
|
+
method(action) {
|
|
370
|
+
this._options.action = action;
|
|
371
|
+
return this;
|
|
372
|
+
}
|
|
373
|
+
name(name) {
|
|
374
|
+
this._options.name = name;
|
|
375
|
+
return this;
|
|
376
|
+
}
|
|
377
|
+
description(description) {
|
|
378
|
+
this._options.description = description;
|
|
379
|
+
return this;
|
|
380
|
+
}
|
|
381
|
+
cacheControl(cache) {
|
|
382
|
+
this._options.cacheControl = cache;
|
|
383
|
+
return this;
|
|
384
|
+
}
|
|
385
|
+
middleware(middleware, allowDuplicates = false) {
|
|
386
|
+
if (!Array.isArray(middleware)) {
|
|
387
|
+
middleware = [middleware];
|
|
388
|
+
}
|
|
389
|
+
if (this._options.middlewares !== undefined &&
|
|
390
|
+
this._options.middlewares?.length !== 0) {
|
|
391
|
+
if (allowDuplicates) {
|
|
392
|
+
this._options.middlewares = this._options.middlewares?.concat(middleware);
|
|
393
|
+
}
|
|
394
|
+
else {
|
|
395
|
+
// add to existing middlewares and filter out potential duplicates
|
|
396
|
+
this._options.middlewares = this._options.middlewares?.concat(middleware.filter(mid => this._options.middlewares?.indexOf(mid) === -1));
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
this._options.middlewares = middleware;
|
|
401
|
+
}
|
|
402
|
+
return this;
|
|
403
|
+
}
|
|
404
|
+
path(path) {
|
|
405
|
+
this._options.path = path;
|
|
406
|
+
return this;
|
|
407
|
+
}
|
|
408
|
+
queryParams(params) {
|
|
409
|
+
this._options.queryParams = params;
|
|
410
|
+
return this;
|
|
411
|
+
}
|
|
412
|
+
urlParams(params) {
|
|
413
|
+
this._options.urlParams = params;
|
|
414
|
+
return this;
|
|
415
|
+
}
|
|
416
|
+
bodyParams(params) {
|
|
417
|
+
this._options.bodyParams = params;
|
|
418
|
+
return this;
|
|
419
|
+
}
|
|
420
|
+
return(name, fields) {
|
|
421
|
+
this._returns = new ConduitGrpcSdk.ConduitRouteReturnDefinition(name, fields);
|
|
422
|
+
return this;
|
|
423
|
+
}
|
|
424
|
+
handler(fn) {
|
|
425
|
+
this._handler = fn;
|
|
426
|
+
return this;
|
|
427
|
+
}
|
|
428
|
+
add() {
|
|
429
|
+
if (!this.manager)
|
|
430
|
+
throw new Error('Builder not setup with manager');
|
|
431
|
+
if (!this._options)
|
|
432
|
+
throw new Error('Cannot build route without options');
|
|
433
|
+
if (!this._options.action)
|
|
434
|
+
throw new Error('Cannot build route without action');
|
|
435
|
+
if (!this._options.path)
|
|
436
|
+
throw new Error('Cannot build route without action');
|
|
437
|
+
if (!this._returns)
|
|
438
|
+
throw new Error('Cannot build route without return');
|
|
439
|
+
if (!this._handler)
|
|
440
|
+
throw new Error('Cannot build route without handler');
|
|
441
|
+
this.manager.route(this._options, this._returns, this._handler);
|
|
442
|
+
}
|
|
443
|
+
build() {
|
|
444
|
+
if (!this._options)
|
|
445
|
+
throw new Error('Cannot build route without options');
|
|
446
|
+
if (!this._options.action)
|
|
447
|
+
throw new Error('Cannot build route without action');
|
|
448
|
+
if (!this._options.path)
|
|
449
|
+
throw new Error('Cannot build route without action');
|
|
450
|
+
if (!this._returns)
|
|
451
|
+
throw new Error('Cannot build route without return');
|
|
452
|
+
if (!this._handler)
|
|
453
|
+
throw new Error('Cannot build route without handler');
|
|
454
|
+
return {
|
|
455
|
+
input: this._options,
|
|
456
|
+
returnType: this._returns,
|
|
457
|
+
handler: this._handler,
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
function generateLog(routerType, routerRequest, requestReceive, call, status) {
|
|
463
|
+
let log = '';
|
|
464
|
+
const latency = Date.now() - requestReceive;
|
|
465
|
+
if (routerRequest) {
|
|
466
|
+
log += `(${routerType}) Request: ${call.request.path}`;
|
|
467
|
+
}
|
|
468
|
+
else {
|
|
469
|
+
log += `(${routerType}) Socket: ${call.request.event} socket: ${call.request.socket}`;
|
|
470
|
+
}
|
|
471
|
+
log += ` ${status ?? '200'} ${latency}`;
|
|
472
|
+
ConduitGrpcSdk.Logger.log(log);
|
|
473
|
+
ConduitGrpcSdk.Metrics?.set('grpc_request_latency_seconds', latency / 1000);
|
|
474
|
+
ConduitGrpcSdk.Metrics?.set(`${routerType}_grpc_request_latency_seconds`, latency / 1000);
|
|
475
|
+
const successStatus = !status || status.toString().charAt(0) === '2';
|
|
476
|
+
ConduitGrpcSdk.Metrics?.increment(`${routerType}_grpc_response_statuses_total`, 1, {
|
|
477
|
+
success: successStatus ? 'true' : 'false',
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
function parseRequestData(data) {
|
|
481
|
+
if (data && data.length !== 0) {
|
|
482
|
+
return JSON.parse(data);
|
|
483
|
+
}
|
|
484
|
+
else {
|
|
485
|
+
return {};
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
function parseResponseData(r, routerRequest, requestReceive, call, callback, responded, routerType) {
|
|
489
|
+
if (responded.did)
|
|
490
|
+
return;
|
|
491
|
+
responded.did = true;
|
|
492
|
+
if (!r) {
|
|
493
|
+
callback({
|
|
494
|
+
code: grpcJs.status.INTERNAL,
|
|
495
|
+
message: 'Handler did not return a response',
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
if (routerRequest) {
|
|
499
|
+
if (typeof r === 'string') {
|
|
500
|
+
callback(null, { result: r });
|
|
501
|
+
}
|
|
502
|
+
else {
|
|
503
|
+
let respObject;
|
|
504
|
+
if (r.removeCookies || r.setCookies) {
|
|
505
|
+
respObject = {
|
|
506
|
+
removeCookies: r.removeCookies,
|
|
507
|
+
setCookies: r.setCookies,
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
if (r.result || r.redirect) {
|
|
511
|
+
callback(null, {
|
|
512
|
+
...respObject,
|
|
513
|
+
redirect: r.redirect ?? undefined,
|
|
514
|
+
result: r.result
|
|
515
|
+
? typeof r.result === 'string'
|
|
516
|
+
? r.result
|
|
517
|
+
: JSON.stringify(r.result)
|
|
518
|
+
: undefined,
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
else {
|
|
522
|
+
callback(null, { ...respObject, result: JSON.stringify(r) });
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
else {
|
|
527
|
+
if (r.hasOwnProperty('data'))
|
|
528
|
+
r.data = JSON.stringify(r.data);
|
|
529
|
+
callback(null, r);
|
|
530
|
+
}
|
|
531
|
+
generateLog(routerType, routerRequest, requestReceive, call, undefined);
|
|
532
|
+
}
|
|
533
|
+
function wrapRouterGrpcFunction(fun, routerType) {
|
|
534
|
+
return (call, callback) => {
|
|
535
|
+
const requestReceive = Date.now();
|
|
536
|
+
let routerRequest = true;
|
|
537
|
+
ConduitGrpcSdk.Metrics?.increment(`${routerType}_grpc_requests_total`);
|
|
538
|
+
try {
|
|
539
|
+
call.request.context = parseRequestData(call.request.context);
|
|
540
|
+
call.request.params = parseRequestData(call.request.params);
|
|
541
|
+
call.request.cookies = parseRequestData(call.request.cookies);
|
|
542
|
+
call.request.urlParams = parseRequestData(call.request.urlParams);
|
|
543
|
+
call.request.queryParams = parseRequestData(call.request.queryParams);
|
|
544
|
+
call.request.bodyParams = parseRequestData(call.request.bodyParams);
|
|
545
|
+
routerRequest = !call.request.hasOwnProperty('event');
|
|
546
|
+
if (routerRequest) {
|
|
547
|
+
call.request.headers = parseRequestData(call.request.headers);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
catch (e) {
|
|
551
|
+
ConduitGrpcSdk.Metrics?.increment(`${routerType}_grpc_errors_total`);
|
|
552
|
+
generateLog(routerType, routerRequest, requestReceive, call, grpcJs.status.INTERNAL);
|
|
553
|
+
ConduitGrpcSdk.Logger.error(e.message ?? 'Something went wrong');
|
|
554
|
+
return callback({
|
|
555
|
+
code: grpcJs.status.INTERNAL,
|
|
556
|
+
message: e.message ?? 'Something went wrong',
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
const responded = { did: false };
|
|
560
|
+
fun(call, r => {
|
|
561
|
+
parseResponseData(r, routerRequest, requestReceive, call, callback, responded, routerType);
|
|
562
|
+
})
|
|
563
|
+
.then(r => parseResponseData(r, routerRequest, requestReceive, call, callback, responded, routerType))
|
|
564
|
+
.catch(error => {
|
|
565
|
+
ConduitGrpcSdk.Metrics?.increment(`${routerType}_grpc_errors_total`);
|
|
566
|
+
generateLog(routerType, routerRequest, requestReceive, call, error.code ?? grpcJs.status.INTERNAL);
|
|
567
|
+
ConduitGrpcSdk.Logger.error(error.message ?? 'Something went wrong');
|
|
568
|
+
callback({
|
|
569
|
+
code: error.code ?? grpcJs.status.INTERNAL,
|
|
570
|
+
message: error.details ?? error.message ?? 'Something went wrong',
|
|
571
|
+
});
|
|
572
|
+
});
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
function wrapFunctionsAsync(functions, routerType) {
|
|
577
|
+
const modifiedFunctions = {};
|
|
578
|
+
Object.keys(functions).forEach(key => {
|
|
579
|
+
modifiedFunctions[key] = wrapRouterGrpcFunction(functions[key], routerType);
|
|
580
|
+
});
|
|
581
|
+
return modifiedFunctions;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
class ProxyRouteBuilder {
|
|
585
|
+
manager;
|
|
586
|
+
_options = { path: '' };
|
|
587
|
+
_proxy = { target: '' };
|
|
588
|
+
constructor(manager) {
|
|
589
|
+
this.manager = manager;
|
|
590
|
+
}
|
|
591
|
+
method(action) {
|
|
592
|
+
this._options.action = action;
|
|
593
|
+
return this;
|
|
594
|
+
}
|
|
595
|
+
path(path) {
|
|
596
|
+
this._options.path = path;
|
|
597
|
+
return this;
|
|
598
|
+
}
|
|
599
|
+
target(target) {
|
|
600
|
+
this._proxy.target = target;
|
|
601
|
+
return this;
|
|
602
|
+
}
|
|
603
|
+
options(options) {
|
|
604
|
+
this._options = options;
|
|
605
|
+
return this;
|
|
606
|
+
}
|
|
607
|
+
proxy(proxy) {
|
|
608
|
+
this._proxy = proxy;
|
|
609
|
+
return this;
|
|
610
|
+
}
|
|
611
|
+
middleware(middleware, allowDuplicates = false) {
|
|
612
|
+
if (!Array.isArray(middleware)) {
|
|
613
|
+
middleware = [middleware];
|
|
614
|
+
}
|
|
615
|
+
if (this._options.middlewares) {
|
|
616
|
+
if (allowDuplicates) {
|
|
617
|
+
this._options.middlewares = this._options.middlewares.concat(middleware);
|
|
618
|
+
}
|
|
619
|
+
else {
|
|
620
|
+
this._options.middlewares = this._options.middlewares.concat(middleware.filter(mid => this._options.middlewares?.indexOf(mid) === -1));
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
else {
|
|
624
|
+
this._options.middlewares = middleware;
|
|
625
|
+
}
|
|
626
|
+
return this;
|
|
627
|
+
}
|
|
628
|
+
add() {
|
|
629
|
+
if (!this.manager)
|
|
630
|
+
throw new Error('Builder not setup with manager');
|
|
631
|
+
if (!this._options.path)
|
|
632
|
+
throw new Error('Cannot build route without path');
|
|
633
|
+
if (!this._proxy.target)
|
|
634
|
+
throw new Error('Cannot build route without target');
|
|
635
|
+
const input = {
|
|
636
|
+
options: this._options,
|
|
637
|
+
proxy: this._proxy,
|
|
638
|
+
};
|
|
639
|
+
this.manager.proxyRoute(input);
|
|
640
|
+
}
|
|
641
|
+
build() {
|
|
642
|
+
if (!this.manager)
|
|
643
|
+
throw new Error('Builder not setup with manager');
|
|
644
|
+
if (!this._options.path)
|
|
645
|
+
throw new Error('Cannot build route without path');
|
|
646
|
+
if (!this._proxy.target)
|
|
647
|
+
throw new Error('Cannot build route without target');
|
|
648
|
+
if (!this._options.action)
|
|
649
|
+
throw new Error('Cannot build route without action');
|
|
650
|
+
return {
|
|
651
|
+
input: {
|
|
652
|
+
options: this._options,
|
|
653
|
+
proxy: this._proxy,
|
|
654
|
+
},
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
class RoutingManager {
|
|
660
|
+
_router;
|
|
661
|
+
_server;
|
|
662
|
+
_moduleRoutes = {};
|
|
663
|
+
_moduleProxyRoutes = {};
|
|
664
|
+
static ClientController;
|
|
665
|
+
static AdminController;
|
|
666
|
+
_routeHandlers = {};
|
|
667
|
+
isAdmin = false;
|
|
668
|
+
constructor(_router, _server) {
|
|
669
|
+
this._router = _router;
|
|
670
|
+
this._server = _server;
|
|
671
|
+
if (_router instanceof ConduitGrpcSdk.Admin) {
|
|
672
|
+
this.isAdmin = true;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
get(path) {
|
|
676
|
+
return new RouteBuilder(this).method(ConduitGrpcSdk.ConduitRouteActions.GET).path(path);
|
|
677
|
+
}
|
|
678
|
+
post(path) {
|
|
679
|
+
return new RouteBuilder(this).method(ConduitGrpcSdk.ConduitRouteActions.POST).path(path);
|
|
680
|
+
}
|
|
681
|
+
delete(path) {
|
|
682
|
+
return new RouteBuilder(this).method(ConduitGrpcSdk.ConduitRouteActions.DELETE).path(path);
|
|
683
|
+
}
|
|
684
|
+
update(path) {
|
|
685
|
+
return new RouteBuilder(this).method(ConduitGrpcSdk.ConduitRouteActions.UPDATE).path(path);
|
|
686
|
+
}
|
|
687
|
+
patch(path) {
|
|
688
|
+
return new RouteBuilder(this).method(ConduitGrpcSdk.ConduitRouteActions.PATCH).path(path);
|
|
689
|
+
}
|
|
690
|
+
proxy() {
|
|
691
|
+
return new ProxyRouteBuilder(this);
|
|
692
|
+
}
|
|
693
|
+
clear() {
|
|
694
|
+
this._moduleRoutes = {};
|
|
695
|
+
this._routeHandlers = {};
|
|
696
|
+
this._moduleProxyRoutes = {};
|
|
697
|
+
}
|
|
698
|
+
middleware(input, handler) {
|
|
699
|
+
const routeObject = this.parseRouteObject({
|
|
700
|
+
options: input,
|
|
701
|
+
grpcFunction: input.name,
|
|
702
|
+
});
|
|
703
|
+
this._moduleRoutes[routeObject.grpcFunction] = routeObject;
|
|
704
|
+
this._routeHandlers[routeObject.grpcFunction] = handler;
|
|
705
|
+
}
|
|
706
|
+
route(input, type, handler) {
|
|
707
|
+
const routeObject = this.parseRouteObject({
|
|
708
|
+
options: input,
|
|
709
|
+
returns: {
|
|
710
|
+
name: type.name,
|
|
711
|
+
fields: JSON.stringify(type.fields),
|
|
712
|
+
},
|
|
713
|
+
grpcFunction: this.generateGrpcName(input),
|
|
714
|
+
});
|
|
715
|
+
this._moduleRoutes[routeObject.grpcFunction] = routeObject;
|
|
716
|
+
this._routeHandlers[routeObject.grpcFunction] = handler;
|
|
717
|
+
}
|
|
718
|
+
proxyRoute(input) {
|
|
719
|
+
const routeObject = this.parseRouteObject({
|
|
720
|
+
options: input,
|
|
721
|
+
});
|
|
722
|
+
this._moduleProxyRoutes[routeObject.options.path + routeObject.proxy.target] =
|
|
723
|
+
routeObject;
|
|
724
|
+
}
|
|
725
|
+
socket(input, events) {
|
|
726
|
+
const eventsObj = {};
|
|
727
|
+
const routeObject = this.parseRouteObject({
|
|
728
|
+
options: input,
|
|
729
|
+
events: '',
|
|
730
|
+
});
|
|
731
|
+
let primary;
|
|
732
|
+
Object.keys(events).forEach((eventName) => {
|
|
733
|
+
if (!primary)
|
|
734
|
+
primary = eventName;
|
|
735
|
+
const event = events[eventName];
|
|
736
|
+
eventsObj[eventName] = {
|
|
737
|
+
grpcFunction: eventName,
|
|
738
|
+
params: JSON.stringify(event.params),
|
|
739
|
+
returns: {
|
|
740
|
+
name: event.returnType?.name ?? '',
|
|
741
|
+
fields: JSON.stringify(event.returnType?.fields),
|
|
742
|
+
},
|
|
743
|
+
};
|
|
744
|
+
this._routeHandlers[eventName] = event.handler;
|
|
745
|
+
});
|
|
746
|
+
routeObject.events = JSON.stringify(eventsObj);
|
|
747
|
+
this._moduleRoutes[primary] = routeObject;
|
|
748
|
+
}
|
|
749
|
+
async registerRoutes() {
|
|
750
|
+
if (Object.keys(this._routeHandlers).length === 0)
|
|
751
|
+
return;
|
|
752
|
+
const modifiedFunctions = wrapFunctionsAsync(this._routeHandlers, this.isAdmin ? 'admin' : 'client');
|
|
753
|
+
if (this.isAdmin) {
|
|
754
|
+
RoutingManager.AdminController.setRoutes(modifiedFunctions);
|
|
755
|
+
}
|
|
756
|
+
else {
|
|
757
|
+
RoutingManager.ClientController.setRoutes(modifiedFunctions);
|
|
758
|
+
}
|
|
759
|
+
const paths = Object.values(this._moduleRoutes);
|
|
760
|
+
return this._router.register(paths);
|
|
761
|
+
}
|
|
762
|
+
generateGrpcName(options) {
|
|
763
|
+
if (options.name) {
|
|
764
|
+
return options.name.charAt(0).toUpperCase() + options.name.slice(1);
|
|
765
|
+
}
|
|
766
|
+
else {
|
|
767
|
+
const name = options.action.charAt(0) +
|
|
768
|
+
options.action.slice(1).toLowerCase() +
|
|
769
|
+
this.extractNameFromPath(options.path);
|
|
770
|
+
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
extractNameFromPath(path) {
|
|
774
|
+
path = path.replace(/[-:]/g, '/');
|
|
775
|
+
return path
|
|
776
|
+
.split('/')
|
|
777
|
+
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
778
|
+
.join('');
|
|
779
|
+
}
|
|
780
|
+
parseRouteObject(routeObject) {
|
|
781
|
+
if (!routeObject.options.middlewares) {
|
|
782
|
+
routeObject.options.middlewares = [];
|
|
783
|
+
}
|
|
784
|
+
for (const option in routeObject.options) {
|
|
785
|
+
if (!routeObject.options.hasOwnProperty(option))
|
|
786
|
+
continue;
|
|
787
|
+
if (option === 'middlewares')
|
|
788
|
+
continue;
|
|
789
|
+
if (typeof routeObject.options[option] === 'string' ||
|
|
790
|
+
routeObject.options[option] instanceof String)
|
|
791
|
+
continue;
|
|
792
|
+
routeObject.options[option] = JSON.stringify(routeObject.options[option]);
|
|
793
|
+
}
|
|
794
|
+
return routeObject;
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
const __filename$2 = node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
799
|
+
const __dirname$2 = path.dirname(__filename$2);
|
|
800
|
+
class ConduitServiceModule {
|
|
801
|
+
_moduleName;
|
|
802
|
+
_serviceName;
|
|
803
|
+
_address; // external address:port of service (LoadBalancer)
|
|
804
|
+
grpcServer;
|
|
805
|
+
events = new events.EventEmitter();
|
|
806
|
+
_serviceHealthState = ConduitGrpcSdk.HealthCheckStatus.SERVING; // default for health-agnostic modules
|
|
807
|
+
constructor(moduleName) {
|
|
808
|
+
this._moduleName = lodashEs.camelCase(moduleName);
|
|
809
|
+
}
|
|
810
|
+
_registered = false;
|
|
811
|
+
set registered(registered) {
|
|
812
|
+
this._registered = registered;
|
|
813
|
+
}
|
|
814
|
+
_port; // port to bring up gRPC service
|
|
815
|
+
get port() {
|
|
816
|
+
return this._port;
|
|
817
|
+
}
|
|
818
|
+
_grpcSdk;
|
|
819
|
+
get grpcSdk() {
|
|
820
|
+
if (!this._grpcSdk)
|
|
821
|
+
throw new Error('grpcSdk not defined yet');
|
|
822
|
+
return this._grpcSdk;
|
|
823
|
+
}
|
|
824
|
+
set grpcSdk(grpcSdk) {
|
|
825
|
+
if (this._grpcSdk)
|
|
826
|
+
throw new Error('grpcSdk already defined');
|
|
827
|
+
this._grpcSdk = grpcSdk;
|
|
828
|
+
}
|
|
829
|
+
get healthState() {
|
|
830
|
+
return this._serviceHealthState;
|
|
831
|
+
}
|
|
832
|
+
updateHealth(state, init = false) {
|
|
833
|
+
if ((state === ConduitGrpcSdk.HealthCheckStatus.UNKNOWN && !init) ||
|
|
834
|
+
state === ConduitGrpcSdk.HealthCheckStatus.SERVICE_UNKNOWN) {
|
|
835
|
+
throw new Error(`Cannot explicitly set gRPC health state to ${ConduitGrpcSdk.HealthCheckStatus[state]}`);
|
|
836
|
+
}
|
|
837
|
+
if (!init) {
|
|
838
|
+
ConduitGrpcSdk.Metrics?.set('module_health_state', state === ConduitGrpcSdk.HealthCheckStatus.SERVING ? 1 : 0);
|
|
839
|
+
}
|
|
840
|
+
if (init) {
|
|
841
|
+
this._serviceHealthState = state;
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
844
|
+
if (this._serviceHealthState !== state) {
|
|
845
|
+
this._serviceHealthState = state;
|
|
846
|
+
// do not emit health updates until registered
|
|
847
|
+
if (this._registered) {
|
|
848
|
+
this.events.emit(`grpc-health-change:${this._serviceName}`, state);
|
|
849
|
+
this._grpcSdk?.config.moduleHealthProbe(this._moduleName, this._address);
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
healthCheck(call, callback) {
|
|
854
|
+
const service = call.request.service.substring(call.request.service.indexOf('.') + 1);
|
|
855
|
+
if (service && service !== this._serviceName) {
|
|
856
|
+
callback(null, {
|
|
857
|
+
status: ConduitGrpcSdk.HealthCheckStatus.SERVICE_UNKNOWN,
|
|
858
|
+
});
|
|
859
|
+
}
|
|
860
|
+
else {
|
|
861
|
+
if (!this._registered) {
|
|
862
|
+
return callback(null, {
|
|
863
|
+
status: ConduitGrpcSdk.HealthCheckResponse_ServingStatus.UNKNOWN,
|
|
864
|
+
});
|
|
865
|
+
}
|
|
866
|
+
callback(null, {
|
|
867
|
+
status: this._serviceHealthState,
|
|
868
|
+
});
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
healthWatch(call) {
|
|
872
|
+
const service = call.request.service.substring(call.request.service.indexOf('.') + 1);
|
|
873
|
+
if (service && service !== this._serviceName) {
|
|
874
|
+
call.write({
|
|
875
|
+
status: ConduitGrpcSdk.HealthCheckStatus.SERVICE_UNKNOWN,
|
|
876
|
+
});
|
|
877
|
+
}
|
|
878
|
+
else {
|
|
879
|
+
this.events.on(`grpc-health-change:${this._serviceName}`, (status) => {
|
|
880
|
+
call.write({
|
|
881
|
+
status: status,
|
|
882
|
+
});
|
|
883
|
+
});
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
async addHealthCheckService() {
|
|
887
|
+
await this.grpcServer.addService(path.resolve(__dirname$2, './grpc_health_check.proto'), 'grpc.health.v1.Health', {
|
|
888
|
+
Check: this.healthCheck.bind(this),
|
|
889
|
+
Watch: this.healthWatch.bind(this),
|
|
890
|
+
});
|
|
891
|
+
}
|
|
892
|
+
async addModuleService() {
|
|
893
|
+
await this.grpcServer.addService(path.resolve(__dirname$2, './module.proto'), 'conduit.module.v1.ConduitModule', {
|
|
894
|
+
SetConfig: this.setConfig.bind(this),
|
|
895
|
+
});
|
|
896
|
+
await this.grpcServer.addService(path.resolve(__dirname$2, './module.proto'), 'conduit.module.v1.ClientRouter', {
|
|
897
|
+
Route: RoutingManager.ClientController.handleRequest.bind(RoutingManager.ClientController),
|
|
898
|
+
SocketRoute: RoutingManager.ClientController.handleRequest.bind(RoutingManager.ClientController),
|
|
899
|
+
});
|
|
900
|
+
await this.grpcServer.addService(path.resolve(__dirname$2, './module.proto'), 'conduit.module.v1.AdminRouter', {
|
|
901
|
+
Route: RoutingManager.AdminController.handleRequest.bind(RoutingManager.AdminController),
|
|
902
|
+
SocketRoute: RoutingManager.AdminController.handleRequest.bind(RoutingManager.AdminController),
|
|
903
|
+
});
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
class ConfigController {
|
|
908
|
+
static instance;
|
|
909
|
+
_config;
|
|
910
|
+
get config() {
|
|
911
|
+
// return copy of config and not the original object;
|
|
912
|
+
return Object.assign({}, this._config);
|
|
913
|
+
}
|
|
914
|
+
set config(config) {
|
|
915
|
+
this._config = config;
|
|
916
|
+
}
|
|
917
|
+
static getInstance() {
|
|
918
|
+
if (!ConfigController.instance) {
|
|
919
|
+
ConfigController.instance = new ConfigController();
|
|
920
|
+
}
|
|
921
|
+
return ConfigController.instance;
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
exports.ModuleLifecycleStage = void 0;
|
|
926
|
+
(function (ModuleLifecycleStage) {
|
|
927
|
+
ModuleLifecycleStage["CREATE_GRPC"] = "creat-grpc-server";
|
|
928
|
+
ModuleLifecycleStage["PRE_SERVER_START"] = "pre-grpc-start";
|
|
929
|
+
ModuleLifecycleStage["SERVER_STARTED"] = "grpc-server-started";
|
|
930
|
+
ModuleLifecycleStage["PRE_REGISTER"] = "pre-register";
|
|
931
|
+
ModuleLifecycleStage["POST_REGISTER"] = "post-register";
|
|
932
|
+
})(exports.ModuleLifecycleStage || (exports.ModuleLifecycleStage = {}));
|
|
933
|
+
|
|
934
|
+
const processMeta = (meta) => {
|
|
935
|
+
if (Array.isArray(meta)) {
|
|
936
|
+
return meta.reduce((message, meta) => `${message} \n ${JSON.stringify(meta, null, 2)}`, '');
|
|
937
|
+
}
|
|
938
|
+
else {
|
|
939
|
+
return JSON.stringify(meta, null, 2);
|
|
940
|
+
}
|
|
941
|
+
};
|
|
942
|
+
const createFormat = (logMeta = true) => {
|
|
943
|
+
return winston.format.combine(winston.format.printf(info => {
|
|
944
|
+
// This will customize the Error Message
|
|
945
|
+
if (info.stack) {
|
|
946
|
+
return `[${info.timestamp}] [${info.level.toUpperCase()}]: ${info.message} ${info.stack}`;
|
|
947
|
+
}
|
|
948
|
+
if (logMeta) {
|
|
949
|
+
return `[${info.timestamp}] [${info.level.toUpperCase()}]: ${info.message} ${!lodashEs.isEmpty(info.meta) ? processMeta(info.meta) : ''}`;
|
|
950
|
+
}
|
|
951
|
+
else {
|
|
952
|
+
return `[${info.timestamp}] [${info.level.toUpperCase()}]: ${info.message}`;
|
|
953
|
+
}
|
|
954
|
+
}));
|
|
955
|
+
};
|
|
956
|
+
const defaultTransport = new winston.transports.Console({
|
|
957
|
+
level: 'debug',
|
|
958
|
+
format: winston.format.combine(winston.format.prettyPrint(), winston.format.errors({ stack: true }), winston.format.timestamp({
|
|
959
|
+
format: 'YYYY-MM-DD HH:mm:ss',
|
|
960
|
+
}), createFormat(false), winston.format.colorize({
|
|
961
|
+
all: true,
|
|
962
|
+
})),
|
|
963
|
+
});
|
|
964
|
+
class ConduitLogger {
|
|
965
|
+
_winston;
|
|
966
|
+
constructor(transports) {
|
|
967
|
+
this._winston = winston.createLogger({
|
|
968
|
+
format: winston.format.combine(winston.format.prettyPrint(), winston.format.errors({ stack: true }), winston.format.timestamp({
|
|
969
|
+
format: 'YYYY-MM-DD HH:mm:ss',
|
|
970
|
+
}), createFormat()),
|
|
971
|
+
transports: transports ? [...transports, defaultTransport] : [defaultTransport],
|
|
972
|
+
});
|
|
973
|
+
}
|
|
974
|
+
get winston() {
|
|
975
|
+
return this._winston;
|
|
976
|
+
}
|
|
977
|
+
addTransport(transport) {
|
|
978
|
+
this._winston.add(transport);
|
|
979
|
+
}
|
|
980
|
+
log(message, level = 'info', cb) {
|
|
981
|
+
return this._winston.log(level, message, cb);
|
|
982
|
+
}
|
|
983
|
+
logObject(object, message = '', level = 'info', cb) {
|
|
984
|
+
return this._winston.log(level, message, object, cb);
|
|
985
|
+
}
|
|
986
|
+
info(message, cb) {
|
|
987
|
+
return this._winston.info(message, cb);
|
|
988
|
+
}
|
|
989
|
+
warn(message, cb) {
|
|
990
|
+
return this._winston.warn(message, cb);
|
|
991
|
+
}
|
|
992
|
+
error(message, cb) {
|
|
993
|
+
if (typeof message === 'object') {
|
|
994
|
+
return this._winston.error(message);
|
|
995
|
+
}
|
|
996
|
+
return this._winston.error(message, cb);
|
|
997
|
+
}
|
|
998
|
+
http(message, cb) {
|
|
999
|
+
return this._winston.http(message, cb);
|
|
1000
|
+
}
|
|
1001
|
+
verbose(message, cb) {
|
|
1002
|
+
return this._winston.verbose(message, cb);
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
async function lokiReadyCheck(lokiUrl) {
|
|
1006
|
+
return new Promise((resolve, reject) => {
|
|
1007
|
+
const data = [];
|
|
1008
|
+
http.get(`${lokiUrl}/ready`, r => {
|
|
1009
|
+
r.on('data', chunk => data.push(chunk));
|
|
1010
|
+
r.on('end', () => {
|
|
1011
|
+
if (Buffer.concat(data).toString() === 'ready\n')
|
|
1012
|
+
resolve();
|
|
1013
|
+
else
|
|
1014
|
+
reject(false);
|
|
1015
|
+
});
|
|
1016
|
+
}).on('error', err => {
|
|
1017
|
+
reject(err.message);
|
|
1018
|
+
});
|
|
1019
|
+
});
|
|
1020
|
+
}
|
|
1021
|
+
async function setupLoki(module, instance) {
|
|
1022
|
+
let lokiUrl = process.env.LOKI_URL;
|
|
1023
|
+
if (lokiUrl && lokiUrl !== '') {
|
|
1024
|
+
if (lokiUrl.endsWith('/'))
|
|
1025
|
+
lokiUrl = lokiUrl.slice(0, -1);
|
|
1026
|
+
const onTry = async () => {
|
|
1027
|
+
return await lokiReadyCheck(lokiUrl)
|
|
1028
|
+
.then(() => {
|
|
1029
|
+
ConduitGrpcSdk.Logger.addTransport(new LokiTransport({
|
|
1030
|
+
level: 'debug',
|
|
1031
|
+
host: lokiUrl,
|
|
1032
|
+
batching: false,
|
|
1033
|
+
replaceTimestamp: true,
|
|
1034
|
+
labels: {
|
|
1035
|
+
module,
|
|
1036
|
+
instance,
|
|
1037
|
+
...(process.env.CONDUIT_NAMESPACE && {
|
|
1038
|
+
namespace: process.env.CONDUIT_NAMESPACE,
|
|
1039
|
+
}),
|
|
1040
|
+
},
|
|
1041
|
+
}));
|
|
1042
|
+
return false;
|
|
1043
|
+
})
|
|
1044
|
+
.catch(() => true); // retry
|
|
1045
|
+
};
|
|
1046
|
+
const onFailure = () => {
|
|
1047
|
+
ConduitGrpcSdk.Logger.error(`Failed to connect to Loki on '${lokiUrl}'`);
|
|
1048
|
+
};
|
|
1049
|
+
await linearBackoffTimeoutAsync(onTry, 250, 15, onFailure, true);
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
class MetricsServer {
|
|
1054
|
+
moduleName;
|
|
1055
|
+
instance;
|
|
1056
|
+
Registry;
|
|
1057
|
+
constructor(moduleName, instance, registry) {
|
|
1058
|
+
this.moduleName = moduleName;
|
|
1059
|
+
this.instance = instance;
|
|
1060
|
+
this.Registry = registry;
|
|
1061
|
+
}
|
|
1062
|
+
initialize() {
|
|
1063
|
+
const server = express();
|
|
1064
|
+
const port = this.getHttpPort();
|
|
1065
|
+
const url = '0.0.0.0:' + port.toString();
|
|
1066
|
+
server.listen(port, () => {
|
|
1067
|
+
ConduitGrpcSdk.Logger.info(`Metrics server listening on: ${url}`);
|
|
1068
|
+
});
|
|
1069
|
+
server.get('/', (req, res) => {
|
|
1070
|
+
return res
|
|
1071
|
+
.status(200)
|
|
1072
|
+
.send(`Conduit Metrics for module: ${this.moduleName}, instance: ${this.instance}`);
|
|
1073
|
+
});
|
|
1074
|
+
server.get('/metrics', async (req, res) => {
|
|
1075
|
+
const metrics = await this.Registry.metrics();
|
|
1076
|
+
return res.status(200).send(metrics);
|
|
1077
|
+
});
|
|
1078
|
+
return server;
|
|
1079
|
+
}
|
|
1080
|
+
getHttpPort() {
|
|
1081
|
+
const value = process.env['METRICS_PORT'];
|
|
1082
|
+
if (!value) {
|
|
1083
|
+
ConduitGrpcSdk.Logger.error(`Metrics HTTP port not set`);
|
|
1084
|
+
process.exit(-1);
|
|
1085
|
+
}
|
|
1086
|
+
const port = parseInt(value, 10);
|
|
1087
|
+
if (lodashEs.isNaN(port) || port < 1 || port > 65535) {
|
|
1088
|
+
ConduitGrpcSdk.Logger.error(`Invalid HTTP port value: ${port}`);
|
|
1089
|
+
process.exit(-1);
|
|
1090
|
+
}
|
|
1091
|
+
return port;
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
var defaultMetrics = {
|
|
1096
|
+
internalGrpcRequests: {
|
|
1097
|
+
type: ConduitGrpcSdk.MetricType.Counter,
|
|
1098
|
+
config: {
|
|
1099
|
+
name: 'internal_grpc_requests_total',
|
|
1100
|
+
help: "Tracks the total number of Conduit's internal gRPC requests",
|
|
1101
|
+
},
|
|
1102
|
+
},
|
|
1103
|
+
clientGrpcRequests: {
|
|
1104
|
+
type: ConduitGrpcSdk.MetricType.Counter,
|
|
1105
|
+
config: {
|
|
1106
|
+
name: 'client_grpc_requests_total',
|
|
1107
|
+
help: 'Tracks the total number of the client gRPC requests',
|
|
1108
|
+
},
|
|
1109
|
+
},
|
|
1110
|
+
adminGrpcRequests: {
|
|
1111
|
+
type: ConduitGrpcSdk.MetricType.Counter,
|
|
1112
|
+
config: {
|
|
1113
|
+
name: 'admin_grpc_requests_total',
|
|
1114
|
+
help: 'Tracks the total number of the admin gRPC requests',
|
|
1115
|
+
},
|
|
1116
|
+
},
|
|
1117
|
+
clientGrpcErrors: {
|
|
1118
|
+
type: ConduitGrpcSdk.MetricType.Counter,
|
|
1119
|
+
config: {
|
|
1120
|
+
name: 'client_grpc_errors_total',
|
|
1121
|
+
help: 'Tracks the total number of client grpc errors',
|
|
1122
|
+
},
|
|
1123
|
+
},
|
|
1124
|
+
adminGrpcErrors: {
|
|
1125
|
+
type: ConduitGrpcSdk.MetricType.Counter,
|
|
1126
|
+
config: {
|
|
1127
|
+
name: 'admin_grpc_errors_total',
|
|
1128
|
+
help: 'Tracks the total number of admin grpc errors',
|
|
1129
|
+
},
|
|
1130
|
+
},
|
|
1131
|
+
moduleHealthState: {
|
|
1132
|
+
type: ConduitGrpcSdk.MetricType.Gauge,
|
|
1133
|
+
config: {
|
|
1134
|
+
name: 'module_health_state',
|
|
1135
|
+
help: 'Tracks the health state of the module',
|
|
1136
|
+
},
|
|
1137
|
+
},
|
|
1138
|
+
grpcRequestLatency: {
|
|
1139
|
+
type: ConduitGrpcSdk.MetricType.Gauge,
|
|
1140
|
+
config: {
|
|
1141
|
+
name: 'grpc_request_latency_seconds',
|
|
1142
|
+
help: 'Tracks the latency of grpc requests in seconds',
|
|
1143
|
+
},
|
|
1144
|
+
},
|
|
1145
|
+
adminGrpcRequestLatency: {
|
|
1146
|
+
type: ConduitGrpcSdk.MetricType.Gauge,
|
|
1147
|
+
config: {
|
|
1148
|
+
name: 'admin_grpc_request_latency_seconds',
|
|
1149
|
+
help: 'Tracks the latency of admin grpc requests in seconds',
|
|
1150
|
+
},
|
|
1151
|
+
},
|
|
1152
|
+
clientGrpcRequestLatency: {
|
|
1153
|
+
type: ConduitGrpcSdk.MetricType.Gauge,
|
|
1154
|
+
config: {
|
|
1155
|
+
name: 'client_grpc_request_latency_seconds',
|
|
1156
|
+
help: 'Tracks the latency of client grpc requests in seconds',
|
|
1157
|
+
},
|
|
1158
|
+
},
|
|
1159
|
+
grpcResponseStatuses: {
|
|
1160
|
+
type: ConduitGrpcSdk.MetricType.Counter,
|
|
1161
|
+
config: {
|
|
1162
|
+
name: 'grpc_response_statuses_total',
|
|
1163
|
+
help: 'Tracks the total number of grpc response codes',
|
|
1164
|
+
labelNames: ['success'],
|
|
1165
|
+
},
|
|
1166
|
+
},
|
|
1167
|
+
adminGrpcResponseStatuses: {
|
|
1168
|
+
type: ConduitGrpcSdk.MetricType.Counter,
|
|
1169
|
+
config: {
|
|
1170
|
+
name: 'admin_grpc_response_statuses_total',
|
|
1171
|
+
help: 'Tracks the total number of admin grpc response codes',
|
|
1172
|
+
labelNames: ['success'],
|
|
1173
|
+
},
|
|
1174
|
+
},
|
|
1175
|
+
clientGrpcResponseStatuses: {
|
|
1176
|
+
type: ConduitGrpcSdk.MetricType.Counter,
|
|
1177
|
+
config: {
|
|
1178
|
+
name: 'client_grpc_response_statuses_total',
|
|
1179
|
+
help: 'Tracks the total number of client grpc response codes',
|
|
1180
|
+
labelNames: ['success'],
|
|
1181
|
+
},
|
|
1182
|
+
},
|
|
1183
|
+
};
|
|
1184
|
+
|
|
1185
|
+
class ConduitMetrics {
|
|
1186
|
+
moduleName;
|
|
1187
|
+
instance;
|
|
1188
|
+
_registry;
|
|
1189
|
+
_httpServer;
|
|
1190
|
+
constructor(moduleName, instance) {
|
|
1191
|
+
this.moduleName = moduleName;
|
|
1192
|
+
this.instance = instance;
|
|
1193
|
+
this._registry = new promClient.Registry();
|
|
1194
|
+
this._registry.setDefaultLabels({
|
|
1195
|
+
module_name: this.moduleName,
|
|
1196
|
+
module_instance: this.instance,
|
|
1197
|
+
});
|
|
1198
|
+
this.collectDefaultMetrics();
|
|
1199
|
+
this._httpServer = new MetricsServer(moduleName, instance, this._registry);
|
|
1200
|
+
this._httpServer.initialize();
|
|
1201
|
+
}
|
|
1202
|
+
initializeDefaultMetrics() {
|
|
1203
|
+
for (const metric of Object.values(defaultMetrics)) {
|
|
1204
|
+
this.registerMetric(metric.type, metric.config);
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
registerMetric(type, config) {
|
|
1208
|
+
if (this.getMetric(config.name))
|
|
1209
|
+
return;
|
|
1210
|
+
const metricConfig = JSON.parse(JSON.stringify(config));
|
|
1211
|
+
metricConfig.name = this.addPrefix(config.name);
|
|
1212
|
+
switch (type) {
|
|
1213
|
+
case ConduitGrpcSdk.MetricType.Counter:
|
|
1214
|
+
this.createCounter(metricConfig);
|
|
1215
|
+
break;
|
|
1216
|
+
case ConduitGrpcSdk.MetricType.Gauge:
|
|
1217
|
+
this.createGauge(metricConfig);
|
|
1218
|
+
break;
|
|
1219
|
+
case ConduitGrpcSdk.MetricType.Histogram:
|
|
1220
|
+
this.createHistogram(metricConfig);
|
|
1221
|
+
break;
|
|
1222
|
+
case ConduitGrpcSdk.MetricType.Summary:
|
|
1223
|
+
this.createSummary(metricConfig);
|
|
1224
|
+
break;
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
collectDefaultMetrics() {
|
|
1228
|
+
promClient.collectDefaultMetrics({
|
|
1229
|
+
register: this._registry,
|
|
1230
|
+
prefix: 'conduit_',
|
|
1231
|
+
// probably not needed
|
|
1232
|
+
labels: {
|
|
1233
|
+
module_name: this.moduleName,
|
|
1234
|
+
instance_instance: this.instance,
|
|
1235
|
+
},
|
|
1236
|
+
});
|
|
1237
|
+
}
|
|
1238
|
+
createCounter(config) {
|
|
1239
|
+
return new promClient.Counter({ ...config, registers: [this._registry] });
|
|
1240
|
+
}
|
|
1241
|
+
createSummary(config) {
|
|
1242
|
+
return new promClient.Summary({ ...config, registers: [this._registry] });
|
|
1243
|
+
}
|
|
1244
|
+
createHistogram(config) {
|
|
1245
|
+
return new promClient.Histogram({ ...config, registers: [this._registry] });
|
|
1246
|
+
}
|
|
1247
|
+
createGauge(config) {
|
|
1248
|
+
return new promClient.Gauge({ ...config, registers: [this._registry] });
|
|
1249
|
+
}
|
|
1250
|
+
getMetric(name) {
|
|
1251
|
+
return this._registry.getSingleMetric(this.addPrefix(name));
|
|
1252
|
+
}
|
|
1253
|
+
increment(metric, increment = 1, labels) {
|
|
1254
|
+
const metricInstance = this._registry.getSingleMetric(this.addPrefix(metric));
|
|
1255
|
+
if (!(metricInstance instanceof promClient.Counter) && !(metricInstance instanceof promClient.Gauge)) {
|
|
1256
|
+
throw new Error(`Metric ${metric} is not an incrementable metric`);
|
|
1257
|
+
}
|
|
1258
|
+
return labels
|
|
1259
|
+
? metricInstance.labels({ ...labels }).inc(increment)
|
|
1260
|
+
: metricInstance.inc(increment);
|
|
1261
|
+
}
|
|
1262
|
+
decrement(metric, decrement = 1, labels) {
|
|
1263
|
+
const metricInstance = this._registry.getSingleMetric(this.addPrefix(metric));
|
|
1264
|
+
if (!(metricInstance instanceof promClient.Gauge)) {
|
|
1265
|
+
throw new Error(`Metric ${metric} is not a decrementable metric`);
|
|
1266
|
+
}
|
|
1267
|
+
return labels
|
|
1268
|
+
? metricInstance.labels({ ...labels }).dec(decrement)
|
|
1269
|
+
: metricInstance.dec(decrement);
|
|
1270
|
+
}
|
|
1271
|
+
set(metric, value, labels) {
|
|
1272
|
+
const metricInstance = this._registry.getSingleMetric(this.addPrefix(metric));
|
|
1273
|
+
if (!(metricInstance instanceof promClient.Gauge)) {
|
|
1274
|
+
throw new Error(`Metric ${metric} is not a Gauge`);
|
|
1275
|
+
}
|
|
1276
|
+
return labels
|
|
1277
|
+
? metricInstance.labels({ ...labels }).set(value)
|
|
1278
|
+
: metricInstance.set(value);
|
|
1279
|
+
}
|
|
1280
|
+
observe(metric, value, labels) {
|
|
1281
|
+
const metricInstance = this._registry.getSingleMetric(this.addPrefix(metric));
|
|
1282
|
+
if (!(metricInstance instanceof promClient.Histogram) && !(metricInstance instanceof promClient.Summary)) {
|
|
1283
|
+
throw new Error(`Metric ${metric} is not a Histogram`);
|
|
1284
|
+
}
|
|
1285
|
+
return labels
|
|
1286
|
+
? metricInstance.labels({ ...labels }).observe(value)
|
|
1287
|
+
: metricInstance.observe(value);
|
|
1288
|
+
}
|
|
1289
|
+
addPrefix(metric) {
|
|
1290
|
+
return `conduit_${metric}`;
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
// Forked from nice-grpc-prometheus
|
|
1295
|
+
const registry = new promClient.Registry();
|
|
1296
|
+
const typeLabel = 'grpc_type';
|
|
1297
|
+
const serviceLabel = 'grpc_service';
|
|
1298
|
+
const methodLabel = 'grpc_method';
|
|
1299
|
+
const pathLabel = 'grpc_path';
|
|
1300
|
+
const codeLabel = 'grpc_code';
|
|
1301
|
+
/**
|
|
1302
|
+
* 1ms, 4ms, 16ms, ..., ~1 hour in seconds
|
|
1303
|
+
*/
|
|
1304
|
+
const latencySecondsBuckets = promClient.exponentialBuckets(0.001, 4, 12);
|
|
1305
|
+
function getLabels(method) {
|
|
1306
|
+
const callType = method.requestStream
|
|
1307
|
+
? method.responseStream
|
|
1308
|
+
? 'bidi_stream'
|
|
1309
|
+
: 'client_stream'
|
|
1310
|
+
: method.responseStream
|
|
1311
|
+
? 'server_stream'
|
|
1312
|
+
: 'unary';
|
|
1313
|
+
const { path } = method;
|
|
1314
|
+
const [serviceName, methodName] = path.split('/').slice(1);
|
|
1315
|
+
return {
|
|
1316
|
+
[typeLabel]: callType,
|
|
1317
|
+
[serviceLabel]: serviceName,
|
|
1318
|
+
[methodLabel]: methodName,
|
|
1319
|
+
[pathLabel]: path,
|
|
1320
|
+
};
|
|
1321
|
+
}
|
|
1322
|
+
async function* incrementStreamMessagesCounter(iterable, counter) {
|
|
1323
|
+
for await (const item of iterable) {
|
|
1324
|
+
counter.inc();
|
|
1325
|
+
yield item;
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
const clientStartedMetric = new promClient.Counter({
|
|
1329
|
+
registers: [registry],
|
|
1330
|
+
name: 'conduit_grpc_client_started_total',
|
|
1331
|
+
help: 'Total number of RPCs started on the client.',
|
|
1332
|
+
labelNames: [typeLabel, serviceLabel, methodLabel, pathLabel],
|
|
1333
|
+
});
|
|
1334
|
+
const clientHandledMetric = new promClient.Counter({
|
|
1335
|
+
registers: [registry],
|
|
1336
|
+
name: 'conduit_grpc_client_handled_total',
|
|
1337
|
+
help: 'Total number of RPCs completed on the client, regardless of success or failure.',
|
|
1338
|
+
labelNames: [typeLabel, serviceLabel, methodLabel, pathLabel, codeLabel],
|
|
1339
|
+
});
|
|
1340
|
+
const clientStreamMsgReceivedMetric = new promClient.Counter({
|
|
1341
|
+
registers: [registry],
|
|
1342
|
+
name: 'conduit_grpc_client_msg_received_total',
|
|
1343
|
+
help: 'Total number of RPC stream messages received by the client.',
|
|
1344
|
+
labelNames: [typeLabel, serviceLabel, methodLabel, pathLabel],
|
|
1345
|
+
});
|
|
1346
|
+
const clientStreamMsgSentMetric = new promClient.Counter({
|
|
1347
|
+
registers: [registry],
|
|
1348
|
+
name: 'conduit_grpc_client_msg_sent_total',
|
|
1349
|
+
help: 'Total number of gRPC stream messages sent by the client.',
|
|
1350
|
+
labelNames: [typeLabel, serviceLabel, methodLabel, pathLabel],
|
|
1351
|
+
});
|
|
1352
|
+
const clientHandlingSecondsMetric = new promClient.Histogram({
|
|
1353
|
+
registers: [registry],
|
|
1354
|
+
name: 'grpc_client_handling_seconds',
|
|
1355
|
+
help: 'Histogram of response latency (seconds) of the gRPC until it is finished by the application.',
|
|
1356
|
+
labelNames: [typeLabel, serviceLabel, methodLabel, pathLabel, codeLabel],
|
|
1357
|
+
buckets: latencySecondsBuckets,
|
|
1358
|
+
});
|
|
1359
|
+
function clientMiddleware() {
|
|
1360
|
+
return async function* prometheusClientMiddlewareGenerator(call, options) {
|
|
1361
|
+
const labels = getLabels(call.method);
|
|
1362
|
+
clientStartedMetric.inc(labels);
|
|
1363
|
+
const stopTimer = clientHandlingSecondsMetric.startTimer(labels);
|
|
1364
|
+
let settled = false;
|
|
1365
|
+
let status = niceGrpcCommon.Status.OK;
|
|
1366
|
+
try {
|
|
1367
|
+
let request;
|
|
1368
|
+
if (!call.requestStream) {
|
|
1369
|
+
request = call.request;
|
|
1370
|
+
}
|
|
1371
|
+
else {
|
|
1372
|
+
request = incrementStreamMessagesCounter(call.request, clientStreamMsgSentMetric.labels(labels));
|
|
1373
|
+
}
|
|
1374
|
+
if (!call.responseStream) {
|
|
1375
|
+
const response = yield* call.next(request, options);
|
|
1376
|
+
settled = true;
|
|
1377
|
+
return response;
|
|
1378
|
+
}
|
|
1379
|
+
else {
|
|
1380
|
+
yield* incrementStreamMessagesCounter(call.next(request, options), clientStreamMsgReceivedMetric.labels(labels));
|
|
1381
|
+
settled = true;
|
|
1382
|
+
return;
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
catch (err) {
|
|
1386
|
+
settled = true;
|
|
1387
|
+
if (err instanceof niceGrpcCommon.ClientError) {
|
|
1388
|
+
status = err.code;
|
|
1389
|
+
}
|
|
1390
|
+
else if (abortControllerX.isAbortError(err)) {
|
|
1391
|
+
status = niceGrpcCommon.Status.ABORTED;
|
|
1392
|
+
}
|
|
1393
|
+
else {
|
|
1394
|
+
status = niceGrpcCommon.Status.UNKNOWN;
|
|
1395
|
+
}
|
|
1396
|
+
throw err;
|
|
1397
|
+
}
|
|
1398
|
+
finally {
|
|
1399
|
+
if (!settled) {
|
|
1400
|
+
status = niceGrpcCommon.Status.CANCELLED;
|
|
1401
|
+
}
|
|
1402
|
+
stopTimer({ [codeLabel]: niceGrpcCommon.Status[status] });
|
|
1403
|
+
clientHandledMetric.inc({
|
|
1404
|
+
...labels,
|
|
1405
|
+
[codeLabel]: niceGrpcCommon.Status[status],
|
|
1406
|
+
});
|
|
1407
|
+
}
|
|
1408
|
+
};
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
const __filename$1 = node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
1412
|
+
const __dirname$1 = path.dirname(__filename$1);
|
|
1413
|
+
const initializeSdk = (coreUrl, moduleName, watchModules = true, serviceHealthStatusGetter = () => ConduitGrpcSdk.HealthCheckStatus.SERVING) => {
|
|
1414
|
+
let logger;
|
|
1415
|
+
try {
|
|
1416
|
+
logger = new ConduitLogger([
|
|
1417
|
+
new winston.transports.File({
|
|
1418
|
+
filename: path.join(__dirname$1, '.logs/combined.log'),
|
|
1419
|
+
level: 'info',
|
|
1420
|
+
}),
|
|
1421
|
+
new winston.transports.File({
|
|
1422
|
+
filename: path.join(__dirname$1, '.logs/errors.log'),
|
|
1423
|
+
level: 'error',
|
|
1424
|
+
}),
|
|
1425
|
+
]);
|
|
1426
|
+
}
|
|
1427
|
+
catch (e) {
|
|
1428
|
+
logger = new ConduitLogger();
|
|
1429
|
+
}
|
|
1430
|
+
const grpcSdk = new ConduitGrpcSdk(coreUrl, moduleName, watchModules, logger, serviceHealthStatusGetter);
|
|
1431
|
+
setupLoki(grpcSdk.name, grpcSdk.instance).then();
|
|
1432
|
+
if (process.env.METRICS_PORT) {
|
|
1433
|
+
ConduitGrpcSdk.Metrics = new ConduitMetrics(grpcSdk.name, grpcSdk.instance);
|
|
1434
|
+
grpcSdk.addMiddleware(clientMiddleware());
|
|
1435
|
+
}
|
|
1436
|
+
return grpcSdk;
|
|
1437
|
+
};
|
|
1438
|
+
|
|
1439
|
+
/**
|
|
1440
|
+
* Registers a timeout with linear backoff.
|
|
1441
|
+
* onFailure() only runs on rep exhaustion.
|
|
1442
|
+
* Timeout can be cleared through returned clear() or inside onTry().
|
|
1443
|
+
*/
|
|
1444
|
+
function linearBackoffTimeout(onTry, delay, reps, onFailure) {
|
|
1445
|
+
const nextRep = () => reps === undefined || --reps > 0;
|
|
1446
|
+
let stopSignal = false;
|
|
1447
|
+
const stop = () => {
|
|
1448
|
+
stopSignal = true;
|
|
1449
|
+
};
|
|
1450
|
+
let timeout;
|
|
1451
|
+
const invoker = async () => {
|
|
1452
|
+
if (stopSignal) {
|
|
1453
|
+
return timeout ? timers.clearTimeout(timeout) : null;
|
|
1454
|
+
}
|
|
1455
|
+
delay = Math.floor(delay * 2);
|
|
1456
|
+
if (delay > 0 && nextRep()) {
|
|
1457
|
+
timeout = setTimeout(invoker, delay);
|
|
1458
|
+
onTry(stop);
|
|
1459
|
+
}
|
|
1460
|
+
else {
|
|
1461
|
+
timeout = null;
|
|
1462
|
+
onFailure && onFailure();
|
|
1463
|
+
}
|
|
1464
|
+
};
|
|
1465
|
+
timeout = setTimeout(invoker, delay);
|
|
1466
|
+
return {
|
|
1467
|
+
clear: () => {
|
|
1468
|
+
if (timeout) {
|
|
1469
|
+
timers.clearTimeout(timeout);
|
|
1470
|
+
timeout = null;
|
|
1471
|
+
}
|
|
1472
|
+
},
|
|
1473
|
+
};
|
|
1474
|
+
}
|
|
1475
|
+
/**
|
|
1476
|
+
* Registers a timeout with linear backoff.
|
|
1477
|
+
* onFailure() only runs on rep exhaustion.
|
|
1478
|
+
* @param {() => Promise<boolean>} onTry - Async handler, returns 'continue' boolean flag
|
|
1479
|
+
*/
|
|
1480
|
+
async function linearBackoffTimeoutAsync(onTry, delay, reps, onFailure, startNow = false) {
|
|
1481
|
+
const nextRep = () => reps === undefined || --reps > 0;
|
|
1482
|
+
const invoker = async () => {
|
|
1483
|
+
delay = Math.floor(delay * 2);
|
|
1484
|
+
if (delay > 0 && nextRep()) {
|
|
1485
|
+
if (await onTry())
|
|
1486
|
+
setTimeout(invoker, delay);
|
|
1487
|
+
}
|
|
1488
|
+
else {
|
|
1489
|
+
onFailure && (await onFailure());
|
|
1490
|
+
}
|
|
1491
|
+
};
|
|
1492
|
+
setTimeout(invoker, startNow ? 0 : delay);
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
function merge(objA, objB) {
|
|
1496
|
+
const customizer = (objValue, srcValue) => {
|
|
1497
|
+
if (Array.isArray(objValue)) {
|
|
1498
|
+
// don't merge arrays
|
|
1499
|
+
return srcValue;
|
|
1500
|
+
}
|
|
1501
|
+
};
|
|
1502
|
+
return lodashEs.mergeWith({}, objA, objB, customizer);
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
const convictConfigParser = (config) => {
|
|
1506
|
+
if (typeof config === 'object') {
|
|
1507
|
+
Object.keys(config).forEach(key => {
|
|
1508
|
+
if (key === '_cvtProperties') {
|
|
1509
|
+
config = convictConfigParser(config._cvtProperties);
|
|
1510
|
+
}
|
|
1511
|
+
else {
|
|
1512
|
+
config[key] = convictConfigParser(config[key]);
|
|
1513
|
+
}
|
|
1514
|
+
});
|
|
1515
|
+
}
|
|
1516
|
+
return config;
|
|
1517
|
+
};
|
|
1518
|
+
|
|
1519
|
+
class RoutingController {
|
|
1520
|
+
_routeHandlers = {};
|
|
1521
|
+
handleRequest(call, callback) {
|
|
1522
|
+
if (this._routeHandlers[call.request.functionName]) {
|
|
1523
|
+
this._routeHandlers[call.request.functionName](call, callback);
|
|
1524
|
+
}
|
|
1525
|
+
else {
|
|
1526
|
+
callback({
|
|
1527
|
+
code: grpcJs.status.NOT_FOUND,
|
|
1528
|
+
message: 'Not found',
|
|
1529
|
+
});
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
setRoutes(routes) {
|
|
1533
|
+
this._routeHandlers = routes;
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
class ManagedModule extends ConduitServiceModule {
|
|
1538
|
+
config;
|
|
1539
|
+
configOverride = false;
|
|
1540
|
+
service;
|
|
1541
|
+
serviceAddress;
|
|
1542
|
+
servicePort;
|
|
1543
|
+
_moduleState;
|
|
1544
|
+
constructor(moduleName) {
|
|
1545
|
+
super(moduleName);
|
|
1546
|
+
this._moduleState = exports.ModuleLifecycleStage.CREATE_GRPC;
|
|
1547
|
+
if (!process.env.CONDUIT_SERVER) {
|
|
1548
|
+
throw new Error('CONDUIT_SERVER is undefined, specify Conduit server URL');
|
|
1549
|
+
}
|
|
1550
|
+
this.servicePort = process.env.GRPC_PORT ?? '5000';
|
|
1551
|
+
this.serviceAddress =
|
|
1552
|
+
// @compat (v0.15): SERVICE_IP -> SERVICE_URL
|
|
1553
|
+
process.env.SERVICE_URL || process.env.SERVICE_IP || '0.0.0.0:' + this.servicePort;
|
|
1554
|
+
try {
|
|
1555
|
+
this.grpcSdk = initializeSdk(process.env.CONDUIT_SERVER, this.name, true, () => {
|
|
1556
|
+
return this.healthState;
|
|
1557
|
+
});
|
|
1558
|
+
}
|
|
1559
|
+
catch (e) {
|
|
1560
|
+
throw new Error('Failed to initialize grpcSdk');
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
get name() {
|
|
1564
|
+
return this._moduleName;
|
|
1565
|
+
}
|
|
1566
|
+
get address() {
|
|
1567
|
+
return this._address;
|
|
1568
|
+
}
|
|
1569
|
+
async start() {
|
|
1570
|
+
await this.grpcSdk.initialize();
|
|
1571
|
+
this.initialize(this.serviceAddress, this.servicePort);
|
|
1572
|
+
try {
|
|
1573
|
+
await this.preRegisterLifecycle();
|
|
1574
|
+
await this.grpcSdk.config.registerModule(this.name, this.address, this.healthState);
|
|
1575
|
+
}
|
|
1576
|
+
catch (err) {
|
|
1577
|
+
ConduitGrpcSdk.Logger.error('Failed to initialize server');
|
|
1578
|
+
ConduitGrpcSdk.Logger.error(err);
|
|
1579
|
+
process.exit(-1);
|
|
1580
|
+
}
|
|
1581
|
+
await this.postRegisterLifecycle().catch((err) => {
|
|
1582
|
+
ConduitGrpcSdk.Logger.error('Failed to activate module');
|
|
1583
|
+
ConduitGrpcSdk.Logger.error(err);
|
|
1584
|
+
process.exit(-1);
|
|
1585
|
+
});
|
|
1586
|
+
}
|
|
1587
|
+
/**
|
|
1588
|
+
* This is the first function triggered on module spin up.
|
|
1589
|
+
* @param address {string} external address:port of service (LoadBalancer)
|
|
1590
|
+
* @param port {string} port to bring up gRPC service
|
|
1591
|
+
*/
|
|
1592
|
+
initialize(address, port) {
|
|
1593
|
+
this._address = address;
|
|
1594
|
+
this._port = port;
|
|
1595
|
+
if (this.configSchema) {
|
|
1596
|
+
this.config = convict(this.configSchema);
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
/**
|
|
1600
|
+
* This is triggered before spinning up the Grpc Server
|
|
1601
|
+
* of the module. On this stage, the redis bus and state have
|
|
1602
|
+
* not yet been initialized, and only communications with Conduit core
|
|
1603
|
+
* have been established.
|
|
1604
|
+
*/
|
|
1605
|
+
async preServerStart() { }
|
|
1606
|
+
/**
|
|
1607
|
+
* This is triggered right after Grpc Server start.
|
|
1608
|
+
* At this stage the core module will communicate with your service
|
|
1609
|
+
* for health checks, and the Bus and State management mechanics
|
|
1610
|
+
* are online and available.
|
|
1611
|
+
*/
|
|
1612
|
+
async onServerStart() { }
|
|
1613
|
+
/**
|
|
1614
|
+
* Triggers right before registering the module with Conduit Core.
|
|
1615
|
+
*/
|
|
1616
|
+
async preRegister() { }
|
|
1617
|
+
/**
|
|
1618
|
+
* Triggers when module has been registered with Conduit Core
|
|
1619
|
+
* This is the step where you should initialize your
|
|
1620
|
+
* module's general routing (admin or client) and any other operation,
|
|
1621
|
+
* that would require other modules being able to reach you
|
|
1622
|
+
*/
|
|
1623
|
+
async onRegister() { }
|
|
1624
|
+
/**
|
|
1625
|
+
* This is triggered when the module receives new configuration.
|
|
1626
|
+
* At this step the configuration has not been checked yet,
|
|
1627
|
+
* and has only been parsed.
|
|
1628
|
+
* @param config
|
|
1629
|
+
*/
|
|
1630
|
+
async preConfig(config) {
|
|
1631
|
+
return config;
|
|
1632
|
+
}
|
|
1633
|
+
/**
|
|
1634
|
+
* This is triggered when new configuration has been applied.
|
|
1635
|
+
* This happens either when changes are being made on the configuration,
|
|
1636
|
+
* or on module start up, where the config is recovered from the database.
|
|
1637
|
+
* In either case the configuration is now available through the
|
|
1638
|
+
* Config Controller of the sdk.
|
|
1639
|
+
*/
|
|
1640
|
+
async onConfig() { }
|
|
1641
|
+
/**
|
|
1642
|
+
* Registers common and module-specific metric types.
|
|
1643
|
+
*/
|
|
1644
|
+
async registerMetrics() {
|
|
1645
|
+
if (ConduitGrpcSdk.Metrics) {
|
|
1646
|
+
ConduitGrpcSdk.Metrics.initializeDefaultMetrics();
|
|
1647
|
+
if (this.metricsSchema) {
|
|
1648
|
+
Object.values(this.metricsSchema).forEach(metric => {
|
|
1649
|
+
ConduitGrpcSdk.Metrics.registerMetric(metric.type, metric.config);
|
|
1650
|
+
});
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1653
|
+
}
|
|
1654
|
+
/**
|
|
1655
|
+
* Initializes metric startup values.
|
|
1656
|
+
* Implemented by individual modules.
|
|
1657
|
+
*/
|
|
1658
|
+
async initializeMetrics() { }
|
|
1659
|
+
async createGrpcServer() {
|
|
1660
|
+
this.grpcServer = new GrpcServer(this._port);
|
|
1661
|
+
this._port = (await this.grpcServer.createNewServer()).toString();
|
|
1662
|
+
}
|
|
1663
|
+
async startGrpcServer() {
|
|
1664
|
+
if (this.service) {
|
|
1665
|
+
this._serviceName = this.service.protoDescription.substring(this.service.protoDescription.indexOf('.') + 1);
|
|
1666
|
+
await this.grpcServer.addService(this.service.protoPath, this.service.protoDescription, this.service.functions);
|
|
1667
|
+
}
|
|
1668
|
+
RoutingManager.ClientController = new RoutingController();
|
|
1669
|
+
RoutingManager.AdminController = new RoutingController();
|
|
1670
|
+
await this.addHealthCheckService();
|
|
1671
|
+
await this.addModuleService();
|
|
1672
|
+
await this.grpcServer.start();
|
|
1673
|
+
ConduitGrpcSdk.Logger.log('gRPC server listening on ' + this._port);
|
|
1674
|
+
}
|
|
1675
|
+
async setConfig(call, callback) {
|
|
1676
|
+
try {
|
|
1677
|
+
if (!this.config) {
|
|
1678
|
+
return callback({
|
|
1679
|
+
code: grpcJs.status.INVALID_ARGUMENT,
|
|
1680
|
+
message: 'Module is not configurable',
|
|
1681
|
+
});
|
|
1682
|
+
}
|
|
1683
|
+
let config = JSON.parse(call.request.newConfig);
|
|
1684
|
+
config = merge(this.config.getProperties(), config);
|
|
1685
|
+
config = await this.preConfig(config);
|
|
1686
|
+
const previousConfig = this.config.getProperties();
|
|
1687
|
+
try {
|
|
1688
|
+
this.config.load(config).validate({
|
|
1689
|
+
allowed: 'warn',
|
|
1690
|
+
});
|
|
1691
|
+
config = this.config.getProperties();
|
|
1692
|
+
callback(null, { updatedConfig: JSON.stringify(config) });
|
|
1693
|
+
}
|
|
1694
|
+
catch (e) {
|
|
1695
|
+
this.config = convict(this.configSchema);
|
|
1696
|
+
this.config.load(previousConfig);
|
|
1697
|
+
return callback({
|
|
1698
|
+
code: grpcJs.status.INVALID_ARGUMENT,
|
|
1699
|
+
message: 'Invalid configuration values: ' + e.message,
|
|
1700
|
+
});
|
|
1701
|
+
}
|
|
1702
|
+
ConfigController.getInstance().config = config;
|
|
1703
|
+
await this.onConfig();
|
|
1704
|
+
this.grpcSdk.bus?.publish(lodashEs.kebabCase(this.name) + ':config:update', JSON.stringify(config));
|
|
1705
|
+
}
|
|
1706
|
+
catch (e) {
|
|
1707
|
+
return callback({ code: grpcJs.status.INTERNAL, message: e.message });
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
/** Used to update the module's configuration on initial Redis/DB reconciliation. */
|
|
1711
|
+
async handleConfigSyncUpdate() {
|
|
1712
|
+
if (!this.config)
|
|
1713
|
+
return;
|
|
1714
|
+
this.grpcSdk.bus.subscribe(`${lodashEs.kebabCase(this.name)}:config:update`, async (message) => {
|
|
1715
|
+
ConfigController.getInstance().config = await this.preConfig(JSON.parse(message));
|
|
1716
|
+
await this.onConfig();
|
|
1717
|
+
});
|
|
1718
|
+
}
|
|
1719
|
+
async preRegisterLifecycle() {
|
|
1720
|
+
await this.createGrpcServer();
|
|
1721
|
+
this._moduleState = exports.ModuleLifecycleStage.PRE_SERVER_START;
|
|
1722
|
+
await this.preServerStart();
|
|
1723
|
+
await this.grpcSdk.initializeEventBus();
|
|
1724
|
+
await this.handleConfigSyncUpdate();
|
|
1725
|
+
await this.registerMetrics();
|
|
1726
|
+
await this.startGrpcServer();
|
|
1727
|
+
this._moduleState = exports.ModuleLifecycleStage.SERVER_STARTED;
|
|
1728
|
+
await this.onServerStart();
|
|
1729
|
+
await this.initializeMetrics();
|
|
1730
|
+
this._moduleState = exports.ModuleLifecycleStage.PRE_REGISTER;
|
|
1731
|
+
await this.preRegister();
|
|
1732
|
+
}
|
|
1733
|
+
async postRegisterLifecycle() {
|
|
1734
|
+
this._moduleState = exports.ModuleLifecycleStage.POST_REGISTER;
|
|
1735
|
+
this.registered = true;
|
|
1736
|
+
await this.onRegister();
|
|
1737
|
+
if (this.config) {
|
|
1738
|
+
const configSchema = this.config.getSchema();
|
|
1739
|
+
let config = this.config.getProperties();
|
|
1740
|
+
config = await this.preConfig(config);
|
|
1741
|
+
config = await this.grpcSdk.config.configure(config, convictConfigParser(configSchema), this.configOverride);
|
|
1742
|
+
ConfigController.getInstance();
|
|
1743
|
+
if (config)
|
|
1744
|
+
ConfigController.getInstance().config = config;
|
|
1745
|
+
if (!config || config.active || !config.hasOwnProperty('active'))
|
|
1746
|
+
await this.onConfig();
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
}
|
|
1750
|
+
|
|
1751
|
+
exports.ConduitActiveSchema = ConduitActiveSchema;
|
|
1752
|
+
exports.ConduitBoolean = ConduitBoolean;
|
|
1753
|
+
exports.ConduitDate = ConduitDate;
|
|
1754
|
+
exports.ConduitJson = ConduitJson;
|
|
1755
|
+
exports.ConduitNumber = ConduitNumber;
|
|
1756
|
+
exports.ConduitObjectId = ConduitObjectId;
|
|
1757
|
+
exports.ConduitRelation = ConduitRelation;
|
|
1758
|
+
exports.ConduitServiceModule = ConduitServiceModule;
|
|
1759
|
+
exports.ConduitString = ConduitString;
|
|
1760
|
+
exports.ConfigController = ConfigController;
|
|
1761
|
+
exports.GrpcServer = GrpcServer;
|
|
1762
|
+
exports.ManagedModule = ManagedModule;
|
|
1763
|
+
exports.ProxyRouteBuilder = ProxyRouteBuilder;
|
|
1764
|
+
exports.RouteBuilder = RouteBuilder;
|
|
1765
|
+
exports.RoutingManager = RoutingManager;
|
|
1766
|
+
exports.addServiceToServer = addServiceToServer;
|
|
1767
|
+
exports.createParsedRouterRequest = createParsedRouterRequest;
|
|
1768
|
+
exports.createServer = createServer;
|
|
1769
|
+
exports.initializeSdk = initializeSdk;
|
|
1770
|
+
exports.linearBackoffTimeout = linearBackoffTimeout;
|
|
1771
|
+
exports.linearBackoffTimeoutAsync = linearBackoffTimeoutAsync;
|
|
1772
|
+
exports.merge = merge;
|
|
1773
|
+
exports.wrapFunctionsAsync = wrapFunctionsAsync;
|
|
1774
|
+
exports.wrapGrpcFunctions = wrapGrpcFunctions;
|
|
1775
|
+
exports.wrapRouterGrpcFunction = wrapRouterGrpcFunction;
|
|
1776
|
+
//# sourceMappingURL=index.cjs.map
|