refget_client/
async_client.rs1use refget_model::{ComparisonResult, SeqCol, SeqColLevel1, SequenceMetadata, SequenceServiceInfo};
4use reqwest::{Client, RequestBuilder, Response, StatusCode};
5use serde_json::Value;
6
7use crate::error::{ClientError, ClientResult};
8use crate::response::{self, MetadataResponse};
9
10pub struct RefgetClient {
14 client: Client,
15 base_url: String,
16}
17
18impl RefgetClient {
19 pub fn new(base_url: &str) -> ClientResult<Self> {
21 let client = Client::builder().build().map_err(ClientError::Http)?;
22 Self::with_client(client, base_url)
23 }
24
25 pub fn with_client(client: Client, base_url: &str) -> ClientResult<Self> {
27 if base_url.is_empty() {
28 return Err(ClientError::InvalidUrl("base URL must not be empty".to_string()));
29 }
30 Ok(Self { client, base_url: base_url.trim_end_matches('/').to_string() })
31 }
32
33 async fn send_optional(&self, req: RequestBuilder) -> ClientResult<Option<Response>> {
38 let resp = req.send().await?;
39 let status = resp.status();
40 if status.is_success() {
41 Ok(Some(resp))
42 } else if status == StatusCode::NOT_FOUND {
43 Ok(None)
44 } else {
45 let body = resp.text().await.unwrap_or_default();
46 Err(ClientError::ServerError { status: status.as_u16(), body })
47 }
48 }
49
50 async fn send_required(&self, req: RequestBuilder) -> ClientResult<Response> {
52 let resp = req.send().await?;
53 if resp.status().is_success() {
54 Ok(resp)
55 } else {
56 let status = resp.status().as_u16();
57 let body = resp.text().await.unwrap_or_default();
58 Err(ClientError::ServerError { status, body })
59 }
60 }
61
62 pub async fn get_sequence(
69 &self,
70 digest: &str,
71 start: Option<u64>,
72 end: Option<u64>,
73 ) -> ClientResult<Option<Vec<u8>>> {
74 let mut req = self.client.get(format!("{}/sequence/{digest}", self.base_url));
75 if let Some(s) = start {
76 req = req.query(&[("start", s)]);
77 }
78 if let Some(e) = end {
79 req = req.query(&[("end", e)]);
80 }
81 match self.send_optional(req).await? {
82 Some(resp) => Ok(Some(resp.bytes().await?.to_vec())),
83 None => Ok(None),
84 }
85 }
86
87 pub async fn get_metadata(&self, digest: &str) -> ClientResult<Option<SequenceMetadata>> {
89 let req = self.client.get(format!("{}/sequence/{digest}/metadata", self.base_url));
90 match self.send_optional(req).await? {
91 Some(resp) => {
92 let envelope: MetadataResponse = resp.json().await?;
93 Ok(Some(envelope.metadata))
94 }
95 None => Ok(None),
96 }
97 }
98
99 pub async fn get_sequence_service_info(&self) -> ClientResult<SequenceServiceInfo> {
101 let req = self.client.get(format!("{}/sequence/service-info", self.base_url));
102 let resp = self.send_required(req).await?;
103 let value: Value = resp.json().await?;
104 response::deserialize_sequence_service_info(value).map_err(ClientError::Deserialize)
105 }
106
107 pub async fn get_collection_level0(&self, digest: &str) -> ClientResult<Option<String>> {
111 let req = self
112 .client
113 .get(format!("{}/collection/{digest}", self.base_url))
114 .query(&[("level", "0")]);
115 match self.send_optional(req).await? {
116 Some(resp) => {
117 let value: Value = resp.json().await?;
118 match value.as_str() {
119 Some(s) => Ok(Some(s.to_string())),
120 None => Ok(Some(value.to_string())),
121 }
122 }
123 None => Ok(None),
124 }
125 }
126
127 pub async fn get_collection_level1(&self, digest: &str) -> ClientResult<Option<SeqColLevel1>> {
129 let req = self
130 .client
131 .get(format!("{}/collection/{digest}", self.base_url))
132 .query(&[("level", "1")]);
133 match self.send_optional(req).await? {
134 Some(resp) => Ok(Some(resp.json().await?)),
135 None => Ok(None),
136 }
137 }
138
139 pub async fn get_collection_level2(&self, digest: &str) -> ClientResult<Option<SeqCol>> {
141 let req = self
142 .client
143 .get(format!("{}/collection/{digest}", self.base_url))
144 .query(&[("level", "2")]);
145 match self.send_optional(req).await? {
146 Some(resp) => Ok(Some(resp.json().await?)),
147 None => Ok(None),
148 }
149 }
150
151 pub async fn get_collection_raw(&self, digest: &str, level: u8) -> ClientResult<Option<Value>> {
153 let req = self
154 .client
155 .get(format!("{}/collection/{digest}", self.base_url))
156 .query(&[("level", level.to_string())]);
157 match self.send_optional(req).await? {
158 Some(resp) => Ok(Some(resp.json().await?)),
159 None => Ok(None),
160 }
161 }
162
163 pub async fn compare_collections(
165 &self,
166 digest_a: &str,
167 digest_b: &str,
168 ) -> ClientResult<ComparisonResult> {
169 let req = self.client.get(format!("{}/comparison/{digest_a}/{digest_b}", self.base_url));
170 Ok(self.send_required(req).await?.json().await?)
171 }
172
173 pub async fn compare_collection_with(
175 &self,
176 digest: &str,
177 collection: &SeqCol,
178 ) -> ClientResult<ComparisonResult> {
179 let req =
180 self.client.post(format!("{}/comparison/{digest}", self.base_url)).json(collection);
181 Ok(self.send_required(req).await?.json().await?)
182 }
183
184 pub async fn list_collections(
188 &self,
189 filters: &[(&str, &str)],
190 page: usize,
191 page_size: usize,
192 ) -> ClientResult<Value> {
193 let mut req = self
194 .client
195 .get(format!("{}/list/collection", self.base_url))
196 .query(&[("page", page.to_string()), ("page_size", page_size.to_string())]);
197 for (key, value) in filters {
198 req = req.query(&[(key, value)]);
199 }
200 Ok(self.send_required(req).await?.json().await?)
201 }
202
203 pub async fn get_attribute(&self, attr: &str, digest: &str) -> ClientResult<Option<Value>> {
205 let req =
206 self.client.get(format!("{}/attribute/collection/{attr}/{digest}", self.base_url));
207 match self.send_optional(req).await? {
208 Some(resp) => Ok(Some(resp.json().await?)),
209 None => Ok(None),
210 }
211 }
212
213 pub async fn get_seqcol_service_info(&self) -> ClientResult<Value> {
215 let req = self.client.get(format!("{}/service-info", self.base_url));
216 Ok(self.send_required(req).await?.json().await?)
217 }
218}