Fixing serverId issues

This commit is contained in:
Bruno Alves de Faria 2017-06-16 16:36:34 -03:00
parent 95533c785b
commit b4bb44625c
62 changed files with 685 additions and 556 deletions

View File

@ -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

View File

@ -32,6 +32,7 @@ Meteor.startup(() => {
Template.viewer.onCreated(() => {
Session.set('ViewerReady', false);
console.warn('>>>>viewer.data', Template.instance().data);
const instance = Template.instance();

View File

@ -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' } });

View File

@ -1,3 +1,4 @@
import { Meteor } from 'meteor/meteor';
import { OHIF } from 'meteor/ohif:core';
import loglevel from 'loglevel';

View File

@ -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;
}

View File

@ -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,

View File

@ -0,0 +1,5 @@
import { OHIF } from 'meteor/ohif:core';
OHIF.servers = {
collections: {}
};

View File

@ -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 };

View File

@ -0,0 +1,4 @@
import { CurrentServer } from './currentServer.js';
import { Servers } from './servers.js';
export { CurrentServer, Servers };

View File

@ -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 };

View File

@ -0,0 +1,3 @@
import './base.js';
import './collections';
import './lib';

View File

@ -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) {

View File

@ -0,0 +1 @@
import './subscriptions.js';

View File

@ -1,2 +1,4 @@
import { Meteor } from 'meteor/meteor';
Meteor.subscribe('servers');
Meteor.subscribe('currentServer');

View File

@ -0,0 +1 @@
import './serverInformation';

View File

@ -1,3 +1,5 @@
import { Template } from 'meteor/templating';
Template.serverInformationDicomWeb.onRendered(() => {
const instance = Template.instance();
instance.autorun(function() {

View File

@ -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);

View File

@ -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();

View File

@ -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

View File

@ -0,0 +1 @@
import './collections';

View File

@ -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');
});

View File

@ -0,0 +1,4 @@
import './publications.js';
import './methods.js';
import './startup.js';
import './lib';

View File

@ -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)
});
};

View File

@ -0,0 +1 @@
import './control.js';

View File

@ -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)
});

View File

@ -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());

View File

@ -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));
});

View File

@ -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 };
export { StudyImportStatus };

View File

@ -1,4 +1,2 @@
import './base.js';
import './lib';
import './schema';
import './collections.js';

View File

@ -1 +0,0 @@
import './servers.js';

View File

@ -1,2 +1 @@
import './studies.js';
import './subscriptions.js';

View File

@ -1,4 +1,2 @@
import './seriesDetailsModal';
import './serverInformation';
import './studylist';
import './themeSelector';

View File

@ -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');
});

View File

@ -1,6 +1,4 @@
import './publications.js';
import './servers.js';
import './validateServerConfiguration.js';
import './lib';
import './methods';

View File

@ -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.';

View File

@ -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);

View File

@ -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.';

View File

@ -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());

View File

@ -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)
};
};

View File

@ -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);
};
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);
};

View File

@ -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);
}
};

View File

@ -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));
});

View File

@ -0,0 +1 @@
import './components';

View File

@ -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',

View File

@ -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

View File

@ -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);
}

View File

@ -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');

View File

@ -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'
});
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'
});