dicomweb_client/
lib.rs

1use dicom::object::InMemDicomObject;
2use log::info;
3use thiserror::Error;
4
5pub use dicomweb_util::DICOMJson;
6pub mod async_surf;
7pub mod reqwest;
8
9#[derive(Error, Debug)]
10pub enum Error {
11    #[error("{0}")]
12    Io(#[from] std::io::Error),
13    #[error("{0}")]
14    Reqwest(#[from] reqwest::Error),
15    #[error("{0}")]
16    Surf(surf::Error),
17    #[error("{0}")]
18    Serde(#[from] serde_json::Error),
19    #[error("{0}")]
20    Dicom(#[from] dicom::object::Error),
21    #[error("{0}")]
22    DicomCastValue(#[from] dicom::core::value::CastValueError),
23    #[error("{0}")]
24    Util(#[from] dicomweb_util::Error),
25    #[error("{0}")]
26    Http(#[from] http::header::ToStrError),
27    #[error("{0}")]
28    DICOMweb(String),
29}
30pub type Result<T> = std::result::Result<T, Error>;
31
32pub trait DICOMwebClient {
33    type QueryBuilder: DICOMQueryBuilder;
34
35    fn default_headers(self, key: &'static str, value: &str) -> Self;
36
37    fn search_studies(&mut self) -> Self::QueryBuilder {
38        let url = format!("{}/studies", self.get_qido_prefix());
39        info!("get url {}", &url);
40        self.get_url(&url)
41            .header("Accept", "application/dicom+json")
42    }
43
44    fn search_series(&mut self, study_instance_uid: &str) -> Self::QueryBuilder {
45        let url = format!(
46            "{}/studies/{}/series",
47            self.get_qido_prefix(),
48            study_instance_uid
49        );
50        info!("get url {}", &url);
51        self.get_url(&url)
52            .header("Accept", "application/dicom+json")
53    }
54
55    fn search_instances(
56        &mut self,
57        study_instance_uid: &str,
58        series_instance_uid: &str,
59    ) -> Self::QueryBuilder {
60        let url = format!(
61            "{}/studies/{}/series/{}/instances",
62            self.get_qido_prefix(),
63            study_instance_uid,
64            series_instance_uid,
65        );
66        info!("get url {}", &url);
67        self.get_url(&url)
68            .header("Accept", "application/dicom+json")
69    }
70
71    fn retrieve_study(&mut self, study_instance_uid: &str) -> Self::QueryBuilder {
72        todo!()
73    }
74
75    fn retrieve_series(
76        &mut self,
77        study_instance_uid: &str,
78        series_instance_uid: &str,
79    ) -> Self::QueryBuilder {
80        todo!()
81    }
82
83    fn retrieve_instance(
84        &mut self,
85        study_instance_uid: &str,
86        series_instance_uid: &str,
87        sop_instance_uid: &str,
88    ) -> Self::QueryBuilder {
89        let url = format!(
90            "{}/studies/{}/series/{}/instances/{}",
91            self.get_wado_prefix(),
92            study_instance_uid,
93            series_instance_uid,
94            sop_instance_uid,
95        );
96        info!("get url {}", &url);
97        self.get_url(&url)
98            .header("Accept", "multipart/related; type=\"application/dicom\"")
99    }
100
101    fn store_instances(&mut self) -> Self::QueryBuilder {
102        todo!();
103    }
104
105    fn get_url(&mut self, url: &str) -> Self::QueryBuilder;
106    fn get_qido_prefix(&self) -> &str;
107    fn get_wado_prefix(&self) -> &str;
108}
109
110pub trait DICOMQueryBuilder {
111    fn query(self, key: &str, value: &str) -> Self;
112    fn header(self, key: &str, value: &str) -> Self;
113
114    fn patient_name(self, name_query: &str) -> Self
115    where
116        Self: Sized,
117    {
118        self.query("PatientName", name_query)
119    }
120
121    fn limit(self, limit: u32) -> Self
122    where
123        Self: Sized,
124    {
125        self.query("limit", limit.to_string().as_str())
126    }
127
128    fn offset(self, offset: u32) -> Self
129    where
130        Self: Sized,
131    {
132        self.query("offset", offset.to_string().as_str())
133    }
134}
135
136#[cfg(test)]
137mod tests {
138    #[test]
139    fn it_works() {
140        assert_eq!(2 + 2, 4);
141    }
142}