cod-dicomweb-server
Version:
A wadors server proxy that get data from a Cloud Optimized Dicom format.
150 lines (149 loc) • 5.92 kB
JavaScript
import { get } from 'idb-keyval';
import { FILE_SYSTEM_ROUTES, IDB_DIR_HANDLE_KEY } from './constants/dataRetrieval';
let directoryHandle;
export async function getDirectoryHandle() {
try {
if (!directoryHandle) {
directoryHandle = (await get(IDB_DIR_HANDLE_KEY));
}
if (!directoryHandle) {
directoryHandle = await navigator.storage.getDirectory();
}
return directoryHandle;
}
catch (error) {
console.warn(`Error getting directoryhandle: ${error.message}`);
}
}
async function readJsonFile(directoryHandle, name) {
return await directoryHandle
.getFileHandle(name)
.then((fileHandle) => fileHandle
.getFile()
.then((file) => file.text())
.then((metadataString) => JSON.parse(metadataString)))
.catch(() => null);
}
async function readArrayBufferFile(directoryHandle, name) {
return await directoryHandle
.getFileHandle(name)
.then((fileHandle) => fileHandle.getFile().then((file) => file.arrayBuffer()))
.catch(() => null);
}
export async function readFile(directoryHandle, name, options = {}) {
if (!name) {
return;
}
const pathParts = name.split('/');
let currentDir = directoryHandle;
try {
for (let i = 0; i < pathParts.length - 1; i++) {
currentDir = await currentDir.getDirectoryHandle(pathParts[i], { create: true });
}
const fileName = pathParts.at(-1);
if (options.isJson) {
return readJsonFile(currentDir, fileName);
}
else {
return readArrayBufferFile(currentDir, fileName).catch(async () => {
console.warn(`Error reading the file ${name} from partial folder, trying from full file`);
if (options.offsets && pathParts.includes(FILE_SYSTEM_ROUTES.Partial)) {
try {
pathParts.splice(pathParts.findIndex((part) => part === FILE_SYSTEM_ROUTES.Partial), 1);
currentDir = directoryHandle;
for (let i = 0; i < pathParts.length - 1; i++) {
currentDir = await currentDir.getDirectoryHandle(pathParts[i], { create: true });
}
const convertedFileName = pathParts.at(-1).split('_')[0] + '.tar';
const fileArraybuffer = await readArrayBufferFile(currentDir, convertedFileName);
return fileArraybuffer.slice(options.offsets.startByte, options.offsets.endByte);
}
catch (error) {
console.warn(`Error reading the file ${name}: ${error.message}`);
}
}
});
}
}
catch (error) {
console.warn(`Error reading the file ${name}: ${error.message}`);
}
}
export async function writeFile(directoryHandle, name, file, isJson = false) {
try {
const pathParts = name.split('/');
let currentDir = directoryHandle;
for (let i = 0; i < pathParts.length - 1; i++) {
currentDir = await currentDir.getDirectoryHandle(pathParts[i], { create: true });
}
const fileName = pathParts.at(-1);
const fileHandle = await currentDir.getFileHandle(fileName, { create: true });
// @ts-ignore
const fileWritable = await fileHandle.createWritable();
if (isJson) {
await fileWritable.write(JSON.stringify(file));
}
else {
await fileWritable.write(file);
}
await fileWritable.close();
}
catch (error) {
console.warn(`Error writing the file ${name}: ${error.message}`);
}
}
export function download(fileName, file) {
try {
const blob = new Blob([file], { type: 'application/x-tar' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = fileName;
a.click();
URL.revokeObjectURL(url);
return true;
}
catch (error) {
console.warn(`Error downloading file - ${fileName}: ` + error.message);
return false;
}
}
export async function clearPartialFiles() {
const removePartialFolder = async (dirHandle) => {
// @ts-ignore
for await (const [name, handle] of dirHandle.entries()) {
if (handle.kind === 'directory') {
if (name.toLowerCase() === FILE_SYSTEM_ROUTES.Partial) {
await dirHandle.removeEntry(name, { recursive: true }).catch((e) => console.warn(`Failed to remove ${name}:`, e));
}
else {
// Recurse into other directories
await removePartialFolder(handle);
}
}
}
};
try {
await removePartialFolder(directoryHandle);
}
catch (error) {
console.warn(`Error clearing partial files: ${error.message}`);
}
}
export function parseCachePath(url) {
const urlObj = new URL(url);
const bucketPath = urlObj.pathname.match(/\/(.*?)\/studies/)[1];
const [studyInstanceUID, _, seriesInstanceUID] = urlObj.pathname.match(/studies\/(.*?)(\.tar|\/metadata.json)/)[1].split('/');
return `${bucketPath}/${studyInstanceUID}/${seriesInstanceUID}`;
}
export function createStreamingFileName(url) {
return `${parseCachePath(url)}/${url.split('series/')[1]}`;
}
export function createPartialFileName(url, offsets) {
const seriesInstanceUID = url.match(/series\/(.*?).tar/)[1];
const offsetPart = `${offsets ? `_${offsets?.startByte}_${offsets?.endByte}` : ''}`;
return `${parseCachePath(url)}/${FILE_SYSTEM_ROUTES.Partial}/${seriesInstanceUID}${offsetPart}.dcm`;
}
export function createMetadataFileName(url) {
return `${parseCachePath(url)}/metadata.json`;
}