diff --git a/OHIFViewer/.meteor/packages b/OHIFViewer/.meteor/packages index cea4948af..db08c3217 100644 --- a/OHIFViewer/.meteor/packages +++ b/OHIFViewer/.meteor/packages @@ -39,6 +39,7 @@ ohif:cornerstone-settings ohif:viewerbase ohif:study-list ohif:dicom-services +ohif:dicomweb-client ohif:hanging-protocols ohif:metadata diff --git a/OHIFViewer/.meteor/versions b/OHIFViewer/.meteor/versions index acd3f344d..64dc7a1a8 100644 --- a/OHIFViewer/.meteor/versions +++ b/OHIFViewer/.meteor/versions @@ -86,6 +86,7 @@ ohif:cornerstone@0.0.1 ohif:cornerstone-settings@0.0.1 ohif:design@0.0.1 ohif:dicom-services@0.0.1 +ohif:dicomweb-client@0.0.1 ohif:hanging-protocols@0.0.1 ohif:header@0.0.1 ohif:hotkeys@0.0.1 diff --git a/OHIFViewer/client/components/viewer/viewer.js b/OHIFViewer/client/components/viewer/viewer.js index 96e525f68..67edd5621 100644 --- a/OHIFViewer/client/components/viewer/viewer.js +++ b/OHIFViewer/client/components/viewer/viewer.js @@ -120,7 +120,7 @@ Template.viewer.onCreated(() => { const studyMetadata = new OHIF.metadata.StudyMetadata(study, study.studyInstanceUid); let displaySets = study.displaySets; - if(!study.displaySets) { + if (!study.displaySets) { displaySets = OHIF.viewerbase.sortingManager.getDisplaySets(studyMetadata); study.displaySets = displaySets; } @@ -131,6 +131,9 @@ Template.viewer.onCreated(() => { OHIF.viewer.Studies.insert(study); OHIF.viewer.StudyMetadataList.insert(studyMetadata); OHIF.viewer.data.studyInstanceUids.push(study.studyInstanceUid); + + // Updates WADO-RS metaDataManager + OHIF.viewerbase.updateMetaDataManager(study); }); }); diff --git a/OHIFViewer/client/routes.js b/OHIFViewer/client/routes.js index b84c2ba84..6d6daece8 100644 --- a/OHIFViewer/client/routes.js +++ b/OHIFViewer/client/routes.js @@ -3,7 +3,13 @@ import { OHIF } from 'meteor/ohif:core'; Router.configure({ layoutTemplate: 'layout', - loadingTemplate: 'layout' +}); + +Router.waitOn(function() { + return [ + Meteor.subscribe('servers'), + Meteor.subscribe('currentServer') + ]; }); Router.onBeforeAction('loading'); diff --git a/Packages/ohif-dicom-services/package.js b/Packages/ohif-dicom-services/package.js index 763c3d85a..7fae860dd 100755 --- a/Packages/ohif-dicom-services/package.js +++ b/Packages/ohif-dicom-services/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'ohif:dicom-services', - summary: 'DICOM Services: DICOMWeb and DIMSE C-Service functions', + summary: 'DICOM Services: DIMSE C-Service functions', version: '0.0.1' }); @@ -10,18 +10,6 @@ Package.onUse(function(api) { api.use('http'); api.use('ecmascript'); - // DICOMWeb functions - api.addFiles('server/DICOMWeb/namespace.js', 'server'); - api.addFiles('server/DICOMWeb/getJSON.js', 'server'); - api.addFiles('server/DICOMWeb/getName.js', 'server'); - api.addFiles('server/DICOMWeb/getNumber.js', 'server'); - api.addFiles('server/DICOMWeb/getString.js', 'server'); - api.addFiles('server/DICOMWeb/getModalities.js', 'server'); - api.addFiles('server/DICOMWeb/getAttribute.js', 'server'); - api.addFiles('server/DICOMWeb/getBulkData.js', 'server'); - - api.export('DICOMWeb', 'server'); - // DIMSE functions api.addFiles('server/DIMSE/require.js', 'server'); api.addFiles('server/DIMSE/constants.js', 'server'); diff --git a/Packages/ohif-dicom-services/server/DICOMWeb/getBulkData.js b/Packages/ohif-dicom-services/server/DICOMWeb/getBulkData.js deleted file mode 100644 index 808fad3c4..000000000 --- a/Packages/ohif-dicom-services/server/DICOMWeb/getBulkData.js +++ /dev/null @@ -1,230 +0,0 @@ -import { OHIF } from 'meteor/ohif:core'; - -const ASCII = 'ascii'; -const http = Npm.require('http') -const url = Npm.require('url'); - -function getMultipartContentInfo(headers) { - - let dict = null, - multipartRegex = /^\s*multipart\/[^;]+/g, - contentType = headers['content-type']; - - if (typeof contentType === 'string' && multipartRegex.test(contentType)) { - let match, - pairRegex = /;\s*([^=]+)=([^;\r\n]+)/g; - pairRegex.lastIndex = multipartRegex.lastIndex; - while ((match = pairRegex.exec(contentType)) !== null) { - let key = match[1], value = match[2]; - if (dict === null) { - dict = {}; - } - dict[key] = value; - } - } - - return dict; - -} - -function parseContentHeader(data, offset) { - - let endOfHeader = data.indexOf('\r\n\r\n', offset, ASCII); - - if (endOfHeader < 0 || endOfHeader <= offset || endOfHeader > data.length) { - throw { - name: 'DICOMWebContentParsingError', - message: 'End of content header cannot be determined...' - }; - } - - let match, - header = { - start: offset, - end: endOfHeader + 4, - fields: {} - }, - headerRegex = /([\w\-]+):\s*([^\r\n]+)(?:\r\n)?/g, - headerContentRegex = /\t([^\r\n]+)(?:\r\n)?/g, - headerString = data.toString('ascii', offset, endOfHeader); - - while ((match = headerRegex.exec(headerString)) !== null) { - let key = match[1].toLowerCase(), value = match[2]; - while (headerString.charAt(headerRegex.lastIndex) === '\t') { - headerContentRegex.lastIndex = headerRegex.lastIndex; - if ((match = headerContentRegex.exec(headerString)) !== null) { - headerRegex.lastIndex = headerContentRegex.lastIndex; - value += ' ' + match[1]; - continue; - } - break; - } - header.fields[key] = value; - } - - return header; - -} - -function parseResponse(headers, data) { - - let contentInfo = getMultipartContentInfo(headers); - - if (!contentInfo || !contentInfo.boundary) { - throw { - name: 'DICOMWebContentParsingError', - message: 'Content boundary not specified...' - }; - } - - let boundary = contentInfo.boundary, - delimiter = '--' + boundary + '\r\n', - index = data.indexOf(delimiter, 0, ASCII); - - if (index < 0) { - throw { - name: 'DICOMWebContentParsingError', - message: 'The specified boundary could not be found...' - }; - } - - let closingIndex, closingDelimiter = Buffer.from('\r\n--' + boundary + '--', ASCII); - - index += delimiter.length; - if (data[index] !== 0x0D || data[index + 1] !== 0x0A) { - // multipart content headers are present, so let's parse them... - let contentHeader = parseContentHeader(data, index); - if (contentHeader && contentHeader.end > index) { - if (contentHeader.fields['content-length'] > 0) { - let endOfData = contentHeader.end + parseInt(contentHeader.fields['content-length'], 10); - if (endOfData === data.indexOf(closingDelimiter, endOfData)) { - // content-length is valid... - return data.slice(contentHeader.end, endOfData); - } - } - index = contentHeader.end; - } - } else { - // no headers, the content comes right after... - index += 2; - } - - closingIndex = data.indexOf(closingDelimiter, index); - if (closingIndex < 0 || closingIndex < index) { - throw { - name: 'DICOMWebContentParsingError', - message: 'The end of the content could not be determined...' - }; - } - - return data.slice(index, closingIndex); - -} - -function makeRequest(geturl, options, callback) { - const headers = 'multipart/related; type=application/octet-stream'; - const parsed = url.parse(geturl); - - let requestOpt = { - hostname: parsed.hostname, - headers: { - Accept: headers - }, - path: parsed.path, - method: 'GET', - }; - - let requester; - if (parsed.protocol === 'https:') { - requester = https.request; - - const allowUnauthorizedAgent = new https.Agent({ rejectUnauthorized: false }); - requestOpt.agent = allowUnauthorizedAgent - } else { - requester = http.request; - } - - if (parsed.port) { - requestOpt.port = parsed.port; - } - - if (options.auth) { - requestOpt.auth = options.auth; - } - - let req = requester(requestOpt, function(resp) { - - let data = []; - - if (resp.statusCode !== 200) { - callback({ - name: 'DICOMWebRequestError', - message: `Unexpected status code for DICOMWeb response (${resp.statusCode})...` - }, null); - } - - resp.on('data', function(chunk) { - data.push(chunk); - }); - - resp.on('error', function (responseError) { - OHIF.log.error('There was an error in the DICOMWeb Server'); - OHIF.log.error(responseError.stack); - OHIF.log.trace(); - - callback(responseError, null); - }); - - resp.on('end', function() { - try { - callback(null, parseResponse(resp.headers, Buffer.concat(data))); - } catch (error) { - callback(error, null); - } - }); - - }); - - req.on('error', function (requestError) { - OHIF.log.error('Couldn\'t connect to DICOMWeb server.'); - OHIF.log.error('Make sure you are trying to connect to the right server and that it is up and running.'); - OHIF.log.error(requestError.stack); - OHIF.log.trace(); - - callback(requestError, null); - }); - - req.end(); - -} - -const makeRequestSync = Meteor.wrapAsync(makeRequest); - -// TODO: Unify this stuff with the getJSON code -DICOMWeb.getBulkData = function(geturl, options) { - - if (options && options.logRequests) { - OHIF.log.info(geturl); - } - - if (options && options.logTiming) { - console.time(geturl); - } - - var result = makeRequestSync(geturl, options); - - if (options && options.logTiming) { - console.timeEnd(geturl); - } - - if (options && options.logResponses) { - OHIF.log.info(result); - } - - if (!Buffer.isBuffer(result)) { - throw result; - } - - return result; - -}; diff --git a/Packages/ohif-dicom-services/server/DICOMWeb/getJSON.js b/Packages/ohif-dicom-services/server/DICOMWeb/getJSON.js deleted file mode 100644 index d520048bd..000000000 --- a/Packages/ohif-dicom-services/server/DICOMWeb/getJSON.js +++ /dev/null @@ -1,110 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { OHIF } from 'meteor/ohif:core'; - -const http = Npm.require('http'); -const https = Npm.require('https'); -const url = Npm.require('url'); - -function makeRequest(geturl, options, callback) { - const parsed = url.parse(geturl); - const jsonHeaders = ['application/json', 'application/dicom+json']; - - let requestOpt = { - hostname: parsed.hostname, - headers: { - Accept: 'application/json' - }, - path: parsed.path, - method: 'GET' - }; - - let requester; - if (parsed.protocol === 'https:') { - requester = https.request; - - const allowUnauthorizedAgent = new https.Agent({ rejectUnauthorized: false }); - requestOpt.agent = allowUnauthorizedAgent; - } else { - requester = http.request; - } - - if (parsed.port) { - requestOpt.port = parsed.port; - } - - if (options.auth) { - requestOpt.auth = options.auth; - } - - if (options.headers) { - Object.keys(options.headers).forEach(key => { - const value = options.headers[key]; - requestOpt.headers[key] = value; - }); - } - - const req = requester(requestOpt, function(resp) { - // TODO: handle errors with 400+ code - const contentType = (resp.headers['content-type'] || '').split(';')[0]; - if (jsonHeaders.indexOf(contentType) === -1) { - const errorMessage = `We only support json but "${contentType}" was sent by the server`; - callback(new Error(errorMessage), null); - return; - } - - let output = ''; - - resp.setEncoding('utf8'); - - resp.on('data', function(chunk){ - output += chunk; - }); - - resp.on('error', function (responseError) { - OHIF.log.error('There was an error in the DICOMWeb Server') - OHIF.log.error(error.stack); - OHIF.log.trace(); - - callback(new Meteor.Error('server-internal-error', responseError.message), null); - }); - - resp.on('end', function(){ - callback(null, { data: JSON.parse(output) }); - }); - }); - - req.on('error', function (requestError) { - OHIF.log.error('Couldn\'t connect to DICOMWeb server.'); - OHIF.log.error('Make sure you are trying to connect to the right server and that it is up and running.'); - OHIF.log.error(requestError.stack); - OHIF.log.trace(); - - callback(new Meteor.Error('server-connection-error', requestError.message), null); - }); - - req.end(); -} - -const makeRequestSync = Meteor.wrapAsync(makeRequest); - -DICOMWeb.getJSON = function(geturl, options) { - if (options && options.logRequests) { - OHIF.log.info(geturl); - } - - if (options && options.logTiming) { - console.time(geturl); - } - - const result = makeRequestSync(geturl, options); - - if (options && options.logTiming) { - console.timeEnd(geturl); - } - - if (options && options.logResponses) { - OHIF.log.info(result); - } - - return result; -}; diff --git a/Packages/ohif-dicom-services/server/DICOMWeb/namespace.js b/Packages/ohif-dicom-services/server/DICOMWeb/namespace.js deleted file mode 100644 index 7ee760f79..000000000 --- a/Packages/ohif-dicom-services/server/DICOMWeb/namespace.js +++ /dev/null @@ -1 +0,0 @@ -DICOMWeb = {}; diff --git a/Packages/ohif-dicomweb-client/package.js b/Packages/ohif-dicomweb-client/package.js new file mode 100644 index 000000000..c4c806088 --- /dev/null +++ b/Packages/ohif-dicomweb-client/package.js @@ -0,0 +1,21 @@ +Package.describe({ + name: 'ohif:dicomweb-client', + summary: 'DICOM Services: DICOMWeb', + version: '0.0.1' +}); + +Npm.depends({ + 'url-parse': '1.4.1', + 'isomorphic-fetch': '2.2.1', +}); + +Package.onUse(function(api) { + api.versionsFrom('1.6'); + + api.use('ecmascript'); + + // DICOMWeb functions + api.mainModule('src/index.js'); + + api.export('DICOMWeb'); +}); diff --git a/Packages/ohif-dicomweb-client/src/get.js b/Packages/ohif-dicomweb-client/src/get.js new file mode 100644 index 000000000..3bceb0661 --- /dev/null +++ b/Packages/ohif-dicomweb-client/src/get.js @@ -0,0 +1,33 @@ +import makeRequest from "./makeRequest"; + +/** + * Make a request to the URL given a set of options. + * This function will add optional timing, request, and respone logging. + * + * @param {String} url + * @param {Object} options + * @return {Promise<*>} + */ +const get = async function get(url, options) { + if (options.logRequests) { + console.log(url); + } + + if (options.logTiming) { + console.time(url); + } + + const result = await makeRequest(url, options); + + if (options.logTiming) { + console.timeEnd(url); + } + + if (options.logResponses) { + console.info(result); + } + + return result; +} + +export default get; diff --git a/Packages/ohif-dicom-services/server/DICOMWeb/getAttribute.js b/Packages/ohif-dicomweb-client/src/getAttribute.js similarity index 93% rename from Packages/ohif-dicom-services/server/DICOMWeb/getAttribute.js rename to Packages/ohif-dicomweb-client/src/getAttribute.js index bcb2a96e4..ea6f316b1 100644 --- a/Packages/ohif-dicom-services/server/DICOMWeb/getAttribute.js +++ b/Packages/ohif-dicomweb-client/src/getAttribute.js @@ -5,7 +5,7 @@ * @param [defaultValue] - The value to return if the element is not present * @returns {*} */ -DICOMWeb.getAttribute = function(element, defaultValue) { +const getAttribute = function(element, defaultValue) { if (!element) { return defaultValue; } @@ -42,3 +42,5 @@ function convertToInt(input) { return parseInt(output, 16); } + +export default getAttribute; diff --git a/Packages/ohif-dicomweb-client/src/getBulkData.js b/Packages/ohif-dicomweb-client/src/getBulkData.js new file mode 100644 index 000000000..dc576fc17 --- /dev/null +++ b/Packages/ohif-dicomweb-client/src/getBulkData.js @@ -0,0 +1,133 @@ +import get from './get.js'; + +const ASCII = 'ascii'; + +function getMultipartContentInfo(headers) { + const multipartRegex = /^\s*multipart\/[^;]+/g; + const contentType = headers.get('content-type'); + let dict = null; + + if (typeof contentType === 'string' && multipartRegex.test(contentType)) { + let match; + let pairRegex = /;\s*([^=]+)=([^;\r\n]+)/g; + + pairRegex.lastIndex = multipartRegex.lastIndex; + while ((match = pairRegex.exec(contentType)) !== null) { + let key = match[1] + let value = match[2]; + + if (dict === null) { + dict = {}; + } + dict[key] = value; + } + } + + return dict; +} + +function parseContentHeader(data, offset) { + const endOfHeader = data.indexOf('\r\n\r\n', offset); + + if (endOfHeader < 0 || endOfHeader <= offset || endOfHeader > data.length) { + throw new Error('End of content header cannot be determined...'); + } + + const header = { + start: offset, + end: endOfHeader + 4, + fields: {} + }; + const headerRegex = /([\w\-]+):\s*([^\r\n]+)(?:\r\n)?/g; + const headerContentRegex = /\t([^\r\n]+)(?:\r\n)?/g; + const headerString = data.slice(offset, endOfHeader); + + let match; + + while ((match = headerRegex.exec(headerString)) !== null) { + const key = match[1].toLowerCase(), value = match[2]; + + while (headerString.charAt(headerRegex.lastIndex) === '\t') { + headerContentRegex.lastIndex = headerRegex.lastIndex; + + if ((match = headerContentRegex.exec(headerString)) !== null) { + headerRegex.lastIndex = headerContentRegex.lastIndex; + value += ' ' + match[1]; + continue; + } + + break; + } + header.fields[key] = value; + } + + return header; + +} + +function toBytes(input) { + const data = []; + for (let i = 0; i < input.length; i++){ + data.push(input.charCodeAt(i)); + } + + return data; +} + + +function parseResponse(headers, data) { + const contentInfo = getMultipartContentInfo(headers); + + if (!contentInfo || !contentInfo.boundary) { + throw new Error('Content boundary not specified...'); + } + + const boundary = contentInfo.boundary; + const delimiter = '--' + boundary + '\r\n'; + let index = data.indexOf(delimiter, 0, ASCII); + + if (index < 0) { + throw new Error('DICOMWeb: The specified boundary could not be found...'); + } + + let closingIndex + let closingDelimiter = '\r\n--' + boundary + '--'; + + index += delimiter.length; + if (data[index] !== 0x0D || data[index + 1] !== 0x0A) { + // multipart content headers are present, so let's parse them... + let contentHeader = parseContentHeader(data, index); + if (contentHeader && contentHeader.end > index) { + if (contentHeader.fields['content-length'] > 0) { + let endOfData = contentHeader.end + parseInt(contentHeader.fields['content-length'], 10); + if (endOfData === data.indexOf(closingDelimiter, endOfData)) { + // content-length is valid... + return data.slice(contentHeader.end, endOfData); + } + } + index = contentHeader.end; + } + } else { + // no headers, the content comes right after... + index += 2; + } + + closingIndex = data.indexOf(closingDelimiter, index); + if (closingIndex < 0 || closingIndex < index) { + throw new Error('DICOMWeb: The end of the content could not be determined...') + } + + return toBytes(data.slice(index, closingIndex)); +} + +const getBulkData = async function(url, options = {}) { + options.headers = options.headers || {}; + options.headers.Accept = 'multipart/related; type=application/octet-stream'; + + const response = await get(url, options); + const data = await response.text(); + + return parseResponse(response.headers, data); +} + +export default getBulkData; diff --git a/Packages/ohif-dicomweb-client/src/getJSON.js b/Packages/ohif-dicomweb-client/src/getJSON.js new file mode 100644 index 000000000..69480f0ba --- /dev/null +++ b/Packages/ohif-dicomweb-client/src/getJSON.js @@ -0,0 +1,16 @@ +import get from './get.js'; +import getAttribute from "./getAttribute"; + +const getJSON = async function (url, options) { + options.headers = options.headers || {}; + options.headers.Accept = 'application/json'; + return get(url, options).then(response => { + if (!(response instanceof Response)) { + return ''; + } + + return response.json(); + }); +}; + +export default getJSON; diff --git a/Packages/ohif-dicom-services/server/DICOMWeb/getModalities.js b/Packages/ohif-dicomweb-client/src/getModalities.js similarity index 86% rename from Packages/ohif-dicom-services/server/DICOMWeb/getModalities.js rename to Packages/ohif-dicomweb-client/src/getModalities.js index 672c7da7d..a80525c5a 100644 --- a/Packages/ohif-dicom-services/server/DICOMWeb/getModalities.js +++ b/Packages/ohif-dicomweb-client/src/getModalities.js @@ -1,4 +1,4 @@ -DICOMWeb.getModalities = function(modality, modalitiesInStudy) { +const getModalities = function(modality, modalitiesInStudy) { var modalities = {}; if (modality) { modalities = modality; @@ -19,3 +19,5 @@ DICOMWeb.getModalities = function(modality, modalitiesInStudy) { } return modalities; }; + +export default getModalities; diff --git a/Packages/ohif-dicom-services/server/DICOMWeb/getName.js b/Packages/ohif-dicomweb-client/src/getName.js similarity index 93% rename from Packages/ohif-dicom-services/server/DICOMWeb/getName.js rename to Packages/ohif-dicomweb-client/src/getName.js index 4070c4757..3256633a6 100644 --- a/Packages/ohif-dicom-services/server/DICOMWeb/getName.js +++ b/Packages/ohif-dicomweb-client/src/getName.js @@ -5,7 +5,7 @@ * @param [defaultValue] - The default value to return if the element is not found * @returns {*} */ -DICOMWeb.getName = function(element, defaultValue) { +export default function getName(element, defaultValue) { if (!element) { return defaultValue; } diff --git a/Packages/ohif-dicom-services/server/DICOMWeb/getNumber.js b/Packages/ohif-dicomweb-client/src/getNumber.js similarity index 91% rename from Packages/ohif-dicom-services/server/DICOMWeb/getNumber.js rename to Packages/ohif-dicomweb-client/src/getNumber.js index c80357747..a8c7ce5d6 100644 --- a/Packages/ohif-dicom-services/server/DICOMWeb/getNumber.js +++ b/Packages/ohif-dicomweb-client/src/getNumber.js @@ -4,7 +4,7 @@ * @param [defaultValue] - The default value to return if the element does not exist * @returns {*} */ -DICOMWeb.getNumber = function(element, defaultValue) { +export default function getNumber(element, defaultValue) { if (!element) { return defaultValue; } diff --git a/Packages/ohif-dicom-services/server/DICOMWeb/getString.js b/Packages/ohif-dicomweb-client/src/getString.js similarity index 93% rename from Packages/ohif-dicom-services/server/DICOMWeb/getString.js rename to Packages/ohif-dicomweb-client/src/getString.js index 904e354d5..07c1823ae 100644 --- a/Packages/ohif-dicom-services/server/DICOMWeb/getString.js +++ b/Packages/ohif-dicomweb-client/src/getString.js @@ -5,7 +5,7 @@ * @param [defaultValue] - The value to return if the element is not present * @returns {*} */ -DICOMWeb.getString = function(element, defaultValue) { +export default function getString(element, defaultValue) { if (!element) { return defaultValue; } diff --git a/Packages/ohif-dicomweb-client/src/index.js b/Packages/ohif-dicomweb-client/src/index.js new file mode 100644 index 000000000..c7a0c1d78 --- /dev/null +++ b/Packages/ohif-dicomweb-client/src/index.js @@ -0,0 +1,23 @@ +import get from './get.js'; +import getAttribute from './getAttribute.js'; +import getBulkData from './getBulkData.js'; +import getJSON from './getJSON.js'; +import getModalities from './getModalities.js'; +import getName from './getName.js'; +import getNumber from './getNumber.js'; +import getString from './getString.js'; +import makeRequest from './makeRequest.js'; + +const DICOMWeb = { + get, + getAttribute, + getBulkData, + getJSON, + getModalities, + getName, + getNumber, + getString, + makeRequest +}; + +export { DICOMWeb }; diff --git a/Packages/ohif-dicomweb-client/src/makeRequest.js b/Packages/ohif-dicomweb-client/src/makeRequest.js new file mode 100644 index 000000000..e820157b4 --- /dev/null +++ b/Packages/ohif-dicomweb-client/src/makeRequest.js @@ -0,0 +1,60 @@ +import { Meteor } from "meteor/meteor"; +import URL from 'url-parse'; +import 'isomorphic-fetch'; + +async function makeRequest(url, options) { + const parsed = new URL(url); + + let requestOpt = { + method: 'GET', + headers: {} + }; + + // TODO: Clean this up + const accessToken = false //Meteor.user().services.keycloak.accessToken; + if (accessToken) { + requestOpt.headers = { + Authorization: `Bearer ${accessToken}` + }; + } else if (requestOpt.auth) { + requestOpt.headers = { + Authorization: requestOpt.auth + }; + } + + if (options.headers) { + Object.keys(options.headers).forEach(key => { + requestOpt.headers[key] = options.headers[key]; + }); + } + + return new Promise((resolve, reject) => { + // TODO: Kept getting weird build errors from RegExp + const isAbsolute = parsed.href.indexOf('http://') === 0 || parsed.href.indexOf('https://'); + + let url = parsed.href; + + if (isAbsolute === false) { + url = Meteor.absoluteUrl(parsed.href); + } + + fetch(url, requestOpt).then((response) => { + if (response.status >= 400) { + reject(new Error(response.status)); + } + + if (response.status === 204) { + resolve([]); + } else { + // TODO: Handle 204 no content + resolve(response); + } + }, (error) => { + console.error('There was an error in the DICOMWeb Server'); + + reject(new Error(error)); + }); + }); +} + +export default makeRequest; diff --git a/Packages/ohif-servers/both/schema/servers.js b/Packages/ohif-servers/both/schema/servers.js index 883cdcfe7..aa90dd1d5 100644 --- a/Packages/ohif-servers/both/schema/servers.js +++ b/Packages/ohif-servers/both/schema/servers.js @@ -29,6 +29,12 @@ export const DICOMWebRequestOptions = new SimpleSchema({ defaultValue: 'orthanc:orthanc', optional: true }, + requestFromBrowser: { + type: Boolean, + label: 'Make DICOMWeb requests from the Browser', + defaultValue: false, + optional: true + }, logRequests: { type: Boolean, defaultValue: true, @@ -76,7 +82,7 @@ export const DICOMWebServer = new SimpleSchema({ }, qidoSupportsIncludeField: { type: Boolean, - label: 'QIDO supports including fields', + label: 'QIDO supports "includefield" query key', defaultValue: false }, requestOptions: { diff --git a/Packages/ohif-servers/client/components/serverInformation/serverInformationDicomWeb/serverInformationDicomWeb.html b/Packages/ohif-servers/client/components/serverInformation/serverInformationDicomWeb/serverInformationDicomWeb.html index 727bc91af..97429706c 100644 --- a/Packages/ohif-servers/client/components/serverInformation/serverInformationDicomWeb/serverInformationDicomWeb.html +++ b/Packages/ohif-servers/client/components/serverInformation/serverInformationDicomWeb/serverInformationDicomWeb.html @@ -4,11 +4,11 @@ {{>inputText labelClass='form-group' key='wadoUriRoot'}}
- {{>inputText labelClass='form-group' key='wadoRoot'}} + {{>inputSelect labelClass='form-group' key='imageRendering' hideSearch=true + options=(clone placeholder='Select an option')}}
- {{>inputSelect labelClass='form-group' key='imageRendering' hideSearch=true - options=(clone placeholder='Select an option')}} + {{>inputText labelClass='form-group' key='wadoRoot'}}
{{>inputSelect labelClass='form-group' key='thumbnailRendering' hideSearch=true @@ -30,9 +30,12 @@

Request options

- {{#group class='row' key='requestOptions'}} + {{#group class='row p-y-1' key='requestOptions'}}
{{>inputText labelClass='form-group' key='auth'}} +
+ {{>inputCheckbox key='requestFromBrowser'}} +
Logging options diff --git a/Packages/ohif-studies/imports/both/index.js b/Packages/ohif-studies/imports/both/index.js index e69de29bb..5783456aa 100644 --- a/Packages/ohif-studies/imports/both/index.js +++ b/Packages/ohif-studies/imports/both/index.js @@ -0,0 +1,2 @@ +import './lib'; +import './services'; diff --git a/Packages/ohif-studies/imports/server/lib/encodeQueryData.js b/Packages/ohif-studies/imports/both/lib/encodeQueryData.js similarity index 100% rename from Packages/ohif-studies/imports/server/lib/encodeQueryData.js rename to Packages/ohif-studies/imports/both/lib/encodeQueryData.js diff --git a/Packages/ohif-studies/imports/server/lib/index.js b/Packages/ohif-studies/imports/both/lib/index.js similarity index 50% rename from Packages/ohif-studies/imports/server/lib/index.js rename to Packages/ohif-studies/imports/both/lib/index.js index 108c39eed..8271ccc98 100644 --- a/Packages/ohif-studies/imports/server/lib/index.js +++ b/Packages/ohif-studies/imports/both/lib/index.js @@ -1 +1,2 @@ import './encodeQueryData.js'; +import './parseFloatArray.js'; diff --git a/Packages/ohif-studies/imports/server/lib/parseFloatArray.js b/Packages/ohif-studies/imports/both/lib/parseFloatArray.js similarity index 100% rename from Packages/ohif-studies/imports/server/lib/parseFloatArray.js rename to Packages/ohif-studies/imports/both/lib/parseFloatArray.js diff --git a/Packages/ohif-studies/imports/both/services/index.js b/Packages/ohif-studies/imports/both/services/index.js new file mode 100644 index 000000000..8808a8ee6 --- /dev/null +++ b/Packages/ohif-studies/imports/both/services/index.js @@ -0,0 +1,6 @@ +import './namespace'; + +// DICOMWeb instance, study, and metadata retrieval +import './qido/instances.js'; +import './qido/studies.js'; +import './wado/retrieveMetadata.js'; diff --git a/Packages/ohif-studies/imports/both/services/namespace.js b/Packages/ohif-studies/imports/both/services/namespace.js new file mode 100644 index 000000000..1c6f6b75d --- /dev/null +++ b/Packages/ohif-studies/imports/both/services/namespace.js @@ -0,0 +1,6 @@ +import { OHIF } from 'meteor/ohif:core'; + +OHIF.studies.services = { + QIDO: {}, + WADO: {} +}; diff --git a/Packages/ohif-studies/imports/server/services/qido/instances.js b/Packages/ohif-studies/imports/both/services/qido/instances.js similarity index 98% rename from Packages/ohif-studies/imports/server/services/qido/instances.js rename to Packages/ohif-studies/imports/both/services/qido/instances.js index 8421055cc..e13ae54ea 100644 --- a/Packages/ohif-studies/imports/server/services/qido/instances.js +++ b/Packages/ohif-studies/imports/both/services/qido/instances.js @@ -1,4 +1,5 @@ import { OHIF } from 'meteor/ohif:core'; +import { DICOMWeb } from 'meteor/ohif:dicomweb-client'; /** * Creates a QIDO URL given the server settings and a study instance UID diff --git a/Packages/ohif-studies/imports/server/services/qido/studies.js b/Packages/ohif-studies/imports/both/services/qido/studies.js similarity index 92% rename from Packages/ohif-studies/imports/server/services/qido/studies.js rename to Packages/ohif-studies/imports/both/services/qido/studies.js index 35766b9f5..24b39e1ae 100644 --- a/Packages/ohif-studies/imports/server/services/qido/studies.js +++ b/Packages/ohif-studies/imports/both/services/qido/studies.js @@ -1,4 +1,5 @@ import { OHIF } from 'meteor/ohif:core'; +import { DICOMWeb } from 'meteor/ohif:dicomweb-client'; /** * Creates a QIDO date string for a date range query @@ -99,13 +100,13 @@ function resultDataToStudies(resultData) { OHIF.studies.services.QIDO.Studies = (server, filter) => { const url = filterToQIDOURL(server, filter); - try { - const result = DICOMWeb.getJSON(url, server.requestOptions); + return new Promise((resolve, reject) => { + console.warn(DICOMWeb); - return resultDataToStudies(result.data); - } catch (error) { - OHIF.log.trace(); + DICOMWeb.getJSON(url, server.requestOptions).then(result => { + const studies = resultDataToStudies(result); - throw error; - } + resolve(studies); + }, reject); + }); }; diff --git a/Packages/ohif-studies/imports/server/services/wado/retrieveMetadata.js b/Packages/ohif-studies/imports/both/services/wado/retrieveMetadata.js similarity index 82% rename from Packages/ohif-studies/imports/server/services/wado/retrieveMetadata.js rename to Packages/ohif-studies/imports/both/services/wado/retrieveMetadata.js index 5a458e198..3f5475cef 100644 --- a/Packages/ohif-studies/imports/server/services/wado/retrieveMetadata.js +++ b/Packages/ohif-studies/imports/both/services/wado/retrieveMetadata.js @@ -1,4 +1,5 @@ import { OHIF } from 'meteor/ohif:core'; +import { DICOMWeb } from 'meteor/ohif:dicomweb-client'; import { parseFloatArray } from '../../lib/parseFloatArray'; /** @@ -67,9 +68,8 @@ function buildInstanceWadoUrl(server, studyInstanceUid, seriesInstanceUid, sopIn params.push('transferSyntax=*'); const paramString = params.join('&'); - const uri = encodeURIComponent(paramString); - return `${server.wadoUriRoot}?${uri}`; + return `${server.wadoUriRoot}?${paramString}`; } function buildInstanceWadoRsUri(server, studyInstanceUid, seriesInstanceUid, sopInstanceUid) { @@ -106,17 +106,19 @@ function getPaletteColor(server, instance, tag, lutDescriptor) { const numLutEntries = lutDescriptor[0]; const bits = lutDescriptor[2]; const uri = WADOProxy.convertURL(instance[tag].BulkDataURI, server) - const data = DICOMWeb.getBulkData(uri); + const bulkDataPromise = DICOMWeb.getBulkData(uri); - for (var i = 0; i < numLutEntries; i++) { - if(bits === 16) { - lut[i] = data.readUInt16LE(i*2); - } else { - lut[i] = data.readUInt8(i); + return bulkDataPromise.then(data => { + for (var i = 0; i < numLutEntries; i++) { + if(bits === 16) { + lut[i] = data[i * 65536] + data[i + 1]; + } else { + lut[i] = data[i]; + } } - } - return lut; + return lut; + }) } /** @@ -126,38 +128,33 @@ function getPaletteColor(server, instance, tag, lutDescriptor) { * @param instance {Object} The retrieved instance metadata; * @returns {String} The ReferenceSOPInstanceUID */ -function getPaletteColors(server, instance, lutDescriptor) { +async function getPaletteColors(server, instance, lutDescriptor) { + let entry = null; + let paletteUID = DICOMWeb.getString(instance['00281199']); - let entry = null, - paletteUID = DICOMWeb.getString(instance['00281199']); - - if (paletteColorCache.isValidUID(paletteUID)) { - entry = paletteColorCache.get(paletteUID); - } else { - paletteUID = null; - } - - if (!entry) { - // no entry on cache... Fetch remote data. - try { - let r, g, b; - r = getPaletteColor(server, instance, '00281201', lutDescriptor); - g = getPaletteColor(server, instance, '00281202', lutDescriptor);; - b = getPaletteColor(server, instance, '00281203', lutDescriptor);; - - entry = { red: r, green: g, blue: b }; - if (paletteUID !== null) { - // when paletteUID is present, the entry can be cached... - entry.uid = paletteUID; - paletteColorCache.add(entry); - } - } catch (error) { - OHIF.log.error(`(${error.name}) ${error.message}`); + return new Promise((resolve, reject) => { + if (paletteColorCache.isValidUID(paletteUID)) { + entry = paletteColorCache.get(paletteUID); + return resolve(entry); } - } - return entry; + // no entry in cache... Fetch remote data. + const r = getPaletteColor(server, instance, '00281201', lutDescriptor); + const g = getPaletteColor(server, instance, '00281202', lutDescriptor);; + const b = getPaletteColor(server, instance, '00281203', lutDescriptor);; + const promises = [r, g, b]; + + Promise.all(promises).then((args) => { + entry = { red: r, green: g, blue: b }; + + // when paletteUID is present, the entry can be cached... + entry.uid = paletteUID; + paletteColorCache.add(entry); + + resolve(entry); + }); + }); } function getFrameIncrementPointer(element) { @@ -204,21 +201,27 @@ function getRadiopharmaceuticalInfo(instance) { * @param resultData * @returns {{seriesList: Array, patientName: *, patientId: *, accessionNumber: *, studyDate: *, modalities: *, studyDescription: *, imageCount: *, studyInstanceUid: *}} */ -function resultDataToStudyMetadata(server, studyInstanceUid, resultData) { - var seriesMap = {}; - var seriesList = []; +async function resultDataToStudyMetadata(server, studyInstanceUid, resultData) { + const seriesMap = {}; + const seriesList = []; + + if (!WADOProxy) { + WADOProxy = { + convertURL: (a => a) + }; + } if (!resultData.length) { return; } - var anInstance = resultData[0]; + const anInstance = resultData[0]; if (!anInstance) { return; } - var studyData = { - seriesList: seriesList, + const studyData = { + seriesList, patientName: DICOMWeb.getName(anInstance['00100010']), patientId: DICOMWeb.getString(anInstance['00100020']), patientAge: DICOMWeb.getNumber(anInstance['00101010']), @@ -233,7 +236,7 @@ function resultDataToStudyMetadata(server, studyInstanceUid, resultData) { institutionName: DICOMWeb.getString(anInstance['00080080']) }; - resultData.forEach(function(instance) { + await Promise.all(resultData.map(async function(instance) { var seriesInstanceUid = DICOMWeb.getString(instance['0020000E']); var series = seriesMap[seriesInstanceUid]; if (!series) { @@ -250,17 +253,16 @@ function resultDataToStudyMetadata(server, studyInstanceUid, resultData) { seriesList.push(series); } - var sopInstanceUid = DICOMWeb.getString(instance['00080018']); - + const sopInstanceUid = DICOMWeb.getString(instance['00080018']); const wadouri = buildInstanceWadoUrl(server, studyInstanceUid, seriesInstanceUid, sopInstanceUid); const baseWadoRsUri = buildInstanceWadoRsUri(server, studyInstanceUid, seriesInstanceUid, sopInstanceUid); const wadorsuri = buildInstanceFrameWadoRsUri(server, studyInstanceUid, seriesInstanceUid, sopInstanceUid); - var instanceSummary = { + const instanceSummary = { imageType: DICOMWeb.getString(instance['00080008']), sopClassUid: DICOMWeb.getString(instance['00080016']), modality: DICOMWeb.getString(instance['00080060']), - sopInstanceUid: sopInstanceUid, + sopInstanceUid, instanceNumber: DICOMWeb.getNumber(instance['00200013']), imagePositionPatient: DICOMWeb.getString(instance['00200032']), imageOrientationPatient: DICOMWeb.getString(instance['00200037']), @@ -312,12 +314,13 @@ function resultDataToStudyMetadata(server, studyInstanceUid, resultData) { const redPaletteColorLookupTableDescriptor = parseFloatArray(DICOMWeb.getString(instance['00281101'])); const greenPaletteColorLookupTableDescriptor = parseFloatArray(DICOMWeb.getString(instance['00281102'])); const bluePaletteColorLookupTableDescriptor = parseFloatArray(DICOMWeb.getString(instance['00281103'])); - const palettes = getPaletteColors(server, instance, redPaletteColorLookupTableDescriptor); + const palettes = await getPaletteColors(server, instance, redPaletteColorLookupTableDescriptor); if (palettes) { if (palettes.uid) { instanceSummary.paletteColorLookupTableUID = palettes.uid; } + instanceSummary.redPaletteColorLookupTableData = palettes.red; instanceSummary.greenPaletteColorLookupTableData = palettes.green; instanceSummary.bluePaletteColorLookupTableData = palettes.blue; @@ -328,8 +331,7 @@ function resultDataToStudyMetadata(server, studyInstanceUid, resultData) { } series.instances.push(instanceSummary); - - }); + })); return studyData; } @@ -338,26 +340,19 @@ function resultDataToStudyMetadata(server, studyInstanceUid, resultData) { * Retrieved Study MetaData from a DICOM server using a WADO call * @param server * @param studyInstanceUid - * @returns {{seriesList: Array, patientName: *, patientId: *, accessionNumber: *, studyDate: *, modalities: *, studyDescription: *, imageCount: *, studyInstanceUid: *}} + * @returns {Promise} */ -OHIF.studies.services.WADO.RetrieveMetadata = function(server, studyInstanceUid) { - var url = buildUrl(server, studyInstanceUid); +OHIF.studies.services.WADO.RetrieveMetadata = async function(server, studyInstanceUid) { + const url = buildUrl(server, studyInstanceUid); - try { - var result = DICOMWeb.getJSON(url, server.requestOptions); + return new Promise((resolve, reject) => { + DICOMWeb.getJSON(url, server.requestOptions).then(result => { + resultDataToStudyMetadata(server, studyInstanceUid, result).then((study) => { + study.wadoUriRoot = server.wadoUriRoot; + study.studyInstanceUid = studyInstanceUid; - var study = resultDataToStudyMetadata(server, studyInstanceUid, result.data); - if (!study) { - study = {}; - } - - study.wadoUriRoot = server.wadoUriRoot; - study.studyInstanceUid = studyInstanceUid; - - return study; - } catch (error) { - OHIF.log.trace(); - - throw error; - } + resolve(study); + }, reject); + }, reject); + }); }; diff --git a/Packages/ohif-studies/imports/client/lib/loadStudy.js b/Packages/ohif-studies/imports/client/lib/loadStudy.js index f0e3bfe02..f52461a22 100644 --- a/Packages/ohif-studies/imports/client/lib/loadStudy.js +++ b/Packages/ohif-studies/imports/client/lib/loadStudy.js @@ -1,6 +1,7 @@ import { ReactiveDict } from 'meteor/reactive-dict'; import { Tracker } from 'meteor/tracker'; import { OHIF } from 'meteor/ohif:core'; +import { Meteor } from "meteor/meteor"; // Create a studies loaded state dictionary to enable reactivity. Values: loading|loaded|failed OHIF.studies.loadingDict = new ReactiveDict(); @@ -24,16 +25,34 @@ OHIF.studies.loadStudy = studyInstanceUid => new Promise((resolve, reject) => { } return OHIF.studies.retrieveStudyMetadata(studyInstanceUid).then(study => { - // Add the display sets to the study if not present - if (!study.displaySets) { - const displaySets = OHIF.viewerbase.sortingManager.getDisplaySets(study); - study.displaySets = displaySets; - study.setDisplaySets(displaySets); - study.forEachDisplaySet(displaySet => { - OHIF.viewerbase.stackManager.makeAndAddStack(study, displaySet); + if (window.HipaaLogger && Meteor.user && Meteor.user()) { + window.HipaaLogger.logEvent({ + eventType: 'viewed', + userId: Meteor.userId(), + userName: Meteor.user().profile.fullName, + collectionName: 'Study', + recordId: studyInstanceUid, + patientId: study.patientId, + patientName: study.patientName }); } + // Once the data was retrieved, the series are sorted by series and instance number + OHIF.viewerbase.sortStudy(study); + + // Updates WADO-RS metaDataManager + OHIF.viewerbase.updateMetaDataManager(study); + + // Transform the study in a StudyMetadata object + const studyMetadata = new OHIF.metadata.StudyMetadata(study); + + // Add the display sets to the study + study.displaySets = OHIF.viewerbase.sortingManager.getDisplaySets(studyMetadata); + study.displaySets.forEach(displaySet => { + OHIF.viewerbase.stackManager.makeAndAddStack(study, displaySet); + studyMetadata.addDisplaySet(displaySet); + }); + // Double check to make sure this study wasn't already inserted into OHIF.viewer.Studies // so we don't cause duplicate entry errors const loaded = OHIF.viewer.Studies.findBy({ studyInstanceUid: study.studyInstanceUid }); diff --git a/Packages/ohif-studies/imports/client/lib/retrieveStudyMetadata.js b/Packages/ohif-studies/imports/client/lib/retrieveStudyMetadata.js index 3c7c1c9bb..8e178274e 100644 --- a/Packages/ohif-studies/imports/client/lib/retrieveStudyMetadata.js +++ b/Packages/ohif-studies/imports/client/lib/retrieveStudyMetadata.js @@ -6,6 +6,18 @@ import 'meteor/ohif:viewerbase'; // promises and prevent unnecessary subsequent calls to the server const StudyMetaDataPromises = new Map(); +/** + * Delete the study promise cached to ensure next retrieve will get it retrieved by server call + * + * @param {String} studyInstanceUid The UID of the Study to be removed from cache + * + */ +OHIF.studies.deleteStudyMetadataPromise = (studyInstanceUid) => { + if (StudyMetaDataPromises.has(studyInstanceUid)) { + StudyMetaDataPromises.delete(studyInstanceUid); + } +}; + /** * Retrieves study metadata using a server call * @@ -30,70 +42,50 @@ OHIF.studies.retrieveStudyMetadata = (studyInstanceUid, seriesInstanceUids) => { // Create a promise to handle the data retrieval const promise = new Promise((resolve, reject) => { + const server = OHIF.servers.getCurrentServer(); + // If no study metadata is in the cache variable, we need to retrieve it from // the server with a call. - Meteor.call('GetStudyMetadata', studyInstanceUid, function(error, study) { - OHIF.log.timeEnd(timingKey); + if (server.type === 'dicomWeb' && server.requestOptions.requestFromBrowser === true) { + OHIF.studies.services.WADO.RetrieveMetadata(server, studyInstanceUid).then(function (data) { + resolve(data) + }, reject); + } else { + Meteor.call('GetStudyMetadata', studyInstanceUid, function (error, study) { + OHIF.log.timeEnd(timingKey); - if (error) { - const errorType = error.error; - let errorMessage = ''; + if (error) { + const errorType = error.error; + let errorMessage = ''; - if (errorType === 'server-connection-error') { - errorMessage = 'There was an error connecting to the DICOM server, please verify if it is up and running.'; - } else if (errorType === 'server-internal-error') { - errorMessage = `There was an internal error with the DICOM server getting metadeta for ${studyInstanceUid}`; - } else { - errorMessage = `For some reason we could not retrieve the study\'s metadata for ${studyInstanceUid}.`; + if (errorType === 'server-connection-error') { + errorMessage = 'There was an error connecting to the DICOM server, please verify if it is up and running.'; + } else if (errorType === 'server-internal-error') { + errorMessage = `There was an internal error with the DICOM server getting metadeta for ${studyInstanceUid}`; + } else { + errorMessage = `For some reason we could not retrieve the study\'s metadata for ${studyInstanceUid}.`; + } + + OHIF.log.error(errorMessage); + OHIF.log.error(error.stack); + reject(`GetStudyMetadata: ${errorMessage}`); + return; } - OHIF.log.error(errorMessage); - OHIF.log.error(error.stack); - reject(`GetStudyMetadata: ${errorMessage}`); - return; - } + // Filter series if seriesInstanceUid exists + if (seriesInstanceUids && seriesInstanceUids.length) { + study.seriesList = study.seriesList.filter(series => seriesInstanceUids.indexOf(series.seriesInstanceUid) > -1); + } - // Filter series if seriesInstanceUid exists - if (seriesInstanceUids && seriesInstanceUids.length) { - study.seriesList = study.seriesList.filter(series => seriesInstanceUids.indexOf(series.seriesInstanceUid) > -1); - } + if (!study) { + reject(`GetStudyMetadata: No study data returned from server: ${studyInstanceUid}`); + return; + } - if (!study) { - reject(`GetStudyMetadata: No study data returned from server: ${studyInstanceUid}`); - return; - } - - if (window.HipaaLogger && Meteor.user && Meteor.user()) { - window.HipaaLogger.logEvent({ - eventType: 'viewed', - userId: Meteor.userId(), - userName: Meteor.user().profile.fullName, - collectionName: 'Study', - recordId: studyInstanceUid, - patientId: study.patientId, - patientName: study.patientName - }); - } - - // Once the data was retrieved, the series are sorted by series and instance number - OHIF.viewerbase.sortStudy(study); - - // Updates WADO-RS metaDataManager - OHIF.viewerbase.updateMetaDataManager(study); - - // Transform the study in a StudyMetadata object - const studyMetadata = new OHIF.metadata.StudyMetadata(study); - - // Add the display sets to the study - study.displaySets = OHIF.viewerbase.sortingManager.getDisplaySets(studyMetadata); - study.displaySets.forEach(displaySet => { - OHIF.viewerbase.stackManager.makeAndAddStack(study, displaySet); - studyMetadata.addDisplaySet(displaySet); + // Resolve the promise with the final study metadata object + resolve(study); }); - - // Resolve the promise with the final study metadata object - resolve(study); - }); + } }); // Store the promise in cache diff --git a/Packages/ohif-studies/imports/client/lib/searchStudies.js b/Packages/ohif-studies/imports/client/lib/searchStudies.js index 5a7b5a5a0..8fe6b6949 100644 --- a/Packages/ohif-studies/imports/client/lib/searchStudies.js +++ b/Packages/ohif-studies/imports/client/lib/searchStudies.js @@ -15,13 +15,19 @@ OHIF.studies.searchStudies = filter => { return studySearchPromises.get(promiseKey); } else { const promise = new Promise((resolve, reject) => { - Meteor.call('StudyListSearch', filter, (error, studiesData) => { - if (error) { - reject(error); - } else { - resolve(studiesData); - } - }); + const server = OHIF.servers.getCurrentServer(); + + if (server.type === 'dicomWeb' && server.requestOptions.requestFromBrowser === true) { + OHIF.studies.services.QIDO.Studies(server, filter).then(resolve, reject); + } else { + Meteor.call('StudyListSearch', filter, (error, studiesData) => { + if (error) { + reject(error); + } else { + resolve(studiesData); + } + }); + } }); studySearchPromises.set(promiseKey, promise); return promise; diff --git a/Packages/ohif-studies/imports/server/index.js b/Packages/ohif-studies/imports/server/index.js index 62012bab6..037e4f456 100644 --- a/Packages/ohif-studies/imports/server/index.js +++ b/Packages/ohif-studies/imports/server/index.js @@ -1,3 +1,2 @@ -import './lib'; import './methods'; import './services'; diff --git a/Packages/ohif-studies/imports/server/services/dimse/instances.js b/Packages/ohif-studies/imports/server/services/dimse/instances.js index 0e914e06a..6672c069d 100644 --- a/Packages/ohif-studies/imports/server/services/dimse/instances.js +++ b/Packages/ohif-studies/imports/server/services/dimse/instances.js @@ -5,6 +5,7 @@ import { OHIF } from 'meteor/ohif:core'; * an array of series that are present in the study * * @param resultData + * @param studyInstanceUid * @returns {Array} Series List */ function resultDataToStudyMetadata(resultData, studyInstanceUid) { diff --git a/Packages/ohif-studies/imports/server/services/dimse/retrieveMetadata.js b/Packages/ohif-studies/imports/server/services/dimse/retrieveMetadata.js index f0922598c..255b496f6 100644 --- a/Packages/ohif-studies/imports/server/services/dimse/retrieveMetadata.js +++ b/Packages/ohif-studies/imports/server/services/dimse/retrieveMetadata.js @@ -1,5 +1,5 @@ import { OHIF } from 'meteor/ohif:core'; -import { parseFloatArray } from 'meteor/ohif:studies/imports/server/lib/parseFloatArray'; +import { parseFloatArray } from 'meteor/ohif:studies/imports/both/lib/parseFloatArray'; /** * Returns the value of the element (e.g. '00280009') diff --git a/Packages/ohif-studies/imports/server/services/index.js b/Packages/ohif-studies/imports/server/services/index.js index b22669b9f..82160d7b0 100644 --- a/Packages/ohif-studies/imports/server/services/index.js +++ b/Packages/ohif-studies/imports/server/services/index.js @@ -1,10 +1,5 @@ import './namespace.js'; -// DICOMWeb instance, study, and metadata retrieval -import './qido/instances.js'; -import './qido/studies.js'; -import './wado/retrieveMetadata.js'; - // DIMSE instance, study, and metadata retrieval import './dimse/instances.js'; import './dimse/studies.js'; diff --git a/Packages/ohif-studies/imports/server/services/namespace.js b/Packages/ohif-studies/imports/server/services/namespace.js index 5985b87ab..f2ca6c3eb 100644 --- a/Packages/ohif-studies/imports/server/services/namespace.js +++ b/Packages/ohif-studies/imports/server/services/namespace.js @@ -1,8 +1,3 @@ import { OHIF } from 'meteor/ohif:core'; -const Services = {}; -Services.QIDO = {}; -Services.WADO = {}; -Services.DIMSE = {}; - -OHIF.studies.services = Services; +OHIF.studies.services.DIMSE = {}; diff --git a/Packages/ohif-studies/package.js b/Packages/ohif-studies/package.js index 96111efca..30993e323 100644 --- a/Packages/ohif-studies/package.js +++ b/Packages/ohif-studies/package.js @@ -5,7 +5,7 @@ Package.describe({ }); Package.onUse(function(api) { - api.versionsFrom('1.4'); + api.versionsFrom('1.6'); api.use([ 'ecmascript', @@ -21,6 +21,7 @@ Package.onUse(function(api) { 'ohif:log', 'ohif:servers', 'ohif:dicom-services', + 'ohif:dicomweb-client', 'ohif:viewerbase', 'ohif:wadoproxy' ]); diff --git a/Packages/ohif-study-list/client/components/studylist/studylistResult/studylistResult.js b/Packages/ohif-study-list/client/components/studylist/studylistResult/studylistResult.js index ea5e5450b..43b15a52e 100644 --- a/Packages/ohif-study-list/client/components/studylist/studylistResult/studylistResult.js +++ b/Packages/ohif-study-list/client/components/studylist/studylistResult/studylistResult.js @@ -151,29 +151,12 @@ function search() { // returned as 'undefined' const modality = replaceUndefinedColumnValue($('input#modality').val()); - Meteor.call('StudyListSearch', filter, (error, studies) => { + OHIF.studies.searchStudies(filter).then((studies) => { OHIF.log.info('StudyListSearch'); // Hide loading text Session.set('showLoadingText', false); - if (error) { - Session.set('serverError', true); - - const errorType = error.error; - - if (errorType === 'server-connection-error') { - OHIF.log.error('There was an error connecting to the DICOM server, please verify if it is up and running.'); - } else if (errorType === 'server-internal-error') { - OHIF.log.error('There was an internal error with the DICOM server'); - } else { - OHIF.log.error('For some reason we could not list the studies.') - } - - OHIF.log.error(error.stack); - return; - } - if (!studies) { OHIF.log.warn('No studies found'); return; @@ -196,6 +179,20 @@ function search() { OHIF.studylist.collections.Studies.insert(study); } }); + }, (error) => { + Session.set('serverError', true); + + const errorType = error.error; + + if (errorType === 'server-connection-error') { + OHIF.log.error('There was an error connecting to the DICOM server, please verify if it is up and running.'); + } else if (errorType === 'server-internal-error') { + OHIF.log.error('There was an internal error with the DICOM server'); + } else { + OHIF.log.error('For some reason we could not list the studies.') + } + + OHIF.log.error(error.stack); }); } diff --git a/Packages/ohif-study-list/client/lib/index.js b/Packages/ohif-study-list/client/lib/index.js index 34f13ff8f..5c7aecbdc 100644 --- a/Packages/ohif-study-list/client/lib/index.js +++ b/Packages/ohif-study-list/client/lib/index.js @@ -3,8 +3,6 @@ import './exportStudies.js'; import './getSelectedStudies.js'; import './importStudies.js'; import './queryStudies.js'; -import './retrieveStudiesMetadata.js'; -import './retrieveStudyMetadata.js'; import './studylist.js'; import './viewSeriesDetails.js'; import './viewStudies.js'; diff --git a/Packages/ohif-study-list/client/lib/retrieveStudiesMetadata.js b/Packages/ohif-study-list/client/lib/retrieveStudiesMetadata.js deleted file mode 100644 index 8d9e6fb55..000000000 --- a/Packages/ohif-study-list/client/lib/retrieveStudiesMetadata.js +++ /dev/null @@ -1,12 +0,0 @@ -import { OHIF } from 'meteor/ohif:core'; - -const note = 'OHIF.studylist.retrieveStudiesMetadata is deprecated.'; -const instructions = 'Please use OHIF.studies.retrieveStudiesMetadata instead.'; - -/** - * @deprecated Please use OHIF.studies.retrieveStudiesMetadata instead - */ -OHIF.studylist.retrieveStudiesMetadata = function() { - OHIF.log.warn(`${note}\n${instructions}`); - OHIF.studies.retrieveStudiesMetadata.apply(this, arguments); -}; diff --git a/Packages/ohif-study-list/client/lib/retrieveStudyMetadata.js b/Packages/ohif-study-list/client/lib/retrieveStudyMetadata.js deleted file mode 100644 index b86d11c12..000000000 --- a/Packages/ohif-study-list/client/lib/retrieveStudyMetadata.js +++ /dev/null @@ -1,12 +0,0 @@ -import { OHIF } from 'meteor/ohif:core'; - -const note = 'OHIF.studylist.retrieveStudyMetadata is deprecated.'; -const instructions = 'Please use OHIF.studies.retrieveStudyMetadata instead.'; - -/** - * @deprecated Please use OHIF.studies.retrieveStudyMetadata instead - */ -OHIF.studylist.retrieveStudyMetadata = function() { - OHIF.log.warn(`${note}\n${instructions}`); - OHIF.studies.retrieveStudyMetadata.apply(this, arguments); -};