From b4bb44625c8560ef9df235c981f8c39f77246191 Mon Sep 17 00:00:00 2001 From: Bruno Alves de Faria Date: Fri, 16 Jun 2017 16:36:34 -0300 Subject: [PATCH] Fixing serverId issues --- LesionTracker/.meteor/versions | 1 + .../client/components/viewer/viewer.js | 1 + LesionTracker/client/routes.js | 4 +- Packages/ohif-log/main.js | 1 + .../both/configuration/timepoints.js | 2 +- .../client/conformance/ConformanceCriteria.js | 3 + Packages/ohif-servers/both/base.js | 5 + .../both/collections/currentServer.js | 9 + .../ohif-servers/both/collections/index.js | 4 + .../ohif-servers/both/collections/servers.js | 12 + Packages/ohif-servers/both/index.js | 3 + .../both/lib/getCurrentServer.js | 5 +- .../both/lib/index.js | 0 .../both/schema/servers.js | 0 .../ohif-servers/client/collections/index.js | 1 + .../client/collections/subscriptions.js | 2 + .../ohif-servers/client/components/index.js | 1 + .../components/serverInformation/index.js | 0 .../serverInformationDicomWeb.html | 0 .../serverInformationDicomWeb.js | 2 + .../serverInformationDimse.html | 0 .../serverInformationDimse.js | 6 + .../serverInformationForm.html | 0 .../serverInformationForm.js | 6 +- .../serverInformationList.html | 0 .../serverInformationList.js | 9 +- .../serverInformationModal.html | 0 .../serverInformationModal.js | 0 .../serverInformationModal.styl | 0 Packages/ohif-servers/client/index.js | 1 + Packages/ohif-servers/package.js | 28 ++ Packages/ohif-servers/server/index.js | 4 + .../server/lib/control.js} | 58 +-- Packages/ohif-servers/server/lib/index.js | 1 + Packages/ohif-servers/server/methods.js | 9 + Packages/ohif-servers/server/publications.js | 10 + Packages/ohif-servers/server/startup.js | 61 ++++ Packages/ohif-study-list/both/collections.js | 13 +- Packages/ohif-study-list/both/index.js | 2 - Packages/ohif-study-list/both/schema/index.js | 1 - .../client/collections/index.js | 1 - .../client/components/index.js | 2 - Packages/ohif-study-list/package.js | 8 +- Packages/ohif-study-list/server/index.js | 2 - .../server/methods/getStudyMetadata.js | 3 +- .../server/methods/importStudies.js | 65 ++-- .../server/methods/studylistSearch.js | 5 +- .../ohif-study-list/server/publications.js | 10 - .../server/services/dimse/instances.js | 134 +++---- .../server/services/dimse/retrieveMetadata.js | 338 ++++++++--------- .../server/services/dimse/setup.js | 10 +- .../server/validateServerConfiguration.js | 28 -- .../client/components}/index.js | 0 .../themeSelectorModal.html | 0 .../themeSelectorModal/themeSelectorModal.js | 0 .../themeSelectorModal.styl | 0 Packages/ohif-themes-common/client/index.js | 1 + Packages/ohif-themes-common/package.js | 5 + .../studyTimepointBrowser.js | 18 +- .../client/lib/prepareViewerData.js | 1 + Packages/ohif-wadoproxy/package.js | 1 + Packages/ohif-wadoproxy/server/routes.js | 344 +++++++++--------- 62 files changed, 685 insertions(+), 556 deletions(-) create mode 100644 Packages/ohif-servers/both/base.js create mode 100644 Packages/ohif-servers/both/collections/currentServer.js create mode 100644 Packages/ohif-servers/both/collections/index.js create mode 100644 Packages/ohif-servers/both/collections/servers.js create mode 100644 Packages/ohif-servers/both/index.js rename Packages/{ohif-study-list => ohif-servers}/both/lib/getCurrentServer.js (64%) rename Packages/{ohif-study-list => ohif-servers}/both/lib/index.js (100%) rename Packages/{ohif-study-list => ohif-servers}/both/schema/servers.js (100%) create mode 100644 Packages/ohif-servers/client/collections/index.js rename Packages/{ohif-study-list => ohif-servers}/client/collections/subscriptions.js (60%) create mode 100644 Packages/ohif-servers/client/components/index.js rename Packages/{ohif-study-list => ohif-servers}/client/components/serverInformation/index.js (100%) rename Packages/{ohif-study-list => ohif-servers}/client/components/serverInformation/serverInformationDicomWeb/serverInformationDicomWeb.html (100%) rename Packages/{ohif-study-list => ohif-servers}/client/components/serverInformation/serverInformationDicomWeb/serverInformationDicomWeb.js (87%) rename Packages/{ohif-study-list => ohif-servers}/client/components/serverInformation/serverInformationDimse/serverInformationDimse.html (100%) rename Packages/{ohif-study-list => ohif-servers}/client/components/serverInformation/serverInformationDimse/serverInformationDimse.js (86%) rename Packages/{ohif-study-list => ohif-servers}/client/components/serverInformation/serverInformationForm/serverInformationForm.html (100%) rename Packages/{ohif-study-list => ohif-servers}/client/components/serverInformation/serverInformationForm/serverInformationForm.js (88%) rename Packages/{ohif-study-list => ohif-servers}/client/components/serverInformation/serverInformationList/serverInformationList.html (100%) rename Packages/{ohif-study-list => ohif-servers}/client/components/serverInformation/serverInformationList/serverInformationList.js (83%) rename Packages/{ohif-study-list => ohif-servers}/client/components/serverInformation/serverInformationModal/serverInformationModal.html (100%) rename Packages/{ohif-study-list => ohif-servers}/client/components/serverInformation/serverInformationModal/serverInformationModal.js (100%) rename Packages/{ohif-study-list => ohif-servers}/client/components/serverInformation/serverInformationModal/serverInformationModal.styl (100%) create mode 100644 Packages/ohif-servers/client/index.js create mode 100644 Packages/ohif-servers/package.js create mode 100644 Packages/ohif-servers/server/index.js rename Packages/{ohif-study-list/server/servers.js => ohif-servers/server/lib/control.js} (53%) create mode 100644 Packages/ohif-servers/server/lib/index.js create mode 100644 Packages/ohif-servers/server/methods.js create mode 100644 Packages/ohif-servers/server/publications.js create mode 100644 Packages/ohif-servers/server/startup.js delete mode 100644 Packages/ohif-study-list/both/schema/index.js delete mode 100644 Packages/ohif-study-list/server/validateServerConfiguration.js rename Packages/{ohif-study-list/client/components/themeSelector => ohif-themes-common/client/components}/index.js (100%) rename Packages/{ohif-study-list/client/components/themeSelector => ohif-themes-common/client/components}/themeSelectorModal/themeSelectorModal.html (100%) rename Packages/{ohif-study-list/client/components/themeSelector => ohif-themes-common/client/components}/themeSelectorModal/themeSelectorModal.js (100%) rename Packages/{ohif-study-list/client/components/themeSelector => ohif-themes-common/client/components}/themeSelectorModal/themeSelectorModal.styl (100%) create mode 100644 Packages/ohif-themes-common/client/index.js diff --git a/LesionTracker/.meteor/versions b/LesionTracker/.meteor/versions index fe1e1d426..0bc993717 100644 --- a/LesionTracker/.meteor/versions +++ b/LesionTracker/.meteor/versions @@ -99,6 +99,7 @@ ohif:measurements@0.0.1 ohif:metadata@0.0.1 ohif:polyfill@0.0.1 ohif:select-tree@0.0.1 +ohif:servers@0.0.1 ohif:study-list@0.0.1 ohif:themes@0.0.1 ohif:themes-common@0.0.1 diff --git a/LesionTracker/client/components/viewer/viewer.js b/LesionTracker/client/components/viewer/viewer.js index 8d9505242..bf99afcfa 100644 --- a/LesionTracker/client/components/viewer/viewer.js +++ b/LesionTracker/client/components/viewer/viewer.js @@ -32,6 +32,7 @@ Meteor.startup(() => { Template.viewer.onCreated(() => { Session.set('ViewerReady', false); + console.warn('>>>>viewer.data', Template.instance().data); const instance = Template.instance(); diff --git a/LesionTracker/client/routes.js b/LesionTracker/client/routes.js index 7e1be2e82..eb4e67943 100644 --- a/LesionTracker/client/routes.js +++ b/LesionTracker/client/routes.js @@ -37,9 +37,7 @@ Router.route('/studylist', { // Retrieve the timepoints data to display in studylist const promise = OHIF.studylist.timepointApi.retrieveTimepoints({}); - promise.then(() => { - next() - }); + promise.then(() => next()); }, action: function() { this.render('app', { data: { template: 'studylist' } }); diff --git a/Packages/ohif-log/main.js b/Packages/ohif-log/main.js index beab00033..984b6fada 100644 --- a/Packages/ohif-log/main.js +++ b/Packages/ohif-log/main.js @@ -1,3 +1,4 @@ +import { Meteor } from 'meteor/meteor'; import { OHIF } from 'meteor/ohif:core'; import loglevel from 'loglevel'; diff --git a/Packages/ohif-measurements/both/configuration/timepoints.js b/Packages/ohif-measurements/both/configuration/timepoints.js index caa18e9f8..b176e99fd 100644 --- a/Packages/ohif-measurements/both/configuration/timepoints.js +++ b/Packages/ohif-measurements/both/configuration/timepoints.js @@ -29,7 +29,7 @@ class TimepointApi { retrieveTimepoints(filter) { const retrievalFn = configuration.dataExchange.retrieve; if (!_.isFunction(retrievalFn)) { - OHIF.log.error('Timepoint retrieval function has not been configured.') + OHIF.log.error('Timepoint retrieval function has not been configured.'); return; } diff --git a/Packages/ohif-measurements/client/conformance/ConformanceCriteria.js b/Packages/ohif-measurements/client/conformance/ConformanceCriteria.js index 7628d9863..56df8a267 100644 --- a/Packages/ohif-measurements/client/conformance/ConformanceCriteria.js +++ b/Packages/ohif-measurements/client/conformance/ConformanceCriteria.js @@ -156,6 +156,9 @@ class ConformanceCriteria { const promise = OHIF.studylist.retrieveStudyMetadata(studyInstanceUid); promise.then(study => { + cornerstone.loadImage(imageId).then(image => { + console.warn('>>>>LOADED', image); + }); const metadata = OHIF.viewer.metadataProvider.getMetadata(imageId); data[measurementType].push({ measurement, diff --git a/Packages/ohif-servers/both/base.js b/Packages/ohif-servers/both/base.js new file mode 100644 index 000000000..5da3e99ea --- /dev/null +++ b/Packages/ohif-servers/both/base.js @@ -0,0 +1,5 @@ +import { OHIF } from 'meteor/ohif:core'; + +OHIF.servers = { + collections: {} +}; diff --git a/Packages/ohif-servers/both/collections/currentServer.js b/Packages/ohif-servers/both/collections/currentServer.js new file mode 100644 index 000000000..94ee8e5c9 --- /dev/null +++ b/Packages/ohif-servers/both/collections/currentServer.js @@ -0,0 +1,9 @@ +import { Mongo } from 'meteor/mongo'; +import { OHIF } from 'meteor/ohif:core'; + +// CurrentServer is a single document collection to describe which of the Servers is being used +const CurrentServer = new Mongo.Collection('currentServer'); +CurrentServer._debugName = 'CurrentServer'; +OHIF.servers.collections.currentServer = CurrentServer; + +export { CurrentServer }; diff --git a/Packages/ohif-servers/both/collections/index.js b/Packages/ohif-servers/both/collections/index.js new file mode 100644 index 000000000..34743b128 --- /dev/null +++ b/Packages/ohif-servers/both/collections/index.js @@ -0,0 +1,4 @@ +import { CurrentServer } from './currentServer.js'; +import { Servers } from './servers.js'; + +export { CurrentServer, Servers }; diff --git a/Packages/ohif-servers/both/collections/servers.js b/Packages/ohif-servers/both/collections/servers.js new file mode 100644 index 000000000..1c9663e6b --- /dev/null +++ b/Packages/ohif-servers/both/collections/servers.js @@ -0,0 +1,12 @@ +import { Mongo } from 'meteor/mongo'; +import { OHIF } from 'meteor/ohif:core'; +// import { Servers as ServerSchema } from 'meteor/ohif:servers/both/schema/servers.js'; + +// Servers describe the DICOM servers configurations +const Servers = new Mongo.Collection('servers'); +// TODO: Make the Schema match what we are currently sticking into the Collection +//Servers.attachSchema(ServerSchema); +Servers._debugName = 'Servers'; +OHIF.servers.collections.servers = Servers; + +export { Servers }; diff --git a/Packages/ohif-servers/both/index.js b/Packages/ohif-servers/both/index.js new file mode 100644 index 000000000..09b1213d9 --- /dev/null +++ b/Packages/ohif-servers/both/index.js @@ -0,0 +1,3 @@ +import './base.js'; +import './collections'; +import './lib'; diff --git a/Packages/ohif-study-list/both/lib/getCurrentServer.js b/Packages/ohif-servers/both/lib/getCurrentServer.js similarity index 64% rename from Packages/ohif-study-list/both/lib/getCurrentServer.js rename to Packages/ohif-servers/both/lib/getCurrentServer.js index d34022712..68a67385b 100644 --- a/Packages/ohif-study-list/both/lib/getCurrentServer.js +++ b/Packages/ohif-servers/both/lib/getCurrentServer.js @@ -1,7 +1,10 @@ +import { OHIF } from 'meteor/ohif:core'; +import { Servers, CurrentServer } from 'meteor/ohif:servers/both/collections'; + /** * Retrieves the current server configuration used to retrieve studies */ -getCurrentServer = () => { +OHIF.servers.getCurrentServer = () => { const currentServer = CurrentServer.findOne(); if (!currentServer) { diff --git a/Packages/ohif-study-list/both/lib/index.js b/Packages/ohif-servers/both/lib/index.js similarity index 100% rename from Packages/ohif-study-list/both/lib/index.js rename to Packages/ohif-servers/both/lib/index.js diff --git a/Packages/ohif-study-list/both/schema/servers.js b/Packages/ohif-servers/both/schema/servers.js similarity index 100% rename from Packages/ohif-study-list/both/schema/servers.js rename to Packages/ohif-servers/both/schema/servers.js diff --git a/Packages/ohif-servers/client/collections/index.js b/Packages/ohif-servers/client/collections/index.js new file mode 100644 index 000000000..8e673e096 --- /dev/null +++ b/Packages/ohif-servers/client/collections/index.js @@ -0,0 +1 @@ +import './subscriptions.js'; diff --git a/Packages/ohif-study-list/client/collections/subscriptions.js b/Packages/ohif-servers/client/collections/subscriptions.js similarity index 60% rename from Packages/ohif-study-list/client/collections/subscriptions.js rename to Packages/ohif-servers/client/collections/subscriptions.js index 1da4725c2..85a3cb1bf 100644 --- a/Packages/ohif-study-list/client/collections/subscriptions.js +++ b/Packages/ohif-servers/client/collections/subscriptions.js @@ -1,2 +1,4 @@ +import { Meteor } from 'meteor/meteor'; + Meteor.subscribe('servers'); Meteor.subscribe('currentServer'); diff --git a/Packages/ohif-servers/client/components/index.js b/Packages/ohif-servers/client/components/index.js new file mode 100644 index 000000000..289f47818 --- /dev/null +++ b/Packages/ohif-servers/client/components/index.js @@ -0,0 +1 @@ +import './serverInformation'; diff --git a/Packages/ohif-study-list/client/components/serverInformation/index.js b/Packages/ohif-servers/client/components/serverInformation/index.js similarity index 100% rename from Packages/ohif-study-list/client/components/serverInformation/index.js rename to Packages/ohif-servers/client/components/serverInformation/index.js diff --git a/Packages/ohif-study-list/client/components/serverInformation/serverInformationDicomWeb/serverInformationDicomWeb.html b/Packages/ohif-servers/client/components/serverInformation/serverInformationDicomWeb/serverInformationDicomWeb.html similarity index 100% rename from Packages/ohif-study-list/client/components/serverInformation/serverInformationDicomWeb/serverInformationDicomWeb.html rename to Packages/ohif-servers/client/components/serverInformation/serverInformationDicomWeb/serverInformationDicomWeb.html diff --git a/Packages/ohif-study-list/client/components/serverInformation/serverInformationDicomWeb/serverInformationDicomWeb.js b/Packages/ohif-servers/client/components/serverInformation/serverInformationDicomWeb/serverInformationDicomWeb.js similarity index 87% rename from Packages/ohif-study-list/client/components/serverInformation/serverInformationDicomWeb/serverInformationDicomWeb.js rename to Packages/ohif-servers/client/components/serverInformation/serverInformationDicomWeb/serverInformationDicomWeb.js index 09c315466..25ff896eb 100644 --- a/Packages/ohif-study-list/client/components/serverInformation/serverInformationDicomWeb/serverInformationDicomWeb.js +++ b/Packages/ohif-servers/client/components/serverInformation/serverInformationDicomWeb/serverInformationDicomWeb.js @@ -1,3 +1,5 @@ +import { Template } from 'meteor/templating'; + Template.serverInformationDicomWeb.onRendered(() => { const instance = Template.instance(); instance.autorun(function() { diff --git a/Packages/ohif-study-list/client/components/serverInformation/serverInformationDimse/serverInformationDimse.html b/Packages/ohif-servers/client/components/serverInformation/serverInformationDimse/serverInformationDimse.html similarity index 100% rename from Packages/ohif-study-list/client/components/serverInformation/serverInformationDimse/serverInformationDimse.html rename to Packages/ohif-servers/client/components/serverInformation/serverInformationDimse/serverInformationDimse.html diff --git a/Packages/ohif-study-list/client/components/serverInformation/serverInformationDimse/serverInformationDimse.js b/Packages/ohif-servers/client/components/serverInformation/serverInformationDimse/serverInformationDimse.js similarity index 86% rename from Packages/ohif-study-list/client/components/serverInformation/serverInformationDimse/serverInformationDimse.js rename to Packages/ohif-servers/client/components/serverInformation/serverInformationDimse/serverInformationDimse.js index dd28ecee5..540f9e232 100644 --- a/Packages/ohif-study-list/client/components/serverInformation/serverInformationDimse/serverInformationDimse.js +++ b/Packages/ohif-servers/client/components/serverInformation/serverInformationDimse/serverInformationDimse.js @@ -1,3 +1,8 @@ +import { Template } from 'meteor/templating'; +import { ReactiveVar } from 'meteor/reactive-var'; +import { Tracker } from 'meteor/tracker'; +import { _ } from 'meteor/underscore'; + Template.serverInformationDimse.onCreated(() => { const instance = Template.instance(); instance.peers = new ReactiveVar([]); @@ -14,6 +19,7 @@ Template.serverInformationDimse.onCreated(() => { peers.push({}); instance.peers.set(peers); }, + removePeer(peerIndex) { const peers = instance.peers.get(); peers.splice(peerIndex, 1); diff --git a/Packages/ohif-study-list/client/components/serverInformation/serverInformationForm/serverInformationForm.html b/Packages/ohif-servers/client/components/serverInformation/serverInformationForm/serverInformationForm.html similarity index 100% rename from Packages/ohif-study-list/client/components/serverInformation/serverInformationForm/serverInformationForm.html rename to Packages/ohif-servers/client/components/serverInformation/serverInformationForm/serverInformationForm.html diff --git a/Packages/ohif-study-list/client/components/serverInformation/serverInformationForm/serverInformationForm.js b/Packages/ohif-servers/client/components/serverInformation/serverInformationForm/serverInformationForm.js similarity index 88% rename from Packages/ohif-study-list/client/components/serverInformation/serverInformationForm/serverInformationForm.js rename to Packages/ohif-servers/client/components/serverInformation/serverInformationForm/serverInformationForm.js index d7dd00cbe..a3fec1a77 100644 --- a/Packages/ohif-study-list/client/components/serverInformation/serverInformationForm/serverInformationForm.js +++ b/Packages/ohif-servers/client/components/serverInformation/serverInformationForm/serverInformationForm.js @@ -1,8 +1,9 @@ import { Meteor } from 'meteor/meteor'; import { Template } from 'meteor/templating'; import { ReactiveVar } from 'meteor/reactive-var'; -import { DICOMWebServer as dicomSchema } from 'meteor/ohif:study-list/both/schema/servers.js'; -import { DIMSEServer as dimseSchema } from 'meteor/ohif:study-list/both/schema/servers.js'; +import { OHIF } from 'meteor/ohif:core'; +import { DICOMWebServer as dicomSchema } from 'meteor/ohif:servers/both/schema/servers.js'; +import { DIMSEServer as dimseSchema } from 'meteor/ohif:servers/both/schema/servers.js'; Template.serverInformationForm.onCreated(() => { const instance = Template.instance(); @@ -21,6 +22,7 @@ Template.serverInformationForm.onCreated(() => { Meteor.call('serverSave', formData, function(error) { if (error) { // TODO: check for errors: not-authorized, data-write + OHIF.log.error(error); } instance.data.resetState(); diff --git a/Packages/ohif-study-list/client/components/serverInformation/serverInformationList/serverInformationList.html b/Packages/ohif-servers/client/components/serverInformation/serverInformationList/serverInformationList.html similarity index 100% rename from Packages/ohif-study-list/client/components/serverInformation/serverInformationList/serverInformationList.html rename to Packages/ohif-servers/client/components/serverInformation/serverInformationList/serverInformationList.html diff --git a/Packages/ohif-study-list/client/components/serverInformation/serverInformationList/serverInformationList.js b/Packages/ohif-servers/client/components/serverInformation/serverInformationList/serverInformationList.js similarity index 83% rename from Packages/ohif-study-list/client/components/serverInformation/serverInformationList/serverInformationList.js rename to Packages/ohif-servers/client/components/serverInformation/serverInformationList/serverInformationList.js index 8969d8160..cf75b906a 100644 --- a/Packages/ohif-study-list/client/components/serverInformation/serverInformationList/serverInformationList.js +++ b/Packages/ohif-servers/client/components/serverInformation/serverInformationList/serverInformationList.js @@ -1,15 +1,21 @@ +import { Meteor } from 'meteor/meteor'; +import { Template } from 'meteor/templating'; +import { Servers, CurrentServer } from 'meteor/ohif:servers/both/collections'; + Template.serverInformationList.onCreated(() => { const instance = Template.instance(); instance.api = { add: () => instance.data.mode.set('create'), + edit(server) { instance.data.currentItem.set(server); instance.data.mode.set('edit'); }, + delete(server) { // TODO: Replace this for confirmation dialog after LT-refactor is merged back to master - if (!confirm('Are you sure you want to remove this peer?')) { + if (!window.confirm('Are you sure you want to remove this peer?')) { return; } @@ -17,6 +23,7 @@ Template.serverInformationList.onCreated(() => { // TODO: check for errors: data-write }); }, + use(server) { Meteor.call('serverSetActive', server._id, error => { // TODO: check for errors: data-write diff --git a/Packages/ohif-study-list/client/components/serverInformation/serverInformationModal/serverInformationModal.html b/Packages/ohif-servers/client/components/serverInformation/serverInformationModal/serverInformationModal.html similarity index 100% rename from Packages/ohif-study-list/client/components/serverInformation/serverInformationModal/serverInformationModal.html rename to Packages/ohif-servers/client/components/serverInformation/serverInformationModal/serverInformationModal.html diff --git a/Packages/ohif-study-list/client/components/serverInformation/serverInformationModal/serverInformationModal.js b/Packages/ohif-servers/client/components/serverInformation/serverInformationModal/serverInformationModal.js similarity index 100% rename from Packages/ohif-study-list/client/components/serverInformation/serverInformationModal/serverInformationModal.js rename to Packages/ohif-servers/client/components/serverInformation/serverInformationModal/serverInformationModal.js diff --git a/Packages/ohif-study-list/client/components/serverInformation/serverInformationModal/serverInformationModal.styl b/Packages/ohif-servers/client/components/serverInformation/serverInformationModal/serverInformationModal.styl similarity index 100% rename from Packages/ohif-study-list/client/components/serverInformation/serverInformationModal/serverInformationModal.styl rename to Packages/ohif-servers/client/components/serverInformation/serverInformationModal/serverInformationModal.styl diff --git a/Packages/ohif-servers/client/index.js b/Packages/ohif-servers/client/index.js new file mode 100644 index 000000000..20b848c68 --- /dev/null +++ b/Packages/ohif-servers/client/index.js @@ -0,0 +1 @@ +import './collections'; diff --git a/Packages/ohif-servers/package.js b/Packages/ohif-servers/package.js new file mode 100644 index 000000000..8dec73d60 --- /dev/null +++ b/Packages/ohif-servers/package.js @@ -0,0 +1,28 @@ +Package.describe({ + name: 'ohif:servers', + summary: 'OHIF collections to manage DICOM server information', + version: '0.0.1' +}); + +Package.onUse(function(api) { + api.versionsFrom('1.4'); + + api.use('ecmascript'); + api.use('jquery'); + api.use('stylus'); + api.use('aldeed:simple-schema'); + api.use('aldeed:collection2'); + + // Our custom packages + api.use('ohif:core'); + api.use('ohif:log'); + + // Client and server imports + api.addFiles('both/index.js', [ 'client', 'server' ]); + + // Server imports + api.addFiles('server/index.js', 'server'); + + // Client imports + api.addFiles('client/index.js', 'client'); +}); diff --git a/Packages/ohif-servers/server/index.js b/Packages/ohif-servers/server/index.js new file mode 100644 index 000000000..63e1b649b --- /dev/null +++ b/Packages/ohif-servers/server/index.js @@ -0,0 +1,4 @@ +import './publications.js'; +import './methods.js'; +import './startup.js'; +import './lib'; diff --git a/Packages/ohif-study-list/server/servers.js b/Packages/ohif-servers/server/lib/control.js similarity index 53% rename from Packages/ohif-study-list/server/servers.js rename to Packages/ohif-servers/server/lib/control.js index 479055190..abecd754f 100644 --- a/Packages/ohif-study-list/server/servers.js +++ b/Packages/ohif-servers/server/lib/control.js @@ -1,33 +1,15 @@ import { Meteor } from 'meteor/meteor'; -import { _ } from 'meteor/underscore'; +import { OHIF } from 'meteor/ohif:core'; +import { Servers, CurrentServer } from 'meteor/ohif:servers/both/collections'; -Meteor.startup(function() { - console.log('Adding Servers from JSON Configuration'); - Servers.remove({ - origin: 'json' - }); - - _.each(Meteor.settings.servers, function(endpoints, serverType) { - _.each(endpoints, function(endpoint) { - const server = _.clone(endpoint); - server.origin = 'json'; - server.type = serverType; - Servers.insert(server); - }); - }); - - ServersControl.resetCurrentServer(); -}); - -class ServersControl { - - static writeCallback(error, affected) { +OHIF.servers.control = { + writeCallback(error, affected) { if (error) { throw new Meteor.Error('data-write', error); } - } + }, - static resetCurrentServer() { + resetCurrentServer() { const currentServer = CurrentServer.findOne(); if (currentServer && Servers.find({ _id: currentServer.serverId }).count()) { return; @@ -44,13 +26,13 @@ class ServersControl { serverId: newServer._id }); } - } + }, - static find(query) { + find(query) { return Servers.find(query).fetch(); - } + }, - static save(serverSettings) { + save(serverSettings) { const query = { _id: serverSettings._id }; @@ -63,32 +45,24 @@ class ServersControl { } return Servers.update(query, serverSettings, options, this.writeCallback); - } + }, - static setActive(serverId) { + setActive(serverId) { CurrentServer.remove({}); CurrentServer.insert({ serverId: serverId }); - } + }, - static remove(serverId) { + remove(serverId) { const query = { _id: serverId }; const removeStatus = Servers.remove(query, this.writeCallback); - ServersControl.resetCurrentServer(); + OHIF.servers.control.resetCurrentServer(); return removeStatus; } - -} - -Meteor.methods({ - serverFind: query => ServersControl.find(query), - serverSave: serverSettings => ServersControl.save(serverSettings), - serverSetActive: serverId => ServersControl.setActive(serverId), - serverRemove: serverId => ServersControl.remove(serverId) -}); +}; diff --git a/Packages/ohif-servers/server/lib/index.js b/Packages/ohif-servers/server/lib/index.js new file mode 100644 index 000000000..a9eaa0310 --- /dev/null +++ b/Packages/ohif-servers/server/lib/index.js @@ -0,0 +1 @@ +import './control.js'; diff --git a/Packages/ohif-servers/server/methods.js b/Packages/ohif-servers/server/methods.js new file mode 100644 index 000000000..3d92c18a2 --- /dev/null +++ b/Packages/ohif-servers/server/methods.js @@ -0,0 +1,9 @@ +import { Meteor } from 'meteor/meteor'; +import { OHIF } from 'meteor/ohif:core'; + +Meteor.methods({ + serverFind: query => OHIF.servers.control.find(query), + serverSave: serverSettings => OHIF.servers.control.save(serverSettings), + serverSetActive: serverId => OHIF.servers.control.setActive(serverId), + serverRemove: serverId => OHIF.servers.control.remove(serverId) +}); diff --git a/Packages/ohif-servers/server/publications.js b/Packages/ohif-servers/server/publications.js new file mode 100644 index 000000000..cc1db288c --- /dev/null +++ b/Packages/ohif-servers/server/publications.js @@ -0,0 +1,10 @@ +import { Meteor } from 'meteor/meteor'; +import { Servers, CurrentServer } from 'meteor/ohif:servers/both/collections'; + +// When publishing Servers Collection, do not publish the requestOptions.headers +// field in case any authentication information is being passed +Meteor.publish('servers', () => Servers.find({}, { + fields: { 'requestOptions.headers': 0 } +})); + +Meteor.publish('currentServer', () => CurrentServer.find()); diff --git a/Packages/ohif-servers/server/startup.js b/Packages/ohif-servers/server/startup.js new file mode 100644 index 000000000..30c718a2e --- /dev/null +++ b/Packages/ohif-servers/server/startup.js @@ -0,0 +1,61 @@ +import { Meteor } from 'meteor/meteor'; +import { _ } from 'meteor/underscore'; +import { OHIF } from 'meteor/ohif:core'; +import { Servers } from 'meteor/ohif:servers/both/collections'; +import { ServerConfiguration } from 'meteor/ohif:servers/both/schema/servers.js'; + +// Check the servers on meteor startup +Meteor.startup(function() { + OHIF.log.info('Updating servers information from JSON configuration'); + + _.each(Meteor.settings.servers, function(endpoints, serverType) { + _.each(endpoints, function(endpoint) { + const server = _.clone(endpoint); + server.origin = 'json'; + server.type = serverType; + + // Try to find a server with the same name/type/origin combination + const existingServer = Servers.findOne({ + name: server.name, + type: server.type, + origin: server.origin + }); + + // Check if server was already added. Update it if so and insert if not + if (existingServer) { + const newServerData = _.clone(existingServer); + delete newServerData._id; + Servers.update(existingServer._id, { $set: newServerData }); + } else { + Servers.insert(server); + } + }); + }); + + OHIF.servers.control.resetCurrentServer(); +}); + +// Validate the servers configuration +Meteor.startup(() => { + // Save custom properties (if any)... + // "Meteor.settings" and "Meteor.settings.public" are set by default... + let custom = { + private: Meteor.settings.custom, + public: Meteor.settings.public.custom + }; + + // ... and remove them to prevent clean up + delete Meteor.settings.custom; + delete Meteor.settings.public.custom; + + ServerConfiguration.clean(Meteor.settings); + + // TODO: Make the error messages more clear + // Taking this out for now to prevent confusion. + // check(Meteor.settings, ServerConfiguration); + + Meteor.settings.custom = custom.private; + Meteor.settings.public.custom = custom.public; + + OHIF.log.info(JSON.stringify(Meteor.settings, null, 2)); +}); diff --git a/Packages/ohif-study-list/both/collections.js b/Packages/ohif-study-list/both/collections.js index b26df6b1b..f6087a964 100644 --- a/Packages/ohif-study-list/both/collections.js +++ b/Packages/ohif-study-list/both/collections.js @@ -1,19 +1,8 @@ import { Mongo } from 'meteor/mongo'; import { OHIF } from 'meteor/ohif:core'; -import { Servers as ServerSchema } from 'meteor/ohif:study-list/both/schema/servers.js'; const StudyImportStatus = new Mongo.Collection('studyImportStatus'); StudyImportStatus._debugName = 'StudyImportStatus'; OHIF.studylist.collections.StudyImportStatus = StudyImportStatus; -// Servers describe the DICOM servers configurations -Servers = new Mongo.Collection('servers'); -// TODO: Make the Schema match what we are currently sticking into the Collection -//Servers.attachSchema(ServerSchema); -Servers._debugName = 'Servers'; - -// CurrentServer is a single document collection to describe which of the Servers is being used -CurrentServer = new Mongo.Collection('currentServer'); -CurrentServer._debugName = 'CurrentServer'; - -export { StudyImportStatus, Servers, CurrentServer }; \ No newline at end of file +export { StudyImportStatus }; diff --git a/Packages/ohif-study-list/both/index.js b/Packages/ohif-study-list/both/index.js index d8fdd34ca..7024e769b 100644 --- a/Packages/ohif-study-list/both/index.js +++ b/Packages/ohif-study-list/both/index.js @@ -1,4 +1,2 @@ import './base.js'; -import './lib'; -import './schema'; import './collections.js'; diff --git a/Packages/ohif-study-list/both/schema/index.js b/Packages/ohif-study-list/both/schema/index.js deleted file mode 100644 index f2c6f574c..000000000 --- a/Packages/ohif-study-list/both/schema/index.js +++ /dev/null @@ -1 +0,0 @@ -import './servers.js'; diff --git a/Packages/ohif-study-list/client/collections/index.js b/Packages/ohif-study-list/client/collections/index.js index 40c37c4ad..bfd5d030d 100644 --- a/Packages/ohif-study-list/client/collections/index.js +++ b/Packages/ohif-study-list/client/collections/index.js @@ -1,2 +1 @@ import './studies.js'; -import './subscriptions.js'; diff --git a/Packages/ohif-study-list/client/components/index.js b/Packages/ohif-study-list/client/components/index.js index 82e1f295f..62e3eb2ef 100644 --- a/Packages/ohif-study-list/client/components/index.js +++ b/Packages/ohif-study-list/client/components/index.js @@ -1,4 +1,2 @@ import './seriesDetailsModal'; -import './serverInformation'; import './studylist'; -import './themeSelector'; diff --git a/Packages/ohif-study-list/package.js b/Packages/ohif-study-list/package.js index 0770d252f..522edd8d4 100644 --- a/Packages/ohif-study-list/package.js +++ b/Packages/ohif-study-list/package.js @@ -31,6 +31,7 @@ Package.onUse(function(api) { api.use('ohif:design'); api.use('ohif:core'); api.use('ohif:log'); + api.use('ohif:servers'); api.use('ohif:dicom-services'); api.use('ohif:viewerbase'); api.use('ohif:wadoproxy'); @@ -44,12 +45,5 @@ Package.onUse(function(api) { // Client imports api.addFiles('client/index.js', 'client'); - // Export Servers and CurrentServer Collections - api.export('Servers', ['client', 'server']); - api.export('CurrentServer', ['client', 'server']); - - // Export shared lib functions - api.export('getCurrentServer', ['client', 'server']); - api.export('Services', 'server'); }); diff --git a/Packages/ohif-study-list/server/index.js b/Packages/ohif-study-list/server/index.js index dd8cc07b4..6ffca0633 100644 --- a/Packages/ohif-study-list/server/index.js +++ b/Packages/ohif-study-list/server/index.js @@ -1,6 +1,4 @@ import './publications.js'; -import './servers.js'; -import './validateServerConfiguration.js'; import './lib'; import './methods'; diff --git a/Packages/ohif-study-list/server/methods/getStudyMetadata.js b/Packages/ohif-study-list/server/methods/getStudyMetadata.js index f364af8b9..2121062a0 100644 --- a/Packages/ohif-study-list/server/methods/getStudyMetadata.js +++ b/Packages/ohif-study-list/server/methods/getStudyMetadata.js @@ -1,3 +1,4 @@ +import { Meteor } from 'meteor/meteor'; import { OHIF } from 'meteor/ohif:core'; Meteor.methods({ @@ -10,7 +11,7 @@ Meteor.methods({ // Get the server data. This is user-defined in the config.json files or through servers // configuration modal - const server = getCurrentServer(); + const server = OHIF.servers.getCurrentServer(); if (!server) { throw 'No properly configured server was available over DICOMWeb or DIMSE.'; diff --git a/Packages/ohif-study-list/server/methods/importStudies.js b/Packages/ohif-study-list/server/methods/importStudies.js index 14adfe798..8e5c9cfde 100644 --- a/Packages/ohif-study-list/server/methods/importStudies.js +++ b/Packages/ohif-study-list/server/methods/importStudies.js @@ -1,7 +1,8 @@ +import { Meteor } from 'meteor/meteor'; import { OHIF } from 'meteor/ohif:core'; -var fs = Npm.require('fs'); -var fiber = Npm.require('fibers'); +const fs = Npm.require('fs'); +const fiber = Npm.require('fibers'); WebApp.connectHandlers.use('/uploadFilesToImport', function(req, res) { if (!req.headers.filename) { @@ -11,21 +12,21 @@ WebApp.connectHandlers.use('/uploadFilesToImport', function(req, res) { } // Store files in temp location (they will be deleted when their import operations are completed) - var dicomDir = '/tmp/dicomDir'; + const dicomDir = '/tmp/dicomDir'; createFolderIfNotExist(dicomDir); - var fullFileName = dicomDir + '/' + req.headers.filename; - var file = fs.createWriteStream(fullFileName); + const fullFileName = dicomDir + '/' + req.headers.filename; + const file = fs.createWriteStream(fullFileName); - file.on('error',function(error){ - console.log(error); + file.on('error', function(error) { + OHIF.log.warn(error); // Response: INTERNAL SERVER ERROR (500) res.statusCode = 400; res.end(); }); - file.on('finish',function(){ + file.on('finish', function() { // Response: SUCCESS (200) - res.writeHead(200, {'Content-Type': 'text/plain'}); + res.writeHead(200, { 'Content-Type': 'text/plain' }); res.end(fullFileName); }); @@ -39,7 +40,7 @@ Meteor.methods({ * @returns {boolean} */ importSupported: function() { - const server = getCurrentServer(); + const server = OHIF.servers.getCurrentServer(); if (server && server.type === 'dimse') { return true; } @@ -54,7 +55,7 @@ Meteor.methods({ return; } - const server = getCurrentServer(); + const server = OHIF.servers.getCurrentServer(); if (!server) { throw 'No properly configured server was available over DICOMWeb or DIMSE.'; @@ -62,7 +63,7 @@ Meteor.methods({ if (server.type === 'dicomWeb') { //TODO: Support importing studies into dicomWeb - console.log('Importing studies into dicomWeb is currently not supported.'); + OHIF.log.warn('Importing studies into dicomWeb is currently not supported.'); } else if (server.type === 'dimse') { importStudiesDIMSE(studiesToImport, studyImportStatusId); } @@ -72,7 +73,10 @@ Meteor.methods({ * @returns {studyImportStatusId: string} */ createStudyImportStatus: function() { - var studyImportStatus = { numberOfStudiesImported: 0, numberOfStudiesFailed: 0 }; + const studyImportStatus = { + numberOfStudiesImported: 0, + numberOfStudiesFailed: 0 + }; return OHIF.studylist.collections.StudyImportStatus.insert(studyImportStatus); }, /** @@ -96,17 +100,25 @@ function importStudiesDIMSE(studiesToImport, studyImportStatusId) { try { // Update the import status if (err) { - OHIF.studylist.collections.StudyImportStatus.update({_id: studyImportStatusId}, {$inc: {'numberOfStudiesFailed': 1}}); - console.log("Failed to import study via DIMSE: ", file, err); + OHIF.studylist.collections.StudyImportStatus.update( + { _id: studyImportStatusId }, + { $inc: { numberOfStudiesFailed: 1 } } + ); + OHIF.log.warn('Failed to import study via DIMSE: ', file, err); } else { - OHIF.studylist.collections.StudyImportStatus.update({_id: studyImportStatusId}, {$inc: {'numberOfStudiesImported': 1}}); - console.log("Study successfully imported via DIMSE: ", file); + OHIF.studylist.collections.StudyImportStatus.update( + { _id: studyImportStatusId }, + { $inc: { numberOfStudiesImported: 1 } } + ); + OHIF.log.info('Study successfully imported via DIMSE: ', file); } } catch(error) { - - OHIF.studylist.collections.StudyImportStatus.update({_id: studyImportStatusId}, {$inc: {'numberOfStudiesFailed': 1}}); - console.log("Failed to import study via DIMSE: ", file, error); + OHIF.studylist.collections.StudyImportStatus.update( + { _id: studyImportStatusId }, + { $inc: { numberOfStudiesFailed: 1 } } + ); + OHIF.log.warn('Failed to import study via DIMSE: ', file, error); } finally { // The import operation of this file is completed, so delete it if still exists if (fileExists(file)) { @@ -116,17 +128,20 @@ function importStudiesDIMSE(studiesToImport, studyImportStatusId) { }).run(); } catch(error) { - OHIF.studylist.collections.StudyImportStatus.update({_id: studyImportStatusId}, {$inc: {'numberOfStudiesFailed': 1}}); - console.log("Failed to import study via DIMSE: ", file, error); + OHIF.studylist.collections.StudyImportStatus.update( + { _id: studyImportStatusId }, + { $inc: { numberOfStudiesFailed: 1 } } + ); + OHIF.log.warn('Failed to import study via DIMSE: ', file, error); } }); } function createFolderIfNotExist(folder) { - var folderParts = folder.split('/'); - var folderPart = folderParts[0]; - for (var i = 1; i < folderParts.length; i++) { + const folderParts = folder.split('/'); + let folderPart = folderParts[0]; + for (let i = 1; i < folderParts.length; i++) { folderPart += '/' + folderParts[i]; if (!folderExists(folderPart)) { fs.mkdirSync(folderPart); diff --git a/Packages/ohif-study-list/server/methods/studylistSearch.js b/Packages/ohif-study-list/server/methods/studylistSearch.js index 383dc27a4..4efdb81f2 100644 --- a/Packages/ohif-study-list/server/methods/studylistSearch.js +++ b/Packages/ohif-study-list/server/methods/studylistSearch.js @@ -1,3 +1,6 @@ +import { Meteor } from 'meteor/meteor'; +import { OHIF } from 'meteor/ohif:core'; + Meteor.methods({ /** * Use the specified filter to conduct a search from the DICOM server @@ -7,7 +10,7 @@ Meteor.methods({ StudyListSearch(filter) { // Get the server data. This is user-defined in the config.json files or through servers // configuration modal - const server = getCurrentServer(); + const server = OHIF.servers.getCurrentServer(); if (!server) { throw 'No properly configured server was available over DICOMWeb or DIMSE.'; diff --git a/Packages/ohif-study-list/server/publications.js b/Packages/ohif-study-list/server/publications.js index 48c7fd76f..b543c23c4 100644 --- a/Packages/ohif-study-list/server/publications.js +++ b/Packages/ohif-study-list/server/publications.js @@ -2,13 +2,3 @@ import { Meteor } from 'meteor/meteor'; import { OHIF } from 'meteor/ohif:core'; Meteor.publish('studyImportStatus', () => OHIF.studylist.collections.StudyImportStatus.find()); - -// When publishing Servers Collection, do not publish the requestOptions.headers -// field in case any authentication information is being passed -Meteor.publish('servers', () => Servers.find({}, { - fields: { - 'requestOptions.headers': 0 - } -})); - -Meteor.publish('currentServer', () => CurrentServer.find()); diff --git a/Packages/ohif-study-list/server/services/dimse/instances.js b/Packages/ohif-study-list/server/services/dimse/instances.js index adda9c667..83145cf05 100755 --- a/Packages/ohif-study-list/server/services/dimse/instances.js +++ b/Packages/ohif-study-list/server/services/dimse/instances.js @@ -1,66 +1,68 @@ -/** - * Parses data returned from a study search and transforms it into - * an array of series that are present in the study - * - * @param resultData - * @returns {Array} Series List - */ -function resultDataToStudyMetadata(resultData) { - var seriesMap = {}; - var seriesList = []; - - resultData.forEach(function(instanceRaw) { - var instance = instanceRaw.toObject(); - // Use seriesMap to cache series data - // If the series instance UID has already been used to - // process series data, continue using that series - var seriesInstanceUid = instance[0x0020000E]; - var series = seriesMap[seriesInstanceUid]; - - // If no series data exists in the seriesMap cache variable, - // process any available series data - if (!series) { - series = { - seriesInstanceUid: seriesInstanceUid, - seriesNumber: instance[0x00200011], - instances: [] - }; - - // Save this data in the seriesMap cache variable - seriesMap[seriesInstanceUid] = series; - seriesList.push(series); - } - - // TODO: Check which peer it should point to - var server = getCurrentServer().peers[0]; - - var serverRoot = server.host + ':' + server.port; - - var sopInstanceUid = instance[0x00080018]; - var uri = serverRoot + '/studies/' + studyInstanceUid + '/series/' + seriesInstanceUid + '/instances/' + sopInstanceUid + '/frames/1'; - - // Add this instance to the current series - series.instances.push({ - sopClassUid: instance[0x00080016], - sopInstanceUid: sopInstanceUid, - uri: uri, - instanceNumber: instance[0x00200013] - }); - }); - return seriesList; -} - -/** - * Retrieve a set of instances using a DIMSE call - * @param studyInstanceUid - * @returns {{wadoUriRoot: String, studyInstanceUid: String, seriesList: Array}} - */ -Services.DIMSE.Instances = function(studyInstanceUid) { - //var url = buildUrl(server, studyInstanceUid); - var result = DIMSE.retrieveInstances(studyInstanceUid); - - return { - studyInstanceUid: studyInstanceUid, - seriesList: resultDataToStudyMetadata(result) - }; -}; +import { OHIF } from 'meteor/ohif:core'; + +/** + * Parses data returned from a study search and transforms it into + * an array of series that are present in the study + * + * @param resultData + * @returns {Array} Series List + */ +function resultDataToStudyMetadata(resultData, studyInstanceUid) { + const seriesMap = {}; + const seriesList = []; + + resultData.forEach(function(instanceRaw) { + const instance = instanceRaw.toObject(); + // Use seriesMap to cache series data + // If the series instance UID has already been used to + // process series data, continue using that series + const seriesInstanceUid = instance[0x0020000E]; + let series = seriesMap[seriesInstanceUid]; + + // If no series data exists in the seriesMap cache variable, + // process any available series data + if (!series) { + series = { + seriesInstanceUid: seriesInstanceUid, + seriesNumber: instance[0x00200011], + instances: [] + }; + + // Save this data in the seriesMap cache variable + seriesMap[seriesInstanceUid] = series; + seriesList.push(series); + } + + // TODO: Check which peer it should point to + const server = OHIF.servers.getCurrentServer().peers[0]; + + const serverRoot = server.host + ':' + server.port; + + const sopInstanceUid = instance[0x00080018]; + const uri = serverRoot + '/studies/' + studyInstanceUid + '/series/' + seriesInstanceUid + '/instances/' + sopInstanceUid + '/frames/1'; + + // Add this instance to the current series + series.instances.push({ + sopClassUid: instance[0x00080016], + sopInstanceUid, + uri, + instanceNumber: instance[0x00200013] + }); + }); + return seriesList; +} + +/** + * Retrieve a set of instances using a DIMSE call + * @param studyInstanceUid + * @returns {{wadoUriRoot: String, studyInstanceUid: String, seriesList: Array}} + */ +Services.DIMSE.Instances = function(studyInstanceUid) { + //var url = buildUrl(server, studyInstanceUid); + const result = DIMSE.retrieveInstances(studyInstanceUid); + + return { + studyInstanceUid: studyInstanceUid, + seriesList: resultDataToStudyMetadata(result, studyInstanceUid) + }; +}; diff --git a/Packages/ohif-study-list/server/services/dimse/retrieveMetadata.js b/Packages/ohif-study-list/server/services/dimse/retrieveMetadata.js index be203f3a7..f228e5b2c 100755 --- a/Packages/ohif-study-list/server/services/dimse/retrieveMetadata.js +++ b/Packages/ohif-study-list/server/services/dimse/retrieveMetadata.js @@ -1,169 +1,169 @@ -import { OHIF } from 'meteor/ohif:core'; -import { parseFloatArray } from 'meteor/ohif:study-list/server/lib/parseFloatArray'; - -/** - * Returns the value of the element (e.g. '00280009') - * - * @param element - The group/element of the element (e.g. '00280009') - * @param defaultValue - The default value to return if the element does not exist - * @returns {*} - */ -function getValue(element, defaultValue) { - if (!element || !element.value) { - return defaultValue; - } - - return element.value; -} - -/** - * Parses the SourceImageSequence, if it exists, in order - * to return a ReferenceSOPInstanceUID. The ReferenceSOPInstanceUID - * is used to refer to this image in any accompanying DICOM-SR documents. - * - * @param instance - * @returns {String} The ReferenceSOPInstanceUID - */ -function getSourceImageInstanceUid(instance) { - // TODO= Parse the whole Source Image Sequence - // This is a really poor workaround for now. - // Later we should probably parse the whole sequence. - var SourceImageSequence = instance[0x00082112]; - if (SourceImageSequence && SourceImageSequence.length) { - return SourceImageSequence[0][0x00081155]; - } -} - -/** - * Parses result data from a DIMSE search into Study MetaData - * Returns an object populated with study metadata, including the - * series list. - * - * @param studyInstanceUid - * @param resultData - * @returns {{seriesList: Array, patientName: *, patientId: *, accessionNumber: *, studyDate: *, modalities: *, studyDescription: *, imageCount: *, studyInstanceUid: *}} - */ -function resultDataToStudyMetadata(studyInstanceUid, resultData) { - OHIF.log.info('resultDataToStudyMetadata'); - var seriesMap = {}; - var seriesList = []; - - if (!resultData.length) { - return; - } - - var anInstance = resultData[0].toObject(); - if (!anInstance) { - return; - } - - var studyData = { - seriesList: seriesList, - patientName: anInstance[0x00100010], - patientId: anInstance[0x00100020], - patientBirthDate: anInstance[0x00100030], - patientSex: anInstance[0x00100040], - accessionNumber: anInstance[0x00080050], - studyDate: anInstance[0x00080020], - modalities: anInstance[0x00080061], - studyDescription: anInstance[0x00081030], - imageCount: anInstance[0x00201208], - studyInstanceUid: anInstance[0x0020000D], - institutionName: anInstance[0x00080080] - }; - - resultData.forEach(function(instanceRaw) { - var instance = instanceRaw.toObject(); - var seriesInstanceUid = instance[0x0020000E]; - var series = seriesMap[seriesInstanceUid]; - if (!series) { - series = { - seriesDescription: instance[0x0008103E], - modality: instance[0x00080060], - seriesInstanceUid: seriesInstanceUid, - seriesNumber: parseFloat(instance[0x00200011]), - instances: [] - }; - seriesMap[seriesInstanceUid] = series; - seriesList.push(series); - } - - var sopInstanceUid = instance[0x00080018]; - - var instanceSummary = { - imageType: instance[0x00080008], - sopClassUid: instance[0x00080016], - modality: instance[0x00080060], - sopInstanceUid: sopInstanceUid, - instanceNumber: parseFloat(instance[0x00200013]), - imagePositionPatient: instance[0x00200032], - imageOrientationPatient: instance[0x00200037], - frameOfReferenceUID: instance[0x00200052], - sliceThickness: parseFloat(instance[0x00180050]), - sliceLocation: parseFloat(instance[0x00201041]), - tablePosition: parseFloat(instance[0x00189327]), - samplesPerPixel: parseFloat(instance[0x00280002]), - photometricInterpretation: instance[0x00280004], - planarConfiguration: parseFloat(instance[0x00280006]), - rows: parseFloat(instance[0x00280010]), - columns: parseFloat(instance[0x00280011]), - pixelSpacing: instance[0x00280030], - bitsAllocated: parseFloat(instance[0x00280100]), - bitsStored: parseFloat(instance[0x00280101]), - highBit: parseFloat(instance[0x00280102]), - pixelRepresentation: parseFloat(instance[0x00280103]), - windowCenter: instance[0x00281050], - windowWidth: instance[0x00281051], - rescaleIntercept: parseFloat(instance[0x00281052]), - rescaleSlope: parseFloat(instance[0x00281053]), - sourceImageInstanceUid: getSourceImageInstanceUid(instance), - laterality: instance[0x00200062], - viewPosition: instance[0x00185101], - acquisitionDateTime: instance[0x0008002A], - numberOfFrames: parseFloat(instance[0x00280008]), - frameIncrementPointer: getValue(instance[0x00280009]), - frameTime: parseFloat(instance[0x00181063]), - frameTimeVector: parseFloatArray(instance[0x00181065]), - lossyImageCompression: instance[0x00282110], - derivationDescription: instance[0x00282111], - lossyImageCompressionRatio: instance[0x00282112], - lossyImageCompressionMethod: instance[0x00282114], - spacingBetweenSlices: instance[0x00180088], - echoNumber: instance[0x00180086], - contrastBolusAgent: instance[0x00180010] - }; - - // Retrieve the actual data over WADO-URI - var server = getCurrentServer(); - const wadouri = `${server.wadoUriRoot}?requestType=WADO&studyUID=${studyInstanceUid}&seriesUID=${seriesInstanceUid}&objectUID=${sopInstanceUid}&contentType=application%2Fdicom`; - instanceSummary.wadouri = WADOProxy.convertURL(wadouri, server); - - series.instances.push(instanceSummary); - }); - - studyData.studyInstanceUid = studyInstanceUid; - - return studyData; -} - -/** - * Retrieved Study MetaData from a DICOM server using DIMSE - * @param studyInstanceUid - * @returns {{seriesList: Array, patientName: *, patientId: *, accessionNumber: *, studyDate: *, modalities: *, studyDescription: *, imageCount: *, studyInstanceUid: *}} - */ -Services.DIMSE.RetrieveMetadata = function(studyInstanceUid) { - // TODO: Check which peer it should point to - const activeServer = getCurrentServer().peers[0]; - const supportsInstanceRetrievalByStudyUid = activeServer.supportsInstanceRetrievalByStudyUid; - let results; - - // Check explicitly for a value of false, since this property - // may be left undefined in config files - if (supportsInstanceRetrievalByStudyUid === false) { - results = DIMSE.retrieveInstancesByStudyOnly(studyInstanceUid); - } else { - results = DIMSE.retrieveInstances(studyInstanceUid); - } - - return resultDataToStudyMetadata(studyInstanceUid, results); -}; \ No newline at end of file +import { OHIF } from 'meteor/ohif:core'; +import { parseFloatArray } from 'meteor/ohif:study-list/server/lib/parseFloatArray'; + +/** + * Returns the value of the element (e.g. '00280009') + * + * @param element - The group/element of the element (e.g. '00280009') + * @param defaultValue - The default value to return if the element does not exist + * @returns {*} + */ +function getValue(element, defaultValue) { + if (!element || !element.value) { + return defaultValue; + } + + return element.value; +} + +/** + * Parses the SourceImageSequence, if it exists, in order + * to return a ReferenceSOPInstanceUID. The ReferenceSOPInstanceUID + * is used to refer to this image in any accompanying DICOM-SR documents. + * + * @param instance + * @returns {String} The ReferenceSOPInstanceUID + */ +function getSourceImageInstanceUid(instance) { + // TODO= Parse the whole Source Image Sequence + // This is a really poor workaround for now. + // Later we should probably parse the whole sequence. + const SourceImageSequence = instance[0x00082112]; + if (SourceImageSequence && SourceImageSequence.length) { + return SourceImageSequence[0][0x00081155]; + } +} + +/** + * Parses result data from a DIMSE search into Study MetaData + * Returns an object populated with study metadata, including the + * series list. + * + * @param studyInstanceUid + * @param resultData + * @returns {{seriesList: Array, patientName: *, patientId: *, accessionNumber: *, studyDate: *, modalities: *, studyDescription: *, imageCount: *, studyInstanceUid: *}} + */ +function resultDataToStudyMetadata(studyInstanceUid, resultData) { + OHIF.log.info('resultDataToStudyMetadata'); + const seriesMap = {}; + const seriesList = []; + + if (!resultData.length) { + return; + } + + const anInstance = resultData[0].toObject(); + if (!anInstance) { + return; + } + + const studyData = { + seriesList: seriesList, + patientName: anInstance[0x00100010], + patientId: anInstance[0x00100020], + patientBirthDate: anInstance[0x00100030], + patientSex: anInstance[0x00100040], + accessionNumber: anInstance[0x00080050], + studyDate: anInstance[0x00080020], + modalities: anInstance[0x00080061], + studyDescription: anInstance[0x00081030], + imageCount: anInstance[0x00201208], + studyInstanceUid: anInstance[0x0020000D], + institutionName: anInstance[0x00080080] + }; + + resultData.forEach(function(instanceRaw) { + const instance = instanceRaw.toObject(); + const seriesInstanceUid = instance[0x0020000E]; + let series = seriesMap[seriesInstanceUid]; + if (!series) { + series = { + seriesDescription: instance[0x0008103E], + modality: instance[0x00080060], + seriesInstanceUid: seriesInstanceUid, + seriesNumber: parseFloat(instance[0x00200011]), + instances: [] + }; + seriesMap[seriesInstanceUid] = series; + seriesList.push(series); + } + + const sopInstanceUid = instance[0x00080018]; + + const instanceSummary = { + imageType: instance[0x00080008], + sopClassUid: instance[0x00080016], + modality: instance[0x00080060], + sopInstanceUid: sopInstanceUid, + instanceNumber: parseFloat(instance[0x00200013]), + imagePositionPatient: instance[0x00200032], + imageOrientationPatient: instance[0x00200037], + frameOfReferenceUID: instance[0x00200052], + sliceThickness: parseFloat(instance[0x00180050]), + sliceLocation: parseFloat(instance[0x00201041]), + tablePosition: parseFloat(instance[0x00189327]), + samplesPerPixel: parseFloat(instance[0x00280002]), + photometricInterpretation: instance[0x00280004], + planarConfiguration: parseFloat(instance[0x00280006]), + rows: parseFloat(instance[0x00280010]), + columns: parseFloat(instance[0x00280011]), + pixelSpacing: instance[0x00280030], + bitsAllocated: parseFloat(instance[0x00280100]), + bitsStored: parseFloat(instance[0x00280101]), + highBit: parseFloat(instance[0x00280102]), + pixelRepresentation: parseFloat(instance[0x00280103]), + windowCenter: instance[0x00281050], + windowWidth: instance[0x00281051], + rescaleIntercept: parseFloat(instance[0x00281052]), + rescaleSlope: parseFloat(instance[0x00281053]), + sourceImageInstanceUid: getSourceImageInstanceUid(instance), + laterality: instance[0x00200062], + viewPosition: instance[0x00185101], + acquisitionDateTime: instance[0x0008002A], + numberOfFrames: parseFloat(instance[0x00280008]), + frameIncrementPointer: getValue(instance[0x00280009]), + frameTime: parseFloat(instance[0x00181063]), + frameTimeVector: parseFloatArray(instance[0x00181065]), + lossyImageCompression: instance[0x00282110], + derivationDescription: instance[0x00282111], + lossyImageCompressionRatio: instance[0x00282112], + lossyImageCompressionMethod: instance[0x00282114], + spacingBetweenSlices: instance[0x00180088], + echoNumber: instance[0x00180086], + contrastBolusAgent: instance[0x00180010] + }; + + // Retrieve the actual data over WADO-URI + const server = OHIF.servers.getCurrentServer(); + const wadouri = `${server.wadoUriRoot}?requestType=WADO&studyUID=${studyInstanceUid}&seriesUID=${seriesInstanceUid}&objectUID=${sopInstanceUid}&contentType=application%2Fdicom`; + instanceSummary.wadouri = WADOProxy.convertURL(wadouri, server); + + series.instances.push(instanceSummary); + }); + + studyData.studyInstanceUid = studyInstanceUid; + + return studyData; +} + +/** + * Retrieved Study MetaData from a DICOM server using DIMSE + * @param studyInstanceUid + * @returns {{seriesList: Array, patientName: *, patientId: *, accessionNumber: *, studyDate: *, modalities: *, studyDescription: *, imageCount: *, studyInstanceUid: *}} + */ +Services.DIMSE.RetrieveMetadata = function(studyInstanceUid) { + // TODO: Check which peer it should point to + const activeServer = OHIF.servers.getCurrentServer().peers[0]; + const supportsInstanceRetrievalByStudyUid = activeServer.supportsInstanceRetrievalByStudyUid; + let results; + + // Check explicitly for a value of false, since this property + // may be left undefined in config files + if (supportsInstanceRetrievalByStudyUid === false) { + results = DIMSE.retrieveInstancesByStudyOnly(studyInstanceUid); + } else { + results = DIMSE.retrieveInstances(studyInstanceUid); + } + + return resultDataToStudyMetadata(studyInstanceUid, results); +}; diff --git a/Packages/ohif-study-list/server/services/dimse/setup.js b/Packages/ohif-study-list/server/services/dimse/setup.js index 3ddbb3a2a..919251fe2 100644 --- a/Packages/ohif-study-list/server/services/dimse/setup.js +++ b/Packages/ohif-study-list/server/services/dimse/setup.js @@ -1,11 +1,13 @@ import { Meteor } from 'meteor/meteor'; +import { OHIF } from 'meteor/ohif:core'; +import { CurrentServer } from 'meteor/ohif:servers/both/collections'; const setupDIMSE = () => { // Terminate existing DIMSE servers and sockets and clean up the connection object DIMSE.connection.reset(); // Get the new server configuration - const server = getCurrentServer(); + const server = OHIF.servers.getCurrentServer(); // Stop here if the new server is not of DIMSE type if (server.type !== 'dimse') { @@ -15,16 +17,16 @@ const setupDIMSE = () => { // Check if peers were defined in the server configuration and throw an error if not const peers = server.peers; if (!peers || !peers.length) { - console.error('dimse-config: ' + 'No DIMSE Peers provided.'); + OHIF.log.error('dimse-config: ' + 'No DIMSE Peers provided.'); throw new Meteor.Error('dimse-config', 'No DIMSE Peers provided.'); } // Add all the DIMSE peers, establishing the connections - console.log('Adding DIMSE peers'); + OHIF.log.info('Adding DIMSE peers'); try { peers.forEach(peer => DIMSE.connection.addPeer(peer)); } catch(error) { - console.error('dimse-addPeers: ' + error); + OHIF.log.error('dimse-addPeers: ' + error); throw new Meteor.Error('dimse-addPeers', error); } }; diff --git a/Packages/ohif-study-list/server/validateServerConfiguration.js b/Packages/ohif-study-list/server/validateServerConfiguration.js deleted file mode 100644 index dc5488965..000000000 --- a/Packages/ohif-study-list/server/validateServerConfiguration.js +++ /dev/null @@ -1,28 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -// import { check } from 'meteor/check'; -import { OHIF } from 'meteor/ohif:core'; -import { ServerConfiguration } from 'meteor/ohif:study-list/both/schema/servers.js'; - -Meteor.startup(() => { - // Save custom properties (if any)... - // "Meteor.settings" and "Meteor.settings.public" are set by default... - let custom = { - private: Meteor.settings.custom, - public: Meteor.settings.public.custom - }; - - // ... and remove them to prevent clean up - delete Meteor.settings.custom; - delete Meteor.settings.public.custom; - - ServerConfiguration.clean(Meteor.settings); - - // TODO: Make the error messages more clear - // Taking this out for now to prevent confusion. - // check(Meteor.settings, ServerConfiguration); - - Meteor.settings.custom = custom.private; - Meteor.settings.public.custom = custom.public; - - OHIF.log.info(JSON.stringify(Meteor.settings, null, 2)); -}); diff --git a/Packages/ohif-study-list/client/components/themeSelector/index.js b/Packages/ohif-themes-common/client/components/index.js similarity index 100% rename from Packages/ohif-study-list/client/components/themeSelector/index.js rename to Packages/ohif-themes-common/client/components/index.js diff --git a/Packages/ohif-study-list/client/components/themeSelector/themeSelectorModal/themeSelectorModal.html b/Packages/ohif-themes-common/client/components/themeSelectorModal/themeSelectorModal.html similarity index 100% rename from Packages/ohif-study-list/client/components/themeSelector/themeSelectorModal/themeSelectorModal.html rename to Packages/ohif-themes-common/client/components/themeSelectorModal/themeSelectorModal.html diff --git a/Packages/ohif-study-list/client/components/themeSelector/themeSelectorModal/themeSelectorModal.js b/Packages/ohif-themes-common/client/components/themeSelectorModal/themeSelectorModal.js similarity index 100% rename from Packages/ohif-study-list/client/components/themeSelector/themeSelectorModal/themeSelectorModal.js rename to Packages/ohif-themes-common/client/components/themeSelectorModal/themeSelectorModal.js diff --git a/Packages/ohif-study-list/client/components/themeSelector/themeSelectorModal/themeSelectorModal.styl b/Packages/ohif-themes-common/client/components/themeSelectorModal/themeSelectorModal.styl similarity index 100% rename from Packages/ohif-study-list/client/components/themeSelector/themeSelectorModal/themeSelectorModal.styl rename to Packages/ohif-themes-common/client/components/themeSelectorModal/themeSelectorModal.styl diff --git a/Packages/ohif-themes-common/client/index.js b/Packages/ohif-themes-common/client/index.js new file mode 100644 index 000000000..758f32245 --- /dev/null +++ b/Packages/ohif-themes-common/client/index.js @@ -0,0 +1 @@ +import './components'; diff --git a/Packages/ohif-themes-common/package.js b/Packages/ohif-themes-common/package.js index 58e654718..b8eb59f6e 100644 --- a/Packages/ohif-themes-common/package.js +++ b/Packages/ohif-themes-common/package.js @@ -7,8 +7,13 @@ Package.describe({ Package.onUse(function(api) { api.versionsFrom('1.4.2.3'); + api.use('ecmascript'); + api.use('templating'); api.use('stylus'); + // Client imports + api.addFiles('client/index.js', 'client'); + // Importable themes api.addFiles([ 'themes.styl', diff --git a/Packages/ohif-viewerbase/client/components/viewer/studyTimepointBrowser/studyTimepointBrowser.js b/Packages/ohif-viewerbase/client/components/viewer/studyTimepointBrowser/studyTimepointBrowser.js index e10416f86..c6faedbd5 100644 --- a/Packages/ohif-viewerbase/client/components/viewer/studyTimepointBrowser/studyTimepointBrowser.js +++ b/Packages/ohif-viewerbase/client/components/viewer/studyTimepointBrowser/studyTimepointBrowser.js @@ -30,7 +30,7 @@ Template.studyTimepointBrowser.onCreated(() => { return timepoint.studyInstanceUids.map(studyInstanceUid => { const query = { patientId: timepoint.patientId, - studyInstanceUid + studyInstanceUid: studyInstanceUid }; const loadedStudy = OHIF.viewer.Studies.findBy(query); @@ -40,7 +40,7 @@ Template.studyTimepointBrowser.onCreated(() => { const notYetLoaded = OHIF.studylist.collections.Studies.findOne(query); if (!notYetLoaded) { - OHIF.log.info(`No study data available for Study: ${studyInstanceUid}`); + throw new OHIFError(`No study data available for Study: ${studyInstanceUid}`); } return notYetLoaded; @@ -165,8 +165,20 @@ Template.studyTimepointBrowser.helpers({ timepoints = timepointApi.key(); } } + + // Filter timepoints and show only the current timepoint and previous ones + let result = []; + const currentTimepoint = timepointApi.current(); + if (currentTimepoint) { + timepoints.forEach(timepoint => { + if (timepoint.latestDate.getTime() <= currentTimepoint.latestDate.getTime()) { + result.push(timepoint); + } + }); + } + // Returns the timepoints - return timepoints; + return result; }, // Get the studies for a specific timepoint diff --git a/Packages/ohif-viewerbase/client/lib/prepareViewerData.js b/Packages/ohif-viewerbase/client/lib/prepareViewerData.js index 7c4c5bf8b..fe5579426 100644 --- a/Packages/ohif-viewerbase/client/lib/prepareViewerData.js +++ b/Packages/ohif-viewerbase/client/lib/prepareViewerData.js @@ -44,6 +44,7 @@ export const prepareViewerData = ({ studyInstanceUids, timepointId, timepointsFi // Find the timepoint by ID and load the studies from it OHIF.studylist.timepointApi.retrieveTimepoints(timepointsFilter).then(() => { const viewerData = buildViewerDataFromTimepointId(timepointId); + console.warn('>>>>', viewerData); processData(viewerData); }).catch(reject); } diff --git a/Packages/ohif-wadoproxy/package.js b/Packages/ohif-wadoproxy/package.js index 2a80c729a..dbf38c9e2 100755 --- a/Packages/ohif-wadoproxy/package.js +++ b/Packages/ohif-wadoproxy/package.js @@ -16,6 +16,7 @@ Package.onUse(function(api) { api.use('iron:router@1.0.13'); api.use('ohif:core'); + api.use('ohif:servers'); api.addFiles('server/namespace.js', 'server'); api.addFiles('server/initialize.js', 'server'); diff --git a/Packages/ohif-wadoproxy/server/routes.js b/Packages/ohif-wadoproxy/server/routes.js index 4fca995ef..6f584acad 100755 --- a/Packages/ohif-wadoproxy/server/routes.js +++ b/Packages/ohif-wadoproxy/server/routes.js @@ -1,172 +1,172 @@ -import { Meteor } from 'meteor/meteor'; -import { Router } from 'meteor/iron:router'; -import { Accounts } from 'meteor/accounts-base'; - -import { OHIF } from 'meteor/ohif:core'; - -const url = require("url"); -const http = require("http"); -const https = require("https"); -const now = require("performance-now") - -const doAuth = Meteor.users.find().count() ? true : false; - -const authenticateUser = request => { - // Only allow logged-in users to access this route - const userId = request.headers['x-user-id'] - const loginToken = request.headers['x-auth-token'] - if (!userId || !loginToken) { - return; - } - - const hashedToken = Accounts._hashLoginToken(loginToken); - - return Meteor.users.findOne({ - _id: userId, - 'services.resume.loginTokens.hashedToken': hashedToken - }); -} - -// Setup a Route using Iron Router to avoid Cross-origin resource sharing -// (CORS) errors. We only handle this route on the Server. -Router.route(Settings.uri.replace(OHIF.utils.absoluteUrl(), ''), function() { - const request = this.request; - const response = this.response; - const params = this.params; - - let start = now(); - let user; - if (doAuth) { - user = authenticateUser(request); - if (!user) { - response.writeHead(401); - response.end('Error: You must be logged in to perform this action.\n'); - return; - } - } - let end = now(); - const authenticationTime = end - start; - - start = now(); - - // TODO: Merge this with ohif-study-list? There is a circular dependency now... - const server = Servers.findOne(params.query.serverId); - if (!server) { - response.writeHead(500); - response.end('Error: No Server with the specified Server ID was found.\n'); - return; - } - - const requestOpt = server.requestOptions; - - // If no Web Access to DICOM Objects (WADO) Service URL is provided - // return an error for the request. - const wadoUrl = params.query.url; - if (!wadoUrl) { - response.writeHead(500); - response.end('Error: No WADO URL was provided.\n'); - return; - } - - if (requestOpt.logRequests) { - console.log(request.url); - } - - start = now(); - if (requestOpt.logTiming) { - console.time(request.url); - } - - // Use Node's URL parse to decode the query URL - const parsed = url.parse(wadoUrl); - - // Create an object to hold the information required - // for the request to the PACS. - let options = { - headers: {}, - method: request.method, - hostname: parsed.hostname, - path: parsed.path - }; - - let requester; - if (parsed.protocol === 'https:') { - requester = https.request; - - const allowUnauthorizedAgent = new https.Agent({ rejectUnauthorized: false }); - options.agent = allowUnauthorizedAgent - } else { - requester = http.request; - } - - if (parsed.port) { - options.port = parsed.port; - } - - Object.keys(request.headers).forEach(entry => { - const value = request.headers[entry]; - if (entry) { - options.headers[entry] = value; - } - }); - - // Retrieve the authorization user:password string for the PACS, - // if one is required, and include it in the request to the PACS. - if (requestOpt.auth) { - options.auth = requestOpt.auth; - } - - end = now(); - const prepRequestTime = end - start; - - // Use Node's HTTP API to send a request to the PACS - const proxyRequest = requester(options, proxyResponse => { - // When we receive data from the PACS, stream it as the - // response to the original request. - // console.log(`Got response: ${proxyResponse.statusCode}`); - end = now(); - const proxyReqTime = end - start; - const totalProxyTime = authenticationTime + prepRequestTime + proxyReqTime; - const serverTimingHeaders = ` - auth=${authenticationTime}; "Authenticate User", - prep-req=${prepRequestTime}; "Prepare Request Headers", - proxy-req=${proxyReqTime}; "Request to WADO URI", - total-proxy=${totalProxyTime}; "Total", - `.replace(/\n/g, ''); - - proxyResponse.headers['Server-Timing'] = serverTimingHeaders; - - response.writeHead(proxyResponse.statusCode, proxyResponse.headers); - - if (requestOpt.logTiming) { - console.timeEnd(request.url); - } - - return proxyResponse.pipe(response, {end: true}); - }); - - // If our request to the PACS fails, log the error message - proxyRequest.on('error', error => { - end = now(); - const proxyReqTime = end - start; - const totalProxyTime = authenticationTime + prepRequestTime + proxyReqTime; - console.timeEnd(request.url); - const serverTimingHeaders = { - 'Server-Timing': ` - auth=${authenticationTime}; "Authenticate User", - prep-req=${prepRequestTime}; "Prepare Request Headers", - proxy-req=${proxyReqTime}; "Request to WADO URI", - total-proxy=${totalProxyTime}; "Total", - `.replace(/\n/g, '') - }; - - response.writeHead(500, serverTimingHeaders); - response.end(`Error: Problem with request to PACS: ${error.message}\n`); - }); - - // Stream the original request information into the request - // to the PACS - request.pipe(proxyRequest); -}, { - where: 'server' -}); \ No newline at end of file +import { Meteor } from 'meteor/meteor'; +import { Router } from 'meteor/iron:router'; +import { Accounts } from 'meteor/accounts-base'; +import { OHIF } from 'meteor/ohif:core'; +import { Servers } from 'meteor/ohif:servers/both/collections'; + +const url = require('url'); +const http = require('http'); +const https = require('https'); +const now = require('performance-now'); + +const doAuth = Meteor.users.find().count() ? true : false; + +const authenticateUser = request => { + // Only allow logged-in users to access this route + const userId = request.headers['x-user-id']; + const loginToken = request.headers['x-auth-token']; + if (!userId || !loginToken) { + return; + } + + const hashedToken = Accounts._hashLoginToken(loginToken); + + return Meteor.users.findOne({ + _id: userId, + 'services.resume.loginTokens.hashedToken': hashedToken + }); +}; + +// Setup a Route using Iron Router to avoid Cross-origin resource sharing +// (CORS) errors. We only handle this route on the Server. +Router.route(Settings.uri.replace(OHIF.utils.absoluteUrl(), ''), function() { + const request = this.request; + const response = this.response; + const params = this.params; + + let start = now(); + let user; + if (doAuth) { + user = authenticateUser(request); + if (!user) { + response.writeHead(401); + response.end('Error: You must be logged in to perform this action.\n'); + return; + } + } + + let end = now(); + const authenticationTime = end - start; + + start = now(); + + const server = Servers.findOne(params.query.serverId); + if (!server) { + response.writeHead(500); + response.end('Error: No Server with the specified Server ID was found.\n'); + return; + } + + const requestOpt = server.requestOptions; + + // If no Web Access to DICOM Objects (WADO) Service URL is provided + // return an error for the request. + const wadoUrl = params.query.url; + if (!wadoUrl) { + response.writeHead(500); + response.end('Error: No WADO URL was provided.\n'); + return; + } + + if (requestOpt.logRequests) { + console.log(request.url); + } + + start = now(); + if (requestOpt.logTiming) { + console.time(request.url); + } + + // Use Node's URL parse to decode the query URL + const parsed = url.parse(wadoUrl); + + // Create an object to hold the information required + // for the request to the PACS. + let options = { + headers: {}, + method: request.method, + hostname: parsed.hostname, + path: parsed.path + }; + + let requester; + if (parsed.protocol === 'https:') { + requester = https.request; + + const allowUnauthorizedAgent = new https.Agent({ rejectUnauthorized: false }); + options.agent = allowUnauthorizedAgent; + } else { + requester = http.request; + } + + if (parsed.port) { + options.port = parsed.port; + } + + Object.keys(request.headers).forEach(entry => { + const value = request.headers[entry]; + if (entry) { + options.headers[entry] = value; + } + }); + + // Retrieve the authorization user:password string for the PACS, + // if one is required, and include it in the request to the PACS. + if (requestOpt.auth) { + options.auth = requestOpt.auth; + } + + end = now(); + const prepRequestTime = end - start; + + // Use Node's HTTP API to send a request to the PACS + const proxyRequest = requester(options, proxyResponse => { + // When we receive data from the PACS, stream it as the + // response to the original request. + // console.log(`Got response: ${proxyResponse.statusCode}`); + end = now(); + const proxyReqTime = end - start; + const totalProxyTime = authenticationTime + prepRequestTime + proxyReqTime; + const serverTimingHeaders = ` + auth=${authenticationTime}; "Authenticate User", + prep-req=${prepRequestTime}; "Prepare Request Headers", + proxy-req=${proxyReqTime}; "Request to WADO URI", + total-proxy=${totalProxyTime}; "Total", + `.replace(/\n/g, ''); + + proxyResponse.headers['Server-Timing'] = serverTimingHeaders; + + response.writeHead(proxyResponse.statusCode, proxyResponse.headers); + + if (requestOpt.logTiming) { + console.timeEnd(request.url); + } + + return proxyResponse.pipe(response, { end: true }); + }); + + // If our request to the PACS fails, log the error message + proxyRequest.on('error', error => { + end = now(); + const proxyReqTime = end - start; + const totalProxyTime = authenticationTime + prepRequestTime + proxyReqTime; + console.timeEnd(request.url); + const serverTimingHeaders = { + 'Server-Timing': ` + auth=${authenticationTime}; "Authenticate User", + prep-req=${prepRequestTime}; "Prepare Request Headers", + proxy-req=${proxyReqTime}; "Request to WADO URI", + total-proxy=${totalProxyTime}; "Total", + `.replace(/\n/g, '') + }; + + response.writeHead(500, serverTimingHeaders); + response.end(`Error: Problem with request to PACS: ${error.message}\n`); + }); + + // Stream the original request information into the request + // to the PACS + request.pipe(proxyRequest); +}, { + where: 'server' +});