@5minds/node-red-contrib-processcube 1.5.5-develop-21476e-m3hs5zs1 → 1.5.5-develop-a8e9c4-m3iqz7yx
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/package.json +2 -2
- package/processcube-engine-config.js +81 -108
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@5minds/node-red-contrib-processcube",
|
3
|
-
"version": "1.5.5-develop-
|
3
|
+
"version": "1.5.5-develop-a8e9c4-m3iqz7yx",
|
4
4
|
"license": "MIT",
|
5
5
|
"description": "Node-RED nodes for ProcessCube",
|
6
6
|
"scripts": {
|
@@ -57,7 +57,7 @@
|
|
57
57
|
"examples": "examples"
|
58
58
|
},
|
59
59
|
"dependencies": {
|
60
|
-
"@5minds/processcube_engine_client": "
|
60
|
+
"@5minds/processcube_engine_client": "5.1.0-hotfix-a73235-m346kg1n",
|
61
61
|
"jwt-decode": "^4.0.0",
|
62
62
|
"openid-client": "^5.5.0"
|
63
63
|
},
|
@@ -2,19 +2,20 @@ const engine_client = require('@5minds/processcube_engine_client');
|
|
2
2
|
const jwt = require('jwt-decode');
|
3
3
|
const oidc = require('openid-client');
|
4
4
|
|
5
|
-
const DELAY_FACTOR = 0.85;
|
6
|
-
|
7
5
|
module.exports = function (RED) {
|
8
6
|
function ProcessCubeEngineNode(n) {
|
9
7
|
RED.nodes.createNode(this, n);
|
10
8
|
const node = this;
|
11
9
|
const identityChangedCallbacks = [];
|
12
|
-
this.url = RED.util.evaluateNodeProperty(n.url, n.urlType, node);
|
13
10
|
this.identity = null;
|
14
11
|
|
15
12
|
this.credentials.clientId = RED.util.evaluateNodeProperty(n.clientId, n.clientIdType, node);
|
16
13
|
this.credentials.clientSecret = RED.util.evaluateNodeProperty(n.clientSecret, n.clientSecretType, node);
|
17
14
|
|
15
|
+
// known issue: kann bei falschem timing zu laufzeitfehlern führen (absprache MM)
|
16
|
+
// set the engine url
|
17
|
+
const stopRefreshing = periodicallyRefreshEngineClient(this, n, 10000);
|
18
|
+
|
18
19
|
this.registerOnIdentityChanged = function (callback) {
|
19
20
|
identityChangedCallbacks.push(callback);
|
20
21
|
};
|
@@ -36,123 +37,95 @@ module.exports = function (RED) {
|
|
36
37
|
}
|
37
38
|
};
|
38
39
|
|
39
|
-
node
|
40
|
-
|
41
|
-
|
42
|
-
|
40
|
+
function periodicallyRefreshEngineClient(node, n, intervalMs) {
|
41
|
+
function refreshUrl() {
|
42
|
+
const newUrl = RED.util.evaluateNodeProperty(n.url, n.urlType, node);
|
43
|
+
|
44
|
+
if (node.url == newUrl) {
|
45
|
+
return;
|
46
|
+
}
|
47
|
+
|
48
|
+
node.url = newUrl;
|
49
|
+
if (node.credentials.clientId && node.credentials.clientSecret) {
|
50
|
+
if (this.engineClient) {
|
51
|
+
this.engineClient.dispose();
|
52
|
+
}
|
53
|
+
node.engineClient = new engine_client.EngineClient(node.url, () =>
|
54
|
+
getFreshIdentity(node.url, node)
|
55
|
+
);
|
56
|
+
} else {
|
57
|
+
if (this.engineClient) {
|
58
|
+
this.engineClient.dispose();
|
59
|
+
}
|
60
|
+
node.engineClient = new engine_client.EngineClient(node.url);
|
61
|
+
}
|
43
62
|
}
|
44
|
-
});
|
45
63
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
.getAuthorityAddress()
|
51
|
-
.then((authorityUrl) => {
|
52
|
-
startRefreshingIdentityCycle(
|
53
|
-
this.credentials.clientId,
|
54
|
-
this.credentials.clientSecret,
|
55
|
-
authorityUrl,
|
56
|
-
node
|
57
|
-
).catch((reason) => {
|
58
|
-
console.error(reason);
|
59
|
-
node.error(reason);
|
60
|
-
});
|
61
|
-
})
|
62
|
-
.catch((reason) => {
|
63
|
-
console.error(reason);
|
64
|
-
node.error(reason);
|
65
|
-
});
|
66
|
-
} else {
|
67
|
-
this.engineClient = new engine_client.EngineClient(this.url);
|
64
|
+
refreshUrl();
|
65
|
+
const intervalId = setInterval(refreshUrl, intervalMs);
|
66
|
+
|
67
|
+
return () => clearInterval(intervalId);
|
68
68
|
}
|
69
|
-
}
|
70
|
-
RED.nodes.registerType('processcube-engine-config', ProcessCubeEngineNode, {
|
71
|
-
credentials: {
|
72
|
-
clientId: { type: 'text' },
|
73
|
-
clientSecret: { type: 'password' },
|
74
|
-
},
|
75
|
-
});
|
76
|
-
};
|
77
69
|
|
78
|
-
async function
|
79
|
-
|
70
|
+
async function getFreshIdentity(url, node) {
|
71
|
+
try {
|
72
|
+
if (
|
73
|
+
!RED.util.evaluateNodeProperty(n.clientId, n.clientIdType, node) ||
|
74
|
+
!RED.util.evaluateNodeProperty(n.clientSecret, n.clientSecretType, node)
|
75
|
+
) {
|
76
|
+
return null;
|
77
|
+
}
|
78
|
+
|
79
|
+
const res = await fetch(url + '/atlas_engine/api/v1/authority', {
|
80
|
+
method: 'GET',
|
81
|
+
headers: {
|
82
|
+
Authorization: `Bearer ZHVtbXlfdG9rZW4=`,
|
83
|
+
'Content-Type': 'application/json',
|
84
|
+
},
|
85
|
+
});
|
80
86
|
|
81
|
-
|
82
|
-
client_id: clientId,
|
83
|
-
client_secret: clientSecret,
|
84
|
-
});
|
87
|
+
const body = await res.json();
|
85
88
|
|
86
|
-
|
87
|
-
grant_type: 'client_credentials',
|
88
|
-
scope: 'engine_etw engine_read engine_write',
|
89
|
-
});
|
89
|
+
const issuer = await oidc.Issuer.discover(body);
|
90
90
|
|
91
|
-
|
92
|
-
|
91
|
+
const client = new issuer.Client({
|
92
|
+
client_id: RED.util.evaluateNodeProperty(n.clientId, n.clientIdType, node),
|
93
|
+
client_secret: RED.util.evaluateNodeProperty(n.clientSecret, n.clientSecretType, node),
|
94
|
+
});
|
93
95
|
|
94
|
-
|
95
|
-
|
96
|
-
|
96
|
+
const tokenSet = await client.grant({
|
97
|
+
grant_type: 'client_credentials',
|
98
|
+
scope: 'engine_etw engine_read engine_write',
|
99
|
+
});
|
97
100
|
|
98
|
-
|
99
|
-
|
100
|
-
userId: decodedToken.sub,
|
101
|
-
};
|
102
|
-
}
|
101
|
+
const accessToken = tokenSet.access_token;
|
102
|
+
const decodedToken = jwt.jwtDecode(accessToken);
|
103
103
|
|
104
|
-
|
105
|
-
|
104
|
+
const freshIdentity = {
|
105
|
+
token: tokenSet.access_token,
|
106
|
+
userId: decodedToken.sub,
|
107
|
+
};
|
106
108
|
|
107
|
-
|
108
|
-
expiresIn = Math.floor(tokenSet.expires_at - Date.now() / 1000);
|
109
|
-
}
|
110
|
-
|
111
|
-
if (expiresIn === undefined) {
|
112
|
-
throw new Error('Could not determine the time until the access token for external task workers expires');
|
113
|
-
}
|
109
|
+
node.setIdentity(freshIdentity);
|
114
110
|
|
115
|
-
|
116
|
-
}
|
117
|
-
|
118
|
-
/**
|
119
|
-
* Start refreshing the identity in regular intervals.
|
120
|
-
* @param {TokenSet | null} tokenSet The token set to refresh the identity for
|
121
|
-
* @returns {Promise<void>} A promise that resolves when the timer for refreshing the identity is initialized
|
122
|
-
* */
|
123
|
-
async function startRefreshingIdentityCycle(clientId, clientSecret, authorityUrl, configNode) {
|
124
|
-
let retries = 5;
|
125
|
-
|
126
|
-
const refresh = async () => {
|
127
|
-
try {
|
128
|
-
const newTokenSet = await getFreshTokenSet(clientId, clientSecret, authorityUrl);
|
129
|
-
const expiresIn = await getExpiresInForExternalTaskWorkers(newTokenSet);
|
130
|
-
const delay = expiresIn * DELAY_FACTOR * 1000;
|
131
|
-
|
132
|
-
freshIdentity = getIdentityForExternalTaskWorkers(newTokenSet);
|
133
|
-
|
134
|
-
configNode.setIdentity(freshIdentity);
|
135
|
-
|
136
|
-
retries = 5;
|
137
|
-
setTimeout(refresh, delay);
|
138
|
-
} catch (error) {
|
139
|
-
if (retries === 0) {
|
140
|
-
console.error(
|
141
|
-
'Could not refresh identity for external task worker processes. Stopping all external task workers.',
|
142
|
-
{ error }
|
143
|
-
);
|
144
|
-
return;
|
111
|
+
return freshIdentity;
|
112
|
+
} catch (e) {
|
113
|
+
node.error(`Could not get fresh identity: ${e}`);
|
145
114
|
}
|
146
|
-
console.error('Could not refresh identity for external task worker processes.', {
|
147
|
-
error,
|
148
|
-
retryCount: retries,
|
149
|
-
});
|
150
|
-
retries--;
|
151
|
-
|
152
|
-
const delay = 2 * 1000;
|
153
|
-
setTimeout(refresh, delay);
|
154
115
|
}
|
155
|
-
};
|
156
116
|
|
157
|
-
|
158
|
-
|
117
|
+
node.on('close', async () => {
|
118
|
+
if (this.engineClient) {
|
119
|
+
stopRefreshing();
|
120
|
+
this.engineClient.dispose();
|
121
|
+
this.engineClient = null;
|
122
|
+
}
|
123
|
+
});
|
124
|
+
}
|
125
|
+
RED.nodes.registerType('processcube-engine-config', ProcessCubeEngineNode, {
|
126
|
+
credentials: {
|
127
|
+
clientId: { type: 'text' },
|
128
|
+
clientSecret: { type: 'password' },
|
129
|
+
},
|
130
|
+
});
|
131
|
+
};
|