1pub mod structs;
58pub mod tutorials;
59
60use crate::structs::*;
61use anyhow::{Error, Result};
62use dotenvy::dotenv;
63use fxhash::FxHashMap;
64use indicatif::ProgressBar;
65use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC as NON_ALNUM};
66use reqwest::{self as request, header};
67
68#[cfg(test)]
69mod tests;
70
71fn encode(s: &str) -> String {
72 utf8_percent_encode(s, NON_ALNUM).to_string()
73}
74
75#[derive(Clone, Debug, Default)]
76pub struct QueryParams {
77 pub paper_id: String,
78 pub query_text: Option<String>,
79 pub fields: Option<Vec<PaperField>>,
80 pub author_fields: Option<Vec<AuthorField>>,
81 pub publication_types: Option<Vec<PublicationTypes>>,
82 pub open_access_pdf: Option<bool>,
83 pub min_citation_count: Option<u32>,
84 pub publication_date_or_year: Option<String>,
85 pub year: Option<String>,
86 pub venue: Option<Vec<String>>,
87 pub fields_of_study: Option<Vec<FieldsOfStudy>>,
88 pub offset: Option<u64>,
89 pub limit: Option<u64>,
90 pub token: Option<String>,
91 pub sort: Option<String>,
92}
93
94impl QueryParams {
95 pub fn paper_id(&mut self, paper_id: &str) -> &mut Self {
96 self.paper_id = paper_id.to_string();
97 self
98 }
99 pub fn query_text(&mut self, query_text: &str) -> &mut Self {
100 self.query_text = Some(query_text.to_string());
101 self
102 }
103 pub fn fields(&mut self, fields: Vec<PaperField>) -> &mut Self {
104 self.fields = Some(fields);
105 self
106 }
107 pub fn author_fields(&mut self, author_fields: Vec<AuthorField>) -> &mut Self {
108 self.author_fields = Some(author_fields);
109 self
110 }
111 pub fn publication_types(&mut self, publication_types: Vec<PublicationTypes>) -> &mut Self {
112 self.publication_types = Some(publication_types);
113 self
114 }
115 pub fn open_access_pdf(&mut self, open_access_pdf: bool) -> &mut Self {
116 self.open_access_pdf = Some(open_access_pdf);
117 self
118 }
119 pub fn min_citation_count(&mut self, min_citation_count: u32) -> &mut Self {
120 self.min_citation_count = Some(min_citation_count);
121 self
122 }
123 pub fn publication_date_or_year(&mut self, publication_date_or_year: &str) -> &mut Self {
124 self.publication_date_or_year = Some(publication_date_or_year.to_string());
125 self
126 }
127 pub fn year(&mut self, year: &str) -> &mut Self {
128 self.year = Some(year.to_string());
129 self
130 }
131 pub fn venue(&mut self, venue: Vec<&str>) -> &mut Self {
132 let venue: Vec<String> = venue.iter().map(|v| v.to_string()).collect();
133 self.venue = Some(venue);
134 self
135 }
136 pub fn fields_of_study(&mut self, fields_of_study: Vec<FieldsOfStudy>) -> &mut Self {
137 self.fields_of_study = Some(fields_of_study);
138 self
139 }
140 pub fn offset(&mut self, offset: u64) -> &mut Self {
141 self.offset = Some(offset);
142 self
143 }
144 pub fn limit(&mut self, limit: u64) -> &mut Self {
145 self.limit = Some(limit);
146 self
147 }
148 pub fn token(&mut self, token: &str) -> &mut Self {
149 self.token = Some(token.to_string());
150 self
151 }
152 pub fn sort(&mut self, sort: &str) -> &mut Self {
153 self.sort = Some(sort.to_string());
154 self
155 }
156
157 fn fields2string(&self, fields: Vec<PaperField>) -> String {
158 fields
159 .iter()
160 .map(|field| encode(&field.to_string()))
161 .collect::<Vec<String>>()
162 .join(",")
163 }
164
165 fn publication_types2string(&self, publication_types: Vec<PublicationTypes>) -> String {
166 publication_types
167 .iter()
168 .map(|publication_type| encode(&publication_type.to_string()))
169 .collect::<Vec<String>>()
170 .join(",")
171 }
172
173 fn fields_of_study2string(&self, fields_of_study: Vec<FieldsOfStudy>) -> String {
174 fields_of_study
175 .iter()
176 .map(|field| encode(&field.to_string()))
177 .collect::<Vec<String>>()
178 .join(",")
179 }
180
181 fn author_fields2string(&self, author_fields: Vec<AuthorField>) -> String {
182 author_fields
183 .iter()
184 .map(|field| encode(&field.to_string()))
185 .collect::<Vec<String>>()
186 .join(",")
187 }
188
189 pub fn build(&self) -> String {
190 let mut query_params = Vec::new();
191
192 if let Some(query_text) = &self.query_text {
193 query_params.push(format!("query={}", encode(query_text)));
194 }
195 if let Some(fields) = &self.fields {
196 let fields = self.fields2string(fields.clone());
197 query_params.push(format!("fields={}", fields));
198 }
199 if let Some(author_fields) = &self.author_fields {
200 let author_fields = self.author_fields2string(author_fields.clone());
201 query_params.push(format!("fields={}", author_fields));
202 }
203 if let Some(publication_types) = &self.publication_types {
204 let publication_types = self.publication_types2string(publication_types.clone());
205 query_params.push(format!("publicationTypes={}", publication_types));
206 }
207 if self.open_access_pdf.is_some() {
208 query_params.push("openAccessPdf".to_string());
209 }
210 if let Some(min_citation_count) = &self.min_citation_count {
211 query_params.push(format!("minCitationCount={}", min_citation_count));
212 }
213 if let Some(publication_date_or_year) = &self.publication_date_or_year {
214 query_params.push(format!(
215 "publicationDateOrYear={}",
216 publication_date_or_year
217 ));
218 }
219 if let Some(year) = &self.year {
220 query_params.push(format!("year={}", year));
221 }
222 if let Some(venue) = &self.venue {
223 let venue = venue
224 .iter()
225 .map(|v| encode(v))
226 .collect::<Vec<String>>()
227 .join(",");
228 query_params.push(format!("venue={}", venue));
229 }
230 if let Some(fields_of_study) = &self.fields_of_study {
231 let fields_of_study = self.fields_of_study2string(fields_of_study.clone());
232 query_params.push(format!("fieldsOfStudy={}", fields_of_study));
233 }
234 if let Some(offset) = &self.offset {
235 query_params.push(format!("offset={}", offset));
236 }
237 if let Some(limit) = &self.limit {
238 query_params.push(format!("limit={}", limit));
239 }
240 if let Some(token) = &self.token {
241 query_params.push(format!("token={}", token));
242 }
243 if let Some(sort) = &self.sort {
244 query_params.push(format!("sort={}", sort));
245 }
246
247 if query_params.is_empty() {
248 return "".to_string();
249 } else {
250 let query_params = query_params.join("&");
251 return format!("?{}", query_params);
252 }
253 }
254}
255
256#[derive(Clone, Debug, Default)]
257pub struct SemanticScholar {
258 pub api_key: String,
259}
260
261impl SemanticScholar {
262 pub fn new() -> Self {
263 dotenv().ok();
264 let vars = FxHashMap::from_iter(std::env::vars().into_iter().map(|(k, v)| (k, v)));
265 let api_key = vars
266 .get("SEMANTIC_SCHOLAR_API_KEY")
267 .unwrap_or(&"".to_string())
268 .to_string();
269 Self { api_key: api_key }
270 }
271
272 fn get_url(&self, endpoint: Endpoint, query_params: &mut QueryParams) -> String {
273 let paper_id = query_params.paper_id.clone();
274 let query_params = query_params.build();
275 match endpoint {
276 Endpoint::GetMultiplePpaerDetails => {
277 return format!(
278 "https://api.semanticscholar.org/graph/v1/paper/batch{}",
279 query_params
280 );
281 }
282 Endpoint::GetAPaperByTitle => {
283 let url = format!(
284 "https://api.semanticscholar.org/graph/v1/paper/search/match{}",
285 query_params
286 );
287 return url;
288 }
289 Endpoint::GetPapersByTitle => {
290 let url = format!(
291 "https://api.semanticscholar.org/graph/v1/paper/search{}",
292 query_params
293 );
294 return url;
295 }
296 Endpoint::GetPaperDetails => {
297 let url = format!(
298 "https://api.semanticscholar.org/graph/v1/paper/{}{}",
299 paper_id, query_params
300 );
301 return url;
302 }
303 Endpoint::GetAuthorDetails => {
304 let url = format!(
305 "https://api.semanticscholar.org/graph/v1/author/{}{}",
306 paper_id, query_params
307 );
308 return url;
309 }
310 Endpoint::GetReferencesOfAPaper => {
311 let url = format!(
312 "https://api.semanticscholar.org/graph/v1/paper/{}/references{}",
313 paper_id, query_params
314 );
315 return url;
316 }
317 Endpoint::GetCitationsOfAPaper => {
318 let url = format!(
319 "https://api.semanticscholar.org/graph/v1/paper/{}/citations{}",
320 paper_id, query_params
321 );
322 return url;
323 }
324 Endpoint::SearchAuthors => {
325 let url = format!(
326 "https://api.semanticscholar.org/graph/v1/author/search{}",
327 query_params
328 );
329 return url;
330 }
331 Endpoint::GetAuthorPapers => {
332 let url = format!(
333 "https://api.semanticscholar.org/graph/v1/author/{}/papers{}",
334 paper_id, query_params
335 );
336 return url;
337 }
338 Endpoint::GetPaperAuthors => {
339 let url = format!(
340 "https://api.semanticscholar.org/graph/v1/paper/{}/authors{}",
341 paper_id, query_params
342 );
343 return url;
344 }
345 }
346 }
347
348 fn sleep(&self, seconds: u64, message: &str) {
349 let pb = ProgressBar::new(seconds);
350 pb.set_style(
351 indicatif::ProgressStyle::default_bar()
352 .template(
353 "{spinner:.green} [{elapsed_precise}] [{bar:40.green/cyan}] {pos}s/{len}s {msg}",
354 )
355 .unwrap()
356 .progress_chars("█▓▒░"),
357 );
358 if message.is_empty() {
359 pb.set_message("Waiting for the next request...");
360 } else {
361 pb.set_message(message.to_string());
362 }
363 for _ in 0..seconds {
364 pb.inc(1);
365 std::thread::sleep(std::time::Duration::from_secs(1));
366 }
367 pb.finish_and_clear();
368 }
369
370 pub async fn bulk_query_by_ids(
404 &mut self,
405 paper_ids: Vec<&str>,
406 fields: Vec<PaperField>,
407 max_retry_count: u64,
408 wait_time: u64,
409 ) -> Result<Vec<Paper>> {
410 let mut max_retry_count = max_retry_count.clone();
411
412 let mut headers = header::HeaderMap::new();
413 headers.insert("Content-Type", "application/json".parse().unwrap());
414 headers.insert("user-agent", "ss-tools/0.1".parse().unwrap());
415 if !self.api_key.is_empty() {
416 headers.insert("x-api-key", self.api_key.parse().unwrap());
417 }
418 let client = request::Client::builder()
419 .default_headers(headers)
420 .build()
421 .unwrap();
422
423 let mut query_params = QueryParams::default();
424 query_params.fields(fields.clone());
425 let url = self.get_url(Endpoint::GetMultiplePpaerDetails, &mut query_params);
426 let body = format!(
427 "{{\"ids\":[{}]}}",
428 paper_ids
429 .iter()
430 .map(|v| format!("\"{}\"", v))
431 .collect::<Vec<String>>()
432 .join(",")
433 );
434
435 loop {
436 if max_retry_count == 0 {
437 return Err(Error::msg("Failed to get papers"));
438 }
439 let body = client
440 .post(url.clone())
441 .body(body.clone())
442 .send()
443 .await?
444 .text()
445 .await?;
446
447 match serde_json::from_str::<Vec<Paper>>(&body) {
448 Ok(response) => {
449 return Ok(response);
450 }
451 Err(e) => {
452 max_retry_count -= 1;
453 self.sleep(
454 wait_time,
455 format!("Error: {} Body: {}", &e.to_string(), &body).as_str(),
456 );
457 continue;
458 }
459 }
460 }
461 }
462
463 pub async fn query_papers_by_title(
493 &mut self,
494 query_params: QueryParams,
495 max_retry_count: u64,
496 wait_time: u64,
497 ) -> Result<Vec<Paper>> {
498 let mut query_params = query_params.clone();
499 let mut max_retry_count = max_retry_count.clone();
500
501 let mut headers = header::HeaderMap::new();
502 headers.insert("Content-Type", "application/json".parse().unwrap());
503 headers.insert("user-agent", "ss-tools/0.1".parse().unwrap());
504 if !self.api_key.is_empty() {
505 headers.insert("x-api-key", self.api_key.parse().unwrap());
506 }
507 let client = request::Client::builder()
508 .default_headers(headers)
509 .build()
510 .unwrap();
511
512 let url = self.get_url(Endpoint::GetPapersByTitle, &mut query_params);
513
514 loop {
515 if max_retry_count == 0 {
516 return Err(Error::msg(format!(
517 "Failed to get paper id for: {}",
518 query_params.query_text.unwrap().clone()
519 )));
520 }
521
522 let body = client.get(url.clone()).send().await?.text().await?;
523 match serde_json::from_str::<PaperIds>(&body) {
524 Ok(response) => {
525 if response.data.is_empty() || response.total == 0 {
526 max_retry_count -= 1;
527 self.sleep(
528 wait_time,
529 format!("Error: Response is empty. Body: {}", &body).as_str(),
530 );
531 continue;
532 }
533 return Ok(response.data);
534 }
535 Err(e) => {
536 max_retry_count -= 1;
537 self.sleep(
538 wait_time,
539 format!("Error: {} Body: {}", &e.to_string(), &body).as_str(),
540 );
541 continue;
542 }
543 }
544 }
545 }
546
547 pub async fn query_a_paper_by_title(
576 &mut self,
577 query_params: QueryParams,
578 max_retry_count: u64,
579 wait_time: u64,
580 ) -> Result<Paper> {
581 let mut query_params = query_params.clone();
582 let mut max_retry_count = max_retry_count.clone();
583
584 let mut headers = header::HeaderMap::new();
585 headers.insert("Content-Type", "application/json".parse().unwrap());
586 headers.insert("user-agent", "ss-tools/0.1".parse().unwrap());
587 if !self.api_key.is_empty() {
588 headers.insert("x-api-key", self.api_key.parse()?);
589 }
590 let client = request::Client::builder()
591 .default_headers(headers)
592 .build()?;
593
594 let url = self.get_url(Endpoint::GetAPaperByTitle, &mut query_params);
595 loop {
596 if max_retry_count == 0 {
597 return Err(Error::msg(format!(
598 "Failed to get paper id for: {}",
599 query_params.query_text.unwrap()
600 )));
601 }
602
603 let body = client.get(url.clone()).send().await?.text().await?;
604 match serde_json::from_str::<PaperIds>(&body) {
605 Ok(response) => {
606 if response.data.len() < 1 {
607 max_retry_count -= 1;
608 self.sleep(
609 wait_time,
610 format!("Error: Response is empty. Body: {}", &body).as_str(),
611 );
612 continue;
613 }
614 let paper = response.data.first().unwrap().clone();
615 return Ok(paper);
616 }
617 Err(e) => {
618 max_retry_count -= 1;
619 self.sleep(
620 wait_time,
621 format!("Error: {} Body: {}", &e.to_string(), &body).as_str(),
622 );
623 continue;
624 }
625 }
626 }
627 }
628
629 pub async fn query_paper_details(
659 &mut self,
660 query_params: QueryParams,
661 max_retry_count: u64,
662 wait_time: u64,
663 ) -> Result<Paper> {
664 let mut query_params = query_params.clone();
665 let mut max_retry_count = max_retry_count.clone();
666
667 let mut fields = query_params.fields.clone().unwrap_or_default();
668 if !fields.contains(&PaperField::PaperId) {
669 fields.push(PaperField::PaperId);
670 query_params.fields = Some(fields);
671 }
672
673 let mut headers = header::HeaderMap::new();
674 headers.insert("Content-Type", "application/json".parse().unwrap());
675 headers.insert("user-agent", "ss-tools/0.1".parse().unwrap());
676 if !self.api_key.is_empty() {
677 headers.insert("x-api-key", self.api_key.parse().unwrap());
678 }
679 let client = request::Client::builder()
680 .default_headers(headers)
681 .build()
682 .unwrap();
683
684 let url = self.get_url(Endpoint::GetPaperDetails, &mut query_params);
685 loop {
686 if max_retry_count == 0 {
687 return Err(Error::msg(format!(
688 "Failed to get paper details: {}",
689 query_params.paper_id
690 )));
691 }
692 let body = client.get(url.clone()).send().await?.text().await?;
693 match serde_json::from_str::<Paper>(&body) {
694 Ok(response) => {
695 return Ok(response);
696 }
697 Err(e) => {
698 max_retry_count -= 1;
699 self.sleep(
700 wait_time,
701 format!("Error: {} Body: {}", &e.to_string(), &body).as_str(),
702 );
703 continue;
704 }
705 }
706 }
707 }
708
709 pub async fn query_paper_citations(
710 &mut self,
711 query_params: QueryParams,
712 max_retry_count: u64,
713 wait_time: u64,
714 ) -> Result<ResponsePapers> {
715 let mut query_params = query_params.clone();
716 let mut max_retry_count = max_retry_count.clone();
717
718 let mut fields = query_params.fields.clone().unwrap_or_default();
719 if !fields.contains(&PaperField::PaperId) {
720 fields.push(PaperField::PaperId);
721 query_params.fields = Some(fields);
722 }
723
724 let mut headers = header::HeaderMap::new();
725 headers.insert("Content-Type", "application/json".parse().unwrap());
726 headers.insert("user-agent", "ss-tools/0.1".parse().unwrap());
727 if !self.api_key.is_empty() {
728 headers.insert("x-api-key", self.api_key.parse().unwrap());
729 }
730 let client = request::Client::builder()
731 .default_headers(headers)
732 .build()
733 .unwrap();
734
735 let url = self.get_url(Endpoint::GetCitationsOfAPaper, &mut query_params);
736
737 loop {
738 if max_retry_count == 0 {
739 return Err(Error::msg(format!(
740 "Failed to get paper citations: {}",
741 query_params.paper_id
742 )));
743 }
744 match client.get(url.clone()).send().await {
745 Ok(response) => {
746 let body = response.text().await?;
747 match serde_json::from_str::<ResponsePapers>(&body) {
748 Ok(response) => {
749 return Ok(response);
750 }
751 Err(e) => {
752 max_retry_count -= 1;
753 self.sleep(
754 wait_time,
755 format!("Error: {} Body: {}", &e.to_string(), &body).as_str(),
756 );
757 continue;
758 }
759 }
760 }
761 Err(e) => {
762 max_retry_count -= 1;
763 self.sleep(wait_time, &e.to_string());
764 continue;
765 }
766 }
767 }
768 }
769
770 pub async fn query_paper_references(
771 &mut self,
772 query_params: QueryParams,
773 max_retry_count: u64,
774 wait_time: u64,
775 ) -> Result<ResponsePapers> {
776 let mut query_params = query_params.clone();
777 let mut max_retry_count = max_retry_count.clone();
778
779 let mut fields = query_params.fields.clone().unwrap_or_default();
780 if !fields.contains(&PaperField::PaperId) {
781 fields.push(PaperField::PaperId);
782 query_params.fields = Some(fields);
783 }
784
785 let mut headers = header::HeaderMap::new();
786 headers.insert("Content-Type", "application/json".parse().unwrap());
787 headers.insert("user-agent", "ss-tools/0.1".parse().unwrap());
788 if !self.api_key.is_empty() {
789 headers.insert("x-api-key", self.api_key.parse().unwrap());
790 }
791 let client = request::Client::builder()
792 .default_headers(headers)
793 .build()
794 .unwrap();
795
796 let url = self.get_url(Endpoint::GetReferencesOfAPaper, &mut query_params);
797 loop {
798 if max_retry_count == 0 {
799 return Err(Error::msg(format!(
800 "Failed to get paper references: {}",
801 query_params.paper_id
802 )));
803 }
804
805 match client.get(url.clone()).send().await {
806 Ok(response) => {
807 let body = response.text().await?;
808 match serde_json::from_str::<ResponsePapers>(&body) {
809 Ok(response) => {
810 return Ok(response);
811 }
812 Err(e) => {
813 max_retry_count -= 1;
814 self.sleep(
815 wait_time,
816 format!("Error: {} Body: {}", &e.to_string(), &body).as_str(),
817 );
818 continue;
819 }
820 }
821 }
822 Err(e) => {
823 max_retry_count -= 1;
824 self.sleep(wait_time, &e.to_string());
825 continue;
826 }
827 }
828 }
829 }
830
831 pub async fn query_author_details(
859 &mut self,
860 query_params: QueryParams,
861 max_retry_count: u64,
862 wait_time: u64,
863 ) -> Result<Author> {
864 let mut query_params = query_params.clone();
865 let mut max_retry_count = max_retry_count.clone();
866
867 let mut headers = header::HeaderMap::new();
868 headers.insert("Content-Type", "application/json".parse().unwrap());
869 headers.insert("user-agent", "ss-tools/0.1".parse().unwrap());
870 if !self.api_key.is_empty() {
871 headers.insert("x-api-key", self.api_key.parse().unwrap());
872 }
873 let client = request::Client::builder()
874 .default_headers(headers)
875 .build()
876 .unwrap();
877
878 let url = self.get_url(Endpoint::GetAuthorDetails, &mut query_params);
879 loop {
880 if max_retry_count == 0 {
881 return Err(Error::msg(format!(
882 "Failed to get author details: {}",
883 query_params.paper_id
884 )));
885 }
886 let body = client.get(url.clone()).send().await?.text().await?;
887 match serde_json::from_str::<Author>(&body) {
888 Ok(response) => {
889 return Ok(response);
890 }
891 Err(e) => {
892 max_retry_count -= 1;
893 self.sleep(
894 wait_time,
895 format!("Error: {} Body: {}", &e.to_string(), &body).as_str(),
896 );
897 continue;
898 }
899 }
900 }
901 }
902
903 pub async fn search_authors(
930 &mut self,
931 query_params: QueryParams,
932 max_retry_count: u64,
933 wait_time: u64,
934 ) -> Result<AuthorSearchResponse> {
935 let mut query_params = query_params.clone();
936 let mut max_retry_count = max_retry_count.clone();
937
938 let mut headers = header::HeaderMap::new();
939 headers.insert("Content-Type", "application/json".parse().unwrap());
940 headers.insert("user-agent", "ss-tools/0.1".parse().unwrap());
941 if !self.api_key.is_empty() {
942 headers.insert("x-api-key", self.api_key.parse().unwrap());
943 }
944 let client = request::Client::builder()
945 .default_headers(headers)
946 .build()
947 .unwrap();
948
949 let url = self.get_url(Endpoint::SearchAuthors, &mut query_params);
950 loop {
951 if max_retry_count == 0 {
952 return Err(Error::msg("Failed to search authors"));
953 }
954 match client.get(url.clone()).send().await {
955 Ok(response) => {
956 let body = response.text().await?;
957 match serde_json::from_str::<AuthorSearchResponse>(&body) {
958 Ok(response) => {
959 return Ok(response);
960 }
961 Err(e) => {
962 max_retry_count -= 1;
963 self.sleep(
964 wait_time,
965 format!("Error: {} Body: {}", &e.to_string(), &body).as_str(),
966 );
967 continue;
968 }
969 }
970 }
971 Err(e) => {
972 max_retry_count -= 1;
973 self.sleep(wait_time, &e.to_string());
974 continue;
975 }
976 }
977 }
978 }
979
980 pub async fn query_author_papers(
1008 &mut self,
1009 query_params: QueryParams,
1010 max_retry_count: u64,
1011 wait_time: u64,
1012 ) -> Result<AuthorPapersResponse> {
1013 let mut query_params = query_params.clone();
1014 let mut max_retry_count = max_retry_count.clone();
1015
1016 let mut fields = query_params.fields.clone().unwrap_or_default();
1017 if !fields.contains(&PaperField::PaperId) {
1018 fields.push(PaperField::PaperId);
1019 query_params.fields = Some(fields);
1020 }
1021
1022 let mut headers = header::HeaderMap::new();
1023 headers.insert("Content-Type", "application/json".parse().unwrap());
1024 headers.insert("user-agent", "ss-tools/0.1".parse().unwrap());
1025 if !self.api_key.is_empty() {
1026 headers.insert("x-api-key", self.api_key.parse().unwrap());
1027 }
1028 let client = request::Client::builder()
1029 .default_headers(headers)
1030 .build()
1031 .unwrap();
1032
1033 let url = self.get_url(Endpoint::GetAuthorPapers, &mut query_params);
1034 loop {
1035 if max_retry_count == 0 {
1036 return Err(Error::msg(format!(
1037 "Failed to get author papers: {}",
1038 query_params.paper_id
1039 )));
1040 }
1041 match client.get(url.clone()).send().await {
1042 Ok(response) => {
1043 let body = response.text().await?;
1044 match serde_json::from_str::<AuthorPapersResponse>(&body) {
1045 Ok(response) => {
1046 return Ok(response);
1047 }
1048 Err(e) => {
1049 max_retry_count -= 1;
1050 self.sleep(
1051 wait_time,
1052 format!("Error: {} Body: {}", &e.to_string(), &body).as_str(),
1053 );
1054 continue;
1055 }
1056 }
1057 }
1058 Err(e) => {
1059 max_retry_count -= 1;
1060 self.sleep(wait_time, &e.to_string());
1061 continue;
1062 }
1063 }
1064 }
1065 }
1066
1067 pub async fn query_paper_authors(
1094 &mut self,
1095 query_params: QueryParams,
1096 max_retry_count: u64,
1097 wait_time: u64,
1098 ) -> Result<PaperAuthorsResponse> {
1099 let mut query_params = query_params.clone();
1100 let mut max_retry_count = max_retry_count.clone();
1101
1102 let mut headers = header::HeaderMap::new();
1103 headers.insert("Content-Type", "application/json".parse().unwrap());
1104 headers.insert("user-agent", "ss-tools/0.1".parse().unwrap());
1105 if !self.api_key.is_empty() {
1106 headers.insert("x-api-key", self.api_key.parse().unwrap());
1107 }
1108 let client = request::Client::builder()
1109 .default_headers(headers)
1110 .build()
1111 .unwrap();
1112
1113 let url = self.get_url(Endpoint::GetPaperAuthors, &mut query_params);
1114 loop {
1115 if max_retry_count == 0 {
1116 return Err(Error::msg(format!(
1117 "Failed to get paper authors: {}",
1118 query_params.paper_id
1119 )));
1120 }
1121 match client.get(url.clone()).send().await {
1122 Ok(response) => {
1123 let body = response.text().await?;
1124 match serde_json::from_str::<PaperAuthorsResponse>(&body) {
1125 Ok(response) => {
1126 return Ok(response);
1127 }
1128 Err(e) => {
1129 max_retry_count -= 1;
1130 self.sleep(
1131 wait_time,
1132 format!("Error: {} Body: {}", &e.to_string(), &body).as_str(),
1133 );
1134 continue;
1135 }
1136 }
1137 }
1138 Err(e) => {
1139 max_retry_count -= 1;
1140 self.sleep(wait_time, &e.to_string());
1141 continue;
1142 }
1143 }
1144 }
1145 }
1146}