@5minds/node-red-contrib-processcube 1.5.5 → 1.5.6-feature-60b2c2-m3pneelx
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
};
|