@futdevpro/nts-dynamo 1.9.15 → 1.9.16

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.
Files changed (117) hide show
  1. package/.copilot/patterns.json +7 -7
  2. package/.github/workflows/main.yml +206 -0
  3. package/HOWTO.md +15 -15
  4. package/README.md +140 -140
  5. package/build/_models/control-models/endpoint-params.control-model.d.ts.map +1 -1
  6. package/build/_models/control-models/endpoint-params.control-model.js +2 -0
  7. package/build/_models/control-models/endpoint-params.control-model.js.map +1 -1
  8. package/build/_models/control-models/socket-event.control-model.js +1 -1
  9. package/build/_services/core/global.service.d.ts.map +1 -1
  10. package/build/_services/core/global.service.js +1 -0
  11. package/build/_services/core/global.service.js.map +1 -1
  12. package/build/_services/route/routing-module.service.d.ts +1 -0
  13. package/build/_services/route/routing-module.service.d.ts.map +1 -1
  14. package/build/_services/route/routing-module.service.js +17 -23
  15. package/build/_services/route/routing-module.service.js.map +1 -1
  16. package/build/_services/server/app.server.d.ts.map +1 -1
  17. package/build/_services/server/app.server.js +4 -1
  18. package/build/_services/server/app.server.js.map +1 -1
  19. package/build/_services/socket/socket-client.service.d.ts.map +1 -1
  20. package/build/_services/socket/socket-client.service.js +1 -0
  21. package/build/_services/socket/socket-client.service.js.map +1 -1
  22. package/nodemon.json +17 -15
  23. package/package.json +5 -5
  24. package/src/_constants/global-settings.const.ts +27 -27
  25. package/src/_constants/index.ts +2 -2
  26. package/src/_constants/mocks/app-extended-server.mock.ts +198 -198
  27. package/src/_constants/mocks/app-params.mock.ts +9 -9
  28. package/src/_constants/mocks/app-server.mock.ts +185 -185
  29. package/src/_constants/mocks/auth-service.mock.ts +28 -28
  30. package/src/_constants/mocks/controller.mock.ts +16 -16
  31. package/src/_constants/mocks/data-model.mock.ts +83 -83
  32. package/src/_constants/mocks/email-service-collection.mock.ts +13 -13
  33. package/src/_constants/mocks/email-service.mock.ts +19 -19
  34. package/src/_constants/mocks/email-template.mock.html +14 -14
  35. package/src/_constants/mocks/endpoint.mock.ts +90 -90
  36. package/src/_constants/mocks/socket-client.mock.ts +43 -43
  37. package/src/_constants/mocks/socket-server.mock.ts +43 -43
  38. package/src/_enums/data-model-type.enum.ts +14 -14
  39. package/src/_enums/data-service-function.enum.ts +15 -15
  40. package/src/_enums/http/http-call-type.enum.ts +12 -12
  41. package/src/_enums/http/http-response-type.enum.ts +7 -7
  42. package/src/_enums/http/socket-event-type.enum.ts +18 -18
  43. package/src/_enums/index.ts +13 -13
  44. package/src/_enums/predefined-data-types.enum.ts +27 -27
  45. package/src/_enums/route-security.enum.ts +12 -12
  46. package/src/_enums/socket-security.enum.ts +11 -11
  47. package/src/_models/control-models/api-call-params.control-model.ts +126 -126
  48. package/src/_models/control-models/app-ext-system-controls.control-model.ts +9 -9
  49. package/src/_models/control-models/app-params.control-model.ts +45 -45
  50. package/src/_models/control-models/app-system-controls.control-model.ts +9 -9
  51. package/src/_models/control-models/endpoint-params.control-model.ts +309 -307
  52. package/src/_models/control-models/http-settings.control-model.ts +29 -29
  53. package/src/_models/control-models/index.ts +13 -13
  54. package/src/_models/control-models/socket-client-service-params.control-model.ts +28 -28
  55. package/src/_models/control-models/socket-event.control-model.ts +150 -150
  56. package/src/_models/control-models/socket-presence.control-model.ts +207 -207
  57. package/src/_models/control-models/socket-server-service-params.control-model.ts +20 -20
  58. package/src/_models/control-models/system-control.control-model.ts +12 -12
  59. package/src/_models/index.ts +9 -9
  60. package/src/_models/interfaces/certification-settings.interface.ts +7 -7
  61. package/src/_models/interfaces/global-service-settings.interface.ts +45 -45
  62. package/src/_models/interfaces/global-settings.interface.ts +83 -83
  63. package/src/_models/interfaces/index.ts +7 -7
  64. package/src/_models/interfaces/routing-module-settings.interface.ts +20 -20
  65. package/src/_models/types/db-filter.type.ts +108 -108
  66. package/src/_models/types/db-update.type.ts +100 -100
  67. package/src/_models/types/index.ts +5 -5
  68. package/src/_modules/api-service.index.ts +12 -12
  69. package/src/_modules/app-extended.index.ts +28 -28
  70. package/src/_modules/app.index.ts +24 -24
  71. package/src/_modules/auth.index.ts +7 -7
  72. package/src/_modules/constants.index.ts +2 -2
  73. package/src/_modules/controller.index.ts +10 -10
  74. package/src/_modules/custom-data/custom-data.controller.ts +69 -69
  75. package/src/_modules/custom-data/custom-data.data-service.ts +20 -20
  76. package/src/_modules/custom-data/get-custom-data-routing-module.util.ts +23 -23
  77. package/src/_modules/custom-data/index.ts +6 -6
  78. package/src/_modules/custom-data-module.index.ts +2 -2
  79. package/src/_modules/data-service.index.ts +9 -9
  80. package/src/_modules/email.index.ts +8 -8
  81. package/src/_modules/enums.index.ts +2 -2
  82. package/src/_modules/extended.index.ts +8 -8
  83. package/src/_modules/models.index.ts +2 -2
  84. package/src/_modules/services.index.ts +2 -2
  85. package/src/_modules/test/get-test-routing-module.util.ts +23 -23
  86. package/src/_modules/test/index.ts +5 -5
  87. package/src/_modules/test/test.controller.ts +115 -115
  88. package/src/_modules/test-module.index.ts +2 -2
  89. package/src/_modules/usage/get-usage-routing-module.util.ts +22 -22
  90. package/src/_modules/usage/index.ts +7 -7
  91. package/src/_modules/usage/usage.controller.ts +120 -120
  92. package/src/_modules/usage/usage.data-service.ts +172 -172
  93. package/src/_modules/usage-module.index.ts +2 -2
  94. package/src/_services/base/data.service.ts +921 -921
  95. package/src/_services/base/db.service.spec.ts +32 -32
  96. package/src/_services/base/db.service.ts +1063 -1063
  97. package/src/_services/base/singleton.service.ts +21 -21
  98. package/src/_services/core/api.service.ts +453 -453
  99. package/src/_services/core/auth.service.ts +172 -172
  100. package/src/_services/core/email.service.ts +678 -678
  101. package/src/_services/core/global.service.ts +270 -269
  102. package/src/_services/core/service-collection.service.ts +5 -5
  103. package/src/_services/index.ts +23 -23
  104. package/src/_services/route/controller.service.ts +129 -129
  105. package/src/_services/route/routing-module.service.ts +293 -273
  106. package/src/_services/server/app-extended.server.spec.ts +76 -76
  107. package/src/_services/server/app-extended.server.ts +520 -520
  108. package/src/_services/server/app.server.spec.ts +67 -67
  109. package/src/_services/server/app.server.ts +1181 -1179
  110. package/src/_services/shared.service.spec.ts +19 -19
  111. package/src/_services/shared.static-service.ts +73 -73
  112. package/src/_services/socket/socket-client.service.ts +236 -235
  113. package/src/_services/socket/socket-server.service.spec.ts +11 -11
  114. package/src/_services/socket/socket-server.service.ts +761 -761
  115. package/src/index.ts +18 -18
  116. package/tsconfig.json +41 -41
  117. package/build/tsconfig.tsbuildinfo +0 -1
@@ -1,1179 +1,1181 @@
1
-
2
- import Mongoose = require('mongoose');
3
- import Express = require('express');
4
- /* import Mongoose from 'mongoose';
5
- import Express from 'express'; */
6
-
7
- import * as Http from 'http';
8
- import * as Https from 'https';
9
- import * as FileSystem from 'fs';
10
- import * as BodyParser from 'body-parser';
11
-
12
- /* import { version } from '../../../package.json'; */
13
-
14
- import {
15
- DynamoFM_AnyError,
16
- DynamoFM_Array, DynamoFM_Error, DynamoFM_error_defaults,
17
- DynamoFM_Error_Settings,
18
- DynamoFM_ErrorLevel, DynamoFM_Log, second, DynamoFM_wait
19
- } from '@futdevpro/fsm-dynamo';
20
-
21
- import { DynamoNTS_SingletonService } from '../base/singleton.service';
22
- import { DynamoNTS_RouteSecurity } from '../../_enums/route-security.enum';
23
- import { DynamoNTS_RoutingModule } from '../route/routing-module.service';
24
- import { DynamoNTS_GlobalService } from '../core/global.service';
25
- import { DynamoNTS_Http_Settings } from '../../_models/control-models/http-settings.control-model';
26
- import {
27
- DynamoNTS_Certification_Settings
28
- } from '../../_models/interfaces/certification-settings.interface';
29
- import {
30
- DynamoNTS_GlobalService_Settings
31
- } from '../../_models/interfaces/global-service-settings.interface';
32
- import { DynamoNTS_globalSettings } from '../../_constants/global-settings.const';
33
- import { DynamoNTS_App_Params } from '../../_models/control-models/app-params.control-model';
34
- import {
35
- DynamoNTS_Endpoint_Params
36
- } from '../../_models/control-models/endpoint-params.control-model';
37
- import {
38
- DynamoNTS_AppSystemControls
39
- } from '../../_models/control-models/app-system-controls.control-model';
40
-
41
-
42
- /**
43
- * This will be the MAIN service of our server project,
44
- * follow the types and type instructions while setting up your project
45
- *
46
- * In this service, there are abstract functions that you will need to implement,
47
- * where you need to set up the main params for your application.
48
- *
49
- * (after the example, you can find the list of services you can/should setup)
50
- *
51
- * @example
52
- * export class App extends DynamoNTS_AppExtended {
53
- *
54
- * ...
55
- *
56
- * // Setting up App params, and preparing project global settings
57
- * setupAppParams(): void {
58
- * this.params = new DynamoNTS_AppParams({
59
- * name: 'Warbots Server',
60
- * title: warbotsTitleLog,
61
- * version: version,
62
- * dbName: 'warbots',
63
- * });
64
- *
65
- * // dynamoNTS_GlobalSettings.logRequestsContent = false;
66
- * }
67
- *
68
- * ...
69
- *
70
- * // Setting up DBServices
71
- * setGlobalServiceCollection(): void {
72
- * DynamoNTS_GlobalService.setServices({
73
- * authService: AuthService.getInstance(),
74
- * emailServiceCollection: EmailServiceCollectionService.getInstance(),
75
- * dbModels: [
76
- * userModelParams,
77
- * userDataModelParams,
78
- * userOptionsModelParams,
79
- * userStatisticsModelParams,
80
- * userAchievementsModelParams,
81
- * userNotificationsModelParams,
82
- *
83
- * matchStatisticsModelParams,
84
- * matchDataModelParams,
85
-
86
- * DynamoFM_usageSessionModel_params,
87
- * DynamoFM_customDataModel_params,
88
- * ]
89
- * });
90
- * }
91
- *
92
- * ...
93
- *
94
- * // Setting up Routes
95
- * setupRoutingModules(): void {
96
- * this.httpPort = env.port;
97
-
98
- * this.routingModules = [
99
- * new DynamoNTS_RoutingModule({
100
- * route: '/user',
101
- * controllers: [
102
- * UserController.getInstance(),
103
- * UserDataController.getInstance(),
104
- * UserOptionsController.getInstance(),
105
- * UserStatisticsController.getInstance(),
106
- * UserAchievementsController.getInstance(),
107
- * UserNotificationsController.getInstance()
108
- * ]
109
- * }),
110
- * new DynamoNTS_RoutingModule({
111
- * route: '/match',
112
- * controllers: [
113
- * MatchController.getInstance(),
114
- * MatchDistributionController.getInstance(),
115
- * MatchStatisticsController.getInstance(),
116
- * ]
117
- * }),
118
- * new DynamoNTS_RoutingModule({
119
- * route: '/server',
120
- * controllers: [
121
- * ServerController.getInstance(),
122
- * ]
123
- * }),
124
-
125
- * getTestRoutingModule(),
126
- * getUsageRoutingModule()
127
- * ];
128
- * }
129
- * }
130
- *
131
- * //
132
- * // The Services available
133
- * //
134
- * // Authentication Service
135
- * // A commonly used basic service,
136
- * // which is necessary fur certain functions (such as registering call issuers)
137
- * //
138
- * // This will handle Authentication Token checking/refreshing,
139
- * // checking issuer's identifier and routeParams,
140
- * // handling JWT Token, or maybe with OAuth2 or other commonly used security procedures
141
- * //
142
- * // You can create one with this Dynamo Object:
143
- * //
144
- *
145
- * @example
146
- * // follow the instructions on the abstract class (DynamoNTS_AuthService)
147
- * export class AuthService extends DynamoNTS_AuthService {}
148
- *
149
- *
150
- *
151
- * //
152
- */
153
-
154
- /**
155
- * This will be the MAIN service of our server project,
156
- * follow the types and type instructions while setting up your project
157
- *
158
- * In this service, there are abstract functions that you will need to implement,
159
- * where you need to set up the main params for your application.
160
- *
161
- * (after the example, you can find the list of services you can/should setup)
162
- *
163
- * You need to setup the following functions:
164
- * ```ts
165
- * // this is where you set up the main params for your application
166
- * getAppParams(): DynamoNTS_AppParams
167
- *
168
- * // this is where you connect your main services
169
- * getGlobalServiceSettings(): DynamoNTS_GlobalServiceSettings
170
- *
171
- * // this is where you set up your ports
172
- * getPorts(): DynamoNTS_PortSettings
173
- *
174
- * // this is where you set up your routes
175
- * getRoutingModules(): DynamoNTS_RoutingModule[]
176
- *
177
- *
178
- *
179
- * ```
180
- * optionally you can setup the following functions:
181
- * ```ts
182
- * // this is where you set up your certifications
183
- * getCertificationSettings(): DynamoNTS_CertificationSettings
184
- *
185
- * // this is where you set up additional root services
186
- * getRootServices(): DynamoNTS_SingletonService[]
187
- *
188
- * // this is where you set up your initial db entries
189
- * createEntries(): void
190
- *
191
- * // this is where you can define post setup processes
192
- * postProcess(): void
193
- *
194
- *
195
- *
196
- * ```
197
- *
198
- */
199
- export abstract class DynamoNTS_App extends DynamoNTS_SingletonService {
200
-
201
- // TODO: rename all DynamoNTS_ > DyNTS_ ------------------------------------------------------------------------------------------------------------------------------------
202
-
203
- protected systemControls: DynamoNTS_AppSystemControls = new DynamoNTS_AppSystemControls();
204
- get started(): boolean {
205
- return this.systemControls.app.started;
206
- }
207
- protected get superStarted(): boolean {
208
- return this.systemControls.app.started;
209
- }
210
- protected constructErrors: (Error | DynamoFM_Error)[] = [];
211
-
212
- /* removed since cant use version from package.json
213
- private readonly _ntsVersion: string = 'v01.07.18';
214
- protected get ntsVersion(): string {
215
- return this._ntsVersion;
216
- } */
217
-
218
- get serverName(): string {
219
- return this.params.name;
220
- }
221
-
222
- private _params: DynamoNTS_App_Params;
223
- protected get params(): DynamoNTS_App_Params {
224
- return this._params;
225
- }
226
-
227
- protected mongoose = Mongoose;
228
-
229
- private _security: DynamoNTS_RouteSecurity;
230
- protected get security(): DynamoNTS_RouteSecurity {
231
- return this._security;
232
- }
233
-
234
- protected _portSettings: DynamoNTS_Http_Settings = new DynamoNTS_Http_Settings();
235
- protected get portSettings(): DynamoNTS_Http_Settings {
236
- return this._portSettings;
237
- }
238
-
239
- private _cert?: DynamoNTS_Certification_Settings;
240
- protected get cert(): DynamoNTS_Certification_Settings {
241
- return this._cert;
242
- }
243
-
244
- protected openExpress: Express.Application;
245
- private secureExpress: Express.Application;
246
- protected httpsServer: Https.Server;
247
- protected httpServer: Http.Server;
248
-
249
- private globalService: DynamoNTS_GlobalService;
250
- private _rootServices: DynamoNTS_SingletonService[] = [];
251
-
252
- private _routingModules: DynamoNTS_RoutingModule[] = [];
253
-
254
- defaultErrorUserMsg =
255
- `We encountered a Server Error, ` +
256
- `\nplease contact the responsible development team.\n` +
257
- `\n(Internal Server error)`;
258
-
259
- /**
260
- * setting this value to true, enables this service debug logs
261
- */
262
- protected logSetup: boolean;
263
- protected deepLog: boolean;
264
- protected logFn: boolean;
265
- protected debugLog: boolean;
266
-
267
- constructor(extended?: boolean){
268
- super();
269
-
270
- process.on('unhandledRejection', (reason: object, p_passWhatIsThis: any): void => {
271
- DynamoFM_Log.highlightedError(
272
- 'Unhandled Rejection at: ', p_passWhatIsThis,
273
- '\nRejection reason:', reason
274
- );
275
-
276
- try {
277
- DynamoNTS_GlobalService.globalErrorHandler?.(
278
- new DynamoFM_Error({
279
- errorCode: 'NTS-AS0-BASE-UR',
280
- message: 'Unhandled Rejection!',
281
- error: new Error(p_passWhatIsThis),
282
- additionalContent: {
283
- reason: reason,
284
- p_noIdeaWhatIsThisFromProcessRejection: p_passWhatIsThis,
285
- },
286
- level: DynamoFM_ErrorLevel.critical,
287
- })
288
- );
289
-
290
- } catch (error) {
291
- DynamoFM_Log.error('globalErrorHandler (MULTILEVEL) ERROR:', error);
292
- }
293
- });
294
-
295
- this.asyncConstruct(extended).catch((error: any): void => {
296
- DynamoFM_Log.error(
297
- `\nApplication: ${this._params.name} start failed.` +
298
- `\n`, error
299
- );
300
-
301
- if (error?.flag?.includes?.('DYNAMO-ERROR-OBJECT')) {
302
- DynamoFM_Log.error(`\nErrorMessage: ${(error as DynamoFM_Error)._message}`);
303
- DynamoFM_Log.error(`ErrorCode: ${(error as DynamoFM_Error)._errorCode}`);
304
- }
305
- });
306
- }
307
-
308
- private async asyncConstruct(extended?: boolean): Promise<void> {
309
- if (this.logFn && this.deepLog) DynamoFM_Log.log('\nfn:. asyncConstruct');
310
- try {
311
- this.systemControls.app.init = true;
312
- this._params = this.getAppParams();
313
- DynamoFM_Log.log(
314
- `\n\n\n\n\n\n\n\n\n\n` +
315
- `Starting ${this._params?.name}... `
316
- );
317
-
318
- if (!this._params) {
319
- throw new Error('getAppParams() must return a DynamoNTS_AppParams object!');
320
- }
321
-
322
- process.stdout.write(
323
- String.fromCharCode(27) + ']0;' +
324
- this._params?.name +
325
- String.fromCharCode(7)
326
- );
327
-
328
- DynamoFM_error_defaults.issuerSystem = this._params.systemName;
329
-
330
- this.overrideDynamoNTSGlobalSettings?.();
331
-
332
- this.logSetup = DynamoNTS_globalSettings.logSetup;
333
-
334
- this.globalService = DynamoNTS_GlobalService.getInstance();
335
- await DynamoNTS_GlobalService.setServices(this.getGlobalServiceCollection());
336
- DynamoNTS_GlobalService.setParams(this.params);
337
-
338
- if (this.getPortSettings) {
339
- this._portSettings = this.getPortSettings();
340
- }
341
-
342
- if (this.getCertificationSettings) {
343
- this._cert = this.getCertificationSettings();
344
- }
345
-
346
- if (this.getRoutingModules) {
347
- this._routingModules = this.getRoutingModules();
348
- }
349
-
350
- await this.startDB();
351
-
352
- await this.createEntries?.();
353
-
354
- this.setSecurity();
355
-
356
- if (this._routingModules?.length) {
357
- await this.initExpresses();
358
- await this.startExpresses();
359
-
360
- if (this._security !== DynamoNTS_RouteSecurity.secure) {
361
- await this.mountOpenRoutes();
362
- }
363
-
364
- if (this._security !== DynamoNTS_RouteSecurity.open && this._cert) {
365
- await this.mountSecureRoutes();
366
- }
367
-
368
- if (this.logSetup) {
369
- DynamoFM_Log.log(`\nRoutes mounted.... server using security: ${this._security}`);
370
- }
371
- }
372
-
373
- if (this.getRootServices) {
374
- this._rootServices = await this.getRootServices();
375
- }
376
-
377
- await this.postProcess?.();
378
-
379
-
380
- if (!extended) {
381
- await this.ready();
382
-
383
- if (this.params.title) {
384
- DynamoFM_Log.success(this.params.title);
385
- }
386
- DynamoFM_Log.info(`Version: ${this.params.version}`);
387
- /* DynamoFM_Log.info(`NTS Version: ${this.ntsVersion}`); */
388
- DynamoFM_Log.H_success(`${this.params.name} started successfully.`);
389
- }
390
- } catch (error) {
391
- this.constructErrors.push(error);
392
- DynamoFM_Log.error(
393
- `${this._params.name} start failed. ERRORS`,
394
- this.constructErrors,
395
- error
396
- );
397
-
398
- throw new DynamoFM_Error({
399
- ...this._getDefaultErrorSettings(
400
- 'asyncConstruct',
401
- error
402
- ),
403
-
404
- errorCode: 'NTS-AS0-001',
405
- additionalContent: {
406
- constructErrors: this.constructErrors,
407
- systemControls: this.systemControls,
408
- systemReadies: {
409
- app: this.systemControls.app.getReady(),
410
- mongoose: this.systemControls.mongoose.getReady(),
411
- httpServer: this.systemControls.httpServer.getReady(),
412
- httpsServer: this.systemControls.httpsServer.getReady(),
413
- },
414
- },
415
- });
416
- }
417
- }
418
-
419
- async ready(timeout: number = 4 * second): Promise<void> {
420
- if (this.logFn) DynamoFM_Log.log('\nfn:. ready');
421
- let ready: boolean = false;
422
- const start: number = +new Date();
423
-
424
- if (this.constructErrors.length) {
425
- DynamoFM_Log.error(
426
- `${this._params.name} start failed. \nERRORS:`,
427
- this.constructErrors
428
- );
429
-
430
- throw new DynamoFM_Error({
431
- ...this._getDefaultErrorSettings(
432
- 'ready',
433
- new Error(`${this._params.name} start failed. ERRORS`)
434
- ),
435
-
436
- errorCode: 'NTS-AS0-R01',
437
- additionalContent:
438
- this.constructErrors.length === 1 ?
439
- this.constructErrors[0] :
440
- { errors: this.constructErrors },
441
- });
442
- }
443
-
444
- while (!ready && +new Date() - start < timeout) {
445
- if (this.systemControls.app.init) {
446
- ready = (
447
- this.systemControls.mongoose.getReady() &&
448
- this.systemControls.httpServer.getReady() &&
449
- this.systemControls.httpsServer.getReady()
450
- );
451
- } else {
452
- DynamoFM_Log.error(`${this.params.name} APP NOT INITIALIZED while trying to get ready.`);
453
- }
454
-
455
- if (!ready) {
456
- await DynamoFM_wait(100);
457
- }
458
- }
459
-
460
- if (timeout < +new Date() - start) {
461
- DynamoFM_Log.error(`${this._params.name} start failed. TIMEOUT`, this.constructErrors);
462
-
463
- throw new DynamoFM_Error({
464
- ...this._getDefaultErrorSettings(
465
- 'ready',
466
- new Error(`${this._params.name} start failed. TIMEOUT`)
467
- ),
468
-
469
- errorCode: 'NTS-AS0-R02',
470
- additionalContent: {
471
- constructErrors: this.constructErrors,
472
- systemControls: this.systemControls,
473
- systemReadies: {
474
- mongoose: this.systemControls.mongoose.getReady(),
475
- httpServer: this.systemControls.httpServer.getReady(),
476
- httpsServer: this.systemControls.httpsServer.getReady(),
477
- },
478
- },
479
- });
480
- }
481
-
482
- if (this.constructErrors.length) {
483
- DynamoFM_Log.error(`${this._params.name} start failed. ERROR`, this.constructErrors);
484
-
485
- throw new DynamoFM_Error({
486
- ...this._getDefaultErrorSettings(
487
- 'ready',
488
- new Error(`${this._params.name} start failed. ERROR`)
489
- ),
490
-
491
- errorCode: 'NTS-AS0-R03',
492
- additionalContent: this.constructErrors,
493
- });
494
- }
495
-
496
- if (ready) {
497
- this.systemControls.app.started = true;
498
-
499
- if (this.logFn && this.deepLog) DynamoFM_Log.log('\nfn:. ready: return');
500
-
501
- return;
502
- } else {
503
- this.systemControls.app.started = false;
504
-
505
- let msg: string = `${this._params.name} start failed. UNKNOWN`;
506
-
507
- if (this.systemControls.mongoose.init && !this.systemControls.mongoose.started) {
508
- msg += `\nMongoose start failed.`;
509
- }
510
-
511
- if (this.systemControls.httpServer.init && !this.systemControls.httpServer.started) {
512
- msg += `\nHTTP Server start failed.`;
513
- }
514
-
515
- if (this.systemControls.httpsServer.init && !this.systemControls.httpsServer.started) {
516
- msg += `\nHTTPS Server start failed.`;
517
- }
518
-
519
- DynamoFM_Log.error(msg, this.constructErrors);
520
-
521
- throw new DynamoFM_Error({
522
- ...this._getDefaultErrorSettings(
523
- 'ready',
524
- new Error(msg)
525
- ),
526
-
527
- errorCode: 'NTS-AS0-R04',
528
- additionalContent: {
529
- constructErrors: this.constructErrors,
530
- systemControls: this.systemControls,
531
- systemReadies: {
532
- app: this.systemControls.app.getReady(),
533
- mongoose: this.systemControls.mongoose.getReady(),
534
- httpServer: this.systemControls.httpServer.getReady(),
535
- httpsServer: this.systemControls.httpsServer.getReady(),
536
- },
537
- },
538
- error: this.constructErrors?.[0] ?? new Error(),
539
- });
540
- }
541
- }
542
-
543
- async stop(dontLog?: boolean): Promise<void> {
544
- DynamoFM_Log.info('\nstoping server...\n');
545
-
546
- await this.ready();
547
-
548
- if (this.started) {
549
-
550
- if (this.systemControls.mongoose.init) {
551
- DynamoFM_Log.info(`\nstopping Mongoose....`);
552
-
553
- let tryCount: number = 0;
554
-
555
- while (
556
- !this.systemControls.mongoose.started &&
557
- !this.constructErrors.length &&
558
- tryCount++ < 10
559
- ) {
560
- DynamoFM_Log.warn(`Mongoose not even started yet....`);
561
- await DynamoFM_wait(second);
562
- }
563
- this.systemControls.mongoose.started = false;
564
-
565
- if (this.mongoose) {
566
- await DynamoFM_Array.asyncForEach(
567
- Object.keys(this.mongoose.models),
568
- async (modelName): Promise<void> => {
569
- await this.mongoose.deleteModel(modelName);
570
- }
571
- );
572
-
573
- const disconnect: Promise<void> = new Promise((resolve): void => {
574
- this.mongoose.connection.on('disconnecting', (): void => {
575
- resolve();
576
- });
577
- });
578
-
579
- await this.mongoose.disconnect();
580
- await this.mongoose.connection.close();
581
- await disconnect;
582
-
583
- while (
584
- this.mongoose.connection.readyState !== 0 &&
585
- !this.constructErrors.length
586
- ) {
587
- DynamoFM_Log.warn(`\nMongoose still not disconnected....`);
588
- await DynamoFM_wait(second);
589
- }
590
- } else {
591
- DynamoFM_Log.error(`\nMongoose not found.`);
592
- }
593
- this.systemControls.mongoose.init = false;
594
- }
595
-
596
- if (this.systemControls.httpServer.init) {
597
- this.systemControls.httpServer.started = false;
598
-
599
- if (this.httpServer) {
600
- await new Promise((resolve): void => {
601
- this.httpServer.close(resolve);
602
- });
603
- } else {
604
- DynamoFM_Log.error(`\nHTTP Server not found.`);
605
- }
606
- this.systemControls.httpServer.init = false;
607
- }
608
-
609
- if (this.systemControls.httpsServer.init) {
610
- this.systemControls.httpsServer.started = false;
611
-
612
- if (this.httpsServer) {
613
- await new Promise((resolve): void => {
614
- this.httpsServer.close(resolve);
615
- });
616
- } else {
617
- DynamoFM_Log.error(`\nHTTPS Server not found.`);
618
- }
619
- this.systemControls.httpsServer.init = false;
620
- }
621
-
622
- if (!dontLog) {
623
- DynamoFM_Log.H_log(`${this._params.name} stopped successfully.`);
624
- }
625
- }
626
- }
627
-
628
- /**
629
- *
630
- */
631
- private async startDB(): Promise<void> {
632
- if (this.logFn && this.deepLog) DynamoFM_Log.log('\nfn:. startDB');
633
-
634
- await new Promise<void>(
635
- (resolve, reject): void => {
636
- this.systemControls.mongoose.init = true;
637
-
638
- this.mongoose.connection
639
- .once('open', (): void => {
640
- this.systemControls.mongoose.started = true;
641
- DynamoFM_Log.success('\nConnected to MongoDB\n');
642
-
643
- resolve();
644
- })
645
- .on('error', (error): void => {
646
- if (!this.systemControls.mongoose.started) {
647
- this.constructErrors.push(error);
648
-
649
- if (this.debugLog) DynamoFM_Log.error(
650
- '\nUnable to connect to MongoDB server, ERROR: ',
651
- error
652
- );
653
-
654
- const d_error: DynamoFM_Error = new DynamoFM_Error({
655
- ...this._getDefaultErrorSettings(
656
- 'startDB',
657
- error
658
- ),
659
-
660
- errorCode: 'NTS-AS0-SDB1',
661
- message: `Unable to start connection to MongoDB server, ERROR: ${error}`,
662
- });
663
-
664
- DynamoNTS_GlobalService.globalErrorHandler?.(d_error);
665
- reject(d_error);
666
-
667
- } else {
668
- if (this.debugLog) DynamoFM_Log.error('\nMongoDB ERROR: ', error);
669
-
670
- const d_error: DynamoFM_Error = new DynamoFM_Error({
671
- ...this._getDefaultErrorSettings(
672
- 'mongoose.connection.on(error)',
673
- error
674
- ),
675
-
676
- errorCode: 'NTS-AS0-SDB2',
677
- message: `MongoDB ERROR: ${error}`,
678
- level: DynamoFM_ErrorLevel.critical,
679
- });
680
-
681
- DynamoNTS_GlobalService.globalErrorHandler?.(d_error);
682
- }
683
- });
684
-
685
- this.mongoose.connect(
686
- this._params.dbUri,
687
- {
688
- useNewUrlParser: true,
689
- useUnifiedTopology: true,
690
- }
691
- );
692
- }
693
- );
694
- }
695
-
696
- /**
697
- *
698
- */
699
- private async initExpresses(): Promise<void> {
700
- if (this.logFn && this.deepLog) DynamoFM_Log.log('\nfn:. initExpresses');
701
-
702
- if (this._security && this._security !== DynamoNTS_RouteSecurity.secure) {
703
- if (!this._portSettings.httpPort) {
704
- let errorMsg: string =
705
- `\nYou have open routes, but httpPort is not set!` +
706
- `\nsecurity: ${this._security}` +
707
- `\nset httpPort in DynamoBEServer - setupRoutingModules() to enable secure routes.`;
708
-
709
- errorMsg += '\n\nThe routes setted to use open server:';
710
- this._routingModules.forEach((module: DynamoNTS_RoutingModule): void => {
711
- if (module.security != DynamoNTS_RouteSecurity.secure) {
712
- errorMsg += `\n ${module.route} (security: ${module.security})`;
713
- errorMsg += `\n subroutes using open sever:`;
714
- module.endpoints.forEach((endpoint: DynamoNTS_Endpoint_Params): void => {
715
- if (endpoint.security != DynamoNTS_RouteSecurity.secure) {
716
- errorMsg += `\n ${endpoint.endpoint} (security: ${endpoint.security})`;
717
- }
718
- });
719
- }
720
- });
721
-
722
- const error = new Error('Open routes cannot be established!');
723
- const errorStack: string[] = error.stack.split('\n');
724
-
725
- errorStack.splice(1, 2);
726
- error.stack = errorStack.join('\n');
727
-
728
- DynamoFM_Log.error(errorMsg);
729
-
730
- throw error;
731
- }
732
-
733
- await this.initOpenExpress();
734
- }
735
-
736
- if (this._security && this._security !== DynamoNTS_RouteSecurity.open) {
737
- if (!this._cert || !this._portSettings.httpsPort) {
738
- let errorMsg: string =
739
- `\nYou have secure routes, but the certification paths or httpsPort are not set!` +
740
- `\nsecurity: ${this._security}` +
741
- `\nset...` +
742
- `\n(missing exact howto...)` +
743
- /* `\n httpsPort and` +
744
- `\n cert: {` +
745
- `\n keyPath: FileSystem.PathLike,` +
746
- `\n certPath: FileSystem.PathLike,` +
747
- `\n }` + */
748
- `\nin DynamoBEServer - getRoutingModules() to enable secure routes.`;
749
-
750
- errorMsg += '\n\nThe routes setted to use secure server:';
751
- this._routingModules.forEach((module: DynamoNTS_RoutingModule): void => {
752
- if (module.security && module.security !== DynamoNTS_RouteSecurity.open) {
753
- errorMsg += `\n ${module.route} (security: ${module.security})`;
754
- errorMsg += `\n subroutes using secure sever:`;
755
- module.endpoints.forEach((endpoint: DynamoNTS_Endpoint_Params): void => {
756
- if (endpoint.security && endpoint.security !== DynamoNTS_RouteSecurity.open) {
757
- errorMsg += `\n ${endpoint.endpoint} (security: ${endpoint.security})`;
758
- }
759
- });
760
- }
761
- });
762
-
763
- const error = new Error('Secure routes cannot be established!');
764
- const errorStack: string[] = error.stack.split('\n');
765
-
766
- errorStack.splice(1, 2);
767
- error.stack = errorStack.join('\n');
768
-
769
- DynamoFM_Log.error(errorMsg);
770
-
771
- throw error;
772
- }
773
-
774
- await this.initSecureExpress();
775
- }
776
- }
777
-
778
- /**
779
- *
780
- */
781
- protected async initOpenExpress(): Promise<void> {
782
- if (this.logFn) DynamoFM_Log.log('\nfn:. initOpenExpress');
783
- this.openExpress = Express();
784
- this.openExpress.use(BodyParser.urlencoded(this._portSettings.httpUrlencoded));
785
- this.openExpress.use(BodyParser.json(this._portSettings.httpJson));
786
- }
787
-
788
- /**
789
- *
790
- */
791
- protected async initSecureExpress(): Promise<void> {
792
- if (this.logFn) DynamoFM_Log.log('\nfn:. initSecureExpress');
793
- this.secureExpress = Express();
794
- this.secureExpress.use(BodyParser.urlencoded(this._portSettings.httpsUrlencoded));
795
- this.secureExpress.use(BodyParser.json(this._portSettings.httpsJson));
796
-
797
- const options = {
798
- key: FileSystem.readFileSync(this._cert.keyPath),
799
- cert: FileSystem.readFileSync(this._cert.certPath),
800
- };
801
-
802
- this.httpsServer = Https.createServer(options, this.secureExpress);
803
- }
804
-
805
- /**
806
- *
807
- */
808
- private async startExpresses(): Promise<void> {
809
- if (this.logFn && this.deepLog) DynamoFM_Log.log('\nfn:. startExpresses');
810
- try {
811
- if (this._security && this._security !== DynamoNTS_RouteSecurity.open) {
812
- await new Promise<void>((resolve, reject): void => {
813
- this.systemControls.httpsServer.init = true;
814
- this.httpsServer
815
- .listen(this._portSettings.httpsPort, 'localhost', 0, (): void => {
816
- this.systemControls.httpsServer.started = true;
817
- DynamoFM_Log.success(
818
- `\nHTTPS (secure) server is listening on port: ${this._portSettings.httpsPort}`
819
- );
820
-
821
- resolve();
822
- })
823
- .on('error', (error): void => {
824
- if (this.debugLog) DynamoFM_Log.error(`\nHTTPS (secure) server ERROR`, error);
825
-
826
- if (!this.systemControls.httpsServer.started) {
827
- const d_error: DynamoFM_Error = new DynamoFM_Error({
828
- ...this._getDefaultErrorSettings(
829
- 'startExpresses',
830
- error
831
- ),
832
-
833
- errorCode: 'NTS-AS0-SE1',
834
- message: `HTTPS (secure) start server ERROR`,
835
- });
836
-
837
- this.constructErrors.push(d_error);
838
- DynamoNTS_GlobalService.globalErrorHandler?.(d_error);
839
-
840
- reject(d_error);
841
-
842
- } else {
843
- const d_error: DynamoFM_Error = new DynamoFM_Error({
844
- ...this._getDefaultErrorSettings(
845
- 'httpsServer.on(error)',
846
- error
847
- ),
848
-
849
- errorCode: 'NTS-AS0-SE2',
850
- message: `HTTPS (secure) server ERROR`,
851
- level: DynamoFM_ErrorLevel.serious,
852
- });
853
-
854
- DynamoNTS_GlobalService.globalErrorHandler?.(d_error);
855
- }
856
- })
857
- .on('uncaughtException', (exception): void => {
858
- const d_error: DynamoFM_Error = new DynamoFM_Error({
859
- ...this._getDefaultErrorSettings(
860
- 'httpsServer.on(uncaughtException)',
861
- exception
862
- ),
863
-
864
- errorCode: 'NTS-AS0-SE3',
865
- message: `HTTPS (secure) server uncaughtException`,
866
- level: DynamoFM_ErrorLevel.critical,
867
- });
868
-
869
- if (this.debugLog) DynamoFM_Log.warn(
870
- `\nHTTPS (secure) server uncaughtException`,
871
- d_error
872
- );
873
-
874
- DynamoNTS_GlobalService.globalErrorHandler?.(d_error);
875
- });
876
- });
877
- }
878
-
879
- if (this._security && this._security !== DynamoNTS_RouteSecurity.secure) {
880
- this.systemControls.httpServer.init = true;
881
- await new Promise<void>((resolve, reject): void => {
882
- this.httpServer = this.openExpress
883
- .listen(this._portSettings.httpPort, (): void => {
884
- this.systemControls.httpServer.started = true;
885
- DynamoFM_Log.success(
886
- `\nHTTP (open) server is listening on port: ${this._portSettings.httpPort}`
887
- );
888
-
889
- resolve();
890
- })
891
- .on('error', (error): void => {
892
- if (this.debugLog) DynamoFM_Log.error(`\nHTTP (open) server ERROR`, error);
893
-
894
- if (!this.systemControls.httpServer.started) {
895
- const d_error: DynamoFM_Error = new DynamoFM_Error({
896
- ...this._getDefaultErrorSettings(
897
- 'startExpresses',
898
- error
899
- ),
900
-
901
- errorCode: 'NTS-AS0-SE3',
902
- message: `HTTP (open) start server ERROR`,
903
- });
904
-
905
- this.constructErrors.push(d_error);
906
- DynamoNTS_GlobalService.globalErrorHandler?.(d_error);
907
-
908
- reject(d_error);
909
-
910
- } else {
911
- const d_error: DynamoFM_Error = new DynamoFM_Error({
912
- ...this._getDefaultErrorSettings(
913
- 'httpServer.on(error)',
914
- error
915
- ),
916
-
917
- errorCode: 'NTS-AS0-SE4',
918
- message: `HTTP (open) server ERROR`,
919
- level: DynamoFM_ErrorLevel.serious,
920
- });
921
-
922
- DynamoNTS_GlobalService.globalErrorHandler?.(d_error);
923
- }
924
- })
925
- .on('uncaughtException', (exception): void => {
926
- const d_error: DynamoFM_Error = new DynamoFM_Error({
927
- ...this._getDefaultErrorSettings(
928
- 'httpServer.on(uncaughtException)',
929
- exception
930
- ),
931
-
932
- errorCode: 'NTS-AS0-SE5',
933
- message: `HTTP (open) server uncaughtException`,
934
- level: DynamoFM_ErrorLevel.critical,
935
- });
936
-
937
- if (this.debugLog) {
938
- DynamoFM_Log.warn(`\nHTTP (open) server uncaughtException`, d_error);
939
- }
940
-
941
- DynamoNTS_GlobalService.globalErrorHandler?.(d_error);
942
- });
943
- });
944
- }
945
- } catch (error) {
946
- DynamoFM_Log.error(`startExpresses failed...`, error);
947
-
948
- throw error;
949
- }
950
- }
951
-
952
- /**
953
- *
954
- */
955
- private async expressErrorHandling(error, req, res, next): Promise<void> {
956
- try {
957
- if (error) {
958
- const d_error: DynamoFM_Error = new DynamoFM_Error({
959
- ...this._getDefaultErrorSettings(
960
- 'expressErrorHandling',
961
- error
962
- ),
963
-
964
- errorCode: 'NTS-AS0-EEH1',
965
- message: `Express ERROR`,
966
- additionalContent: {
967
- req,
968
- res,
969
- },
970
- level: DynamoFM_ErrorLevel.error,
971
- });
972
-
973
- await DynamoNTS_GlobalService.globalErrorHandler?.(d_error, req, res);
974
-
975
- } else {
976
- DynamoFM_Log.H_error(
977
- 'WTF??? express error; without error?...' +
978
- '\nerr:', error,
979
- '\nreq:', req,
980
- '\nres:', res
981
- );
982
- }
983
- } catch (error) {
984
- DynamoFM_Log.H_error(
985
- 'MULTILEVEL ERROR (expressErrorHandling)....' +
986
- '\n', error
987
- );
988
- }
989
- }
990
-
991
- /**
992
- *
993
- */
994
- private async mountSecureRoutes (): Promise<void> {
995
- if (this.logFn && this.deepLog) DynamoFM_Log.log('\nfn:. mountSecureRoutes');
996
-
997
- this.openExpress.use(
998
- (error, req, res, next): Promise<void> => this.expressErrorHandling(error, req, res, next)
999
- );
1000
-
1001
- await DynamoFM_Array.asyncForEach(
1002
- this._routingModules,
1003
- async (module: DynamoNTS_RoutingModule): Promise<void> => {
1004
- if (module.security !== DynamoNTS_RouteSecurity.open) {
1005
- if (this.logSetup) {
1006
- DynamoFM_Log.log(`route mount (secure): ${module.route}`);
1007
- }
1008
-
1009
- const existingRoutes: DynamoNTS_RoutingModule[] = this._routingModules.filter(
1010
- (mod: DynamoNTS_RoutingModule): boolean => mod.route === module.route
1011
- );
1012
-
1013
- if (1 < existingRoutes.length) {
1014
- const error: Error = new Error(`ROUTE DUPLICATION: ${module.route}`);
1015
- const errorStack: string[] = error.stack.split('\n');
1016
-
1017
- errorStack.splice(1, 4);
1018
- error.stack = errorStack.join('\n');
1019
-
1020
- DynamoFM_Log.error(`ROUTE DUPLICATION: ${module.route}`, error);
1021
-
1022
- throw new DynamoFM_Error({
1023
- ...this._getDefaultErrorSettings(
1024
- 'mountSecureRoutes',
1025
- error
1026
- ),
1027
-
1028
- errorCode: 'NTS-AS0-MSR1',
1029
- message: `ROUTE DUPLICATION: ${module.route}`,
1030
- });
1031
- }
1032
-
1033
- this.secureExpress.use(module.route, module.secureRouter);
1034
- }
1035
- }
1036
- );
1037
- }
1038
-
1039
- /**
1040
- *
1041
- */
1042
- private async mountOpenRoutes(): Promise<void> {
1043
- if (this.logFn && this.deepLog) DynamoFM_Log.log('\nfn:. mountOpenRoutes');
1044
-
1045
- this.openExpress.use(
1046
- (error, req, res, next): Promise<void> => this.expressErrorHandling(error, req, res, next)
1047
- );
1048
-
1049
- await DynamoFM_Array.asyncForEach(
1050
- this._routingModules,
1051
- async (module: DynamoNTS_RoutingModule): Promise<void> => {
1052
- if (module.security !== DynamoNTS_RouteSecurity.secure) {
1053
- if (this.logSetup) {
1054
- DynamoFM_Log.log(`route mount (open): ${module.route}`);
1055
- }
1056
-
1057
- const existingRoutes: DynamoNTS_RoutingModule[] = this._routingModules.filter(
1058
- (mod: DynamoNTS_RoutingModule): boolean => mod.route === module.route
1059
- );
1060
-
1061
- if (1 < existingRoutes.length) {
1062
- const error: Error = new Error(`ROUTE DUPLICATION: ${module.route}`);
1063
- const errorStack: string[] = error.stack.split('\n');
1064
-
1065
- errorStack.splice(1, 4);
1066
- error.stack = errorStack.join('\n');
1067
-
1068
- DynamoFM_Log.error(`ROUTE DUPLICATION: ${module.route}`, error);
1069
-
1070
- throw new DynamoFM_Error({
1071
- ...this._getDefaultErrorSettings(
1072
- 'mountOpenRoutes',
1073
- error
1074
- ),
1075
-
1076
- errorCode: 'NTS-AS0-MOR1',
1077
- message: `ROUTE DUPLICATION: ${module.route}`,
1078
- });
1079
- }
1080
-
1081
- this.openExpress.use(module.route, module.openRouter);
1082
- }
1083
- }
1084
- );
1085
- }
1086
-
1087
- /**
1088
- *
1089
- */
1090
- private setSecurity(): void {
1091
- if (this.logFn && this.deepLog) DynamoFM_Log.log('\nfn:. setSecurity');
1092
- this._routingModules.forEach((module: DynamoNTS_RoutingModule): void => {
1093
- if (!module.security) {
1094
- DynamoFM_Log.warn(`RoutingModule security is not set for ${module.route}\n`);
1095
-
1096
- } else if (!this._security) {
1097
- this._security = module.security;
1098
-
1099
- } else if (this._security !== module.security) {
1100
- this._security = DynamoNTS_RouteSecurity.both;
1101
- }
1102
- });
1103
-
1104
- if (!this._security) {
1105
- let msg = `Could not set security for the server! (${this.security})`;
1106
-
1107
- msg += '\n RoutingModules:';
1108
- this._routingModules.forEach((module: DynamoNTS_RoutingModule): void => {
1109
- msg += `\n ${module.route} (security: ${module.security})`;
1110
- });
1111
-
1112
- if (this._routingModules.length === 0) {
1113
- msg += '\n - no RoutingModule found -\n';
1114
- }
1115
- DynamoFM_Log.warn(msg);
1116
- }
1117
- }
1118
-
1119
- private _getDefaultErrorSettings(
1120
- fnName: string,
1121
- error: DynamoFM_AnyError
1122
- ): DynamoFM_Error_Settings {
1123
- return {
1124
- status: (error as DynamoFM_Error)?.___status ?? 500,
1125
- message: (error as Error)?.message ?? `${fnName} was UNSUCCESSFUL (NTS)`,
1126
- addECToUserMsg: !(error as DynamoFM_Error)?.__userMessage,
1127
- userMessage: (error as DynamoFM_Error)?.__userMessage ?? this.defaultErrorUserMsg,
1128
- issuerService: `${this?.constructor?.name}-DynamoNTS_App`,
1129
- error: error,
1130
- level: DynamoFM_ErrorLevel.fatal,
1131
- };
1132
- }
1133
-
1134
- /**
1135
- * MISSING Description (TODO)
1136
- */
1137
- abstract getAppParams(): DynamoNTS_App_Params;
1138
-
1139
- /**
1140
- * MISSING Description (TODO)
1141
- */
1142
- abstract getGlobalServiceCollection(): DynamoNTS_GlobalService_Settings;
1143
-
1144
- /**
1145
- * MISSING Description (TODO)
1146
- */
1147
- abstract getPortSettings(): DynamoNTS_Http_Settings;
1148
-
1149
- /**
1150
- * MISSING Description (TODO)
1151
- */
1152
- overrideDynamoNTSGlobalSettings?(): void;
1153
-
1154
- /**
1155
- * MISSING Description (TODO)
1156
- */
1157
- getRoutingModules?(): DynamoNTS_RoutingModule[];
1158
-
1159
- /**
1160
- * MISSING Description (TODO)
1161
- */
1162
- getRootServices?(): Promise<DynamoNTS_SingletonService[]>;
1163
-
1164
- /**
1165
- * MISSING Description (TODO)
1166
- */
1167
- getCertificationSettings?(): DynamoNTS_Certification_Settings;
1168
-
1169
- /**
1170
- * MISSING Description (TODO)
1171
- */
1172
- createEntries?(): Promise<void>;
1173
-
1174
- /**
1175
- * MISSING Description (TODO)
1176
- */
1177
- postProcess?(): Promise<void>;
1178
-
1179
- }
1
+
2
+ import Mongoose = require('mongoose');
3
+ import Express = require('express');
4
+ /* import Mongoose from 'mongoose';
5
+ import Express from 'express'; */
6
+
7
+ import * as Http from 'http';
8
+ import * as Https from 'https';
9
+ import * as FileSystem from 'fs';
10
+ import * as BodyParser from 'body-parser';
11
+
12
+ /* import { version } from '../../../package.json'; */
13
+
14
+ import {
15
+ DynamoFM_AnyError,
16
+ DynamoFM_Array, DynamoFM_Error, DynamoFM_error_defaults,
17
+ DynamoFM_Error_Settings,
18
+ DynamoFM_ErrorLevel, DynamoFM_Log, second, DynamoFM_wait
19
+ } from '@futdevpro/fsm-dynamo';
20
+
21
+ import { DynamoNTS_SingletonService } from '../base/singleton.service';
22
+ import { DynamoNTS_RouteSecurity } from '../../_enums/route-security.enum';
23
+ import { DynamoNTS_RoutingModule } from '../route/routing-module.service';
24
+ import { DynamoNTS_GlobalService } from '../core/global.service';
25
+ import { DynamoNTS_Http_Settings } from '../../_models/control-models/http-settings.control-model';
26
+ import {
27
+ DynamoNTS_Certification_Settings
28
+ } from '../../_models/interfaces/certification-settings.interface';
29
+ import {
30
+ DynamoNTS_GlobalService_Settings
31
+ } from '../../_models/interfaces/global-service-settings.interface';
32
+ import { DynamoNTS_globalSettings } from '../../_constants/global-settings.const';
33
+ import { DynamoNTS_App_Params } from '../../_models/control-models/app-params.control-model';
34
+ import {
35
+ DynamoNTS_Endpoint_Params
36
+ } from '../../_models/control-models/endpoint-params.control-model';
37
+ import {
38
+ DynamoNTS_AppSystemControls
39
+ } from '../../_models/control-models/app-system-controls.control-model';
40
+
41
+
42
+ /**
43
+ * This will be the MAIN service of our server project,
44
+ * follow the types and type instructions while setting up your project
45
+ *
46
+ * In this service, there are abstract functions that you will need to implement,
47
+ * where you need to set up the main params for your application.
48
+ *
49
+ * (after the example, you can find the list of services you can/should setup)
50
+ *
51
+ * @example
52
+ * export class App extends DynamoNTS_AppExtended {
53
+ *
54
+ * ...
55
+ *
56
+ * // Setting up App params, and preparing project global settings
57
+ * setupAppParams(): void {
58
+ * this.params = new DynamoNTS_AppParams({
59
+ * name: 'Warbots Server',
60
+ * title: warbotsTitleLog,
61
+ * version: version,
62
+ * dbName: 'warbots',
63
+ * });
64
+ *
65
+ * // dynamoNTS_GlobalSettings.logRequestsContent = false;
66
+ * }
67
+ *
68
+ * ...
69
+ *
70
+ * // Setting up DBServices
71
+ * setGlobalServiceCollection(): void {
72
+ * DynamoNTS_GlobalService.setServices({
73
+ * authService: AuthService.getInstance(),
74
+ * emailServiceCollection: EmailServiceCollectionService.getInstance(),
75
+ * dbModels: [
76
+ * userModelParams,
77
+ * userDataModelParams,
78
+ * userOptionsModelParams,
79
+ * userStatisticsModelParams,
80
+ * userAchievementsModelParams,
81
+ * userNotificationsModelParams,
82
+ *
83
+ * matchStatisticsModelParams,
84
+ * matchDataModelParams,
85
+
86
+ * DynamoFM_usageSessionModel_params,
87
+ * DynamoFM_customDataModel_params,
88
+ * ]
89
+ * });
90
+ * }
91
+ *
92
+ * ...
93
+ *
94
+ * // Setting up Routes
95
+ * setupRoutingModules(): void {
96
+ * this.httpPort = env.port;
97
+
98
+ * this.routingModules = [
99
+ * new DynamoNTS_RoutingModule({
100
+ * route: '/user',
101
+ * controllers: [
102
+ * UserController.getInstance(),
103
+ * UserDataController.getInstance(),
104
+ * UserOptionsController.getInstance(),
105
+ * UserStatisticsController.getInstance(),
106
+ * UserAchievementsController.getInstance(),
107
+ * UserNotificationsController.getInstance()
108
+ * ]
109
+ * }),
110
+ * new DynamoNTS_RoutingModule({
111
+ * route: '/match',
112
+ * controllers: [
113
+ * MatchController.getInstance(),
114
+ * MatchDistributionController.getInstance(),
115
+ * MatchStatisticsController.getInstance(),
116
+ * ]
117
+ * }),
118
+ * new DynamoNTS_RoutingModule({
119
+ * route: '/server',
120
+ * controllers: [
121
+ * ServerController.getInstance(),
122
+ * ]
123
+ * }),
124
+
125
+ * getTestRoutingModule(),
126
+ * getUsageRoutingModule()
127
+ * ];
128
+ * }
129
+ * }
130
+ *
131
+ * //
132
+ * // The Services available
133
+ * //
134
+ * // Authentication Service
135
+ * // A commonly used basic service,
136
+ * // which is necessary fur certain functions (such as registering call issuers)
137
+ * //
138
+ * // This will handle Authentication Token checking/refreshing,
139
+ * // checking issuer's identifier and routeParams,
140
+ * // handling JWT Token, or maybe with OAuth2 or other commonly used security procedures
141
+ * //
142
+ * // You can create one with this Dynamo Object:
143
+ * //
144
+ *
145
+ * @example
146
+ * // follow the instructions on the abstract class (DynamoNTS_AuthService)
147
+ * export class AuthService extends DynamoNTS_AuthService {}
148
+ *
149
+ *
150
+ *
151
+ * //
152
+ */
153
+
154
+ /**
155
+ * This will be the MAIN service of our server project,
156
+ * follow the types and type instructions while setting up your project
157
+ *
158
+ * In this service, there are abstract functions that you will need to implement,
159
+ * where you need to set up the main params for your application.
160
+ *
161
+ * (after the example, you can find the list of services you can/should setup)
162
+ *
163
+ * You need to setup the following functions:
164
+ * ```ts
165
+ * // this is where you set up the main params for your application
166
+ * getAppParams(): DynamoNTS_AppParams
167
+ *
168
+ * // this is where you connect your main services
169
+ * getGlobalServiceSettings(): DynamoNTS_GlobalServiceSettings
170
+ *
171
+ * // this is where you set up your ports
172
+ * getPorts(): DynamoNTS_PortSettings
173
+ *
174
+ * // this is where you set up your routes
175
+ * getRoutingModules(): DynamoNTS_RoutingModule[]
176
+ *
177
+ *
178
+ *
179
+ * ```
180
+ * optionally you can setup the following functions:
181
+ * ```ts
182
+ * // this is where you set up your certifications
183
+ * getCertificationSettings(): DynamoNTS_CertificationSettings
184
+ *
185
+ * // this is where you set up additional root services
186
+ * getRootServices(): DynamoNTS_SingletonService[]
187
+ *
188
+ * // this is where you set up your initial db entries
189
+ * createEntries(): void
190
+ *
191
+ * // this is where you can define post setup processes
192
+ * postProcess(): void
193
+ *
194
+ *
195
+ *
196
+ * ```
197
+ *
198
+ */
199
+ export abstract class DynamoNTS_App extends DynamoNTS_SingletonService {
200
+
201
+ // TODO: rename all DynamoNTS_ > DyNTS_ ------------------------------------------------------------------------------------------------------------------------------------
202
+
203
+ protected systemControls: DynamoNTS_AppSystemControls = new DynamoNTS_AppSystemControls();
204
+ get started(): boolean {
205
+ return this.systemControls.app.started;
206
+ }
207
+ protected get superStarted(): boolean {
208
+ return this.systemControls.app.started;
209
+ }
210
+ protected constructErrors: (Error | DynamoFM_Error)[] = [];
211
+
212
+ /* removed since cant use version from package.json
213
+ private readonly _ntsVersion: string = 'v01.07.18';
214
+ protected get ntsVersion(): string {
215
+ return this._ntsVersion;
216
+ } */
217
+
218
+ get serverName(): string {
219
+ return this.params.name;
220
+ }
221
+
222
+ private _params: DynamoNTS_App_Params;
223
+ protected get params(): DynamoNTS_App_Params {
224
+ return this._params;
225
+ }
226
+
227
+ protected mongoose = Mongoose;
228
+
229
+ private _security: DynamoNTS_RouteSecurity;
230
+ protected get security(): DynamoNTS_RouteSecurity {
231
+ return this._security;
232
+ }
233
+
234
+ protected _portSettings: DynamoNTS_Http_Settings = new DynamoNTS_Http_Settings();
235
+ protected get portSettings(): DynamoNTS_Http_Settings {
236
+ return this._portSettings;
237
+ }
238
+
239
+ private _cert?: DynamoNTS_Certification_Settings;
240
+ protected get cert(): DynamoNTS_Certification_Settings {
241
+ return this._cert;
242
+ }
243
+
244
+ protected openExpress: Express.Application;
245
+ private secureExpress: Express.Application;
246
+ protected httpsServer: Https.Server;
247
+ protected httpServer: Http.Server;
248
+
249
+ private globalService: DynamoNTS_GlobalService;
250
+ private _rootServices: DynamoNTS_SingletonService[] = [];
251
+
252
+ private _routingModules: DynamoNTS_RoutingModule[] = [];
253
+
254
+ defaultErrorUserMsg =
255
+ `We encountered a Server Error, ` +
256
+ `\nplease contact the responsible development team.\n` +
257
+ `\n(Internal Server error)`;
258
+
259
+ /**
260
+ * setting this value to true, enables this service debug logs
261
+ */
262
+ protected logSetup: boolean;
263
+ protected deepLog: boolean;
264
+ protected logFn: boolean;
265
+ protected debugLog: boolean;
266
+
267
+ constructor(extended?: boolean){
268
+ super();
269
+
270
+ process.on('unhandledRejection', (reason: object, p_passWhatIsThis: any): void => {
271
+ DynamoFM_Log.highlightedError(
272
+ 'Unhandled Rejection at: ', p_passWhatIsThis,
273
+ '\nRejection reason:', reason
274
+ );
275
+
276
+ try {
277
+ DynamoNTS_GlobalService.globalErrorHandler?.(
278
+ new DynamoFM_Error({
279
+ errorCode: 'NTS-AS0-BASE-UR',
280
+ message: 'Unhandled Rejection!',
281
+ error: new Error(p_passWhatIsThis),
282
+ additionalContent: {
283
+ reason: reason,
284
+ p_noIdeaWhatIsThisFromProcessRejection: p_passWhatIsThis,
285
+ },
286
+ level: DynamoFM_ErrorLevel.critical,
287
+ })
288
+ );
289
+
290
+ } catch (error) {
291
+ DynamoFM_Log.error('globalErrorHandler (MULTILEVEL) ERROR:', error);
292
+ }
293
+ });
294
+
295
+ this.asyncConstruct(extended).catch((error: any): void => {
296
+ DynamoFM_Log.error(
297
+ `\nApplication: ${this._params.name} start failed.` +
298
+ `\n`, error
299
+ );
300
+
301
+ if (error?.flag?.includes?.('DYNAMO-ERROR-OBJECT')) {
302
+ DynamoFM_Log.error(`\nErrorMessage: ${(error as DynamoFM_Error)._message}`);
303
+ DynamoFM_Log.error(`ErrorCode: ${(error as DynamoFM_Error)._errorCode}`);
304
+ DynamoFM_Log.error(`UserMessage: ${(error as DynamoFM_Error).__userMessage}`);
305
+ }
306
+ });
307
+ }
308
+
309
+ private async asyncConstruct(extended?: boolean): Promise<void> {
310
+ if (this.logFn && this.deepLog) DynamoFM_Log.log('\nfn:. asyncConstruct');
311
+ try {
312
+ this.systemControls.app.init = true;
313
+ this._params = this.getAppParams();
314
+ DynamoFM_Log.log(
315
+ `\n\n\n\n\n\n\n\n\n\n` +
316
+ `Starting ${this._params?.name}... ` +
317
+ /* `v${version}` + */
318
+ `\n\n\n\n\n\n\n\n\n\n`
319
+ );
320
+
321
+ if (!this._params) {
322
+ throw new Error('getAppParams() must return a DynamoNTS_AppParams object!');
323
+ }
324
+
325
+ process.stdout.write(
326
+ String.fromCharCode(27) + ']0;' +
327
+ this._params?.name +
328
+ String.fromCharCode(7)
329
+ );
330
+
331
+ DynamoFM_error_defaults.issuerSystem = this._params.systemName;
332
+
333
+ this.overrideDynamoNTSGlobalSettings?.();
334
+
335
+ this.logSetup = DynamoNTS_globalSettings.logSetup;
336
+
337
+ this.globalService = DynamoNTS_GlobalService.getInstance();
338
+ await DynamoNTS_GlobalService.setServices(this.getGlobalServiceCollection());
339
+ DynamoNTS_GlobalService.setParams(this.params);
340
+
341
+ if (this.getPortSettings) {
342
+ this._portSettings = this.getPortSettings();
343
+ }
344
+
345
+ if (this.getCertificationSettings) {
346
+ this._cert = this.getCertificationSettings();
347
+ }
348
+
349
+ if (this.getRoutingModules) {
350
+ this._routingModules = this.getRoutingModules();
351
+ }
352
+
353
+ await this.startDB();
354
+
355
+ await this.createEntries?.();
356
+
357
+ this.setSecurity();
358
+
359
+ if (this._routingModules?.length) {
360
+ await this.initExpresses();
361
+ await this.startExpresses();
362
+
363
+ if (this._security !== DynamoNTS_RouteSecurity.secure) {
364
+ await this.mountOpenRoutes();
365
+ }
366
+
367
+ if (this._security !== DynamoNTS_RouteSecurity.open && this._cert) {
368
+ await this.mountSecureRoutes();
369
+ }
370
+
371
+ if (this.logSetup) {
372
+ DynamoFM_Log.log(`\nRoutes mounted.... server using security: ${this._security}`);
373
+ }
374
+ }
375
+
376
+ if (this.getRootServices) {
377
+ this._rootServices = await this.getRootServices();
378
+ }
379
+
380
+ await this.postProcess?.();
381
+
382
+ if (!extended) {
383
+ await this.ready();
384
+
385
+ if (this.params.title) {
386
+ DynamoFM_Log.success(this.params.title);
387
+ }
388
+ DynamoFM_Log.info(`Version: ${this.params.version}`);
389
+ /* DynamoFM_Log.info(`NTS Version: ${this.ntsVersion}`); */
390
+ DynamoFM_Log.H_success(`${this.params.name} started successfully.`);
391
+ }
392
+ } catch (error) {
393
+ this.constructErrors.push(error);
394
+ DynamoFM_Log.error(
395
+ `${this._params.name} start failed. ERRORS`,
396
+ this.constructErrors,
397
+ error
398
+ );
399
+
400
+ throw new DynamoFM_Error({
401
+ ...this._getDefaultErrorSettings(
402
+ 'asyncConstruct',
403
+ error
404
+ ),
405
+
406
+ errorCode: 'NTS-AS0-001',
407
+ additionalContent: {
408
+ constructErrors: this.constructErrors,
409
+ systemControls: this.systemControls,
410
+ systemReadies: {
411
+ app: this.systemControls.app.getReady(),
412
+ mongoose: this.systemControls.mongoose.getReady(),
413
+ httpServer: this.systemControls.httpServer.getReady(),
414
+ httpsServer: this.systemControls.httpsServer.getReady(),
415
+ },
416
+ },
417
+ });
418
+ }
419
+ }
420
+
421
+ async ready(timeout: number = 4 * second): Promise<void> {
422
+ if (this.logFn) DynamoFM_Log.log('\nfn:. ready');
423
+ let ready: boolean = false;
424
+ const start: number = +new Date();
425
+
426
+ if (this.constructErrors.length) {
427
+ DynamoFM_Log.error(
428
+ `${this._params.name} start failed. \nERRORS:`,
429
+ this.constructErrors
430
+ );
431
+
432
+ throw new DynamoFM_Error({
433
+ ...this._getDefaultErrorSettings(
434
+ 'ready',
435
+ new Error(`${this._params.name} start failed. ERRORS`)
436
+ ),
437
+
438
+ errorCode: 'NTS-AS0-R01',
439
+ additionalContent:
440
+ this.constructErrors.length === 1 ?
441
+ this.constructErrors[0] :
442
+ { errors: this.constructErrors },
443
+ });
444
+ }
445
+
446
+ while (!ready && +new Date() - start < timeout) {
447
+ if (this.systemControls.app.init) {
448
+ ready = (
449
+ this.systemControls.mongoose.getReady() &&
450
+ this.systemControls.httpServer.getReady() &&
451
+ this.systemControls.httpsServer.getReady()
452
+ );
453
+ } else {
454
+ DynamoFM_Log.error(`${this.params.name} APP NOT INITIALIZED while trying to get ready.`);
455
+ }
456
+
457
+ if (!ready) {
458
+ await DynamoFM_wait(100);
459
+ }
460
+ }
461
+
462
+ if (timeout < +new Date() - start) {
463
+ DynamoFM_Log.error(`${this._params.name} start failed. TIMEOUT`, this.constructErrors);
464
+
465
+ throw new DynamoFM_Error({
466
+ ...this._getDefaultErrorSettings(
467
+ 'ready',
468
+ new Error(`${this._params.name} start failed. TIMEOUT`)
469
+ ),
470
+
471
+ errorCode: 'NTS-AS0-R02',
472
+ additionalContent: {
473
+ constructErrors: this.constructErrors,
474
+ systemControls: this.systemControls,
475
+ systemReadies: {
476
+ mongoose: this.systemControls.mongoose.getReady(),
477
+ httpServer: this.systemControls.httpServer.getReady(),
478
+ httpsServer: this.systemControls.httpsServer.getReady(),
479
+ },
480
+ },
481
+ });
482
+ }
483
+
484
+ if (this.constructErrors.length) {
485
+ DynamoFM_Log.error(`${this._params.name} start failed. ERROR`, this.constructErrors);
486
+
487
+ throw new DynamoFM_Error({
488
+ ...this._getDefaultErrorSettings(
489
+ 'ready',
490
+ new Error(`${this._params.name} start failed. ERROR`)
491
+ ),
492
+
493
+ errorCode: 'NTS-AS0-R03',
494
+ additionalContent: this.constructErrors,
495
+ });
496
+ }
497
+
498
+ if (ready) {
499
+ this.systemControls.app.started = true;
500
+
501
+ if (this.logFn && this.deepLog) DynamoFM_Log.log('\nfn:. ready: return');
502
+
503
+ return;
504
+ } else {
505
+ this.systemControls.app.started = false;
506
+
507
+ let msg: string = `${this._params.name} start failed. UNKNOWN`;
508
+
509
+ if (this.systemControls.mongoose.init && !this.systemControls.mongoose.started) {
510
+ msg += `\nMongoose start failed.`;
511
+ }
512
+
513
+ if (this.systemControls.httpServer.init && !this.systemControls.httpServer.started) {
514
+ msg += `\nHTTP Server start failed.`;
515
+ }
516
+
517
+ if (this.systemControls.httpsServer.init && !this.systemControls.httpsServer.started) {
518
+ msg += `\nHTTPS Server start failed.`;
519
+ }
520
+
521
+ DynamoFM_Log.error(msg, this.constructErrors);
522
+
523
+ throw new DynamoFM_Error({
524
+ ...this._getDefaultErrorSettings(
525
+ 'ready',
526
+ new Error(msg)
527
+ ),
528
+
529
+ errorCode: 'NTS-AS0-R04',
530
+ additionalContent: {
531
+ constructErrors: this.constructErrors,
532
+ systemControls: this.systemControls,
533
+ systemReadies: {
534
+ app: this.systemControls.app.getReady(),
535
+ mongoose: this.systemControls.mongoose.getReady(),
536
+ httpServer: this.systemControls.httpServer.getReady(),
537
+ httpsServer: this.systemControls.httpsServer.getReady(),
538
+ },
539
+ },
540
+ error: this.constructErrors?.[0] ?? new Error(),
541
+ });
542
+ }
543
+ }
544
+
545
+ async stop(dontLog?: boolean): Promise<void> {
546
+ DynamoFM_Log.info('\nstoping server...\n');
547
+
548
+ await this.ready();
549
+
550
+ if (this.started) {
551
+
552
+ if (this.systemControls.mongoose.init) {
553
+ DynamoFM_Log.info(`\nstopping Mongoose....`);
554
+
555
+ let tryCount: number = 0;
556
+
557
+ while (
558
+ !this.systemControls.mongoose.started &&
559
+ !this.constructErrors.length &&
560
+ tryCount++ < 10
561
+ ) {
562
+ DynamoFM_Log.warn(`Mongoose not even started yet....`);
563
+ await DynamoFM_wait(second);
564
+ }
565
+ this.systemControls.mongoose.started = false;
566
+
567
+ if (this.mongoose) {
568
+ await DynamoFM_Array.asyncForEach(
569
+ Object.keys(this.mongoose.models),
570
+ async (modelName): Promise<void> => {
571
+ await this.mongoose.deleteModel(modelName);
572
+ }
573
+ );
574
+
575
+ const disconnect: Promise<void> = new Promise((resolve): void => {
576
+ this.mongoose.connection.on('disconnecting', (): void => {
577
+ resolve();
578
+ });
579
+ });
580
+
581
+ await this.mongoose.disconnect();
582
+ await this.mongoose.connection.close();
583
+ await disconnect;
584
+
585
+ while (
586
+ this.mongoose.connection.readyState !== 0 &&
587
+ !this.constructErrors.length
588
+ ) {
589
+ DynamoFM_Log.warn(`\nMongoose still not disconnected....`);
590
+ await DynamoFM_wait(second);
591
+ }
592
+ } else {
593
+ DynamoFM_Log.error(`\nMongoose not found.`);
594
+ }
595
+ this.systemControls.mongoose.init = false;
596
+ }
597
+
598
+ if (this.systemControls.httpServer.init) {
599
+ this.systemControls.httpServer.started = false;
600
+
601
+ if (this.httpServer) {
602
+ await new Promise((resolve): void => {
603
+ this.httpServer.close(resolve);
604
+ });
605
+ } else {
606
+ DynamoFM_Log.error(`\nHTTP Server not found.`);
607
+ }
608
+ this.systemControls.httpServer.init = false;
609
+ }
610
+
611
+ if (this.systemControls.httpsServer.init) {
612
+ this.systemControls.httpsServer.started = false;
613
+
614
+ if (this.httpsServer) {
615
+ await new Promise((resolve): void => {
616
+ this.httpsServer.close(resolve);
617
+ });
618
+ } else {
619
+ DynamoFM_Log.error(`\nHTTPS Server not found.`);
620
+ }
621
+ this.systemControls.httpsServer.init = false;
622
+ }
623
+
624
+ if (!dontLog) {
625
+ DynamoFM_Log.H_log(`${this._params.name} stopped successfully.`);
626
+ }
627
+ }
628
+ }
629
+
630
+ /**
631
+ *
632
+ */
633
+ private async startDB(): Promise<void> {
634
+ if (this.logFn && this.deepLog) DynamoFM_Log.log('\nfn:. startDB');
635
+
636
+ await new Promise<void>(
637
+ (resolve, reject): void => {
638
+ this.systemControls.mongoose.init = true;
639
+
640
+ this.mongoose.connection
641
+ .once('open', (): void => {
642
+ this.systemControls.mongoose.started = true;
643
+ DynamoFM_Log.success('\nConnected to MongoDB\n');
644
+
645
+ resolve();
646
+ })
647
+ .on('error', (error): void => {
648
+ if (!this.systemControls.mongoose.started) {
649
+ this.constructErrors.push(error);
650
+
651
+ if (this.debugLog) DynamoFM_Log.error(
652
+ '\nUnable to connect to MongoDB server, ERROR: ',
653
+ error
654
+ );
655
+
656
+ const d_error: DynamoFM_Error = new DynamoFM_Error({
657
+ ...this._getDefaultErrorSettings(
658
+ 'startDB',
659
+ error
660
+ ),
661
+
662
+ errorCode: 'NTS-AS0-SDB1',
663
+ message: `Unable to start connection to MongoDB server, ERROR: ${error}`,
664
+ });
665
+
666
+ DynamoNTS_GlobalService.globalErrorHandler?.(d_error);
667
+ reject(d_error);
668
+
669
+ } else {
670
+ if (this.debugLog) DynamoFM_Log.error('\nMongoDB ERROR: ', error);
671
+
672
+ const d_error: DynamoFM_Error = new DynamoFM_Error({
673
+ ...this._getDefaultErrorSettings(
674
+ 'mongoose.connection.on(error)',
675
+ error
676
+ ),
677
+
678
+ errorCode: 'NTS-AS0-SDB2',
679
+ message: `MongoDB ERROR: ${error}`,
680
+ level: DynamoFM_ErrorLevel.critical,
681
+ });
682
+
683
+ DynamoNTS_GlobalService.globalErrorHandler?.(d_error);
684
+ }
685
+ });
686
+
687
+ this.mongoose.connect(
688
+ this._params.dbUri,
689
+ {
690
+ useNewUrlParser: true,
691
+ useUnifiedTopology: true,
692
+ }
693
+ );
694
+ }
695
+ );
696
+ }
697
+
698
+ /**
699
+ *
700
+ */
701
+ private async initExpresses(): Promise<void> {
702
+ if (this.logFn && this.deepLog) DynamoFM_Log.log('\nfn:. initExpresses');
703
+
704
+ if (this._security && this._security !== DynamoNTS_RouteSecurity.secure) {
705
+ if (!this._portSettings.httpPort) {
706
+ let errorMsg: string =
707
+ `\nYou have open routes, but httpPort is not set!` +
708
+ `\nsecurity: ${this._security}` +
709
+ `\nset httpPort in DynamoBEServer - setupRoutingModules() to enable secure routes.`;
710
+
711
+ errorMsg += '\n\nThe routes setted to use open server:';
712
+ this._routingModules.forEach((module: DynamoNTS_RoutingModule): void => {
713
+ if (module.security != DynamoNTS_RouteSecurity.secure) {
714
+ errorMsg += `\n ${module.route} (security: ${module.security})`;
715
+ errorMsg += `\n subroutes using open sever:`;
716
+ module.endpoints.forEach((endpoint: DynamoNTS_Endpoint_Params): void => {
717
+ if (endpoint.security != DynamoNTS_RouteSecurity.secure) {
718
+ errorMsg += `\n ${endpoint.endpoint} (security: ${endpoint.security})`;
719
+ }
720
+ });
721
+ }
722
+ });
723
+
724
+ const error = new Error('Open routes cannot be established!');
725
+ const errorStack: string[] = error.stack.split('\n');
726
+
727
+ errorStack.splice(1, 2);
728
+ error.stack = errorStack.join('\n');
729
+
730
+ DynamoFM_Log.error(errorMsg);
731
+
732
+ throw error;
733
+ }
734
+
735
+ await this.initOpenExpress();
736
+ }
737
+
738
+ if (this._security && this._security !== DynamoNTS_RouteSecurity.open) {
739
+ if (!this._cert || !this._portSettings.httpsPort) {
740
+ let errorMsg: string =
741
+ `\nYou have secure routes, but the certification paths or httpsPort are not set!` +
742
+ `\nsecurity: ${this._security}` +
743
+ `\nset...` +
744
+ `\n(missing exact howto...)` +
745
+ /* `\n httpsPort and` +
746
+ `\n cert: {` +
747
+ `\n keyPath: FileSystem.PathLike,` +
748
+ `\n certPath: FileSystem.PathLike,` +
749
+ `\n }` + */
750
+ `\nin DynamoBEServer - getRoutingModules() to enable secure routes.`;
751
+
752
+ errorMsg += '\n\nThe routes setted to use secure server:';
753
+ this._routingModules.forEach((module: DynamoNTS_RoutingModule): void => {
754
+ if (module.security && module.security !== DynamoNTS_RouteSecurity.open) {
755
+ errorMsg += `\n ${module.route} (security: ${module.security})`;
756
+ errorMsg += `\n subroutes using secure sever:`;
757
+ module.endpoints.forEach((endpoint: DynamoNTS_Endpoint_Params): void => {
758
+ if (endpoint.security && endpoint.security !== DynamoNTS_RouteSecurity.open) {
759
+ errorMsg += `\n ${endpoint.endpoint} (security: ${endpoint.security})`;
760
+ }
761
+ });
762
+ }
763
+ });
764
+
765
+ const error = new Error('Secure routes cannot be established!');
766
+ const errorStack: string[] = error.stack.split('\n');
767
+
768
+ errorStack.splice(1, 2);
769
+ error.stack = errorStack.join('\n');
770
+
771
+ DynamoFM_Log.error(errorMsg);
772
+
773
+ throw error;
774
+ }
775
+
776
+ await this.initSecureExpress();
777
+ }
778
+ }
779
+
780
+ /**
781
+ *
782
+ */
783
+ protected async initOpenExpress(): Promise<void> {
784
+ if (this.logFn) DynamoFM_Log.log('\nfn:. initOpenExpress');
785
+ this.openExpress = Express();
786
+ this.openExpress.use(BodyParser.urlencoded(this._portSettings.httpUrlencoded));
787
+ this.openExpress.use(BodyParser.json(this._portSettings.httpJson));
788
+ }
789
+
790
+ /**
791
+ *
792
+ */
793
+ protected async initSecureExpress(): Promise<void> {
794
+ if (this.logFn) DynamoFM_Log.log('\nfn:. initSecureExpress');
795
+ this.secureExpress = Express();
796
+ this.secureExpress.use(BodyParser.urlencoded(this._portSettings.httpsUrlencoded));
797
+ this.secureExpress.use(BodyParser.json(this._portSettings.httpsJson));
798
+
799
+ const options = {
800
+ key: FileSystem.readFileSync(this._cert.keyPath),
801
+ cert: FileSystem.readFileSync(this._cert.certPath),
802
+ };
803
+
804
+ this.httpsServer = Https.createServer(options, this.secureExpress);
805
+ }
806
+
807
+ /**
808
+ *
809
+ */
810
+ private async startExpresses(): Promise<void> {
811
+ if (this.logFn && this.deepLog) DynamoFM_Log.log('\nfn:. startExpresses');
812
+ try {
813
+ if (this._security && this._security !== DynamoNTS_RouteSecurity.open) {
814
+ await new Promise<void>((resolve, reject): void => {
815
+ this.systemControls.httpsServer.init = true;
816
+ this.httpsServer
817
+ .listen(this._portSettings.httpsPort, 'localhost', 0, (): void => {
818
+ this.systemControls.httpsServer.started = true;
819
+ DynamoFM_Log.success(
820
+ `\nHTTPS (secure) server is listening on port: ${this._portSettings.httpsPort}`
821
+ );
822
+
823
+ resolve();
824
+ })
825
+ .on('error', (error): void => {
826
+ if (this.debugLog) DynamoFM_Log.error(`\nHTTPS (secure) server ERROR`, error);
827
+
828
+ if (!this.systemControls.httpsServer.started) {
829
+ const d_error: DynamoFM_Error = new DynamoFM_Error({
830
+ ...this._getDefaultErrorSettings(
831
+ 'startExpresses',
832
+ error
833
+ ),
834
+
835
+ errorCode: 'NTS-AS0-SE1',
836
+ message: `HTTPS (secure) start server ERROR`,
837
+ });
838
+
839
+ this.constructErrors.push(d_error);
840
+ DynamoNTS_GlobalService.globalErrorHandler?.(d_error);
841
+
842
+ reject(d_error);
843
+
844
+ } else {
845
+ const d_error: DynamoFM_Error = new DynamoFM_Error({
846
+ ...this._getDefaultErrorSettings(
847
+ 'httpsServer.on(error)',
848
+ error
849
+ ),
850
+
851
+ errorCode: 'NTS-AS0-SE2',
852
+ message: `HTTPS (secure) server ERROR`,
853
+ level: DynamoFM_ErrorLevel.serious,
854
+ });
855
+
856
+ DynamoNTS_GlobalService.globalErrorHandler?.(d_error);
857
+ }
858
+ })
859
+ .on('uncaughtException', (exception): void => {
860
+ const d_error: DynamoFM_Error = new DynamoFM_Error({
861
+ ...this._getDefaultErrorSettings(
862
+ 'httpsServer.on(uncaughtException)',
863
+ exception
864
+ ),
865
+
866
+ errorCode: 'NTS-AS0-SE3',
867
+ message: `HTTPS (secure) server uncaughtException`,
868
+ level: DynamoFM_ErrorLevel.critical,
869
+ });
870
+
871
+ if (this.debugLog) DynamoFM_Log.warn(
872
+ `\nHTTPS (secure) server uncaughtException`,
873
+ d_error
874
+ );
875
+
876
+ DynamoNTS_GlobalService.globalErrorHandler?.(d_error);
877
+ });
878
+ });
879
+ }
880
+
881
+ if (this._security && this._security !== DynamoNTS_RouteSecurity.secure) {
882
+ this.systemControls.httpServer.init = true;
883
+ await new Promise<void>((resolve, reject): void => {
884
+ this.httpServer = this.openExpress
885
+ .listen(this._portSettings.httpPort, (): void => {
886
+ this.systemControls.httpServer.started = true;
887
+ DynamoFM_Log.success(
888
+ `\nHTTP (open) server is listening on port: ${this._portSettings.httpPort}`
889
+ );
890
+
891
+ resolve();
892
+ })
893
+ .on('error', (error): void => {
894
+ if (this.debugLog) DynamoFM_Log.error(`\nHTTP (open) server ERROR`, error);
895
+
896
+ if (!this.systemControls.httpServer.started) {
897
+ const d_error: DynamoFM_Error = new DynamoFM_Error({
898
+ ...this._getDefaultErrorSettings(
899
+ 'startExpresses',
900
+ error
901
+ ),
902
+
903
+ errorCode: 'NTS-AS0-SE3',
904
+ message: `HTTP (open) start server ERROR`,
905
+ });
906
+
907
+ this.constructErrors.push(d_error);
908
+ DynamoNTS_GlobalService.globalErrorHandler?.(d_error);
909
+
910
+ reject(d_error);
911
+
912
+ } else {
913
+ const d_error: DynamoFM_Error = new DynamoFM_Error({
914
+ ...this._getDefaultErrorSettings(
915
+ 'httpServer.on(error)',
916
+ error
917
+ ),
918
+
919
+ errorCode: 'NTS-AS0-SE4',
920
+ message: `HTTP (open) server ERROR`,
921
+ level: DynamoFM_ErrorLevel.serious,
922
+ });
923
+
924
+ DynamoNTS_GlobalService.globalErrorHandler?.(d_error);
925
+ }
926
+ })
927
+ .on('uncaughtException', (exception): void => {
928
+ const d_error: DynamoFM_Error = new DynamoFM_Error({
929
+ ...this._getDefaultErrorSettings(
930
+ 'httpServer.on(uncaughtException)',
931
+ exception
932
+ ),
933
+
934
+ errorCode: 'NTS-AS0-SE5',
935
+ message: `HTTP (open) server uncaughtException`,
936
+ level: DynamoFM_ErrorLevel.critical,
937
+ });
938
+
939
+ if (this.debugLog) {
940
+ DynamoFM_Log.warn(`\nHTTP (open) server uncaughtException`, d_error);
941
+ }
942
+
943
+ DynamoNTS_GlobalService.globalErrorHandler?.(d_error);
944
+ });
945
+ });
946
+ }
947
+ } catch (error) {
948
+ DynamoFM_Log.error(`startExpresses failed...`, error);
949
+
950
+ throw error;
951
+ }
952
+ }
953
+
954
+ /**
955
+ *
956
+ */
957
+ private async expressErrorHandling(error, req, res, next): Promise<void> {
958
+ try {
959
+ if (error) {
960
+ const d_error: DynamoFM_Error = new DynamoFM_Error({
961
+ ...this._getDefaultErrorSettings(
962
+ 'expressErrorHandling',
963
+ error
964
+ ),
965
+
966
+ errorCode: 'NTS-AS0-EEH1',
967
+ message: `Express ERROR`,
968
+ additionalContent: {
969
+ req,
970
+ res,
971
+ },
972
+ level: DynamoFM_ErrorLevel.error,
973
+ });
974
+
975
+ await DynamoNTS_GlobalService.globalErrorHandler?.(d_error, req, res);
976
+
977
+ } else {
978
+ DynamoFM_Log.H_error(
979
+ 'WTF??? express error; without error?...' +
980
+ '\nerr:', error,
981
+ '\nreq:', req,
982
+ '\nres:', res
983
+ );
984
+ }
985
+ } catch (error) {
986
+ DynamoFM_Log.H_error(
987
+ 'MULTILEVEL ERROR (expressErrorHandling)....' +
988
+ '\n', error
989
+ );
990
+ }
991
+ }
992
+
993
+ /**
994
+ *
995
+ */
996
+ private async mountSecureRoutes (): Promise<void> {
997
+ if (this.logFn && this.deepLog) DynamoFM_Log.log('\nfn:. mountSecureRoutes');
998
+
999
+ this.openExpress.use(
1000
+ (error, req, res, next): Promise<void> => this.expressErrorHandling(error, req, res, next)
1001
+ );
1002
+
1003
+ await DynamoFM_Array.asyncForEach(
1004
+ this._routingModules,
1005
+ async (module: DynamoNTS_RoutingModule): Promise<void> => {
1006
+ if (module.security !== DynamoNTS_RouteSecurity.open) {
1007
+ if (this.logSetup) {
1008
+ DynamoFM_Log.log(`route mount (secure): ${module.route}`);
1009
+ }
1010
+
1011
+ const existingRoutes: DynamoNTS_RoutingModule[] = this._routingModules.filter(
1012
+ (mod: DynamoNTS_RoutingModule): boolean => mod.route === module.route
1013
+ );
1014
+
1015
+ if (1 < existingRoutes.length) {
1016
+ const error: Error = new Error(`ROUTE DUPLICATION: ${module.route}`);
1017
+ const errorStack: string[] = error.stack.split('\n');
1018
+
1019
+ errorStack.splice(1, 4);
1020
+ error.stack = errorStack.join('\n');
1021
+
1022
+ DynamoFM_Log.error(`ROUTE DUPLICATION: ${module.route}`, error);
1023
+
1024
+ throw new DynamoFM_Error({
1025
+ ...this._getDefaultErrorSettings(
1026
+ 'mountSecureRoutes',
1027
+ error
1028
+ ),
1029
+
1030
+ errorCode: 'NTS-AS0-MSR1',
1031
+ message: `ROUTE DUPLICATION: ${module.route}`,
1032
+ });
1033
+ }
1034
+
1035
+ this.secureExpress.use(module.route, module.secureRouter);
1036
+ }
1037
+ }
1038
+ );
1039
+ }
1040
+
1041
+ /**
1042
+ *
1043
+ */
1044
+ private async mountOpenRoutes(): Promise<void> {
1045
+ if (this.logFn && this.deepLog) DynamoFM_Log.log('\nfn:. mountOpenRoutes');
1046
+
1047
+ this.openExpress.use(
1048
+ (error, req, res, next): Promise<void> => this.expressErrorHandling(error, req, res, next)
1049
+ );
1050
+
1051
+ await DynamoFM_Array.asyncForEach(
1052
+ this._routingModules,
1053
+ async (module: DynamoNTS_RoutingModule): Promise<void> => {
1054
+ if (module.security !== DynamoNTS_RouteSecurity.secure) {
1055
+ if (this.logSetup) {
1056
+ DynamoFM_Log.log(`route mount (open): ${module.route}`);
1057
+ }
1058
+
1059
+ const existingRoutes: DynamoNTS_RoutingModule[] = this._routingModules.filter(
1060
+ (mod: DynamoNTS_RoutingModule): boolean => mod.route === module.route
1061
+ );
1062
+
1063
+ if (1 < existingRoutes.length) {
1064
+ const error: Error = new Error(`ROUTE DUPLICATION: ${module.route}`);
1065
+ const errorStack: string[] = error.stack.split('\n');
1066
+
1067
+ errorStack.splice(1, 4);
1068
+ error.stack = errorStack.join('\n');
1069
+
1070
+ DynamoFM_Log.error(`ROUTE DUPLICATION: ${module.route}`, error);
1071
+
1072
+ throw new DynamoFM_Error({
1073
+ ...this._getDefaultErrorSettings(
1074
+ 'mountOpenRoutes',
1075
+ error
1076
+ ),
1077
+
1078
+ errorCode: 'NTS-AS0-MOR1',
1079
+ message: `ROUTE DUPLICATION: ${module.route}`,
1080
+ });
1081
+ }
1082
+
1083
+ this.openExpress.use(module.route, module.openRouter);
1084
+ }
1085
+ }
1086
+ );
1087
+ }
1088
+
1089
+ /**
1090
+ *
1091
+ */
1092
+ private setSecurity(): void {
1093
+ if (this.logFn && this.deepLog) DynamoFM_Log.log('\nfn:. setSecurity');
1094
+ this._routingModules.forEach((module: DynamoNTS_RoutingModule): void => {
1095
+ if (!module.security) {
1096
+ DynamoFM_Log.warn(`RoutingModule security is not set for ${module.route}\n`);
1097
+
1098
+ } else if (!this._security) {
1099
+ this._security = module.security;
1100
+
1101
+ } else if (this._security !== module.security) {
1102
+ this._security = DynamoNTS_RouteSecurity.both;
1103
+ }
1104
+ });
1105
+
1106
+ if (!this._security) {
1107
+ let msg = `Could not set security for the server! (${this.security})`;
1108
+
1109
+ msg += '\n RoutingModules:';
1110
+ this._routingModules.forEach((module: DynamoNTS_RoutingModule): void => {
1111
+ msg += `\n ${module.route} (security: ${module.security})`;
1112
+ });
1113
+
1114
+ if (this._routingModules.length === 0) {
1115
+ msg += '\n - no RoutingModule found -\n';
1116
+ }
1117
+ DynamoFM_Log.warn(msg);
1118
+ }
1119
+ }
1120
+
1121
+ private _getDefaultErrorSettings(
1122
+ fnName: string,
1123
+ error: DynamoFM_AnyError
1124
+ ): DynamoFM_Error_Settings {
1125
+ return {
1126
+ status: (error as DynamoFM_Error)?.___status ?? 500,
1127
+ message: (error as Error)?.message ?? `${fnName} was UNSUCCESSFUL (NTS)`,
1128
+ addECToUserMsg: !(error as DynamoFM_Error)?.__userMessage,
1129
+ userMessage: (error as DynamoFM_Error)?.__userMessage ?? this.defaultErrorUserMsg,
1130
+ issuerService: `${this?.constructor?.name}-DynamoNTS_App`,
1131
+ error: error,
1132
+ level: DynamoFM_ErrorLevel.fatal,
1133
+ };
1134
+ }
1135
+
1136
+ /**
1137
+ * MISSING Description (TODO)
1138
+ */
1139
+ abstract getAppParams(): DynamoNTS_App_Params;
1140
+
1141
+ /**
1142
+ * MISSING Description (TODO)
1143
+ */
1144
+ abstract getGlobalServiceCollection(): DynamoNTS_GlobalService_Settings;
1145
+
1146
+ /**
1147
+ * MISSING Description (TODO)
1148
+ */
1149
+ abstract getPortSettings(): DynamoNTS_Http_Settings;
1150
+
1151
+ /**
1152
+ * MISSING Description (TODO)
1153
+ */
1154
+ overrideDynamoNTSGlobalSettings?(): void;
1155
+
1156
+ /**
1157
+ * MISSING Description (TODO)
1158
+ */
1159
+ getRoutingModules?(): DynamoNTS_RoutingModule[];
1160
+
1161
+ /**
1162
+ * MISSING Description (TODO)
1163
+ */
1164
+ getRootServices?(): Promise<DynamoNTS_SingletonService[]>;
1165
+
1166
+ /**
1167
+ * MISSING Description (TODO)
1168
+ */
1169
+ getCertificationSettings?(): DynamoNTS_Certification_Settings;
1170
+
1171
+ /**
1172
+ * MISSING Description (TODO)
1173
+ */
1174
+ createEntries?(): Promise<void>;
1175
+
1176
+ /**
1177
+ * MISSING Description (TODO)
1178
+ */
1179
+ postProcess?(): Promise<void>;
1180
+
1181
+ }