From 7cf30ab18b42545e39586995918878183e4d2630 Mon Sep 17 00:00:00 2001 From: newt Date: Sat, 2 Nov 2024 00:01:51 +0000 Subject: [PATCH] feat: setup ratatui --- Cargo.lock | 310 ++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 + old.rs | 99 +++++++++++++++++ src/lib.rs | 1 + src/main.rs | 118 +++++--------------- 5 files changed, 440 insertions(+), 90 deletions(-) create mode 100644 old.rs create mode 100644 src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 1af6d2d..8ecf22f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,6 +26,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + [[package]] name = "atomic-waker" version = "1.1.2" @@ -77,6 +83,21 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" +[[package]] +name = "cassowary" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" + +[[package]] +name = "castaway" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0abae9be0aaf9ea96a3b1b8b1b55c602ca751eba1b1500220cea4ecbafe7c0d5" +dependencies = [ + "rustversion", +] + [[package]] name = "cc" version = "1.1.31" @@ -119,6 +140,20 @@ dependencies = [ "tracing-error", ] +[[package]] +name = "compact_str" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6050c3a16ddab2e412160b31f2c871015704239bca62f72f6e5f0be631d3f644" +dependencies = [ + "castaway", + "cfg-if", + "itoa", + "rustversion", + "ryu", + "static_assertions", +] + [[package]] name = "cookie" version = "0.18.1" @@ -163,6 +198,31 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "crossterm" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" +dependencies = [ + "bitflags", + "crossterm_winapi", + "mio", + "parking_lot", + "rustix", + "signal-hook", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +dependencies = [ + "winapi", +] + [[package]] name = "deranged" version = "0.3.11" @@ -184,7 +244,9 @@ version = "0.1.0" dependencies = [ "color-eyre", "cookie_store", + "crossterm", "dotenvy", + "ratatui", "regex", "reqwest", "reqwest_cookie_store", @@ -192,6 +254,12 @@ dependencies = [ "url", ] +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + [[package]] name = "encoding_rs" version = "0.8.35" @@ -239,6 +307,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" + [[package]] name = "foreign-types" version = "0.3.2" @@ -343,6 +417,17 @@ name = "hashbrown" version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" @@ -498,12 +583,37 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "indoc" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" + +[[package]] +name = "instability" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b23a0c8dfe501baac4adf6ebbfa6eddf8f0c07f56b058cc1288017e32397846c" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "ipnet" version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.11" @@ -537,12 +647,31 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +[[package]] +name = "lru" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +dependencies = [ + "hashbrown", +] + [[package]] name = "memchr" version = "2.7.4" @@ -582,6 +711,7 @@ checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ "hermit-abi", "libc", + "log", "wasi", "windows-sys 0.52.0", ] @@ -674,6 +804,35 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "percent-encoding" version = "2.3.1" @@ -738,6 +897,36 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "ratatui" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b" +dependencies = [ + "bitflags", + "cassowary", + "compact_str", + "crossterm", + "indoc", + "instability", + "itertools", + "lru", + "paste", + "strum", + "unicode-segmentation", + "unicode-truncate", + "unicode-width 0.2.0", +] + +[[package]] +name = "redox_syscall" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +dependencies = [ + "bitflags", +] + [[package]] name = "regex" version = "1.11.1" @@ -898,6 +1087,12 @@ dependencies = [ "untrusted", ] +[[package]] +name = "rustversion" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" + [[package]] name = "ryu" version = "1.0.18" @@ -913,6 +1108,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "security-framework" version = "2.11.1" @@ -995,6 +1196,36 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "signal-hook" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-mio" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" +dependencies = [ + "libc", + "mio", + "signal-hook", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + [[package]] name = "slab" version = "0.4.9" @@ -1026,6 +1257,34 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + [[package]] name = "subtle" version = "2.6.1" @@ -1283,6 +1542,35 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-truncate" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf" +dependencies = [ + "itertools", + "unicode-segmentation", + "unicode-width 0.1.14", +] + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-width" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" + [[package]] name = "untrusted" version = "0.9.0" @@ -1410,6 +1698,28 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-registry" version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index 04a1985..e56b118 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,9 @@ dotenvy = ["dep:dotenvy"] [dependencies] color-eyre = "0.6.3" cookie_store = "0.21.0" +crossterm = "0.28.1" dotenvy = { version = "0.15.7", optional = true } +ratatui = "0.29.0" regex = "1.11.1" reqwest = { version = "0.12.9", features = ["cookies", "multipart"] } reqwest_cookie_store = "0.8.0" diff --git a/old.rs b/old.rs new file mode 100644 index 0000000..0b52be3 --- /dev/null +++ b/old.rs @@ -0,0 +1,99 @@ +use color_eyre::eyre::eyre; +use color_eyre::Result; +use regex::Regex; +use reqwest::multipart::Form; +use reqwest::{Client, Url}; +use reqwest_cookie_store::CookieStoreMutex; +use std::env; +use std::sync::Arc; + +const DEFAULT_BASE_URL: &str = "https://echo360.org.uk"; + +#[tokio::main] +async fn main() -> Result<()> { + color_eyre::install()?; + #[cfg(feature = "dotenvy")] + dotenvy::dotenv()?; + + let jar = Arc::new(CookieStoreMutex::default()); + let client = Client::builder().cookie_provider(jar.clone()).build()?; + let base_url = Url::parse(DEFAULT_BASE_URL)?; + let domain = base_url.domain().unwrap(); + + // get the csrf token + client.get(base_url.clone()).send().await?; + + let csrf_token = jar + .lock() + .unwrap() + .get(domain, "/", "PLAY_SESSION") + .map(|cookie| { + let cookie_value = cookie.value().to_string(); + cookie_value + .split("&") + .nth(1) + .map(|part| part.split("=").last()) + .flatten() + .map(|x| x.to_string()) + }) + .flatten() + .ok_or(eyre!("No csrf token found"))?; + + // authenticate + client + .post(format!("{base_url}login")) + .query(&[("csrfToken", csrf_token)]) + .multipart( + Form::new() + .text("email", env::var("ECHO360_EMAIL")?) + .text("password", env::var("ECHO360_PASSWORD")?), + ) + .send() + .await?; + + // get institution id + let insitution_id = jar + .lock() + .unwrap() + .get(domain, "/", "PLAY_SESSION") + .map(|cookie| { + let cookie_value = cookie.value().to_string(); + cookie_value + .split("&") + .nth(1) + .map(|part| part.split("=").last()) + .flatten() + .map(|x| x.to_string()) + }) + .flatten() + .ok_or(eyre!("No institution id found"))?; + + println!("Institution ID: {}", insitution_id); + + // get authenticated user's name + let name = { + let html = client + .get(format!("{base_url}courses")) + .send() + .await? + .text() + .await?; + let first_name = Regex::new(r#"\\"firstName\\":\\"(\w+)\\""#)? + .captures(&html) + .unwrap() + .get(1) + .unwrap() + .as_str(); + let last_name = Regex::new(r#"\\"lastName\\":\\"(\w+)\\""#)? + .captures(&html) + .unwrap() + .get(1) + .unwrap() + .as_str(); + format!("{} {}", first_name, last_name) + }; + + println!("Name: {}", name); + + Ok(()) +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..ec17946 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1 @@ +pub type Terminal = ratatui::Terminal>; diff --git a/src/main.rs b/src/main.rs index 0b52be3..e13785c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,99 +1,37 @@ -use color_eyre::eyre::eyre; use color_eyre::Result; -use regex::Regex; -use reqwest::multipart::Form; -use reqwest::{Client, Url}; -use reqwest_cookie_store::CookieStoreMutex; -use std::env; -use std::sync::Arc; +use crossterm::event::{self, KeyCode, KeyEventKind}; +use echoed::Terminal; +use ratatui::widgets::Paragraph; -const DEFAULT_BASE_URL: &str = "https://echo360.org.uk"; +async fn run(mut terminal: Terminal) -> Result<()> { + loop { + terminal.draw(|frame| { + let greeting = Paragraph::new("Hello Ratatui! (press 'q' to quit)"); + frame.render_widget(greeting, frame.area()); + })?; + + if let event::Event::Key(key) = event::read()? { + if key.kind == KeyEventKind::Press && key.code == KeyCode::Char('q') { + return Ok(()); + } + } + } + + #[allow(unreachable_code)] + Ok(()) +} #[tokio::main] async fn main() -> Result<()> { - color_eyre::install()?; - #[cfg(feature = "dotenvy")] - dotenvy::dotenv()?; + // setup ratatui + let mut terminal = ratatui::init(); + terminal.clear()?; - let jar = Arc::new(CookieStoreMutex::default()); - let client = Client::builder().cookie_provider(jar.clone()).build()?; - let base_url = Url::parse(DEFAULT_BASE_URL)?; - let domain = base_url.domain().unwrap(); + // run ratatui application + let result = run(terminal).await; - // get the csrf token - client.get(base_url.clone()).send().await?; + // restore terminal to previous state + ratatui::restore(); - let csrf_token = jar - .lock() - .unwrap() - .get(domain, "/", "PLAY_SESSION") - .map(|cookie| { - let cookie_value = cookie.value().to_string(); - cookie_value - .split("&") - .nth(1) - .map(|part| part.split("=").last()) - .flatten() - .map(|x| x.to_string()) - }) - .flatten() - .ok_or(eyre!("No csrf token found"))?; - - // authenticate - client - .post(format!("{base_url}login")) - .query(&[("csrfToken", csrf_token)]) - .multipart( - Form::new() - .text("email", env::var("ECHO360_EMAIL")?) - .text("password", env::var("ECHO360_PASSWORD")?), - ) - .send() - .await?; - - // get institution id - let insitution_id = jar - .lock() - .unwrap() - .get(domain, "/", "PLAY_SESSION") - .map(|cookie| { - let cookie_value = cookie.value().to_string(); - cookie_value - .split("&") - .nth(1) - .map(|part| part.split("=").last()) - .flatten() - .map(|x| x.to_string()) - }) - .flatten() - .ok_or(eyre!("No institution id found"))?; - - println!("Institution ID: {}", insitution_id); - - // get authenticated user's name - let name = { - let html = client - .get(format!("{base_url}courses")) - .send() - .await? - .text() - .await?; - let first_name = Regex::new(r#"\\"firstName\\":\\"(\w+)\\""#)? - .captures(&html) - .unwrap() - .get(1) - .unwrap() - .as_str(); - let last_name = Regex::new(r#"\\"lastName\\":\\"(\w+)\\""#)? - .captures(&html) - .unwrap() - .get(1) - .unwrap() - .as_str(); - format!("{} {}", first_name, last_name) - }; - - println!("Name: {}", name); - - Ok(()) + result }