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}