[BE] Replace once_cell with RwLock. Fix classroom empty users error
This commit is contained in:
parent
525c72a9f6
commit
3d60f11f43
2
backend/Cargo.lock
generated
2
backend/Cargo.lock
generated
@ -131,7 +131,7 @@ dependencies = [
|
|||||||
"chrono",
|
"chrono",
|
||||||
"dotenvy",
|
"dotenvy",
|
||||||
"isahc",
|
"isahc",
|
||||||
"once_cell",
|
"lazy_static",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"rocket",
|
"rocket",
|
||||||
"scraper",
|
"scraper",
|
||||||
|
@ -9,12 +9,12 @@ edition = "2021"
|
|||||||
reqwest = { version = "0.11", features = ["json", "cookies"] }
|
reqwest = { version = "0.11", features = ["json", "cookies"] }
|
||||||
rocket = { version = "=0.5.0-rc.3" , features = ["json", "msgpack", "uuid"] }
|
rocket = { version = "=0.5.0-rc.3" , features = ["json", "msgpack", "uuid"] }
|
||||||
sqlx = { version = "0.7.1", features = [ "runtime-tokio", "tls-rustls", "mysql", "macros", "chrono" ] }
|
sqlx = { version = "0.7.1", features = [ "runtime-tokio", "tls-rustls", "mysql", "macros", "chrono" ] }
|
||||||
once_cell = "1.18.0"
|
|
||||||
dotenvy = "0.15.7"
|
dotenvy = "0.15.7"
|
||||||
serde = "1.0.188"
|
serde = "1.0.188"
|
||||||
chrono = "0.4.27"
|
chrono = "0.4.27"
|
||||||
scraper = "0.17.1"
|
scraper = "0.17.1"
|
||||||
isahc = { version = "1.7.2", features = ["cookies"] }
|
isahc = { version = "1.7.2", features = ["cookies"] }
|
||||||
urlencoding = "2.1.3"
|
urlencoding = "2.1.3"
|
||||||
|
lazy_static = "1.4.0"
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,12 +1,21 @@
|
|||||||
|
use lazy_static::lazy_static;
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
use isahc::{cookies::CookieJar, prelude::*, Request};
|
use isahc::{cookies::CookieJar, prelude::*, Request};
|
||||||
use once_cell::sync::OnceCell;
|
use std::sync::RwLock;
|
||||||
|
|
||||||
|
struct CookieHold {
|
||||||
|
pub jar: CookieJar,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
/// Stores a client with a persistent cookie store
|
/// Stores a client with a persistent cookie store
|
||||||
static SESSION_COOKIE: OnceCell<CookieJar> = OnceCell::new();
|
static ref SESSION_COOKIE: RwLock<CookieHold> = RwLock::new(CookieHold { jar: CookieJar::new()});
|
||||||
/// Stores the last time a request was made, in seconds since UNIX epoch
|
/// Stores the last time a request was made, in seconds since UNIX epoch
|
||||||
static SESSION_TIME: OnceCell<u64> = OnceCell::new();
|
static ref SESSION_TIME: RwLock<u64> = RwLock::new(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Makes a request to the online classroom, and returns the html string
|
/// Makes a request to the online classroom, and returns the html string
|
||||||
pub async fn request(url: String) -> Result<String, String> {
|
pub async fn request(url: String) -> Result<String, String> {
|
||||||
@ -15,9 +24,7 @@ pub async fn request(url: String) -> Result<String, String> {
|
|||||||
ensure_session().await?;
|
ensure_session().await?;
|
||||||
|
|
||||||
// Get the stored client
|
// Get the stored client
|
||||||
let jar = SESSION_COOKIE
|
let jar = SESSION_COOKIE.read().unwrap().jar.clone();
|
||||||
.get()
|
|
||||||
.expect("SESSION_COOKIE was not set, even after calling ensure_session");
|
|
||||||
|
|
||||||
let uri = format!("{}{}", classroom_url, url);
|
let uri = format!("{}{}", classroom_url, url);
|
||||||
|
|
||||||
@ -41,10 +48,7 @@ pub async fn request(url: String) -> Result<String, String> {
|
|||||||
|
|
||||||
/// Makes sure that the session cookie is set, and that it is valid
|
/// Makes sure that the session cookie is set, and that it is valid
|
||||||
pub async fn ensure_session() -> Result<(), String> {
|
pub async fn ensure_session() -> Result<(), String> {
|
||||||
let last_usage_time = match SESSION_TIME.get() {
|
let last_usage_time = SESSION_TIME.read().unwrap().clone();
|
||||||
Some(time) => *time,
|
|
||||||
None => 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get current time in seconds
|
// Get current time in seconds
|
||||||
let current_time = SystemTime::now()
|
let current_time = SystemTime::now()
|
||||||
@ -57,9 +61,9 @@ pub async fn ensure_session() -> Result<(), String> {
|
|||||||
// Default PHP session timeout is 1440 seconds. Use a 1400 seconds timeout to be safe
|
// Default PHP session timeout is 1440 seconds. Use a 1400 seconds timeout to be safe
|
||||||
if time_passed > 1400 {
|
if time_passed > 1400 {
|
||||||
login().await?;
|
login().await?;
|
||||||
if let Err(err) = SESSION_TIME.set(current_time) {
|
|
||||||
return Err(format!("Error setting session time: {:?}", err));
|
let mut time_ptr = SESSION_TIME.write().unwrap();
|
||||||
}
|
*time_ptr = current_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -86,10 +90,10 @@ async fn login() -> Result<(), String> {
|
|||||||
.send();
|
.send();
|
||||||
|
|
||||||
match response {
|
match response {
|
||||||
Ok(_) => match SESSION_COOKIE.set(jar.clone()) {
|
Ok(_) => {
|
||||||
Ok(_) => Ok(()),
|
SESSION_COOKIE.write().unwrap().jar = jar.clone();
|
||||||
Err(error) => Err(format!("Error saving client: {:?}", error)),
|
Ok(())
|
||||||
},
|
}
|
||||||
Err(error) => Err(format!("Error connecting to online classroom: {:?}", error)),
|
Err(error) => Err(format!("Error connecting to online classroom: {:?}", error)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,11 +53,19 @@ fn parse_users(file: &str) -> Result<Vec<ClassroomPerson>, String> {
|
|||||||
|
|
||||||
let fragment = Html::parse_document(file);
|
let fragment = Html::parse_document(file);
|
||||||
|
|
||||||
// TODO: If no users are found, the form is not rendered, and the html is different
|
|
||||||
// Handle this case
|
|
||||||
let form_element = match fragment.select(&form_selector).next() {
|
let form_element = match fragment.select(&form_selector).next() {
|
||||||
Some(el) => el,
|
Some(el) => el,
|
||||||
None => return Err("Error selecting form#form_users_id: not found".into()),
|
// If the form is not found, it may mean that no users were found
|
||||||
|
None => {
|
||||||
|
let Ok(secondary_button) = Selector::parse("#img_plus_and_minus") else {
|
||||||
|
return Err("Error parsing secondary button selector".into());
|
||||||
|
};
|
||||||
|
|
||||||
|
match fragment.select(&secondary_button).next() {
|
||||||
|
Some(_) => return Ok(Vec::new()),
|
||||||
|
None => return Err("Error parsing html: no form or empty form found.".into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut result_vec = Vec::new();
|
let mut result_vec = Vec::new();
|
||||||
|
Loading…
Reference in New Issue
Block a user