leetcode_api/leetcode/impl_lc/
get_qs.rs1use std::sync::atomic::Ordering;
2
3use futures::{StreamExt, stream};
4use lcode_config::global::G_USER_CONFIG;
5use miette::Result;
6use tracing::{debug, error};
7
8use crate::{
9 Json,
10 dao::{InsertToDB, query::Query, save_info::FileInfo},
11 entities::index,
12 leetcode::{
13 CATEGORIES, CUR_QS_INDEX_NUM, CUR_TOPIC_QS_INDEX_NUM, IdSlug, LeetCode, TOTAL_QS_INDEX_NUM,
14 TOTAL_TOPIC_QS_INDEX_NUM,
15 graphqls::GraphqlQuery,
16 question::{
17 pb_list::PbListData,
18 qs_detail::{Question, QuestionData},
19 qs_index::Problems,
20 },
21 },
22};
23
24impl LeetCode {
25 pub async fn sync_problem_index(&self) -> Result<()> {
34 stream::iter(CATEGORIES)
35 .for_each_concurrent(None, |category| async move {
36 let all_pb_url = G_USER_CONFIG
37 .urls
38 .mod_all_pb_api(category);
39
40 let mut count = 0;
42 let pbs: Problems = loop {
43 match self
44 .request(&all_pb_url, None, self.headers.clone())
45 .await
46 {
47 Ok(v) => break v,
48 Err(err) => {
49 count += 1;
50 error!("{}, frequency: {}", err, count);
51 if count > 5 {
52 break Problems::default();
53 }
54 },
55 }
56 };
57
58 TOTAL_QS_INDEX_NUM.fetch_add(pbs.num_total, Ordering::Relaxed);
59
60 stream::iter(pbs.stat_status_pairs)
61 .for_each_concurrent(None, |mut problem| async move {
62 problem
63 .insert_to_db(category.to_owned())
64 .await;
65 CUR_QS_INDEX_NUM.fetch_add(1, Ordering::Relaxed);
66 })
67 .await;
68 })
69 .await;
70
71 TOTAL_QS_INDEX_NUM.store(0, Ordering::Relaxed);
72 CUR_QS_INDEX_NUM.store(0, Ordering::Relaxed);
73 Ok(())
74 }
75
76 pub async fn sync_index_topic(&self) -> Result<()> {
78 let url = &G_USER_CONFIG.urls.graphql;
79
80 let graphql = GraphqlQuery::get_count();
81 let data: PbListData = self
82 .request(url, Some(&graphql.0), self.headers.clone())
83 .await?;
84 let total = data.data.problemset_question_list.total;
85
86 stream::iter((0..total).step_by(100))
87 .for_each_concurrent(None, |skip| async move {
88 let graphql = GraphqlQuery::new(skip);
89
90 let mut count = 0;
92 let data: PbListData = loop {
93 match self
94 .request(url, Some(&graphql), self.headers.clone())
95 .await
96 {
97 Ok(it) => break it,
98 Err(err) => {
99 count += 1;
100 error!("{}, frequency: {}", err, count);
101 if count > 3 {
102 break PbListData::default();
103 }
104 },
105 }
106 };
107
108 TOTAL_TOPIC_QS_INDEX_NUM.fetch_add(100, Ordering::Relaxed);
109
110 let pb_list = data
111 .data
112 .problemset_question_list
113 .questions;
114
115 stream::iter(pb_list)
116 .for_each_concurrent(None, |mut new_pb| async move {
117 new_pb.insert_to_db(0).await;
118 CUR_TOPIC_QS_INDEX_NUM.fetch_add(1, Ordering::Relaxed);
119 })
120 .await;
121 })
122 .await;
123
124 TOTAL_TOPIC_QS_INDEX_NUM.store(0, Ordering::Relaxed);
125 CUR_TOPIC_QS_INDEX_NUM.store(0, Ordering::Relaxed);
126 Ok(())
127 }
128
129 async fn get_qs_detail_helper_force(&self, pb: &index::Model) -> Result<Question> {
130 let json: Json = GraphqlQuery::qs_detail(&pb.question_title_slug);
131
132 let mut qs: QuestionData = self
133 .request(
134 &G_USER_CONFIG.urls.graphql,
135 Some(&json),
136 self.headers.clone(),
137 )
138 .await?;
139
140 qs.data.question.qs_slug = Some(pb.question_title_slug.clone());
141 qs.data
142 .question
143 .insert_one(pb.question_id)
144 .await;
145
146 Ok(qs.data.question)
147 }
148
149 pub async fn get_qs_detail(
156 &self,
157 idslug: IdSlug,
158 force: bool,
159 write: bool,
160 ) -> Result<Question> {
161 if let IdSlug::Id(id) = idslug {
162 if id == 0 {
163 miette::bail!("Question Id require large 0")
164 }
165 }
166 let pb = Query::get_question_index(&idslug).await?;
167 debug!("pb: {:?}", pb);
168 let detail = if force {
169 self.get_qs_detail_helper_force(&pb)
170 .await?
171 }
172 else {
173 let temp = Query::query_detail_by_id(pb.question_id).await?;
174
175 let the_detail = temp.unwrap_or_default();
176 let detail: Question = serde_json::from_str(&the_detail.content).unwrap_or_default();
177 if detail.qs_slug.is_none() {
179 self.get_qs_detail_helper_force(&pb)
180 .await?
181 }
182 else {
183 detail
184 }
185 };
186
187 if write {
188 let chf = FileInfo::build(&pb).await?;
189 chf.write_to_file(&detail).await?;
190 }
191
192 Ok(detail)
193 }
194}