From 8b64a2e1c320f47ffea82878f38cb55d04beab04 Mon Sep 17 00:00:00 2001 From: MeexReay Date: Sun, 9 Feb 2025 14:28:34 +0300 Subject: [PATCH] fix console and other stuff --- .gitignore | 2 - Cargo.lock | 282 ++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 6 +- README.md | 6 +- main.rs | 133 ------------------------- src/main.rs | 162 ++++++++++++++++++++++++++++++ test.txt | 1 + 7 files changed, 449 insertions(+), 143 deletions(-) delete mode 100644 main.rs create mode 100644 src/main.rs create mode 100644 test.txt diff --git a/.gitignore b/.gitignore index e58a696..c41cc9e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1 @@ -main -main.exe /target \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 58dd46e..d2766a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,3 +5,285 @@ version = 4 [[package]] name = "bRAC" version = "1.99.2" +dependencies = [ + "rand", + "termion", +] + +[[package]] +name = "bitflags" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +dependencies = [ + "cfg-if", + "libc", + "wasi", + "windows-targets", +] + +[[package]] +name = "libc" +version = "0.2.169" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags", + "libc", + "redox_syscall", +] + +[[package]] +name = "numtoa" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aa2c4e539b869820a2b82e1aef6ff40aa85e65decdd5185e83fb4b1249cd00f" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy 0.7.35", +] + +[[package]] +name = "proc-macro2" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +dependencies = [ + "rand_chacha", + "rand_core", + "zerocopy 0.8.17", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff" +dependencies = [ + "getrandom", + "zerocopy 0.8.17", +] + +[[package]] +name = "redox_syscall" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_termios" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20145670ba436b55d91fc92d25e71160fbfbdd57831631c8d7d36377a476f1cb" + +[[package]] +name = "syn" +version = "2.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termion" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eaa98560e51a2cf4f0bb884d8b2098a9ea11ecf3b7078e9c68242c74cc923a7" +dependencies = [ + "libc", + "libredox", + "numtoa", + "redox_termios", +] + +[[package]] +name = "unicode-ident" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" + +[[package]] +name = "wasi" +version = "0.13.3+wasi-0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa91407dacce3a68c56de03abe2760159582b846c6a4acd2f456618087f12713" +dependencies = [ + "zerocopy-derive 0.8.17", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06718a168365cad3d5ff0bb133aad346959a2074bd4a85c121255a11304a8626" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index b6b4855..4252924 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,5 @@ version = "1.99.2" edition = "2021" [dependencies] - -[[bin]] -name = "bRAC" -path = "main.rs" +rand = "0.9.0" +termion = "4.0.3" \ No newline at end of file diff --git a/README.md b/README.md index 7806850..72fc245 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,6 @@ better RAC client ## how to use ```bash -rustc main.rs # build -./main # run -cargo build # build with cargo -cargo run # run with cargo +cargo build # build +cargo run # run ``` \ No newline at end of file diff --git a/main.rs b/main.rs deleted file mode 100644 index f11699a..0000000 --- a/main.rs +++ /dev/null @@ -1,133 +0,0 @@ -use std::{error::Error, fmt::format, io::{stdin, stdout, BufRead, Read, Write}, net::TcpStream, thread, time::{self, SystemTime, UNIX_EPOCH}}; - -const MAX_MESSAGES: usize = 100; -const DEFAULT_HOST: &str = "meex.lol:11234"; - -fn send_message(host: &str, message: &str) -> Result<(), Box> { - let mut stream = TcpStream::connect(host)?; - stream.write_all(&[0x01])?; - stream.write_all(message.as_bytes())?; - stream.write_all("\0".repeat(1023 - message.len()).as_bytes())?; - Ok(()) -} - -fn read_messages(host: &str, skip: usize) -> Result> { - let mut stream = TcpStream::connect(host)?; - - stream.write_all(&[0x00])?; - - let packet_size = { - let mut data = Vec::new(); - - loop { - let mut buf = vec![0; 1]; - stream.read_exact(&mut buf)?; - let ch = buf[0]; - if ch == 0 { - break - } - data.push(ch); - } - - String::from_utf8(data)? - .trim_matches(char::from(0)) - .parse()? - }; - - // println!("{} {}", skip, packet_size); - - if packet_size <= skip { - return Ok(String::new()) - } - - let to_read = if skip == 0 { - stream.write_all(&[0x01])?; - packet_size - } else { - stream.write_all(&[0x02])?; - stream.write_all(skip.to_string().as_bytes())?; - packet_size - skip - }; - - let packet_data = { - let mut data = vec![0; to_read]; - stream.read_exact(&mut data)?; - data.retain(|x| *x != 0); - while String::from_utf8_lossy(&data).len() != to_read { - let mut buf = vec![0; to_read - data.len()]; - stream.read_exact(&mut buf)?; - data.append(&mut buf); - data.retain(|x| *x != 0); - } - String::from_utf8_lossy(&data).to_string() - }; - - // println!("{}", packet_data); - - Ok(packet_data) -} - -fn print_console(messages: Vec<&str>) -> Result<(), Box> { - let mut messages = messages.clone(); - messages.reverse(); - messages.truncate(MAX_MESSAGES); - messages.reverse(); - let mut out = stdout().lock(); - let text = format!("{}{}\n> ", "\n".repeat(MAX_MESSAGES - messages.len()), messages.join("\n")); - out.write_all(text.as_bytes())?; - out.flush()?; - Ok(()) -} - -fn recv_loop(host: &str) -> Result<(), Box> { - let mut cache = String::new(); - while let Ok(messages) = read_messages(host, cache.len()) { - if messages.len() == 0 { continue } - cache.push_str(&messages); - print_console(cache.split("\n").collect())?; - } - Ok(()) -} - -fn get_input(prompt: &str, default: &str) -> String { - let input = || -> Option { - let mut out = stdout().lock(); - out.write_all(prompt.as_bytes()).ok()?; - out.flush().ok()?; - stdin().lock().lines().next() - .map(|o| o.ok()) - .flatten() - }(); - - if let Some(input) = &input { - if input.is_empty() { - default - } else { - input - } - } else { - default - }.to_string() -} - -fn main() { - let host = get_input(&format!("Host (default: {}) > ", DEFAULT_HOST), DEFAULT_HOST); - - let anon_name = format!("Anon#{:X}", SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs()); - - let name = get_input(&format!("Name (default: {}) > ", anon_name), &anon_name); - - thread::spawn({ - let host = host.clone(); - - move || { - let _ = recv_loop(&host); - println!("Connection closed"); - } - }); - - let mut lines = stdin().lock().lines(); - while let Some(Ok(message)) = lines.next() { - send_message(&host, &format!("<{}> {}", &name, &message)).expect("Error sending message"); - } -} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..dad69ac --- /dev/null +++ b/src/main.rs @@ -0,0 +1,162 @@ +use std::{error::Error, fmt::format, fs, io::{stdin, stdout, BufRead, Read, Write}, net::TcpStream, sync::{Arc, RwLock}, thread, time::{self, Duration, SystemTime, UNIX_EPOCH}}; + +use rand::random; +use termion::{event::Key, input::TermRead, raw::IntoRawMode}; + +const MAX_MESSAGES: usize = 100; +const DEFAULT_HOST: &str = "meex.lol:11234"; + +fn send_message(host: &str, message: &str) -> Result<(), Box> { + let mut stream = TcpStream::connect(host)?; + stream.write_all(&[0x01])?; + stream.write_all(message.as_bytes())?; + stream.write_all("\0".repeat(1023 - message.len()).as_bytes())?; + Ok(()) +} + +fn skip_null(stream: &mut TcpStream) -> Result, Box> { + loop { + let mut buf = vec![0; 1]; + stream.read_exact(&mut buf)?; + if buf[0] != 0 { + break Ok(buf) + } + } +} + +fn read_messages(host: &str) -> Result> { + let mut stream = TcpStream::connect(host)?; + + stream.write_all(&[0x00])?; + + let packet_size = { + let mut data = skip_null(&mut stream)?; + + loop { + let mut buf = vec![0; 1]; + stream.read_exact(&mut buf)?; + let ch = buf[0]; + if ch == 0 { + break + } + data.push(ch); + } + + String::from_utf8(data)? + .trim_matches(char::from(0)) + .parse()? + }; + + // println!("{} {}", skip, packet_size); + stream.write_all(&[0x01])?; + + let packet_data = { + let mut data = skip_null(&mut stream)?; + while data.len() < packet_size { + let mut buf = vec![0; packet_size - data.len()]; + let read_bytes = stream.read(&mut buf)?; + buf.truncate(read_bytes); + data.append(&mut buf); + } + String::from_utf8_lossy(&data).to_string() + }; + + Ok(packet_data) +} + +fn recv_loop(host: &str, cache: Arc>, input: Arc>) -> Result<(), Box> { + while let Ok(data) = read_messages(host) { + if data == cache.read().unwrap().clone() { + continue + } + + *cache.write().unwrap() = data; + print_console(&cache.read().unwrap(), &input.read().unwrap())?; + } + Ok(()) +} + +fn get_input(prompt: &str, default: &str) -> String { + let input = || -> Option { + let mut out = stdout().lock(); + out.write_all(prompt.as_bytes()).ok()?; + out.flush().ok()?; + stdin().lock().lines().next() + .map(|o| o.ok()) + .flatten() + }(); + + if let Some(input) = &input { + if input.is_empty() { + default + } else { + input + } + } else { + default + }.to_string() +} + +fn print_console(messages: &str, input: &str) -> Result<(), Box> { + let mut messages = messages.split("\n") + .map(|o| o.to_string()) + .collect::>(); + messages.reverse(); + messages.truncate(MAX_MESSAGES); + messages.reverse(); + let mut out = stdout().into_raw_mode()?; + let text = format!("{}{}\n> {}", "\n".repeat(MAX_MESSAGES - messages.len()), messages.join("\n"), input); + for line in text.lines() { + write!(out, "\r\n{}", line)?; + out.flush()?; + } + Ok(()) +} + +fn main() { + let host = get_input(&format!("Host (default: {}) > ", DEFAULT_HOST), DEFAULT_HOST); + let anon_name = format!("Anon#{:X}", random::()); + let name = get_input(&format!("Name (default: {}) > ", anon_name), &anon_name); + + let messages = Arc::new(RwLock::new(String::new())); + let input = Arc::new(RwLock::new(String::new())); + + thread::spawn({ + let host = host.clone(); + let messages = messages.clone(); + let input = input.clone(); + + move || { + let _ = recv_loop(&host, messages, input); + println!("Connection closed"); + } + }); + + let stdout = stdout().into_raw_mode().unwrap(); + + let stdin = stdin(); + for key in stdin.keys() { + match key.unwrap() { + Key::Char('\n') => { + let message = input.read().unwrap().clone(); + if !message.is_empty() { + send_message(&host, &format!("<{}> {}", name, message)).expect("Error sending message"); + input.write().unwrap().clear(); + } + } + Key::Backspace => { + input.write().unwrap().pop(); + } + Key::Char(c) => { + input.write().unwrap().push(c); + } + Key::Esc => break, + Key::Ctrl('c') => break, + Key::Ctrl('z') => break, + Key::Ctrl('x') => break, + _ => {} + } + + print_console(&messages.read().unwrap(), &input.read().unwrap()).expect("Error printing console"); + } +} diff --git a/test.txt b/test.txt new file mode 100644 index 0000000..040ab53 --- /dev/null +++ b/test.txt @@ -0,0 +1 @@ +[2025-02-09 10:40:02] {192.168.0.201} Извините, я при ап \ No newline at end of file