cod-dicomweb-server 1.3.10 → 1.3.12
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/dist/cjs/main.js +1680 -1683
- package/dist/esm/classes/CodDicomWebServer.d.ts +1 -1
- package/dist/esm/classes/CodDicomWebServer.js +15 -15
- package/dist/esm/classes/customClasses.d.ts +1 -0
- package/dist/esm/dataRetrieval/register.d.ts +1 -1
- package/dist/esm/dataRetrieval/register.js +1 -2
- package/dist/esm/dataRetrieval/scripts/fileStreaming.d.ts +1 -4
- package/dist/esm/dataRetrieval/scripts/fileStreaming.js +5 -27
- package/dist/esm/fileManager.d.ts +3 -7
- package/dist/esm/fileManager.js +29 -17
- package/dist/esm/types/codDicomWebServerOptions.d.ts +1 -1
- package/dist/esm/types/fileManagerFile.d.ts +6 -0
- package/dist/esm/types/index.d.ts +1 -1
- package/dist/esm/types/index.js +1 -1
- package/dist/umd/563.js +1 -1
- package/dist/umd/563.js.map +1 -1
- package/dist/umd/846.js +2 -2
- package/dist/umd/846.js.map +1 -1
- package/dist/umd/main.js +3 -3
- package/dist/umd/main.js.map +1 -1
- package/package.json +1 -1
- package/dist/esm/types/fileManagerOptions.d.ts +0 -4
- /package/dist/esm/types/{fileManagerOptions.js → fileManagerFile.js} +0 -0
|
@@ -11,7 +11,7 @@ import { download, getDirectoryHandle } from '../fileAccessSystemUtils';
|
|
|
11
11
|
class CodDicomWebServer {
|
|
12
12
|
filePromises = {};
|
|
13
13
|
options = {
|
|
14
|
-
|
|
14
|
+
maxCacheSize: 4 * 1024 * 1024 * 1024,
|
|
15
15
|
domain: constants.url.DOMAIN,
|
|
16
16
|
enableLocalCache: false
|
|
17
17
|
};
|
|
@@ -19,19 +19,19 @@ class CodDicomWebServer {
|
|
|
19
19
|
metadataManager;
|
|
20
20
|
seriesUidFileUrls = {};
|
|
21
21
|
constructor(args = {}) {
|
|
22
|
-
const {
|
|
23
|
-
this.options.
|
|
22
|
+
const { maxCacheSize, domain, disableWorker, enableLocalCache } = args;
|
|
23
|
+
this.options.maxCacheSize = maxCacheSize || this.options.maxCacheSize;
|
|
24
24
|
this.options.domain = domain || this.options.domain;
|
|
25
25
|
this.options.enableLocalCache = !!enableLocalCache;
|
|
26
26
|
const fileStreamingScriptName = constants.dataRetrieval.FILE_STREAMING_WORKER_NAME;
|
|
27
27
|
const filePartialScriptName = constants.dataRetrieval.FILE_PARTIAL_WORKER_NAME;
|
|
28
|
-
this.fileManager = new FileManager(
|
|
28
|
+
this.fileManager = new FileManager();
|
|
29
29
|
this.metadataManager = new MetadataManager();
|
|
30
30
|
if (disableWorker) {
|
|
31
31
|
const dataRetrievalManager = getDataRetrievalManager();
|
|
32
32
|
dataRetrievalManager.setDataRetrieverMode(Enums.DataRetrieveMode.REQUEST);
|
|
33
33
|
}
|
|
34
|
-
register({ fileStreamingScriptName, filePartialScriptName }
|
|
34
|
+
register({ fileStreamingScriptName, filePartialScriptName });
|
|
35
35
|
}
|
|
36
36
|
setOptions = (newOptions) => {
|
|
37
37
|
Object.keys(newOptions).forEach((key) => {
|
|
@@ -110,10 +110,6 @@ class CodDicomWebServer {
|
|
|
110
110
|
if (pixelDataElement.hadUndefinedLength && pixelDataElement.fragments) {
|
|
111
111
|
({ position: dataOffset, length } = pixelDataElement.fragments[0]);
|
|
112
112
|
}
|
|
113
|
-
else {
|
|
114
|
-
// Adding 8 bytes for 4 bytes tag + 4 bytes length for uncomppressed pixelData
|
|
115
|
-
dataOffset += 8;
|
|
116
|
-
}
|
|
117
113
|
return arraybuffer.slice(dataOffset, dataOffset + length);
|
|
118
114
|
}
|
|
119
115
|
});
|
|
@@ -167,15 +163,11 @@ class CodDicomWebServer {
|
|
|
167
163
|
});
|
|
168
164
|
}
|
|
169
165
|
const directoryHandle = this.options.enableLocalCache && (await getDirectoryHandle());
|
|
170
|
-
const { maxWorkerFetchSize } = this.getOptions();
|
|
171
166
|
const dataRetrievalManager = getDataRetrievalManager();
|
|
172
|
-
const { FILE_STREAMING_WORKER_NAME, FILE_PARTIAL_WORKER_NAME
|
|
167
|
+
const { FILE_STREAMING_WORKER_NAME, FILE_PARTIAL_WORKER_NAME } = constants.dataRetrieval;
|
|
173
168
|
let tarPromise;
|
|
174
169
|
if (!this.filePromises[fileUrl]) {
|
|
175
170
|
tarPromise = new Promise((resolveFile, rejectFile) => {
|
|
176
|
-
if (this.fileManager.getTotalSize() + THRESHOLD > maxWorkerFetchSize) {
|
|
177
|
-
throw new CustomError(`CodDicomWebServer.ts: Maximum size(${maxWorkerFetchSize}) for fetching files reached`);
|
|
178
|
-
}
|
|
179
171
|
const FetchTypeEnum = constants.Enums.FetchType;
|
|
180
172
|
if (fetchType === FetchTypeEnum.API_OPTIMIZED) {
|
|
181
173
|
const handleFirstChunk = (evt) => {
|
|
@@ -255,7 +247,7 @@ class CodDicomWebServer {
|
|
|
255
247
|
rejectRequest(evt.message);
|
|
256
248
|
throw evt.error;
|
|
257
249
|
}
|
|
258
|
-
const { url, position, chunk, isAppending } = evt.data;
|
|
250
|
+
const { url, position, chunk, totalLength, isAppending } = evt.data;
|
|
259
251
|
if (isAppending) {
|
|
260
252
|
if (chunk) {
|
|
261
253
|
this.fileManager.append(url, chunk, position);
|
|
@@ -264,6 +256,14 @@ class CodDicomWebServer {
|
|
|
264
256
|
this.fileManager.setPosition(url, position);
|
|
265
257
|
}
|
|
266
258
|
}
|
|
259
|
+
else {
|
|
260
|
+
// The full empty file including with first chunk have been stored to fileManager
|
|
261
|
+
// by the worker listener in the file promise.
|
|
262
|
+
// So, we check whether the cache exceeded the limit here.
|
|
263
|
+
if (this.fileManager.getTotalSize() > this.options.maxCacheSize) {
|
|
264
|
+
this.fileManager.decacheNecessaryBytes(url, totalLength);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
267
|
if (!requestResolved && url === fileUrl && offsets && position > offsets.endByte) {
|
|
268
268
|
try {
|
|
269
269
|
const file = this.fileManager.get(url, offsets);
|
|
@@ -2,7 +2,7 @@ import { Enums } from '../constants';
|
|
|
2
2
|
import { getDataRetrievalManager } from './dataRetrievalManager';
|
|
3
3
|
import filePartial from './scripts/filePartial';
|
|
4
4
|
import fileStreaming from './scripts/fileStreaming';
|
|
5
|
-
export function register(workerNames
|
|
5
|
+
export function register(workerNames) {
|
|
6
6
|
const { fileStreamingScriptName, filePartialScriptName } = workerNames;
|
|
7
7
|
const dataRetrievalManager = getDataRetrievalManager();
|
|
8
8
|
if (dataRetrievalManager.getDataRetrieverMode() === Enums.DataRetrieveMode.REQUEST) {
|
|
@@ -21,5 +21,4 @@ export function register(workerNames, maxFetchSize) {
|
|
|
21
21
|
});
|
|
22
22
|
dataRetrievalManager.register(filePartialScriptName, partialWorkerFn);
|
|
23
23
|
}
|
|
24
|
-
dataRetrievalManager.executeTask(fileStreamingScriptName, 'setMaxFetchSize', maxFetchSize);
|
|
25
24
|
}
|
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
declare const fileStreaming: {
|
|
2
|
-
maxFetchSize: number;
|
|
3
|
-
fetchedSize: number;
|
|
4
|
-
setMaxFetchSize(size: number): void;
|
|
5
|
-
decreaseFetchedSize(size: number): void;
|
|
6
2
|
stream(args: {
|
|
7
3
|
url: string;
|
|
8
4
|
headers?: Record<string, string>;
|
|
@@ -14,6 +10,7 @@ declare const fileStreaming: {
|
|
|
14
10
|
isAppending?: boolean;
|
|
15
11
|
fileArraybuffer?: Uint8Array;
|
|
16
12
|
chunk?: Uint8Array;
|
|
13
|
+
totalLength: number;
|
|
17
14
|
}) => void): Promise<Uint8Array | void>;
|
|
18
15
|
};
|
|
19
16
|
export default fileStreaming;
|
|
@@ -1,18 +1,6 @@
|
|
|
1
1
|
import { CustomError } from '../../classes/customClasses';
|
|
2
2
|
import { createStreamingFileName, readFile, writeFile } from '../../fileAccessSystemUtils';
|
|
3
3
|
const fileStreaming = {
|
|
4
|
-
maxFetchSize: 4 * 1024 * 1024 * 1024,
|
|
5
|
-
fetchedSize: 0,
|
|
6
|
-
setMaxFetchSize(size) {
|
|
7
|
-
if (size > 0) {
|
|
8
|
-
this.maxFetchSize = size;
|
|
9
|
-
}
|
|
10
|
-
},
|
|
11
|
-
decreaseFetchedSize(size) {
|
|
12
|
-
if (size > 0 && size <= this.fetchedSize) {
|
|
13
|
-
this.fetchedSize -= size;
|
|
14
|
-
}
|
|
15
|
-
},
|
|
16
4
|
async stream(args, callBack) {
|
|
17
5
|
const { url, headers, useSharedArrayBuffer, directoryHandle } = args;
|
|
18
6
|
const controller = new AbortController();
|
|
@@ -23,7 +11,8 @@ const fileStreaming = {
|
|
|
23
11
|
if (directoryHandle) {
|
|
24
12
|
const file = (await readFile(directoryHandle, fileName, { isJson: false }));
|
|
25
13
|
if (file) {
|
|
26
|
-
|
|
14
|
+
const totalLength = file.byteLength;
|
|
15
|
+
callBack({ url, position: totalLength, fileArraybuffer: new Uint8Array(file), totalLength });
|
|
27
16
|
return;
|
|
28
17
|
}
|
|
29
18
|
}
|
|
@@ -48,11 +37,6 @@ const fileStreaming = {
|
|
|
48
37
|
}
|
|
49
38
|
if (!completed) {
|
|
50
39
|
let position = firstChunk.value.length;
|
|
51
|
-
if (this.fetchedSize + position > this.maxFetchSize) {
|
|
52
|
-
controller.abort();
|
|
53
|
-
throw new CustomError(`Maximum size(${this.maxFetchSize}) for fetching files reached`);
|
|
54
|
-
}
|
|
55
|
-
this.fetchedSize += position;
|
|
56
40
|
if (useSharedArrayBuffer) {
|
|
57
41
|
sharedArraybuffer = new SharedArrayBuffer(totalLength);
|
|
58
42
|
fileArraybuffer = new Uint8Array(sharedArraybuffer);
|
|
@@ -61,7 +45,7 @@ const fileStreaming = {
|
|
|
61
45
|
fileArraybuffer = new Uint8Array(totalLength);
|
|
62
46
|
}
|
|
63
47
|
fileArraybuffer.set(firstChunk.value);
|
|
64
|
-
callBack({ url, position, fileArraybuffer });
|
|
48
|
+
callBack({ url, position, fileArraybuffer, totalLength });
|
|
65
49
|
while (!completed) {
|
|
66
50
|
result = await reader.read();
|
|
67
51
|
if (result.done) {
|
|
@@ -69,20 +53,14 @@ const fileStreaming = {
|
|
|
69
53
|
continue;
|
|
70
54
|
}
|
|
71
55
|
const chunk = result.value;
|
|
72
|
-
if (this.fetchedSize + chunk.length > this.maxFetchSize) {
|
|
73
|
-
sharedArraybuffer = null;
|
|
74
|
-
fileArraybuffer = null;
|
|
75
|
-
controller.abort();
|
|
76
|
-
throw new CustomError(`Maximum size(${this.maxFetchSize}) for fetching files reached`);
|
|
77
|
-
}
|
|
78
|
-
this.fetchedSize += chunk.length;
|
|
79
56
|
fileArraybuffer.set(chunk, position);
|
|
80
57
|
position += chunk.length;
|
|
81
58
|
callBack({
|
|
82
59
|
isAppending: true,
|
|
83
60
|
url,
|
|
84
61
|
position: position,
|
|
85
|
-
chunk: !useSharedArrayBuffer ? chunk : undefined
|
|
62
|
+
chunk: !useSharedArrayBuffer ? chunk : undefined,
|
|
63
|
+
totalLength
|
|
86
64
|
});
|
|
87
65
|
}
|
|
88
66
|
if (directoryHandle) {
|
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { FileManagerFile } from './types';
|
|
2
2
|
declare class FileManager {
|
|
3
3
|
private files;
|
|
4
|
-
|
|
5
|
-
constructor({ fileStreamingScriptName }: FileManagerOptions);
|
|
6
|
-
set(url: string, file: {
|
|
7
|
-
data: Uint8Array;
|
|
8
|
-
position: number;
|
|
9
|
-
}): void;
|
|
4
|
+
set(url: string, file: Omit<FileManagerFile, 'lastModified'>): void;
|
|
10
5
|
get(url: string, offsets?: {
|
|
11
6
|
startByte: number;
|
|
12
7
|
endByte: number;
|
|
@@ -17,5 +12,6 @@ declare class FileManager {
|
|
|
17
12
|
getTotalSize(): number;
|
|
18
13
|
remove(url: string): void;
|
|
19
14
|
purge(): void;
|
|
15
|
+
decacheNecessaryBytes(url: string, bytesNeeded: number): number;
|
|
20
16
|
}
|
|
21
17
|
export default FileManager;
|
package/dist/esm/fileManager.js
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
import { getDataRetrievalManager } from './dataRetrieval/dataRetrievalManager';
|
|
2
1
|
class FileManager {
|
|
3
2
|
files = {};
|
|
4
|
-
fileStreamingScriptName;
|
|
5
|
-
constructor({ fileStreamingScriptName }) {
|
|
6
|
-
this.fileStreamingScriptName = fileStreamingScriptName;
|
|
7
|
-
}
|
|
8
3
|
set(url, file) {
|
|
9
|
-
this.files[url] = file;
|
|
4
|
+
this.files[url] = { ...file, lastModified: Date.now() };
|
|
10
5
|
}
|
|
11
6
|
get(url, offsets) {
|
|
12
7
|
if (!this.files[url] || (offsets && this.files[url].position <= offsets.endByte)) {
|
|
@@ -17,6 +12,7 @@ class FileManager {
|
|
|
17
12
|
setPosition(url, position) {
|
|
18
13
|
if (this.files[url]) {
|
|
19
14
|
this.files[url].position = position;
|
|
15
|
+
this.files[url].lastModified = Date.now();
|
|
20
16
|
}
|
|
21
17
|
}
|
|
22
18
|
getPosition(url) {
|
|
@@ -29,24 +25,40 @@ class FileManager {
|
|
|
29
25
|
}
|
|
30
26
|
}
|
|
31
27
|
getTotalSize() {
|
|
32
|
-
return Object.
|
|
33
|
-
return
|
|
28
|
+
return Object.values(this.files).reduce((total, { data }) => {
|
|
29
|
+
return total + data.byteLength;
|
|
34
30
|
}, 0);
|
|
35
31
|
}
|
|
36
32
|
remove(url) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
33
|
+
try {
|
|
34
|
+
delete this.files[url];
|
|
35
|
+
console.log(`Removed ${url} from CodDicomwebServer cache`);
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
console.warn(`Error removing ${url} from CodDicomwebServer cache:`, error);
|
|
41
39
|
}
|
|
42
|
-
const retrievalManager = getDataRetrievalManager();
|
|
43
|
-
retrievalManager.executeTask(this.fileStreamingScriptName, 'decreaseFetchedSize', removedSize);
|
|
44
40
|
}
|
|
45
41
|
purge() {
|
|
42
|
+
const fileURLs = Object.keys(this.files);
|
|
43
|
+
const totalSize = this.getTotalSize();
|
|
44
|
+
fileURLs.forEach((url) => this.remove(url));
|
|
45
|
+
console.log(`Purged ${totalSize - this.getTotalSize()} bytes from CodDicomwebServer cache`);
|
|
46
|
+
}
|
|
47
|
+
decacheNecessaryBytes(url, bytesNeeded) {
|
|
46
48
|
const totalSize = this.getTotalSize();
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
const filesToDelete = [];
|
|
50
|
+
let collectiveSize = 0;
|
|
51
|
+
Object.entries(this.files)
|
|
52
|
+
.sort(([, a], [, b]) => a.lastModified - b.lastModified)
|
|
53
|
+
.forEach(([key, file]) => {
|
|
54
|
+
if (collectiveSize < bytesNeeded && key !== url) {
|
|
55
|
+
filesToDelete.push(key);
|
|
56
|
+
collectiveSize += file.data.byteLength;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
filesToDelete.forEach((key) => this.remove(key));
|
|
60
|
+
console.log(`Decached ${totalSize - this.getTotalSize()} bytes`);
|
|
61
|
+
return collectiveSize;
|
|
50
62
|
}
|
|
51
63
|
}
|
|
52
64
|
export default FileManager;
|
package/dist/esm/types/index.js
CHANGED