@5minds/node-red-contrib-processcube 1.5.5 → 1.5.6-feature-60b2c2-m3pneelx
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/endevent-finished-listener.js +12 -6
- package/externaltask-event-listener.js +7 -0
- package/externaltask-input.js +118 -101
- package/package.json +2 -2
- package/process-event-listener.js +11 -3
- package/processcube-engine-config.js +87 -108
- package/usertask-event-listener.js +9 -2
- package/wait-for-usertask.js +38 -35
@@ -4,6 +4,13 @@ module.exports = function (RED) {
|
|
4
4
|
var node = this;
|
5
5
|
node.engine = RED.nodes.getNode(config.engine);
|
6
6
|
|
7
|
+
const eventEmitter = node.engine.eventEmitter;
|
8
|
+
|
9
|
+
eventEmitter.on('engine-client-changed', () => {
|
10
|
+
console.log('new engineClient received');
|
11
|
+
register();
|
12
|
+
});
|
13
|
+
|
7
14
|
const register = async () => {
|
8
15
|
const client = node.engine.engineClient;
|
9
16
|
|
@@ -11,7 +18,7 @@ module.exports = function (RED) {
|
|
11
18
|
node.error('No engine configured.');
|
12
19
|
return;
|
13
20
|
}
|
14
|
-
|
21
|
+
|
15
22
|
let currentIdentity = node.engine.identity;
|
16
23
|
|
17
24
|
let subscription = null;
|
@@ -23,24 +30,23 @@ module.exports = function (RED) {
|
|
23
30
|
payload: endEventFinished,
|
24
31
|
});
|
25
32
|
},
|
26
|
-
{ identity: currentIdentity }
|
33
|
+
{ identity: currentIdentity }
|
27
34
|
);
|
28
35
|
|
29
36
|
node.engine.registerOnIdentityChanged(async (identity) => {
|
30
37
|
client.events.removeSubscription(subscription, currentIdentity);
|
31
|
-
|
38
|
+
|
32
39
|
currentIdentity = identity;
|
33
40
|
|
34
41
|
subscription = await client.events.onEndEventFinished(
|
35
42
|
(endEventFinished) => {
|
36
43
|
node.send({
|
37
|
-
payload: endEventFinished
|
44
|
+
payload: endEventFinished,
|
38
45
|
});
|
39
46
|
},
|
40
|
-
{ identity: currentIdentity }
|
47
|
+
{ identity: currentIdentity }
|
41
48
|
);
|
42
49
|
});
|
43
|
-
|
44
50
|
} catch (error) {
|
45
51
|
node.error(error);
|
46
52
|
}
|
@@ -4,6 +4,13 @@ module.exports = function (RED) {
|
|
4
4
|
var node = this;
|
5
5
|
node.engine = RED.nodes.getNode(config.engine);
|
6
6
|
|
7
|
+
const eventEmitter = node.engine.eventEmitter;
|
8
|
+
|
9
|
+
eventEmitter.on('engine-client-changed', () => {
|
10
|
+
console.log('new engineClient received');
|
11
|
+
register();
|
12
|
+
});
|
13
|
+
|
7
14
|
const register = async () => {
|
8
15
|
let currentIdentity = node.engine.identity;
|
9
16
|
|
package/externaltask-input.js
CHANGED
@@ -32,132 +32,149 @@ module.exports = function (RED) {
|
|
32
32
|
eventEmitter = flowContext.get('emitter');
|
33
33
|
}
|
34
34
|
|
35
|
-
const
|
36
|
-
const saveHandleCallback = (data, callback) => {
|
37
|
-
try {
|
38
|
-
callback(data);
|
39
|
-
} catch (error) {
|
40
|
-
node.error(`Error in callback 'saveHandleCallback': ${error.message}`);
|
41
|
-
}
|
42
|
-
};
|
43
|
-
|
44
|
-
return await new Promise((resolve, reject) => {
|
45
|
-
const handleFinishTask = (msg) => {
|
46
|
-
let result = RED.util.encodeObject(msg.payload);
|
35
|
+
const engineEventEmitter = node.engine.eventEmitter;
|
47
36
|
|
48
|
-
|
49
|
-
|
50
|
-
|
37
|
+
engineEventEmitter.on('engine-client-changed', () => {
|
38
|
+
console.log('new engineClient received');
|
39
|
+
register();
|
40
|
+
});
|
51
41
|
|
52
|
-
|
53
|
-
|
42
|
+
const register = async () => {
|
43
|
+
const etwCallback = async (payload, externalTask) => {
|
44
|
+
const saveHandleCallback = (data, callback) => {
|
45
|
+
try {
|
46
|
+
callback(data);
|
47
|
+
} catch (error) {
|
48
|
+
node.error(`Error in callback 'saveHandleCallback': ${error.message}`);
|
54
49
|
}
|
50
|
+
};
|
55
51
|
|
56
|
-
|
52
|
+
return await new Promise((resolve, reject) => {
|
53
|
+
const handleFinishTask = (msg) => {
|
54
|
+
let result = RED.util.encodeObject(msg.payload);
|
57
55
|
|
58
|
-
|
59
|
-
|
60
|
-
|
56
|
+
node.log(
|
57
|
+
`handle event for *external task flowNodeInstanceId* '${externalTask.flowNodeInstanceId}' and *processInstanceId* ${externalTask.processInstanceId} with result ${result} on msg._msgid ${msg._msgid}.`
|
58
|
+
);
|
61
59
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
);
|
60
|
+
if (externalTask.flowNodeInstanceId) {
|
61
|
+
delete started_external_tasks[externalTask.flowNodeInstanceId];
|
62
|
+
}
|
66
63
|
|
67
|
-
|
68
|
-
delete started_external_tasks[externalTask.flowNodeInstanceId];
|
69
|
-
}
|
64
|
+
showStatus(node, Object.keys(started_external_tasks).length);
|
70
65
|
|
71
|
-
|
66
|
+
//resolve(result);
|
67
|
+
saveHandleCallback(result, resolve);
|
68
|
+
};
|
72
69
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
saveHandleCallback(msg, resolve);
|
78
|
-
};
|
70
|
+
const handleErrorTask = (msg) => {
|
71
|
+
node.log(
|
72
|
+
`handle error event for *external task flowNodeInstanceId* '${externalTask.flowNodeInstanceId}' and *processInstanceId* '${externalTask.processInstanceId}' on *msg._msgid* '${msg._msgid}'.`
|
73
|
+
);
|
79
74
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
);
|
75
|
+
if (externalTask.flowNodeInstanceId) {
|
76
|
+
delete started_external_tasks[externalTask.flowNodeInstanceId];
|
77
|
+
}
|
84
78
|
|
85
|
-
|
86
|
-
handleErrorTask(msg);
|
87
|
-
} else {
|
88
|
-
handleFinishTask(msg);
|
89
|
-
}
|
90
|
-
});
|
79
|
+
showStatus(node, Object.keys(started_external_tasks).length);
|
91
80
|
|
92
|
-
|
81
|
+
// TODO: with reject, the default error handling is proceed
|
82
|
+
// SEE: https://github.com/5minds/ProcessCube.Engine.Client.ts/blob/develop/src/ExternalTaskWorker.ts#L180
|
83
|
+
// reject(result);
|
84
|
+
//resolve(msg);
|
85
|
+
saveHandleCallback(msg, resolve);
|
86
|
+
};
|
93
87
|
|
94
|
-
|
88
|
+
eventEmitter.once(`handle-${externalTask.flowNodeInstanceId}`, (msg, isError = false) => {
|
89
|
+
node.log(
|
90
|
+
`handle event for *external task flowNodeInstanceId* '${externalTask.flowNodeInstanceId}' and *processInstanceId* '${externalTask.processInstanceId}' with *msg._msgid* '${msg._msgid}' and *isError* '${isError}'`
|
91
|
+
);
|
95
92
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
};
|
93
|
+
if (isError) {
|
94
|
+
handleErrorTask(msg);
|
95
|
+
} else {
|
96
|
+
handleFinishTask(msg);
|
97
|
+
}
|
98
|
+
});
|
103
99
|
|
104
|
-
|
105
|
-
`Received *external task flowNodeInstanceId* '${externalTask.flowNodeInstanceId}' and *processInstanceId* '${externalTask.processInstanceId}' with *msg._msgid* '${msg._msgid}'`
|
106
|
-
);
|
100
|
+
started_external_tasks[externalTask.flowNodeInstanceId] = externalTask;
|
107
101
|
|
108
|
-
|
109
|
-
});
|
110
|
-
};
|
102
|
+
showStatus(node, Object.keys(started_external_tasks).length);
|
111
103
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
104
|
+
let msg = {
|
105
|
+
_msgid: RED.util.generateId(),
|
106
|
+
task: RED.util.encodeObject(externalTask),
|
107
|
+
payload: payload,
|
108
|
+
flowNodeInstanceId: externalTask.flowNodeInstanceId,
|
109
|
+
processInstanceId: externalTask.processInstanceId,
|
110
|
+
};
|
116
111
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
});
|
112
|
+
node.log(
|
113
|
+
`Received *external task flowNodeInstanceId* '${externalTask.flowNodeInstanceId}' and *processInstanceId* '${externalTask.processInstanceId}' with *msg._msgid* '${msg._msgid}'`
|
114
|
+
);
|
121
115
|
|
122
|
-
|
123
|
-
externalTaskWorker.onWorkerError((errorType, error, externalTask) => {
|
124
|
-
switch (errorType) {
|
125
|
-
case 'extendLock':
|
126
|
-
case 'finishExternalTask':
|
127
|
-
case 'processExternalTask':
|
128
|
-
node.error(
|
129
|
-
`Worker error ${errorType} for *external task flowNodeInstanceId* '${externalTask.flowNodeInstanceId}' and *processInstanceId* '${externalTask.processInstanceId}': ${error.message}`
|
130
|
-
);
|
131
|
-
|
132
|
-
if (externalTask) {
|
133
|
-
delete started_external_tasks[externalTask.flowNodeInstanceId];
|
134
|
-
}
|
135
|
-
|
136
|
-
showStatus(node, Object.keys(started_external_tasks).length);
|
137
|
-
break;
|
138
|
-
default:
|
139
|
-
node.error(`Worker error ${errorType}: ${error.message}`);
|
140
|
-
break;
|
141
|
-
}
|
116
|
+
node.send(msg);
|
142
117
|
});
|
118
|
+
};
|
143
119
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
120
|
+
client.externalTasks
|
121
|
+
.subscribeToExternalTaskTopic(
|
122
|
+
config.topic,
|
123
|
+
etwCallback,
|
124
|
+
RED.util.evaluateNodeProperty(config.workerConfig, 'json', node)
|
125
|
+
)
|
126
|
+
.then(async (externalTaskWorker) => {
|
127
|
+
node.status({ fill: 'blue', shape: 'ring', text: 'subcribed' });
|
128
|
+
|
129
|
+
externalTaskWorker.identity = engine.identity;
|
130
|
+
engine.registerOnIdentityChanged((identity) => {
|
131
|
+
externalTaskWorker.identity = identity;
|
132
|
+
});
|
133
|
+
|
134
|
+
// export type WorkerErrorHandler = (errorType: 'fetchAndLock' | 'extendLock' | 'processExternalTask' | 'finishExternalTask', error: Error, externalTask?: ExternalTask<any>) => void;
|
135
|
+
externalTaskWorker.onWorkerError((errorType, error, externalTask) => {
|
136
|
+
switch (errorType) {
|
137
|
+
case 'extendLock':
|
138
|
+
case 'finishExternalTask':
|
139
|
+
case 'processExternalTask':
|
140
|
+
node.error(
|
141
|
+
`Worker error ${errorType} for *external task flowNodeInstanceId* '${externalTask.flowNodeInstanceId}' and *processInstanceId* '${externalTask.processInstanceId}': ${error.message}`
|
142
|
+
);
|
143
|
+
|
144
|
+
if (externalTask) {
|
145
|
+
delete started_external_tasks[externalTask.flowNodeInstanceId];
|
146
|
+
}
|
147
|
+
|
148
|
+
showStatus(node, Object.keys(started_external_tasks).length);
|
149
|
+
break;
|
150
|
+
default:
|
151
|
+
node.error(`Worker error ${errorType}: ${error.message}`);
|
152
|
+
break;
|
153
|
+
}
|
154
|
+
});
|
149
155
|
|
150
|
-
node.on('close', () => {
|
151
156
|
try {
|
152
|
-
externalTaskWorker.
|
153
|
-
} catch {
|
154
|
-
node.error('
|
157
|
+
externalTaskWorker.start();
|
158
|
+
} catch (error) {
|
159
|
+
node.error(`Worker start 'externalTaskWorker.start' failed: ${error.message}`);
|
155
160
|
}
|
161
|
+
|
162
|
+
node.on('close', () => {
|
163
|
+
try {
|
164
|
+
externalTaskWorker.stop();
|
165
|
+
} catch {
|
166
|
+
node.error('Client close failed');
|
167
|
+
}
|
168
|
+
});
|
169
|
+
})
|
170
|
+
.catch((error) => {
|
171
|
+
node.error(`Error in subscribeToExternalTaskTopic: ${error.message}`);
|
156
172
|
});
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
173
|
+
};
|
174
|
+
|
175
|
+
if (node.engine) {
|
176
|
+
register();
|
177
|
+
}
|
161
178
|
}
|
162
179
|
|
163
180
|
RED.nodes.registerType('externaltask-input', ExternalTaskInput);
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@5minds/node-red-contrib-processcube",
|
3
|
-
"version": "1.5.
|
3
|
+
"version": "1.5.6-feature-60b2c2-m3pneelx",
|
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
|
},
|
@@ -4,6 +4,13 @@ module.exports = function (RED) {
|
|
4
4
|
var node = this;
|
5
5
|
node.engine = RED.nodes.getNode(config.engine);
|
6
6
|
|
7
|
+
const eventEmitter = node.engine.eventEmitter;
|
8
|
+
|
9
|
+
eventEmitter.on('engine-client-changed', () => {
|
10
|
+
console.log('new engineClient received');
|
11
|
+
register();
|
12
|
+
});
|
13
|
+
|
7
14
|
const register = async () => {
|
8
15
|
const client = node.engine.engineClient;
|
9
16
|
|
@@ -24,7 +31,8 @@ module.exports = function (RED) {
|
|
24
31
|
async (processNotification) => {
|
25
32
|
if (
|
26
33
|
config.processmodel != '' &&
|
27
|
-
config.processmodel != processNotification.processModelId
|
34
|
+
config.processmodel != processNotification.processModelId
|
35
|
+
) {
|
28
36
|
return;
|
29
37
|
}
|
30
38
|
|
@@ -65,7 +73,8 @@ module.exports = function (RED) {
|
|
65
73
|
async (processNotification) => {
|
66
74
|
if (
|
67
75
|
config.processmodel != '' &&
|
68
|
-
config.processmodel != processNotification.processModelId
|
76
|
+
config.processmodel != processNotification.processModelId
|
77
|
+
) {
|
69
78
|
return;
|
70
79
|
}
|
71
80
|
|
@@ -433,7 +442,6 @@ module.exports = function (RED) {
|
|
433
442
|
},
|
434
443
|
{ identity: currentIdentity }
|
435
444
|
);
|
436
|
-
|
437
445
|
});
|
438
446
|
|
439
447
|
node.on('close', () => {
|
@@ -1,20 +1,23 @@
|
|
1
|
+
const EventEmitter = require('node:events');
|
1
2
|
const engine_client = require('@5minds/processcube_engine_client');
|
2
3
|
const jwt = require('jwt-decode');
|
3
4
|
const oidc = require('openid-client');
|
4
5
|
|
5
|
-
const DELAY_FACTOR = 0.85;
|
6
|
-
|
7
6
|
module.exports = function (RED) {
|
8
7
|
function ProcessCubeEngineNode(n) {
|
9
8
|
RED.nodes.createNode(this, n);
|
10
9
|
const node = this;
|
11
10
|
const identityChangedCallbacks = [];
|
12
|
-
this.url = RED.util.evaluateNodeProperty(n.url, n.urlType, node);
|
13
11
|
this.identity = null;
|
14
12
|
|
15
13
|
this.credentials.clientId = RED.util.evaluateNodeProperty(n.clientId, n.clientIdType, node);
|
16
14
|
this.credentials.clientSecret = RED.util.evaluateNodeProperty(n.clientSecret, n.clientSecretType, node);
|
17
15
|
|
16
|
+
node.eventEmitter = new EventEmitter();
|
17
|
+
|
18
|
+
// set the engine url
|
19
|
+
const stopRefreshing = periodicallyRefreshEngineClient(this, n, 10000);
|
20
|
+
|
18
21
|
this.registerOnIdentityChanged = function (callback) {
|
19
22
|
identityChangedCallbacks.push(callback);
|
20
23
|
};
|
@@ -36,123 +39,99 @@ module.exports = function (RED) {
|
|
36
39
|
}
|
37
40
|
};
|
38
41
|
|
39
|
-
node
|
40
|
-
|
41
|
-
|
42
|
-
|
42
|
+
function periodicallyRefreshEngineClient(node, n, intervalMs) {
|
43
|
+
function refreshUrl() {
|
44
|
+
const newUrl = RED.util.evaluateNodeProperty(n.url, n.urlType, node);
|
45
|
+
|
46
|
+
if (node.url === newUrl) {
|
47
|
+
return;
|
48
|
+
}
|
49
|
+
|
50
|
+
node.url = newUrl;
|
51
|
+
if (node.credentials.clientId && node.credentials.clientSecret) {
|
52
|
+
if (this.engineClient) {
|
53
|
+
this.engineClient.dispose();
|
54
|
+
}
|
55
|
+
node.engineClient = new engine_client.EngineClient(node.url, () =>
|
56
|
+
getFreshIdentity(node.url, node)
|
57
|
+
);
|
58
|
+
|
59
|
+
node.eventEmitter.emit('engine-client-changed');
|
60
|
+
} else {
|
61
|
+
if (this.engineClient) {
|
62
|
+
this.engineClient.dispose();
|
63
|
+
}
|
64
|
+
node.engineClient = new engine_client.EngineClient(node.url);
|
65
|
+
|
66
|
+
node.eventEmitter.emit('engine-client-changed');
|
67
|
+
}
|
43
68
|
}
|
44
|
-
});
|
45
69
|
|
46
|
-
|
47
|
-
|
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);
|
68
|
-
}
|
69
|
-
}
|
70
|
-
RED.nodes.registerType('processcube-engine-config', ProcessCubeEngineNode, {
|
71
|
-
credentials: {
|
72
|
-
clientId: { type: 'text' },
|
73
|
-
clientSecret: { type: 'password' },
|
74
|
-
},
|
75
|
-
});
|
76
|
-
};
|
70
|
+
refreshUrl();
|
71
|
+
const intervalId = setInterval(refreshUrl, intervalMs);
|
77
72
|
|
78
|
-
|
79
|
-
|
73
|
+
return () => clearInterval(intervalId);
|
74
|
+
}
|
80
75
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
76
|
+
async function getFreshIdentity(url, node) {
|
77
|
+
try {
|
78
|
+
if (
|
79
|
+
!RED.util.evaluateNodeProperty(n.clientId, n.clientIdType, node) ||
|
80
|
+
!RED.util.evaluateNodeProperty(n.clientSecret, n.clientSecretType, node)
|
81
|
+
) {
|
82
|
+
return null;
|
83
|
+
}
|
84
|
+
|
85
|
+
const res = await fetch(url + '/atlas_engine/api/v1/authority', {
|
86
|
+
method: 'GET',
|
87
|
+
headers: {
|
88
|
+
Authorization: `Bearer ZHVtbXlfdG9rZW4=`,
|
89
|
+
'Content-Type': 'application/json',
|
90
|
+
},
|
91
|
+
});
|
85
92
|
|
86
|
-
|
87
|
-
grant_type: 'client_credentials',
|
88
|
-
scope: 'engine_etw engine_read engine_write',
|
89
|
-
});
|
93
|
+
const body = await res.json();
|
90
94
|
|
91
|
-
|
92
|
-
}
|
95
|
+
const issuer = await oidc.Issuer.discover(body);
|
93
96
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
+
const client = new issuer.Client({
|
98
|
+
client_id: RED.util.evaluateNodeProperty(n.clientId, n.clientIdType, node),
|
99
|
+
client_secret: RED.util.evaluateNodeProperty(n.clientSecret, n.clientSecretType, node),
|
100
|
+
});
|
97
101
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
}
|
102
|
+
const tokenSet = await client.grant({
|
103
|
+
grant_type: 'client_credentials',
|
104
|
+
scope: 'engine_etw engine_read engine_write',
|
105
|
+
});
|
103
106
|
|
104
|
-
|
105
|
-
|
107
|
+
const accessToken = tokenSet.access_token;
|
108
|
+
const decodedToken = jwt.jwtDecode(accessToken);
|
106
109
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
+
const freshIdentity = {
|
111
|
+
token: tokenSet.access_token,
|
112
|
+
userId: decodedToken.sub,
|
113
|
+
};
|
110
114
|
|
111
|
-
|
112
|
-
throw new Error('Could not determine the time until the access token for external task workers expires');
|
113
|
-
}
|
115
|
+
node.setIdentity(freshIdentity);
|
114
116
|
|
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;
|
117
|
+
return freshIdentity;
|
118
|
+
} catch (e) {
|
119
|
+
node.error(`Could not get fresh identity: ${e}`);
|
145
120
|
}
|
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
121
|
}
|
155
|
-
};
|
156
122
|
|
157
|
-
|
158
|
-
|
123
|
+
node.on('close', async () => {
|
124
|
+
if (this.engineClient) {
|
125
|
+
stopRefreshing();
|
126
|
+
this.engineClient.dispose();
|
127
|
+
this.engineClient = null;
|
128
|
+
}
|
129
|
+
});
|
130
|
+
}
|
131
|
+
RED.nodes.registerType('processcube-engine-config', ProcessCubeEngineNode, {
|
132
|
+
credentials: {
|
133
|
+
clientId: { type: 'text' },
|
134
|
+
clientSecret: { type: 'password' },
|
135
|
+
},
|
136
|
+
});
|
137
|
+
};
|
@@ -4,6 +4,13 @@ module.exports = function (RED) {
|
|
4
4
|
var node = this;
|
5
5
|
node.engine = RED.nodes.getNode(config.engine);
|
6
6
|
|
7
|
+
const eventEmitter = node.engine.eventEmitter;
|
8
|
+
|
9
|
+
eventEmitter.on('engine-client-changed', () => {
|
10
|
+
console.log('new engineClient received');
|
11
|
+
register();
|
12
|
+
});
|
13
|
+
|
7
14
|
const register = async () => {
|
8
15
|
let currentIdentity = node.engine.identity;
|
9
16
|
|
@@ -20,7 +27,7 @@ module.exports = function (RED) {
|
|
20
27
|
function userTaskCallback() {
|
21
28
|
return async (userTaskNotification) => {
|
22
29
|
if (config.usertask != '' && config.usertask != userTaskNotification.flowNodeId) return;
|
23
|
-
|
30
|
+
|
24
31
|
const newQuery = {
|
25
32
|
flowNodeInstanceId: userTaskNotification.flowNodeInstanceId,
|
26
33
|
...query,
|
@@ -84,7 +91,7 @@ module.exports = function (RED) {
|
|
84
91
|
currentIdentity = identity;
|
85
92
|
|
86
93
|
subscription = subscribe();
|
87
|
-
})
|
94
|
+
});
|
88
95
|
|
89
96
|
node.on('close', async () => {
|
90
97
|
if (node.engine && node.engine.engineClient && client) {
|
package/wait-for-usertask.js
CHANGED
@@ -5,13 +5,12 @@ module.exports = function (RED) {
|
|
5
5
|
|
6
6
|
node.engine = RED.nodes.getNode(config.engine);
|
7
7
|
|
8
|
-
const client = node.engine.engineClient;
|
9
|
-
|
10
8
|
let subscription = null;
|
11
9
|
let currentIdentity = node.engine.identity;
|
12
10
|
let subscribe = null;
|
13
11
|
|
14
12
|
node.on('input', async function (msg) {
|
13
|
+
const client = node.engine.engineClient;
|
15
14
|
subscribe = async () => {
|
16
15
|
if (!client) {
|
17
16
|
node.error('No engine configured.');
|
@@ -20,44 +19,49 @@ module.exports = function (RED) {
|
|
20
19
|
|
21
20
|
const query = RED.util.evaluateNodeProperty(config.query, config.query_type, node, msg);
|
22
21
|
|
23
|
-
subscription = await client.userTasks.onUserTaskWaiting(
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
22
|
+
subscription = await client.userTasks.onUserTaskWaiting(
|
23
|
+
async (userTaskWaitingNotification) => {
|
24
|
+
const newQuery = {
|
25
|
+
flowNodeInstanceId: userTaskWaitingNotification.flowNodeInstanceId,
|
26
|
+
...query,
|
27
|
+
};
|
28
|
+
|
29
|
+
try {
|
30
|
+
const matchingFlowNodes = await client.userTasks.query(newQuery, {
|
31
|
+
identity: currentIdentity,
|
32
|
+
});
|
33
|
+
|
34
|
+
if (matchingFlowNodes.userTasks && matchingFlowNodes.userTasks.length == 1) {
|
35
|
+
// remove subscription
|
36
|
+
client.userTasks.removeSubscription(subscription, currentIdentity);
|
37
|
+
|
38
|
+
const userTask = matchingFlowNodes.userTasks[0];
|
39
|
+
|
40
|
+
msg.payload = { userTask: userTask };
|
41
|
+
node.send(msg);
|
42
|
+
} else {
|
43
|
+
// nothing todo - wait for next notification
|
44
|
+
}
|
45
|
+
} catch (error) {
|
46
|
+
node.error(error);
|
43
47
|
}
|
44
|
-
}
|
45
|
-
|
46
|
-
|
48
|
+
},
|
49
|
+
{ identity: currentIdentity }
|
50
|
+
);
|
47
51
|
|
48
|
-
|
49
|
-
|
50
|
-
node.log({ "Handling old userTasks config.only_for_new": config.only_for_new });
|
52
|
+
node.log({ 'Handling old userTasks config.only_for_new': config.only_for_new });
|
51
53
|
|
52
54
|
if (config.only_for_new === false) {
|
53
55
|
// only check suspended user tasks
|
54
56
|
const suspendedQuery = {
|
55
|
-
|
56
|
-
...query
|
57
|
+
state: 'suspended',
|
58
|
+
...query,
|
57
59
|
};
|
58
60
|
|
59
61
|
try {
|
60
|
-
const matchingFlowNodes = await client.userTasks.query(suspendedQuery, {
|
62
|
+
const matchingFlowNodes = await client.userTasks.query(suspendedQuery, {
|
63
|
+
identity: currentIdentity,
|
64
|
+
});
|
61
65
|
|
62
66
|
if (matchingFlowNodes.userTasks && matchingFlowNodes.userTasks.length >= 1) {
|
63
67
|
const userTask = matchingFlowNodes.userTasks[0];
|
@@ -80,7 +84,6 @@ module.exports = function (RED) {
|
|
80
84
|
});
|
81
85
|
|
82
86
|
node.engine.registerOnIdentityChanged(async (identity) => {
|
83
|
-
|
84
87
|
if (subscription) {
|
85
88
|
client.userTasks.removeSubscription(subscription, currentIdentity);
|
86
89
|
currentIdentity = identity;
|
@@ -90,11 +93,11 @@ module.exports = function (RED) {
|
|
90
93
|
}
|
91
94
|
});
|
92
95
|
|
93
|
-
node.on(
|
96
|
+
node.on('close', async () => {
|
94
97
|
if (client != null && subscription != null) {
|
95
98
|
client.userTasks.removeSubscription(subscription, currentIdentity);
|
96
99
|
}
|
97
100
|
});
|
98
101
|
}
|
99
|
-
RED.nodes.registerType(
|
100
|
-
}
|
102
|
+
RED.nodes.registerType('wait-for-usertask', WaitForUsertask);
|
103
|
+
};
|