use std::net::{TcpListener, SocketAddr, IpAddr, Ipv4Addr, TcpStream};
use std::process::Command;
use std::borrow::Borrow;
use std::error::Error;
pub mod http;
pub mod file;
use http::{ Request, Response };
use std::io::{Read, Write};
const DEFAULT_BUFFER_SIZE: usize = 4096;
pub fn run_server<F>(views_handler: F) where
F: Fn(Request) -> Response,
F: Send + Copy + 'static {
let localhost = SocketAddr::new(
IpAddr::V4(Ipv4Addr::new(127,0,0,1)), 0);
let listener = TcpListener::bind(localhost)
.expect("Cannot allocate available port.");
try_open_in_browser(listener.borrow());
for stream in listener.incoming() {
match stream { Err(_) => (), Ok(stream) => {
match handle_connection(stream, views_handler) {
Ok(_) => (), Err(_) => (),
};
}, };
}
}
fn handle_connection<F>(mut stream: TcpStream, views_handler: F)
-> Result<(), Box<dyn Error>> where
F: Fn(Request) -> Response,
F: Send + Copy + 'static {
let mut buffer = [0u8; DEFAULT_BUFFER_SIZE];
stream.read(& mut buffer)?;
let request = String::from_utf8(buffer.to_vec())?;
let request_object = Request::from(request.as_str());
let response = views_handler(request_object).to_string();
stream.write(response.as_bytes())?;
stream.flush()?;
Ok(())
}
fn try_open_in_browser(listener_borrow: &TcpListener) {
let address_url = listener_borrow.local_addr()
.expect("Cannot get server address.").to_string();
let address_string = format!("http://{}", address_url);
let address_str = address_string.as_str();
match try_call_system_command(address_str) {
Ok(()) => println!(
"If your browser is not opened,\n\
please visit {} in your browser.", address_str
),
Err(_) => println!(
"Cannot open in browser automatically.\n\
Please visit {} in your browser.", address_str
)
}
fn try_call_system_command(address: &str)
-> Result<(), Box<dyn Error>> {
match std::env::consts::OS {
"windows" => { Command::new("powershell")
.arg("start").arg(address).output()?; },
"macos" => { Command::new("terminal")
.arg("open").arg(address).output()?; },
"linux" => { Command::new("terminal")
.arg("curl").arg(address).output()?; },
_ => { println!("Unsupported Operation System..."); },
}; Ok(())
}
}