leetcode_api/leetcode/impl_lc/
judge.rs1use std::time::Duration;
2
3use lcode_config::global::G_USER_CONFIG;
4use miette::Result;
5use regex::Regex;
6use tokio::{join, time::sleep};
7use tracing::{debug, trace};
8
9use crate::{
10 Json,
11 dao::{query::Query, save_info::FileInfo},
12 leetcode::{
13 IdSlug, LeetCode,
14 graphqls::GraphqlQuery,
15 resps::{
16 run_res::*,
17 submit_list::{SubmissionData, SubmissionList},
18 },
19 },
20};
21
22impl LeetCode {
23 pub async fn add_test_case(&self, id: u32, case: &str) -> Result<()> {
24 if case.is_empty() {
25 return Ok(());
26 }
27 let idx = Query::get_question_index(&IdSlug::Id(id)).await?;
28
29 let info = FileInfo::build(&idx).await?;
30 info.append_test_case(case).await?;
31
32 Ok(())
33 }
34
35 pub async fn reset_test_case(&self, id: u32) -> Result<()> {
36 let idx = Query::get_question_index(&IdSlug::Id(id)).await?;
37 let detail = self
38 .get_qs_detail(IdSlug::Id(id), false, false)
39 .await?;
40 let info = FileInfo::build(&idx).await?;
41 info.reset_test_case(&detail.example_testcases)
42 .await?;
43
44 Ok(())
45 }
46}
47
48impl LeetCode {
49 pub async fn submit_code(&self, idslug: IdSlug) -> Result<(SubmitInfo, RunResult)> {
53 let (code, pb) = join!(
54 self.get_user_code(idslug.clone()),
55 Query::get_question_index(&idslug)
56 );
57 let ((code, _), pb) = (code?, pb?);
58
59 let mut json: Json = Json::new();
60 json.insert("lang", G_USER_CONFIG.config.lang.clone());
61 json.insert("question_id", pb.question_id.to_string());
62 json.insert("typed_code", code);
63
64 trace!("submit insert json: {:#?}", json);
65
66 let sub_info: SubmitInfo = match self
67 .request(
68 &G_USER_CONFIG
69 .urls
70 .mod_submit(&pb.question_title_slug),
71 Some(&json),
72 self.headers.clone(),
73 )
74 .await
75 {
76 Ok(it) => it,
77 Err(err) => {
78 return Ok((
79 SubmitInfo::default(),
80 RunResultBuild::default()
81 .set_status_msg(err.to_string())
82 .build(),
83 ));
84 },
85 };
86
87 let last_sub_result = self.get_submit_res(&sub_info).await?;
88 debug!("last submit result: {:#?}", last_sub_result);
89
90 Ok((sub_info, last_sub_result))
91 }
92
93 pub async fn get_submit_res(&self, sub_id: &SubmitInfo) -> Result<RunResult> {
97 let test_res_url = G_USER_CONFIG
98 .urls
99 .mod_submissions(&sub_id.submission_id().to_string());
100 trace!("start get last submit detail");
101
102 for _ in 0..9 {
103 sleep(Duration::from_millis(700)).await;
104
105 let resp_json: RunResult = self
106 .request(&test_res_url, None, self.headers.clone())
107 .await?;
108 if resp_json.success() {
109 return Ok(resp_json);
110 }
111 }
112 Ok(RunResultBuild::default()
113 .set_status_msg(
114 "Get the submit result error, please check your code, it may fail to execute, or \
115 check your network"
116 .to_owned(),
117 )
118 .build())
119 }
120
121 pub async fn all_submit_res(&self, idslug: IdSlug) -> Result<SubmissionList> {
123 let pb = Query::get_question_index(&idslug).await?;
124
125 let json: Json = GraphqlQuery::subission_list(&pb.question_title_slug);
126
127 let pat: SubmissionData = self
128 .request(
129 &G_USER_CONFIG.urls.graphql,
130 Some(&json),
131 self.headers.clone(),
132 )
133 .await?;
134
135 Ok(pat.submission_list())
136 }
137
138 pub async fn test_code(&self, idslug: IdSlug) -> Result<(TestInfo, RunResult)> {
139 let (code, pb) = join!(
140 self.get_user_code(idslug.clone()),
141 Query::get_question_index(&idslug)
142 );
143 let ((code, test_case), pb) = (code?, pb?);
144 debug!("code:\n{}", code);
145
146 let mut json: Json = Json::new();
147 json.insert("lang", G_USER_CONFIG.config.lang.clone());
148 json.insert("question_id", pb.question_id.to_string());
149 json.insert("typed_code", code);
150 json.insert("data_input", test_case);
151
152 let test_info: TestInfo = match self
153 .request(
154 &G_USER_CONFIG
155 .urls
156 .mod_test(&pb.question_title_slug),
157 Some(&json),
158 self.headers.clone(),
159 )
160 .await
161 {
162 Ok(it) => it,
163 Err(err) => {
164 return Ok((
165 TestInfo::default(),
166 RunResultBuild::default()
167 .set_status_msg(err.to_string())
168 .build(),
169 ));
170 },
171 };
172
173 let test_result = self.get_test_res(&test_info).await?;
174
175 Ok((test_info, test_result))
176 }
177
178 async fn get_test_res(&self, test_info: &TestInfo) -> Result<RunResult> {
180 for _ in 0..9 {
181 sleep(Duration::from_millis(700)).await;
182
183 let resp_json: RunResult = self
184 .request(
185 &G_USER_CONFIG
186 .urls
187 .mod_submissions(test_info.interpret_id()),
188 None,
189 self.headers.clone(),
190 )
191 .await?;
192 if resp_json.success() {
193 return Ok(resp_json);
194 }
195 }
196 Ok(RunResultBuild::default()
197 .set_status_msg(
198 "Get the test result error, please check your network,or check test case it may \
199 not correct"
200 .to_owned(),
201 )
202 .build())
203 }
204
205 pub async fn get_user_code(&self, idslug: IdSlug) -> Result<(String, String)> {
207 let pb = Query::get_question_index(&idslug).await?;
208 let chf = FileInfo::build(&pb).await?;
209 let (code, mut test_case) = chf.get_user_code(&idslug).await?;
210
211 if test_case.is_empty() {
212 test_case = self
213 .get_qs_detail(idslug, false, true)
214 .await?
215 .example_testcases;
216 }
217 let (start, end, ..) = G_USER_CONFIG.get_lang_info();
218 let code_re = Regex::new(&format!(r"(?s){}\n(?P<code>.*){}", start, end))
219 .expect("get_user_code regex new failed");
220
221 #[expect(clippy::option_if_let_else, reason = "borrow checker")]
223 let res = match code_re.captures(&code) {
224 Some(val) => val["code"].to_owned(),
225 None => code,
226 };
227
228 Ok((res, test_case))
229 }
230}