From 30e13ae38acb70c51d96391926823138a6e48cca Mon Sep 17 00:00:00 2001 From: "CHIN\\a5566" Date: Mon, 14 Aug 2023 16:47:29 +0800 Subject: [PATCH] feat: Retrieve Transaction Metadata Resources APIs --- .../metadata/retrieveInstanceMetadata.js | 65 +++++++++++++++++ .../metadata/retrieveSeriesMetadata.js | 68 ++++++++++++++++++ .../WADO-RS/metadata/retrieveStudyMetadata.js | 71 +++++++++++++++++++ api-sql/dicom-web/wado-rs-metadata.route.js | 71 +++++++++++++++++++ routes.js | 2 +- 5 files changed, 276 insertions(+), 1 deletion(-) create mode 100644 api-sql/dicom-web/controller/WADO-RS/metadata/retrieveInstanceMetadata.js create mode 100644 api-sql/dicom-web/controller/WADO-RS/metadata/retrieveSeriesMetadata.js create mode 100644 api-sql/dicom-web/controller/WADO-RS/metadata/retrieveStudyMetadata.js create mode 100644 api-sql/dicom-web/wado-rs-metadata.route.js diff --git a/api-sql/dicom-web/controller/WADO-RS/metadata/retrieveInstanceMetadata.js b/api-sql/dicom-web/controller/WADO-RS/metadata/retrieveInstanceMetadata.js new file mode 100644 index 00000000..8b47b5d1 --- /dev/null +++ b/api-sql/dicom-web/controller/WADO-RS/metadata/retrieveInstanceMetadata.js @@ -0,0 +1,65 @@ +const _ = require("lodash"); +const fs = require("fs"); +const path = require("path"); +const fileExist = require("@root/utils/file/fileExist"); +const wadoService = require("../service/WADO-RS.service"); +const errorResponse = require("@root/utils/errorResponse/errorResponseMessage"); +const { Controller } = require("@root/api/controller.class"); +const { ApiLogger } = require("@root/utils/logs/api-logger"); +const { InstanceModel } = require("@models/sql/models/instance.model"); + +class RetrieveInstanceMetadataController extends Controller { + constructor(req, res) { + super(req, res); + } + + async mainProcess() { + let apiLogger = new ApiLogger(this.request, "WADO-RS"); + + apiLogger.addTokenValue(); + apiLogger.logger.info(`[WADO-RS] [Get Study's Series' Instance Metadata] [instance UID: ${this.request.params.instanceUID}, series UID: ${this.request.params.seriesUID}, study UID: ${this.request.params.studyUID}]`); + try { + let responseMetadata = []; + + let imagePathObj = await InstanceModel.getPathOfInstance(this.request.params); + if (imagePathObj) { + let instanceDir = path.dirname(imagePathObj.instancePath); + let metadataPath = path.join(instanceDir, `${imagePathObj.instanceUID}.metadata.json`); + if (await fileExist(metadataPath)) { + let metadataJsonStr = fs.readFileSync(metadataPath, { encoding: "utf-8" }); + let metadataJson = JSON.parse(metadataJsonStr); + wadoService.addHostnameOfBulkDataUrl(metadataJson, this.request); + responseMetadata.push(metadataJson); + } + this.response.writeHead(200, { + "Content-Type": "application/dicom+json" + }); + return this.response.end(JSON.stringify(responseMetadata)); + } + + this.response.writeHead(204); + return this.response.end(JSON.stringify( + errorResponse.getNotFoundErrorMessage( + `Not found metadata of instance UID: ${this.request.params.instanceUID}, series UID: ${this.request.params.seriesUID}, study UID: ${this.request.params.studyUID}` + ) + )); + } catch(e) { + let errorStr = JSON.stringify(e, Object.getOwnPropertyNames(e)); + console.error(errorStr); + this.response.writeHead(500, { + "Content-Type": "application/dicom+json" + }); + return this.response.end(); + } + } +} +/** + * + * @param {import("http").IncomingMessage} req + * @param {import("http").ServerResponse} res + */ +module.exports = async function(req, res) { + let controller = new RetrieveInstanceMetadataController(req, res); + + await controller.doPipeline(); +}; \ No newline at end of file diff --git a/api-sql/dicom-web/controller/WADO-RS/metadata/retrieveSeriesMetadata.js b/api-sql/dicom-web/controller/WADO-RS/metadata/retrieveSeriesMetadata.js new file mode 100644 index 00000000..ecfb2905 --- /dev/null +++ b/api-sql/dicom-web/controller/WADO-RS/metadata/retrieveSeriesMetadata.js @@ -0,0 +1,68 @@ +const _ = require("lodash"); +const fs = require("fs"); +const path = require("path"); +const fileExist = require("@root/utils/file/fileExist"); +const wadoService = require("../service/WADO-RS.service"); +const errorResponse = require("@root/utils/errorResponse/errorResponseMessage"); +const { Controller } = require("@root/api/controller.class"); +const { ApiLogger } = require("@root/utils/logs/api-logger"); +const { SeriesModel } = require("@models/sql/models/series.model"); + +class RetrieveSeriesMetadataController extends Controller { + constructor(req, res) { + super(req, res); + } + + async mainProcess() { + let apiLogger = new ApiLogger(this.request, "WADO-RS"); + apiLogger.addTokenValue(); + + + apiLogger.logger.info(`[WADO-RS] [Get Study's Series' Instances Metadata] [series UID: ${this.request.params.seriesUID}, study UID: ${this.request.params.studyUID}]`); + try { + let responseMetadata = []; + + let imagesPathList = await SeriesModel.getPathGroupOfInstances(this.request.params); + if (imagesPathList.length > 0) { + for (let imagePathObj of imagesPathList) { + let instanceDir = path.dirname(imagePathObj.instancePath); + let metadataPath = path.join(instanceDir, `${imagePathObj.instanceUID}.metadata.json`); + if (await fileExist(metadataPath)) { + let metadataJsonStr = fs.readFileSync(metadataPath, { encoding: "utf-8" }); + let metadataJson = JSON.parse(metadataJsonStr); + wadoService.addHostnameOfBulkDataUrl(metadataJson, this.request); + responseMetadata.push(metadataJson); + } + } + this.response.writeHead(200, { + "Content-Type": "application/dicom+json" + }); + return this.response.end(JSON.stringify(responseMetadata)); + } + + this.response.writeHead(204); + return this.response.end(JSON.stringify( + errorResponse.getNotFoundErrorMessage( + `Not found metadata of series UID:${this.request.params.seriesUID} study UID: ${this.request.params.studyUID}` + ) + )); + } catch(e) { + let errorStr = JSON.stringify(e, Object.getOwnPropertyNames(e)); + console.error(errorStr); + this.response.writeHead(500, { + "Content-Type": "application/dicom+json" + }); + return this.response.end(); + } + } +} +/** + * + * @param {import("http").IncomingMessage} req + * @param {import("http").ServerResponse} res + */ +module.exports = async function(req, res) { + let controller = new RetrieveSeriesMetadataController(req, res); + + await controller.doPipeline(); +}; \ No newline at end of file diff --git a/api-sql/dicom-web/controller/WADO-RS/metadata/retrieveStudyMetadata.js b/api-sql/dicom-web/controller/WADO-RS/metadata/retrieveStudyMetadata.js new file mode 100644 index 00000000..16a7bcf0 --- /dev/null +++ b/api-sql/dicom-web/controller/WADO-RS/metadata/retrieveStudyMetadata.js @@ -0,0 +1,71 @@ +const _ = require("lodash"); +const fs = require("fs"); +const path = require("path"); +const fileExist = require("@root/utils/file/fileExist"); +const wadoService = require("../service/WADO-RS.service"); +const errorResponse = require("@root/utils/errorResponse/errorResponseMessage"); +const { Controller } = require("@root/api/controller.class"); +const { ApiLogger } = require("@root/utils/logs/api-logger"); +const { StudyModel } = require("@models/sql/models/study.model"); + +class RetrieveStudyMetadataController extends Controller { + constructor(req, res) { + super(req, res); + } + + async mainProcess() { + + let apiLogger = new ApiLogger(this.request, "WADO-RS"); + apiLogger.addTokenValue(); + + apiLogger.logger.info(`Get Study's Instances Metadata [study UID: ${this.request.params.studyUID}]`); + + try { + let responseMetadata = []; + + let pathGroupOfInstancesInStudy = await StudyModel.getPathGroupOfInstances(this.request.params); + + if (pathGroupOfInstancesInStudy.length > 0) { + + for (let imagePathObj of pathGroupOfInstancesInStudy) { + let instanceDir = path.dirname(imagePathObj.instancePath); + let metadataPath = path.join(instanceDir, `${imagePathObj.instanceUID}.metadata.json`); + if (await fileExist(metadataPath)) { + let metadataJsonStr = fs.readFileSync(metadataPath, { encoding: "utf-8" }); + let metadataJson = JSON.parse(metadataJsonStr); + wadoService.addHostnameOfBulkDataUrl(metadataJson, this.request); + responseMetadata.push(metadataJson); + } + } + + this.response.writeHead(200, { + "Content-Type": "application/dicom+json" + }); + return this.response.end(JSON.stringify(responseMetadata)); + } + + this.response.writeHead(204); + return this.response.end(); + + } catch(e) { + let errorStr = JSON.stringify(e, Object.getOwnPropertyNames(e)); + apiLogger.logger.error(errorStr); + + this.response.writeHead(500, { + "Content-Type": "application/dicom+json" + }); + return this.response.end(); + } + } +} + +/** + * + * @param {import("http").IncomingMessage} req + * @param {import("http").ServerResponse} res + */ +module.exports = async function(req, res) { + let controller = new RetrieveStudyMetadataController(req, res); + + await controller.doPipeline(); +}; \ No newline at end of file diff --git a/api-sql/dicom-web/wado-rs-metadata.route.js b/api-sql/dicom-web/wado-rs-metadata.route.js new file mode 100644 index 00000000..9bd25200 --- /dev/null +++ b/api-sql/dicom-web/wado-rs-metadata.route.js @@ -0,0 +1,71 @@ +const express = require("express"); +const Joi = require("joi"); +const { validateParams, intArrayJoi } = require("@root/api/validator"); +const router = express(); + + +//#region WADO-RS Retrieve Transaction Metadata Resources + +/** + * @openapi + * /dicom-web/studies/{studyUID}/metadata: + * get: + * tags: + * - WADO-RS + * description: Retrieve Study's instances' metadata + * parameters: + * - $ref: "#/components/parameters/studyUID" + * responses: + * 200: + * $ref: "#/components/responses/DicomMetadata" + * + */ +router.get( + "/studies/:studyUID/metadata", + require("./controller/WADO-RS/metadata/retrieveStudyMetadata") +); + +/** + * @openapi + * /dicom-web/studies/{studyUID}/series/{seriesUID}/metadata: + * get: + * tags: + * - WADO-RS + * description: Retrieve Study's series' instances' metadata + * parameters: + * - $ref: "#/components/parameters/studyUID" + * - $ref: "#/components/parameters/seriesUID" + * responses: + * 200: + * $ref: "#/components/responses/DicomMetadata" + * + */ +router.get( + "/studies/:studyUID/series/:seriesUID/metadata", + require("./controller/WADO-RS/metadata/retrieveSeriesMetadata") +); + +/** + * @openapi + * /dicom-web/studies/{studyUID}/series/{seriesUID}/instances/{instanceUID}/metadata: + * get: + * tags: + * - WADO-RS + * description: Retrieve instance's metadata + * parameters: + * - $ref: "#/components/parameters/studyUID" + * - $ref: "#/components/parameters/seriesUID" + * - $ref: "#/components/parameters/instanceUID" + * responses: + * 200: + * $ref: "#/components/responses/DicomMetadata" + * + */ +router.get( + "/studies/:studyUID/series/:seriesUID/instances/:instanceUID/metadata", + require("./controller/WADO-RS/metadata/retrieveInstanceMetadata") +); + +//#endregion + +module.exports = router; \ No newline at end of file diff --git a/routes.js b/routes.js index 6aea6b4b..e09c44cd 100644 --- a/routes.js +++ b/routes.js @@ -22,7 +22,7 @@ module.exports = function (app) { app.use("/dicom-web", require("./api-sql/dicom-web/stow-rs.route")); app.use("/dicom-web", require("./api-sql/dicom-web/qido-rs.route")); app.use("/dicom-web", require("./api-sql/dicom-web/wado-rs-instance.route")); - app.use("/dicom-web", require("./api/dicom-web/wado-rs-metadata.route")); + app.use("/dicom-web", require("./api-sql/dicom-web/wado-rs-metadata.route")); app.use("/dicom-web", require("./api-sql/dicom-web/wado-rs-rendered.route")); app.use("/dicom-web", require("./api/dicom-web/wado-rs-bulkdata.route")); app.use("/dicom-web", require("./api/dicom-web/wado-rs-thumbnail.route"));