diff options
Diffstat (limited to 'src/bin/client.rs')
| -rw-r--r-- | src/bin/client.rs | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/src/bin/client.rs b/src/bin/client.rs new file mode 100644 index 0000000..45c5090 --- /dev/null +++ b/src/bin/client.rs | |||
| @@ -0,0 +1,98 @@ | |||
| 1 | use std::io::{BufRead, BufReader, Write, stdin, stdout}; | ||
| 2 | use std::net::TcpStream; | ||
| 3 | use std::time::Instant; | ||
| 4 | |||
| 5 | #[cfg(windows)] | ||
| 6 | mod win { | ||
| 7 | use std::io; | ||
| 8 | use std::os::windows::io::AsRawHandle; | ||
| 9 | use winapi::um::consoleapi::GetConsoleMode; | ||
| 10 | use winapi::um::consoleapi::SetConsoleMode; | ||
| 11 | use winapi::um::wincon::ENABLE_VIRTUAL_TERMINAL_PROCESSING; | ||
| 12 | use winapi::um::winbase::STD_OUTPUT_HANDLE; | ||
| 13 | use winapi::um::processenv::GetStdHandle; | ||
| 14 | use winapi::shared::minwindef::DWORD; | ||
| 15 | |||
| 16 | pub fn enable_vt() -> io::Result<()> { | ||
| 17 | unsafe { | ||
| 18 | let h = GetStdHandle(STD_OUTPUT_HANDLE); | ||
| 19 | if h.is_null() { return Err(io::Error::last_os_error()); } | ||
| 20 | |||
| 21 | let mut mode: DWORD = 0; | ||
| 22 | if GetConsoleMode(h, &mut mode) == 0 { | ||
| 23 | return Err(io::Error::last_os_error()); | ||
| 24 | } | ||
| 25 | let new = mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING; | ||
| 26 | if SetConsoleMode(h, new) == 0 { | ||
| 27 | return Err(io::Error::last_os_error()); | ||
| 28 | } | ||
| 29 | Ok(()) | ||
| 30 | } | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | fn main() { | ||
| 35 | #[cfg(windows)] | ||
| 36 | win::enable_vt().unwrap(); | ||
| 37 | |||
| 38 | let mut addr: Option<String>; | ||
| 39 | let mut stream: Option<TcpStream> = None; | ||
| 40 | loop { | ||
| 41 | print!("Command: "); | ||
| 42 | stdout().flush().unwrap(); | ||
| 43 | let mut line = String::new(); | ||
| 44 | stdin().read_line(&mut line).unwrap(); | ||
| 45 | let line = line.trim(); | ||
| 46 | if line.is_empty() { | ||
| 47 | continue; | ||
| 48 | } | ||
| 49 | let parts: Vec<&str> = line.splitn(2, ' ').collect(); | ||
| 50 | match parts[0] { | ||
| 51 | "connect" => { | ||
| 52 | if parts.len() < 2 { | ||
| 53 | println!("Usage: connect <addr>"); | ||
| 54 | continue; | ||
| 55 | } | ||
| 56 | addr = Some(parts[1].to_string()); | ||
| 57 | match TcpStream::connect(addr.as_ref().unwrap()) { | ||
| 58 | Ok(s) => { | ||
| 59 | let mut ping_writer = s.try_clone().unwrap(); | ||
| 60 | let mut ping_reader = BufReader::new(s.try_clone().unwrap()); | ||
| 61 | let start = Instant::now(); | ||
| 62 | writeln!(ping_writer, "PING").unwrap(); | ||
| 63 | let mut response = String::new(); | ||
| 64 | ping_reader.read_line(&mut response).unwrap(); | ||
| 65 | let elapsed = start.elapsed(); | ||
| 66 | println!("Connected to {} with ping delay: {:?}", addr.as_ref().unwrap(), elapsed); | ||
| 67 | stream = Some(s); | ||
| 68 | } | ||
| 69 | Err(e) => { | ||
| 70 | println!("Failed to connect: {}", e); | ||
| 71 | } | ||
| 72 | } | ||
| 73 | } | ||
| 74 | "send" => { | ||
| 75 | if stream.is_none() { | ||
| 76 | println!("Not connected. Use 'connect <addr>' first."); | ||
| 77 | continue; | ||
| 78 | } | ||
| 79 | if parts.len() < 2 { | ||
| 80 | println!("Usage: send <message>"); | ||
| 81 | continue; | ||
| 82 | } | ||
| 83 | let msg = parts[1]; | ||
| 84 | let s = stream.as_mut().unwrap(); | ||
| 85 | let writer_stream = s.try_clone().unwrap(); | ||
| 86 | let mut writer = writer_stream; | ||
| 87 | let response_reader_stream = s.try_clone().unwrap(); | ||
| 88 | let mut response_reader = BufReader::new(response_reader_stream); | ||
| 89 | writeln!(writer, "{}", msg).unwrap(); | ||
| 90 | let mut response = String::new(); | ||
| 91 | response_reader.read_line(&mut response).unwrap(); | ||
| 92 | println!("Echo: {}", response.trim()); | ||
| 93 | } | ||
| 94 | "quit" => break, | ||
| 95 | _ => println!("Unknown command. Available: connect, send, quit"), | ||
| 96 | } | ||
| 97 | } | ||
| 98 | } | ||
