@cornerstonejs/core 1.30.1 → 1.32.0

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.
Files changed (73) hide show
  1. package/dist/cjs/RenderingEngine/StackViewport.js +1 -0
  2. package/dist/cjs/RenderingEngine/StackViewport.js.map +1 -1
  3. package/dist/cjs/RenderingEngine/VideoViewport.d.ts +15 -2
  4. package/dist/cjs/RenderingEngine/VideoViewport.js +97 -33
  5. package/dist/cjs/RenderingEngine/VideoViewport.js.map +1 -1
  6. package/dist/cjs/RenderingEngine/Viewport.js +1 -1
  7. package/dist/cjs/RenderingEngine/Viewport.js.map +1 -1
  8. package/dist/cjs/enums/RequestType.d.ts +2 -1
  9. package/dist/cjs/enums/RequestType.js +1 -0
  10. package/dist/cjs/enums/RequestType.js.map +1 -1
  11. package/dist/cjs/index.d.ts +2 -2
  12. package/dist/cjs/index.js +2 -1
  13. package/dist/cjs/index.js.map +1 -1
  14. package/dist/cjs/init.d.ts +2 -1
  15. package/dist/cjs/init.js +16 -1
  16. package/dist/cjs/init.js.map +1 -1
  17. package/dist/cjs/requestPool/requestPoolManager.d.ts +1 -2
  18. package/dist/cjs/requestPool/requestPoolManager.js +8 -10
  19. package/dist/cjs/requestPool/requestPoolManager.js.map +1 -1
  20. package/dist/cjs/types/IVideoViewport.d.ts +6 -1
  21. package/dist/cjs/utilities/getViewportsWithImageURI.js +6 -5
  22. package/dist/cjs/utilities/getViewportsWithImageURI.js.map +1 -1
  23. package/dist/cjs/webWorkerManager/webWorkerManager.d.ts +21 -0
  24. package/dist/cjs/webWorkerManager/webWorkerManager.js +167 -0
  25. package/dist/cjs/webWorkerManager/webWorkerManager.js.map +1 -0
  26. package/dist/esm/RenderingEngine/StackViewport.js +1 -0
  27. package/dist/esm/RenderingEngine/StackViewport.js.map +1 -1
  28. package/dist/esm/RenderingEngine/VideoViewport.js +97 -33
  29. package/dist/esm/RenderingEngine/VideoViewport.js.map +1 -1
  30. package/dist/esm/RenderingEngine/Viewport.js +1 -1
  31. package/dist/esm/RenderingEngine/Viewport.js.map +1 -1
  32. package/dist/esm/enums/RequestType.js +1 -0
  33. package/dist/esm/enums/RequestType.js.map +1 -1
  34. package/dist/esm/index.js +2 -2
  35. package/dist/esm/index.js.map +1 -1
  36. package/dist/esm/init.js +12 -1
  37. package/dist/esm/init.js.map +1 -1
  38. package/dist/esm/requestPool/requestPoolManager.js +8 -10
  39. package/dist/esm/requestPool/requestPoolManager.js.map +1 -1
  40. package/dist/esm/utilities/getViewportsWithImageURI.js +6 -5
  41. package/dist/esm/utilities/getViewportsWithImageURI.js.map +1 -1
  42. package/dist/esm/webWorkerManager/webWorkerManager.js +132 -0
  43. package/dist/esm/webWorkerManager/webWorkerManager.js.map +1 -0
  44. package/dist/types/RenderingEngine/StackViewport.d.ts.map +1 -1
  45. package/dist/types/RenderingEngine/VideoViewport.d.ts +15 -2
  46. package/dist/types/RenderingEngine/VideoViewport.d.ts.map +1 -1
  47. package/dist/types/enums/RequestType.d.ts +2 -1
  48. package/dist/types/enums/RequestType.d.ts.map +1 -1
  49. package/dist/types/index.d.ts +2 -2
  50. package/dist/types/index.d.ts.map +1 -1
  51. package/dist/types/init.d.ts +2 -1
  52. package/dist/types/init.d.ts.map +1 -1
  53. package/dist/types/requestPool/requestPoolManager.d.ts +1 -2
  54. package/dist/types/requestPool/requestPoolManager.d.ts.map +1 -1
  55. package/dist/types/types/IVideoViewport.d.ts +6 -1
  56. package/dist/types/types/IVideoViewport.d.ts.map +1 -1
  57. package/dist/types/utilities/getViewportsWithImageURI.d.ts.map +1 -1
  58. package/dist/types/webWorkerManager/webWorkerManager.d.ts +22 -0
  59. package/dist/types/webWorkerManager/webWorkerManager.d.ts.map +1 -0
  60. package/dist/umd/index.js +1 -2
  61. package/dist/umd/index.js.map +1 -1
  62. package/package.json +3 -2
  63. package/src/RenderingEngine/StackViewport.ts +1 -0
  64. package/src/RenderingEngine/VideoViewport.ts +146 -28
  65. package/src/RenderingEngine/Viewport.ts +1 -1
  66. package/src/enums/RequestType.ts +3 -1
  67. package/src/index.ts +2 -0
  68. package/src/init.ts +18 -0
  69. package/src/requestPool/requestPoolManager.ts +9 -13
  70. package/src/types/IVideoViewport.ts +44 -4
  71. package/src/utilities/getViewportsWithImageURI.ts +6 -13
  72. package/src/webWorkerManager/webWorkerManager.js +218 -0
  73. package/dist/umd/index.js.LICENSE.txt +0 -1
@@ -0,0 +1,218 @@
1
+ import * as Comlink from 'comlink';
2
+ import { RequestType } from '../enums/';
3
+ import { RequestPoolManager } from '../requestPool/requestPoolManager';
4
+
5
+ class CentralizedWorkerManager {
6
+ constructor() {
7
+ this.workerRegistry = {};
8
+ this.workerPoolManager = new RequestPoolManager('webworker');
9
+ this.checkIntervalForIdleWorkers = 1000;
10
+ }
11
+
12
+ setCheckIntervalForIdleWorkers(value) {
13
+ this.checkIntervalForIdleWorkers = value;
14
+ }
15
+
16
+ /**
17
+ * Registers a new worker, it doesn't mean that the function will get executed.
18
+ *
19
+ * @param workerName - The name of the worker.
20
+ * @param workerFn - The function that creates a new instance of the worker.
21
+ * @param options - Optional parameters.
22
+ * @param options.maxWorkerInstances - The maximum number of instances of this worker that can be created.
23
+ * For instance if you create a worker with maxWorkerInstances = 2, then only 2 instances of this worker will be created
24
+ * and in case there are 10 tasks that need to be executed, each will get assigned 5 tasks.
25
+ * @param options.overwrite - Whether to overwrite the worker if it's already registered.
26
+ * @param options.autoTerminateOnIdle - Whether to automatically terminate idle workers.
27
+ */
28
+ registerWorker(workerName, workerFn, options = {}) {
29
+ const {
30
+ maxWorkerInstances = 1,
31
+ overwrite = false,
32
+ autoTerminateOnIdle = false,
33
+ } = options;
34
+
35
+ if (this.workerRegistry[workerName] && !overwrite) {
36
+ console.warn(`Worker type '${workerName}' is already registered...`);
37
+ return;
38
+ }
39
+
40
+ if (overwrite && this.workerRegistry[workerName]?.idleCheckIntervalId) {
41
+ clearInterval(this.workerRegistry[workerName].idleCheckIntervalId);
42
+ }
43
+
44
+ const workerProperties = {
45
+ workerFn: null,
46
+ idleCheckIntervalId: null,
47
+ instances: [],
48
+ loadCounters: [],
49
+ lastActiveTime: [],
50
+ // used for termination
51
+ nativeWorkers: [],
52
+ };
53
+
54
+ if (
55
+ (autoTerminateOnIdle && !workerProperties.idleCheckIntervalId) ||
56
+ overwrite
57
+ ) {
58
+ const idleCheckIntervalId = setInterval(() => {
59
+ this.terminateIdleWorkers(workerName, autoTerminateOnIdle);
60
+ }, this.checkIntervalForIdleWorkers);
61
+
62
+ workerProperties.idleCheckIntervalId = idleCheckIntervalId;
63
+ }
64
+
65
+ workerProperties.loadCounters = Array(maxWorkerInstances).fill(0);
66
+ workerProperties.lastActiveTime = Array(maxWorkerInstances).fill(null);
67
+
68
+ for (let i = 0; i < maxWorkerInstances; i++) {
69
+ const worker = workerFn();
70
+ workerProperties.instances.push(Comlink.wrap(worker));
71
+ workerProperties.nativeWorkers.push(worker);
72
+ workerProperties.workerFn = workerFn;
73
+ }
74
+
75
+ this.workerRegistry[workerName] = workerProperties;
76
+ }
77
+
78
+ getNextWorkerAPI(workerName) {
79
+ const workerProperties = this.workerRegistry[workerName];
80
+
81
+ if (!workerProperties) {
82
+ console.error(`Worker type '${workerName}' is not registered.`);
83
+ return null;
84
+ }
85
+
86
+ // Find the worker with the minimum load.
87
+ const workerInstances = workerProperties.instances.filter(
88
+ (instance) => instance !== null
89
+ );
90
+
91
+ let minLoadIndex = 0;
92
+ let minLoadValue = workerProperties.loadCounters[0] || 0;
93
+
94
+ for (let i = 1; i < workerInstances.length; i++) {
95
+ const currentLoadValue = workerProperties.loadCounters[i] || 0;
96
+ if (currentLoadValue < minLoadValue) {
97
+ minLoadIndex = i;
98
+ minLoadValue = currentLoadValue;
99
+ }
100
+ }
101
+
102
+ // Check and recreate the worker if it was terminated.
103
+ if (workerProperties.instances[minLoadIndex] === null) {
104
+ const worker = workerProperties.workerFn();
105
+ workerProperties.instances[minLoadIndex] = Comlink.wrap(worker);
106
+ workerProperties.nativeWorkers[minLoadIndex] = worker;
107
+ }
108
+
109
+ // Update the load counter.
110
+ workerProperties.loadCounters[minLoadIndex] += 1;
111
+
112
+ // return the worker that has the minimum load.
113
+ return {
114
+ api: workerProperties.instances[minLoadIndex],
115
+ index: minLoadIndex,
116
+ };
117
+ }
118
+
119
+ /**
120
+ * Executes a task on a worker.
121
+ *
122
+ * @param workerName - The name of the worker to execute the task on.
123
+ * @param methodName - The name of the method to execute on the worker.
124
+ * @param args - The arguments to pass to the method. Default is an empty object.
125
+ * @param options - An object containing options for the request. Default is an empty object.
126
+ * @param options.requestType - The type of the request. Default is RequestType.Compute.
127
+ * @param options.priority - The priority of the request. Default is 0.
128
+ * @param options.options - Additional options for the request. Default is an empty object.
129
+ *
130
+ * @returns A promise that resolves with the result of the task.
131
+ */
132
+ executeTask(
133
+ workerName,
134
+ methodName,
135
+ args = {},
136
+ { requestType = RequestType.Compute, priority = 0, options = {} } = {}
137
+ ) {
138
+ return new Promise((resolve, reject) => {
139
+ const requestFn = async () => {
140
+ const { api, index } = this.getNextWorkerAPI(workerName);
141
+ if (!api) {
142
+ const error = new Error(
143
+ `No available worker instance for '${workerName}'`
144
+ );
145
+ console.error(error);
146
+ reject(error);
147
+ return;
148
+ }
149
+
150
+ try {
151
+ const results = await api[methodName](args);
152
+
153
+ const workerProperties = this.workerRegistry[workerName];
154
+ workerProperties.lastActiveTime[index] = Date.now();
155
+
156
+ resolve(results);
157
+ } catch (err) {
158
+ console.error(
159
+ `Error executing method '${methodName}' on worker '${workerName}':`,
160
+ err
161
+ );
162
+ reject(err);
163
+ } finally {
164
+ this.workerRegistry[workerName].loadCounters[index]--;
165
+ }
166
+ };
167
+
168
+ this.workerPoolManager.addRequest(
169
+ requestFn,
170
+ requestType,
171
+ options,
172
+ priority
173
+ );
174
+ });
175
+ }
176
+
177
+ terminateIdleWorkers(workerName, idleTimeThreshold) {
178
+ const workerProperties = this.workerRegistry[workerName];
179
+
180
+ const now = Date.now();
181
+
182
+ workerProperties.instances.forEach((workerInstance, index) => {
183
+ // If the worker has not yet executed any task, skip this iteration
184
+ if (workerProperties.lastActiveTime[index] == null) {
185
+ return;
186
+ }
187
+
188
+ const idleTime = now - workerProperties.lastActiveTime[index];
189
+
190
+ // If the worker has been idle for longer than the threshold and it exists
191
+ if (idleTime > idleTimeThreshold && workerInstance !== null) {
192
+ workerInstance[Comlink.releaseProxy]();
193
+ workerProperties.nativeWorkers[index].terminate();
194
+
195
+ workerProperties.instances[index] = null;
196
+ workerProperties.lastActiveTime[index] = null;
197
+ }
198
+ });
199
+ }
200
+
201
+ terminate(workerName) {
202
+ const workerProperties = this.workerRegistry[workerName];
203
+ if (!workerProperties) {
204
+ console.error(`Worker type '${workerName}' is not registered.`);
205
+ return;
206
+ }
207
+
208
+ workerProperties.instances.forEach((workerInstance) => {
209
+ workerInstance[Comlink.releaseProxy]();
210
+ });
211
+
212
+ workerProperties.nativeWorkers.forEach((worker) => {
213
+ worker.terminate();
214
+ });
215
+ }
216
+ }
217
+
218
+ export default CentralizedWorkerManager;
@@ -1 +0,0 @@
1
- /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */