Skip to content

Commit

Permalink
Support toph.co
Browse files Browse the repository at this point in the history
Fix for codechef.com
  • Loading branch information
EgorKulikov committed Nov 27, 2024
1 parent a1dbcd5 commit 8378a57
Show file tree
Hide file tree
Showing 4 changed files with 290 additions and 32 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ At the moment the following is supported:
- AtCoder
- Universal Cup
- Luogu (no support for changing language, language of the last submit is used)
- Toph (no support for changing language, language of the last submit is used)
73 changes: 60 additions & 13 deletions src/codechef.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use thirtyfour::{By, Cookie, Key, WebDriver};

pub async fn login(driver: &WebDriver, cookies: Vec<Cookie>) -> WebDriverResult<Vec<Cookie>> {
driver.goto("https://codechef.com/").await?;
driver.delete_all_cookies().await?;
for cookie in cookies {
driver.add_cookie(cookie).await?;
}
Expand All @@ -29,26 +30,52 @@ pub async fn login(driver: &WebDriver, cookies: Vec<Cookie>) -> WebDriverResult<
.with_prompt("Enter your codechef password")
.interact_on(&Term::stdout())
.unwrap();
driver.action_chain().send_keys(login).send_keys(Key::Tab).perform().await?;
driver.action_chain().send_keys(password).send_keys(Key::Tab).perform().await?;
driver
.action_chain()
.send_keys(login)
.send_keys(Key::Tab)
.perform()
.await?;
driver
.action_chain()
.send_keys(password)
.send_keys(Key::Tab)
.perform()
.await?;
driver.action_chain().send_keys(" ").perform().await?;
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
Ok(driver.get_all_cookies().await?)
}

pub async fn submit(driver: &WebDriver, url: String, language: String, source: String) -> WebDriverResult<()> {
pub async fn submit(
driver: &WebDriver,
url: String,
language: String,
source: String,
) -> WebDriverResult<()> {
driver.maximize_window().await?;
driver.goto(&url).await?;
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
tokio::time::sleep(std::time::Duration::from_secs(2)).await;
let language_select = driver.find(By::Id("language-select")).await?;
language_select.click().await?;
driver.action_chain().send_keys(language).perform().await?;
let center = language_select.rect().await?.icenter();
driver.action_chain().move_to(center.0, center.1 + 80).click().perform().await?;
driver.execute("\
driver
.action_chain()
.move_to(center.0, center.1 + 80)
.click()
.perform()
.await?;
driver
.execute(
"\
var editordiv = document.getElementById(\"submit-ide-v2\");\
var editor = ace.edit(editordiv);\
editor.setValue(arguments[0]);\
", vec![serde_json::to_value(source).unwrap()]).await?;
",
vec![serde_json::to_value(source).unwrap()],
)
.await?;
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
driver.screenshot(Path::new("screenshot.png")).await?;
driver.find(By::Id("submit_btn")).await?.click().await?;
Expand All @@ -66,10 +93,16 @@ pub async fn submit(driver: &WebDriver, url: String, language: String, source: S
clear(7);
let full_verdict = verdict.find(By::Tag("span")).await?.text().await?;
let accepted = full_verdict.contains("Correct Answer");
let _ = execute!(stdout, SetForegroundColor(if accepted { Color::Green } else { Color::Red }));
let _ = execute!(
stdout,
SetForegroundColor(if accepted { Color::Green } else { Color::Red })
);
println!("{}", full_verdict);
let _ = execute!(stdout, ResetColor);
File::create("source.txt").unwrap().write_all(driver.source().await?.as_bytes()).unwrap();
File::create("source.txt")
.unwrap()
.write_all(driver.source().await?.as_bytes())
.unwrap();
let table = loop {
match driver.find(By::ClassName("status-table")).await {
Ok(table) => break table,
Expand All @@ -82,7 +115,9 @@ pub async fn submit(driver: &WebDriver, url: String, language: String, source: S
let rows = table.find_all(By::Tag("tr")).await?;
println!("Subtask Task Result");
for row in rows.into_iter().skip(1) {
if row.class_name().await? == Some("skip".to_string()) || row.class_name().await? == Some("subtask-result".to_string()) {
if row.class_name().await? == Some("skip".to_string())
|| row.class_name().await? == Some("subtask-result".to_string())
{
continue;
}
let is_accepted = row.class_name().await? == Some("correct".to_string());
Expand All @@ -92,12 +127,24 @@ pub async fn submit(driver: &WebDriver, url: String, language: String, source: S
}
let subtask = cells[0].text().await?;
let task = cells[1].text().await?;
let result = cells[2].text().await?.replace("\n", "").replace("\"", "").replace("<br>", " ");
let _ = execute!(stdout, SetForegroundColor(if is_accepted { Color::Green } else { Color::Red }));
let result = cells[2]
.text()
.await?
.replace("\n", "")
.replace("\"", "")
.replace("<br>", " ");
let _ = execute!(
stdout,
SetForegroundColor(if is_accepted {
Color::Green
} else {
Color::Red
})
);
println!("{:7} {:4} {}", subtask, task, result);
let _ = execute!(stdout, ResetColor);
}
break;
}
Ok(())
}
}
79 changes: 60 additions & 19 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
mod codeforces;
mod codechef;
mod yandex;
mod atcoder;
mod ucup;
mod codechef;
mod codeforces;
mod luogu;
mod toph;
mod ucup;
mod yandex;

use regex::Regex;
use std::collections::HashMap;
Expand Down Expand Up @@ -37,59 +38,81 @@ async fn main() -> WebDriverResult<()> {
}
println!("Selenium is not running, starting");
let mut command = Command::new("docker");
command.args(&["run", "--rm", "-d", "-p", "4444:4444", "-p", "5900:5900", "--name", "selenium-server", "-v", "//dev/shm:/dev/shm", "selenium/standalone-chrome:latest"]);
command.args(&[
"run",
"--rm",
"-d",
"-p",
"4444:4444",
"-p",
"5900:5900",
"--name",
"selenium-server",
"-v",
"//dev/shm:/dev/shm",
"selenium/standalone-chrome:latest",
]);
command.status().unwrap();
println!("Waiting for selenium to start");
tokio::time::sleep(Duration::from_secs(5)).await;
WebDriver::new("http://localhost:4444", caps).await?
}
};

driver.set_page_load_timeout(Duration::from_secs(20)).await?;
driver
.set_page_load_timeout(Duration::from_secs(20))
.await?;

run(&driver, &url, &language, &source).await?;

driver.quit().await?;
Ok(())
}

async fn run(driver: &WebDriver, url: &String, language: &String, source: &String) -> WebDriverResult<()> {
async fn run(
driver: &WebDriver,
url: &String,
language: &String,
source: &String,
) -> WebDriverResult<()> {
let cookies_string = std::fs::read_to_string("cookies.json").unwrap_or("{}".to_string());
let mut all_cookies: HashMap<String, Vec<Cookie>> = serde_json::from_str(&cookies_string).unwrap_or(HashMap::new());
let mut all_cookies: HashMap<String, Vec<Cookie>> =
serde_json::from_str(&cookies_string).unwrap_or(HashMap::new());
let url_regex = Regex::new(r"https?://(?:www\.)?([^/]+).*").unwrap();
let domain = {
match url_regex.captures(url) {
None => {
println!("Unexpected URL");
return Ok(());
}
Some(caps) =>
caps[1].to_string(),
Some(caps) => caps[1].to_string(),
}
};


let site = match domain.as_str() {
"codeforces.com" => Site::Codeforces,
"codechef.com" => Site::Codechef,
"contest.yandex.com" => Site::Yandex,
"atcoder.jp" => Site::AtCoder,
"contest.ucup.ac" => Site::UniversalCup,
"luogu.com.cn" => Site::Luogu,
"toph.co" => Site::Toph,
_ => {
println!("Unsupported domain");
return Ok(());
}
};

println!("Logging in");
let cookies = site.login(&driver, all_cookies.get(&domain).cloned().unwrap_or(vec![])).await?;
let cookies = site
.login(&driver, all_cookies.get(&domain).cloned().unwrap_or(vec![]))
.await?;
all_cookies.insert(domain, cookies.clone());
println!("Logged in, saving cookies");
let cookies_string = serde_json::to_string(&all_cookies).unwrap();
std::fs::write("cookies.json", cookies_string).unwrap();
println!("Submitting");
site.submit(&driver, url.clone(), language.clone(), source.clone()).await?;
site.submit(&driver, url.clone(), language.clone(), source.clone())
.await?;
Ok(())
}

Expand All @@ -100,28 +123,41 @@ enum Site {
AtCoder,
UniversalCup,
Luogu,
Toph,
}

impl Site {
async fn submit(&self, driver: &WebDriver, url: String, language: String, source: String) -> WebDriverResult<()> {
async fn submit(
&self,
driver: &WebDriver,
url: String,
language: String,
source: String,
) -> WebDriverResult<()> {
match self {
Site::Codeforces => codeforces::submit(driver, url, language, source).await,
Site::Codechef => codechef::submit(driver, url, language, source).await,
Site::Yandex => yandex::submit(driver, url, language, source).await,
Site::AtCoder => atcoder::submit(driver, url, language, source).await,
Site::UniversalCup => ucup::submit(driver, url, language, source).await,
Site::Luogu => luogu::submit(driver, url, language, source).await,
Site::Toph => toph::submit(driver, url, language, source).await,
}
}

async fn login(&self, driver: &WebDriver, cookies: Vec<Cookie>) -> WebDriverResult<Vec<Cookie>> {
async fn login(
&self,
driver: &WebDriver,
cookies: Vec<Cookie>,
) -> WebDriverResult<Vec<Cookie>> {
match self {
Site::Codeforces => codeforces::login(driver, cookies).await,
Site::Codechef => codechef::login(driver, cookies).await,
Site::Yandex => yandex::login(driver, cookies).await,
Site::AtCoder => atcoder::login(driver, cookies).await,
Site::UniversalCup => ucup::login(driver, cookies).await,
Site::Luogu => luogu::login(driver, cookies).await,
Site::Toph => toph::login(driver, cookies).await,
}
}
}
Expand Down Expand Up @@ -153,13 +189,18 @@ async fn select_value(selector: WebElement, value: &str) -> WebDriverResult<bool
}

async fn set_value(driver: &WebDriver, element: WebElement, value: String) -> WebDriverResult<()> {
driver.execute("arguments[0].value = arguments[1];", vec![element.to_json()?, serde_json::to_value(value).unwrap()]).await?;
driver
.execute(
"arguments[0].value = arguments[1];",
vec![element.to_json()?, serde_json::to_value(value).unwrap()],
)
.await?;
Ok(())
}

#[allow(dead_code)]
async fn save_source(driver: &WebDriver) -> WebDriverResult<()> {
std::fs::write("source.txt", driver.source().await?).unwrap();
std::fs::write("source.html", driver.source().await?).unwrap();
Ok(())
}

Expand All @@ -173,4 +214,4 @@ fn clear(len: usize) {
for _ in 0..len {
print!("{}", 8u8 as char);
}
}
}
Loading

0 comments on commit 8378a57

Please sign in to comment.