UNPKG

cod-dicomweb-server

Version:

A wadors server proxy that get data from a Cloud Optimized Dicom format.

106 lines (105 loc) 4.37 kB
import { CustomError } from '../../classes/customClasses'; import { createStreamingFileName, readFile, writeFile } from '../../fileAccessSystemUtils'; const fileStreaming = { maxFetchSize: 4 * 1024 * 1024 * 1024, fetchedSize: 0, setMaxFetchSize(size) { if (size > 0) { this.maxFetchSize = size; } }, decreaseFetchedSize(size) { if (size > 0 && size <= this.fetchedSize) { this.fetchedSize -= size; } }, async stream(args, callBack) { const { url, headers, useSharedArrayBuffer, directoryHandle } = args; const controller = new AbortController(); let sharedArraybuffer = null; let fileArraybuffer = null; try { const fileName = createStreamingFileName(url); if (directoryHandle) { const file = await readFile(directoryHandle, fileName); if (file) { callBack({ url, position: file.byteLength, fileArraybuffer: new Uint8Array(file) }); return; } } const response = await fetch(url, { headers: { ...headers }, signal: controller.signal }); if (!response.ok) { throw new CustomError(`HTTP error! status: ${response.status}`); } const reader = response.body?.getReader(); if (!reader) { throw new CustomError('Failed to get reader from response body'); } let result; let completed = false; const totalLength = parseInt(response.headers.get('Content-Length') || '0', 10); const firstChunk = await reader.read(); completed = firstChunk.done; if (!firstChunk.value) { throw new CustomError('The fetched chunks does not have value'); } if (!completed) { let position = firstChunk.value.length; if (this.fetchedSize + position > this.maxFetchSize) { controller.abort(); throw new CustomError(`Maximum size(${this.maxFetchSize}) for fetching files reached`); } this.fetchedSize += position; if (useSharedArrayBuffer) { sharedArraybuffer = new SharedArrayBuffer(totalLength); fileArraybuffer = new Uint8Array(sharedArraybuffer); } else { fileArraybuffer = new Uint8Array(totalLength); } fileArraybuffer.set(firstChunk.value); callBack({ url, position, fileArraybuffer }); while (!completed) { result = await reader.read(); if (result.done) { completed = true; continue; } const chunk = result.value; if (this.fetchedSize + chunk.length > this.maxFetchSize) { sharedArraybuffer = null; fileArraybuffer = null; controller.abort(); throw new CustomError(`Maximum size(${this.maxFetchSize}) for fetching files reached`); } this.fetchedSize += chunk.length; fileArraybuffer.set(chunk, position); position += chunk.length; callBack({ isAppending: true, url, position: position, chunk: !useSharedArrayBuffer ? chunk : undefined }); } if (directoryHandle) { writeFile(directoryHandle, fileName, fileArraybuffer.slice().buffer); } } } catch (error) { const streamingError = new CustomError('fileStreaming.ts: ' + error.message || 'An error occured when streaming'); console.error(streamingError.message, error); throw streamingError; } finally { sharedArraybuffer = null; fileArraybuffer = null; controller.abort(); } } }; export default fileStreaming;