@futdevpro/nts-dynamo 1.15.7 → 1.15.9
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/__documentations/nts-integration-tests-2026-03-17.md +26 -0
- package/build/_collections/default-fallback-cache-max-age.const.d.ts +3 -0
- package/build/_collections/default-fallback-cache-max-age.const.d.ts.map +1 -0
- package/build/_collections/default-fallback-cache-max-age.const.js +6 -0
- package/build/_collections/default-fallback-cache-max-age.const.js.map +1 -0
- package/build/_collections/default-not-found-page.const.d.ts +6 -0
- package/build/_collections/default-not-found-page.const.d.ts.map +1 -0
- package/build/_collections/default-not-found-page.const.js +25 -0
- package/build/_collections/default-not-found-page.const.js.map +1 -0
- package/build/_collections/default-socket-path.const.d.ts +3 -0
- package/build/_collections/default-socket-path.const.d.ts.map +1 -0
- package/build/_collections/default-socket-path.const.js +6 -0
- package/build/_collections/default-socket-path.const.js.map +1 -0
- package/build/_models/control-models/http-settings.control-model.d.ts +7 -0
- package/build/_models/control-models/http-settings.control-model.d.ts.map +1 -1
- package/build/_models/control-models/http-settings.control-model.js +7 -0
- package/build/_models/control-models/http-settings.control-model.js.map +1 -1
- package/build/_models/interfaces/static-client-settings.interface.d.ts +29 -0
- package/build/_models/interfaces/static-client-settings.interface.d.ts.map +1 -0
- package/build/_models/interfaces/static-client-settings.interface.js +3 -0
- package/build/_models/interfaces/static-client-settings.interface.js.map +1 -0
- package/build/_modules/mock/app-extended-server.mock.js +2 -2
- package/build/_modules/mock/app-extended-server.mock.js.map +1 -1
- package/build/_modules/mock/app-integration-test.mock.d.ts +20 -0
- package/build/_modules/mock/app-integration-test.mock.d.ts.map +1 -0
- package/build/_modules/mock/app-integration-test.mock.js +46 -0
- package/build/_modules/mock/app-integration-test.mock.js.map +1 -0
- package/build/_modules/mock/app-server.mock.js +2 -2
- package/build/_modules/mock/app-server.mock.js.map +1 -1
- package/build/_modules/mock/socket-client.mock.js +1 -1
- package/build/_modules/mock/socket-client.mock.js.map +1 -1
- package/build/_modules/mock/socket-server.mock.d.ts +1 -1
- package/build/_modules/mock/socket-server.mock.d.ts.map +1 -1
- package/build/_modules/mock/socket-server.mock.js +2 -8
- package/build/_modules/mock/socket-server.mock.js.map +1 -1
- package/build/_modules/socket/_models/socket-server-service-params.control-model.d.ts +4 -2
- package/build/_modules/socket/_models/socket-server-service-params.control-model.d.ts.map +1 -1
- package/build/_modules/socket/_models/socket-server-service-params.control-model.js +3 -1
- package/build/_modules/socket/_models/socket-server-service-params.control-model.js.map +1 -1
- package/build/_modules/socket/_services/socket-server.service.d.ts +9 -2
- package/build/_modules/socket/_services/socket-server.service.d.ts.map +1 -1
- package/build/_modules/socket/_services/socket-server.service.js +27 -11
- package/build/_modules/socket/_services/socket-server.service.js.map +1 -1
- package/build/_modules/socket/app-extended.server.d.ts +9 -2
- package/build/_modules/socket/app-extended.server.d.ts.map +1 -1
- package/build/_modules/socket/app-extended.server.js +42 -25
- package/build/_modules/socket/app-extended.server.js.map +1 -1
- package/build/_services/base/data.service.d.ts.map +1 -1
- package/build/_services/base/data.service.js +4 -5
- package/build/_services/base/data.service.js.map +1 -1
- package/build/_services/base/db.service.d.ts.map +1 -1
- package/build/_services/base/db.service.js +8 -0
- package/build/_services/base/db.service.js.map +1 -1
- package/build/_services/server/app.server.d.ts +18 -0
- package/build/_services/server/app.server.d.ts.map +1 -1
- package/build/_services/server/app.server.js +74 -2
- package/build/_services/server/app.server.js.map +1 -1
- package/build/index.d.ts +4 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +4 -0
- package/build/index.js.map +1 -1
- package/nodemon.json +2 -1
- package/package.json +4 -4
- package/src/_collections/default-fallback-cache-max-age.const.spec.ts +11 -0
- package/src/_collections/default-fallback-cache-max-age.const.ts +2 -0
- package/src/_collections/default-not-found-page.const.spec.ts +19 -0
- package/src/_collections/default-not-found-page.const.ts +22 -0
- package/src/_collections/default-socket-path.const.spec.ts +12 -0
- package/src/_collections/default-socket-path.const.ts +2 -0
- package/src/_models/control-models/http-settings.control-model.spec.ts +11 -0
- package/src/_models/control-models/http-settings.control-model.ts +8 -0
- package/src/_models/interfaces/static-client-settings.interface.spec.ts +29 -0
- package/src/_models/interfaces/static-client-settings.interface.ts +28 -0
- package/src/_modules/mock/app-extended-server.mock.ts +2 -2
- package/src/_modules/mock/app-integration-test.mock.ts +51 -0
- package/src/_modules/mock/app-server.mock.ts +2 -2
- package/src/_modules/mock/socket-client.mock.spec.ts +1 -1
- package/src/_modules/mock/socket-client.mock.ts +1 -1
- package/src/_modules/mock/socket-server.mock.spec.ts +1 -1
- package/src/_modules/mock/socket-server.mock.ts +5 -13
- package/src/_modules/socket/_models/socket-server-service-params.control-model.spec.ts +13 -0
- package/src/_modules/socket/_models/socket-server-service-params.control-model.ts +4 -2
- package/src/_modules/socket/_services/socket-server.service.ts +37 -6
- package/src/_modules/socket/app-extended.integration.spec.ts +85 -0
- package/src/_modules/socket/app-extended.server.ts +47 -40
- package/src/_services/base/data.service.ts +4 -7
- package/src/_services/base/db.service.ts +11 -3
- package/src/_services/route/routing-module.service.spec.ts +15 -0
- package/src/_services/server/app.server.ts +107 -2
- package/src/index.ts +4 -0
|
@@ -85,7 +85,7 @@ export class DyNTS_AppFull_Mock extends DyNTS_App {
|
|
|
85
85
|
|
|
86
86
|
getPortSettings(): DyNTS_Http_Settings {
|
|
87
87
|
return {
|
|
88
|
-
httpPort:
|
|
88
|
+
httpPort: 0,
|
|
89
89
|
};
|
|
90
90
|
}
|
|
91
91
|
|
|
@@ -172,7 +172,7 @@ export class DyNTS_AppTEST_Mock extends DyNTS_App {
|
|
|
172
172
|
|
|
173
173
|
getPortSettings(): DyNTS_Http_Settings {
|
|
174
174
|
return {
|
|
175
|
-
httpPort:
|
|
175
|
+
httpPort: 0,
|
|
176
176
|
};
|
|
177
177
|
}
|
|
178
178
|
|
|
@@ -34,7 +34,7 @@ describe('| SocketClient_Mock', () => {
|
|
|
34
34
|
expect(params).toEqual(jasmine.any(DyNTS_SocketClientService_Params));
|
|
35
35
|
expect(params.service).toBe('-test-socket-target-');
|
|
36
36
|
expect(params.name).toBe('socket-client-mock');
|
|
37
|
-
expect(params.port).toBe(
|
|
37
|
+
expect(params.port).toBe(0);
|
|
38
38
|
expect(params.socketOptions.reconnection).toBeTrue();
|
|
39
39
|
});
|
|
40
40
|
});
|
|
@@ -34,7 +34,7 @@ export class SocketClient_Mock extends DyNTS_SocketClient_ServiceBase {
|
|
|
34
34
|
return new DyNTS_SocketClientService_Params({
|
|
35
35
|
service: '-test-socket-target-',
|
|
36
36
|
name: 'socket-client-mock',
|
|
37
|
-
port:
|
|
37
|
+
port: 0,
|
|
38
38
|
socketOptions: {
|
|
39
39
|
reconnection: true,
|
|
40
40
|
},
|
|
@@ -20,7 +20,7 @@ describe('| DyNTS_SocketServer_Mock', () => {
|
|
|
20
20
|
|
|
21
21
|
expect(params).toBeInstanceOf(DyNTS_SocketServerService_Params);
|
|
22
22
|
expect(params.name).toBe('test');
|
|
23
|
-
expect(params.port).toBe(
|
|
23
|
+
expect(params.port).toBe(0);
|
|
24
24
|
});
|
|
25
25
|
|
|
26
26
|
it('| should return an empty array for incoming events', () => {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { DyFM_SocketEvent } from '@futdevpro/fsm-dynamo/socket';
|
|
2
2
|
import { Socket } from 'socket.io';
|
|
3
|
-
import * as net from 'net';
|
|
4
3
|
|
|
5
4
|
import {
|
|
6
5
|
DyNTS_SocketPresence
|
|
@@ -10,28 +9,21 @@ import {
|
|
|
10
9
|
} from '../socket/_models/socket-server-service-params.control-model';
|
|
11
10
|
import { DyNTS_SocketServerService } from '../socket/_services/socket-server.service';
|
|
12
11
|
|
|
13
|
-
/**
|
|
14
|
-
* Utility function to find an available port starting from a base port
|
|
15
|
-
*/
|
|
16
|
-
const findAvailablePort = (basePort: number): number => {
|
|
17
|
-
return basePort; // For now, return the base port, but this could be enhanced
|
|
18
|
-
};
|
|
19
|
-
|
|
20
12
|
/**
|
|
21
13
|
* Mock Socket Server Service for testing purposes
|
|
22
|
-
* Uses
|
|
14
|
+
* Uses port 0 so the OS assigns a random available port
|
|
23
15
|
*/
|
|
24
|
-
export class DyNTS_SocketServer_Mock extends
|
|
16
|
+
export class DyNTS_SocketServer_Mock extends
|
|
25
17
|
DyNTS_SocketServerService<DyNTS_SocketPresence> {
|
|
26
|
-
|
|
18
|
+
|
|
27
19
|
static getInstance(): DyNTS_SocketServer_Mock {
|
|
28
20
|
return DyNTS_SocketServer_Mock.getSingletonInstance();
|
|
29
21
|
}
|
|
30
|
-
|
|
22
|
+
|
|
31
23
|
getServiceParams(): DyNTS_SocketServerService_Params<any> {
|
|
32
24
|
return new DyNTS_SocketServerService_Params({
|
|
33
25
|
name: 'test',
|
|
34
|
-
port:
|
|
26
|
+
port: 0,
|
|
35
27
|
});
|
|
36
28
|
}
|
|
37
29
|
|
|
@@ -30,4 +30,17 @@ describe('| DyNTS_SocketServerService_Params', () => {
|
|
|
30
30
|
expect(instance.port).toBe(8080);
|
|
31
31
|
expect(instance.security).toBe(DyNTS_global_settings.defaultSocketSecurity);
|
|
32
32
|
});
|
|
33
|
+
|
|
34
|
+
it('| should allow port to be omitted (optional, default used by app-extended)', () => {
|
|
35
|
+
const params = {
|
|
36
|
+
name: 'TestSocketNoPort',
|
|
37
|
+
security: DyNTS_SocketSecurity.open,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const instance = new DyNTS_SocketServerService_Params(params);
|
|
41
|
+
|
|
42
|
+
expect(instance.name).toBe('TestSocketNoPort');
|
|
43
|
+
expect(instance.port).toBeUndefined();
|
|
44
|
+
expect(instance.security).toBe(DyNTS_SocketSecurity.open);
|
|
45
|
+
});
|
|
33
46
|
});
|
|
@@ -3,11 +3,13 @@ import { DyNTS_global_settings } from '../../../_collections/global-settings.con
|
|
|
3
3
|
import { DyNTS_SocketSecurity } from '../_enums/socket-security.enum';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* Socket service paraméterek.
|
|
7
|
+
* A port opcionális: ha nincs megadva, az app-extended a getPortSettings() httpPort/httpsPort értékét használja (ugyanaz a port, mint a HTTP/HTTPS).
|
|
7
8
|
*/
|
|
8
9
|
export class DyNTS_SocketServerService_Params<T = any> {
|
|
9
10
|
name: string;
|
|
10
|
-
|
|
11
|
+
/** Opcionális: ha nincs megadva, az extended app a HTTP/HTTPS portot használja (same port). */
|
|
12
|
+
port?: number;
|
|
11
13
|
security?: DyNTS_SocketSecurity;
|
|
12
14
|
|
|
13
15
|
constructor(
|
|
@@ -21,6 +21,14 @@ import {
|
|
|
21
21
|
DyNTS_SocketServerService_Params
|
|
22
22
|
} from '../_models/socket-server-service-params.control-model';
|
|
23
23
|
|
|
24
|
+
/** Opciók a setupSocketServer híváshoz: attacholt HTTP szerver esetén ne hívjuk a listen()-t. */
|
|
25
|
+
export interface DyNTS_SocketServerSetupOptions {
|
|
26
|
+
/** Ha true, a Socket.IO egy már listenelő HTTP/HTTPS szerverre van attacholva – ne hívjuk a listen()-t. */
|
|
27
|
+
attachedToExistingServer?: boolean;
|
|
28
|
+
/** A tényleges port (pl. defaultolt httpPort/httpsPort) – logokban használjuk. */
|
|
29
|
+
effectivePort?: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
24
32
|
/**
|
|
25
33
|
* You need to define the following functions:
|
|
26
34
|
* ```ts
|
|
@@ -42,7 +50,7 @@ export abstract class DyNTS_SocketServerService<
|
|
|
42
50
|
|
|
43
51
|
protected params: DyNTS_SocketServerService_Params;
|
|
44
52
|
get name(): string { return this.params.name; }
|
|
45
|
-
get port(): number { return this.params.port; }
|
|
53
|
+
get port(): number | undefined { return this.params.port; }
|
|
46
54
|
get security(): DyNTS_SocketSecurity { return this.params.security; }
|
|
47
55
|
get activeSubscriptionsCount(): number { return this.presences.length; }
|
|
48
56
|
|
|
@@ -270,11 +278,14 @@ export abstract class DyNTS_SocketServerService<
|
|
|
270
278
|
async setupSocketServer(
|
|
271
279
|
newSocketServer: SocketIO.Server,
|
|
272
280
|
security: DyNTS_SocketSecurity.open | DyNTS_SocketSecurity.secure,
|
|
273
|
-
successCallback: () => void
|
|
281
|
+
successCallback: () => void,
|
|
282
|
+
options?: DyNTS_SocketServerSetupOptions
|
|
274
283
|
): Promise<SocketIO.Server> {
|
|
275
284
|
try {
|
|
276
285
|
if (this.highDetailedLogs) console.log('\nfn:. setupSocketServer');
|
|
277
286
|
|
|
287
|
+
const effectivePort: number | undefined = options?.effectivePort ?? this.params.port;
|
|
288
|
+
|
|
278
289
|
newSocketServer.on(DyFM_SocketEvent_Key.incomingNewConnection, async (socket: SocketIO.Socket) => {
|
|
279
290
|
try {
|
|
280
291
|
let issuer: string;
|
|
@@ -497,16 +508,35 @@ export abstract class DyNTS_SocketServerService<
|
|
|
497
508
|
await this.closeSocket(socket, `${this.params.name} on connection error`, error);
|
|
498
509
|
}
|
|
499
510
|
});
|
|
500
|
-
|
|
511
|
+
|
|
512
|
+
const isAttach: boolean =
|
|
513
|
+
options?.attachedToExistingServer === true ||
|
|
514
|
+
(this.params.port === undefined && options?.effectivePort !== undefined);
|
|
515
|
+
|
|
516
|
+
if (isAttach) {
|
|
517
|
+
DyFM_Log.success(
|
|
518
|
+
`\nsocket server setup finished: "${this.params.name}"` +
|
|
519
|
+
(effectivePort !== undefined ? ` (attached to server on port: ${effectivePort})` : ' (attached to existing server)')
|
|
520
|
+
);
|
|
521
|
+
successCallback();
|
|
522
|
+
} else {
|
|
501
523
|
try {
|
|
502
|
-
|
|
524
|
+
const portToListen: number | undefined = this.params.port ?? options?.effectivePort;
|
|
525
|
+
if (portToListen === undefined) {
|
|
526
|
+
throw new Error(
|
|
527
|
+
`PORT NOT SET: "${this.params.name}". ` +
|
|
528
|
+
`Either set port in getServiceParams() or pass effectivePort in setupSocketServer options.`
|
|
529
|
+
);
|
|
530
|
+
}
|
|
531
|
+
newSocketServer.listen(portToListen);
|
|
503
532
|
|
|
504
533
|
DyFM_Log.success(
|
|
505
534
|
`\nsocket server setup finished: "${this.params.name}"` +
|
|
506
|
-
`\nsocket server listening on port: "${
|
|
535
|
+
`\nsocket server listening on port: "${portToListen}"`
|
|
507
536
|
);
|
|
508
537
|
} catch (listenError) {
|
|
509
|
-
const
|
|
538
|
+
const portForMsg: number | undefined = this.params.port ?? options?.effectivePort;
|
|
539
|
+
const errorMessage = `Failed to bind socket server "${this.params.name}" to port ${portForMsg}. ` +
|
|
510
540
|
`This could be due to port already in use or insufficient permissions. ` +
|
|
511
541
|
`Please ensure the port is available and try again.`;
|
|
512
542
|
|
|
@@ -515,6 +545,7 @@ export abstract class DyNTS_SocketServerService<
|
|
|
515
545
|
}
|
|
516
546
|
|
|
517
547
|
successCallback();
|
|
548
|
+
}
|
|
518
549
|
|
|
519
550
|
if (security === DyNTS_SocketSecurity.open) {
|
|
520
551
|
this.openSocketServer = newSocketServer;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import * as Fs from 'fs';
|
|
2
|
+
import * as Os from 'os';
|
|
3
|
+
import * as Path from 'path';
|
|
4
|
+
|
|
5
|
+
import Axios from 'axios';
|
|
6
|
+
|
|
7
|
+
import { DyNTS_defaultNotFoundPageHtml } from '../../_collections/default-not-found-page.const';
|
|
8
|
+
import { DyNTS_AppIntegrationTest_Mock } from '../mock/app-integration-test.mock';
|
|
9
|
+
|
|
10
|
+
let INTEGRATION_BASE_URL: string = '';
|
|
11
|
+
const INTEGRATION_READY_TIMEOUT_MS: number = 10000;
|
|
12
|
+
|
|
13
|
+
describe('| DyNTS_AppExtended (integration)', (): void => {
|
|
14
|
+
beforeAll((): void => {
|
|
15
|
+
jasmine.DEFAULT_TIMEOUT_INTERVAL = INTEGRATION_READY_TIMEOUT_MS + 5000;
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
let app: DyNTS_AppIntegrationTest_Mock;
|
|
19
|
+
let tempDir: string = '';
|
|
20
|
+
|
|
21
|
+
beforeAll(async (): Promise<void> => {
|
|
22
|
+
tempDir = Fs.mkdtempSync(Path.join(Os.tmpdir(), 'dynts-int-'));
|
|
23
|
+
const indexContent: string = '<!DOCTYPE html><html><body>Integration test index</body></html>';
|
|
24
|
+
Fs.writeFileSync(Path.join(tempDir, 'index.html'), indexContent, { encoding: 'utf-8' });
|
|
25
|
+
|
|
26
|
+
DyNTS_AppIntegrationTest_Mock.integrationStaticRoot = tempDir;
|
|
27
|
+
app = new DyNTS_AppIntegrationTest_Mock();
|
|
28
|
+
await app.ready(INTEGRATION_READY_TIMEOUT_MS);
|
|
29
|
+
|
|
30
|
+
INTEGRATION_BASE_URL = `http://localhost:${app.resolvedPort}`;
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
afterAll(async (): Promise<void> => {
|
|
34
|
+
try {
|
|
35
|
+
if (app?.started) {
|
|
36
|
+
await app.stop();
|
|
37
|
+
}
|
|
38
|
+
} catch {
|
|
39
|
+
// stop() hiba (pl. socket server már leállt) ne szakítsa meg a suite-ot
|
|
40
|
+
}
|
|
41
|
+
if (tempDir && Fs.existsSync(tempDir)) {
|
|
42
|
+
Fs.rmSync(tempDir, { recursive: true });
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('| app elindul és started true', (): void => {
|
|
47
|
+
expect(app.started).toBe(true);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('| GET nem létező path -> 404 és default "Page not found" HTML', async (): Promise<void> => {
|
|
51
|
+
const response = await Axios.get(`${INTEGRATION_BASE_URL}/nonexistent-path-xyz`, {
|
|
52
|
+
validateStatus: (): boolean => true,
|
|
53
|
+
responseType: 'text',
|
|
54
|
+
});
|
|
55
|
+
expect(response.status).toBe(404);
|
|
56
|
+
expect(response.headers['content-type']).toContain('html');
|
|
57
|
+
expect(typeof response.data).toBe('string');
|
|
58
|
+
expect((response.data as string).trim()).toContain('Page not found');
|
|
59
|
+
expect(response.data).toBe(DyNTS_defaultNotFoundPageHtml);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('| GET /index.html -> 200 és static tartalom', async (): Promise<void> => {
|
|
63
|
+
const response = await Axios.get(`${INTEGRATION_BASE_URL}/index.html`, {
|
|
64
|
+
responseType: 'text',
|
|
65
|
+
});
|
|
66
|
+
expect(response.status).toBe(200);
|
|
67
|
+
expect(response.data).toContain('Integration test index');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('| GET API base path alatt (mock route) -> 200', async (): Promise<void> => {
|
|
71
|
+
const response = await Axios.get(`${INTEGRATION_BASE_URL}/api/test-0/test-base`, {
|
|
72
|
+
responseType: 'text',
|
|
73
|
+
});
|
|
74
|
+
expect(response.status).toBe(200);
|
|
75
|
+
expect(response.data).toBe('test-base');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('| GET API másik endpoint -> 200', async (): Promise<void> => {
|
|
79
|
+
const response = await Axios.get(`${INTEGRATION_BASE_URL}/api/test-0/test-simple`, {
|
|
80
|
+
responseType: 'text',
|
|
81
|
+
});
|
|
82
|
+
expect(response.status).toBe(200);
|
|
83
|
+
expect(response.data).toBe('test-simple');
|
|
84
|
+
});
|
|
85
|
+
});
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
DyFM_Log,
|
|
13
13
|
} from '@futdevpro/fsm-dynamo';
|
|
14
14
|
|
|
15
|
+
import { DyNTS_defaultSocketPath } from '../../_collections/default-socket-path.const';
|
|
15
16
|
import { DyNTS_global_settings } from '../../_collections/global-settings.const';
|
|
16
17
|
import { DyNTS_RouteSecurity } from '../../_enums/route-security.enum';
|
|
17
18
|
import {
|
|
@@ -112,7 +113,7 @@ import { DyNTS_SocketServerService } from './_services/socket-server.service';
|
|
|
112
113
|
*
|
|
113
114
|
* ...
|
|
114
115
|
*
|
|
115
|
-
* // Setting up Sockets
|
|
116
|
+
* // Setting up Sockets (port opcionális – ha nincs megadva, a HTTP/HTTPS portot használjuk, same port)
|
|
116
117
|
* this.socketServices = [
|
|
117
118
|
* NotificationService.getInstance(),
|
|
118
119
|
* ChatService.getInstance(),
|
|
@@ -130,9 +131,12 @@ export abstract class DyNTS_AppExtended extends DyNTS_App {
|
|
|
130
131
|
|
|
131
132
|
private socketSecurity: DyNTS_RouteSecurity;
|
|
132
133
|
|
|
133
|
-
|
|
134
|
+
/** Csak akkor van értékadva, ha nincs base httpServer (pl. nincs open route) és open socket van. */
|
|
135
|
+
private httpSocketServer: Http.Server | undefined;
|
|
134
136
|
|
|
135
137
|
/**
|
|
138
|
+
* Socket szolgáltatások. A port opcionális: ha nincs megadva, az extended app
|
|
139
|
+
* a getPortSettings() httpPort/httpsPort értékét használja (WebSocket és HTTP ugyanazon a porton).
|
|
136
140
|
* @example
|
|
137
141
|
* // Setting up Sockets
|
|
138
142
|
* this.socketServices = [
|
|
@@ -431,19 +435,25 @@ export abstract class DyNTS_AppExtended extends DyNTS_App {
|
|
|
431
435
|
}
|
|
432
436
|
|
|
433
437
|
/**
|
|
434
|
-
*
|
|
438
|
+
* Socket szerverek felállítása. By default a socket a HTTP/HTTPS porton fut (same port);
|
|
439
|
+
* ha a service.port nincs megadva, a getPortSettings() httpPort/httpsPort értékét használjuk.
|
|
440
|
+
* Ha a base app már listenel (httpServer/httpsServer), arra attacholjuk a Socket.IO-t,
|
|
441
|
+
* különben külön httpSocketServer-t hozunk létre és listenelünk.
|
|
442
|
+
* A Socket.IO path a portSettings.socketPath-ből jön (default: DyNTS_defaultSocketPath); a kliensnek ugyanazt kell használnia.
|
|
435
443
|
*/
|
|
436
444
|
private async setupSocketServerServices(): Promise<void> {
|
|
437
445
|
try {
|
|
438
446
|
if (this.fnLogs) console.log('\nfn:. setupSocketServerServices');
|
|
439
|
-
|
|
447
|
+
|
|
448
|
+
const useBaseHttpServer: boolean = !!this.httpServer;
|
|
449
|
+
const useBaseHttpsServer: boolean = !!this.httpsServer;
|
|
440
450
|
|
|
441
451
|
if (this.socketSecurity !== DyNTS_RouteSecurity.secure) {
|
|
442
452
|
if (!this.openExpress) {
|
|
443
453
|
await this.initOpenExpress();
|
|
444
454
|
}
|
|
445
455
|
|
|
446
|
-
if (!this.httpSocketServer) {
|
|
456
|
+
if (!useBaseHttpServer && !this.httpSocketServer) {
|
|
447
457
|
this.httpSocketServer = Http.createServer(this.openExpress);
|
|
448
458
|
}
|
|
449
459
|
}
|
|
@@ -464,8 +474,10 @@ export abstract class DyNTS_AppExtended extends DyNTS_App {
|
|
|
464
474
|
|
|
465
475
|
errorMsg += '\n\nThe socket services setted to use secure server:';
|
|
466
476
|
this.socketServices.forEach((service: DyNTS_SocketServerService<any>): void => {
|
|
467
|
-
if (service.security
|
|
468
|
-
|
|
477
|
+
if (service.security !== DyNTS_SocketSecurity.open) {
|
|
478
|
+
const effPort: number | undefined = service.port ??
|
|
479
|
+
this.portSettings.httpsPort;
|
|
480
|
+
errorMsg += `\n ${service?.name} (port: ${effPort})`;
|
|
469
481
|
}
|
|
470
482
|
});
|
|
471
483
|
|
|
@@ -486,49 +498,33 @@ export abstract class DyNTS_AppExtended extends DyNTS_App {
|
|
|
486
498
|
this.socketServices,
|
|
487
499
|
async (service: DyNTS_SocketServerService<any>): Promise<void> => {
|
|
488
500
|
try {
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
throw new Error(
|
|
493
|
-
`PORT NOT SET: "${service.name}"`
|
|
494
|
-
);
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
const existingPorts: DyNTS_SocketServerService<any>[] = this.socketServices.filter(
|
|
498
|
-
(mod: DyNTS_SocketServerService<any>): boolean => mod.port === service.port
|
|
499
|
-
);
|
|
501
|
+
const effectivePort: number | undefined = service.security === DyNTS_SocketSecurity.open
|
|
502
|
+
? (service.port ?? this.portSettings.httpPort)
|
|
503
|
+
: (service.port ?? this.portSettings.httpsPort);
|
|
500
504
|
|
|
501
|
-
if (
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
) {
|
|
506
|
-
const error = new Error(
|
|
507
|
-
`PORT DUPLICATION: "${service.port}"` +
|
|
508
|
-
`\n same ports at: ${existingPorts.map(
|
|
509
|
-
(sss: DyNTS_SocketServerService<any>): string => sss.name
|
|
510
|
-
).join(', ')}`
|
|
505
|
+
if (effectivePort === undefined) {
|
|
506
|
+
throw new Error(
|
|
507
|
+
`PORT NOT SET: "${service.name}". ` +
|
|
508
|
+
`Set port in getServiceParams() or ensure getPortSettings() returns httpPort/httpsPort.`
|
|
511
509
|
);
|
|
512
|
-
const errorStack: string[] = error.stack?.split('\n');
|
|
513
|
-
|
|
514
|
-
errorStack.splice(1, 4);
|
|
515
|
-
error.stack = errorStack.join('\n');
|
|
516
|
-
|
|
517
|
-
DyFM_Log.error(`\n${error.message}`);
|
|
518
|
-
|
|
519
|
-
throw error;
|
|
520
510
|
}
|
|
521
511
|
|
|
522
512
|
if (service.security === DyNTS_SocketSecurity.open) {
|
|
513
|
+
this.systemControlsExt.httpSocketServer.init = true;
|
|
514
|
+
const serverForOpen: Http.Server = useBaseHttpServer
|
|
515
|
+
? this.httpServer
|
|
516
|
+
: this.httpSocketServer!;
|
|
523
517
|
if (this.logSetup) console.log(
|
|
524
|
-
`\nsocket setup (open): ${service?.name}:${
|
|
518
|
+
`\nsocket setup (open): ${service?.name}:${effectivePort}` +
|
|
519
|
+
(useBaseHttpServer ? ' (shared with HTTP)' : '')
|
|
525
520
|
);
|
|
526
521
|
this.httpSocketSettingUpCount++;
|
|
527
522
|
this.systemControlsExt.httpSocketServer.started = false;
|
|
528
523
|
|
|
524
|
+
const socketPath: string = this.portSettings.socketPath ?? DyNTS_defaultSocketPath;
|
|
529
525
|
this.allSocketServers.push(
|
|
530
526
|
await service.setupSocketServer(
|
|
531
|
-
new SocketIO.Server(
|
|
527
|
+
new SocketIO.Server(serverForOpen, { path: socketPath }),
|
|
532
528
|
DyNTS_SocketSecurity.open,
|
|
533
529
|
(): void => {
|
|
534
530
|
this.httpSocketSettingUpCount--;
|
|
@@ -536,20 +532,27 @@ export abstract class DyNTS_AppExtended extends DyNTS_App {
|
|
|
536
532
|
if (this.httpSocketSettingUpCount === 0) {
|
|
537
533
|
this.systemControlsExt.httpSocketServer.started = true;
|
|
538
534
|
}
|
|
535
|
+
},
|
|
536
|
+
{
|
|
537
|
+
attachedToExistingServer: useBaseHttpServer,
|
|
538
|
+
effectivePort: effectivePort,
|
|
539
539
|
}
|
|
540
540
|
)
|
|
541
541
|
);
|
|
542
542
|
|
|
543
543
|
} else if (service.security === DyNTS_SocketSecurity.secure) {
|
|
544
|
+
this.systemControlsExt.httpsSocketServer.init = true;
|
|
544
545
|
if (this.logSetup) console.log(
|
|
545
|
-
`\nsocket setup (secure): ${service?.name}:${
|
|
546
|
+
`\nsocket setup (secure): ${service?.name}:${effectivePort}` +
|
|
547
|
+
(useBaseHttpsServer ? ' (shared with HTTPS)' : '')
|
|
546
548
|
);
|
|
547
549
|
this.httpsSocketSettingUpCount++;
|
|
548
550
|
this.systemControlsExt.httpsSocketServer.started = false;
|
|
549
551
|
|
|
552
|
+
const socketPathSecure: string = this.portSettings.socketPath ?? DyNTS_defaultSocketPath;
|
|
550
553
|
this.allSocketServers.push(
|
|
551
554
|
await service.setupSocketServer(
|
|
552
|
-
new SocketIO.Server(this.httpsServer),
|
|
555
|
+
new SocketIO.Server(this.httpsServer, { path: socketPathSecure }),
|
|
553
556
|
DyNTS_SocketSecurity.secure,
|
|
554
557
|
(): void => {
|
|
555
558
|
this.httpsSocketSettingUpCount--;
|
|
@@ -557,6 +560,10 @@ export abstract class DyNTS_AppExtended extends DyNTS_App {
|
|
|
557
560
|
if (this.httpsSocketSettingUpCount === 0) {
|
|
558
561
|
this.systemControlsExt.httpsSocketServer.started = true;
|
|
559
562
|
}
|
|
563
|
+
},
|
|
564
|
+
{
|
|
565
|
+
attachedToExistingServer: useBaseHttpsServer,
|
|
566
|
+
effectivePort: effectivePort,
|
|
560
567
|
}
|
|
561
568
|
)
|
|
562
569
|
);
|
|
@@ -1327,7 +1327,7 @@ export class DyNTS_DataService<T extends DyFM_Metadata> {
|
|
|
1327
1327
|
...this._getDefaultErrorSettings(
|
|
1328
1328
|
'validateByPropertyParams',
|
|
1329
1329
|
new Error(
|
|
1330
|
-
|
|
1330
|
+
`Validation failed! (multiple validation errors for ${this.dataParams.dataName})` +
|
|
1331
1331
|
validationErrors.map((error: DyFM_Error) => `\n ${DyFM_Error.getAnyMessage(error)}`).join('')
|
|
1332
1332
|
)
|
|
1333
1333
|
),
|
|
@@ -1367,10 +1367,7 @@ export class DyNTS_DataService<T extends DyFM_Metadata> {
|
|
|
1367
1367
|
): void {
|
|
1368
1368
|
// basic required validations
|
|
1369
1369
|
if (
|
|
1370
|
-
(
|
|
1371
|
-
propertyParams.required ||
|
|
1372
|
-
propertyParams.index
|
|
1373
|
-
) && (
|
|
1370
|
+
propertyParams.required && (
|
|
1374
1371
|
propertyValue === null ||
|
|
1375
1372
|
propertyValue === undefined
|
|
1376
1373
|
)
|
|
@@ -1380,7 +1377,7 @@ export class DyNTS_DataService<T extends DyFM_Metadata> {
|
|
|
1380
1377
|
'validateProperty',
|
|
1381
1378
|
new Error(
|
|
1382
1379
|
`validateProperty failed, "${this.getPropertyKey(propertyParams, isSubObjectOf)}" is missing! ` +
|
|
1383
|
-
`(
|
|
1380
|
+
`(required in "${this.dataParams.dataName}" dataParams) ` +
|
|
1384
1381
|
((data as any)?.name ? `\n The failed data's name: ${(data as any).name}` : '')
|
|
1385
1382
|
)
|
|
1386
1383
|
),
|
|
@@ -1391,7 +1388,7 @@ export class DyNTS_DataService<T extends DyFM_Metadata> {
|
|
|
1391
1388
|
validationErrors: {
|
|
1392
1389
|
[propertyParams.key]: {
|
|
1393
1390
|
message: `validateProperty failed, "${this.getPropertyKey(propertyParams, isSubObjectOf)}" is missing! ` +
|
|
1394
|
-
`(
|
|
1391
|
+
`(required in "${this.dataParams.dataName}" dataParams) ` +
|
|
1395
1392
|
((data as any)?.name ? `\n The failed data's name: ${(data as any).name}` : ''),
|
|
1396
1393
|
code: `${this.ecBase}DyNTS-DS0-VP1`,
|
|
1397
1394
|
userMessage: 'The property is required and must be a valid value!',
|
|
@@ -1495,11 +1495,17 @@ export class DyNTS_DBService<T extends DyFM_Metadata> {
|
|
|
1495
1495
|
}
|
|
1496
1496
|
|
|
1497
1497
|
if (!properties._deletedBy) {
|
|
1498
|
-
properties._deletedBy = {
|
|
1498
|
+
properties._deletedBy = {
|
|
1499
1499
|
key: '_deletedBy', type: DyFM_BasicProperty_Type.string,
|
|
1500
1500
|
};
|
|
1501
1501
|
}
|
|
1502
1502
|
|
|
1503
|
+
if (!properties._archived) {
|
|
1504
|
+
properties._archived = {
|
|
1505
|
+
key: '_archived', type: DyFM_BasicProperty_Type.date,
|
|
1506
|
+
};
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1503
1509
|
return properties;
|
|
1504
1510
|
}
|
|
1505
1511
|
|
|
@@ -1521,10 +1527,12 @@ export class DyNTS_DBService<T extends DyFM_Metadata> {
|
|
|
1521
1527
|
}
|
|
1522
1528
|
|
|
1523
1529
|
if (!properties._archived) {
|
|
1524
|
-
properties._archived = {
|
|
1530
|
+
properties._archived = {
|
|
1525
1531
|
key: '_archived', type: DyFM_BasicProperty_Type.date,
|
|
1526
|
-
required: true,
|
|
1532
|
+
required: true,
|
|
1527
1533
|
};
|
|
1534
|
+
} else if (properties._archived.required === undefined) {
|
|
1535
|
+
properties._archived.required = true;
|
|
1528
1536
|
}
|
|
1529
1537
|
|
|
1530
1538
|
return properties;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
import { DyFM_Error, DyFM_HttpCallType } from '@futdevpro/fsm-dynamo';
|
|
3
3
|
|
|
4
|
+
import { DyNTS_global_settings } from '../../_collections/global-settings.const';
|
|
4
5
|
import { DyNTS_RouteSecurity } from '../../_enums/route-security.enum';
|
|
5
6
|
import { DyNTS_Endpoint_Params } from '../../_models/control-models/endpoint-params.control-model';
|
|
6
7
|
import {
|
|
@@ -80,4 +81,18 @@ describe('| DyNTS_RoutingModule', () => {
|
|
|
80
81
|
routingModule.endpoints = [ mockEndpoint, mockEndpoint ];
|
|
81
82
|
expect(() => routingModule['mountRoutes']()).toThrowError(/ENDPOINT DUPLICATION/);
|
|
82
83
|
});
|
|
84
|
+
|
|
85
|
+
it('| should use DyNTS_global_settings.baseUrl as route prefix', () => {
|
|
86
|
+
const originalBaseUrl: string = DyNTS_global_settings.baseUrl;
|
|
87
|
+
try {
|
|
88
|
+
DyNTS_global_settings.baseUrl = '/custom-api';
|
|
89
|
+
const moduleWithCustomBase: DyNTS_RoutingModule = new DyNTS_RoutingModule({
|
|
90
|
+
route: '/foo',
|
|
91
|
+
controllers: [ mockController ],
|
|
92
|
+
});
|
|
93
|
+
expect(moduleWithCustomBase.route).toBe('/custom-api/foo');
|
|
94
|
+
} finally {
|
|
95
|
+
DyNTS_global_settings.baseUrl = originalBaseUrl;
|
|
96
|
+
}
|
|
97
|
+
});
|
|
83
98
|
});
|