@5minds/node-red-contrib-processcube 0.11.0-feature-34fec2-lydislpd → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ {
2
+ "$": "4d3947a7155e180f5e1361182578e6ca2miDlL35ToUWYsN6HIEZN1KBk9Ec3/4="
3
+ }
@@ -2,11 +2,8 @@
2
2
  "name": "node-red-contrib-processcube-sample",
3
3
  "version": "1.0.0",
4
4
  "description": "A sample for the processcube node-red contrib package",
5
- "scripts": {
6
- "start": "./node_modules/.bin/node-red --settings=./settings.js node-red-contrib-processcube-flows.json"
7
- },
8
5
  "dependencies": {
9
- "@5minds/node-red-contrib-processcube": "file:..",
6
+ "@5minds/node-red-contrib-processcube": "file:/src/node-red-contrib-processcube/",
10
7
  "@5minds/node-red-dashboard-2-processcube-dynamic-form": "^1.0.4",
11
8
  "@5minds/node-red-dashboard-2-processcube-usertask-table": "^1.0.7",
12
9
  "@flowfuse/node-red-dashboard": "^1.11.1",
@@ -41,7 +41,7 @@ module.exports = {
41
41
  * node-red from being able to decrypt your existing credentials and they will be
42
42
  * lost.
43
43
  */
44
- //credentialSecret: "a-secret-key",
44
+ credentialSecret: "a-secret-key",
45
45
 
46
46
  /** By default, the flow JSON will be formatted over multiple lines making
47
47
  * it easier to compare changes when using version control.
@@ -53,7 +53,7 @@ module.exports = {
53
53
  * the user's home directory. To use a different location, the following
54
54
  * property can be used
55
55
  */
56
- //userDir: '/home/nol/.node-red/',
56
+ userDir: '/nodered/',
57
57
 
58
58
  /** Node-RED scans the `nodes` directory in the userDir to find local node files.
59
59
  * The following property can be used to specify an additional directory to scan.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@5minds/node-red-contrib-processcube",
3
- "version": "0.11.0-feature-34fec2-lydislpd",
3
+ "version": "0.11.0",
4
4
  "license": "MIT",
5
5
  "description": "Node-RED nodes for ProcessCube",
6
6
  "authors": [
@@ -44,12 +44,13 @@
44
44
  "UserTaskNewListener": "usertask-new-listener.js",
45
45
  "UserTaskFinishedListener": "usertask-finished-listener.js",
46
46
  "UserTaskInput": "usertask-input.js",
47
- "UserTaskOutput": "usertask-output.js",
48
- "WaitForUsertask": "wait-for-usertask.js"
47
+ "UserTaskOutput": "usertask-output.js"
49
48
  }
50
49
  },
51
50
  "dependencies": {
52
- "@5minds/processcube_engine_client": "^5.0.0"
51
+ "@5minds/processcube_engine_client": "^5.0.0",
52
+ "jwt-decode": "^4.0.0",
53
+ "openid-client": "^5.5.0"
53
54
  },
54
55
  "keywords": [
55
56
  "node-red",
package/process-start.js CHANGED
@@ -27,7 +27,7 @@ module.exports = function(RED) {
27
27
  initialToken: msg.payload
28
28
  };
29
29
 
30
- client.processDefinitions.startProcessInstance(startParameters).then((result) => {
30
+ client.processDefinitions.startProcessInstance(startParameters, node.engine.identity).then((result) => {
31
31
 
32
32
  msg.payload = result;
33
33
 
@@ -6,6 +6,10 @@
6
6
  },
7
7
  label: function() {
8
8
  return this.url;
9
+ },
10
+ credentials: {
11
+ clientId: { type: "text" },
12
+ clientSecret: { type: "password" }
9
13
  }
10
14
  });
11
15
  </script>
@@ -15,4 +19,12 @@
15
19
  <label for="node-config-input-url"><i class="fa fa-bookmark"></i> Url</label>
16
20
  <input type="text" id="node-config-input-url">
17
21
  </div>
22
+ <div class="form-row">
23
+ <label for="node-config-input-clientId"><i class="fa fa-bookmark"></i> Client id</label>
24
+ <input type="text" id="node-config-input-clientId">
25
+ </div>
26
+ <div class="form-row">
27
+ <label for="node-config-input-clientSecret"><i class="fa fa-bookmark"></i> Client secret</label>
28
+ <input type="password" id="node-config-input-clientSecret">
29
+ </div>
18
30
  </script>
@@ -1,7 +1,121 @@
1
+ const engine_client = require('@5minds/processcube_engine_client');
2
+ const jwt = require('jwt-decode');
3
+ const oidc = require('openid-client');
4
+
5
+ const DELAY_FACTOR = 0.85;
6
+
1
7
  module.exports = function(RED) {
2
8
  function ProcessCubeEngineNode(n) {
3
9
  RED.nodes.createNode(this, n);
10
+ const identityChangedCallbacks = [];
4
11
  this.url = n.url;
12
+ this.identity = null;
13
+ this.registerOnIdentityChanged = function (callback) {
14
+ identityChangedCallbacks.push(callback);
15
+ }
16
+ this.setIdentity = (identity) => {
17
+ this.identity = identity;
18
+
19
+ for (const callback of identityChangedCallbacks) {
20
+ callback(identity);
21
+ }
22
+ }
23
+
24
+ if (this.credentials.clientId && this.credentials.clientSecret) {
25
+ const engineClient = new engine_client.EngineClient(this.url);
26
+
27
+ engineClient.applicationInfo.getAuthorityAddress().then(authorityUrl => {
28
+ startRefreshingIdentityCycle(this.credentials.clientId, this.credentials.clientSecret, authorityUrl, this);
29
+ });
30
+ }
5
31
  }
6
- RED.nodes.registerType("processcube-engine-config", ProcessCubeEngineNode);
32
+ RED.nodes.registerType("processcube-engine-config", ProcessCubeEngineNode, {
33
+ credentials: {
34
+ clientId: { type: "text" },
35
+ clientSecret: { type: "password" }
36
+ }
37
+ });
38
+ }
39
+
40
+ async function getFreshTokenSet(clientId, clientSecret, authorityUrl) {
41
+ const issuer = await oidc.Issuer.discover(authorityUrl);
42
+
43
+ const client = new issuer.Client({
44
+ client_id: clientId,
45
+ client_secret: clientSecret,
46
+ });
47
+
48
+ const tokenSet = await client.grant({
49
+ grant_type: 'client_credentials',
50
+ scope: 'engine_etw engine_read engine_write',
51
+ });
52
+
53
+ return tokenSet;
54
+ }
55
+
56
+ function getIdentityForExternalTaskWorkers(tokenSet) {
57
+
58
+ const accessToken = tokenSet.access_token;
59
+ const decodedToken = jwt.jwtDecode(accessToken);
60
+
61
+ return {
62
+ token: tokenSet.access_token,
63
+ userId: decodedToken.sub,
64
+ };
65
+ }
66
+
67
+ async function getExpiresInForExternalTaskWorkers(tokenSet) {
68
+ let expiresIn = tokenSet.expires_in;
69
+
70
+ if (!expiresIn && tokenSet.expires_at) {
71
+ expiresIn = Math.floor(tokenSet.expires_at - Date.now() / 1000);
72
+ }
73
+
74
+ if (expiresIn === undefined) {
75
+ throw new Error('Could not determine the time until the access token for external task workers expires');
76
+ }
77
+
78
+ return expiresIn;
79
+ }
80
+
81
+ /**
82
+ * Start refreshing the identity in regular intervals.
83
+ * @param {TokenSet | null} tokenSet The token set to refresh the identity for
84
+ * @returns {Promise<void>} A promise that resolves when the timer for refreshing the identity is initialized
85
+ * */
86
+ async function startRefreshingIdentityCycle(clientId, clientSecret, authorityUrl, configNode) {
87
+ let retries = 5;
88
+
89
+ const refresh = async () => {
90
+ try {
91
+ const newTokenSet = await getFreshTokenSet(clientId, clientSecret, authorityUrl);
92
+ const expiresIn = await getExpiresInForExternalTaskWorkers(newTokenSet);
93
+ const delay = expiresIn * DELAY_FACTOR * 1000;
94
+
95
+ freshIdentity = getIdentityForExternalTaskWorkers(newTokenSet);
96
+
97
+ configNode.setIdentity(freshIdentity);
98
+
99
+ retries = 5;
100
+ setTimeout(refresh, delay);
101
+ } catch (error) {
102
+ if (retries === 0) {
103
+ console.error(
104
+ 'Could not refresh identity for external task worker processes. Stopping all external task workers.',
105
+ { error },
106
+ );
107
+ return;
108
+ }
109
+ console.error('Could not refresh identity for external task worker processes.', {
110
+ error,
111
+ retryCount: retries,
112
+ });
113
+ retries--;
114
+
115
+ const delay = 2 * 1000;
116
+ setTimeout(refresh, delay);
117
+ }
118
+ };
119
+
120
+ await refresh();
7
121
  }
@@ -34,8 +34,12 @@ module.exports = function(RED) {
34
34
  });
35
35
 
36
36
  node.on('input', function(msg) {
37
- const query = RED.util.evaluateNodeProperty(config.query, config.query_type, node, msg)
38
-
37
+ let query = RED.util.evaluateNodeProperty(config.query, config.query_type, node, msg)
38
+ query = {
39
+ ...query,
40
+ identity: node.server.identity
41
+ };
42
+
39
43
  client.processDefinitions.getAll(query).then((matchingProcessDefinitions) => {
40
44
 
41
45
 
@@ -8,9 +8,8 @@
8
8
  <bpmn:lane id="Lane_1xzf0d3">
9
9
  <bpmn:flowNodeRef>StartEvent_1</bpmn:flowNodeRef>
10
10
  <bpmn:flowNodeRef>Activity_1h843f0</bpmn:flowNodeRef>
11
- <bpmn:flowNodeRef>Event_0z1wtnd</bpmn:flowNodeRef>
12
- <bpmn:flowNodeRef>Activity_1y52hvq</bpmn:flowNodeRef>
13
11
  <bpmn:flowNodeRef>Activity_1duxvq1</bpmn:flowNodeRef>
12
+ <bpmn:flowNodeRef>Event_0z1wtnd</bpmn:flowNodeRef>
14
13
  </bpmn:lane>
15
14
  </bpmn:laneSet>
16
15
  <bpmn:startEvent id="StartEvent_1" name="Start">
@@ -27,27 +26,22 @@
27
26
  <bpmn:outgoing>Flow_110cohh</bpmn:outgoing>
28
27
  </bpmn:serviceTask>
29
28
  <bpmn:sequenceFlow id="Flow_110cohh" sourceRef="Activity_1h843f0" targetRef="Activity_1duxvq1" />
30
- <bpmn:sequenceFlow id="Flow_1u1afua" sourceRef="Activity_1duxvq1" targetRef="Activity_1y52hvq" />
31
- <bpmn:endEvent id="Event_0z1wtnd">
32
- <bpmn:incoming>Flow_1oiihw7</bpmn:incoming>
33
- </bpmn:endEvent>
34
- <bpmn:task id="Activity_1y52hvq" name="do wait">
35
- <bpmn:incoming>Flow_1u1afua</bpmn:incoming>
36
- <bpmn:outgoing>Flow_1oiihw7</bpmn:outgoing>
37
- </bpmn:task>
38
- <bpmn:sequenceFlow id="Flow_1oiihw7" sourceRef="Activity_1y52hvq" targetRef="Event_0z1wtnd" />
39
- <bpmn:serviceTask id="Activity_1duxvq1" name="get process models" camunda:type="external" camunda:topic="processmodels">
29
+ <bpmn:serviceTask id="Activity_1duxvq1" name="SampleError" camunda:type="external" camunda:topic="SampleError">
40
30
  <bpmn:incoming>Flow_110cohh</bpmn:incoming>
41
31
  <bpmn:outgoing>Flow_1u1afua</bpmn:outgoing>
42
32
  </bpmn:serviceTask>
33
+ <bpmn:sequenceFlow id="Flow_1u1afua" sourceRef="Activity_1duxvq1" targetRef="Event_0z1wtnd" />
34
+ <bpmn:endEvent id="Event_0z1wtnd">
35
+ <bpmn:incoming>Flow_1u1afua</bpmn:incoming>
36
+ </bpmn:endEvent>
43
37
  </bpmn:process>
44
38
  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
45
39
  <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration_1cidyxu">
46
40
  <bpmndi:BPMNShape id="Participant_0px403d_di" bpmnElement="Participant_0px403d" isHorizontal="true">
47
- <dc:Bounds x="5" y="4" width="885" height="346" />
41
+ <dc:Bounds x="5" y="4" width="695" height="346" />
48
42
  </bpmndi:BPMNShape>
49
43
  <bpmndi:BPMNShape id="Lane_1xzf0d3_di" bpmnElement="Lane_1xzf0d3" isHorizontal="true">
50
- <dc:Bounds x="35" y="4" width="855" height="346" />
44
+ <dc:Bounds x="35" y="4" width="665" height="346" />
51
45
  </bpmndi:BPMNShape>
52
46
  <bpmndi:BPMNShape id="StartEvent_1_di" bpmnElement="StartEvent_1">
53
47
  <dc:Bounds x="92" y="152" width="36" height="36" />
@@ -59,17 +53,13 @@
59
53
  <dc:Bounds x="180" y="130" width="100" height="80" />
60
54
  <bpmndi:BPMNLabel />
61
55
  </bpmndi:BPMNShape>
62
- <bpmndi:BPMNShape id="Event_0z1wtnd_di" bpmnElement="Event_0z1wtnd">
63
- <dc:Bounds x="692" y="152" width="36" height="36" />
64
- </bpmndi:BPMNShape>
65
- <bpmndi:BPMNShape id="Activity_1y52hvq_di" bpmnElement="Activity_1y52hvq">
66
- <dc:Bounds x="540" y="130" width="100" height="80" />
67
- <bpmndi:BPMNLabel />
68
- </bpmndi:BPMNShape>
69
56
  <bpmndi:BPMNShape id="Activity_1ohliek_di" bpmnElement="Activity_1duxvq1">
70
57
  <dc:Bounds x="370" y="130" width="100" height="80" />
71
58
  <bpmndi:BPMNLabel />
72
59
  </bpmndi:BPMNShape>
60
+ <bpmndi:BPMNShape id="Event_0z1wtnd_di" bpmnElement="Event_0z1wtnd">
61
+ <dc:Bounds x="562" y="152" width="36" height="36" />
62
+ </bpmndi:BPMNShape>
73
63
  <bpmndi:BPMNEdge id="Flow_1xfzejj_di" bpmnElement="Flow_1xfzejj">
74
64
  <di:waypoint x="128" y="170" />
75
65
  <di:waypoint x="180" y="170" />
@@ -80,11 +70,7 @@
80
70
  </bpmndi:BPMNEdge>
81
71
  <bpmndi:BPMNEdge id="Flow_1u1afua_di" bpmnElement="Flow_1u1afua">
82
72
  <di:waypoint x="470" y="170" />
83
- <di:waypoint x="540" y="170" />
84
- </bpmndi:BPMNEdge>
85
- <bpmndi:BPMNEdge id="Flow_1oiihw7_di" bpmnElement="Flow_1oiihw7">
86
- <di:waypoint x="640" y="170" />
87
- <di:waypoint x="692" y="170" />
73
+ <di:waypoint x="562" y="170" />
88
74
  </bpmndi:BPMNEdge>
89
75
  </bpmndi:BPMNPlane>
90
76
  </bpmndi:BPMNDiagram>
@@ -34,9 +34,9 @@ module.exports = function(RED) {
34
34
  });
35
35
 
36
36
  node.on('input', function(msg) {
37
- const query = RED.util.evaluateNodeProperty(config.query, config.query_type, node, msg)
37
+ let query = RED.util.evaluateNodeProperty(config.query, config.query_type, node, msg)
38
38
 
39
- client.processInstances.query(query).then((matchingInstances) => {
39
+ client.processInstances.query(query, { identity: node.server.identity }).then((matchingInstances) => {
40
40
 
41
41
  msg.payload = matchingInstances;
42
42
 
@@ -25,7 +25,8 @@ module.exports = function(RED) {
25
25
  config.signalname,
26
26
  {
27
27
  processInstanceId: config.processinstanceid,
28
- payload: msg.payload
28
+ payload: msg.payload,
29
+ identity: node.server.identity
29
30
  }
30
31
 
31
32
  ).then((result) => {
@@ -28,14 +28,29 @@ module.exports = function(RED) {
28
28
  eventEmitter = flowContext.get('emitter');
29
29
  }
30
30
 
31
- node.on("close", async () => {
32
- client.dispose();
33
- client = null;
34
- });
35
-
36
- client.userTasks.onUserTaskFinished((userTaskFinishedNotification) => {
37
- node.send({ payload: { flowNodeInstanceId: userTaskFinishedNotification.flowNodeInstanceId, action: "finished", type: "usertask" } });
38
- });
31
+ const register = async () => {
32
+ let currentIdentity = node.server.identity;
33
+ let subscription = await client.userTasks.onUserTaskFinished((userTaskFinishedNotification) => {
34
+ node.send({ payload: { flowNodeInstanceId: userTaskFinishedNotification.flowNodeInstanceId, action: "finished", type: "usertask" } });
35
+ }, { identity: currentIdentity });
36
+
37
+ node.server.registerOnIdentityChanged(async (identity) => {
38
+ client.userTasks.removeSubscription(subscription, currentIdentity);
39
+ currentIdentity = identity;
40
+
41
+ subscription = await client.userTasks.onUserTaskFinished((userTaskFinishedNotification) => {
42
+ node.send({ payload: { flowNodeInstanceId: userTaskFinishedNotification.flowNodeInstanceId, action: "finished", type: "usertask" } });
43
+ }, { identity: currentIdentity });
44
+ });
45
+
46
+ node.on("close", async () => {
47
+ client.userTasks.removeSubscription(subscription, currentIdentity);
48
+ client.dispose();
49
+ client = null;
50
+ });
51
+ }
52
+
53
+ register();
39
54
  }
40
55
  RED.nodes.registerType("usertask-finished-listener", UserTaskFinishedListener);
41
56
  }
package/usertask-input.js CHANGED
@@ -15,6 +15,7 @@ module.exports = function(RED) {
15
15
  function UserTaskInput(config) {
16
16
  RED.nodes.createNode(this,config);
17
17
  var node = this;
18
+ var msgCounter = 0;
18
19
  var flowContext = node.context().flow;
19
20
  var nodeContext = node.context();
20
21
 
@@ -42,8 +43,11 @@ module.exports = function(RED) {
42
43
  });
43
44
 
44
45
  node.on('input', function(msg) {
45
- const query = RED.util.evaluateNodeProperty(config.query, config.query_type, node, msg)
46
-
46
+ let query = RED.util.evaluateNodeProperty(config.query, config.query_type, node, msg)
47
+ query = {
48
+ ...query,
49
+ identity: node.server.identity
50
+ }
47
51
  client.userTasks.query(query).then((matchingFlowNodes) => {
48
52
 
49
53
  if (!config.force_send_array && matchingFlowNodes && matchingFlowNodes.userTasks && matchingFlowNodes.userTasks.length == 1) {
@@ -27,15 +27,31 @@ module.exports = function(RED) {
27
27
  flowContext.set('emitter', new EventEmitter());
28
28
  eventEmitter = flowContext.get('emitter');
29
29
  }
30
+
31
+ const register = async () => {
32
+ let currentIdentity = node.server.identity;
33
+ let subscription = await client.userTasks.onUserTaskWaiting((userTaskWaitingNotification) => {
34
+ node.send({ payload: { flowNodeInstanceId: userTaskWaitingNotification.flowNodeInstanceId, action: "new", type: "usertask" } });
35
+ }, { identity: currentIdentity });
36
+
37
+ node.server.registerOnIdentityChanged(async (identity) => {
38
+ client.userTasks.removeSubscription(subscription, currentIdentity);
39
+ currentIdentity = identity;
40
+
41
+ subscription = await client.userTasks.onUserTaskWaiting((userTaskWaitingNotification) => {
42
+ node.send({ payload: { flowNodeInstanceId: userTaskWaitingNotification.flowNodeInstanceId, action: "new", type: "usertask" } });
43
+ }, { identity: currentIdentity });
44
+ });
45
+
46
+ node.on("close", async () => {
47
+ client.userTasks.removeSubscription(subscription, currentIdentity);
48
+ client.dispose();
49
+ client = null;
50
+ });
51
+ }
52
+
53
+ register();
30
54
 
31
- node.on("close", async () => {
32
- client.dispose();
33
- client = null;
34
- });
35
-
36
- client.userTasks.onUserTaskWaiting((userTaskWaitingNotification) => {
37
- node.send({ payload: { flowNodeInstanceId: userTaskWaitingNotification.flowNodeInstanceIdaction, action: "new", type: "usertask" } });
38
- });
39
55
  }
40
56
  RED.nodes.registerType("usertask-new-listener", UserTaskNewListener);
41
57
  }
@@ -37,7 +37,7 @@ module.exports = function(RED) {
37
37
 
38
38
  const userTaskResult = RED.util.evaluateNodeProperty(config.result, config.result_type, node, msg);
39
39
 
40
- client.userTasks.finishUserTask(flowNodeInstanceId, userTaskResult).then(() => {
40
+ client.userTasks.finishUserTask(flowNodeInstanceId, userTaskResult, node.server.identity).then(() => {
41
41
 
42
42
  node.send(msg);
43
43
  }).catch(error => {
@@ -1,76 +0,0 @@
1
- <script type="text/javascript">
2
- RED.nodes.registerType('wait-for-usertask',{
3
- category: 'ProcessCube',
4
- color: '#02AFD6',
5
- defaults: {
6
- name: {value: ""},
7
- engine: {value: "", type: "processcube-engine-config"},
8
- query: {value: "payload"},
9
- query_type: {value: "msg"},
10
- only_for_new: {value: false}
11
- },
12
- inputs: 1,
13
- outputs: 1,
14
- icon: "font-awesome/fa-envelope-open",
15
- label: function() {
16
- return this.name || "wait-for-usertask";
17
- },
18
- oneditprepare: function() {
19
- $("#node-input-query").typedInput({
20
- default: 'msg',
21
- types: ['msg', 'json']
22
- });
23
-
24
- $("#node-input-query").typedInput('value', this.query);
25
- $("#node-input-query").typedInput('type', this.query_type);
26
- },
27
- oneditsave: function() {
28
- this.query = $("#node-input-query").typedInput('value'),
29
- this.query_type = $("#node-input-query").typedInput('type')
30
-
31
- }
32
- });
33
- </script>
34
-
35
- <script type="text/html" data-template-name="wait-for-usertask">
36
- <div class="form-row">
37
- <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
38
- <input type="text" id="node-input-name" placeholder="Name">
39
- </div>
40
- <div class="form-row">
41
- <label for="node-input-engine"><i class="fa fa-tag"></i> Engine-URL</label>
42
- <input type="text" id="node-input-engine" placeholder="http://engine:8000">
43
- </div>
44
- <div class="form-row">
45
- <label for="node-input-query"><i class="fa fa-tag"></i> Query</label>
46
- <input type="text" id="node-input-query">
47
- </div>
48
- <div class="form-row" style="display:flex; margin-bottom: 3px;">
49
- <label for="node-input-only_for_new" style="vertical-align:top"><i class="fa fa-list-alt"></i> Only for new</label>
50
- <div>
51
- <input type="checkbox" checked id="node-input-only_for_new" style="display: inline-block; width: auto; margin: 0px 0px 0px 4px;">
52
- <label style="width:auto" for="node-input-multisend">Trigger only for new user task or *checked* also for old ones?</label>
53
- </div>
54
- </div>
55
- </script>
56
-
57
- <script type="text/markdown" data-help-name="wait-for-usertask">
58
- Waiting for Usertasks of the connected ProcessCube Engine.
59
-
60
- ### Inputs
61
-
62
- : payload (json) : the query to filter the usertasks.
63
-
64
- ## Outputs
65
-
66
- : payload.userTask (string) : The filtered UserTask
67
-
68
- ### Details
69
-
70
- - `msg.payload` or a constant json to filter the UserTasks for Waiting for
71
- - `Only for new` will trigger only for new UserTasks if checked and also for old ones if not checked.
72
-
73
- ### References
74
-
75
- - [The ProcessCube Developer Network](https://processcube.io) - All documentation for the ProcessCube&copy; Plattform
76
- </script>
@@ -1,82 +0,0 @@
1
- const process = require('process');
2
-
3
- const engine_client = require('@5minds/processcube_engine_client');
4
- const { userInfo } = require('os');
5
-
6
- module.exports = function (RED) {
7
- function WaitForUsertask(config) {
8
- RED.nodes.createNode(this, config);
9
- var node = this;
10
- var nodeContext = node.context();
11
-
12
- this.engine = this.server = RED.nodes.getNode(config.engine);
13
-
14
- const engineUrl = this.engine?.url || process.env.ENGINE_URL || 'http://engine:8000';
15
-
16
- var client = nodeContext.get('client');
17
-
18
- if (!client) {
19
- nodeContext.set('client', new engine_client.EngineClient(engineUrl));
20
- client = nodeContext.get('client');
21
- }
22
-
23
- node.on("close", async () => {
24
- if (client != null) {
25
- client.dispose();
26
- client = null;
27
- }
28
- });
29
-
30
- node.on('input', async function (msg) {
31
-
32
- const query = RED.util.evaluateNodeProperty(config.query, config.query_type, node, msg)
33
-
34
- const sub = await client.userTasks.onUserTaskWaiting(async (userTaskWaitingNotification) => {
35
-
36
- const newQuery = {
37
- 'flowNodeInstanceId': userTaskWaitingNotification.flowNodeInstanceId,
38
- ...query
39
- };
40
-
41
- const matchingFlowNodes = await client.userTasks.query(newQuery);
42
-
43
- if (matchingFlowNodes.userTasks && matchingFlowNodes.userTasks.length == 1) {
44
- const userTask = matchingFlowNodes.userTasks[0];
45
-
46
- msg.payload = { userTask: userTask };
47
- node.send(msg);
48
- } else {
49
- }
50
-
51
- // remove subscription
52
- client.userTasks.removeSubscription(sub);
53
- });
54
-
55
- console.debug('Handling old userTasks config.only_for_new', config.only_for_new);
56
-
57
- if (config.only_for_new === false) {
58
- // only check suspended user tasks
59
- const suspendedQuery = {
60
- 'state': 'suspended',
61
- ...query
62
- };
63
-
64
- const matchingFlowNodes = await client.userTasks.query(suspendedQuery);
65
-
66
- if (matchingFlowNodes.userTasks && matchingFlowNodes.userTasks.length >= 1) {
67
- const userTask = matchingFlowNodes.userTasks[0];
68
-
69
- msg.payload = { userTask: userTask };
70
- node.send(msg);
71
-
72
- // remove subscription
73
- client.userTasks.removeSubscription(sub);
74
- } else {
75
- // let the *sub* be active
76
-
77
- }
78
- }
79
- });
80
- }
81
- RED.nodes.registerType("wait-for-usertask", WaitForUsertask);
82
- }