From 47baed7d6fef48c225b5f48565eb9eb8ec2afa54 Mon Sep 17 00:00:00 2001 From: MeexReay Date: Thu, 17 Apr 2025 22:56:44 +0300 Subject: [PATCH] move images to assets/ --- Cargo.lock | 5 +- Cargo.toml | 2 +- README.md | 2 +- icon.png => assets/icon.png | Bin image.png => assets/image.png | Bin konata.png => assets/konata.png | Bin logo.gif => assets/logo.gif | Bin src/chat/gtk_gui.rs | 10 +- src/config.rs | 502 ++++++++++++++++---------------- 9 files changed, 260 insertions(+), 261 deletions(-) rename icon.png => assets/icon.png (100%) rename image.png => assets/image.png (100%) rename konata.png => assets/konata.png (100%) rename logo.gif => assets/logo.gif (100%) diff --git a/Cargo.lock b/Cargo.lock index 8d328bd..9b00118 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1054,13 +1054,12 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" dependencies = [ "rand_chacha", "rand_core", - "zerocopy 0.8.17", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 1eb5560..1c20556 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.3+2.0" edition = "2021" [dependencies] -rand = "0.9.0" +rand = "0.9.1" regex = "1.11.1" colored = "3.0.0" lazy_static = "1.5.0" diff --git a/README.md b/README.md index d6b841d..4067486 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ better RAC client - RACS compatible (--enable-ssl or in --configure enable SSL) - chunked reading messages -![screenshot](image.png) +![screenshot](assets/image.png) ## how to run diff --git a/icon.png b/assets/icon.png similarity index 100% rename from icon.png rename to assets/icon.png diff --git a/image.png b/assets/image.png similarity index 100% rename from image.png rename to assets/image.png diff --git a/konata.png b/assets/konata.png similarity index 100% rename from konata.png rename to assets/konata.png diff --git a/logo.gif b/assets/logo.gif similarity index 100% rename from logo.gif rename to assets/logo.gif diff --git a/src/chat/gtk_gui.rs b/src/chat/gtk_gui.rs index 1d12278..d7b8ed1 100644 --- a/src/chat/gtk_gui.rs +++ b/src/chat/gtk_gui.rs @@ -58,7 +58,7 @@ pub fn recv_tick(ctx: Arc) -> Result<(), Box> { ) { Ok(Some((messages, size))) => { let messages: Vec = if ctx.disable_formatting { - messages + messages } else { messages.into_iter().flat_map(|o| format_message(ctx.enable_ip_viewing, o)).collect() }; @@ -179,7 +179,7 @@ fn build_menu(_: Arc, app: &Application) { .comments("better RAC client") .website("https://github.com/MeexReay/bRAC") .website_label("source code") - .logo(&Texture::for_pixbuf(&load_pixbuf(include_bytes!("../../icon.png")))) + .logo(&Texture::for_pixbuf(&load_pixbuf(include_bytes!("../../assets/icon.png")))) .build() .present(); } @@ -222,17 +222,17 @@ fn build_ui(ctx: Arc, app: &Application) -> UiModel { let fixed = Fixed::new(); fixed.set_can_target(false); - let konata = Picture::for_pixbuf(&load_pixbuf(include_bytes!("../../konata.png"))); + let konata = Picture::for_pixbuf(&load_pixbuf(include_bytes!("../../assets/konata.png"))); konata.set_size_request(174, 127); fixed.put(&konata, 325.0, 4.0); - let logo = Picture::for_pixbuf(&load_pixbuf(include_bytes!("../../logo.gif"))); + let logo = Picture::for_pixbuf(&load_pixbuf(include_bytes!("../../assets/logo.gif"))); logo.set_size_request(152, 64); let logo_anim = PixbufAnimation::from_stream( &MemoryInputStream::from_bytes( - &glib::Bytes::from(include_bytes!("../../logo.gif")) + &glib::Bytes::from(include_bytes!("../../assets/logo.gif")) ), None::<&gio::Cancellable> ).unwrap().iter(Some(SystemTime::now())); diff --git a/src/config.rs b/src/config.rs index 7a6aed2..56008d6 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,252 +1,252 @@ -use std::{str::FromStr, sync::{Arc, RwLock}}; -#[allow(unused_imports)] -use std::{env, fs, path::{Path, PathBuf}, thread, time::Duration}; -use colored::Colorize; -use rand::random; -use serde_yml; -use clap::Parser; - -use crate::chat::ChatContext; - -use super::util::get_input; - -const MESSAGE_FORMAT: &str = "\u{B9AC}\u{3E70}<{name}> {text}"; - -#[derive(serde::Serialize, serde::Deserialize)] -pub struct Config { - #[serde(default = "default_host")] - pub host: String, - #[serde(default)] - pub name: Option, - #[serde(default = "default_message_format")] - pub message_format: String, - #[serde(default = "default_update_time")] - pub update_time: usize, - #[serde(default = "default_max_messages")] - pub max_messages: usize, - #[serde(default)] - pub enable_ip_viewing: bool, - #[serde(default)] - pub disable_ip_hiding: bool, - #[serde(default)] - pub enable_auth: bool, - #[serde(default)] - pub enable_ssl: bool, - #[serde(default)] - pub enable_chunked: bool, -} - -fn default_max_messages() -> usize { 200 } -fn default_update_time() -> usize { 50 } -fn default_host() -> String { "meex.lol:11234".to_string() } -fn default_message_format() -> String { MESSAGE_FORMAT.to_string() } - -fn ask_usize(name: impl ToString, default: usize) -> usize { - get_input(format!("{} (default: {}) {} ", name.to_string().bold(), default, ">".bold()).bright_yellow()) - .and_then(|o| o.parse().ok()).unwrap_or(default) -} - -fn ask_string(name: impl ToString, default: impl ToString + Clone) -> String { - ask_string_option(name, default.clone()).unwrap_or(default.to_string()) -} - -fn ask_string_option(name: impl ToString, default: impl ToString) -> Option { - let default = default.to_string(); - get_input(format!("{} (default: {}) {} ", name.to_string().bold(), default, ">".bold()).bright_yellow()) -} - -fn ask_bool(name: impl ToString, default: bool) -> bool { - get_input(format!("{} (Y/N, default: {}) {} ", name.to_string().bold(), if default { "Y" } else { "N" }, ">".bold()).bright_yellow()) - .map(|o| o.to_lowercase() != "n") - .unwrap_or(default) -} - -pub fn configure(path: PathBuf) -> Config { - println!("{}", "To configure the client, please answer a few questions. It won't take long.".yellow()); - println!("{}", "You can reconfigure client in any moment via `bRAC --configure`".yellow()); - println!("{}", format!("Config stores in path `{}`", path.to_string_lossy()).yellow()); - println!(); - - let host = ask_string("Host", default_host()); - let name = ask_string_option("Name", "ask every time"); - let update_time = ask_usize("Update interval", default_update_time()); - let max_messages = ask_usize("Max messages", default_max_messages()); - let message_format = ask_string("Message format", default_message_format()); - let enable_ip_viewing = ask_bool("Enable users IP viewing?", true); - let disable_ip_hiding = ask_bool("Enable your IP viewing?", false); - let enable_auth = ask_bool("Enable auth-mode?", false); - let enable_ssl = ask_bool("Enable SSL?", false); - let enable_chunked = ask_bool("Enable chunked reading?", true); - - let config = Config { - host, - name, - message_format, - update_time, - max_messages, - enable_ip_viewing, - disable_ip_hiding, - enable_auth, - enable_ssl, - enable_chunked - }; - - let config_text = serde_yml::to_string(&config).expect("Config save error"); - fs::create_dir_all(&path.parent().expect("Config save error")).expect("Config save error"); - fs::write(&path, config_text).expect("Config save error"); - - println!(); - println!("{}", "Config saved! You can reconfigure it in any moment via `bRAC --configure`".yellow()); - - config -} - -pub fn load_config(path: PathBuf) -> Config { - if !fs::exists(&path).unwrap_or_default() { - let config = configure(path.clone()); - thread::sleep(Duration::from_secs(4)); - config - } else { - let config = &fs::read_to_string(&path).expect("Config load error"); - serde_yml::from_str(config).expect("Config load error") - } -} - -pub fn get_config_path() -> PathBuf { - let mut config_dir = PathBuf::from_str(".").unwrap(); - - #[cfg(all(feature = "homedir", not(target_os = "windows")))] - if let Some(dir) = { - let home_dir = { - use homedir::my_home; - my_home().ok().flatten() - }; - - #[cfg(target_os = "linux")] - let config_dir = { - let home_dir = home_dir.map(|o| o.join("bRAC")); - home_dir.map(|o| o.join(".config")) - }; - - #[cfg(target_os = "macos")] - let config_dir = { - let home_dir = home_dir.map(|o| o.join("bRAC")); - home_dir.map(|o| o.join(".config")) - }; - - config_dir - } { - config_dir = dir; - } - - #[cfg(target_os = "windows")] - if let Some(dir) = { - env::var("APPDATA") - .ok() - .and_then(|o| Some(PathBuf::from_str(&o).ok()?.join("bRAC"))) - } { - config_dir = dir; - } - - config_dir.join("config.yml") -} - -#[derive(Parser, Debug)] -#[command(version, about, long_about = None)] -pub struct Args { - /// Print config path - #[arg(short='p', long)] - pub config_path: bool, - - /// Use specified host - #[arg(short='H', long)] - pub host: Option, - - /// Use specified name - #[arg(short='n', long)] - pub name: Option, - - /// Use specified message format - #[arg(short='F', long)] - pub message_format: Option, - - /// Print unformatted messages from chat and exit - #[arg(short='r', long)] - pub read_messages: bool, - - /// Send unformatted message to chat and exit - #[arg(short='s', long, value_name="MESSAGE")] - pub send_message: Option, - - /// Disable message formatting and sanitizing - #[arg(short='f', long)] - pub disable_formatting: bool, - - /// Disable slash commands - #[arg(short='c', long)] - pub disable_commands: bool, - - /// Disable ip hiding - #[arg(short='i', long)] - pub disable_ip_hiding: bool, - - /// Enable users IP viewing - #[arg(short='v', long)] - pub enable_users_ip_viewing: bool, - - /// Configure client - #[arg(short='C', long)] - pub configure: bool, - - /// Enable authentication - #[arg(short='a', long)] - pub enable_auth: bool, - - /// Enable SSL - #[arg(short='S', long)] - pub enable_ssl: bool, - - /// Enable chunked reading - #[arg(short='u', long)] - pub enable_chunked: bool, -} - -pub struct Context { - pub chat: Arc>>>, - pub host: String, - pub name: String, - pub disable_formatting: bool, - pub disable_commands: bool, - pub disable_hiding_ip: bool, - pub message_format: String, - pub update_time: usize, - pub max_messages: usize, - pub enable_ip_viewing: bool, - pub enable_auth: bool, - pub enable_ssl: bool, - pub enable_chunked: bool, -} - -impl Context { - pub fn new(config: &Config, args: &Args) -> Context { - Context { - chat: Arc::new(RwLock::new(None)), - message_format: args.message_format.clone().unwrap_or(config.message_format.clone()), - host: args.host.clone().unwrap_or(config.host.clone()), - name: args.name.clone().or(config.name.clone()).unwrap_or_else(|| ask_string("Name", format!("Anon#{:X}", random::()))), - disable_formatting: args.disable_formatting, - disable_commands: args.disable_commands, - disable_hiding_ip: args.disable_ip_hiding, - update_time: config.update_time, - max_messages: config.max_messages, - enable_ip_viewing: args.enable_users_ip_viewing || config.enable_ip_viewing, - enable_auth: args.enable_auth || config.enable_auth, - enable_ssl: args.enable_ssl || config.enable_ssl, - enable_chunked: args.enable_chunked || config.enable_chunked, - } - } - - pub fn chat(&self) -> Arc { - self.chat.read().unwrap().clone().unwrap() - } +use std::{str::FromStr, sync::{Arc, RwLock}}; +#[allow(unused_imports)] +use std::{env, fs, path::{Path, PathBuf}, thread, time::Duration}; +use colored::Colorize; +use rand::random; +use serde_yml; +use clap::Parser; + +use crate::chat::ChatContext; + +use super::util::get_input; + +const MESSAGE_FORMAT: &str = "\u{B9AC}\u{3E70}<{name}> {text}"; + +#[derive(serde::Serialize, serde::Deserialize)] +pub struct Config { + #[serde(default = "default_host")] + pub host: String, + #[serde(default)] + pub name: Option, + #[serde(default = "default_message_format")] + pub message_format: String, + #[serde(default = "default_update_time")] + pub update_time: usize, + #[serde(default = "default_max_messages")] + pub max_messages: usize, + #[serde(default)] + pub enable_ip_viewing: bool, + #[serde(default)] + pub disable_ip_hiding: bool, + #[serde(default)] + pub enable_auth: bool, + #[serde(default)] + pub enable_ssl: bool, + #[serde(default)] + pub enable_chunked: bool, +} + +fn default_max_messages() -> usize { 200 } +fn default_update_time() -> usize { 50 } +fn default_host() -> String { "meex.lol:11234".to_string() } +fn default_message_format() -> String { MESSAGE_FORMAT.to_string() } + +fn ask_usize(name: impl ToString, default: usize) -> usize { + get_input(format!("{} (default: {}) {} ", name.to_string().bold(), default, ">".bold()).bright_yellow()) + .and_then(|o| o.parse().ok()).unwrap_or(default) +} + +fn ask_string(name: impl ToString, default: impl ToString + Clone) -> String { + ask_string_option(name, default.clone()).unwrap_or(default.to_string()) +} + +fn ask_string_option(name: impl ToString, default: impl ToString) -> Option { + let default = default.to_string(); + get_input(format!("{} (default: {}) {} ", name.to_string().bold(), default, ">".bold()).bright_yellow()) +} + +fn ask_bool(name: impl ToString, default: bool) -> bool { + get_input(format!("{} (Y/N, default: {}) {} ", name.to_string().bold(), if default { "Y" } else { "N" }, ">".bold()).bright_yellow()) + .map(|o| o.to_lowercase() != "n") + .unwrap_or(default) +} + +pub fn configure(path: PathBuf) -> Config { + println!("{}", "To configure the client, please answer a few questions. It won't take long.".yellow()); + println!("{}", "You can reconfigure client in any moment via `bRAC --configure`".yellow()); + println!("{}", format!("Config stores in path `{}`", path.to_string_lossy()).yellow()); + println!(); + + let host = ask_string("Host", default_host()); + let name = ask_string_option("Name", "ask every time"); + let update_time = ask_usize("Update interval", default_update_time()); + let max_messages = ask_usize("Max messages", default_max_messages()); + let message_format = ask_string("Message format", default_message_format()); + let enable_ip_viewing = ask_bool("Enable users IP viewing?", true); + let disable_ip_hiding = ask_bool("Enable your IP viewing?", false); + let enable_auth = ask_bool("Enable auth-mode?", false); + let enable_ssl = ask_bool("Enable SSL?", false); + let enable_chunked = ask_bool("Enable chunked reading?", true); + + let config = Config { + host, + name, + message_format, + update_time, + max_messages, + enable_ip_viewing, + disable_ip_hiding, + enable_auth, + enable_ssl, + enable_chunked + }; + + let config_text = serde_yml::to_string(&config).expect("Config save error"); + fs::create_dir_all(&path.parent().expect("Config save error")).expect("Config save error"); + fs::write(&path, config_text).expect("Config save error"); + + println!(); + println!("{}", "Config saved! You can reconfigure it in any moment via `bRAC --configure`".yellow()); + + config +} + +pub fn load_config(path: PathBuf) -> Config { + if !fs::exists(&path).unwrap_or_default() { + let config = configure(path.clone()); + thread::sleep(Duration::from_secs(4)); + config + } else { + let config = &fs::read_to_string(&path).expect("Config load error"); + serde_yml::from_str(config).expect("Config load error") + } +} + +pub fn get_config_path() -> PathBuf { + let mut config_dir = PathBuf::from_str(".").unwrap(); + + #[cfg(all(feature = "homedir", not(target_os = "windows")))] + if let Some(dir) = { + let home_dir = { + use homedir::my_home; + my_home().ok().flatten() + }; + + #[cfg(target_os = "linux")] + let config_dir = { + let home_dir = home_dir.map(|o| o.join("bRAC")); + home_dir.map(|o| o.join(".config")) + }; + + #[cfg(target_os = "macos")] + let config_dir = { + let home_dir = home_dir.map(|o| o.join("bRAC")); + home_dir.map(|o| o.join(".config")) + }; + + config_dir + } { + config_dir = dir; + } + + #[cfg(target_os = "windows")] + if let Some(dir) = { + env::var("APPDATA") + .ok() + .and_then(|o| Some(PathBuf::from_str(&o).ok()?.join("bRAC"))) + } { + config_dir = dir; + } + + config_dir.join("config.yml") +} + +#[derive(Parser, Debug)] +#[command(version, about, long_about = None)] +pub struct Args { + /// Print config path + #[arg(short='p', long)] + pub config_path: bool, + + /// Use specified host + #[arg(short='H', long)] + pub host: Option, + + /// Use specified name + #[arg(short='n', long)] + pub name: Option, + + /// Use specified message format + #[arg(short='F', long)] + pub message_format: Option, + + /// Print unformatted messages from chat and exit + #[arg(short='r', long)] + pub read_messages: bool, + + /// Send unformatted message to chat and exit + #[arg(short='s', long, value_name="MESSAGE")] + pub send_message: Option, + + /// Disable message formatting and sanitizing + #[arg(short='f', long)] + pub disable_formatting: bool, + + /// Disable slash commands + #[arg(short='c', long)] + pub disable_commands: bool, + + /// Disable ip hiding + #[arg(short='i', long)] + pub disable_ip_hiding: bool, + + /// Enable users IP viewing + #[arg(short='v', long)] + pub enable_users_ip_viewing: bool, + + /// Configure client + #[arg(short='C', long)] + pub configure: bool, + + /// Enable authentication + #[arg(short='a', long)] + pub enable_auth: bool, + + /// Enable SSL + #[arg(short='S', long)] + pub enable_ssl: bool, + + /// Enable chunked reading + #[arg(short='u', long)] + pub enable_chunked: bool, +} + +pub struct Context { + pub chat: Arc>>>, + pub host: String, + pub name: String, + pub disable_formatting: bool, + pub disable_commands: bool, + pub disable_hiding_ip: bool, + pub message_format: String, + pub update_time: usize, + pub max_messages: usize, + pub enable_ip_viewing: bool, + pub enable_auth: bool, + pub enable_ssl: bool, + pub enable_chunked: bool, +} + +impl Context { + pub fn new(config: &Config, args: &Args) -> Context { + Context { + chat: Arc::new(RwLock::new(None)), + message_format: args.message_format.clone().unwrap_or(config.message_format.clone()), + host: args.host.clone().unwrap_or(config.host.clone()), + name: args.name.clone().or(config.name.clone()).unwrap_or_else(|| ask_string("Name", format!("Anon#{:X}", random::()))), + disable_formatting: args.disable_formatting, + disable_commands: args.disable_commands, + disable_hiding_ip: args.disable_ip_hiding, + update_time: config.update_time, + max_messages: config.max_messages, + enable_ip_viewing: args.enable_users_ip_viewing || config.enable_ip_viewing, + enable_auth: args.enable_auth || config.enable_auth, + enable_ssl: args.enable_ssl || config.enable_ssl, + enable_chunked: args.enable_chunked || config.enable_chunked, + } + } + + pub fn chat(&self) -> Arc { + self.chat.read().unwrap().clone().unwrap() + } } \ No newline at end of file