Skip to content

Instantly share code, notes, and snippets.

@alex-s168
Created November 20, 2023 19:19
Show Gist options
  • Save alex-s168/7975bfb0b03021aca8c4bf355a2d2d9f to your computer and use it in GitHub Desktop.
Save alex-s168/7975bfb0b03021aca8c4bf355a2d2d9f to your computer and use it in GitHub Desktop.
rust basic read only file server
use std::net::{TcpListener,TcpStream,Shutdown};
use std::result::Result;
use std::io::{Write,Read,BufRead,BufReader};
use std::thread;
use std::io;
use std::process::exit;
use std::path::Path;
use std::fs::{File,read_dir};
use std::env;
fn client(mut stream: TcpStream) {
let _ = writeln!(stream, "hello").map_err(|err| {
eprintln!("ERR: could not send message to client: {err}");
});
let reader = BufReader::new(&stream);
for l in reader.lines() {
if l.is_err() {
continue;
}
let lx = l.unwrap();
let mut command = lx.split(' ');
let argc = command.to_owned().count();
if argc == 0 {
let _ = writeln!(&stream, "invalid cmd");
continue;
}
let inst = command.next().unwrap();
if inst == "quit" {
let _ = stream.shutdown(Shutdown::Both).map_err(|err| {
eprintln!("ERR: could not close connection (requested by client): {}", err);
});
return;
}
if argc < 2 {
let _ = writeln!(&stream, "invalid cmd");
continue;
}
let mut arg = String::new();
for _ in 1..argc {
arg.push_str(command.next().unwrap());
}
if inst == "file" {
let path = Path::new(&arg);
if !path.is_file() {
let _ = writeln!(&stream, "not a file");
continue;
}
let mut file = File::open(path).unwrap();
let len = file.metadata().unwrap().len() as usize;
let _ = writeln!(&stream, "len: {}", len);
let mut string = String::with_capacity(len);
if file.read_to_string(&mut string).is_err() {
let _ = writeln!(&stream, "error reading file");
continue;
}
let _ = writeln!(&stream, "{}", string);
}
else if inst == "list" {
let path = Path::new(&arg);
if !path.is_dir() {
let _ = writeln!(&stream, "not a directory");
continue;
}
let paths = read_dir(path).unwrap();
for p in paths {
let _ = writeln!(&stream, "{}", p.unwrap().path().display());
}
}
else {
let _ = writeln!(&stream, "invalid cmd");
}
}
}
fn main() -> Result<(), ()> {
let mut args = env::args();
let _ = args.next();
if args.len() != 1 {
eprintln!("Invalid arguments! Usage: [ip]:[port]");
exit(1);
}
let addr = args.next().unwrap();
let listener = TcpListener::bind(&addr).map_err(|err| {
eprintln!("ERR: Could not bind {addr} {err}");
})?;
let mut threads: Vec<thread::JoinHandle<_>> = Vec::new();
thread::spawn(|| {
let stdin = io::stdin();
let lines = stdin.lock().lines();
for line in lines {
let cmd = line.unwrap();
if cmd == "exit" {
exit(1);
}
else if cmd == "help" {
println!("exit Stops the server");
}
else {
println!("Enter \"help\" for a list of available commands!");
}
}
});
for stream in listener.incoming() {
if stream.is_err() {
eprintln!("ERR: broken stream");
continue;
}
threads.push(thread::spawn(|| client(stream.unwrap())));
}
Ok(())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment