telnetd implementing more stuff.
This commit is contained in:
@@ -1,3 +1,50 @@
|
||||
fn main() {
|
||||
println!("Taxation is Theft");
|
||||
use std::io::{BufRead, BufReader, Write};
|
||||
use std::net::{TcpListener, TcpStream};
|
||||
use std::thread;
|
||||
use gemma::chip8::computer_manager::Chip8ComputerManager;
|
||||
use gemma::chip8::quirk_modes::QuirkMode;
|
||||
use gemmatelnet::client_handler::handle_client;
|
||||
use log::info;
|
||||
use clap::Parser;
|
||||
|
||||
const LISTEN_HOST: &str = "0.0.0.0";
|
||||
const LISTEN_PORT: u32 = 1420;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(name = "myapp")]
|
||||
#[command(about = "Does awesome things", long_about = None)]
|
||||
struct Cli {
|
||||
#[arg(long, default_value = "0.0.0.0")]
|
||||
host: Option<String>,
|
||||
#[arg(long, default_value = "1420")]
|
||||
port: Option<u32>,
|
||||
}
|
||||
|
||||
impl Cli {
|
||||
pub fn host(&self) -> String {
|
||||
self.host.clone().unwrap_or(LISTEN_HOST.into())
|
||||
}
|
||||
pub fn port(&self) -> u32 {
|
||||
self.port.unwrap_or(LISTEN_PORT.into())
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
let config = Cli::parse();
|
||||
|
||||
let listener = TcpListener::bind(format!("{}:{}", config.host(), config.port()))?;
|
||||
println!("Listening to {}:{}", LISTEN_HOST, LISTEN_PORT);
|
||||
|
||||
for stream in listener.incoming() {
|
||||
match stream {
|
||||
Ok(stream) => {
|
||||
thread::spawn(|| handle_client(stream));
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Connection Failed -> {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
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;
|
||||
|
||||
const CANT_NOTIFY_ERROR: &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
|
||||
menu -> display the menu
|
||||
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() {
|
||||
"status" => {
|
||||
message_to_send = chip8.status_as_string();
|
||||
}
|
||||
"disconnect" => {
|
||||
message_to_send = "Disconnecting User".to_string();
|
||||
time_to_die = true;
|
||||
break;
|
||||
}
|
||||
"new" => {
|
||||
message_to_send = "Starting new Chip-8 Instance".to_string();
|
||||
chip8.reset(QuirkMode::Chip8);
|
||||
}
|
||||
"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())
|
||||
)
|
||||
);
|
||||
}
|
||||
"load" => {
|
||||
|
||||
// chip8 = Chip8ComputerManager::from(chip8).load_new_program_to_system_memory()
|
||||
message_to_send = format!("Preparing to load {} from disk.",
|
||||
p1.unwrap_or("default.ch8").trim());
|
||||
chip8.start();
|
||||
}
|
||||
"menu" => {
|
||||
message_to_send = MENU_TEXT.to_string();
|
||||
}
|
||||
"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();
|
||||
}
|
||||
}
|
||||
"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();
|
||||
}
|
||||
}
|
||||
"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(CANT_NOTIFY_ERROR);
|
||||
|
||||
stream.flush().unwrap();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
pub mod telnet_utils;
|
||||
pub mod client_handler;
|
||||
@@ -0,0 +1,18 @@
|
||||
use std::{fs, io};
|
||||
use std::path::Path;
|
||||
|
||||
pub fn list_of_files_in_directory(root_directory: &Path) -> String {
|
||||
|
||||
let mut return_value = String::new();
|
||||
|
||||
if root_directory.is_dir() {
|
||||
for entry in fs::read_dir(root_directory).unwrap() {
|
||||
let entry = entry.unwrap();
|
||||
let path = entry.path();
|
||||
if path.is_file() {
|
||||
return_value = format!("{}\n{}", return_value, path.file_name().unwrap().to_string_lossy());
|
||||
}
|
||||
}
|
||||
}
|
||||
return_value
|
||||
}
|
||||
Reference in New Issue
Block a user