So we have this task at our school:
this requires us to use single thread and process. We can see that the PID is same so we are thinking that it is showing multiple tasks under the same process, tasks created by async_std::task::spawn as described in rust documentation.
here is the snippet of code that does that:
zero_path_buf: PathBuf,
server_configs: Vec<ServerConfig>,
) -> Result<(), Box<dyn Error>> {
let ports = match get_usize_unique_ports(&server_configs).await {
Ok(ports) => ports,
Err(e) => {
eprintln!("ERROR: Failed to get ports: {}", e);
return Err("Failed to get ports".into());
}
};
let server_address = "0.0.0.0";
for port in ports.clone() {
let addr: SocketAddr = match format!("{}:{}", server_address, port).parse() {
Ok(v) => v,
Err(e) => {
eprintln!("ERROR: Failed to parse 0.0.0.0:port into SocketAddr: {}", e);
return Err("Failed to parse 0.0.0.0:port into SocketAddr".into());
}
};
let listener = match TcpListener::bind(addr).await {
Ok(v) => v,
Err(e) => {
eprintln!("ERROR: Failed to bind addr: {}", e);
return Err("Failed to bind addr".into());
}
};
append_to_file(&format!("addr {}", addr)).await;
let zero_path_buf = zero_path_buf.clone();
let server_configs = server_configs.clone();
task::spawn(async move {
let cookies_storage: Arc<Mutex<HashMap<String, Cookie>>> =
Arc::new(Mutex::new(HashMap::new()));
listener
.incoming()
.for_each_concurrent(None, |stream| async {
let mut stream = match stream {
Ok(v) => v,
Err(e) => {
eprintln!("ERROR: Failed to get stream: {}", e);
return;
}
};
let mut server = Server {
cookies: cookies_storage.clone(),
cookies_check_time: SystemTime::now() + Duration::from_secs(60),
};
let mut headers_buffer: Vec<u8> = Vec::new();
let mut body_buffer: Vec<u8> = Vec::new();
let mut global_error_string = Status::Ok.to_string();
let mut response: Response<Vec<u8>> = Response::new(Vec::new());
let timeout = Duration::from_millis(3000);
let choosen_server_config = read_with_timeout(
timeout,
&mut stream,
&mut headers_buffer,
&mut body_buffer,
&server_configs,
&mut global_error_string,
)
.await;
let mut request = Request::new(Vec::new());
if global_error_string == Status::Ok.to_string() {
parse_raw_request(
headers_buffer,
body_buffer,
&mut request,
&mut global_error_string,
)
.await;
}
server.check_expired_cookies().await;
let (cookie_value, cookie_is_ok) = server
.extract_cookies_from_request_or_provide_new(&request)
.await;
if !cookie_is_ok {
global_error_string = Status::Invalid_Cookie.to_string();
}
if global_error_string == Status::Ok.to_string() {
response = handle_request(
&request,
cookie_value.clone(),
&zero_path_buf,
choosen_server_config.clone(),
&mut global_error_string,
)
.await;
}
check_custom_errors(
global_error_string,
&request,
cookie_value.clone(),
&zero_path_buf,
choosen_server_config.clone(),
&mut response,
)
.await;
match write_response_into_stream(&mut stream, response).await {
Ok(_) => {}
Err(e) => {
eprintln!("ERROR: Failed to write response into stream: {}", e);
return;
}
};
match stream.flush().await {
Ok(_) => {}
Err(e) => {
eprintln!("ERROR: Failed to flush stream: {}", e);
return;
}
};
match stream.shutdown(std::net::Shutdown::Both) {
Ok(_) => {}
Err(e) => {
eprintln!("ERROR: Failed to shutdown stream: {}", e);
}
}
})
.await;
});
}
println!("Server is listening at below http://ip:port pairs:");
let all_listeners: Vec<ServerListeningAt> = get_server_listening_ats(&server_configs).await;
for server_listening_at in all_listeners {
println!(
"http://{}:{} {}",
server_listening_at.server_address,
server_listening_at.ports.join(", "),
server_listening_at.server_name
);
}
async_std::task::sleep(Duration::from_secs(u64::MAX)).await;
Ok(())
}
Now you can see that we are spawning multiple tasks but not multiple threads.
However, there is a group of students who want to fail us on this. Should we fail?
