mirror of
https://github.com/MeexReay/bRAC.git
synced 2025-05-06 13:38:04 +03:00
fix console and other stuff
This commit is contained in:
parent
881b253e07
commit
8b64a2e1c3
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,3 +1 @@
|
|||||||
main
|
|
||||||
main.exe
|
|
||||||
/target
|
/target
|
282
Cargo.lock
generated
282
Cargo.lock
generated
@ -5,3 +5,285 @@ version = 4
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "bRAC"
|
name = "bRAC"
|
||||||
version = "1.99.2"
|
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",
|
||||||
|
]
|
||||||
|
@ -4,7 +4,5 @@ version = "1.99.2"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
rand = "0.9.0"
|
||||||
[[bin]]
|
termion = "4.0.3"
|
||||||
name = "bRAC"
|
|
||||||
path = "main.rs"
|
|
@ -4,8 +4,6 @@ better RAC client
|
|||||||
## how to use
|
## how to use
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
rustc main.rs # build
|
cargo build # build
|
||||||
./main # run
|
cargo run # run
|
||||||
cargo build # build with cargo
|
|
||||||
cargo run # run with cargo
|
|
||||||
```
|
```
|
133
main.rs
133
main.rs
@ -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<dyn Error>> {
|
|
||||||
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<String, Box<dyn Error>> {
|
|
||||||
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<dyn Error>> {
|
|
||||||
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<dyn Error>> {
|
|
||||||
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<String> {
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
162
src/main.rs
Normal file
162
src/main.rs
Normal file
@ -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<dyn Error>> {
|
||||||
|
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<Vec<u8>, Box<dyn Error>> {
|
||||||
|
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<String, Box<dyn Error>> {
|
||||||
|
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<RwLock<String>>, input: Arc<RwLock<String>>) -> Result<(), Box<dyn Error>> {
|
||||||
|
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<String> {
|
||||||
|
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<dyn Error>> {
|
||||||
|
let mut messages = messages.split("\n")
|
||||||
|
.map(|o| o.to_string())
|
||||||
|
.collect::<Vec<String>>();
|
||||||
|
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::<u16>());
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user