@5minds/node-red-contrib-processcube 1.5.5-feature-22f94f-m3eulbpf → 1.5.6-develop-51b402-m3iul3hf

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.
@@ -24,33 +24,38 @@ module.exports = function (RED) {
24
24
  async (processNotification) => {
25
25
  if (
26
26
  config.processmodel != '' &&
27
- config.processmodel != processNotification.processModelId
28
- )
27
+ config.processmodel != processNotification.processModelId) {
29
28
  return;
29
+ }
30
+
30
31
  const newQuery = {
31
32
  processInstanceId: processNotification.processInstanceId,
32
33
  ...query,
33
34
  };
34
35
 
35
- const matchingInstances = await client.processInstances.query(newQuery, {
36
- identity: currentIdentity,
37
- });
38
-
39
- if (
40
- matchingInstances.processInstances &&
41
- matchingInstances.processInstances.length == 1
42
- ) {
43
- const processInstance = matchingInstances.processInstances[0];
44
-
45
- node.send({
46
- payload: {
47
- processInstanceId: processNotification.processInstanceId,
48
- processModelId: processNotification.processModelId,
49
- processInstance: processInstance,
50
- action: 'starting',
51
- type: 'processInstance',
52
- },
36
+ try {
37
+ const matchingInstances = await client.processInstances.query(newQuery, {
38
+ identity: currentIdentity,
53
39
  });
40
+
41
+ if (
42
+ matchingInstances.processInstances &&
43
+ matchingInstances.processInstances.length == 1
44
+ ) {
45
+ const processInstance = matchingInstances.processInstances[0];
46
+
47
+ node.send({
48
+ payload: {
49
+ processInstanceId: processNotification.processInstanceId,
50
+ processModelId: processNotification.processModelId,
51
+ processInstance: processInstance,
52
+ action: 'starting',
53
+ type: 'processInstance',
54
+ },
55
+ });
56
+ }
57
+ } catch (error) {
58
+ node.error(error);
54
59
  }
55
60
  },
56
61
  { identity: currentIdentity }
@@ -60,34 +65,39 @@ module.exports = function (RED) {
60
65
  async (processNotification) => {
61
66
  if (
62
67
  config.processmodel != '' &&
63
- config.processmodel != processNotification.processModelId
64
- )
68
+ config.processmodel != processNotification.processModelId) {
65
69
  return;
70
+ }
71
+
66
72
  const newQuery = {
67
73
  processInstanceId: processNotification.processInstanceId,
68
74
  ...query,
69
75
  };
70
76
 
71
- const matchingInstances = await client.processInstances.query(newQuery, {
72
- identity: currentIdentity,
73
- });
74
-
75
- if (
76
- matchingInstances.processInstances &&
77
- matchingInstances.processInstances.length == 1
78
- ) {
79
- const processInstance = matchingInstances.processInstances[0];
80
- node.send({
81
- payload: {
82
- processInstanceId: processNotification.processInstanceId,
83
- processModelId: processNotification.processModelId,
84
- flowNodeId: processNotification.flowNodeId,
85
- token: processNotification.currentToken,
86
- processInstance: processInstance,
87
- action: 'started',
88
- type: 'processInstance',
89
- },
77
+ try {
78
+ const matchingInstances = await client.processInstances.query(newQuery, {
79
+ identity: currentIdentity,
90
80
  });
81
+
82
+ if (
83
+ matchingInstances.processInstances &&
84
+ matchingInstances.processInstances.length == 1
85
+ ) {
86
+ const processInstance = matchingInstances.processInstances[0];
87
+ node.send({
88
+ payload: {
89
+ processInstanceId: processNotification.processInstanceId,
90
+ processModelId: processNotification.processModelId,
91
+ flowNodeId: processNotification.flowNodeId,
92
+ token: processNotification.currentToken,
93
+ processInstance: processInstance,
94
+ action: 'started',
95
+ type: 'processInstance',
96
+ },
97
+ });
98
+ }
99
+ } catch (error) {
100
+ node.error(error);
91
101
  }
92
102
  },
93
103
  { identity: currentIdentity }
@@ -106,25 +116,29 @@ module.exports = function (RED) {
106
116
  ...query,
107
117
  };
108
118
 
109
- const matchingInstances = await client.processInstances.query(newQuery, {
110
- identity: currentIdentity,
111
- });
112
-
113
- if (
114
- matchingInstances.processInstances &&
115
- matchingInstances.processInstances.length == 1
116
- ) {
117
- const processInstance = matchingInstances.processInstances[0];
118
- node.send({
119
- payload: {
120
- processInstanceId: processNotification.processInstanceId,
121
- processModelId: processNotification.processModelId,
122
- token: processNotification.currentToken,
123
- processInstance: processInstance,
124
- action: 'resumed',
125
- type: 'processInstance',
126
- },
119
+ try {
120
+ const matchingInstances = await client.processInstances.query(newQuery, {
121
+ identity: currentIdentity,
127
122
  });
123
+
124
+ if (
125
+ matchingInstances.processInstances &&
126
+ matchingInstances.processInstances.length == 1
127
+ ) {
128
+ const processInstance = matchingInstances.processInstances[0];
129
+ node.send({
130
+ payload: {
131
+ processInstanceId: processNotification.processInstanceId,
132
+ processModelId: processNotification.processModelId,
133
+ token: processNotification.currentToken,
134
+ processInstance: processInstance,
135
+ action: 'resumed',
136
+ type: 'processInstance',
137
+ },
138
+ });
139
+ }
140
+ } catch (error) {
141
+ node.error(error);
128
142
  }
129
143
  },
130
144
  { identity: currentIdentity }
@@ -143,26 +157,30 @@ module.exports = function (RED) {
143
157
  ...query,
144
158
  };
145
159
 
146
- const matchingInstances = await client.processInstances.query(newQuery, {
147
- identity: currentIdentity,
148
- });
149
-
150
- if (
151
- matchingInstances.processInstances &&
152
- matchingInstances.processInstances.length == 1
153
- ) {
154
- const processInstance = matchingInstances.processInstances[0];
155
- node.send({
156
- payload: {
157
- processInstanceId: processNotification.processInstanceId,
158
- processModelId: processNotification.processModelId,
159
- flowNodeId: processNotification.flowNodeId,
160
- token: processNotification.currentToken,
161
- processInstance: processInstance,
162
- action: 'finished',
163
- type: 'processInstance',
164
- },
160
+ try {
161
+ const matchingInstances = await client.processInstances.query(newQuery, {
162
+ identity: currentIdentity,
165
163
  });
164
+
165
+ if (
166
+ matchingInstances.processInstances &&
167
+ matchingInstances.processInstances.length == 1
168
+ ) {
169
+ const processInstance = matchingInstances.processInstances[0];
170
+ node.send({
171
+ payload: {
172
+ processInstanceId: processNotification.processInstanceId,
173
+ processModelId: processNotification.processModelId,
174
+ flowNodeId: processNotification.flowNodeId,
175
+ token: processNotification.currentToken,
176
+ processInstance: processInstance,
177
+ action: 'finished',
178
+ type: 'processInstance',
179
+ },
180
+ });
181
+ }
182
+ } catch (error) {
183
+ node.error(error);
166
184
  }
167
185
  },
168
186
  { identity: currentIdentity }
@@ -181,25 +199,28 @@ module.exports = function (RED) {
181
199
  ...query,
182
200
  };
183
201
 
184
- const matchingInstances = await client.processInstances.query(newQuery, {
185
- identity: currentIdentity,
186
- });
187
-
188
- if (
189
- matchingInstances.processInstances &&
190
- matchingInstances.processInstances.length == 1
191
- ) {
192
- const processInstance = matchingInstances.processInstances[0];
193
- node.send({
194
- payload: {
195
- processInstanceId: processNotification.processInstanceId,
196
- processModelId: processNotification.processModelId,
197
- token: processNotification.currentToken,
198
- processInstance: processInstance,
199
- action: 'terminated',
200
- type: 'processInstance',
201
- },
202
+ try {
203
+ const matchingInstances = await client.processInstances.query(newQuery, {
204
+ identity: currentIdentity,
202
205
  });
206
+ if (
207
+ matchingInstances.processInstances &&
208
+ matchingInstances.processInstances.length == 1
209
+ ) {
210
+ const processInstance = matchingInstances.processInstances[0];
211
+ node.send({
212
+ payload: {
213
+ processInstanceId: processNotification.processInstanceId,
214
+ processModelId: processNotification.processModelId,
215
+ token: processNotification.currentToken,
216
+ processInstance: processInstance,
217
+ action: 'terminated',
218
+ type: 'processInstance',
219
+ },
220
+ });
221
+ }
222
+ } catch (error) {
223
+ node.error(error);
203
224
  }
204
225
  },
205
226
  { identity: currentIdentity }
@@ -218,25 +239,29 @@ module.exports = function (RED) {
218
239
  ...query,
219
240
  };
220
241
 
221
- const matchingInstances = await client.processInstances.query(newQuery, {
222
- identity: currentIdentity,
223
- });
224
-
225
- if (
226
- matchingInstances.processInstances &&
227
- matchingInstances.processInstances.length == 1
228
- ) {
229
- const processInstance = matchingInstances.processInstances[0];
230
- node.send({
231
- payload: {
232
- processInstanceId: processNotification.processInstanceId,
233
- processModelId: processNotification.processModelId,
234
- token: processNotification.currentToken,
235
- processInstance: processInstance,
236
- action: 'error',
237
- type: 'processInstance',
238
- },
242
+ try {
243
+ const matchingInstances = await client.processInstances.query(newQuery, {
244
+ identity: currentIdentity,
239
245
  });
246
+
247
+ if (
248
+ matchingInstances.processInstances &&
249
+ matchingInstances.processInstances.length == 1
250
+ ) {
251
+ const processInstance = matchingInstances.processInstances[0];
252
+ node.send({
253
+ payload: {
254
+ processInstanceId: processNotification.processInstanceId,
255
+ processModelId: processNotification.processModelId,
256
+ token: processNotification.currentToken,
257
+ processInstance: processInstance,
258
+ action: 'error',
259
+ type: 'processInstance',
260
+ },
261
+ });
262
+ }
263
+ } catch (error) {
264
+ node.error(error);
240
265
  }
241
266
  },
242
267
  { identity: currentIdentity }
@@ -255,24 +280,28 @@ module.exports = function (RED) {
255
280
  ...query,
256
281
  };
257
282
 
258
- const matchingInstances = await client.processInstances.query(newQuery, {
259
- identity: currentIdentity,
260
- });
261
-
262
- if (
263
- matchingInstances.processInstances &&
264
- matchingInstances.processInstances.length == 1
265
- ) {
266
- const processInstance = matchingInstances.processInstances[0];
267
- node.send({
268
- payload: {
269
- processInstanceId: processNotification.processInstanceId,
270
- processModelId: processNotification.processModelId,
271
- processInstance: processInstance,
272
- action: 'owner-changed',
273
- type: 'processInstance',
274
- },
283
+ try {
284
+ const matchingInstances = await client.processInstances.query(newQuery, {
285
+ identity: currentIdentity,
275
286
  });
287
+
288
+ if (
289
+ matchingInstances.processInstances &&
290
+ matchingInstances.processInstances.length == 1
291
+ ) {
292
+ const processInstance = matchingInstances.processInstances[0];
293
+ node.send({
294
+ payload: {
295
+ processInstanceId: processNotification.processInstanceId,
296
+ processModelId: processNotification.processModelId,
297
+ processInstance: processInstance,
298
+ action: 'owner-changed',
299
+ type: 'processInstance',
300
+ },
301
+ });
302
+ }
303
+ } catch (error) {
304
+ node.error(error);
276
305
  }
277
306
  },
278
307
  { identity: currentIdentity }
@@ -291,24 +320,28 @@ module.exports = function (RED) {
291
320
  ...query,
292
321
  };
293
322
 
294
- const matchingInstances = await client.processInstances.query(newQuery, {
295
- identity: currentIdentity,
296
- });
297
-
298
- if (
299
- matchingInstances.processInstances &&
300
- matchingInstances.processInstances.length == 1
301
- ) {
302
- const processInstance = matchingInstances.processInstances[0];
303
- node.send({
304
- payload: {
305
- processInstanceId: processNotification.processInstanceId,
306
- processModelId: processNotification.processModelId,
307
- processInstance: processInstance,
308
- action: 'instances-deleted',
309
- type: 'processInstance',
310
- },
323
+ try {
324
+ const matchingInstances = await client.processInstances.query(newQuery, {
325
+ identity: currentIdentity,
311
326
  });
327
+
328
+ if (
329
+ matchingInstances.processInstances &&
330
+ matchingInstances.processInstances.length == 1
331
+ ) {
332
+ const processInstance = matchingInstances.processInstances[0];
333
+ node.send({
334
+ payload: {
335
+ processInstanceId: processNotification.processInstanceId,
336
+ processModelId: processNotification.processModelId,
337
+ processInstance: processInstance,
338
+ action: 'instances-deleted',
339
+ type: 'processInstance',
340
+ },
341
+ });
342
+ }
343
+ } catch (error) {
344
+ node.error(error);
312
345
  }
313
346
  },
314
347
  { identity: currentIdentity }
@@ -400,6 +433,7 @@ module.exports = function (RED) {
400
433
  },
401
434
  { identity: currentIdentity }
402
435
  );
436
+
403
437
  });
404
438
 
405
439
  node.on('close', () => {
@@ -29,10 +29,9 @@
29
29
  <script type="text/markdown" data-help-name="process-terminate">
30
30
  Terminate an instance of a process model in the ProcessCube.
31
31
 
32
- ## Configs
32
+ ## Inputs
33
33
 
34
- : name (string): name of the node
35
- : engine (string): the engine to connect to
34
+ : payload (string): The id of the processinstance that is going to be terminated.
36
35
 
37
36
  ## Outputs
38
37
 
@@ -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.on('close', async () => {
40
- if (this.engineClient) {
41
- this.engineClient.dispose();
42
- this.engineClient = null;
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
- if (this.credentials.clientId && this.credentials.clientSecret) {
47
- this.engineClient = new engine_client.EngineClient(this.url);
48
-
49
- this.engineClient.applicationInfo
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 getFreshTokenSet(clientId, clientSecret, authorityUrl) {
79
- const issuer = await oidc.Issuer.discover(authorityUrl);
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
- const client = new issuer.Client({
82
- client_id: clientId,
83
- client_secret: clientSecret,
84
- });
87
+ const body = await res.json();
85
88
 
86
- const tokenSet = await client.grant({
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
- return tokenSet;
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
- function getIdentityForExternalTaskWorkers(tokenSet) {
95
- const accessToken = tokenSet.access_token;
96
- const decodedToken = jwt.jwtDecode(accessToken);
96
+ const tokenSet = await client.grant({
97
+ grant_type: 'client_credentials',
98
+ scope: 'engine_etw engine_read engine_write',
99
+ });
97
100
 
98
- return {
99
- token: tokenSet.access_token,
100
- userId: decodedToken.sub,
101
- };
102
- }
101
+ const accessToken = tokenSet.access_token;
102
+ const decodedToken = jwt.jwtDecode(accessToken);
103
103
 
104
- async function getExpiresInForExternalTaskWorkers(tokenSet) {
105
- let expiresIn = tokenSet.expires_in;
104
+ const freshIdentity = {
105
+ token: tokenSet.access_token,
106
+ userId: decodedToken.sub,
107
+ };
106
108
 
107
- if (!expiresIn && tokenSet.expires_at) {
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
- return expiresIn;
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
- await refresh();
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
+ };