Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 59f075b

Browse files
authored
Raise Error::CookieError more often (clearloop#67)
* add graphql query for user info * add parser for graphql user info * return `CookieError` when leetcode rejects exec/test `Run` * add the `is_session_bad` method to somewhat-accurately determine when a LEETCODE_SESSION becomes invalid * When json parsing fails, if the underlying request requires user authentication, use `is_session_bad()` to check if LEETCODE_SESSION is valid.
1 parent ea066f1 commit 59f075b

File tree

3 files changed

+86
-17
lines changed

3 files changed

+86
-17
lines changed

‎src/cache/mod.rs

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ use self::sql::*;
99
use crate::{cfg, err::Error, plugins::LeetCode};
1010
use colored::Colorize;
1111
use diesel::prelude::*;
12+
use serde::de::DeserializeOwned;
1213
use serde_json::Value;
1314
use std::collections::HashMap;
15+
use reqwest::Response;
1416

1517
/// sqlite connection
1618
pub fn conn(p: String) -> SqliteConnection {
@@ -58,6 +60,34 @@ impl Cache {
5860
Ok(())
5961
}
6062

63+
async fn get_user_info(&self) -> Result<(String,bool), Error> {
64+
let user = parser::user(
65+
self.clone().0
66+
.get_user_info().await?
67+
.json().await?
68+
);
69+
match user {
70+
None => Err(Error::NoneError),
71+
Some(None) => Err(Error::CookieError),
72+
Some(Some((s,b))) => Ok((s,b))
73+
}
74+
}
75+
76+
async fn is_session_bad(&self) -> bool {
77+
// i.e. self.get_user_info().contains_err(Error::CookieError)
78+
match self.get_user_info().await {
79+
Err(Error::CookieError) => true,
80+
_ => false
81+
}
82+
}
83+
84+
async fn resp_to_json<T: DeserializeOwned>(&self, resp: Response) -> Result<T, Error> {
85+
let maybe_json: Result<T,_> = resp.json().await;
86+
if maybe_json.is_err() && self.is_session_bad().await {
87+
Err(Error::CookieError)
88+
} else { Ok(maybe_json?) }
89+
}
90+
6191
/// Download leetcode problems to db
6292
pub async fn download_problems(self) -> Result<Vec<Problem>, Error> {
6393
info!("Fetching leetcode problems...");
@@ -69,7 +99,7 @@ impl Cache {
6999
.clone()
70100
.get_category_problems(i)
71101
.await?
72-
.json()
102+
.json()// does not require LEETCODE_SESSION
73103
.await?;
74104
parser::problem(&mut ps, json).ok_or(Error::NoneError)?;
75105
}
@@ -100,7 +130,7 @@ impl Cache {
100130
.0
101131
.get_question_daily()
102132
.await?
103-
.json()
133+
.json()// does not require LEETCODE_SESSION
104134
.await?
105135
).ok_or(Error::NoneError)
106136
}
@@ -265,30 +295,20 @@ impl Cache {
265295

266296
/// TODO: The real delay
267297
async fn recur_verify(&self, rid: String) -> Result<VerifyResult, Error> {
268-
use serde_json::{from_str, Error as SJError};
269298
use std::time::Duration;
270299

271300
trace!("Run veriy recursion...");
272301
std::thread::sleep(Duration::from_micros(3000));
273302

274-
// debug resp raw text
275-
let debug_raw = self
303+
let json:VerifyResult = self.resp_to_json(
304+
self
276305
.clone()
277306
.0
278307
.verify_result(rid.clone())
279308
.await?
280-
.text()
281-
.await?;
282-
debug!("debug resp raw text: \n{:#?}", &debug_raw);
283-
if debug_raw.is_empty() {
284-
return Err(Error::CookieError);
285-
}
286-
287-
// debug json deserializing
288-
let debug_json: Result<VerifyResult, SJError> = from_str(&debug_raw);
289-
debug!("debug json deserializing: \n{:#?}", &debug_json);
309+
).await?;
290310

291-
Ok(debug_json?)
311+
Ok(json)
292312
}
293313

294314
/// Exec problem filter —— Test or Submit
@@ -307,10 +327,16 @@ impl Cache {
307327
.clone()
308328
.run_code(json.clone(), url.clone(), refer.clone())
309329
.await?
310-
.json()
330+
.json()// does not require LEETCODE_SESSION (very oddly)
311331
.await?;
312332
trace!("Run code result {:#?}", run_res);
313333

334+
// Check if leetcode accepted the Run request
335+
if match run {
336+
Run::Test => run_res.interpret_id.is_empty(),
337+
Run::Submit => run_res.submission_id == 0
338+
} { return Err(Error::CookieError) }
339+
314340
let mut res: VerifyResult = VerifyResult::default();
315341
while res.state != "SUCCESS" {
316342
res = match run {

‎src/cache/parser.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,21 @@ pub fn daily(v: Value) -> Option<i32> {
8888
.parse().ok()
8989
}
9090

91+
/// user parser
92+
pub fn user(v: Value) -> Option<Option<(String,bool)>> {
93+
// None => error while parsing
94+
// Some(None) => User not found
95+
// Some("...") => username
96+
let user = v.as_object()?.get("data")?
97+
.as_object()?.get("user")?;
98+
if *user == Value::Null { return Some(None) }
99+
let user = user.as_object()?;
100+
Some(Some((
101+
user.get("username")?.as_str()?.to_owned(),
102+
user.get("isCurrentUserPremium")?.as_bool()?
103+
)))
104+
}
105+
91106
pub use ss::ssr;
92107
/// string or squence
93108
mod ss {

‎src/plugins/leetcode.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,34 @@ impl LeetCode {
121121
.await
122122
}
123123

124+
pub async fn get_user_info(self) -> Result<Response, Error> {
125+
trace!("Requesting user info...");
126+
let url = &self.conf.sys.urls.get("graphql").ok_or(Error::NoneError)?;
127+
let mut json: Json = HashMap::new();
128+
json.insert("operationName", "a".to_string());
129+
json.insert(
130+
"query",
131+
"query a {
132+
user {
133+
username
134+
isCurrentUserPremium
135+
}
136+
}".to_owned()
137+
);
138+
139+
Req {
140+
default_headers: self.default_headers,
141+
refer: None,
142+
info: false,
143+
json: Some(json),
144+
mode: Mode::Post,
145+
name: "get_user_info",
146+
url: (*url).to_string(),
147+
}
148+
.send(&self.client)
149+
.await
150+
}
151+
124152
/// Get daily problem
125153
pub async fn get_question_daily(self) -> Result<Response, Error> {
126154
trace!("Requesting daily problem...");

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /