@push.rocks/smartsocket 2.0.19

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 (47) hide show
  1. package/dist_bundle/bundle.js +10311 -0
  2. package/dist_bundle/bundle.js.map +7 -0
  3. package/dist_ts/00_commitinfo_data.d.ts +8 -0
  4. package/dist_ts/00_commitinfo_data.js +9 -0
  5. package/dist_ts/index.d.ts +4 -0
  6. package/dist_ts/index.js +7 -0
  7. package/dist_ts/interfaces/connection.d.ts +4 -0
  8. package/dist_ts/interfaces/connection.js +2 -0
  9. package/dist_ts/interfaces/index.d.ts +2 -0
  10. package/dist_ts/interfaces/index.js +3 -0
  11. package/dist_ts/interfaces/tag.d.ts +7 -0
  12. package/dist_ts/interfaces/tag.js +2 -0
  13. package/dist_ts/smartsocket.classes.smartsocket.d.ts +43 -0
  14. package/dist_ts/smartsocket.classes.smartsocket.js +102 -0
  15. package/dist_ts/smartsocket.classes.smartsocketclient.d.ts +64 -0
  16. package/dist_ts/smartsocket.classes.smartsocketclient.js +217 -0
  17. package/dist_ts/smartsocket.classes.socketconnection.d.ts +65 -0
  18. package/dist_ts/smartsocket.classes.socketconnection.js +169 -0
  19. package/dist_ts/smartsocket.classes.socketfunction.d.ts +45 -0
  20. package/dist_ts/smartsocket.classes.socketfunction.js +40 -0
  21. package/dist_ts/smartsocket.classes.socketrequest.d.ts +47 -0
  22. package/dist_ts/smartsocket.classes.socketrequest.js +72 -0
  23. package/dist_ts/smartsocket.classes.socketserver.d.ts +35 -0
  24. package/dist_ts/smartsocket.classes.socketserver.js +78 -0
  25. package/dist_ts/smartsocket.logging.d.ts +2 -0
  26. package/dist_ts/smartsocket.logging.js +3 -0
  27. package/dist_ts/smartsocket.plugins.d.ts +13 -0
  28. package/dist_ts/smartsocket.plugins.js +16 -0
  29. package/dist_ts/smartsocket.pluginstyped.d.ts +15 -0
  30. package/dist_ts/smartsocket.pluginstyped.js +2 -0
  31. package/npmextra.json +18 -0
  32. package/package.json +64 -0
  33. package/readme.md +120 -0
  34. package/ts/00_commitinfo_data.ts +8 -0
  35. package/ts/index.ts +7 -0
  36. package/ts/interfaces/connection.ts +11 -0
  37. package/ts/interfaces/index.ts +2 -0
  38. package/ts/interfaces/tag.ts +6 -0
  39. package/ts/smartsocket.classes.smartsocket.ts +137 -0
  40. package/ts/smartsocket.classes.smartsocketclient.ts +266 -0
  41. package/ts/smartsocket.classes.socketconnection.ts +224 -0
  42. package/ts/smartsocket.classes.socketfunction.ts +93 -0
  43. package/ts/smartsocket.classes.socketrequest.ts +126 -0
  44. package/ts/smartsocket.classes.socketserver.ts +94 -0
  45. package/ts/smartsocket.logging.ts +3 -0
  46. package/ts/smartsocket.plugins.ts +29 -0
  47. package/ts/smartsocket.pluginstyped.ts +23 -0
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "@push.rocks/smartsocket",
3
+ "version": "2.0.19",
4
+ "description": "easy and secure websocket communication",
5
+ "main": "dist_ts/index.js",
6
+ "typings": "dist_ts/index.d.ts",
7
+ "type": "module",
8
+ "scripts": {
9
+ "test": "(tstest test/)",
10
+ "build": "(tsbuild --web --allowimplicitany && tsbundle --from ./ts/index.ts --to dist_bundle/bundle.js)",
11
+ "buildDocs": "tsdoc"
12
+ },
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+ssh://git@gitlab.com/pushrocks/smartsocket.git"
16
+ },
17
+ "author": "Lossless GmbH",
18
+ "license": "MIT",
19
+ "bugs": {
20
+ "url": "https://gitlab.com/pushrocks/smartsocket/issues"
21
+ },
22
+ "homepage": "https://gitlab.com/pushrocks/smartsocket#README",
23
+ "dependencies": {
24
+ "@apiglobal/typedrequest-interfaces": "^2.0.1",
25
+ "@pushrocks/isohash": "^2.0.0",
26
+ "@pushrocks/isounique": "^1.0.5",
27
+ "@pushrocks/lik": "^6.0.2",
28
+ "@pushrocks/smartdelay": "^2.0.13",
29
+ "@pushrocks/smartenv": "^5.0.5",
30
+ "@pushrocks/smartexpress": "^4.0.34",
31
+ "@pushrocks/smartjson": "^5.0.1",
32
+ "@pushrocks/smartlog": "^3.0.1",
33
+ "@pushrocks/smartpromise": "^3.1.7",
34
+ "@pushrocks/smartrx": "^3.0.0",
35
+ "@pushrocks/smarttime": "^4.0.1",
36
+ "engine.io": "6.3.1",
37
+ "socket.io": "4.5.4",
38
+ "socket.io-client": "4.5.4"
39
+ },
40
+ "devDependencies": {
41
+ "@gitzone/tsbuild": "^2.1.63",
42
+ "@gitzone/tsbundle": "^2.0.7",
43
+ "@gitzone/tsrun": "^1.2.37",
44
+ "@gitzone/tstest": "^1.0.72",
45
+ "@pushrocks/tapbundle": "^5.0.4",
46
+ "@types/node": "^18.15.11"
47
+ },
48
+ "private": false,
49
+ "files": [
50
+ "ts/**/*",
51
+ "ts_web/**/*",
52
+ "dist/**/*",
53
+ "dist_*/**/*",
54
+ "dist_ts/**/*",
55
+ "dist_ts_web/**/*",
56
+ "assets/**/*",
57
+ "cli.js",
58
+ "npmextra.json",
59
+ "readme.md"
60
+ ],
61
+ "browserslist": [
62
+ "last 1 chrome versions"
63
+ ]
64
+ }
package/readme.md ADDED
@@ -0,0 +1,120 @@
1
+ # @pushrocks/smartsocket
2
+ easy and secure websocket communication
3
+
4
+ ## Availabililty and Links
5
+ * [npmjs.org (npm package)](https://www.npmjs.com/package/@pushrocks/smartsocket)
6
+ * [gitlab.com (source)](https://gitlab.com/pushrocks/smartsocket)
7
+ * [github.com (source mirror)](https://github.com/pushrocks/smartsocket)
8
+ * [docs (typedoc)](https://pushrocks.gitlab.io/smartsocket/)
9
+
10
+ ## Status for master
11
+
12
+ Status Category | Status Badge
13
+ -- | --
14
+ GitLab Pipelines | [![pipeline status](https://gitlab.com/pushrocks/smartsocket/badges/master/pipeline.svg)](https://lossless.cloud)
15
+ GitLab Pipline Test Coverage | [![coverage report](https://gitlab.com/pushrocks/smartsocket/badges/master/coverage.svg)](https://lossless.cloud)
16
+ npm | [![npm downloads per month](https://badgen.net/npm/dy/@pushrocks/smartsocket)](https://lossless.cloud)
17
+ Snyk | [![Known Vulnerabilities](https://badgen.net/snyk/pushrocks/smartsocket)](https://lossless.cloud)
18
+ TypeScript Support | [![TypeScript](https://badgen.net/badge/TypeScript/>=%203.x/blue?icon=typescript)](https://lossless.cloud)
19
+ node Support | [![node](https://img.shields.io/badge/node->=%2010.x.x-blue.svg)](https://nodejs.org/dist/latest-v10.x/docs/api/)
20
+ Code Style | [![Code Style](https://badgen.net/badge/style/prettier/purple)](https://lossless.cloud)
21
+ PackagePhobia (total standalone install weight) | [![PackagePhobia](https://badgen.net/packagephobia/install/@pushrocks/smartsocket)](https://lossless.cloud)
22
+ PackagePhobia (package size on registry) | [![PackagePhobia](https://badgen.net/packagephobia/publish/@pushrocks/smartsocket)](https://lossless.cloud)
23
+ BundlePhobia (total size when bundled) | [![BundlePhobia](https://badgen.net/bundlephobia/minzip/@pushrocks/smartsocket)](https://lossless.cloud)
24
+
25
+ ## Usage
26
+
27
+ Use TypeScript for best in class instellisense.
28
+
29
+ Under the hood we use socket.io and shortid for managed data exchange.
30
+
31
+ ### Serverside
32
+
33
+ ```typescript
34
+ import * as smartsocket from 'smartsocket';
35
+ import * as q from q; // q is a promise library
36
+
37
+ // The "Smartsocket" listens on a port and can receive new "SocketConnection" requests.
38
+ let mySmartsocket = new smartsocket.Smartsocket({
39
+ port: 3000, // the port smartsocket will listen on
40
+ });
41
+
42
+ // optional:
43
+ // run this with anothoer existing server like express
44
+ declare var someExpressServer; // read the express docs about how express actually works
45
+ mySmartsocket.setServer(someExpressServer);
46
+
47
+ // A "SocketRole" can be referenced by "SocketFunction"s.
48
+ // All "SocketRequest"s carry authentication data for a specific "SocketRole".
49
+ // "SocketFunction"s know which "SocketRole"s are allowed to execute them
50
+ let mySocketRole = new smartsocket.SocketRole({
51
+ name: 'someRoleName',
52
+ passwordHash: 'someHashedString',
53
+ });
54
+
55
+ // A "SocketFunction" executes a referenced function and passes in any data of the corresponding "SocketRequest".
56
+ // The referenced function must return a promise and resolve with data of type any.
57
+ // Any "SocketRequest" carries a unique identifier. If the referenced function's promise resolved any passed on argument will be returned to the requesting party
58
+ let testSocketFunction1 = new smartsocket.SocketFunction({
59
+ funcName: 'testSocketFunction1',
60
+ funcDef: (data) => {
61
+ console.log('testSocketFunction1 executed successfully!');
62
+ },
63
+ allowedRoles: [mySocketRole], // all roles that have access to a specific function
64
+ });
65
+
66
+ // A "Smartsocket" exposes a .clientCall() that gets
67
+ // 1. the name of the "SocketFunction" on the client side
68
+ // 2. the data to pass in
69
+ // 3. And a target "SocketConnection" (there can be multiple connections at once)
70
+ // any unique id association is done internally
71
+ mySmartsocket.clientCall('restart', data, someTargetConnection).then((responseData) => {});
72
+ ```
73
+
74
+ #### Client side
75
+
76
+ ```typescript
77
+ import * as smartsocket from 'smartsocket';
78
+
79
+ // A "SmartsocketClient" is different from a "Smartsocket" in that it doesn't expose any public address.
80
+ // Thus any new "SocketConnection"s must be innitiated from a "SmartsocketClient".
81
+ let testSmartsocketClient = new smartsocket.SmartsocketClient({
82
+ port: testConfig.port,
83
+ url: 'http://localhost',
84
+ password: 'testPassword',
85
+ alias: 'testClient1',
86
+ role: 'testRole1',
87
+ });
88
+
89
+ // You can .connect() and .disconnect() from a "Smartsocket"
90
+ testSmartsocketClient.connect().then(() => {
91
+ done();
92
+ });
93
+
94
+ // The client can also specify "SocketFunction"s. It can also specify "SocketRole"s in case a client connects to multiple servers at once
95
+ let testSocketFunction2 = new smartsocket.SocketFunction({
96
+ funcName: 'testSocketFunction2',
97
+ funcDef: (data) => {}, // the function to execute, has to return promise
98
+ allowedRoles: [],
99
+ });
100
+
101
+ // A "SmartsocketClient" can call functions on the serverside using .serverCall() analog to the "Smartsocket"'s .clientCall method.
102
+ mySmartsocketClient.serverCall('function', functionCallData).then((functionResponseData) => {
103
+ // the functionResponseData comes from the server... awesome, right?
104
+ });
105
+ ```
106
+
107
+ > **NOTE:**
108
+ > you can easily chain dependent requests on either the server or client side with promises.
109
+ > `data` is always a js object that you can design for your specific needs.
110
+ > It supports buffers for large binary data network exchange.
111
+
112
+ ## Contribution
113
+
114
+ We are always happy for code contributions. If you are not the code contributing type that is ok. Still, maintaining Open Source repositories takes considerable time and thought. If you like the quality of what we do and our modules are useful to you we would appreciate a little monthly contribution: You can [contribute one time](https://lossless.link/contribute-onetime) or [contribute monthly](https://lossless.link/contribute). :)
115
+
116
+ For further information read the linked docs at the top of this readme.
117
+
118
+ ## Legal
119
+ > MIT licensed | **©** [Task Venture Capital GmbH](https://task.vc)
120
+ | By using this npm module you agree to our [privacy policy](https://lossless.gmbH/privacy)
@@ -0,0 +1,8 @@
1
+ /**
2
+ * autocreated commitinfo by @pushrocks/commitinfo
3
+ */
4
+ export const commitinfo = {
5
+ name: '@pushrocks/smartsocket',
6
+ version: '2.0.19',
7
+ description: 'easy and secure websocket communication'
8
+ }
package/ts/index.ts ADDED
@@ -0,0 +1,7 @@
1
+ // export main classes
2
+ export * from './smartsocket.classes.smartsocket.js';
3
+ export * from './smartsocket.classes.smartsocketclient.js';
4
+
5
+ // export further classes and objects
6
+ export * from './smartsocket.classes.socketfunction.js';
7
+ export * from './smartsocket.classes.socketconnection.js';
@@ -0,0 +1,11 @@
1
+ export interface IRequestAuthPayload {
2
+ serverAlias: string;
3
+ }
4
+
5
+ export type TConnectionStatus =
6
+ | 'new'
7
+ | 'connecting'
8
+ | 'connected'
9
+ | 'disconnecting'
10
+ | 'disconnected'
11
+ | 'timedOut';
@@ -0,0 +1,2 @@
1
+ export * from './connection.js';
2
+ export * from './tag.js';
@@ -0,0 +1,6 @@
1
+ export interface ITag<T = any> {
2
+ id: string;
3
+ payload: T;
4
+ }
5
+
6
+ export type TTagStore = { [key: string]: ITag };
@@ -0,0 +1,137 @@
1
+ import * as plugins from './smartsocket.plugins.js';
2
+ import * as pluginsTyped from './smartsocket.pluginstyped.js';
3
+ import * as interfaces from './interfaces/index.js';
4
+
5
+ // classes
6
+ import { SocketConnection } from './smartsocket.classes.socketconnection.js';
7
+ import {
8
+ ISocketFunctionCallDataRequest,
9
+ SocketFunction,
10
+ ISocketFunctionCallDataResponse,
11
+ } from './smartsocket.classes.socketfunction.js';
12
+ import { SocketRequest } from './smartsocket.classes.socketrequest.js';
13
+ import { SocketServer } from './smartsocket.classes.socketserver.js';
14
+
15
+ import { logger } from './smartsocket.logging.js';
16
+
17
+ export interface ISmartsocketConstructorOptions {
18
+ alias: string;
19
+ port?: number;
20
+ }
21
+
22
+ export class Smartsocket {
23
+ /**
24
+ * a unique id to detect server restarts
25
+ */
26
+ public alias: string;
27
+ public smartenv = new plugins.smartenv.Smartenv();
28
+ public options: ISmartsocketConstructorOptions;
29
+ public io: pluginsTyped.socketIo.Server;
30
+ public socketConnections = new plugins.lik.ObjectMap<SocketConnection>();
31
+ public socketFunctions = new plugins.lik.ObjectMap<SocketFunction<any>>();
32
+ public socketRequests = new plugins.lik.ObjectMap<SocketRequest<any>>();
33
+
34
+ public eventSubject = new plugins.smartrx.rxjs.Subject<interfaces.TConnectionStatus>();
35
+
36
+ private socketServer = new SocketServer(this);
37
+
38
+ constructor(optionsArg: ISmartsocketConstructorOptions) {
39
+ this.options = optionsArg;
40
+ this.alias = plugins.isounique.uni(this.options.alias);
41
+ }
42
+
43
+ public async setExternalServer(serverType: 'smartexpress', serverArg: any) {
44
+ await this.socketServer.setExternalServer(serverType, serverArg);
45
+ }
46
+
47
+ /**
48
+ * starts smartsocket
49
+ */
50
+ public async start() {
51
+ const socketIoModule = await this.smartenv.getSafeNodeModule('socket.io');
52
+ this.io = new socketIoModule.Server(await this.socketServer.getServerForSocketIo(), {
53
+ cors: {
54
+ allowedHeaders: '*',
55
+ methods: '*',
56
+ origin: '*',
57
+ }
58
+ });
59
+ await this.socketServer.start();
60
+ this.io.on('connection', (socketArg) => {
61
+ this._handleSocketConnection(socketArg);
62
+ });
63
+ }
64
+
65
+ /**
66
+ * stops smartsocket
67
+ */
68
+ public async stop() {
69
+ await plugins.smartdelay.delayFor(1000);
70
+ this.socketConnections.forEach((socketObjectArg: SocketConnection) => {
71
+ if (socketObjectArg) {
72
+ logger.log(
73
+ 'info',
74
+ `disconnecting socket with >>alias ${socketObjectArg.alias} due to server stop...`
75
+ );
76
+ socketObjectArg.disconnect();
77
+ }
78
+ });
79
+ this.socketConnections.wipe();
80
+ this.io.close();
81
+
82
+ // stop the corresponging server
83
+ this.socketServer.stop();
84
+ }
85
+
86
+ // communication
87
+
88
+ /**
89
+ * allows call to specific client.
90
+ */
91
+ public async clientCall<T extends plugins.typedrequestInterfaces.ITypedRequest>(
92
+ functionNameArg: T['method'],
93
+ dataArg: T['request'],
94
+ targetSocketConnectionArg: SocketConnection
95
+ ): Promise<T['response']> {
96
+ const socketRequest = new SocketRequest<T>(this, {
97
+ funcCallData: {
98
+ funcDataArg: dataArg,
99
+ funcName: functionNameArg,
100
+ },
101
+ originSocketConnection: targetSocketConnectionArg,
102
+ shortId: plugins.isounique.uni(),
103
+ side: 'requesting',
104
+ });
105
+ const response: ISocketFunctionCallDataResponse<T> = await socketRequest.dispatch();
106
+ const result = response.funcDataArg;
107
+ return result;
108
+ }
109
+
110
+ public addSocketFunction(socketFunction: SocketFunction<any>) {
111
+ this.socketFunctions.add(socketFunction);
112
+ }
113
+
114
+ /**
115
+ * the standard handler for new socket connections
116
+ */
117
+ private async _handleSocketConnection(socketArg: pluginsTyped.socketIo.Socket) {
118
+ const socketConnection: SocketConnection = new SocketConnection({
119
+ alias: undefined,
120
+ authenticated: false,
121
+ side: 'server',
122
+ smartsocketHost: this,
123
+ socket: socketArg,
124
+ });
125
+ logger.log('info', 'Socket connected. Trying to authenticate...');
126
+ this.socketConnections.add(socketConnection);
127
+ const disconnectSubscription = socketConnection.eventSubject.subscribe((eventArg) => {
128
+ if (eventArg === 'disconnected') {
129
+ this.socketConnections.remove(socketConnection);
130
+ disconnectSubscription.unsubscribe();
131
+ }
132
+ });
133
+ await socketConnection.authenticate();
134
+ await socketConnection.listenToFunctionRequests();
135
+ await socketConnection.socket.emit('serverFullyReactive');
136
+ }
137
+ }
@@ -0,0 +1,266 @@
1
+ import * as plugins from './smartsocket.plugins.js';
2
+ import * as pluginsTyped from './smartsocket.pluginstyped.js';
3
+ import * as interfaces from './interfaces/index.js';
4
+
5
+ import { SocketConnection } from './smartsocket.classes.socketconnection.js';
6
+ import {
7
+ ISocketFunctionCallDataRequest,
8
+ SocketFunction,
9
+ } from './smartsocket.classes.socketfunction.js';
10
+ import { ISocketRequestDataObject, SocketRequest } from './smartsocket.classes.socketrequest.js';
11
+ import { logger } from './smartsocket.logging.js';
12
+
13
+ /**
14
+ * interface for class SmartsocketClient
15
+ */
16
+ export interface ISmartsocketClientOptions {
17
+ port: number;
18
+ url: string;
19
+ alias: string; // an alias makes it easier to identify this client in a multo client environment
20
+ autoReconnect?: boolean;
21
+ }
22
+
23
+ export class SmartsocketClient {
24
+ // a unique id
25
+ public shortId = plugins.isounique.uni();
26
+
27
+ // the shortId of the remote we connect to
28
+ public remoteShortId: string = null;
29
+
30
+ public alias: string;
31
+ public socketConnection: SocketConnection;
32
+ public serverUrl: string;
33
+ public serverPort: number;
34
+ public autoReconnect: boolean;
35
+
36
+ // status handling
37
+ public eventSubject = new plugins.smartrx.rxjs.Subject<interfaces.TConnectionStatus>();
38
+ public eventStatus: interfaces.TConnectionStatus = 'new';
39
+
40
+ public socketFunctions = new plugins.lik.ObjectMap<SocketFunction<any>>();
41
+ public socketRequests = new plugins.lik.ObjectMap<SocketRequest<any>>();
42
+
43
+ // tagStore
44
+ private tagStore: { [key: string]: interfaces.ITag } = {};
45
+ private tagStoreSubscription: plugins.smartrx.rxjs.Subscription;
46
+
47
+ /**
48
+ * adds a tag to a connection
49
+ */
50
+ public async addTag(tagArg: interfaces.ITag) {
51
+ if (this.socketConnection) {
52
+ await this.socketConnection.addTag(tagArg);
53
+ } else {
54
+ this.tagStore[tagArg.id] = tagArg;
55
+ }
56
+ }
57
+
58
+ /**
59
+ * gets a tag by id
60
+ * @param tagIdArg
61
+ */
62
+ public async getTagById(tagIdArg: interfaces.ITag['id']) {
63
+ return this.tagStore[tagIdArg];
64
+ }
65
+
66
+ /**
67
+ * removes a tag from a connection
68
+ */
69
+ public async removeTagById(tagIdArg: interfaces.ITag['id']) {
70
+ if (this.socketConnection) {
71
+ this.socketConnection.removeTagById(tagIdArg);
72
+ } else {
73
+ delete this.tagStore[tagIdArg];
74
+ }
75
+ }
76
+
77
+ constructor(optionsArg: ISmartsocketClientOptions) {
78
+ this.alias = optionsArg.alias;
79
+ this.serverUrl = optionsArg.url;
80
+ this.serverPort = optionsArg.port;
81
+ this.autoReconnect = optionsArg.autoReconnect;
82
+ }
83
+
84
+ public addSocketFunction(socketFunction: SocketFunction<any>) {
85
+ this.socketFunctions.add(socketFunction);
86
+ }
87
+
88
+ /**
89
+ * connect the client to the server
90
+ */
91
+ public async connect() {
92
+ const done = plugins.smartpromise.defer();
93
+ const smartenvInstance = new plugins.smartenv.Smartenv();
94
+ const socketIoClient: any = await smartenvInstance.getEnvAwareModule({
95
+ nodeModuleName: 'socket.io-client',
96
+ webUrlArg: 'https://cdn.jsdelivr.net/npm/socket.io-client@4/dist/socket.io.js',
97
+ getFunction: () => {
98
+ const socketIoBrowserModule = (globalThis as any).io;
99
+ // console.log('loaded socket.io for browser');
100
+ return socketIoBrowserModule;
101
+ },
102
+ });
103
+ // console.log(socketIoClient);
104
+ logger.log('info', 'trying to connect...');
105
+ const socketUrl = `${this.serverUrl}:${this.serverPort}`;
106
+ this.socketConnection = new SocketConnection({
107
+ alias: this.alias,
108
+ authenticated: false,
109
+ side: 'client',
110
+ smartsocketHost: this,
111
+ socket: await socketIoClient
112
+ .connect(socketUrl, {
113
+ multiplex: true,
114
+ rememberUpgrade: true,
115
+ autoConnect: false,
116
+ reconnectionAttempts: 0,
117
+ rejectUnauthorized: socketUrl.startsWith('https://localhost') ? false : true,
118
+ })
119
+ .open(),
120
+ });
121
+
122
+ const timer = new plugins.smarttime.Timer(5000);
123
+ timer.start();
124
+ timer.completed.then(() => {
125
+ this.updateStatus('timedOut');
126
+ logger.log('warn', 'connection to server timed out.');
127
+ this.disconnect(true);
128
+ });
129
+
130
+ // authentication flow
131
+ this.socketConnection.socket.on('requestAuth', (dataArg: interfaces.IRequestAuthPayload) => {
132
+ timer.reset();
133
+ logger.log('info', `server ${dataArg.serverAlias} requested authentication`);
134
+
135
+ // lets register the authenticated event
136
+ this.socketConnection.socket.on('authenticated', async () => {
137
+ this.remoteShortId = dataArg.serverAlias;
138
+ logger.log('info', 'client is authenticated');
139
+ this.socketConnection.authenticated = true;
140
+ await this.socketConnection.listenToFunctionRequests();
141
+ });
142
+
143
+ this.socketConnection.socket.on('serverFullyReactive', async () => {
144
+ // lets take care of retagging
145
+ const oldTagStore = this.tagStore;
146
+ this.tagStoreSubscription?.unsubscribe();
147
+ for (const keyArg of Object.keys(this.tagStore)) {
148
+ this.socketConnection.addTag(this.tagStore[keyArg]);
149
+ }
150
+ this.tagStoreSubscription = this.socketConnection.tagStoreObservable.subscribe(
151
+ (tagStoreArg) => {
152
+ this.tagStore = tagStoreArg;
153
+ }
154
+ );
155
+
156
+ for (const tag of Object.keys(oldTagStore)) {
157
+ await this.addTag(oldTagStore[tag]);
158
+ }
159
+ this.updateStatus('connected');
160
+ done.resolve();
161
+ });
162
+
163
+ // lets register the forbidden event
164
+ this.socketConnection.socket.on('forbidden', async () => {
165
+ logger.log('warn', `disconnecting due to being forbidden to use the ressource`);
166
+ await this.disconnect();
167
+ });
168
+
169
+ // lets provide the actual auth data
170
+ this.socketConnection.socket.emit('dataAuth', {
171
+ alias: this.alias,
172
+ });
173
+ });
174
+
175
+ // handle connection
176
+ this.socketConnection.socket.on('connect', async () => {});
177
+
178
+ // handle disconnection and errors
179
+ this.socketConnection.socket.on('disconnect', async () => {
180
+ await this.disconnect(true);
181
+ });
182
+
183
+ this.socketConnection.socket.on('reconnect_failed', async () => {
184
+ await this.disconnect(true);
185
+ });
186
+ this.socketConnection.socket.on('connect_error', async () => {
187
+ await this.disconnect(true);
188
+ });
189
+ return done.promise;
190
+ }
191
+
192
+ private disconnectRunning = false;
193
+
194
+ /**
195
+ * disconnect from the server
196
+ */
197
+ public async disconnect(useAutoReconnectSetting = false) {
198
+ if (this.disconnectRunning) {
199
+ return;
200
+ }
201
+ this.disconnectRunning = true;
202
+ this.updateStatus('disconnecting');
203
+ this.tagStoreSubscription?.unsubscribe();
204
+ if (this.socketConnection) {
205
+ await this.socketConnection.disconnect();
206
+ this.socketConnection = undefined;
207
+ logger.log('ok', 'disconnected socket!');
208
+ } else {
209
+ this.disconnectRunning = false;
210
+ logger.log('warn', 'tried to disconnect, without a SocketConnection');
211
+ return;
212
+ }
213
+
214
+ logger.log('warn', `disconnected from server ${this.remoteShortId}`);
215
+ this.remoteShortId = null;
216
+
217
+ if (this.autoReconnect && useAutoReconnectSetting && this.eventStatus !== 'connecting') {
218
+ this.updateStatus('connecting');
219
+ console.log('debounced reconnect!');
220
+ await plugins.smartdelay.delayForRandom(10000, 20000);
221
+ this.disconnectRunning = false;
222
+ await this.connect();
223
+ } else {
224
+ this.disconnectRunning = false;
225
+ }
226
+ }
227
+
228
+ /**
229
+ * stops the client completely
230
+ */
231
+ public async stop() {
232
+ this.autoReconnect = false;
233
+ await this.disconnect();
234
+ }
235
+
236
+ /**
237
+ * dispatches a server call
238
+ * @param functionNameArg
239
+ * @param dataArg
240
+ */
241
+ public async serverCall<T extends plugins.typedrequestInterfaces.ITypedRequest>(
242
+ functionNameArg: T['method'],
243
+ dataArg: T['request']
244
+ ): Promise<T['response']> {
245
+ const done = plugins.smartpromise.defer();
246
+ const socketRequest = new SocketRequest<T>(this, {
247
+ side: 'requesting',
248
+ originSocketConnection: this.socketConnection,
249
+ shortId: plugins.isounique.uni(),
250
+ funcCallData: {
251
+ funcName: functionNameArg,
252
+ funcDataArg: dataArg,
253
+ },
254
+ });
255
+ const response = await socketRequest.dispatch();
256
+ const result = response.funcDataArg;
257
+ return result;
258
+ }
259
+
260
+ private updateStatus(statusArg: interfaces.TConnectionStatus) {
261
+ if (this.eventStatus !== statusArg) {
262
+ this.eventSubject.next(statusArg);
263
+ }
264
+ this.eventStatus = statusArg;
265
+ }
266
+ }