mirror of https://github.com/fafhrd91/actix-net
				
				
				
			
		
			
				
	
	
		
			99 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Rust
		
	
	
	
			
		
		
	
	
			99 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Rust
		
	
	
	
//! Simple file-reader TCP server with framed stream.
 | 
						|
//!
 | 
						|
//! Using the following command:
 | 
						|
//!
 | 
						|
//! ```sh
 | 
						|
//! nc 127.0.0.1 8080
 | 
						|
//! ```
 | 
						|
//!
 | 
						|
//! Follow the prompt and enter a file path, relative or absolute.
 | 
						|
 | 
						|
#![allow(missing_docs)]
 | 
						|
 | 
						|
use std::io;
 | 
						|
 | 
						|
use actix_codec::{Framed, LinesCodec};
 | 
						|
use actix_rt::net::TcpStream;
 | 
						|
use actix_server::Server;
 | 
						|
use actix_service::{fn_service, ServiceFactoryExt as _};
 | 
						|
use futures_util::{SinkExt as _, StreamExt as _};
 | 
						|
use tokio::{fs::File, io::AsyncReadExt as _};
 | 
						|
 | 
						|
async fn run() -> io::Result<()> {
 | 
						|
    pretty_env_logger::formatted_timed_builder()
 | 
						|
        .parse_env(pretty_env_logger::env_logger::Env::default().default_filter_or("info"));
 | 
						|
 | 
						|
    let addr = ("127.0.0.1", 8080);
 | 
						|
    tracing::info!("starting server on port: {}", &addr.0);
 | 
						|
 | 
						|
    // Bind socket address and start worker(s). By default, the server uses the number of physical
 | 
						|
    // CPU cores as the worker count. For this reason, the closure passed to bind needs to return
 | 
						|
    // a service *factory*; so it can be created once per worker.
 | 
						|
    Server::build()
 | 
						|
        .bind("file-reader", addr, move || {
 | 
						|
            fn_service(move |stream: TcpStream| async move {
 | 
						|
                // set up codec to use with I/O resource
 | 
						|
                let mut framed = Framed::new(stream, LinesCodec::default());
 | 
						|
 | 
						|
                loop {
 | 
						|
                    // prompt for file name
 | 
						|
                    framed.send("Type file name to return:").await?;
 | 
						|
 | 
						|
                    // wait for next line
 | 
						|
                    match framed.next().await {
 | 
						|
                        Some(Ok(line)) => {
 | 
						|
                            match File::open(&line).await {
 | 
						|
                                Ok(mut file) => {
 | 
						|
                                    tracing::info!("reading file: {}", &line);
 | 
						|
 | 
						|
                                    // read file into String buffer
 | 
						|
                                    let mut buf = String::new();
 | 
						|
                                    file.read_to_string(&mut buf).await?;
 | 
						|
 | 
						|
                                    // send String into framed object
 | 
						|
                                    framed.send(buf).await?;
 | 
						|
 | 
						|
                                    // break out of loop and
 | 
						|
                                    break;
 | 
						|
                                }
 | 
						|
                                Err(err) => {
 | 
						|
                                    tracing::error!("{}", err);
 | 
						|
                                    framed
 | 
						|
                                        .send("File not found or not readable. Try again.")
 | 
						|
                                        .await?;
 | 
						|
                                    continue;
 | 
						|
                                }
 | 
						|
                            };
 | 
						|
                        }
 | 
						|
 | 
						|
                        // not being able to read a line from the stream is unrecoverable
 | 
						|
                        Some(Err(err)) => return Err(err),
 | 
						|
 | 
						|
                        // This EOF won't be hit.
 | 
						|
                        None => continue,
 | 
						|
                    }
 | 
						|
                }
 | 
						|
 | 
						|
                // close connection after file has been copied to TCP stream
 | 
						|
                Ok(())
 | 
						|
            })
 | 
						|
            .map_err(|err| tracing::error!("service error: {:?}", err))
 | 
						|
        })?
 | 
						|
        .workers(2)
 | 
						|
        .run()
 | 
						|
        .await
 | 
						|
}
 | 
						|
 | 
						|
#[tokio::main]
 | 
						|
async fn main() -> io::Result<()> {
 | 
						|
    run().await?;
 | 
						|
    Ok(())
 | 
						|
}
 | 
						|
 | 
						|
// alternatively:
 | 
						|
// #[actix_rt::main]
 | 
						|
// async fn main() -> io::Result<()> {
 | 
						|
//     run().await?;
 | 
						|
//     Ok(())
 | 
						|
// }
 |