diff --git a/Cargo.lock b/Cargo.lock index 61606e8..a87df28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,8 +4,10 @@ version = 4 [[package]] name = "RhythmWorks" -version = "0.4.0" +version = "0.5.0" dependencies = [ + "dialoguer", + "keyring", "opentelemetry 0.27.1", "opentelemetry-otlp", "opentelemetry-proto", @@ -444,6 +446,19 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "console" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03e45a4a8926227e4197636ba97a9fc9b00477e9f4bd711395687c5f0734bec4" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "unicode-width", + "windows-sys 0.61.2", +] + [[package]] name = "const-oid" version = "0.9.6" @@ -777,6 +792,18 @@ dependencies = [ "syn 2.0.111", ] +[[package]] +name = "dialoguer" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25f104b501bf2364e78d0d3974cbc774f738f5865306ed128e1e0d7499c0ad96" +dependencies = [ + "console", + "shell-words", + "tempfile", + "zeroize", +] + [[package]] name = "digest" version = "0.10.7" @@ -831,6 +858,12 @@ dependencies = [ "serde", ] +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + [[package]] name = "encoding_rs" version = "0.8.33" @@ -1655,6 +1688,19 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "keyring" +version = "3.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eebcc3aff044e5944a8fbaf69eb277d11986064cba30c468730e8b9909fb551c" +dependencies = [ + "byteorder", + "linux-keyutils", + "log", + "windows-sys 0.60.2", + "zeroize", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -1719,6 +1765,16 @@ dependencies = [ "zlib-rs", ] +[[package]] +name = "linux-keyutils" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "761e49ec5fd8a5a463f9b84e877c373d888935b71c6be78f3767fe2ae6bed18e" +dependencies = [ + "bitflags 2.10.0", + "libc", +] + [[package]] name = "linux-raw-sys" version = "0.11.0" @@ -3239,6 +3295,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shell-words" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77" + [[package]] name = "shlex" version = "1.3.0" @@ -4590,6 +4652,12 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + [[package]] name = "universal-hash" version = "0.5.1" diff --git a/Cargo.toml b/Cargo.toml index dc94c5e..5dd8958 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,9 +1,11 @@ [package] name = "RhythmWorks" -version = "0.4.0" +version = "0.5.0" edition = "2024" [dependencies] +dialoguer = "0.12.0" +keyring = { version = "3.6.3", features = ["linux-native", "windows-native"] } opentelemetry = { version = "0.27.0", features = ["logs", "metrics", "trace"] } opentelemetry-otlp = { version = "0.27.0", features = ["trace", "metrics", "grpc-tonic", "http-proto", "tls", "reqwest-client", "reqwest-rustls"] } opentelemetry-proto = "0.27.0" diff --git a/src/main.rs b/src/main.rs index 2e6ea23..cc53b6e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,14 +1,13 @@ +use dialoguer::Select; +use dialoguer::theme::ColorfulTheme; use modules::*; use opentelemetry::KeyValue; use opentelemetry::global; -use opentelemetry::global::ObjectSafeSpan; -use opentelemetry::trace::SpanKind; use opentelemetry::trace::Status; use opentelemetry::trace::TraceContextExt; use opentelemetry::trace::Tracer; use serenity::all::ChannelId; use serenity::async_trait; -use serenity::futures::channel::oneshot::channel; use serenity::model::channel::Message; use serenity::model::gateway::Ready; use serenity::prelude::*; @@ -16,7 +15,7 @@ use songbird::SerenityInit; use songbird::get; use songbird::input::HlsRequest; use songbird::input::Input; -use std::io; +use std::env; use std::process::Command; use std::process::Stdio; pub mod modules; @@ -82,7 +81,7 @@ impl EventHandler for Handler { cx.span() .set_status(opentelemetry::trace::Status::error(format!( "{} not in Voice Channel", - msg.author.to_string() + msg.author ))); let _ = msg .channel_id @@ -173,7 +172,7 @@ impl EventHandler for Handler { cx.span() .set_status(opentelemetry::trace::Status::error(format!( "{} not in Voice Channel", - msg.author.to_string() + msg.author ))); let _ = msg .channel_id @@ -215,10 +214,16 @@ impl EventHandler for Handler { let _ = call.enqueue_input(input).await; let position = call.queue().len(); let response = if position == 1 { - cx.span().add_event("Starting Playback", vec![KeyValue::new("Status", "Playing".to_string())]); + cx.span().add_event( + "Starting Playback", + vec![KeyValue::new("Status", "Playing".to_string())], + ); "🎶 Now playing!".to_string() } else { - cx.span().add_event("Starting Playback", vec![KeyValue::new("Status", "Added to Queue".to_string())]); + cx.span().add_event( + "Starting Playback", + vec![KeyValue::new("Status", "Added to Queue".to_string())], + ); format!("🎶 Added Song to Queue: #{}", position) }; let _ = msg.channel_id.say(&ctx.http, response).await; @@ -285,25 +290,42 @@ This is free software, and you are welcome to redistribute it under certain cond global::set_tracer_provider(tracer_provider.clone()); let tracer: global::BoxedTracer = global::tracer("tracer"); tracer - .in_span("Checking for Updates", |cx| updator::update()) + .in_span("Checking for Updates", |_cx| updator::update()) .await; - println!("Please paste in your bot token"); - let mut input = String::new(); - io::stdin() - .read_line(&mut input) - .expect("Failed to read line"); - let token = input.trim(); - let intents = GatewayIntents::GUILD_MESSAGES - | GatewayIntents::GUILDS - | GatewayIntents::DIRECT_MESSAGES - | GatewayIntents::MESSAGE_CONTENT - | GatewayIntents::GUILD_VOICE_STATES; - let mut client = Client::builder(&token, intents) - .event_handler(Handler) - .register_songbird() - .await - .expect("Err creating client"); - if let Err(why) = client.start().await { - println!("Client error: {why:?}"); + let service_name = "RhythmWorks"; + let username = env::var("USER").or_else(|_| env::var("USERNAME")).unwrap(); + loop { + let token = credentialmanager::get_token(service_name, &username); + let options: Vec<&'static str> = vec!["- Start Bot", "- Change Token", "- Delete Token"]; + let selection = Select::with_theme(&ColorfulTheme::default()) + .with_prompt("Choose an Option") + .default(0) + .items(&options) + .interact() + .unwrap(); + match selection { + 0 => { + let intents = GatewayIntents::GUILD_MESSAGES + | GatewayIntents::GUILDS + | GatewayIntents::DIRECT_MESSAGES + | GatewayIntents::MESSAGE_CONTENT + | GatewayIntents::GUILD_VOICE_STATES; + let mut client = Client::builder(&token, intents) + .event_handler(Handler) + .register_songbird() + .await + .expect("Err creating client"); + if let Err(why) = client.start().await { + println!("Client error: {why:?}"); + } + } + 1 => { + credentialmanager::change_token(service_name, &username); + } + 2 => { + credentialmanager::remove_token(service_name, &username); + } + _ => println!("Invalid Option"), + } } } diff --git a/src/modules/credentialmanager.rs b/src/modules/credentialmanager.rs new file mode 100644 index 0000000..aff1338 --- /dev/null +++ b/src/modules/credentialmanager.rs @@ -0,0 +1,37 @@ +use dialoguer::{Input, theme::ColorfulTheme}; +use keyring::Entry; + +pub fn get_token<'a>(service: &str, username: &str) -> String { + let entry = Entry::new(service, username).expect("Failed to get keyring entry"); + match entry.get_password() { + Ok(token) => token, + Err(_) => { + let token: String = Input::with_theme(&ColorfulTheme::default()) + .with_prompt("Enter your bot token") + .interact_text() + .unwrap(); + match entry.set_password(&token) { + Ok(_) => {} + Err(e) => { + println!("Failed to set token: {}", e); + std::process::abort() + } + }; + token + } + } +} + +pub fn change_token(service: &str, username: &str) { + let entry = Entry::new(service, username).expect("Failed to get keyring entry"); + let new_token: String = Input::with_theme(&ColorfulTheme::default()) + .with_prompt("New Token") + .interact_text() + .unwrap(); + let _ = entry.set_password(&new_token); +} + +pub fn remove_token(service: &str, username: &str) { + let entry = Entry::new(service, username).expect("Failed to get keyring entry"); + let _ = entry.delete_credential(); +} diff --git a/src/modules/mod.rs b/src/modules/mod.rs index 4ebc0e2..1aa5581 100644 --- a/src/modules/mod.rs +++ b/src/modules/mod.rs @@ -1,2 +1,3 @@ +pub mod credentialmanager; +pub mod telemetry; pub mod updator; -pub mod telemetry; \ No newline at end of file diff --git a/src/modules/updator.rs b/src/modules/updator.rs index 4ebc644..ae5a1e5 100644 --- a/src/modules/updator.rs +++ b/src/modules/updator.rs @@ -25,6 +25,5 @@ pub async fn update() { println!("URL: https://git.racooncity.org/brotoskyj/RhythmWorks/releases"); thread::sleep(std::time::Duration::from_secs(10)); std::process::exit(1); - } else { } }