trevors_chip8_toy/gemmatelnet/src/client_handler.rs

132 lines
4.7 KiB
Rust

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 <filename> -> Load Chip-8 Program from server
help -> display this help
step -> step chip-8 machine 1 step
* steps <number> -> Step a fixed number of steps
* memory -> dump current memory from chip-8 instance
* video -> dump current video from chip-8 instance
* window <start> <length> -> 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 <command> <param1> <param2> (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();
}
}