1use crate::error::*;
18use crate::raw;
19use crate::{Napchart, RemoteNapchart};
20use std::convert::TryInto;
21
22pub struct UploadBuilder<'c> {
32 chart: &'c Napchart,
33 title: Option<String>,
34 description: Option<String>,
35}
36impl<'c> UploadBuilder<'c> {
37 pub(crate) fn new(n: &'c Napchart) -> Self {
38 Self {
39 chart: n,
40 title: None,
41 description: None,
42 }
43 }
44 pub fn title<T: AsRef<str>>(self, title: T) -> Self {
54 assert!(title.as_ref().len() <= 100);
55 Self {
56 title: Some(title.as_ref().to_string()),
57 ..self
58 }
59 }
60 pub fn description<T: AsRef<str>>(self, description: T) -> Self {
70 Self {
71 description: Some(description.as_ref().to_string()),
72 ..self
73 }
74 }
75 fn build(self) -> Result<raw::ChartUploadRequest> {
76 Ok(raw::ChartUploadRequest {
77 chart_data: self.chart.clone().try_into()?,
78 title: self.title,
79 description: self.description,
80 })
81 }
82}
83
84#[doc(hidden)]
85pub mod mock {
86 #[derive(Default)]
87 pub struct BlockingClient {}
88 impl BlockingClient {
89 #[allow(dead_code)]
90 pub fn create_snapshot(
91 &self,
92 payload: super::UploadBuilder,
93 ) -> Result<(), crate::ErrorKind> {
94 let _ = payload.build()?;
95 Ok(())
96 }
97 }
98}
99
100#[derive(Default)]
103pub struct BlockingClient {
104 internal: reqwest::blocking::Client,
105}
106impl BlockingClient {
107 pub fn create_snapshot(&self, payload: UploadBuilder) -> Result<RemoteNapchart> {
110 self.internal
111 .post("https://api.napchart.com/v1/createSnapshot")
112 .json(&payload.build()?)
113 .send()?
114 .json::<raw::ChartCreationReturn>()?
115 .try_into()
116 }
117 pub fn get_chart<T: AsRef<str>>(&self, chartid: T) -> Result<RemoteNapchart> {
120 self.internal
121 .get(format!(
122 "https://api.napchart.com/v1/getChart/{}",
123 chartid.as_ref()
124 ))
125 .send()?
126 .json::<raw::ChartCreationReturn>()?
127 .try_into()
128 }
129 #[allow(dead_code)]
130 pub(crate) fn get_chart_raw<T: AsRef<str>>(
131 &self,
132 chartid: T,
133 ) -> Result<raw::ChartCreationReturn> {
134 Ok(self
135 .internal
136 .get(format!(
137 "https://api.napchart.com/v1/getChart/{}",
138 chartid.as_ref()
139 ))
140 .send()?
141 .json::<raw::ChartCreationReturn>()?)
142 }
143}
144
145#[derive(Default)]
148pub struct AsyncClient {
149 internal: reqwest::Client,
150}
151impl AsyncClient {
152 pub async fn create_snapshot(&self, payload: UploadBuilder<'_>) -> Result<RemoteNapchart> {
155 self.internal
156 .post("https://api.napchart.com/v1/createSnapshot")
157 .json(&payload.build()?)
158 .send()
159 .await?
160 .json::<raw::ChartCreationReturn>()
161 .await?
162 .try_into()
163 }
164 pub async fn get_chart<T: AsRef<str>>(&self, chartid: T) -> Result<RemoteNapchart> {
167 self.internal
168 .get(format!(
169 "https://api.napchart.com/v1/getChart/{}",
170 chartid.as_ref()
171 ))
172 .send()
173 .await?
174 .json::<raw::ChartCreationReturn>()
175 .await?
176 .try_into()
177 }
178}
179
180#[cfg(test)]
181mod tests {
182 use super::*;
183 use tokio::task::spawn_blocking;
184 #[test]
199 fn get_chart() {
200 let client = BlockingClient::default();
201 let rchart = client.get_chart("jex3y").unwrap();
202 assert_eq!(rchart.chartid, "jex3y");
203 assert_eq!(rchart.title, Some("simple test chart".to_string()));
204 assert!(rchart.description.is_none());
205 assert_eq!(rchart.username, Some("barrow".to_string()));
206 assert!(!rchart.is_snapshot);
207 assert_eq!(
208 rchart.public_link,
209 Some("https://napchart.com/barrow/simple-test-chart-jex3y".to_string())
210 );
211 let chart = rchart.chart;
212 assert_eq!(chart.shape, crate::ChartShape::Circle);
213 assert!(chart.color_tags.is_empty());
214 assert_eq!(chart.lanes.len(), 1);
215 let lane = chart.lanes.get(0).unwrap();
216 assert!(!lane.locked);
217 assert_eq!(lane.elements.len(), 2);
218 }
219 #[test]
220 fn get_custom_colors() {
221 let client = BlockingClient::default();
222 let rchart = client.get_chart("oo81DYL84").unwrap();
223 let chart = rchart.chart;
227 assert_eq!(chart.color_tags.len(), 12);
228 let custom_0 = chart.color_tags.get(&crate::ChartColor::Custom0).unwrap();
229 println!("{:#?}", chart);
230 assert_eq!(custom_0, "custom_0 tag");
231 assert_eq!(
232 chart.custom_colors[0],
233 Some(colorsys::Rgb::from((0x50, 0x81, 0x4a)))
234 );
235 }
236 #[test]
237 fn create_snapshot() {
238 let client = BlockingClient::default();
239 let mut lchart = Napchart::default().shape(crate::ChartShape::Circle);
240 lchart
241 .add_lane()
242 .add_element(0, 8 * 60)
243 .unwrap()
244 .color(crate::ChartColor::Red);
245 lchart
246 .add_lane()
247 .add_element(8 * 60, 16 * 60)
248 .unwrap()
249 .color(crate::ChartColor::Blue);
250 let rchart = client
251 .create_snapshot(lchart.upload().title("napchart simple test chart"))
252 .unwrap();
253 assert_eq!(rchart.title, Some("napchart simple test chart".to_string()));
254 assert!(rchart.description.is_none());
255 assert_eq!(rchart.username, None);
256 assert!(rchart.is_snapshot);
257 assert_eq!(rchart.chart, lchart);
258 let chart = rchart.chart;
259 assert_eq!(chart.shape, crate::ChartShape::Circle);
260 assert!(chart.color_tags.is_empty());
261 assert_eq!(chart.lanes.len(), 2);
262 let lane1 = chart.lanes.get(0).unwrap();
263 let lane2 = chart.lanes.get(1).unwrap();
264 assert!(!lane1.locked);
265 assert!(!lane2.locked);
266 assert_eq!(lane1.elements.len(), 1);
267 assert_eq!(lane2.elements.len(), 1);
268 let elem1 = lane1.elems_iter().next().unwrap();
269 let elem2 = lane2.elems_iter().next().unwrap();
270 assert_eq!(elem1.start, 0);
271 assert_eq!(elem1.end, 8 * 60);
272 assert_eq!(elem2.start, 8 * 60);
273 assert_eq!(elem2.end, 16 * 60);
274 let elemd1 = &elem1.data;
275 let elemd2 = &elem2.data;
276 assert_eq!(elemd1.text, String::new());
277 assert_eq!(elemd2.text, String::new());
278 assert_eq!(elemd1.color, crate::ChartColor::Red);
279 assert_eq!(elemd2.color, crate::ChartColor::Blue);
280 }
281 #[tokio::test]
282 async fn get_chart_eq() {
283 let bres = spawn_blocking(move || {
284 let bclient = BlockingClient::default();
285 bclient.get_chart("bwul9").unwrap()
286 })
287 .await
288 .unwrap();
289 let aclient = AsyncClient::default();
290 let ares = aclient.get_chart("bwul9").await.unwrap();
291 assert!(ares.semantic_eq(&bres));
292 }
293 #[tokio::test]
294 async fn create_snapshot_eq() {
295 let mut achart = Napchart::default();
296 let lane = achart.add_lane();
297 lane.add_element(1, 72).unwrap();
298 lane.add_element(470, 472).unwrap();
299 lane.add_element(870, 873).unwrap();
300 lane.add_element(1270, 1274).unwrap();
301 let bchart = achart.clone();
302 let aup = achart
303 .upload()
304 .title("create_snapshot equivalence test")
305 .description("");
306 let (brchart1, brchart2) = spawn_blocking(move || {
307 let bup = bchart
308 .upload()
309 .title("create_snapshot equivalence test")
310 .description("");
311 let bclient = BlockingClient::default();
312 let brchart1 = bclient.create_snapshot(bup).unwrap();
313 let brchart2 = bclient.get_chart(&brchart1.chartid).unwrap();
314 (brchart1, brchart2)
315 })
316 .await
317 .unwrap();
318 let aclient = AsyncClient::default();
319 let archart1 = aclient.create_snapshot(aup).await.unwrap();
320 let archart2 = aclient.get_chart(&archart1.chartid).await.unwrap();
321 assert!(archart1.semantic_eq(&brchart1));
322 assert!(archart2.semantic_eq(&brchart2));
323 }
325}