grexxconnect-ess 1.1.2 → 1.2.2

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/client.js CHANGED
@@ -91,6 +91,10 @@ class WebSocketClient extends EventEmitter {
91
91
  }
92
92
  }
93
93
 
94
+ disconnect(code, message) {
95
+ this.instance.close(code, message);
96
+ }
97
+
94
98
  reconnect( code, msg ) {
95
99
  this.log('connection failed'.red, `retry in ${this.autoReconnectInterval}ms`, code.toString().red, (msg || '').yellow);
96
100
  this.instance.removeAllListeners();
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (C) 2014-2021 Grexx - All Rights Reserved
2
+ * Copyright (C) 2014-2022 Grexx - All Rights Reserved
3
3
  * Unauthorized copying of this file, via any medium is strictly prohibited
4
4
  * Proprietary and confidential
5
5
  */
@@ -8,8 +8,10 @@
8
8
  const EventEmitter = require('events');
9
9
  const WebSocket = require('./client');
10
10
 
11
+ const TIMEOUT_LONG = 30 * 1000; //== 30 seconds
12
+
11
13
  class EssConnect extends EventEmitter {
12
- constructor( settings ) {
14
+ constructor(settings) {
13
15
  super();
14
16
 
15
17
  const thisVersion = require('./package.json').version;
@@ -21,29 +23,95 @@ class EssConnect extends EventEmitter {
21
23
  debug: settings.debug
22
24
  });
23
25
 
24
- const send = ( type, content ) => {
25
- return new Promise(( resolve, reject ) => {
26
+ const _waitQueue = {},
27
+ _unfinishedResponses = {};
28
+
29
+ const send = (type, content, timeout = TIMEOUT_LONG) => {
30
+ return new Promise((resolve, reject) => {
31
+ const essCorrelationId = content?.['ess-correlation-id'];
32
+
33
+ if (!essCorrelationId || !this._ackFunctional) {
34
+ try {
35
+ ws.send(JSON.stringify({
36
+ type: type,
37
+ content: content,
38
+ timestamp: Date.now()
39
+ }));
40
+ return resolve();
41
+ } catch (error) {
42
+ return reject(error);
43
+ }
44
+ }
45
+
46
+ const exceededTimeout = setTimeout(async () => {
47
+ ws.debug(`timeout of ${timeout}ms exceeded for ack response from server`);
48
+ return reject('Timeout exceeded');
49
+ }, timeout);
50
+
51
+ _waitQueue[essCorrelationId] = () => {
52
+ clearTimeout(exceededTimeout);
53
+ ws.debug(`ack response received from server`);
54
+ return resolve('Ack response received from server');
55
+ };
56
+
26
57
  ws.send(JSON.stringify({
27
58
  type: type,
28
59
  content: content,
29
60
  timestamp: Date.now()
30
- }), error => {
31
- if ( error ) {
32
- reject(error);
33
- } else {
34
- resolve();
61
+ }), (error) => {
62
+ if (error) {
63
+ return reject(error);
35
64
  }
36
65
  });
37
66
  });
38
67
  };
39
68
 
40
- ws.on('close', ( code, msg ) => this.emit('disconnected', code, msg));
41
- ws.on('message', _message => {
42
- switch ( _message.type ) {
69
+ const sendAck = async (connectCorrelationId, message = '', type = 'ack') => {
70
+ this.ws.debug(`acknowledging message from server for message header ID: ${connectCorrelationId}`.gray);
71
+ await send(type, {'connect-correlation-id': connectCorrelationId, message});
72
+ this.emit(type);
73
+ };
74
+
75
+ const completeUnfinishedResponses = () => {
76
+ this.ws.debug(`checking for any incomplete message responses: ${Object.keys(_unfinishedResponses).length.toString().blue} unfinished responses`);
77
+ for (const key in _unfinishedResponses) {
78
+ const {type, content} = _unfinishedResponses[key];
79
+ send(type, content).then(() => {
80
+ delete _unfinishedResponses[key];
81
+ }).catch(() => handleTimeout(type, content));
82
+ }
83
+ };
84
+
85
+ const handleTimeout = (type, content) => {
86
+ const id = content['ess-correlation-id'];
87
+ _unfinishedResponses[id] = {type, content};
88
+ ws.disconnect(1012, "Ack response from server timed out");
89
+ };
90
+
91
+ ws.on('close', (code, msg) => this.emit('disconnected', code, msg));
92
+ ws.on('message', async (_message) => {
93
+ const connectCorrelationId = _message['connect-correlation-id'],
94
+ essCorrelationId = _message['ess-correlation-id'];
95
+
96
+ switch (_message.type) {
43
97
  case 'ping':
44
- this.ws.debug('responding to connection-ping');
45
- send('pong');
98
+ this.ws.debug('responding to connection-ping'.gray);
46
99
  this.emit('ping');
100
+ await send('pong');
101
+ break;
102
+ case 'ackFunctional':
103
+ this.ws.debug('responding to functionality check'.green, 'acknowledgements'.blue);
104
+ this._ackFunctional = true;
105
+ await sendAck(connectCorrelationId, null, 'ackFunctional');
106
+ completeUnfinishedResponses();
107
+ break;
108
+ case 'ack':
109
+ this.ws.debug(`received ack from GrexxConnect for message with header ID: ${essCorrelationId}`);
110
+ if (typeof (essCorrelationId) != 'undefined' && typeof (_waitQueue[essCorrelationId]) == 'function') {
111
+ const execFunc = _waitQueue[essCorrelationId];
112
+ execFunc();
113
+ delete _waitQueue[essCorrelationId];
114
+ }
47
115
  break;
48
116
  case 'authorized':
49
117
  this.log('connected and authorized for'.green, _message.namespace.blue);
@@ -56,19 +124,27 @@ class EssConnect extends EventEmitter {
56
124
  this.handleSystemMessage(_message, send);
57
125
  break;
58
126
  case'message':
127
+ await sendAck(connectCorrelationId, "message received and being processed");
59
128
  this.emit('message', {
60
129
  content: _message.content,
61
130
  parsed: this.parseMessage(_message.content.data),
62
131
  resolve: outputData => {
63
- return send('response', {
64
- toMessage: _message,
65
- outputData: outputData
132
+ const type = 'response',
133
+ content = {
134
+ 'ess-correlation-id': connectCorrelationId,
135
+ toMessage: _message,
136
+ outputData: outputData
137
+ };
138
+
139
+ return send(type, content).catch(() => {
140
+ handleTimeout(type, content);
66
141
  });
67
142
  },
68
- reject: ( publicMessage, debugMessage, additionalContext ) => {
143
+ reject: (publicMessage, debugMessage, additionalContext) => {
69
144
  return send('reject', {
70
- toMessage: _message,
71
- errorContext: Object.assign({
145
+ 'ess-correlation-id': connectCorrelationId,
146
+ toMessage: _message,
147
+ errorContext: Object.assign({
72
148
  publicMessage,
73
149
  debugMessage
74
150
  }, additionalContext)
@@ -99,27 +175,27 @@ class EssConnect extends EventEmitter {
99
175
  /**Set a monitoring function. Should return {status:'ok|warning|error', ...}
100
176
  * @param {function} statusFunction
101
177
  */
102
- setMonitoringResponse( statusFunction ) {
178
+ setMonitoringResponse(statusFunction) {
103
179
  this._statusFunction = statusFunction;
104
180
  }
105
181
 
106
- log( ...args ) {
182
+ log(...args) {
107
183
  console.info(' [ESS][MAIN] '.gray, ...args);
108
184
  }
109
185
 
110
- handleSystemMessage( message, send ) {
111
- if ( message.content.action === 'ping' ) {
112
- this.ws.debug('responding to system-ping');
186
+ handleSystemMessage(message, send) {
187
+ if (message.content.action === 'ping') {
188
+ this.ws.debug('responding to system-ping'.gray);
113
189
  send('system', {
114
190
  action: 'pong',
115
191
  client_data: typeof this._statusFunction === 'function' ?
116
- this._statusFunction() : { status: 'ok' },
192
+ this._statusFunction() : {status: 'ok'},
117
193
  server_data: message.content.id
118
194
  });
119
195
  }
120
196
  }
121
197
 
122
- parseMessage( message = [] ) {
198
+ parseMessage(message = []) {
123
199
  const result = {};
124
200
 
125
201
  message.forEach(part => {
package/package.json CHANGED
@@ -2,7 +2,8 @@
2
2
  "name" : "grexxconnect-ess",
3
3
  "author" : "Grexx <info@grexxboxx.com>",
4
4
  "description" : "Grexx Connect - External System Service Helper",
5
- "version" : "1.1.2",
5
+ "version" : "1.2.2",
6
+ "types" : "./schema/index.d.ts",
6
7
  "contributors" : [
7
8
  {
8
9
  "name" : "Jeffrey van Norden",
@@ -11,7 +12,7 @@
11
12
  ],
12
13
  "dependencies" : {
13
14
  "colors": "1.4",
14
- "ws" : "7.4"
15
+ "ws" : "7.5"
15
16
  },
16
17
  "optionalDependencies": {
17
18
  "utf-8-validate": "5.0",
@@ -0,0 +1,26 @@
1
+ /*
2
+ * Copyright (C) 2014-2022 Grexx - All Rights Reserved
3
+ * Unauthorized copying of this file, via any medium is strictly prohibited
4
+ * Proprietary and confidential
5
+ */
6
+
7
+ export = WebSocketClient;
8
+ declare class WebSocketClient extends EventEmitter {
9
+ constructor(url: any, options: any);
10
+ number: number;
11
+ autoReconnectInterval: number;
12
+ _debug: any;
13
+ log(...args: any[]): void;
14
+ debug(...args: any[]): void;
15
+ open(url: any, options: any): void;
16
+ url: any;
17
+ options: any;
18
+ instance: any;
19
+ send(data: any, option: any, cb: any): void;
20
+ reconnect(code: any, msg: any): void;
21
+ onOpen(...args: any[]): void;
22
+ onMessage(data: any, flags: any, number: any): void;
23
+ onError(error: any): void;
24
+ onClose(code: any, msg: any): void;
25
+ }
26
+ import EventEmitter from "events";
@@ -0,0 +1,21 @@
1
+ /*
2
+ * Copyright (C) 2014-2022 Grexx - All Rights Reserved
3
+ * Unauthorized copying of this file, via any medium is strictly prohibited
4
+ * Proprietary and confidential
5
+ */
6
+
7
+ export = EssConnect;
8
+ declare class EssConnect extends EventEmitter {
9
+ constructor(settings: any);
10
+ ws: WebSocket;
11
+ /**Set a monitoring function. Should return {status:'ok|warning|error', ...}
12
+ * @param {function} statusFunction
13
+ */
14
+ setMonitoringResponse(statusFunction: Function): void;
15
+ _statusFunction: Function | undefined;
16
+ log(...args: any[]): void;
17
+ handleSystemMessage(message: any, send: any): void;
18
+ parseMessage(message?: any[]): {};
19
+ }
20
+ import EventEmitter from "events";
21
+ import WebSocket = require("./client");