diff --git a/api/dicom-web/controller/STOW-RS/service/stow-rs.service.js b/api/dicom-web/controller/STOW-RS/service/stow-rs.service.js index e9b9cae5..83bbc104 100644 --- a/api/dicom-web/controller/STOW-RS/service/stow-rs.service.js +++ b/api/dicom-web/controller/STOW-RS/service/stow-rs.service.js @@ -6,23 +6,13 @@ const { DicomJsonBinaryDataModel } = require("@dicom-json-model"); const { DicomFileSaver } = require("./dicom-file-saver"); -const { DicomFhirService } = require("./dicom-fhir.service"); const { DicomJpegGenerator } = require("./dicom-jpeg-generator"); const { logger } = require("../../../../../utils/logs/log"); - -const { raccoonConfig } = require("../../../../../config-class"); const { DicomWebService } = require("../../../service/dicom-web.service"); const { AuditManager } = require("@models/DICOM/audit/auditManager"); const { EventType } = require("@models/DICOM/audit/eventType"); const { EventOutcomeIndicator } = require("@models/DICOM/audit/auditUtils"); -const { - apiPath: DICOM_WEB_API_PATH -} = raccoonConfig.dicomWebConfig; - -const { - isSyncToFhir -} = raccoonConfig.fhirConfig; const StowRsFailureCode = { "GENERAL_FAILURE": "272", @@ -34,11 +24,19 @@ const StowRsFailureCode = { class StowRsService { /** * @param {import('express').Request} req + * @param {import('express').Response} res * @param {import('formidable').File[]} uploadFiles */ - constructor(req, uploadFiles) { + constructor(req, res, uploadFiles) { this.request = req; + this.response = res; + + this.response.locals = { + "storeInfos": [] + }; + this.uploadFiles = uploadFiles; + this.responseMessage = { "00081190": { //Study retrieve URL @@ -90,14 +88,18 @@ class StowRsService { let storeInstanceResult = await this.storeInstance(currentFile); dicomJsonModel = storeInstanceResult.dicomJsonModel; dicomFileSaveInfo = storeInstanceResult.dicomFileSaveInfo; - } catch(e) { + this.response.locals.storeInfos.push({ + dicomFileSaveInfo, + dicomJsonModel + }); + } catch (e) { // log transferred failure let auditManager = new AuditManager( EventType.STORE_CREATE, EventOutcomeIndicator.MajorFailure, DicomWebService.getRemoteAddress(this.request), DicomWebService.getRemoteHostname(this.request), DicomWebService.getServerAddress(), DicomWebService.getServerHostname() ); - + await auditManager.onDicomInstancesTransferred( dicomJsonModel ? [dicomJsonModel.uidObj.studyUID] : "Unknown" ); @@ -105,14 +107,6 @@ class StowRsService { throw e; } - - //sync DICOM to FHIR - if (isSyncToFhir) { - let dicomFhirService = new DicomFhirService(this.request, dicomJsonModel); - await dicomFhirService.initDicomFhirConverter(); - await dicomFhirService.postDicomToFhirServerAndStoreLog(); - } - //generate JPEG let dicomJpegGenerator = new DicomJpegGenerator(dicomJsonModel, dicomFileSaveInfo.instancePath); dicomJpegGenerator.generateAllFrames(); diff --git a/api/dicom-web/controller/STOW-RS/storeInstance.js b/api/dicom-web/controller/STOW-RS/storeInstance.js index 2cbbf5bd..b834cc76 100644 --- a/api/dicom-web/controller/STOW-RS/storeInstance.js +++ b/api/dicom-web/controller/STOW-RS/storeInstance.js @@ -23,7 +23,7 @@ class StoreInstanceController extends Controller { let multipartParseResult = await requestMultipartParser.parse(); if (multipartParseResult.status) { - let stowRsService = new StowRsService(this.request, multipartParseResult.multipart.files); + let stowRsService = new StowRsService(this.request, this.response, multipartParseResult.multipart.files); let storeInstancesResult = await stowRsService.storeInstances(); retCode = storeInstancesResult.code; diff --git a/config-class.js b/config-class.js index 40580adb..0d209cbc 100644 --- a/config-class.js +++ b/config-class.js @@ -56,13 +56,6 @@ class DicomWebConfig { } } -class FhirConfig { - constructor() { - this.isSyncToFhir = env.get("SYCN_TO_FHIR_SERVER").default("true").asBool(); - this.baseUrl = env.get("FHIRSERVER_BASE_URL").default("http://127.0.0.1:8089/fhir").asString(); - } -} - class RaccoonConfig { constructor() { @@ -72,7 +65,6 @@ class RaccoonConfig { this.dicomWebConfig = new DicomWebConfig(); this.dicomDimseConfig = new DimseConfig(); - this.fhirConfig = new FhirConfig(); /** @type {string} */ this.mediaStorageUID = generateUidFromGuid( diff --git a/plugins/config.template.js b/plugins/config.template.js index c53654d0..ecd56b1a 100644 --- a/plugins/config.template.js +++ b/plugins/config.template.js @@ -12,5 +12,20 @@ module.exports.pluginsConfig = { method: "get" } ] + }, + "syncToFhirServer": { + enable: false, + before: false, + routers: [ + { + path: "/dicom-web/studies", + method: "post" + } + ], + fhir: { + server: { + baseUrl: "http://127.0.0.1/fhir" + } + } } }; \ No newline at end of file diff --git a/models/FHIR/DICOM/DICOMToFHIR.js b/plugins/syncToFhirServer/DICOMToFHIR.js similarity index 98% rename from models/FHIR/DICOM/DICOMToFHIR.js rename to plugins/syncToFhirServer/DICOMToFHIR.js index 67bb3b1d..3013c1f8 100644 --- a/models/FHIR/DICOM/DICOMToFHIR.js +++ b/plugins/syncToFhirServer/DICOMToFHIR.js @@ -1,12 +1,12 @@ const { URL } = require("url"); const axios = require("axios").default; const _ = require("lodash"); -const { urlJoin } = require("../../../utils/url"); -const { fhirLogger } = require("../../../utils/logs/log"); +const { urlJoin } = require("../../utils/url"); +const { fhirLogger } = require("../../utils/logs/log"); const { getModalitiesInStudy } = require("@dbModels/instance.model"); const { DicomJsonToFhir } = require("dicomjson-to-fhir"); -class DICOMFHIRConverter { +class DicomFhirConverter { constructor() { this.dicomFHIR = { patient: {}, @@ -329,4 +329,4 @@ class DICOMFHIRConverter { } } -module.exports.DICOMFHIRConverter = DICOMFHIRConverter; +module.exports.DicomFhirConverter = DicomFhirConverter; diff --git a/api/dicom-web/controller/STOW-RS/service/dicom-fhir.service.js b/plugins/syncToFhirServer/dicom-fhir.service.js similarity index 78% rename from api/dicom-web/controller/STOW-RS/service/dicom-fhir.service.js rename to plugins/syncToFhirServer/dicom-fhir.service.js index b06d8cec..3837fce1 100644 --- a/api/dicom-web/controller/STOW-RS/service/dicom-fhir.service.js +++ b/plugins/syncToFhirServer/dicom-fhir.service.js @@ -1,35 +1,46 @@ +const path = require("path"); +const fs = require("fs"); + const mongoose = require("mongoose"); const { - DICOMFHIRConverter -} = require("../../../../../models/FHIR/DICOM/DICOMToFHIR"); -const { fhirLogger } = require("../../../../../utils/logs/log"); + DicomFhirConverter +} = require("./DICOMToFHIR"); +const { fhirLogger } = require("../../utils/logs/log"); -const { raccoonConfig } = require("../../../../../config-class"); +const { raccoonConfig } = require("../../config-class"); const { apiPath: DICOM_WEB_API_PATH } = raccoonConfig.dicomWebConfig; -const { - baseUrl: FHIR_BASE_URL -} = raccoonConfig.fhirConfig; + +let pluginConfigFile = path.join(__dirname, "../config.template.js"); +if (fs.existsSync(path.join(__dirname, "../config.js"))) { + pluginConfigFile = path.join(__dirname, "../config.js"); +} + +const fhirBaseUrl = require(pluginConfigFile).pluginsConfig?.syncToFhirServer?.fhir?.server?.baseUrl; class DicomFhirService { constructor(req, dicomJsonModel) { + if (!fhirBaseUrl) { + throw new Error("missing fhir config in your plugin config"); + } + this.request = req; this.dicomJsonModel = dicomJsonModel; /** * @private */ - this.dicomFhirConverter = new DICOMFHIRConverter(); + this.dicomFhirConverter = new DicomFhirConverter(); } async initDicomFhirConverter() { this.dicomFhirConverter.dicomWeb.name =`raccoon-dicom-web-server`; let protocol = this.request.secure ? "https" : "http"; this.dicomFhirConverter.dicomWeb.retrieveStudiesUrl = `${protocol}://${this.request.headers.host}/${DICOM_WEB_API_PATH}/studies`; - this.dicomFhirConverter.fhir.baseUrl = FHIR_BASE_URL; + this.dicomFhirConverter.fhir.baseUrl = fhirBaseUrl; } async postDicomToFhirServerAndStoreLog() { diff --git a/plugins/syncToFhirServer/index.js b/plugins/syncToFhirServer/index.js new file mode 100644 index 00000000..85f64796 --- /dev/null +++ b/plugins/syncToFhirServer/index.js @@ -0,0 +1,30 @@ +require("./mongoose/syncFHIRLog"); +const path = require("path"); +const fs = require("fs"); +const { DicomFhirService } = require("./dicom-fhir.service"); +let pluginConfigFile = path.join(__dirname, "../config.template.js"); + +if (fs.existsSync(path.join(__dirname, "../config.js"))) pluginConfigFile = path.join(__dirname, "../config.js"); + +const { pluginsConfig } = require(pluginConfigFile); + +/** + * + * @param {import("express").Request} req + * @param {import("express").Response} res + * @returns + */ +module.exports = async function (req, res) { + if (!pluginsConfig?.syncToFhirServer?.enable) return; + + setImmediate(async () => { + for (let i = 0; i < res.locals.storeInfos.length; i++) { + /** @type { import("./storeInfo").StoreInfo } */ + let storeInfo = res.locals.storeInfos[i]; + let dicomFhirService = new DicomFhirService(req, storeInfo.dicomJsonModel); + await dicomFhirService.initDicomFhirConverter(); + await dicomFhirService.postDicomToFhirServerAndStoreLog(); + } + }); + +}; \ No newline at end of file diff --git a/models/mongodb/models/syncFHIRLog.js b/plugins/syncToFhirServer/mongoose/syncFHIRLog.js similarity index 100% rename from models/mongodb/models/syncFHIRLog.js rename to plugins/syncToFhirServer/mongoose/syncFHIRLog.js diff --git a/plugins/syncToFhirServer/storeInfo.d.ts b/plugins/syncToFhirServer/storeInfo.d.ts new file mode 100644 index 00000000..e73e0f91 --- /dev/null +++ b/plugins/syncToFhirServer/storeInfo.d.ts @@ -0,0 +1,7 @@ +import type { DicomJsonModel } from "@models/DICOM/dicom-json-model" +import type { DicomFileSaveInfo } from "@root/utils/typeDef/STOW-RS/STOW-RS" + +export type StoreInfo = { + dicomFileSaveInfo: DicomFileSaveInfo, + dicomJsonModel: DicomJsonModel +} \ No newline at end of file