Feature Changes

Added a Token Credential Manager - Closes #4
Added TUI Menu - Closes #2
This commit is contained in:
brotoskyj
2026-01-16 10:26:17 -05:00
parent 6169e6065d
commit ff9a46c05c
6 changed files with 160 additions and 31 deletions
Generated
+69 -1
View File
@@ -4,8 +4,10 @@ version = 4
[[package]] [[package]]
name = "RhythmWorks" name = "RhythmWorks"
version = "0.4.0" version = "0.5.0"
dependencies = [ dependencies = [
"dialoguer",
"keyring",
"opentelemetry 0.27.1", "opentelemetry 0.27.1",
"opentelemetry-otlp", "opentelemetry-otlp",
"opentelemetry-proto", "opentelemetry-proto",
@@ -444,6 +446,19 @@ dependencies = [
"crossbeam-utils", "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]] [[package]]
name = "const-oid" name = "const-oid"
version = "0.9.6" version = "0.9.6"
@@ -777,6 +792,18 @@ dependencies = [
"syn 2.0.111", "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]] [[package]]
name = "digest" name = "digest"
version = "0.10.7" version = "0.10.7"
@@ -831,6 +858,12 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "encode_unicode"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
[[package]] [[package]]
name = "encoding_rs" name = "encoding_rs"
version = "0.8.33" version = "0.8.33"
@@ -1655,6 +1688,19 @@ dependencies = [
"wasm-bindgen", "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]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "1.5.0" version = "1.5.0"
@@ -1719,6 +1765,16 @@ dependencies = [
"zlib-rs", "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]] [[package]]
name = "linux-raw-sys" name = "linux-raw-sys"
version = "0.11.0" version = "0.11.0"
@@ -3239,6 +3295,12 @@ dependencies = [
"lazy_static", "lazy_static",
] ]
[[package]]
name = "shell-words"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77"
[[package]] [[package]]
name = "shlex" name = "shlex"
version = "1.3.0" version = "1.3.0"
@@ -4590,6 +4652,12 @@ version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
[[package]]
name = "unicode-width"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
[[package]] [[package]]
name = "universal-hash" name = "universal-hash"
version = "0.5.1" version = "0.5.1"
+3 -1
View File
@@ -1,9 +1,11 @@
[package] [package]
name = "RhythmWorks" name = "RhythmWorks"
version = "0.4.0" version = "0.5.0"
edition = "2024" edition = "2024"
[dependencies] [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 = { 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-otlp = { version = "0.27.0", features = ["trace", "metrics", "grpc-tonic", "http-proto", "tls", "reqwest-client", "reqwest-rustls"] }
opentelemetry-proto = "0.27.0" opentelemetry-proto = "0.27.0"
+49 -27
View File
@@ -1,14 +1,13 @@
use dialoguer::Select;
use dialoguer::theme::ColorfulTheme;
use modules::*; use modules::*;
use opentelemetry::KeyValue; use opentelemetry::KeyValue;
use opentelemetry::global; use opentelemetry::global;
use opentelemetry::global::ObjectSafeSpan;
use opentelemetry::trace::SpanKind;
use opentelemetry::trace::Status; use opentelemetry::trace::Status;
use opentelemetry::trace::TraceContextExt; use opentelemetry::trace::TraceContextExt;
use opentelemetry::trace::Tracer; use opentelemetry::trace::Tracer;
use serenity::all::ChannelId; use serenity::all::ChannelId;
use serenity::async_trait; use serenity::async_trait;
use serenity::futures::channel::oneshot::channel;
use serenity::model::channel::Message; use serenity::model::channel::Message;
use serenity::model::gateway::Ready; use serenity::model::gateway::Ready;
use serenity::prelude::*; use serenity::prelude::*;
@@ -16,7 +15,7 @@ use songbird::SerenityInit;
use songbird::get; use songbird::get;
use songbird::input::HlsRequest; use songbird::input::HlsRequest;
use songbird::input::Input; use songbird::input::Input;
use std::io; use std::env;
use std::process::Command; use std::process::Command;
use std::process::Stdio; use std::process::Stdio;
pub mod modules; pub mod modules;
@@ -82,7 +81,7 @@ impl EventHandler for Handler {
cx.span() cx.span()
.set_status(opentelemetry::trace::Status::error(format!( .set_status(opentelemetry::trace::Status::error(format!(
"{} not in Voice Channel", "{} not in Voice Channel",
msg.author.to_string() msg.author
))); )));
let _ = msg let _ = msg
.channel_id .channel_id
@@ -173,7 +172,7 @@ impl EventHandler for Handler {
cx.span() cx.span()
.set_status(opentelemetry::trace::Status::error(format!( .set_status(opentelemetry::trace::Status::error(format!(
"{} not in Voice Channel", "{} not in Voice Channel",
msg.author.to_string() msg.author
))); )));
let _ = msg let _ = msg
.channel_id .channel_id
@@ -215,10 +214,16 @@ impl EventHandler for Handler {
let _ = call.enqueue_input(input).await; let _ = call.enqueue_input(input).await;
let position = call.queue().len(); let position = call.queue().len();
let response = if position == 1 { 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() "🎶 Now playing!".to_string()
} else { } 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) format!("🎶 Added Song to Queue: #{}", position)
}; };
let _ = msg.channel_id.say(&ctx.http, response).await; 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()); global::set_tracer_provider(tracer_provider.clone());
let tracer: global::BoxedTracer = global::tracer("tracer"); let tracer: global::BoxedTracer = global::tracer("tracer");
tracer tracer
.in_span("Checking for Updates", |cx| updator::update()) .in_span("Checking for Updates", |_cx| updator::update())
.await; .await;
println!("Please paste in your bot token"); let service_name = "RhythmWorks";
let mut input = String::new(); let username = env::var("USER").or_else(|_| env::var("USERNAME")).unwrap();
io::stdin() loop {
.read_line(&mut input) let token = credentialmanager::get_token(service_name, &username);
.expect("Failed to read line"); let options: Vec<&'static str> = vec!["- Start Bot", "- Change Token", "- Delete Token"];
let token = input.trim(); let selection = Select::with_theme(&ColorfulTheme::default())
let intents = GatewayIntents::GUILD_MESSAGES .with_prompt("Choose an Option")
| GatewayIntents::GUILDS .default(0)
| GatewayIntents::DIRECT_MESSAGES .items(&options)
| GatewayIntents::MESSAGE_CONTENT .interact()
| GatewayIntents::GUILD_VOICE_STATES; .unwrap();
let mut client = Client::builder(&token, intents) match selection {
.event_handler(Handler) 0 => {
.register_songbird() let intents = GatewayIntents::GUILD_MESSAGES
.await | GatewayIntents::GUILDS
.expect("Err creating client"); | GatewayIntents::DIRECT_MESSAGES
if let Err(why) = client.start().await { | GatewayIntents::MESSAGE_CONTENT
println!("Client error: {why:?}"); | 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"),
}
} }
} }
+37
View File
@@ -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();
}
+2 -1
View File
@@ -1,2 +1,3 @@
pub mod credentialmanager;
pub mod telemetry;
pub mod updator; pub mod updator;
pub mod telemetry;
-1
View File
@@ -25,6 +25,5 @@ pub async fn update() {
println!("URL: https://git.racooncity.org/brotoskyj/RhythmWorks/releases"); println!("URL: https://git.racooncity.org/brotoskyj/RhythmWorks/releases");
thread::sleep(std::time::Duration::from_secs(10)); thread::sleep(std::time::Duration::from_secs(10));
std::process::exit(1); std::process::exit(1);
} else {
} }
} }