node-red-contrib-mobius-flow-base 3.4.0-beta.2 → 3.5.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.
|
@@ -41,13 +41,7 @@ jobs:
|
|
|
41
41
|
run: |
|
|
42
42
|
npm install -g yarn
|
|
43
43
|
yarn install
|
|
44
|
-
|
|
45
|
-
cp src/nodes/*.js dist/nodes/
|
|
46
|
-
cp src/nodes/*.html dist/nodes/
|
|
47
|
-
cp -r src/nodes/icons dist/nodes/
|
|
48
|
-
mkdir -p dist/nodes/common
|
|
49
|
-
cp src/mobsearch.js dist/nodes/common/
|
|
50
|
-
cp src/node-red-ui-funcs.js dist/
|
|
44
|
+
yarn build
|
|
51
45
|
env:
|
|
52
46
|
GH_PKG_READ_TOKEN: ${{ secrets.GH_PKG_READ_TOKEN }}
|
|
53
47
|
|
|
@@ -80,6 +80,11 @@ class EngineApiClient extends engine_api_calls_1.EngineApiCalls {
|
|
|
80
80
|
this.tokens = response.data;
|
|
81
81
|
this.loggedIn = true;
|
|
82
82
|
console.log(`(${this.hostname}) -> Logged in to Mobius Engine API`);
|
|
83
|
+
// Clear any previous refresh loop so repeated logins don't stack intervals
|
|
84
|
+
if (this.refreshLoop) {
|
|
85
|
+
clearInterval(this.refreshLoop);
|
|
86
|
+
this.refreshLoop = null;
|
|
87
|
+
}
|
|
83
88
|
this.refreshLoop = setInterval(this.refresh, 1000 * 60 * 5);
|
|
84
89
|
this.EngineWebSocket.connectToWebSocket(this.tokens.token);
|
|
85
90
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
1
2
|
import { EventEmitter } from "stream";
|
|
2
3
|
type WebSocketTopics = "authorize" | "subscribe" | "unsubscribe" | "connected" | "authorized" | "object-cov" | "resource-cov" | "service-status" | "broadcast-command" | "error" | "ping" | "pong";
|
|
3
4
|
interface EngineWebSocketInterface {
|
|
@@ -27,6 +28,8 @@ export declare class EngineWebSocket extends EventEmitter implements EngineWebSo
|
|
|
27
28
|
constructor(hostname: string, protocol: "http" | "https");
|
|
28
29
|
connectToWebSocket: (token: string) => void;
|
|
29
30
|
private sendWebSocketMessage;
|
|
31
|
+
private clearTimers;
|
|
32
|
+
private teardownSocket;
|
|
30
33
|
private sendPingMessage;
|
|
31
34
|
registerCallback: (topic: WebSocketTopics, callback: Function) => void;
|
|
32
35
|
clearAllCallbacks: () => void;
|
package/dist/engine-websocket.js
CHANGED
|
@@ -6,8 +6,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.EngineWebSocket = void 0;
|
|
7
7
|
const stream_1 = require("stream");
|
|
8
8
|
const ws_1 = __importDefault(require("ws"));
|
|
9
|
+
const maxPendingWebSocketMessages = 1000;
|
|
9
10
|
class EngineWebSocket extends stream_1.EventEmitter {
|
|
10
|
-
webSocket;
|
|
11
|
+
webSocket = null;
|
|
11
12
|
pendingWebSocketMessages = [];
|
|
12
13
|
pendingWebSocketMessageInterval = null;
|
|
13
14
|
pingInterval = null;
|
|
@@ -24,16 +25,23 @@ class EngineWebSocket extends stream_1.EventEmitter {
|
|
|
24
25
|
}
|
|
25
26
|
connectToWebSocket = (token) => {
|
|
26
27
|
this.authToken = token;
|
|
28
|
+
// Tear down any previous socket and timers so repeated logins/reconnects
|
|
29
|
+
// cannot accumulate sockets, ping intervals or reconnect intervals
|
|
30
|
+
this.teardownSocket();
|
|
27
31
|
let webSocketProtocol = "wss";
|
|
28
32
|
if (this.protocol === "http") {
|
|
29
33
|
webSocketProtocol = "ws";
|
|
30
34
|
}
|
|
31
|
-
|
|
32
|
-
this.webSocket
|
|
35
|
+
const ws = new ws_1.default(`${webSocketProtocol}://${this.hostname}/api/engine/v1/mobius/subscribe/connect`);
|
|
36
|
+
this.webSocket = ws;
|
|
37
|
+
ws.onopen = () => {
|
|
38
|
+
if (this.webSocket !== ws) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
33
41
|
this.attemptReconnect = true;
|
|
34
42
|
console.log(`(${this.hostname}) -> Engine API Subscription WebSocket Client Connected`);
|
|
43
|
+
this.clearTimers();
|
|
35
44
|
this.pingInterval = setInterval(this.sendPingMessage, 30000);
|
|
36
|
-
clearInterval(this.reconnectInterval);
|
|
37
45
|
this.sendWebSocketMessage({
|
|
38
46
|
topic: "authorize",
|
|
39
47
|
payload: `Bearer ${this.authToken}`,
|
|
@@ -45,16 +53,14 @@ class EngineWebSocket extends stream_1.EventEmitter {
|
|
|
45
53
|
}
|
|
46
54
|
}, 1000);
|
|
47
55
|
};
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
56
|
+
ws.onclose = () => {
|
|
57
|
+
if (this.webSocket !== ws) {
|
|
58
|
+
// A newer socket has replaced this one; don't touch current state
|
|
59
|
+
return;
|
|
52
60
|
}
|
|
61
|
+
console.log(`(${this.hostname}) -> Engine API Subscription WebSocket Client Closed`);
|
|
53
62
|
this.webSocket = null;
|
|
54
|
-
|
|
55
|
-
if (this.pendingWebSocketMessageInterval) {
|
|
56
|
-
clearInterval(this.pendingWebSocketMessageInterval);
|
|
57
|
-
}
|
|
63
|
+
this.clearTimers();
|
|
58
64
|
if (this.attemptReconnect) {
|
|
59
65
|
this.reconnectInterval = setInterval(() => {
|
|
60
66
|
this.reconnect();
|
|
@@ -62,7 +68,10 @@ class EngineWebSocket extends stream_1.EventEmitter {
|
|
|
62
68
|
}
|
|
63
69
|
this.emit("disconnected");
|
|
64
70
|
};
|
|
65
|
-
|
|
71
|
+
ws.onmessage = (message) => {
|
|
72
|
+
if (this.webSocket !== ws) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
66
75
|
try {
|
|
67
76
|
if (message.data) {
|
|
68
77
|
const parsedMessage = JSON.parse(message.data);
|
|
@@ -73,7 +82,7 @@ class EngineWebSocket extends stream_1.EventEmitter {
|
|
|
73
82
|
console.log(`(${this.hostname}) -> Error parsing message: ${e.code}, ${e.message ? e.message : ""}`);
|
|
74
83
|
}
|
|
75
84
|
};
|
|
76
|
-
|
|
85
|
+
ws.on("error", (e) => {
|
|
77
86
|
if (e.code === "ECONNREFUSED") {
|
|
78
87
|
this.emit("disconnected");
|
|
79
88
|
}
|
|
@@ -93,6 +102,42 @@ class EngineWebSocket extends stream_1.EventEmitter {
|
|
|
93
102
|
}
|
|
94
103
|
else {
|
|
95
104
|
this.pendingWebSocketMessages.push(message);
|
|
105
|
+
if (this.pendingWebSocketMessages.length > maxPendingWebSocketMessages) {
|
|
106
|
+
this.pendingWebSocketMessages.shift();
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
clearTimers = () => {
|
|
111
|
+
if (this.pingInterval) {
|
|
112
|
+
clearInterval(this.pingInterval);
|
|
113
|
+
this.pingInterval = null;
|
|
114
|
+
}
|
|
115
|
+
if (this.pendingWebSocketMessageInterval) {
|
|
116
|
+
clearInterval(this.pendingWebSocketMessageInterval);
|
|
117
|
+
this.pendingWebSocketMessageInterval = null;
|
|
118
|
+
}
|
|
119
|
+
if (this.reconnectInterval) {
|
|
120
|
+
clearInterval(this.reconnectInterval);
|
|
121
|
+
this.reconnectInterval = null;
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
teardownSocket = () => {
|
|
125
|
+
this.clearTimers();
|
|
126
|
+
const oldSocket = this.webSocket;
|
|
127
|
+
this.webSocket = null;
|
|
128
|
+
if (oldSocket) {
|
|
129
|
+
oldSocket.onopen = null;
|
|
130
|
+
oldSocket.onclose = null;
|
|
131
|
+
oldSocket.onmessage = null;
|
|
132
|
+
oldSocket.removeAllListeners();
|
|
133
|
+
// Swallow errors from the discarded socket so they can't crash the process
|
|
134
|
+
oldSocket.on("error", () => { });
|
|
135
|
+
try {
|
|
136
|
+
oldSocket.terminate();
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
// socket already closed
|
|
140
|
+
}
|
|
96
141
|
}
|
|
97
142
|
};
|
|
98
143
|
sendPingMessage = () => {
|
|
@@ -136,14 +181,10 @@ class EngineWebSocket extends stream_1.EventEmitter {
|
|
|
136
181
|
};
|
|
137
182
|
killWebSocket = () => {
|
|
138
183
|
this.attemptReconnect = false;
|
|
139
|
-
if (this.reconnectInterval) {
|
|
140
|
-
clearInterval(this.reconnectInterval);
|
|
141
|
-
}
|
|
142
184
|
this.registeredCallbacks = [];
|
|
143
185
|
this.pendingWebSocketMessages = [];
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
186
|
+
this.teardownSocket();
|
|
187
|
+
this.emit("disconnected");
|
|
147
188
|
console.log(`(${this.hostname}) -> Killing Engine API Subscription WebSocket Client`);
|
|
148
189
|
};
|
|
149
190
|
disconnectFromWebSocket = () => {
|
|
@@ -30,7 +30,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|
|
30
30
|
<input class="input-append-left" type="text" id="node-config-input-host" placeholder="e.g. localhost" style="width: 70%;" >
|
|
31
31
|
</div>
|
|
32
32
|
<p style="text-align:center"> Ensure port number is included in host path if required</p>
|
|
33
|
-
<p style="text-align:center"> e.g. <b>myHostname:
|
|
33
|
+
<p style="text-align:center"> e.g. <b>myHostname:8442</b></p>
|
|
34
34
|
<hr>
|
|
35
35
|
<div class="form-row">
|
|
36
36
|
<label for="node-config-input-username"><i class="fa fa-user"></i> Username</label>
|
|
@@ -49,25 +49,25 @@ POSSIBILITY OF SUCH DAMAGE.
|
|
|
49
49
|
</script>
|
|
50
50
|
|
|
51
51
|
<script type="text/javascript">
|
|
52
|
-
hostLabel =
|
|
53
|
-
RED.nodes.registerType(
|
|
54
|
-
category:
|
|
52
|
+
hostLabel = "test";
|
|
53
|
+
RED.nodes.registerType("mobius connection", {
|
|
54
|
+
category: "config",
|
|
55
55
|
defaults: {
|
|
56
|
-
host: { required: true, value:
|
|
57
|
-
username: { required: true, value:
|
|
58
|
-
password: { required: true, value:
|
|
56
|
+
host: { required: true, value: "mobius:8442" },
|
|
57
|
+
username: { required: true, value: "" },
|
|
58
|
+
password: { required: true, value: "" },
|
|
59
59
|
secure: { required: true, value: false },
|
|
60
60
|
},
|
|
61
61
|
label: function () {
|
|
62
62
|
return `${this.host}`;
|
|
63
63
|
},
|
|
64
64
|
oneditprepare: function () {
|
|
65
|
-
$(
|
|
66
|
-
let secure = $(
|
|
65
|
+
$("#node-config-input-secure").change(function () {
|
|
66
|
+
let secure = $("#node-config-input-secure").is(":checked");
|
|
67
67
|
if (secure) {
|
|
68
|
-
document.getElementById(
|
|
68
|
+
document.getElementById("hostLabel").innerHTML = "https://";
|
|
69
69
|
} else {
|
|
70
|
-
document.getElementById(
|
|
70
|
+
document.getElementById("hostLabel").innerHTML = "http://";
|
|
71
71
|
}
|
|
72
72
|
});
|
|
73
73
|
},
|