diff --git a/README.md b/README.md index 6ddd3df..8fc4444 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,6 @@ An automation tool primarily made for myself (Byte Dice) but publicly available > [!CAUTION] > This tool is not intended for public use outside of the official *Byte Dice Assistant* bots. Expect issues if you host this yourself.\ -> This tool is only designed to run on Windows (10 and 11) and XUbuntu (24.04 and above) and may not work on any other OS. > [!NOTE] > This bot never modifies any Reddit content. All it does and will ever do is read/scrape. @@ -16,6 +15,21 @@ An automation tool primarily made for myself (Byte Dice) but publicly available **ByteDiceAssistant © 2025 by Byte Dice is licensed under CC BY-NC-SA 4.0.**\ **You can learn more about copyright by reading the full [license](/LICENSE.txt).** +## Environment variables: +(Any Reddit stuff can be disabled.) + +| **Name** | **Description** | +| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `ASSISTANT_TOKEN` | The Discord bot token. (Create a Discord bot [here](https://discord.com/developers/docs/intro)!) | +| `ASSISTANT_TOKEN_TEST` | (Optional) A testing Discord bot token. This is only needed when the program is run with `-t` or `--test`. | +| `ASSISTANT_R_ID` | The id for the Reddit bot/account. (Create a Reddit bot [here](https://www.reddit.com/prefs/apps)!) | +| `ASSISTANT_R_TOKEN` | The token for the Reddit bot/account. | +| `ASSISTANT_R_NAME` | The username of the Reddit bot/account. | +| `ASSISTANT_R_PASS` | The password for the Reddit bot/account. | +| `ASSISTANT_OWNERS` | (OPTIONAL) A list of Discord user IDs that "own" the bot. Separate each ID with a single comma and **no** spaces. This will allow the specified user IDs to run root commands such as `/stop`, it will also DM these users when *certain* errors occur. | +| `ASSISTANT_BK_MODS` | (OPTIONAL) Same format as `ASSISTANT_OWNERS` but for people who are allowed to use the `/re_*` commands. | + + \ No newline at end of file diff --git a/src/cmds/db/main_cmd.rs b/src/cmds/db/main_cmd.rs index 92d49dd..0b5338a 100644 --- a/src/cmds/db/main_cmd.rs +++ b/src/cmds/db/main_cmd.rs @@ -1,4 +1,4 @@ -use crate::{Context, Error, db_cmds::{add_server, reddit_channel, wwrps_channel}}; +use crate::{Context, Error, cmds::db::{add_server, reddit_channel, wwrps_channel}}; #[derive(poise::ChoiceParameter, PartialEq)] diff --git a/src/cmds/generic/eight_ball.rs b/src/cmds/generic/eight_ball.rs index 653d261..bc2b1aa 100644 --- a/src/cmds/generic/eight_ball.rs +++ b/src/cmds/generic/eight_ball.rs @@ -1,6 +1,6 @@ use rand::{seq::IteratorRandom, Rng}; -use crate::{db::generic::get_toml_mutex, lang, messages::send_msg, Context, Error}; +use crate::{lang, messages::send_msg, Context, Error}; #[poise::command( @@ -16,7 +16,9 @@ pub async fn cmd( #[description = "Question to ask."] question: String ) -> Result<(), Error> { - let quirky_chance = get_toml_mutex(&ctx.data().cfg).await.unwrap()["commands"]["eight_ball_quirky_chance"].as_float().unwrap(); + let quirky_chance = &ctx.data().cfg + ["commands"]["eight_ball_quirky_chance"] + .as_float().unwrap(); let is_quirky = rand::rng().random_bool(quirky_chance.clamp(0.0, 1.0)); let list = &ctx.data().ball_prompts[if is_quirky { 1 } else { 0 }]; let rand_item = list.iter().choose(&mut rand::rng()); diff --git a/src/cmds/generic/wwrps.rs b/src/cmds/generic/wwrps.rs index 48dd4de..c6c5d91 100644 --- a/src/cmds/generic/wwrps.rs +++ b/src/cmds/generic/wwrps.rs @@ -1,7 +1,7 @@ use poise::serenity_prelude::{ChannelId, Mentionable}; use tokio::sync::MutexGuard; -use crate::{Context, Error, db::generic::get_json_mutex, games::wwrps::{RPS, RPSGame, RPSPlayer}, lang, messages::{http_send_msg, send_msg}}; +use crate::{Context, Error, games::wwrps::{RPS, RPSGame, RPSPlayer}, lang, messages::{http_send_msg, send_msg}}; #[poise::command( @@ -75,7 +75,7 @@ fn results_text(game: &MutexGuard<'_, RPSGame>) -> String { async fn get_wwrps_channel(ctx: Context<'_>) -> Option { - let d = get_json_mutex(&ctx.data().discord_data).await.unwrap(); + let d = &ctx.data().discord_data.lock().await; let is_guild = ctx.guild_channel().await.is_some(); diff --git a/src/cmds/reddit/add.rs b/src/cmds/reddit/add.rs index e0dcacc..cc8e04c 100644 --- a/src/cmds/reddit/add.rs +++ b/src/cmds/reddit/add.rs @@ -1,11 +1,10 @@ use serde_json::json; -use crate::db::generic::get_json_mutex; use crate::db::reddit::{self, POSTS_KEY}; use crate::messages::send_msg; -use crate::re_cmds::get::get_post_from_data; +use crate::cmds::reddit::get::get_post_from_data; use crate::{websocket::send_cmd_json, Context, Error}; -use crate::re_cmds::generic_fns::{is_bk_mod_msg, send_embed_for_post, to_shorturl}; +use crate::cmds::reddit::generic_fns::{is_bk_mod_msg, send_embed_for_post, to_shorturl}; use crate::lang; #[poise::command( @@ -42,8 +41,8 @@ pub async fn cmd( return Ok(()); } - reddit::update_data(ctx.data()).await; - let reddit_data = get_json_mutex(&ctx.data().reddit_data).await?; + reddit::update_data().await; + let reddit_data = &ctx.data().reddit_data.lock().await; if let Some(bk_week) = reddit_data.get(POSTS_KEY) { if let Some(post) = bk_week.get(shorturl) { diff --git a/src/cmds/reddit/approve.rs b/src/cmds/reddit/approve.rs index 03c141a..1f4c76e 100644 --- a/src/cmds/reddit/approve.rs +++ b/src/cmds/reddit/approve.rs @@ -1,6 +1,6 @@ use serde_json::{json, Value}; -use crate::{Context, Error, db::{generic::get_json_mutex, reddit::{self, POSTS_KEY}}, lang, messages::send_msg, re_cmds::generic_fns::{is_bk_mod_msg, to_shorturl}, websocket}; +use crate::{Context, Error, db::{reddit::POSTS_KEY}, lang, messages::send_msg, cmds::reddit::generic_fns::{is_bk_mod_msg, to_shorturl}, websocket}; use super::generic_fns::send_embed_for_removed; @@ -23,8 +23,7 @@ pub async fn cmd( let shorturl_u = to_shorturl(&url); let shorturl = &shorturl_u.unwrap_or(url.clone()); - reddit::update_data(ctx.data()).await; - let reddit_data = get_json_mutex(&ctx.data().reddit_data).await?; + let reddit_data = &ctx.data().reddit_data.lock().await; approve_cmd(ctx, shorturl, &reddit_data, !disapprove.unwrap_or(false)).await; diff --git a/src/cmds/reddit/generic_fns.rs b/src/cmds/reddit/generic_fns.rs index c37c2a4..46860d7 100644 --- a/src/cmds/reddit/generic_fns.rs +++ b/src/cmds/reddit/generic_fns.rs @@ -2,7 +2,7 @@ use poise::serenity_prelude::{self as serenity, ChannelId, ComponentInteraction, use regex::Regex; use serde_json::Value; -use crate::{Context, Data, Error, db::generic::get_toml_mutex, lang, messages::{EmbedOptions, JSON_TEXT_END, JSON_TEXT_START, decode_and_decompress_json, embed_from_options, make_post_embed, make_removed_embed, send_embed, send_msg}}; +use crate::{Context, Data, Error, lang, messages::{EmbedOptions, JSON_TEXT_END, JSON_TEXT_START, decode_and_decompress_json, embed_from_options, make_post_embed, make_removed_embed, send_embed, send_msg}}; pub fn is_bk_mod(mod_list: Vec, uid: u64) -> bool { return mod_list.contains(&uid); @@ -10,7 +10,7 @@ pub fn is_bk_mod(mod_list: Vec, uid: u64) -> bool { pub async fn is_bk_mod_msg(ctx: Context<'_>) -> bool { - if is_bk_mod(ctx.data().bk_mods.clone(), ctx.author().id.get()) { return true; } + if is_bk_mod(ctx.data().env_vars.reddit_mod_discord_ids.clone(), ctx.author().id.get()) { return true; } let sr = get_readable_subreddits(ctx.data()).await.unwrap(); send_msg(ctx, lang!("dc_msg_re_permdeny_not_re_mod", sr), true, true).await; @@ -19,7 +19,7 @@ pub async fn is_bk_mod_msg(ctx: Context<'_>) -> bool { pub async fn is_bk_mod_serenity(ctx: &serenity::Context, data: &Data, author: &Member, component: &ComponentInteraction) -> bool { - if is_bk_mod(data.bk_mods.clone(), author.user.id.get()) { return true; } + if is_bk_mod(data.env_vars.reddit_mod_discord_ids.clone(), author.user.id.get()) { return true; } let sr = get_readable_subreddits(data).await.unwrap(); serenity_send_msg(ctx, component, lang!("dc_msg_re_permdeny_not_re_mod", sr), true).await; @@ -70,8 +70,7 @@ pub async fn send_embed_for_removed(ctx: Context<'_>, url: &str, post: &Value) { pub async fn get_readable_subreddits(data: &Data) -> Result { - let d = get_toml_mutex(&data.cfg).await.unwrap(); - let sr = d["reddit"]["subreddits"].as_array().unwrap(); + let sr = data.cfg["reddit"]["subreddits"].as_array().unwrap(); let sr_str: Vec<&str> = sr .iter() .map(|v| v.as_str().unwrap()) diff --git a/src/cmds/reddit/get.rs b/src/cmds/reddit/get.rs index edfb150..6112869 100644 --- a/src/cmds/reddit/get.rs +++ b/src/cmds/reddit/get.rs @@ -1,6 +1,6 @@ use serde_json::Value; -use crate::{Context, Error, db::{generic::get_json_mutex, reddit::{self, POSTS_KEY}}, lang, messages::send_msg, re_cmds::generic_fns::{send_embed_for_post, to_shorturl}, rs_println}; +use crate::{Context, Error, db::{reddit::{self, POSTS_KEY}}, lang, messages::send_msg, cmds::reddit::generic_fns::{send_embed_for_post, to_shorturl}, rs_println}; use super::generic_fns::send_embed_for_removed; @@ -17,12 +17,12 @@ pub async fn cmd( #[description = "The post URL."] url: String ) -> Result<(), Error> { - reddit::update_data(ctx.data()).await; + reddit::update_data().await; let shorturl_u = to_shorturl(&url); let shorturl = &shorturl_u.unwrap_or(url.clone()); - let reddit_data = get_json_mutex(&ctx.data().reddit_data).await?; + let reddit_data = &ctx.data().reddit_data.lock().await; if let Some(post) = get_post_from_data(ctx, &reddit_data, shorturl).await? { send_embed_for_post(ctx, post, shorturl).await?; diff --git a/src/cmds/reddit/remove.rs b/src/cmds/reddit/remove.rs index 82bd5cf..7e1f89e 100644 --- a/src/cmds/reddit/remove.rs +++ b/src/cmds/reddit/remove.rs @@ -1,6 +1,6 @@ use serde_json::json; -use crate::{Context, Error, db::{generic::get_json_mutex, reddit}, lang, messages::send_msg, re_cmds::{generic_fns::{is_bk_mod_msg, send_embed_for_removed, to_shorturl}, get::get_post_from_data}, websocket::send_cmd_json}; +use crate::{Context, Error, db::reddit, lang, messages::send_msg, cmds::reddit::{generic_fns::{is_bk_mod_msg, send_embed_for_removed, to_shorturl}, get::get_post_from_data}, websocket::send_cmd_json}; #[poise::command( slash_command, @@ -36,8 +36,8 @@ pub async fn cmd( send_msg(ctx, lang!("dc_msg_re_post_404"), true, true).await; } - reddit::update_data(ctx.data()).await; - let reddit_data = get_json_mutex(&ctx.data().reddit_data).await?; + reddit::update_data().await; + let reddit_data = &ctx.data().reddit_data.lock().await; if let Some(post) = get_post_from_data(ctx, &reddit_data, shorturl).await? { if post["removed"]["removed"].as_bool().unwrap() { diff --git a/src/cmds/reddit/shorturl.rs b/src/cmds/reddit/shorturl.rs index a30f50d..4593f76 100644 --- a/src/cmds/reddit/shorturl.rs +++ b/src/cmds/reddit/shorturl.rs @@ -1,4 +1,4 @@ -use crate::{lang, messages::send_msg, re_cmds::generic_fns::to_shorturl, Context, Error}; +use crate::{lang, messages::send_msg, cmds::reddit::generic_fns::to_shorturl, Context, Error}; #[poise::command( diff --git a/src/cmds/reddit/top.rs b/src/cmds/reddit/top.rs index 6905f26..6a4591f 100644 --- a/src/cmds/reddit/top.rs +++ b/src/cmds/reddit/top.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use crate::{Context, Error, db::{generic::get_json_mutex, reddit::POSTS_KEY}, re_cmds::generic_fns::send_embed_for_post}; +use crate::{Context, Error, db::reddit::POSTS_KEY, cmds::reddit::generic_fns::send_embed_for_post}; #[derive(poise::ChoiceParameter, PartialEq)] enum TopCategory { @@ -30,7 +30,7 @@ pub async fn cmd( ) -> Result<(), Error> { let mut all: HashMap<&str, i32> = HashMap::new(); - let posts = &get_json_mutex(&ctx.data().reddit_data).await?[POSTS_KEY]; + let posts = &ctx.data().reddit_data.lock().await[POSTS_KEY]; let posts_u = posts.as_object().unwrap(); for (url, dat) in posts_u { diff --git a/src/cmds/reddit/update.rs b/src/cmds/reddit/update.rs index cfaa591..4e79c64 100644 --- a/src/cmds/reddit/update.rs +++ b/src/cmds/reddit/update.rs @@ -3,7 +3,7 @@ use std::time::{SystemTime, UNIX_EPOCH}; use poise::{serenity_prelude::{ChannelId, EditMessage, GetMessages, Http, Message, MessageId, UserId}, ReplyHandle}; use serde_json::{json, Map, Value}; -use crate::{Context, Error, db::{discord::contains_server, generic::{get_json_mutex, get_toml_mutex}, keys::DC_POSTS_CHANNEL_KEY, reddit::{self, POSTS_KEY}}, lang, messages::{edit_reply, embed_from_options, make_post_embed, make_removed_embed, send_embed, send_msg, trim_post_json}, re_cmds::generic_fns::embed_to_json, rs_println, websocket::send_cmd_json}; +use crate::{Context, Error, db::{discord::contains_server, keys::DC_POSTS_CHANNEL_KEY, reddit::{self, POSTS_KEY}}, lang, messages::{edit_reply, embed_from_options, make_post_embed, make_removed_embed, send_embed, send_msg, trim_post_json}, cmds::reddit::generic_fns::embed_to_json, rs_println, websocket::send_cmd_json}; #[poise::command( slash_command, @@ -39,13 +39,12 @@ pub async fn cmd( let max_age_u = max_age.unwrap_or(8); let max_age_secs = max_age_u as u64 * (60 * 60 * 24); - let max_results_toml = &get_toml_mutex(&ctx.data().cfg).await.unwrap(); - let max_results_pre = max_results_toml["reddit"]["fetch_limit"].as_integer().unwrap(); + let max_results_pre = ctx.data().cfg["reddit"]["fetch_limit"].as_integer().unwrap(); let max_results_final = max_results.unwrap_or(max_results_pre as u16); send_cmd_json("add_new_posts", Some(json!([max_age_secs, max_results_final])), true).await; - reddit::update_data(ctx.data()).await; - let r_data = get_json_mutex(&ctx.data().reddit_data).await?; + reddit::update_data().await; + let r_data = &ctx.data().reddit_data.lock().await; let c_id_u = get_c_id(ctx).await; @@ -118,7 +117,7 @@ async fn get_c_id(ctx: Context<'_>) -> Option { return None; } - let d = get_json_mutex(&ctx.data().discord_data).await.unwrap(); + let d = &ctx.data().discord_data.lock().await; let c_id_u = d["servers"] [ctx.guild_id().unwrap().to_string()] diff --git a/src/cmds/reddit/vote.rs b/src/cmds/reddit/vote.rs index 1af06f0..9b6d8e5 100644 --- a/src/cmds/reddit/vote.rs +++ b/src/cmds/reddit/vote.rs @@ -1,6 +1,6 @@ use serde_json::json; -use crate::{Context, Error, db::{generic::get_json_mutex, reddit::{self, POSTS_KEY}}, lang, messages::send_msg, re_cmds::generic_fns::{is_bk_mod, send_embed_for_removed, to_shorturl}, websocket::send_cmd_json}; +use crate::{Context, Error, db::reddit::{self, POSTS_KEY}, lang, messages::send_msg, cmds::reddit::generic_fns::{is_bk_mod, send_embed_for_removed, to_shorturl}, websocket::send_cmd_json}; #[poise::command( slash_command, @@ -16,9 +16,9 @@ pub async fn cmd( #[description = "Wether to undo your vote or not"] un_vote: Option ) -> Result<(), Error> { - reddit::update_data(ctx.data()).await; + reddit::update_data().await; let uid = ctx.author().id.get(); - let re_data = get_json_mutex(&ctx.data().reddit_data).await?; + let re_data = &ctx.data().reddit_data.lock().await; let post_data = re_data[POSTS_KEY].clone(); let unw_vote = un_vote.unwrap_or(false); @@ -36,7 +36,7 @@ pub async fn cmd( let url_data = &post_data[&shorturl]; - let is_mod = is_bk_mod(ctx.data().bk_mods.clone(), ctx.author().id.get()); + let is_mod = is_bk_mod(ctx.data().env_vars.reddit_mod_discord_ids.clone(), ctx.author().id.get()); let voters_dc = url_data["votes"]["voters_dc"].as_array().unwrap(); let mod_voters = url_data["votes"]["mod_voters"].as_array().unwrap(); let voters = if is_mod { mod_voters } else { voters_dc }; @@ -53,18 +53,14 @@ pub async fn cmd( let r = send_cmd_json("set_vote_post", Some(json!([shorturl, uid, is_mod, true, unw_vote])), true).await.unwrap(); let unw_r = r["value"].as_bool().unwrap(); - if unw_r && !unw_vote && is_mod { - send_msg(ctx, lang!("dc_msg_re_vote_mod_success"), true, true).await; - } - else if unw_r && !unw_vote && !is_mod { - send_msg(ctx, lang!("dc_msg_re_vote_success"), true, true).await; - } - else if unw_r && unw_vote { - send_msg(ctx, lang!("dc_msg_re_vote_remove_success"), true, true).await; - } - else { - send_msg(ctx, lang!("dc_msg_re_vote_err"), true, true).await; - } + if unw_r && !unw_vote && is_mod + { send_msg(ctx, lang!("dc_msg_re_vote_mod_success"), true, true).await; } + else if unw_r && !unw_vote && !is_mod + { send_msg(ctx, lang!("dc_msg_re_vote_success"), true, true).await; } + else if unw_r && unw_vote + { send_msg(ctx, lang!("dc_msg_re_vote_remove_success"), true, true).await; } + else + { send_msg(ctx, lang!("dc_msg_re_vote_err"), true, true).await; } return Ok(()); } \ No newline at end of file diff --git a/src/db.rs b/src/db.rs index de3b182..fedc350 100644 --- a/src/db.rs +++ b/src/db.rs @@ -1,7 +1,7 @@ pub mod bot_data; pub mod cfg; -pub mod terminal_args; pub mod discord; -pub mod generic; +pub mod env_vars; pub mod keys; -pub mod reddit; \ No newline at end of file +pub mod reddit; +pub mod terminal_args; \ No newline at end of file diff --git a/src/db/bot_data.rs b/src/db/bot_data.rs index 6b36d0c..a28a3df 100644 --- a/src/db/bot_data.rs +++ b/src/db/bot_data.rs @@ -1,18 +1,17 @@ use serde_json::Value; use tokio::sync::Mutex; -use crate::{db::terminal_args::Args, games::wwrps::RPSGame, lang::Lang}; +use crate::{db::{env_vars::AssistantEnv, terminal_args::Args}, games::wwrps::RPSGame, lang::Lang}; pub struct Data { - pub owners: Vec, - pub ball_prompts: [Vec; 2], - pub rps_game: Mutex, - pub reddit_data: Mutex>, - pub discord_data: Mutex>, - pub cfg: Mutex>, - pub bk_mods: Vec, pub args: Args, - pub lang_name: Mutex, - pub lang: Mutex + pub ball_prompts: [Vec; 2], + pub cfg: toml::Value, + pub discord_data: Mutex, + pub env_vars: AssistantEnv, + pub lang_name: String, + pub lang: Lang, + pub reddit_data: Mutex, + pub rps_game: Mutex, } \ No newline at end of file diff --git a/src/db/cfg.rs b/src/db/cfg.rs index f23085b..218768d 100644 --- a/src/db/cfg.rs +++ b/src/db/cfg.rs @@ -1,15 +1,13 @@ use std::{fs, io::Write, path::Path}; -use serde_json::{Value, json}; - -use crate::{Data, rs_println, websocket::send_cmd_json}; +use crate::rs_println; static DATA_PATH: &str = "./cfg/cfg.toml"; static PRESET_PATH: &str = "./data/defaults/cfg_default.toml"; -pub async fn read_data(data: &Data, wipe: bool) -> Option { +pub async fn read_data(wipe: bool) -> toml::Value { if !Path::new(DATA_PATH).exists() || wipe { rs_println!( "{} creating new from preset...", @@ -20,16 +18,14 @@ pub async fn read_data(data: &Data, wipe: bool) -> Option { let str_data = fs::read_to_string(DATA_PATH).unwrap(); let json_data: toml::Value = str_data.parse().unwrap(); - let mut cfg_data = data.cfg.lock().await; - *cfg_data = Some(json_data.clone()); - let r = send_cmd_json( + /*let r = send_cmd_json( "update_cfg", Some(json!([toml::to_string(&json_data).unwrap()])), true - ).await; + ).await;*/ - return r; + return json_data; } diff --git a/src/db/discord.rs b/src/db/discord.rs index 3e97f9d..762687d 100644 --- a/src/db/discord.rs +++ b/src/db/discord.rs @@ -8,7 +8,7 @@ static DATA_PATH: &str = "./data/db/dc_data.json"; static PRESET_PATH: &str = "./data/defaults/dc_data_preset.json"; -pub async fn read_data(data: &Data, wipe: bool) { +pub async fn read_data(wipe: bool) -> Value { if !Path::new(DATA_PATH).exists() || wipe { rs_println!( "{} creating new from preset...", @@ -19,8 +19,7 @@ pub async fn read_data(data: &Data, wipe: bool) { let str_data = fs::read_to_string(DATA_PATH).unwrap(); let json_data = serde_json::from_str(&str_data).unwrap(); - let mut dc_data = data.discord_data.lock().await; - *dc_data = json_data; + return json_data; } @@ -51,17 +50,15 @@ pub async fn write_data(data: &Data) { .unwrap(); - let mut dc_data_lock = data.discord_data.lock().await; - let dc_data = dc_data_lock.as_mut().unwrap(); - let json_str = serde_json::to_string_pretty(dc_data).unwrap(); + let dc_data = data.discord_data.lock().await; + let json_str = serde_json::to_string_pretty(&dc_data.clone()).unwrap(); file.write_all(json_str.as_bytes()).unwrap(); } pub async fn add_server(data: &Data, server_id: u64) -> Result<(), ()> { - let mut dc_data_lock = data.discord_data.lock().await; - let dc_data = dc_data_lock.as_mut().unwrap(); + let mut dc_data = data.discord_data.lock().await; if dc_data.get("servers").is_none() { return Err(()); } @@ -76,8 +73,7 @@ pub async fn add_server(data: &Data, server_id: u64) -> Result<(), ()> { pub async fn bind_bk(data: &Data, server_id: u64, channel_id: u64) -> Result<(), ()> { - let mut dc_data_lock = data.discord_data.lock().await; - let dc_data = dc_data_lock.as_mut().unwrap(); + let mut dc_data = data.discord_data.lock().await; if dc_data.get("servers").is_none() { return Err(()); } @@ -96,8 +92,7 @@ pub async fn bind_bk(data: &Data, server_id: u64, channel_id: u64) -> Result<(), pub async fn bind_wwrps(data: &Data, server_id: u64, channel_id: u64) -> Result<(), ()> { - let mut dc_data_lock = data.discord_data.lock().await; - let dc_data = dc_data_lock.as_mut().unwrap(); + let mut dc_data = data.discord_data.lock().await; if dc_data.get("servers").is_none() { return Err(()); } @@ -115,8 +110,7 @@ pub async fn bind_wwrps(data: &Data, server_id: u64, channel_id: u64) -> Result< pub async fn contains_server(data: &Data, server_id: u64) -> bool { - let dc_data_lock = data.discord_data.lock().await; - let dc_data = dc_data_lock.as_ref().unwrap(); + let dc_data = data.discord_data.lock().await; if dc_data.get("servers").is_none() { return false; } diff --git a/src/db/env_vars.rs b/src/db/env_vars.rs new file mode 100644 index 0000000..28ce6c9 --- /dev/null +++ b/src/db/env_vars.rs @@ -0,0 +1,38 @@ +#[derive(Clone)] +pub struct AssistantEnv { + pub token: String, + pub bot_owners: Vec, + pub reddit_mod_discord_ids: Vec +} + + +impl AssistantEnv { + pub fn new(test: bool) -> Self { + let token_name = if test { "ASSISTANT_TOKEN" } + else { "ASSISTANT_TOKEN_TEST" }; + + return AssistantEnv { + token: string_env(token_name), + bot_owners: vec_u64_env("ASSISTANT_OWNERS"), + reddit_mod_discord_ids: vec_u64_env("ASSISTANT_BK_MODS") + }; + } +} + + +fn string_env(name: &str) -> String { + return std::env::var(name) + .expect(format!("Environment variable \"{}\" not found!", name).as_str()) +} + + +fn vec_u64_env(name: &str) -> Vec { + let var = std::env::var(name) + .unwrap_or("0".to_string()); + + return var + .split(",") + .map(|s| s.parse::() + .expect(format!("Failed to parse {}. Invalid syntax.", name).as_str())) + .collect(); +} \ No newline at end of file diff --git a/src/db/generic.rs b/src/db/generic.rs deleted file mode 100644 index 3661800..0000000 --- a/src/db/generic.rs +++ /dev/null @@ -1,21 +0,0 @@ -use serde_json::Value; -use tokio::sync::Mutex; - -use crate::Error; - -pub async fn get_json_mutex(data: &Mutex>) -> Result { - let data_lock = data.lock().await; - return match data_lock.as_ref() { - Some(data) => Ok(data.clone()), - None => Err("Cannot get mutex data: The data is corrupted!".into()), - }; -} - - -pub async fn get_toml_mutex(data: &Mutex>) -> Result { - let data_lock = data.lock().await; - return match data_lock.as_ref() { - Some(data) => Ok(data.clone()), - None => Err("Cannot get mutex data: The data is corrupted!".into()), - }; -} \ No newline at end of file diff --git a/src/db/reddit.rs b/src/db/reddit.rs index dadf4ab..5d533c8 100644 --- a/src/db/reddit.rs +++ b/src/db/reddit.rs @@ -2,7 +2,7 @@ use std::{fs, io::Write, path::Path}; use serde_json::Value; -use crate::{Data, rs_println, rs_warnln, websocket::send_cmd_json}; +use crate::{rs_println, rs_warnln, websocket::send_cmd_json}; static DATA_PATH: &str = "./data/db/re_data.json"; @@ -11,7 +11,7 @@ static PRESET_PATH: &str = "./data/defaults/re_data_preset.json"; pub static POSTS_KEY: &str = "posts"; -pub async fn read_data(data: &Data, wipe: bool) { +pub async fn read_data(wipe: bool) -> Value { if !Path::new(DATA_PATH).exists() || wipe { rs_println!( "{} creating new from preset...", @@ -21,9 +21,8 @@ pub async fn read_data(data: &Data, wipe: bool) { } let str_data = fs::read_to_string(DATA_PATH).unwrap(); - let json_data: Option = serde_json::from_str(&str_data).unwrap(); - let mut re_data = data.reddit_data.lock().await; - *re_data = json_data; + let json_data: Value = serde_json::from_str(&str_data).unwrap(); + return json_data; } @@ -45,9 +44,9 @@ fn generate_data() { } -pub async fn update_data(data: &Data) { +pub async fn update_data() { send_cmd_json("update_data_file", None, true).await; - read_data(data, false).await; + read_data(false).await; } diff --git a/src/db/terminal_args.rs b/src/db/terminal_args.rs index a9a20de..ff65df9 100644 --- a/src/db/terminal_args.rs +++ b/src/db/terminal_args.rs @@ -28,3 +28,17 @@ pub struct Args { #[arg(long, help = "Makes the program not use the schedule system.")] pub nosched: bool } + + +impl Args { + pub fn new() -> Self + { return ::parse(); } +} + + +impl ToString for Args { + fn to_string(&self) -> String { + return serde_json::to_string(self) + .unwrap_or("[FAILED TO CONVERT TO STRING]".to_string()); + } +} \ No newline at end of file diff --git a/src/events.rs b/src/events.rs index b25aa2b..b85671b 100644 --- a/src/events.rs +++ b/src/events.rs @@ -1,4 +1,3 @@ -use crate::db::generic::{get_json_mutex, get_toml_mutex}; use crate::db::reddit::update_data; use crate::r#gen::set_status; use crate::messages::{make_post_embed, make_removed_embed, EmbedOptions}; @@ -41,9 +40,7 @@ async fn on_ready(ctx: &serenity::Context, data_about_bot: &Ready, data: &Data) data_about_bot.user.id ); - let m_data = get_toml_mutex(&data.cfg).await.unwrap(); - - set_status(m_data, ctx).await; + set_status(data.cfg.clone(), ctx).await; } @@ -88,9 +85,9 @@ async fn approve_btn(ctx: &serenity::Context, data: &Data, c_member: &Member, co let c_id = component.channel_id; let m_id = component.message.id; - update_data(data).await; - let new_data = &get_json_mutex(&data.reddit_data) - .await.unwrap()[POSTS_KEY][&url]; + update_data().await; + let new_data = &data.reddit_data + .lock().await[POSTS_KEY][&url]; update_embed(ctx, &url, new_data, &c_id, &m_id).await; @@ -123,9 +120,9 @@ async fn remove_btn(ctx: &serenity::Context, data: &Data, c_member: &Member, com let c_id = component.channel_id; let m_id = component.message.id; - update_data(data).await; - let new_data = &get_json_mutex(&data.reddit_data) - .await.unwrap()[POSTS_KEY][&url]; + update_data().await; + let new_data = &data.reddit_data + .lock().await[POSTS_KEY][&url]; update_embed(ctx, &url, new_data, &c_id, &m_id).await; @@ -144,16 +141,17 @@ async fn remove_btn(ctx: &serenity::Context, data: &Data, c_member: &Member, com async fn vote_btn(ctx: &serenity::Context, data: &Data, c_member: &Member, component: &ComponentInteraction, url: String, vote: bool) -> Result<(), Error> { let uid: u64 = c_member.user.id.into(); - let is_mod = is_bk_mod(data.bk_mods.clone(), uid); + let is_mod = is_bk_mod(data.env_vars.reddit_mod_discord_ids.clone(), uid); let r = send_cmd_json("set_vote_post", Some(json!([&url, uid, is_mod, true, !vote])), true).await.unwrap(); let c_id = component.channel_id; let m_id = component.message.id; - update_data(data).await; - let new_data = &get_json_mutex(&data.reddit_data) - .await.unwrap()[POSTS_KEY][&url]; + update_data().await; + let new_data = &data.reddit_data + .lock().await[POSTS_KEY][&url]; + update_embed(ctx, &url, new_data, &c_id, &m_id).await; if r["value"].as_bool().unwrap() { diff --git a/src/gen.rs b/src/gen.rs index 556ca5e..2f152d7 100644 --- a/src/gen.rs +++ b/src/gen.rs @@ -6,51 +6,41 @@ use poise::serenity_prelude::Client; use tokio::sync::Mutex; use toml::Value; +use crate::db::env_vars::AssistantEnv; use crate::db::{cfg, discord, reddit}; -use crate::db::generic::get_toml_mutex; use crate::games::wwrps::RPSGame; use crate::lang::Lang; use crate::{Args, Cmd, Data, cmds, events, rs_println}; -pub async fn gen_data(args: Args, owners: Vec) -> Data { +pub async fn gen_data(args: Args, env_vars: AssistantEnv) -> Data { let ball_classic_str = std::fs::read_to_string("./cfg/8-ball_classic.txt").unwrap(); let ball_quirk_str = std::fs::read_to_string("./cfg/8-ball_quirky.txt").unwrap(); let ball_classic: Vec = ball_classic_str.lines().map(String::from).collect(); let ball_quirk: Vec = ball_quirk_str .lines().map(String::from).collect(); - let mods_env = std::env::var("ASSISTANT_BK_MODS").unwrap_or("0".to_string()); - let mods_vec_str: Vec = mods_env.split(",").map(String::from).collect(); - let mods_vec_u64: Vec = mods_vec_str - .iter() - .map(|s| s.parse::().expect("Failed to parse ASSISTANT_BK_MODS. Invalid syntax.")) - .collect(); + let re_data = reddit:: read_data(args.clone().wipe).await; + let dc_data = discord::read_data(args.clone().wipe).await; + let cf_data = cfg:: read_data(args.clone().wipe).await; - let data = Data { - owners, - ball_prompts: [ball_classic, ball_quirk], - rps_game: Mutex::new(RPSGame::new()), - bk_mods: mods_vec_u64, - reddit_data: None.into(), - discord_data: None.into(), - cfg: None.into(), + return Data { args: args.clone(), + ball_prompts: [ball_classic, ball_quirk], + cfg: cf_data, + discord_data: dc_data.into(), + env_vars: env_vars, lang_name: "".to_string().into(), - lang: Lang::new().into() + lang: Lang::new().into(), + reddit_data: re_data.into(), + rps_game: Mutex::new(RPSGame::new()) }; - - discord::read_data(&data, args.clone().wipe).await; - reddit:: read_data(&data, args.clone().wipe).await; - cfg:: read_data(&data, args.clone().wipe).await; - - return data; } -pub async fn gen_bot(data: Data, args: Args) -> Client { +pub async fn gen_bot(data: Data) -> Client { let token = - if !args.test { std::env::var("ASSISTANT_TOKEN").expect("Missing ASSISTANT_TOKEN env var!") } + if !data.args.test { std::env::var("ASSISTANT_TOKEN").expect("Missing ASSISTANT_TOKEN env var!") } else { std::env::var("ASSISTANT_TOKEN_TEST").expect("Missing ASSISTANT_TOKEN_TEST env var!") }; let intents = serenity::GatewayIntents::all(); @@ -60,7 +50,7 @@ pub async fn gen_bot(data: Data, args: Args) -> Client { let token_end_len = token[peek_len..].len(); rs_println!("Token: {}{}", token_peek, "*".repeat(token_end_len)); - let own: HashSet = data.owners + let owner_users: HashSet = data.env_vars.bot_owners .clone() .into_iter() .filter_map(|i| if i == 0 { None } else { Some(UserId::from(i))}) @@ -68,7 +58,7 @@ pub async fn gen_bot(data: Data, args: Args) -> Client { let framework = poise::Framework::builder() .options(poise::FrameworkOptions { - owners: own, + owners: owner_users, commands: make_cmd_vec(&data).await, event_handler: events::event_handler, ..Default::default() @@ -89,7 +79,7 @@ pub async fn gen_bot(data: Data, args: Args) -> Client { async fn make_cmd_vec(data: &Data) -> Vec { - let mut cmds = vec![ + let mut cmds: Vec = vec![ // GENERIC cmds::generic::help::cmd(), cmds::generic::eight_ball::cmd(), @@ -110,9 +100,8 @@ async fn make_cmd_vec(data: &Data) -> Vec { // DATABASE cmds::db::main_cmd::cmd() ]; - let cfg = get_toml_mutex(&data.cfg).await.unwrap(); - let disabled = cfg["commands"]["disabled_categories"] + let disabled = data.cfg["commands"]["disabled_categories"] .as_array() .unwrap() .iter() @@ -125,12 +114,12 @@ async fn make_cmd_vec(data: &Data) -> Vec { } -pub async fn set_status(m_data: Value, ctx: &serenity::Context) { +pub async fn set_status(cfg: Value, ctx: &serenity::Context) { let status_str: String; - let status = m_data["general"]["status"].as_str().unwrap(); - let status_c = m_data["general"]["statusCommitNumber"].as_bool().unwrap(); - let status_ec = m_data["general"]["statusExperimentalCommit"].as_bool().unwrap(); + let status = cfg["general"]["status"].as_str().unwrap(); + let status_c = cfg["general"]["statusCommitNumber"].as_bool().unwrap(); + let status_ec = cfg["general"]["statusExperimentalCommit"].as_bool().unwrap(); if status_c { let commit_num_r = process::Command::new("git") diff --git a/src/macros.rs b/src/macros.rs index 4fa57e1..6b4724d 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -66,7 +66,7 @@ macro_rules! warnln { macro_rules! lang { ($key:expr) => { { - use $crate::{LANG, errln}; + /*use $crate::{LANG, errln}; let value = unsafe { LANG .as_ref() @@ -76,11 +76,13 @@ macro_rules! lang { if value.is_none() { errln!("Key not found in LANG JSON: \"{}\"", $key); } - value.unwrap().as_str().expect("LANG JSON value is not a string!").to_string() + value.unwrap().as_str().expect("LANG JSON value is not a string!").to_string()*/ + + "hello".to_string() } }; ($key:expr, $($arg:expr),*) => {{ - use $crate::{LANG, errln}; + /*use $crate::{LANG, errln}; use formatx::formatx; let value = unsafe { @@ -93,6 +95,7 @@ macro_rules! lang { if value.is_none() { errln!("Key not found in LANG JSON: \"{}\"", $key); } let format_str = value.unwrap().as_str().expect("LANG JSON value is not a string!"); - formatx!(format_str, $($arg),*).unwrap() + formatx!(format_str, $($arg),*).unwrap()*/ + "hello".to_string() }}; } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index d6ed65f..a467c84 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,24 +1,22 @@ -#![warn(unused_extern_crates)] #![allow(clippy::needless_return)] -#![allow(static_mut_refs)] -mod events; -mod messages; -mod python; -mod macros; -#[allow(unknown_lints)] -mod websocket; mod cmds; mod db; +mod events; mod games; -mod schedule; mod gen; mod lang; +mod macros; +mod messages; +mod python; +mod schedule; +mod websocket; use std::process; use std::thread; +use std::thread::JoinHandle; use std::time::Duration; use std::vec; use std::error::Error as StdErr; @@ -31,8 +29,8 @@ use tokio::runtime::Runtime; use websocket::send_cmd_json; use crate::db::bot_data::Data; +use crate::db::env_vars::AssistantEnv; use crate::db::terminal_args::Args; -use crate::db::generic::get_toml_mutex; use crate::schedule::Schedule; @@ -43,79 +41,98 @@ type Cmd = Command>; #[tokio::main] async fn main() { - let args = ::parse(); - let args_str = serde_json::to_string(&args).expect("Error serializing args to JSON"); - - let own_env = std::env::var("ASSISTANT_OWNERS").unwrap_or("0".to_string()); - let own_vec_str: Vec = own_env.split(",").map(String::from).collect(); - let own_vec_u64: Vec = own_vec_str - .iter() - .map(|s| s.parse::().expect("Failed to parse ASSISTANT_OWNERS. Invalid syntax.")) - .collect(); + let args = Args::new(); + rs_println!("ARGS: {}", args.to_string()); + let env_vars = AssistantEnv::new(args.test); rs_println!("Generating and/or fetching data and config..."); - let data = gen_data(args.clone(), own_vec_u64.clone()).await; + let data = gen_data(args, env_vars).await; rs_println!("[IMPORTANT] The below message is a test message, it should be written in the language you've selected\nTest message: {}", lang!("log_lang_load_success")); - if args.py && !args.rs { - let _ = python::start(args, *data.lang_name.lock().await).await; + // We start this here cuz we have all the data that we need + if data.args.py && !data.args.rs { + let _ = python::start( + data.args.clone(), + data.lang_name.clone(), + data.env_vars.clone(), + ).await; process::exit(0); } - else if args.rs && ! args.py { - start(args, data).await; + else if data.args.rs && ! data.args.py { + start_bot(data).await; process::exit(0); } - rs_println!("ARGS: {}", args_str); - - let cfg = get_toml_mutex(&data.cfg).await.unwrap(); - let cfg_arr = cfg["commands"]["disabled_categories"].as_array().unwrap(); + let cfg_arr = data.cfg["commands"]["disabled_categories"].as_array().unwrap(); let run_py = !cfg_arr.iter().any(|val| val.as_str() == Some("re")); - let rt_rs = Runtime::new().unwrap(); - let rt_py = Runtime::new().unwrap(); - let python_args = args.clone(); - let rust_args = args.clone(); - if !run_py { rs_println!("[IMPORTANT] You have disabled the \"re\" commands in the CFG. The app will not run the Python code and the websockets to save resources!"); } - let rust = thread::spawn(move || { - rt_rs.block_on(async { - if run_py { websocket::start(rust_args.clone(), own_vec_u64.clone()).await; } - start(rust_args, data).await; - }); - }); - - let python = thread::spawn(move || { - rt_py.block_on(async { - if run_py { let _ = python::start(python_args, *data.lang_name.lock().await).await; } - }); - }); - - if !args.nosched { - let dur = if args.test { Duration::from_secs(60) } else { Duration::from_secs(60 * 10) }; - - let schedules: Vec = vec![ - (dur, || Box::pin(read_reddit_inbox())) - ]; - - run_schedules(schedules).await; - } + if !data.args.nosched { start_schedules(data.args.test); } + + let python = start_py( + data.args.clone(), + data.lang_name.clone(), + data.env_vars.clone(), + run_py + ); + let rust = start_rs(data, run_py); rust.join().unwrap(); python.join().unwrap(); } -async fn start(args: Args, data: Data) { - let mut bot = gen_bot(data, args).await; + +fn start_rs(data: Data, run_py: bool) -> JoinHandle<()> { + let rt = Runtime::new().unwrap(); + + return thread::spawn(move || { + rt.block_on(async { + if run_py { websocket::start(&data).await; } + start_bot(data).await; + }); + }); +} + + +fn start_py( + args: Args, + lang_name: String, + env_vars: AssistantEnv, + run_py: bool +) -> JoinHandle<()> { + let rt = Runtime::new().unwrap(); + + return thread::spawn(move || { + rt.block_on(async { + if run_py { let _ = python::start(args, lang_name, env_vars).await; } + }); + }); +} + + +async fn start_bot(data: Data) { + let mut bot = gen_bot(data).await; rs_println!("Starting Discord bot..."); bot.start().await.unwrap(); } +async fn start_schedules(test: bool) { + let dur = if test { Duration::from_secs(60) } + else { Duration::from_secs(60 * 10) }; + + let schedules: Vec = vec![ + (dur, || Box::pin(read_reddit_inbox())) + ]; + + run_schedules(schedules).await; +} + + async fn read_reddit_inbox() { unsafe { if !websocket::HAS_CONNECTED { return; } diff --git a/src/messages.rs b/src/messages.rs index 197bcef..4d695c7 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -1,7 +1,7 @@ -use std::env; use std::io::{Read, Write}; -use crate::{lang, Args, Context}; +use crate::db::bot_data::Data; +use crate::{lang, Context}; use base64::engine::general_purpose; use base64::Engine; @@ -199,16 +199,26 @@ pub async fn http_edit_msg( } -pub async fn send_dm(msg: String, args: Args, receivers: Vec) { - let token: String = - if !args.test { env::var("ASSISTANT_TOKEN") .expect("Missing ASSISTANT_TOKEN env var!") } - else { env::var("ASSISTANT_TOKEN_TEST").expect("Missing ASSISTANT_TOKEN_TEST env var!") }; +pub async fn send_dm(msg: String, data: &Data) { + let http = Http::new(&data.env_vars.token); + let c_msg = CreateMessage::new().content(msg); + + for uid in data.env_vars.bot_owners.clone() { + if uid == 0 { continue; } + let user = UserId::new(uid); + let _ = user.dm(http.as_ref(), c_msg.clone()).await; + } +} + + + +pub async fn send_dm_min(msg: String, token: String, bot_owners: Vec) { let http = Http::new(&token); let c_msg = CreateMessage::new().content(msg); - for uid in receivers { + for uid in bot_owners { if uid == 0 { continue; } let user = UserId::new(uid); let _ = user.dm(http.as_ref(), c_msg.clone()).await; @@ -265,9 +275,11 @@ pub fn make_removed_embed(post_data: &Value, url: &str, ephemeral: bool) -> Embe let desc = lang!( "dc_msg_embed_re_removed", - if !post_data["removed"]["by"].is_null() { post_data["removed"]["by"].as_str().unwrap() } + if !post_data["removed"]["by"].is_null() + { post_data["removed"]["by"].as_str().unwrap() } else { &none }, - if !post_data["removed"]["reason"].is_null() { post_data["removed"]["reason"].as_str().unwrap() } + if !post_data["removed"]["reason"].is_null() + { post_data["removed"]["reason"].as_str().unwrap() } else { &none } ); diff --git a/src/python.rs b/src/python.rs index ec8454e..072e620 100644 --- a/src/python.rs +++ b/src/python.rs @@ -1,5 +1,7 @@ -use crate::messages::send_dm; -use crate::{errln, lang, rs_println, Args}; +use crate::db::env_vars::AssistantEnv; +use crate::db::terminal_args::Args; +use crate::messages::send_dm_min; +use crate::{errln, lang, rs_println}; use std::fs; use std::ffi::CString; @@ -9,7 +11,7 @@ use pyo3::prelude::*; use pyo3::types::PyList; -pub async fn start(args: Args, lang_name: String) -> PyResult<()> { +pub async fn start(args: Args, lang_name: String, env_vars: AssistantEnv) -> PyResult<()> { rs_println!("Running Python program..."); let args_str = serde_json::to_string(&args).expect("Error serializing args to JSON"); @@ -23,15 +25,12 @@ pub async fn start(args: Args, lang_name: String) -> PyResult<()> { let py_args = args_str.replace(":true", ":True").replace(":false", ":False"); let app_path: CString; - unsafe { - app_path = CString::new( - format!("args = {}\nlang_name = \"{}\"\n{}", - py_args, - lang_name.clone(), - code - ) - ).unwrap(); - } + app_path = CString::new(format!( + "args = {}\nlang_name = \"{}\"\n{}", + py_args, + lang_name, + code + )).unwrap(); let mut traceback: String = String::new(); let mut is_error = false; @@ -57,19 +56,11 @@ pub async fn start(args: Args, lang_name: String) -> PyResult<()> { }); if is_error { - let own_env = std::env::var("ASSISTANT_OWNERS").unwrap_or("0".to_string()); - let own_vec_str: Vec = own_env.split(",").map(String::from).collect(); - let own_vec_u64: Vec = own_vec_str - .iter() - .map(|s| s.parse::().expect("Failed to parse ASSISTANT_OWNERS. Invalid syntax.")) - .collect(); - - send_dm( - lang!("dc_msg_dm_python_err", format!("{}", traceback)), - args, - own_vec_u64 + send_dm_min( + lang!("dc_msg_dm_python_err", traceback), + env_vars.token.clone(), + env_vars.bot_owners.clone() ).await; - errln!("pyO3: {}", traceback); } diff --git a/src/websocket.rs b/src/websocket.rs index fe8826c..c2974d4 100644 --- a/src/websocket.rs +++ b/src/websocket.rs @@ -8,7 +8,8 @@ use futures::StreamExt; use std::sync::Arc; use serde_json::{Value, json}; -use crate::messages::send_dm; +use crate::db::bot_data::Data; +use crate::messages::send_dm_min; use crate::{lang, rs_println}; use crate::Args; @@ -103,17 +104,25 @@ async fn receive_response() -> Option { } -pub async fn start(args: Args, owners: Vec) { +pub async fn start(data: &Data) { rs_println!("Running local websocket..."); - let ip = format!("127.0.0.1:{}", args.port); + let ip = format!("127.0.0.1:{}", data.args.port); let listener = TcpListener::bind(&ip).await.unwrap(); rs_println!("WebSocket server running on ws://{}", ip); - tokio::spawn(handle_connections(listener, args, owners)); + tokio::spawn(handle_connections( + listener, + data.env_vars.token.clone(), + data.env_vars.bot_owners.clone() + )); } -async fn handle_connections(listener: TcpListener, args: Args, owners: Vec) { +async fn handle_connections( + listener: TcpListener, + token: String, + bot_owners: Vec +) { while let Ok((stream, _)) = listener.accept().await { let ws_stream = accept_async(stream).await.unwrap(); let (sender, receiver) = ws_stream.split(); @@ -124,14 +133,17 @@ async fn handle_connections(listener: TcpListener, args: Args, owners: Vec) set_sender(sender_arc.clone()).await; set_receiver(receiver_arc.clone()).await; - while let Some(Ok(msg)) = receiver_arc.lock().await.as_mut().unwrap().next().await { - handle_message(msg, args.clone(), owners.clone()).await; - } + while let Some(Ok(msg)) = receiver_arc.lock().await.as_mut().unwrap().next().await + { handle_message(msg, token.clone(), bot_owners.clone()).await; } } } -async fn handle_message(msg: tungstenite::protocol::Message, args: Args, owners: Vec) { +async fn handle_message( + msg: tungstenite::protocol::Message, + token: String, + bot_owners: Vec +) { match msg { tungstenite::Message::Text(text) => { rs_println!("Received from Python: {}", text); @@ -139,7 +151,11 @@ async fn handle_message(msg: tungstenite::protocol::Message, args: Args, owners: if let Some(stripped) = text.strip_prefix("json:") { let t_json: Value = serde_json::from_str(stripped).unwrap(); if t_json.get("error").is_some() { - send_dm(lang!("dc_msg_dm_python_err_socket"), args, owners).await; + send_dm_min( + lang!("dc_msg_dm_python_err_socket"), + token, + bot_owners + ).await; } } @@ -150,16 +166,7 @@ async fn handle_message(msg: tungstenite::protocol::Message, args: Args, owners: HAS_CONNECTED = true; } } - } - tungstenite::Message::Binary(bytes) => { - if args.dev && args.ping { - rs_println!("[Binary] from Python: {:?}", bytes); - } - } - _ => { - if args.dev && args.ping { - rs_println!("Received from Python: [UNKNOWN / OTHER]"); - } - } + }, + _ => {} } } \ No newline at end of file