[BE] Replace once_cell with RwLock. Fix classroom empty users error

master
Araozu 2023-10-02 11:24:19 -05:00
parent 525c72a9f6
commit 3d60f11f43
4 changed files with 36 additions and 24 deletions

2
backend/Cargo.lock generated
View File

@ -131,7 +131,7 @@ dependencies = [
"chrono", "chrono",
"dotenvy", "dotenvy",
"isahc", "isahc",
"once_cell", "lazy_static",
"reqwest", "reqwest",
"rocket", "rocket",
"scraper", "scraper",

View File

@ -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"

View File

@ -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)),
} }
} }

View File

@ -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();