Skip to content

Commit

Permalink
Add metadata endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
feliwir committed Feb 27, 2024
1 parent 4d5844b commit b2c0039
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 4 deletions.
5 changes: 4 additions & 1 deletion server/src/actix/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ pub fn dicomweb_config(cfg: &mut actix_web::web::ServiceConfig) {
.service(search_instances_study_level)
.service(search_instances_series_level)
.service(retrieve_instance)
.service(retrieve_instance_metadata)
.service(retrieve_series)
.service(retrieve_study);
.service(retrieve_series_metadata)
.service(retrieve_study)
.service(retrieve_study_metadata);
}
11 changes: 9 additions & 2 deletions server/src/actix/qido.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ use actix_web::{get, http, web, HttpRequest, HttpResponse, Responder};
use dicom_json::DicomJson;
use dicom_object::InMemDicomObject;


use crate::{DicomWebServer, QidoInstanceQuery, QidoSeriesQuery, QidoStudyQuery};
use crate::{
DicomWebServer, QidoInstanceQuery, QidoSeriesQuery, QidoStudyQuery, APPLICATION_DICOM_JSON,
};

#[get("/studies")]
pub async fn search_studies_all(
Expand All @@ -18,6 +19,12 @@ pub async fn search_studies_all(
return HttpResponse::NotAcceptable().finish();
}

// If the Accept header is present, it must be application/dicom+json
if accept_header.unwrap().to_str().unwrap() != APPLICATION_DICOM_JSON {
return HttpResponse::NotAcceptable().finish();
}

// Get the matching DICOM objects from the callback
let result = (callbacks.search_study)(&query);

match result {
Expand Down
80 changes: 79 additions & 1 deletion server/src/actix/wado.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use std::io::Write;

use actix_web::{get, web, HttpResponse, Responder};
use dicom::dictionary_std::tags;
use dicom_json::DicomJson;
use dicom_object::InMemDicomObject;

use crate::{actix::MultipartWriter, DicomWebServer};

Expand Down Expand Up @@ -41,6 +44,32 @@ pub async fn retrieve_study(
}
}

#[get("/studies/{study_uid}/metadata")]
pub async fn retrieve_study_metadata(
callbacks: web::Data<DicomWebServer>,
study_uid: web::Path<String>,
) -> impl Responder {
let result = (callbacks.retrieve_study)(&study_uid);

match result {
Ok(dcm_files) => {
// Apply the offset and the filter
let mut filtered: Vec<InMemDicomObject> = dcm_files
.into_iter()
.map(|dcm_file| dcm_file.into_inner())
.collect();

// Remove any bulk data
for dcm in &mut filtered {
dcm.remove_element(tags::PIXEL_DATA);
}

return HttpResponse::Ok().json(DicomJson::from(filtered));
}
Err(e) => return HttpResponse::InternalServerError().body(e.to_string()),
}
}

#[get("/studies/{study_uid}/series/{series_uid}")]
pub async fn retrieve_series(
callbacks: web::Data<DicomWebServer>,
Expand Down Expand Up @@ -76,6 +105,33 @@ pub async fn retrieve_series(
}
}

#[get("/studies/{study_uid}/series/{series_uid}/metadata")]
pub async fn retrieve_series_metadata(
callbacks: web::Data<DicomWebServer>,
path: web::Path<(String, String)>,
) -> impl Responder {
let (study_uid, series_uid) = path.into_inner();
let result = (callbacks.retrieve_series)(&study_uid, &series_uid);

match result {
Ok(dcm_files) => {
// Apply the offset and the filter
let mut filtered: Vec<InMemDicomObject> = dcm_files
.into_iter()
.map(|dcm_file| dcm_file.into_inner())
.collect();

// Remove any bulk data
for dcm in &mut filtered {
dcm.remove_element(tags::PIXEL_DATA);
}

return HttpResponse::Ok().json(DicomJson::from(filtered));
}
Err(e) => return HttpResponse::InternalServerError().body(e.to_string()),
}
}

#[get("/studies/{study_uid}/series/{series_uid}/instances/{instance_uid}")]
pub async fn retrieve_instance(
callbacks: web::Data<DicomWebServer>,
Expand Down Expand Up @@ -109,8 +165,30 @@ pub async fn retrieve_instance(
}
}

#[get("/studies/{study_uid}/series/{series_uid}/instances/{instance_uid}/metadata")]
pub async fn retrieve_instance_metadata(
callbacks: web::Data<DicomWebServer>,
path: web::Path<(String, String, String)>,
) -> impl Responder {
let (study_uid, series_uid, instance_uid) = path.into_inner();
let result = (callbacks.retrieve_instance)(&study_uid, &series_uid, &instance_uid);

match result {
Ok(mut dcm_file) => {
// Remove any bulkdata from the DICOM file
dcm_file.remove_element(tags::PIXEL_DATA);

return HttpResponse::Ok().json(DicomJson::from(dcm_file));
}
Err(e) => return HttpResponse::InternalServerError().body(e.to_string()),
}
}

pub fn wado_config(cfg: &mut web::ServiceConfig) {
cfg.service(retrieve_study)
.service(retrieve_study_metadata)
.service(retrieve_series)
.service(retrieve_instance);
.service(retrieve_series_metadata)
.service(retrieve_instance)
.service(retrieve_instance_metadata);
}
2 changes: 2 additions & 0 deletions server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ pub use filter::study_filter;
#[cfg(feature = "actix")]
pub mod actix;

const APPLICATION_DICOM_JSON: &str = "application/dicom+json";

/// QIDO-RS
///
/// See https://www.dicomstandard.org/using/dicomweb/query-qido-rs for more information
Expand Down

0 comments on commit b2c0039

Please sign in to comment.