From fab9ab50088d5a4417328ad35e87f4f4191895e2 Mon Sep 17 00:00:00 2001 From: John-John Tedro Date: Fri, 24 Jul 2020 08:16:04 +0200 Subject: [PATCH] Clean up main loop --- Cargo.lock | 159 ++++++++------- Cargo.toml | 11 +- README.md | 6 +- bot/src/api/setbac.rs | 2 +- bot/src/command.rs | 2 +- bot/src/irc/currency_admin.rs | 4 +- bot/src/main.rs | 217 ++++++++++----------- bot/src/module/gtav.rs | 2 +- bot/src/module/misc.rs | 2 +- bot/src/module/song.rs | 14 +- bot/src/player/song.rs | 4 +- bot/src/sys/mod.rs | 6 +- bot/src/sys/noop.rs | 10 +- bot/src/sys/{windows.rs => windows/mod.rs} | 76 +++----- bot/src/utils/duration.rs | 2 +- bot/src/utils/mod.rs | 14 +- 16 files changed, 250 insertions(+), 281 deletions(-) rename bot/src/sys/{windows.rs => windows/mod.rs} (75%) diff --git a/Cargo.lock b/Cargo.lock index da7f22d3..0f9616f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -107,7 +107,7 @@ dependencies = [ "async-trait", "futures-util", "hashbrown 0.7.2", - "log 0.4.8", + "log 0.4.11", "serde", "serde-hashkey", "smallvec 1.4.1", @@ -460,7 +460,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e" dependencies = [ "cfg-if", - "crossbeam-channel 0.4.2", + "crossbeam-channel 0.4.3", "crossbeam-deque", "crossbeam-epoch 0.8.2", "crossbeam-queue", @@ -478,12 +478,12 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cced8691919c02aac3cb0a1bc2e9b73d89e832bf9a06fc579d4e71b68a2da061" +checksum = "09ee0cc8804d5393478d743b035099520087a5186f3b93fa58cec08fa62407b6" dependencies = [ + "cfg-if", "crossbeam-utils 0.7.2", - "maybe-uninit", ] [[package]] @@ -761,7 +761,7 @@ checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" dependencies = [ "atty", "humantime", - "log 0.4.8", + "log 0.4.11", "regex", "termcolor", ] @@ -913,7 +913,7 @@ dependencies = [ "futures-channel", "hashbrown 0.6.3", "hex 0.3.2", - "log 0.4.8", + "log 0.4.11", "parking_lot 0.10.2", "pin-utils", "serde", @@ -1135,11 +1135,11 @@ checksum = "d36fab90f82edc3c747f9d438e06cf0a491055896f2a279638bb5beed6c40177" [[package]] name = "handlebars" -version = "3.2.1" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8ae96a0e0dacf151557ccba95a7a80889f8e74a784484377739628fcdb3996" +checksum = "86dbc8a0746b08f363d2e00da48e6c9ceb75c198ac692d2715fcbb5bee74c87d" dependencies = [ - "log 0.4.8", + "log 0.4.11", "pest", "pest_derive", "quick-error", @@ -1167,6 +1167,15 @@ dependencies = [ "autocfg 1.0.0", ] +[[package]] +name = "hashbrown" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34f595585f103464d8d2f6e9864682d74c1601fed5e07d62b1c9058dba8246fb" +dependencies = [ + "autocfg 1.0.0", +] + [[package]] name = "headers" version = "0.3.2" @@ -1320,11 +1329,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c398b2b113b55809ceb9ee3e753fcbac793f1956663f3c36549c1346015c2afe" +checksum = "5b88cd59ee5f71fea89a62248fc8f387d44400cefe05ef548466d61ced9029a7" dependencies = [ "autocfg 1.0.0", + "hashbrown 0.8.1", ] [[package]] @@ -1364,7 +1374,7 @@ dependencies = [ "futures-channel", "futures-util", "irc-proto", - "log 0.4.8", + "log 0.4.11", "native-tls", "parking_lot 0.10.2", "pin-utils", @@ -1398,9 +1408,9 @@ checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" [[package]] name = "js-sys" -version = "0.3.41" +version = "0.3.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4b9172132a62451e56142bff9afc91c8e4a4500aa5b847da36815b63bfda916" +checksum = "52732a3d3ad72c58ad2dc70624f9c17b46ecd0943b9a4f1ee37c4c18c5d983e2" dependencies = [ "wasm-bindgen", ] @@ -1430,7 +1440,7 @@ dependencies = [ "futures-channel", "futures-util", "lazy_static", - "log 0.4.8", + "log 0.4.11", "thiserror", "tokio", ] @@ -1460,9 +1470,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.72" +version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9f8082297d534141b30c8d39e9b1773713ab50fdbe4ff30f750d063b3bfd701" +checksum = "bd7d4bd64732af4bf3a67f367c27df8520ad7e230c5817b8ff485864d80242b9" [[package]] name = "libsqlite3-sys" @@ -1508,14 +1518,14 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" dependencies = [ - "log 0.4.8", + "log 0.4.11", ] [[package]] name = "log" -version = "0.4.8" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" dependencies = [ "cfg-if", "serde", @@ -1539,7 +1549,7 @@ dependencies = [ "fnv", "humantime", "libc", - "log 0.4.8", + "log 0.4.11", "log-mdc", "parking_lot 0.10.2", "serde", @@ -1664,7 +1674,7 @@ dependencies = [ "iovec", "kernel32-sys", "libc", - "log 0.4.8", + "log 0.4.11", "miow 0.2.1", "net2", "slab", @@ -1677,7 +1687,7 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656" dependencies = [ - "log 0.4.8", + "log 0.4.11", "mio", "miow 0.3.5", "winapi 0.3.9", @@ -1724,7 +1734,7 @@ checksum = "136eed74cadb9edd2651ffba732b19a450316b680e4f48d6c79e905799e19d01" dependencies = [ "buf_redux", "httparse", - "log 0.4.8", + "log 0.4.11", "mime 0.2.6", "mime_guess 1.8.8", "quick-error", @@ -1799,7 +1809,7 @@ checksum = "2b0d88c06fe90d5ee94048ba40409ef1d9315d86f6f38c2efdaad4fb50c58b2d" dependencies = [ "lazy_static", "libc", - "log 0.4.8", + "log 0.4.11", "openssl", "openssl-probe", "openssl-sys", @@ -1958,7 +1968,7 @@ dependencies = [ "lazy_static", "leaky-bucket", "libsqlite3-sys", - "log 0.4.8", + "log 0.4.11", "log4rs", "mime 0.3.16", "mime_guess 2.0.3", @@ -2005,7 +2015,7 @@ dependencies = [ "cookie", "futures", "hyper", - "log 0.4.8", + "log 0.4.11", "mime 0.3.16", "mime_guess 2.0.3", "parking_lot 0.10.2", @@ -2043,7 +2053,7 @@ dependencies = [ "fs2", "fxhash", "libc", - "log 0.4.8", + "log 0.4.11", "parking_lot 0.9.0", "serde", ] @@ -2246,7 +2256,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d" dependencies = [ "env_logger", - "log 0.4.8", + "log 0.4.11", ] [[package]] @@ -2263,9 +2273,9 @@ checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a" [[package]] name = "proc-macro2" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa" +checksum = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12" dependencies = [ "unicode-xid", ] @@ -2511,7 +2521,7 @@ dependencies = [ "hyper-tls", "js-sys", "lazy_static", - "log 0.4.8", + "log 0.4.11", "mime 0.3.16", "mime_guess 2.0.3", "native-tls", @@ -2557,9 +2567,9 @@ dependencies = [ [[package]] name = "rust-embed" -version = "5.5.1" +version = "5.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a17890cbd0fae97c2006fa1ecec9554946443c319f4dd8cd8d3b92031725161" +checksum = "213acf1bc5a6dfcd70b62db1e9a7d06325c0e73439c312fcb8599d456d9686ee" dependencies = [ "rust-embed-impl", "rust-embed-utils", @@ -2568,9 +2578,9 @@ dependencies = [ [[package]] name = "rust-embed-impl" -version = "5.5.1" +version = "5.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60cacc306d294556771c6e92737ba7e6be0264144bc46dd713a14ef384b0d6b8" +checksum = "7903c2cf599db8f310b392332f38367ca4acc84420fa1aee3536299f433c10d5" dependencies = [ "quote", "rust-embed-utils", @@ -2865,7 +2875,7 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c3d0ffdcb80d10203517641c514b205d89541b001149df43ae6e902bc19809d" dependencies = [ - "log 0.4.8", + "log 0.4.11", "pagecache", "parking_lot 0.9.0", "serde", @@ -2884,7 +2894,7 @@ dependencies = [ "fs2", "fxhash", "libc", - "log 0.4.8", + "log 0.4.11", "parking_lot 0.10.2", ] @@ -2900,7 +2910,7 @@ dependencies = [ "fs2", "fxhash", "libc", - "log 0.4.8", + "log 0.4.11", "parking_lot 0.10.2", ] @@ -3018,9 +3028,9 @@ checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" [[package]] name = "syn" -version = "1.0.34" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936cae2873c940d92e697597c5eee105fb570cd5689c695806f672883653349b" +checksum = "fb7f4c519df8c117855e19dd8cc851e89eb746fe7a73f0157e0d95fdec5369b0" dependencies = [ "proc-macro2", "quote", @@ -3167,8 +3177,8 @@ checksum = "53953d2d3a5ad81d9f844a32f14ebb121f50b650cd59d0ee2a07cf13c617efed" [[package]] name = "tokio" -version = "0.2.21" -source = "git+https://github.com/udoprog/tokio?branch=rwlock-map#ed3a76085754f05ed7e31ae4ba49788af3b50871" +version = "0.2.22" +source = "git+https://github.com/udoprog/tokio?branch=rwlock-map#3812179b17e1badecbcf734a5ba2fa091fa2f113" dependencies = [ "bytes", "fnv", @@ -3191,7 +3201,7 @@ dependencies = [ [[package]] name = "tokio-macros" version = "0.2.5" -source = "git+https://github.com/udoprog/tokio?branch=rwlock-map#ed3a76085754f05ed7e31ae4ba49788af3b50871" +source = "git+https://github.com/udoprog/tokio?branch=rwlock-map#3812179b17e1badecbcf734a5ba2fa091fa2f113" dependencies = [ "proc-macro2", "quote", @@ -3215,7 +3225,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8b8fe88007ebc363512449868d7da4389c9400072a3f666f212c7280082882a" dependencies = [ "futures", - "log 0.4.8", + "log 0.4.11", "pin-project", "tokio", "tungstenite", @@ -3230,7 +3240,7 @@ dependencies = [ "bytes", "futures-core", "futures-sink", - "log 0.4.8", + "log 0.4.11", "pin-project-lite", "tokio", ] @@ -3244,7 +3254,7 @@ dependencies = [ "bytes", "futures-core", "futures-sink", - "log 0.4.8", + "log 0.4.11", "pin-project-lite", "tokio", ] @@ -3266,12 +3276,12 @@ checksum = "e987b6bf443f4b5b3b6f38704195592cca41c5bb7aedd3c3693c7081f8289860" [[package]] name = "tracing" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e2a2de6b0d5cbb13fc21193a2296888eaab62b6044479aafb3c54c01c29fcd" +checksum = "dbdf4ccd1652592b01286a5dbe1e2a77d78afaa34beadd9872a5f7396f92aaa9" dependencies = [ "cfg-if", - "log 0.4.8", + "log 0.4.11", "tracing-attributes", "tracing-core", ] @@ -3330,7 +3340,7 @@ dependencies = [ "http", "httparse", "input_buffer", - "log 0.4.8", + "log 0.4.11", "rand 0.7.3", "sha-1", "url", @@ -3545,22 +3555,22 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" dependencies = [ - "log 0.4.8", + "log 0.4.11", "try-lock", ] [[package]] name = "warp" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e95175b7a927258ecbb816bdada3cc469cb68593e7940b96a60f4af366a9970" +checksum = "df341dee97c9ae29dfa5e0b0fbbbf620e0d6a36686389bedf83b3daeb8b0d0ac" dependencies = [ "bytes", "futures", "headers", "http", "hyper", - "log 0.4.8", + "log 0.4.11", "mime 0.3.16", "mime_guess 2.0.3", "multipart", @@ -3572,6 +3582,8 @@ dependencies = [ "tokio", "tokio-tungstenite", "tower-service", + "tracing", + "tracing-futures", "urlencoding", ] @@ -3583,9 +3595,9 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasm-bindgen" -version = "0.2.64" +version = "0.2.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a634620115e4a229108b71bde263bb4220c483b3f07f5ba514ee8d15064c4c2" +checksum = "f3edbcc9536ab7eababcc6d2374a0b7bfe13a2b6d562c5e07f370456b1a8f33d" dependencies = [ "cfg-if", "serde", @@ -3595,13 +3607,13 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.64" +version = "0.2.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e53963b583d18a5aa3aaae4b4c1cb535218246131ba22a71f05b518098571df" +checksum = "89ed2fb8c84bfad20ea66b26a3743f3e7ba8735a69fe7d95118c33ec8fc1244d" dependencies = [ "bumpalo", "lazy_static", - "log 0.4.8", + "log 0.4.11", "proc-macro2", "quote", "syn", @@ -3610,9 +3622,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dba48d66049d2a6cc8488702e7259ab7afc9043ad0dc5448444f46f2a453b362" +checksum = "41ad6e4e8b2b7f8c90b6e09a9b590ea15cb0d1dbe28502b5a405cd95d1981671" dependencies = [ "cfg-if", "js-sys", @@ -3622,9 +3634,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.64" +version = "0.2.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fcfd5ef6eec85623b4c6e844293d4516470d8f19cd72d0d12246017eb9060b8" +checksum = "eb071268b031a64d92fc6cf691715ca5a40950694d8f683c5bb43db7c730929e" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3632,9 +3644,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.64" +version = "0.2.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9adff9ee0e94b926ca81b57f57f86d5545cdcb1d259e21ec9bdd95b901754c75" +checksum = "cf592c807080719d1ff2f245a687cbadb3ed28b2077ed7084b47aba8b691f2c6" dependencies = [ "proc-macro2", "quote", @@ -3645,15 +3657,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.64" +version = "0.2.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7b90ea6c632dd06fd765d44542e234d5e63d9bb917ecd64d79778a13bd79ae" +checksum = "72b6c0220ded549d63860c78c38f3bcc558d1ca3f4efa74942c536ddbbb55e87" [[package]] name = "web-sys" -version = "0.3.41" +version = "0.3.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "863539788676619aac1a23e2df3655e96b32b0e05eb72ca34ba045ad573c625d" +checksum = "8be2398f326b7ba09815d0b403095f34dd708579220d099caae89be0b32137b2" dependencies = [ "js-sys", "wasm-bindgen", @@ -3661,10 +3673,11 @@ dependencies = [ [[package]] name = "webbrowser" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a83a4b8838569b89d2a3e7353995088e3b80c420a1269cd3d92ba8196875fc16" +checksum = "ecad156490d6b620308ed411cfee90d280b3cbd13e189ea0d3fada8acc89158a" dependencies = [ + "web-sys", "widestring", "winapi 0.3.9", ] diff --git a/Cargo.toml b/Cargo.toml index 03b02f8f..a0c336e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,8 @@ [workspace] -members = [ - "bot", - "web", -] - -exclude = [ - "tools/builder" -] +default-members = ["bot"] +members = ["bot", "web"] +exclude = ["tools/builder"] [profile.release] opt-level = 'z' diff --git a/README.md b/README.md index ae3c5c66..1ae8ad0c 100644 --- a/README.md +++ b/README.md @@ -69,20 +69,20 @@ You'll need Rust and a working compiler: https://rustup.rs/ After this, you build the project using cargo: ```bash -cargo build --bin oxidize +cargo build ``` If you want to run it directly from the project directory, you can do: ```bash -cargo run --bin oxidize +cargo run ``` If you want to run the bot with the most amount of diagnostics possible, you can do the following: ```bash -env RUST_BACKTRACE=1 cargo +nightly run --bin oxidize -- --log oxidize=trace +env RUST_BACKTRACE=1 cargo +nightly run -- --log oxidize=trace ``` This will include backtraces on errors, which is currently an [unstable feature]. diff --git a/bot/src/api/setbac.rs b/bot/src/api/setbac.rs index 4ecbd90d..23ea703d 100644 --- a/bot/src/api/setbac.rs +++ b/bot/src/api/setbac.rs @@ -419,7 +419,7 @@ impl From> for Item { track_id: i.track_id.to_string(), track_url: i.track_id.url(), user: i.user.clone(), - duration: utils::compact_duration(&i.duration), + duration: utils::compact_duration(i.duration), } } } diff --git a/bot/src/command.rs b/bot/src/command.rs index 20da80e0..ac207a6a 100644 --- a/bot/src/command.rs +++ b/bot/src/command.rs @@ -143,7 +143,7 @@ impl Context { if let Some(duration) = cooldown.check(now.clone()) { self.respond(format!( "Cooldown in effect for {}", - utils::compact_duration(&duration), + utils::compact_duration(duration), )) .await; diff --git a/bot/src/irc/currency_admin.rs b/bot/src/irc/currency_admin.rs index 89fbeb27..ca4f3350 100644 --- a/bot/src/irc/currency_admin.rs +++ b/bot/src/irc/currency_admin.rs @@ -47,7 +47,7 @@ impl command::Handler for Handler { match result { Ok(balance) => { let balance = balance.unwrap_or_default(); - let watch_time = utils::compact_duration(&balance.watch_time().as_std()); + let watch_time = utils::compact_duration(balance.watch_time().as_std()); respond!( user, @@ -70,7 +70,7 @@ impl command::Handler for Handler { match currency.balance_of(ctx.channel(), to_show.as_str()).await { Ok(balance) => { let balance = balance.unwrap_or_default(); - let watch_time = utils::compact_duration(&balance.watch_time().as_std()); + let watch_time = utils::compact_duration(balance.watch_time().as_std()); respond!( ctx, diff --git a/bot/src/main.rs b/bot/src/main.rs index 535684b6..d7dc96df 100644 --- a/bot/src/main.rs +++ b/bot/src/main.rs @@ -2,7 +2,7 @@ #![cfg_attr(feature = "windows", windows_subsystem = "windows")] #![cfg_attr(backtrace, feature(backtrace))] -use anyhow::{anyhow, bail, Context, Error}; +use anyhow::{anyhow, bail, Context, Result}; use backoff::backoff::Backoff as _; use oxidize::api; use oxidize::auth; @@ -138,7 +138,7 @@ fn opts() -> clap::App<'static, 'static> { } /// Setup tracing. -fn tracing_config() -> Result<(), Error> { +fn tracing_config() -> Result<()> { tracing::subscriber::set_global_default(tracing_utils::Subscriber::new())?; Ok(()) } @@ -148,7 +148,7 @@ fn default_log_config( log_path: &Path, trace: bool, modules: &[&str], -) -> Result { +) -> Result { use self::internal::{config_builder, logger_builder, root_builder}; use log::LevelFilter; use log4rs::{append::file::FileAppender, config::Appender, encode::pattern::PatternEncoder}; @@ -221,7 +221,7 @@ fn setup_logs( default_log_file: &Path, trace: bool, modules: Vec<&str>, -) -> Result<(), Error> { +) -> Result<()> { let file = log_config.unwrap_or_else(|| root.join("log4rs.yaml")); if !file.is_file() { @@ -235,7 +235,13 @@ fn setup_logs( Ok(()) } -fn main() -> Result<(), Error> { +#[derive(Debug, Clone, Copy)] +enum Intent { + Shutdown, + Restart, +} + +fn main() -> Result<()> { let opts = opts(); let m = opts.get_matches(); @@ -277,106 +283,119 @@ fn main() -> Result<(), Error> { error_backoff.initial_interval = time::Duration::from_secs(5); error_backoff.max_elapsed_time = None; - let mut current_backoff; - let mut errored = false; + let is_silent = !m.is_present("silent"); - if !m.is_present("silent") { + if !is_silent { let startup = sys::Notification::new(format!("Started Oxidize {}", oxidize::VERSION)); system.notification(startup); } - loop { - if !system.is_running() { - break; - } + let database_path = { + let new = root.join("oxidize.sql"); - if errored { - system.clear(); - errored = false; + if let Some(old) = old_root { + let old = old.join("setmod.sql"); + + if old.is_file() && !new.is_file() { + std::fs::copy(&old, &new).with_context(|| { + anyhow!( + "failed to copy database: {} to {}", + old.display(), + new.display() + ) + })?; + } } - let future = { - let system = system.clone(); - let old_root = old_root.clone(); - let root = root.clone(); + new + }; - try_main(system, old_root, root).instrument(trace_span!(target: "futures", "main",)) - }; + let db = db::Database::open(&database_path) + .with_context(|| anyhow!("failed to open database at: {}", database_path.display()))?; + + let storage = storage::Storage::open(&root.join("storage"))?; + loop { let mut runtime = tokio::runtime::Builder::new() .threaded_scheduler() .enable_all() .build()?; - let result = runtime.block_on(future); + let future = { + try_main(&system, &root, &db, &storage) + .instrument(trace_span!(target: "futures", "main",)) + }; - match result { + let backoff = match runtime.block_on(future) { Err(e) => { let backoff = error_backoff.next_backoff().unwrap_or_default(); - current_backoff = Some(backoff); - errored = true; + system.error(String::from("Bot crashed, see log for more details.")); + oxidize::log_error!(e, "Bot crashed"); + Some(backoff) + } + Ok(Intent::Shutdown) => { + break; + } + Ok(Intent::Restart) => { + error_backoff.reset(); + None + } + }; + if let Some(backoff) = backoff { + if !is_silent { let message = format!( - "Trying to restart in {}.\nSee log for more details.", - utils::compact_duration(&backoff) + "Restart in {}.\nSee log for more details.", + utils::compact_duration(backoff) ); let n = sys::Notification::new(message) - .title("Bot crashed!") + .title("Bot Crashed!") .icon(sys::NotificationIcon::Error); system.notification(n); - system.error(String::from("Bot crashed, see log for more details.")); - oxidize::log_error!(e, "Bot crashed"); } - Ok(()) => { - error_backoff.reset(); - current_backoff = None; - log::info!("Bot was shut down cleanly"); - } - } - if !system.is_running() { - break; - } - - if let Some(current_backoff) = current_backoff.clone() { - log::info!( - "Restarting in {}...", - utils::compact_duration(¤t_backoff) - ); - - let system = system.clone(); + log::info!("Restarting in {}...", utils::compact_duration(backoff)); - runtime.block_on(async move { + let intent = runtime.block_on(async { tokio::select! { - _ = system.wait_for_shutdown() => { - } - _ = system.wait_for_restart() => { - } - _ = tokio::time::delay_for(current_backoff) => { - } + _ = system.wait_for_shutdown() => Intent::Shutdown, + _ = system.wait_for_restart() => Intent::Restart, + _ = tokio::signal::ctrl_c() => Intent::Shutdown, + _ = tokio::time::delay_for(backoff) => Intent::Restart, } }); + + if let Intent::Shutdown = intent { + break; + } } - if !errored { - let n = sys::Notification::new("Restarted bot").icon(sys::NotificationIcon::Warning); + if !is_silent { + let n = + sys::Notification::new("Restarted OxidizeBot").icon(sys::NotificationIcon::Warning); system.notification(n); } } - log::info!("Exiting..."); + if !is_silent { + let shutdown = sys::Notification::new("Exiting OxidizeBot"); + system.notification(shutdown); + } + + log::info!("exiting..."); system.join()?; Ok(()) } /// Actual main function, running the application loop. async fn try_main( - system: sys::System, - old_root: Option, - root: PathBuf, -) -> Result<(), Error> { + system: &sys::System, + root: &Path, + db: &db::Database, + storage: &storage::Storage, +) -> Result { log::info!("Starting Oxidize Bot Version {}", oxidize::VERSION); if !root.is_dir() { @@ -389,28 +408,6 @@ async fn try_main( let mut modules = Vec::>::new(); let mut futures = futures::stream::FuturesUnordered::new(); - let database_path = { - let new = root.join("oxidize.sql"); - - if let Some(old) = old_root { - let old = old.join("setmod.sql"); - - if old.is_file() && !new.is_file() { - std::fs::copy(&old, &new).with_context(|| { - anyhow!( - "failed to copy database: {} to {}", - old.display(), - new.display() - ) - })?; - } - } - - new - }; - - let db = db::Database::open(&database_path) - .with_context(|| anyhow!("failed to open database at: {}", database_path.display()))?; injector.update(db.clone()).await; let scopes_schema = auth::Schema::load_static()?; @@ -467,7 +464,6 @@ async fn try_main( .instrument(trace_span!(target: "futures", "system-loop",)), ); - let storage = storage::Storage::open(&root.join("storage"))?; injector.update(storage.cache()?).await; let (latest, future) = updater::run(&injector); @@ -637,7 +633,7 @@ async fn try_main( .instrument(trace_span!(target: "futures", "open-weather-map",)), ); - let (shutdown, shutdown_rx) = utils::Shutdown::new(); + let (shutdown, internal_shutdown) = utils::Shutdown::new(); let spotify = Arc::new(api::Spotify::new(spotify_token.clone())?); let youtube = Arc::new(api::YouTube::new(youtube_token.clone())?); @@ -730,35 +726,26 @@ async fn try_main( .instrument(trace_span!(target: "futures", "irc",)), ); - let stuff = async move { futures.select_next_some().await.map_err(Some) }; - - let system_shutdown = system.wait_for_shutdown(); - let system_restart = system.wait_for_restart(); - - let shutdown_rx = async move { - let futures = vec![ - system_shutdown.boxed(), - system_restart.boxed(), - shutdown_rx.boxed(), - ]; - let _ = future::select_all(futures).await; - Err::<(), _>(None::) - }; - - let result = future::try_join( - stuff.instrument(trace_span!(target: "futures", "core")), - shutdown_rx.instrument(trace_span!(target: "futures", "shutdown")), - ) - .await; - - match result { - Ok(_) => Ok(()), - Err(Some(e)) => Err(e), - // Shutting down cleanly. - Err(None) => { - log::info!("Shutting down..."); - Ok(()) + tokio::select! { + result = futures.select_next_some() => { + result.map(|_| Intent::Shutdown) } + _ = system.wait_for_shutdown() => { + log::info!("shutdown triggered by system"); + Ok(Intent::Shutdown) + }, + _ = system.wait_for_restart() => { + log::info!("restart triggered by system"); + Ok(Intent::Restart) + }, + _ = internal_shutdown => { + log::info!("shutdown triggered by bot"); + Ok(Intent::Shutdown) + }, + _ = tokio::signal::ctrl_c() => { + log::info!("shutdown triggered by signal"); + Ok(Intent::Shutdown) + }, } } @@ -769,7 +756,7 @@ async fn notify_after_streams( injector: &injector::Injector, mut rx: mpsc::Receiver, system: sys::System, -) -> Result<(), Error> { +) -> Result<()> { let (mut after_streams_stream, mut after_streams) = injector.stream::().await; loop { @@ -811,7 +798,7 @@ async fn notify_after_streams( } /// Run the loop that handles installing this as a service. -async fn system_loop(settings: settings::Settings, system: sys::System) -> Result<(), Error> { +async fn system_loop(settings: settings::Settings, system: sys::System) -> Result<()> { settings .set("run-on-startup", system.is_installed()?) .await?; diff --git a/bot/src/module/gtav.rs b/bot/src/module/gtav.rs index 9e39a8f3..9fc7b8d4 100644 --- a/bot/src/module/gtav.rs +++ b/bot/src/module/gtav.rs @@ -969,7 +969,7 @@ impl command::Handler for Handler { ctx, "{} cooldown in effect, please wait at least {}!", what, - compact_duration(&remaining), + compact_duration(remaining), ); return Ok(()); diff --git a/bot/src/module/misc.rs b/bot/src/module/misc.rs index a173d007..068fcf79 100644 --- a/bot/src/module/misc.rs +++ b/bot/src/module/misc.rs @@ -42,7 +42,7 @@ impl command::Handler for Uptime { // NB: very important to check that _now_ is after started at. Some(ref started_at) if now > *started_at => { let uptime = - utils::compact_duration(&(now - *started_at).to_std().unwrap_or_default()); + utils::compact_duration((now - *started_at).to_std().unwrap_or_default()); respond!(ctx, "Stream has been live for {uptime}.", uptime = uptime); } diff --git a/bot/src/module/song.rs b/bot/src/module/song.rs index c6b4b4fa..a9b845f6 100644 --- a/bot/src/module/song.rs +++ b/bot/src/module/song.rs @@ -231,10 +231,10 @@ impl Handler { let duration = match duration.to_std() { Err(_) => None, - Ok(duration) => Some(utils::compact_duration(&duration)), + Ok(duration) => Some(utils::compact_duration(duration)), }; - let limit = utils::compact_duration(&limit); + let limit = utils::compact_duration(limit); let who = match who { Some(ref who) if who == user.name() => String::from(" by you"), @@ -462,8 +462,8 @@ impl command::Handler for Handler { } Some("current") => match player.current().await { Some(current) => { - let elapsed = utils::digital_duration(¤t.elapsed()); - let duration = utils::digital_duration(¤t.duration()); + let elapsed = utils::digital_duration(current.elapsed()); + let duration = utils::digital_duration(current.duration()); if let Some(name) = current.item.user.as_ref() { respond!( @@ -529,7 +529,7 @@ impl command::Handler for Handler { } } Some((when, item)) => { - let when = utils::compact_duration(&when); + let when = utils::compact_duration(when); if your { respond!( @@ -660,12 +660,12 @@ impl command::Handler for Handler { match count { 0 => ctx.respond("No songs in queue :(").await, 1 => { - let length = utils::long_duration(&duration); + let length = utils::long_duration(duration); ctx.respond(format!("One song in queue with {} of play time.", length)) .await; } count => { - let length = utils::long_duration(&duration); + let length = utils::long_duration(duration); ctx.respond(format!( "{} songs in queue with {} of play time.", count, length diff --git a/bot/src/player/song.rs b/bot/src/player/song.rs index 81b96ac2..d61ddefc 100644 --- a/bot/src/player/song.rs +++ b/bot/src/player/song.rs @@ -145,8 +145,8 @@ impl Song { name: self.item.track.name(), artists, user: self.item.user.as_deref(), - duration: utils::digital_duration(&self.item.duration), - elapsed: utils::digital_duration(&self.elapsed()), + duration: utils::digital_duration(self.item.duration), + elapsed: utils::digital_duration(self.elapsed()), }) } diff --git a/bot/src/sys/mod.rs b/bot/src/sys/mod.rs index f98addf4..ababd797 100644 --- a/bot/src/sys/mod.rs +++ b/bot/src/sys/mod.rs @@ -2,12 +2,12 @@ use anyhow::Error; use std::fmt; use std::time::Duration; -#[cfg(target_os = "windows")] -#[path = "windows.rs"] -mod imp; #[cfg(not(target_os = "windows"))] #[path = "noop.rs"] mod imp; +#[cfg(target_os = "windows")] +#[path = "windows/mod.rs"] +mod imp; #[derive(Debug, Clone, Copy)] pub enum NotificationIcon { diff --git a/bot/src/sys/noop.rs b/bot/src/sys/noop.rs index fbdc1c05..f759ec40 100644 --- a/bot/src/sys/noop.rs +++ b/bot/src/sys/noop.rs @@ -1,17 +1,17 @@ use crate::sys::Notification; use anyhow::Error; -use futures::{channel::oneshot, future}; +use futures::future; use std::path::Path; #[derive(Clone)] pub struct System; impl System { - pub async fn wait_for_shutdown(&self) -> Result<(), oneshot::Canceled> { + pub async fn wait_for_shutdown(&self) { future::pending().await } - pub async fn wait_for_restart(&self) -> Result<(), oneshot::Canceled> { + pub async fn wait_for_restart(&self) { future::pending().await } @@ -21,10 +21,6 @@ impl System { pub fn notification(&self, _: Notification) {} - pub fn is_running(&self) -> bool { - true - } - pub fn join(&self) -> Result<(), Error> { Ok(()) } diff --git a/bot/src/sys/windows.rs b/bot/src/sys/windows/mod.rs similarity index 75% rename from bot/src/sys/windows.rs rename to bot/src/sys/windows/mod.rs index aa90fd39..254cc90a 100644 --- a/bot/src/sys/windows.rs +++ b/bot/src/sys/windows/mod.rs @@ -7,20 +7,18 @@ use std::collections::VecDeque; use std::io; use std::path::Path; use std::ptr; -use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; use std::thread; -use winapi::um::{shellapi, winuser::SW_SHOW}; +use tokio::sync::broadcast; +use winapi::um::shellapi::ShellExecuteW; +use winapi::um::winuser::SW_SHOW; -#[path = "windows/convert.rs"] mod convert; -#[path = "windows/registry.rs"] mod registry; -#[path = "windows/window.rs"] mod window; -const ICON: &[u8] = include_bytes!("../../res/icon.ico"); -const ICON_ERROR: &[u8] = include_bytes!("../../res/icon-error.ico"); +const ICON: &[u8] = include_bytes!("../../../res/icon.ico"); +const ICON_ERROR: &[u8] = include_bytes!("../../../res/icon-error.ico"); #[derive(Debug)] pub enum Event { @@ -32,28 +30,20 @@ pub enum Event { #[derive(Clone)] pub struct System { thread: Arc>>>, - shutdown_senders: Arc>>>, - restart_senders: Arc>>>, + shutdown: broadcast::Sender<()>, + restart: broadcast::Sender<()>, events: mpsc::UnboundedSender, - stopped: Arc, } impl System { /// Wait for system shutdown signal. - pub async fn wait_for_shutdown(&self) -> Result<(), oneshot::Canceled> { - let (tx, rx) = oneshot::channel(); - self.shutdown_senders.lock().push(tx); - rx.await?; - self.stopped.store(true, Ordering::SeqCst); - Ok(()) + pub async fn wait_for_shutdown(&self) { + let _ = self.shutdown.subscribe().recv().await; } /// Wait for system restart signal. - pub async fn wait_for_restart(&self) -> Result<(), oneshot::Canceled> { - let (tx, rx) = oneshot::channel(); - self.restart_senders.lock().push(tx); - rx.await?; - Ok(()) + pub async fn wait_for_restart(&self) { + let _ = self.restart.subscribe().recv().await; } /// Clear the current state. @@ -77,16 +67,10 @@ impl System { } } - /// Test if system is running. - pub fn is_running(&self) -> bool { - // NB: this side effect is a bit unintuitive, but we know that is_running will only be called by the main loop - // when the bot core has been shutdown, and any futures that have called wait_for_shutdown have been dropped. - self.shutdown_senders.lock().clear(); - !self.stopped.load(Ordering::SeqCst) - } - /// Join the current thread. pub fn join(&self) -> Result<(), Error> { + let _ = self.shutdown.send(()); + if let Some(thread) = self.thread.lock().take() { if thread.join().is_err() { bail!("thread panicked"); @@ -148,7 +132,7 @@ fn open_dir(path: &Path) -> io::Result { let operation = "open".to_wide_null(); let result = unsafe { - shellapi::ShellExecuteW( + ShellExecuteW( ptr::null_mut(), operation.as_ptr(), path.as_ptr(), @@ -166,12 +150,12 @@ pub fn setup(root: &Path, log_file: &Path) -> Result { let log_file = log_file.to_owned(); // all senders to notify when we are requesting a restart. - let restart_senders = Arc::new(Mutex::new(Vec::>::new())); - let restart_senders1 = restart_senders.clone(); + let (restart, _) = broadcast::channel(1); + let restart1 = restart.clone(); // all senders to notify when we are shutting down. - let shutdown_senders = Arc::new(Mutex::new(Vec::>::new())); - let shutdown_senders1 = shutdown_senders.clone(); + let (shutdown, mut shutdown_rx) = broadcast::channel(1); + let shutdown1 = shutdown.clone(); let (events, mut events_rx) = mpsc::unbounded::(); @@ -191,7 +175,10 @@ pub fn setup(root: &Path, log_file: &Path) -> Result { let mut notification_on_click = VecDeque::new(); loop { - futures::select! { + tokio::select! { + _ = shutdown_rx.recv() => { + window.quit(); + } event = events_rx.select_next_some() => { log::trace!("Event: {:?}", event); @@ -224,16 +211,11 @@ pub fn setup(root: &Path, log_file: &Path) -> Result { let _ = open_dir(&root)?; } 4 => { - for tx in restart_senders1.lock().drain(..) { - let _ = tx.send(()); - } + let _ = restart1.send(()); } 6 => { window.quit(); - - for tx in shutdown_senders1.lock().drain(..) { - let _ = tx.send(()); - } + let _ = shutdown1.send(()); } _ => (), }, @@ -253,10 +235,7 @@ pub fn setup(root: &Path, log_file: &Path) -> Result { } } - for tx in shutdown_senders1.lock().drain(..) { - let _ = tx.send(()); - } - + let _ = shutdown1.send(()); Ok::<_, Error>(()) }; @@ -269,10 +248,9 @@ pub fn setup(root: &Path, log_file: &Path) -> Result { let system = System { thread: Arc::new(Mutex::new(Some(thread))), - shutdown_senders, - restart_senders, + shutdown, + restart, events, - stopped: Arc::new(AtomicBool::new(false)), }; Ok(system) diff --git a/bot/src/utils/duration.rs b/bot/src/utils/duration.rs index ff2ec6bf..b2adb2e7 100644 --- a/bot/src/utils/duration.rs +++ b/bot/src/utils/duration.rs @@ -50,7 +50,7 @@ impl Duration { pub fn as_digital(&self) -> String { let mut parts = Vec::new(); - let p = utils::partition(&time::Duration::from_secs(self.0)); + let p = utils::partition(time::Duration::from_secs(self.0)); parts.extend(match p.days { 0 => None, diff --git a/bot/src/utils/mod.rs b/bot/src/utils/mod.rs index e87750dc..070aea28 100644 --- a/bot/src/utils/mod.rs +++ b/bot/src/utils/mod.rs @@ -327,7 +327,7 @@ struct DurationParts { /// Partition the given duration into time components. #[inline(always)] -fn partition(duration: &time::Duration) -> DurationParts { +fn partition(duration: time::Duration) -> DurationParts { let rest = duration.as_millis() as u64; let days = rest / (3600 * 24 * 1000); @@ -378,7 +378,7 @@ impl fmt::Display for Percentage { } /// Format the given number of seconds as a compact human time. -pub fn compact_duration(duration: &time::Duration) -> String { +pub fn compact_duration(duration: time::Duration) -> String { let mut parts = Vec::new(); let p = partition(duration); @@ -415,7 +415,7 @@ pub fn compact_duration(duration: &time::Duration) -> String { } /// Format the given number of seconds as a long human time. -pub fn long_duration(duration: &time::Duration) -> String { +pub fn long_duration(duration: time::Duration) -> String { let mut parts = Vec::new(); let p = partition(duration); @@ -446,7 +446,7 @@ pub fn long_duration(duration: &time::Duration) -> String { } /// Format the given number of seconds as a digital duration. -pub fn digital_duration(duration: &time::Duration) -> String { +pub fn digital_duration(duration: time::Duration) -> String { let mut parts = Vec::new(); let p = partition(duration); @@ -738,8 +738,8 @@ pub struct PtDuration(time::Duration); impl PtDuration { /// Access the inner duration. - pub fn as_std(&self) -> &time::Duration { - &self.0 + pub fn as_std(&self) -> time::Duration { + self.0 } /// Convert into inner duration. @@ -801,7 +801,7 @@ impl std::str::FromStr for PtDuration { impl fmt::Display for PtDuration { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let p = partition(&self.0); + let p = partition(self.0); write!(fmt, "PT")?;