dicomweb_client/
async_surf.rs1use crate::{DICOMQueryBuilder, Error, Result};
2use bytes::{Buf, Bytes};
3use dicom::object::{DefaultDicomObject, InMemDicomObject};
4use dicomweb_util::{dicom_from_reader, json2dicom, parse_multipart_body};
5use log::debug;
6use serde::de::DeserializeOwned;
7use serde::{Deserialize, Serialize};
8use serde_json::Value;
9use std::collections::HashMap;
10use std::{convert::TryInto, fmt::format, io::Cursor, marker::PhantomData};
11use surf::Url;
12
13use crate::DICOMwebClient;
14
15impl From<surf::Error> for crate::Error {
16 fn from(e: surf::Error) -> Self {
17 crate::Error::Surf(e)
18 }
19}
20
21#[derive(Default, Debug)]
22pub struct Client {
23 client: surf::Client,
24 config: surf::Config,
25 url: Option<Url>,
26 qido_url_prefix: String,
27 wado_url_prefix: String,
28 stow_url_prefix: String,
29 ups_url_prefix: String,
30}
31
32impl DICOMwebClient for Client {
33 type QueryBuilder = QueryBuilder;
34
35 fn default_headers(mut self, key: &'static str, value: &str) -> Self {
36 self.config = self.config.add_header(key, value).unwrap();
37 self
38 }
39
40 fn get_url(&mut self, url: &str) -> Self::QueryBuilder {
41 let mut newurl = self.url.clone().unwrap();
42 let mut basepath = newurl.path();
43 if basepath == "/" {
44 basepath = "";
45 }
46 let path = format!("{}{}", basepath, url);
47 newurl.set_path(&path.as_str());
48 QueryBuilder {
49 request_builder: self.client.get(newurl),
50 query: Default::default(),
51 }
52 }
53
54 fn get_qido_prefix(&self) -> &str {
55 &self.qido_url_prefix
56 }
57 fn get_wado_prefix(&self) -> &str {
58 &self.wado_url_prefix
59 }
60}
61
62impl Client {
63 pub fn new(url: &str) -> Self {
64 let config = surf::Config::new();
65 let client = surf::Client::new();
66 Self {
67 client,
68 config,
69 url: Some(Url::parse(&url).unwrap()),
70 ..Default::default()
71 }
72 }
73
74 }
80
81pub struct QueryBuilder {
82 query: HashMap<String, String>,
83 request_builder: surf::RequestBuilder,
84}
85
86impl DICOMQueryBuilder for QueryBuilder {
87 fn query(mut self, key: &str, value: &str) -> Self {
88 self.query.insert(key.to_string(), value.to_string());
89 self
90 }
91
92 fn header(mut self, key: &str, value: &str) -> Self {
93 self.request_builder = self.request_builder.header(key, value);
94 self
95 }
96}
97
98impl QueryBuilder {
99 pub async fn results(self) -> Result<Vec<InMemDicomObject>> {
100 let req = self.request_builder.query(&self.query)?;
101 debug!("req: {:?}", req);
102 let mut res = req.send().await?;
103 let content_type = res.header("content-type").unwrap().get(0).unwrap();
104 println!("content-type: {}", content_type);
105
106 if !content_type.as_str().starts_with("application/dicom+json") {
107 panic!(
108 "invalid content type, should be application/dicom+json, response: {:?}",
109 res
110 )
111 }
115
116 let json: Vec<Value> = res.body_json().await?;
117 Ok(json2dicom(&json)?)
118 }
119
120 pub async fn dicoms(self) -> Result<Vec<DefaultDicomObject>> {
121 let mut res = self.request_builder.query(&self.query)?.send().await?;
122 let content_type = res.header("content-type").unwrap().get(0).unwrap();
123 println!("content-type: {}", content_type);
124 let (_, boundary) = content_type.as_str().rsplit_once("boundary=").unwrap();
125 let boundary = String::from(boundary);
126 println!("boundary: {}", boundary);
127
128 let body: Bytes = res.body_bytes().await?.into();
129 let parts = parse_multipart_body(body, &boundary)?;
130 let result = parts
131 .iter()
132 .map(|part| {
133 let reader = Cursor::new(part).reader();
134 dicom_from_reader(reader).unwrap()
135 })
136 .collect();
137 Ok(result)
138 }
139}