diff --git a/Cargo.lock b/Cargo.lock index 07dda9f..4725d89 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -812,6 +812,7 @@ dependencies = [ "mime", "serde", "serde_json", + "uuid", ] [[package]] @@ -2073,6 +2074,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "uuid" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" +dependencies = [ + "getrandom", +] + [[package]] name = "version_check" version = "0.9.4" diff --git a/server/Cargo.toml b/server/Cargo.toml index 419e5ca..da21856 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -21,3 +21,4 @@ memchr = "2.7.1" mime = "0.3.17" serde = { version = "1.0.196", features = ["derive"] } serde_json = "1.0.113" +uuid = { version = "1.7.0", features = ["v4"] } diff --git a/server/src/multipart/builder.rs b/server/src/multipart/builder.rs new file mode 100644 index 0000000..815d7c7 --- /dev/null +++ b/server/src/multipart/builder.rs @@ -0,0 +1,43 @@ +use std::io::{self, Read, Write}; +use uuid::Uuid; + +pub struct MultipartWriter { + boundary: String, + pub data: Vec, + first: bool, +} + +impl MultipartWriter { + pub fn new() -> MultipartWriter { + MultipartWriter { + boundary: format!("boundary-{}", Uuid::new_v4()), + first: true, + data: Vec::new(), + } + } + + pub fn new_with_boundary(boundary: &str) -> MultipartWriter { + MultipartWriter { + boundary: boundary.to_string(), + first: true, + data: Vec::new(), + } + } + + pub fn add(self: &mut Self, reader: &mut dyn Read) -> io::Result { + // writer for the result + let mut writer = std::io::BufWriter::new(&mut self.data); + + // write the boundary + if !self.first { + writer.write_all(b"\r\n").unwrap(); + } + + writer.write_all(b"--").unwrap(); + writer.write_all(self.boundary.as_bytes()).unwrap(); + writer.write_all(b"\r\n").unwrap(); + + // write the content + io::copy(reader, &mut writer) + } +} diff --git a/server/src/multipart/mod.rs b/server/src/multipart/mod.rs index 806e331..2f8b310 100644 --- a/server/src/multipart/mod.rs +++ b/server/src/multipart/mod.rs @@ -1,4 +1,6 @@ +mod builder; mod extractor; mod reader; +pub use builder::*; pub use reader::*; diff --git a/server/src/wado.rs b/server/src/wado.rs index 2bc55e4..7907143 100644 --- a/server/src/wado.rs +++ b/server/src/wado.rs @@ -1,5 +1,9 @@ +use std::io::Cursor; + use actix_web::{get, web, HttpResponse, Responder}; +use crate::{multipart::MultipartWriter, DicomWebServer}; + /// WADO-RS /// /// @@ -18,11 +22,33 @@ pub async fn retrieve_series( #[get("/studies/{study_uid}/series/{series_uid}/instances/{instance_uid}")] pub async fn retrieve_instance( - _study_uid: web::Path, - _series_uid: web::Path, - _instance_uid: web::Path, + callbacks: web::Data, + study_uid: web::Path, + series_uid: web::Path, + instance_uid: web::Path, ) -> impl Responder { - HttpResponse::Ok().body("retrieve_instance") + let result = (callbacks.retrieve_instance)(&study_uid, &series_uid, &instance_uid); + + match result { + Ok(dcm_file) => { + let mut mp = MultipartWriter::new(); + + // Write the DICOM file to memory and add it to our stream + let mut cursor = Cursor::new(Vec::new()); + if let Err(e) = dcm_file.write_all(cursor.clone()) { + return HttpResponse::InternalServerError().body(e.to_string()); + } + + if let Err(e) = mp.add(&mut cursor) { + return HttpResponse::InternalServerError().body(e.to_string()); + } + + return HttpResponse::Ok() + .content_type("multipart/related; type=application/dicom") + .body(mp.data); + } + Err(e) => return HttpResponse::InternalServerError().body(e.to_string()), + } } pub fn wado_config(cfg: &mut web::ServiceConfig) {