use std::io::{BufRead, BufReader}; use std::net::TcpStream; use gemma::chip8::computer_manager::Chip8ComputerManager; use gemma::chip8::quirk_modes::QuirkMode; use crate::telnet_utils::list_of_files_in_directory; use std::io::Write; use std::path::Path; use gemma::constants::RESOURCES_ROOT; use crate::constants::*; const ERROR_CANT_NOTIFY: &str = "Unable to notify client"; const MENU_TEXT: &str = r#" --------------------------- status -> Current status of the Instance new -> Start New Instance * list -> list available files to load into Chip-8 Instance * load -> Load Chip-8 Program from server help -> display this help step -> step chip-8 machine 1 step * steps -> Step a fixed number of steps * memory -> dump current memory from chip-8 instance * video -> dump current video from chip-8 instance * window -> display a window of memory disconnect -> close connection --------------------------- "#; pub fn handle_client(mut stream: TcpStream) { // each client gets their own instance of a Chip-8 system let mut chip8 = Chip8ComputerManager::default(); let peer_addr = stream.peer_addr().unwrap(); println!("New CX From {}", peer_addr); let mut reader = BufReader::new(stream.try_clone().unwrap()); let mut line = String::new(); write!(stream, "Welcome to Gemma Telnet Server\n").unwrap(); write!(stream, "{}", MENU_TEXT).unwrap(); let mut time_to_die: bool = false; while !time_to_die { // clear the buffer line.clear(); // read from the client to the buffer let bytes = reader.read_line(&mut line).unwrap(); if bytes == 0 { println!("Connection closed by {}", peer_addr); break; } // display the message received eprint!("RX {}: {}", peer_addr, line); // split the line into (if params exist) let mut result = line.split(" "); let command = result.next().unwrap(); let p1 = result.next(); let p2 = result.next(); let mut message_to_send: String = "Unrecognized Command".to_string(); match command.trim() { CMD_STATUS => { message_to_send = chip8.status_as_string(); } CMD_DISCONNECT => { message_to_send = "Disconnecting User".to_string(); time_to_die = true; break; } CMD_NEW => { message_to_send = "Starting new Chip-8 Instance".to_string(); chip8.reset(QuirkMode::Chip8); } CMD_LIST => { message_to_send = format!("Listing files in path: \n{}", list_of_files_in_directory( &mut Path::new("/home/tmerritt/Projects/trevors_chip8_toy/resources/roms".into()) ) ); } CMD_LOAD => { let file_to_use = p1.unwrap_or("default.ch8").trim(); // chip8 = Chip8ComputerManager::from(chip8).load_new_program_to_system_memory() message_to_send = format!("Preparing to load {} from disk.", file_to_use); chip8.load_new_program_from_disk_to_system_memory( Path::new(format!("{}/roms/{}", RESOURCES_ROOT, file_to_use).as_str()) ); } CMD_HELP => { message_to_send = MENU_TEXT.to_string(); } CMD_STEPS => { if chip8.core_should_run { let num_steps = p1.unwrap_or("0").trim(); message_to_send = format!("Advancing {} steps.", num_steps); for _ in 0..num_steps.parse().unwrap_or(0) { chip8.tick(); } } else { message_to_send = "Not Ready to Step".to_string(); } } CMD_STEP => { if chip8.core_should_run { message_to_send = "Advancing 1 step.".to_string(); chip8.tick(); } else { message_to_send = "Not Ready To Step".to_string(); } } CMD_WINDOW => { message_to_send = format!("Memory window from {} to {}", p1.unwrap_or("0x0000").trim(), p2.unwrap_or("0xFFFF").trim()); } _ => {} } write!(stream, "{}\n", message_to_send).expect(ERROR_CANT_NOTIFY); stream.flush().unwrap(); } }