cod-dicomweb-server
Version:
A wadors server proxy that get data from a Cloud Optimized Dicom format.
103 lines (102 loc) • 4.28 kB
JavaScript
import constants, { Enums } from '../constants';
import { CustomError } from './customClasses';
export function parseWadorsURL(url, domain) {
if (!url.includes(constants.url.URL_VALIDATION_STRING)) {
return;
}
const filePath = url.split(domain + '/')[1];
const prefix = filePath.split('/studies')[0];
const prefixParts = prefix.split('/');
const bucketName = prefixParts[0];
const bucketPrefix = prefixParts.slice(1).join('/');
const imagePath = filePath.split(prefix + '/')[1];
const imageParts = imagePath.split('/');
const studyInstanceUID = imageParts[1];
const seriesInstanceUID = imageParts[3];
let sopInstanceUID = '', frameNumber = 1, type;
switch (true) {
case imageParts.includes('thumbnail'):
type = Enums.RequestType.THUMBNAIL;
break;
case imageParts.includes('metadata'):
if (imageParts.includes('instances')) {
sopInstanceUID = imageParts[5];
type = Enums.RequestType.INSTANCE_METADATA;
}
else {
type = Enums.RequestType.SERIES_METADATA;
}
break;
case imageParts.includes('frames'):
sopInstanceUID = imageParts[5];
frameNumber = +imageParts[7];
type = Enums.RequestType.FRAME;
break;
default:
throw new CustomError('Invalid type of request');
}
return {
type,
bucketName,
bucketPrefix,
studyInstanceUID,
seriesInstanceUID,
sopInstanceUID,
frameNumber
};
}
export function getFrameDetailsFromMetadata(seriesMetadata, sopInstanceUID, frameIndex, bucketDetails) {
if (!seriesMetadata || !seriesMetadata.cod?.instances) {
throw new CustomError('Invalid seriesMetadata provided.');
}
if (frameIndex === null || frameIndex === undefined) {
throw new CustomError('Frame index is required.');
}
const { domain, bucketName, bucketPrefix } = bucketDetails;
let thumbnailUrl;
if (seriesMetadata.thumbnail) {
const thumbnailGsUtilUri = seriesMetadata.thumbnail.uri;
thumbnailUrl = `${domain}/${thumbnailGsUtilUri.split('gs://')[1]}`;
}
const instanceFound = Object.entries(seriesMetadata.cod.instances).find(([key, instance]) => key === sopInstanceUID)?.[1];
if (!instanceFound) {
return { thumbnailUrl };
}
const { url, uri, headers: offsetHeaders, offset_tables } = instanceFound;
const modifiedUrl = handleUrl(url || uri, domain, bucketName, bucketPrefix);
const { CustomOffsetTable, CustomOffsetTableLengths } = offset_tables;
let sliceStart, sliceEnd, isMultiframe = false;
if (CustomOffsetTable?.length && CustomOffsetTableLengths?.length) {
sliceStart = CustomOffsetTable[frameIndex];
sliceEnd = sliceStart + CustomOffsetTableLengths[frameIndex];
isMultiframe = true;
}
const { start_byte: fileStartByte, end_byte: fileEndByte } = offsetHeaders;
const startByte = sliceStart !== undefined ? fileStartByte + sliceStart : fileStartByte;
const endByte = sliceEnd !== undefined ? fileStartByte + sliceEnd : fileEndByte;
return {
url: modifiedUrl,
startByte,
endByte,
thumbnailUrl,
isMultiframe
};
}
export function handleUrl(url, domain, bucketName, bucketPrefix) {
let modifiedUrl = url;
const matchingExtension = constants.url.FILE_EXTENSIONS.find((extension) => url.includes(extension));
if (matchingExtension) {
const fileParts = url.split(matchingExtension);
modifiedUrl = fileParts[0] + matchingExtension;
}
const filePath = modifiedUrl.split('studies/')[1];
modifiedUrl = `${domain}/${bucketName}/${bucketPrefix ? bucketPrefix + '/' : ''}studies/${filePath}`;
return modifiedUrl;
}
export function createMetadataJsonUrl(params) {
const { domain = constants.url.DOMAIN, bucketName, bucketPrefix, studyInstanceUID, seriesInstanceUID } = params;
if (!bucketName || !bucketPrefix || !studyInstanceUID || !seriesInstanceUID) {
return;
}
return `${domain}/${bucketName}/${bucketPrefix}/studies/${studyInstanceUID}/series/${seriesInstanceUID}/metadata.json`;
}