diff --git a/Cargo.lock b/Cargo.lock index 1a7209c..e2ae16a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aho-corasick" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +dependencies = [ + "memchr", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -69,6 +78,19 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "env_logger" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + [[package]] name = "errno" version = "0.3.1" @@ -268,6 +290,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "hyper" version = "0.14.26" @@ -351,6 +379,18 @@ version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" +[[package]] +name = "is-terminal" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +dependencies = [ + "hermit-abi 0.3.1", + "io-lifetimes", + "rustix", + "windows-sys 0.48.0", +] + [[package]] name = "itoa" version = "1.0.6" @@ -384,6 +424,16 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" version = "0.4.17" @@ -495,6 +545,29 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "windows-sys 0.45.0", +] + [[package]] name = "percent-encoding" version = "2.2.0" @@ -573,6 +646,15 @@ dependencies = [ "getrandom", ] +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + [[package]] name = "redox_syscall" version = "0.3.5" @@ -582,6 +664,23 @@ dependencies = [ "bitflags", ] +[[package]] +name = "regex" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + [[package]] name = "reqwest" version = "0.11.16" @@ -623,9 +722,12 @@ dependencies = [ name = "rulebot" version = "0.1.0" dependencies = [ + "env_logger", "exitcode", + "log", "rand", "reqwest", + "tokio", ] [[package]] @@ -657,6 +759,12 @@ dependencies = [ "windows-sys 0.42.0", ] +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "security-framework" version = "2.8.2" @@ -709,6 +817,15 @@ dependencies = [ "serde", ] +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + [[package]] name = "slab" version = "0.4.8" @@ -718,6 +835,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + [[package]] name = "socket2" version = "0.4.9" @@ -758,11 +881,20 @@ checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", + "redox_syscall 0.3.5", "rustix", "windows-sys 0.45.0", ] +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -789,11 +921,25 @@ dependencies = [ "libc", "mio", "num_cpus", + "parking_lot", "pin-project-lite", + "signal-hook-registry", "socket2", + "tokio-macros", "windows-sys 0.45.0", ] +[[package]] +name = "tokio-macros" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", +] + [[package]] name = "tokio-native-tls" version = "0.3.1" @@ -996,6 +1142,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index e67c277..3ef2bac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,4 +14,7 @@ exclude = ["/.*"] [dependencies] reqwest = { version = "0.11.16", features = ["blocking"] } exitcode = "1.1.2" -rand = "0.8.5" \ No newline at end of file +rand = "0.8.5" +tokio = { version="1.27.0", features = ["full"] } +log = "0.4.17" +env_logger = "0.10.0" \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 50c0077..1d28eb5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ -use std::{fmt::Display, ops::Index}; +use std::{fmt::Display, future::Future, ops::Index, time::Duration}; use rand::Rng; +use tokio::{signal, time}; #[derive(Debug, Clone, Copy)] struct State([bool; 8]); @@ -48,14 +49,32 @@ impl Into for u8 { } } -fn main() { - let mut rng = rand::thread_rng(); - let seed: u16 = rng.gen(); +async fn send_status( + rule: u8, + states: String, +) -> impl Future> { + let client = reqwest::Client::new(); + client + .post("https://mastodon.raptorpond.com/api/v1/statuses") + .header( + "Authorization", + format!( + "Bearer {}", + std::env::var("RULEBOT_MASTODON_TOKEN").unwrap_or_default() + ), + ) + .form(&[ + ("status", format!("Rule: {}\n{}", rule, states)), + ("visibility", String::from("private")), + ]) + .send() +} +fn generate(seed: u16) -> String { let rule: u8 = (seed & 0xff) as u8; let init_state = ((seed >> 8 & 0xff) as u8).into(); - let states: String = (0..8) + (0..8) .scan(init_state, |state, _i| { let old_state = *state; *state = map_state(rule, state); @@ -63,28 +82,70 @@ fn main() { }) .map(|state| state.to_string()) .collect::>() - .join("\n"); - - println!("Rule: {}\n{}", rule, states); + .join("\n") +} - let client = reqwest::blocking::Client::new(); - let res = client - .post("https://mastodon.raptorpond.com/api/v1/statuses") - .header( - "Authorization", - format!("Bearer {}", std::env::var("MASTODON_TOKEN").unwrap()), - ) - .form(&[ - ("status", format!("Rule: {}\n{}", rule, states)), - ("visibility", String::from("private")), - ]) - .send(); +#[tokio::main] +async fn main() { + env_logger::init(); + + let generator = tokio::spawn(async { + let mut interval = time::interval(time::Duration::from_secs( + std::env::var("RULEBOT_POST_INTERVAL") + .unwrap_or("2".into()) + .parse() + .unwrap(), + )); + + loop { + interval.tick().await; + + let seed; + + // Block to drop rng before switching context + { + let mut rng = rand::thread_rng(); + + seed = rng.gen(); + } + + let rule = (seed & 0xff) as u8; + + // Generate the states + let states: String = generate(seed); + + log::info!("Rule: {}\n{}", rule, states); + + // Send toot + let sent = + tokio::time::timeout(Duration::from_secs(1), send_status(rule, states).await).await; + + // Figure out what went wrong + match sent { + Ok(result) => match result { + Ok(response) => { + if response.status() != 200 { + log::error!("Send status error code: {}", response.status()) + } + } + Err(err) => { + log::error!("Send status error: {}", err); + } + }, + Err(_) => { + log::error!("Send status timed out!"); + } + } + } + }); - match res { - Ok(_) => std::process::exit(exitcode::OK), - Err(error) => { - println!("{:?}", error); - std::process::exit(exitcode::IOERR); + match signal::ctrl_c().await { + Ok(()) => {} + Err(err) => { + log::error!("Unable to listen for shutdown signal: {}", err); } } + + // Kill generator + generator.abort() }