dicomweb_client/reqwest/
mod.rs1use reqwest;
2use reqwest::header;
3use reqwest::header::{HeaderMap, HeaderName, HeaderValue};
4
5pub use reqwest::Error;
6#[cfg(not(target_arch = "wasm32"))]
7use reqwest::Proxy;
8use serde::Serialize;
9use std::convert::TryFrom;
10use std::env;
11
12use crate::{DICOMQueryBuilder, DICOMwebClient};
13
14pub mod async_reqwest;
15pub mod blocking_reqwest;
16
17pub trait ReqwestClientBuilder {
18 type Client: ReqwestClient + Default;
19
20 fn new() -> Self;
21 fn proxy(self, proxy: Proxy) -> Self;
22 fn default_headers(self, headers: HeaderMap) -> Self;
23 fn build(self) -> reqwest::Result<Self::Client>;
24}
25
26pub trait ReqwestClient {
27 type ClientBuilder: ReqwestClientBuilder + Default;
28 type RequestBuilder: RequestBuilderTrait;
29
30 fn get<U: reqwest::IntoUrl>(&self, url: U) -> Self::RequestBuilder;
31}
32
33#[derive(Default)]
34pub struct DICOMwebClientReqwest<C, B> {
35 client: Option<C>,
36 config: Option<B>,
37 url: String,
38 qido_url_prefix: String,
39 wado_url_prefix: String,
40 stow_url_prefix: String,
41 ups_url_prefix: String,
42}
43
44impl<C: ReqwestClient, B: ReqwestClientBuilder<Client = C>> DICOMwebClient
45 for DICOMwebClientReqwest<C, B>
46{
47 type QueryBuilder = QueryBuilderReqwest<C::RequestBuilder>;
48
49 fn default_headers(mut self, key: &'static str, value: &str) -> Self {
50 let mut headers = header::HeaderMap::new();
51 headers.insert(key, value.parse().unwrap());
52
53 if let Some(client_builder) = self.config.take() {
54 self.config = Some(client_builder.default_headers(headers));
55 }
56 self
57 }
58
59 fn get_url(&mut self, url: &str) -> Self::QueryBuilder {
60 self.make_client();
61 let url = format!("{}{}", self.url, url);
62 QueryBuilderReqwest {
63 request_builder: self.client.as_ref().unwrap().get(url),
64 }
65 }
66
67 fn get_qido_prefix(&self) -> &str {
68 &self.qido_url_prefix
69 }
70 fn get_wado_prefix(&self) -> &str {
71 &self.wado_url_prefix
72 }
73
74 fn search_studies(&mut self) -> Self::QueryBuilder {
75 let url = format!("{}/studies", self.get_qido_prefix());
76 self.get_url(&url)
77 }
78
79 fn search_series(&mut self, study_instance_uid: &str) -> Self::QueryBuilder {
80 let url = format!(
81 "{}/studies/{}/series",
82 self.get_qido_prefix(),
83 study_instance_uid
84 );
85 self.get_url(&url)
86 }
87
88 fn search_instances(
89 &mut self,
90 study_instance_uid: &str,
91 series_instance_uid: &str,
92 ) -> Self::QueryBuilder {
93 let url = format!(
94 "{}/studies/{}/series/{}/instances",
95 self.get_qido_prefix(),
96 study_instance_uid,
97 series_instance_uid,
98 );
99 self.get_url(&url)
100 }
101
102 fn retrieve_instance(
103 &mut self,
104 study_instance_uid: &str,
105 series_instance_uid: &str,
106 sop_instance_uid: &str,
107 ) -> Self::QueryBuilder {
108 let url = format!(
109 "{}/studies/{}/series/{}/instances/{}",
110 self.get_wado_prefix(),
111 study_instance_uid,
112 series_instance_uid,
113 sop_instance_uid,
114 );
115 self.get_url(&url)
116 }
117}
118
119impl<C: ReqwestClient, B: ReqwestClientBuilder<Client = C>> DICOMwebClientReqwest<C, B> {
120 #[cfg(not(target_arch = "wasm32"))]
121 fn proxy(mut self, proxy: reqwest::Proxy) -> Self {
122 if let Some(client_builder) = self.config.take() {
123 self.config = Some(client_builder.proxy(proxy));
124 }
125 self
126 }
127
128 fn make_client(&mut self) {
129 if let Some(client_builder) = self.config.take() {
130 self.client = client_builder.build().ok();
131 }
132 }
133
134 pub fn new(url: &str) -> Self {
135 let client_builder = Some(B::new());
136 let mut dicomwebclient = Self {
137 client: None,
138 config: client_builder,
139 url: String::from(url),
140 qido_url_prefix: String::default(),
141 wado_url_prefix: String::default(),
142 stow_url_prefix: String::default(),
143 ups_url_prefix: String::default(),
144 };
145
146 #[cfg(not(target_arch = "wasm32"))]
147 if let Ok(proxy) = env::var("http_proxy") {
148 dicomwebclient = dicomwebclient.proxy(reqwest::Proxy::http(proxy).unwrap());
149 }
150
151 dicomwebclient
152 }
153}
154
155pub struct QueryBuilderReqwest<T> {
156 request_builder: T,
157}
158
159pub trait RequestBuilderTrait {
160 fn header<K, V>(self, key: K, value: V) -> Self
161 where
162 HeaderName: TryFrom<K>,
163 HeaderValue: TryFrom<V>,
164 <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
165 <HeaderValue as TryFrom<V>>::Error: Into<http::Error>;
166 fn query<T: Serialize + ?Sized>(self, query: &T) -> Self;
167}
168
169impl<T: RequestBuilderTrait> DICOMQueryBuilder for QueryBuilderReqwest<T> {
170 fn query(mut self, key: &str, value: &str) -> Self {
171 self.request_builder = self.request_builder.query(&[(key, value)]);
172 self
173 }
174
175 fn header(mut self, key: &str, value: &str) -> Self {
176 self.request_builder = self.request_builder.header(key, value);
177 self
178 }
179}
180
181impl<T: RequestBuilderTrait> QueryBuilderReqwest<T> {
182 pub fn header<K, V>(mut self, key: K, value: V) -> QueryBuilderReqwest<T>
183 where
184 HeaderName: TryFrom<K>,
185 <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
186 HeaderValue: TryFrom<V>,
187 <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
188 {
189 self.request_builder = self.request_builder.header(key, value);
190 self
191 }
192}