-
Notifications
You must be signed in to change notification settings - Fork 2
/
main.js
123 lines (109 loc) · 4.62 KB
/
main.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/**
* Initialize either a web worker or a node worker thread to execute CQL ("CQL Worker").
* @param {Object} cqlWorker - Created from `new Worker()`.
* @param {boolean} isNodeJs - Boolean indicating whether to initialize for node or web.
* @returns {Function[]} - An array of functions for using the initilized CQL Worker.
*/
export function initializeCqlWorker(cqlWorker, isNodeJs=false) {
// Define an array to keep track of the expression messages sent to the Web Worker
let messageArray = [
{
expr: 'PLACEHOLDER',
resolver: {}
}
];
// Define an event handler for when cqlWorker sends results back.
// NOTE: Node service workers and web workers implement this differently.
// - https://nodejs.org/api/worker_threads.html
// - https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers
const eventHandler = function(event) {
// Unpack the message from the incoming event.
let expression = isNodeJs ? event.expression : event.data.expression;
let result = isNodeJs ? event.result : event.data.result;
// If the response is that cqlWorker is still waiting on the patient bundle,
// wait 100 ms and resend.
if (result == 'WAITING_FOR_PATIENT_BUNDLE') {
setTimeout( () => cqlWorker.postMessage({__evaluate_library__: 'true'}), 100);
} else {
// Try to find this expression in the messageArray
let executingExpressionIndex = messageArray.map((msg,idx) => {
if (msg.expr == expression) return idx;
else return -1;
}).reduce((a,b) => {
if (a != -1) return a;
else if (b != -1) return b;
else return -1});
// If the expression was found in the messageArray
if (executingExpressionIndex != -1) {
// Return the result by resolving the promise
messageArray[executingExpressionIndex].resolver(result);
// Remove the matching entry from the array
messageArray.splice(executingExpressionIndex,1);
}
}
};
// Listen for incoming messages.
// NOTE: Node service workers and web workers implement this differently.
// - https://nodejs.org/api/worker_threads.html
// - https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers
if (isNodeJs) {
cqlWorker.on('message', eventHandler);
} else {
cqlWorker.onmessage = eventHandler;
}
// Send the cqlWorker an initial message containing the ELM JSON representation of the CQL expressions
const setupExecution = function(elmJson, valueSetJson, cqlParameters, elmJsonDependencies) { // TODO: Should have default parameter values here
cqlWorker.postMessage({elmJson: elmJson, valueSetJson: valueSetJson, parameters: cqlParameters, elmJsonDependencies: elmJsonDependencies});
};
// Send the cqlWorker a message containing the patient bundle of FHIR resources.
const sendPatientBundle = function(patientBundle) {
cqlWorker.postMessage({patientBundle: patientBundle});
};
/**
* Sends an expression to the webworker for evaluation.
* @param {string} expression - The name of a CQL expression.
* @returns {boolean} - A dummy return value.
*/
const evaluateExpression = async function(expression) {
// If this expression is already on the message stack, return its index.
let executingExpressionIndex = messageArray.map((msg,idx) => {
if (msg.expression == expression) return idx;
else return -1;
}).reduce((a,b) => {
if (a != -1) return a;
else if (b != -1) return b;
else return -1});
// If this expression was not found on the stack
if (executingExpressionIndex == -1) {
// Add an entry to the stack
let n = messageArray.push({
expr: expression, // The name of the expression
resolver: null
});
// Send the entry to the Web Worker
cqlWorker.postMessage({expression: expression});
// Return a promise that can be resolved after the web worker returns the result
return new Promise(resolve => messageArray[n-1].resolver = resolve);
} else {
return Promise.resolve(-1);
}
};
/**
* Sends a command to the webworker for to evaluate the entire library.
* @returns {boolean} - A dummy return value.
*/
const evaluateLibrary = async function() {
return evaluateExpression('__evaluate_library__');
};
return [
setupExecution,
sendPatientBundle,
evaluateExpression,
evaluateLibrary
];
}
// Included for backwards compatibility, since the original releases included
// this misspelled version of the main function.
export function initialzieCqlWorker(cqlWorker, isNodeJs=false) {
return initializeCqlWorker(cqlWorker, isNodeJs);
}