mirror of
https://github.com/fafhrd91/actix-net
synced 2024-11-27 20:12:58 +01:00
126ed4c2e3
Co-authored-by: Rob Ede <robjtede@icloud.com>
96 lines
3.2 KiB
Rust
96 lines
3.2 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.
|
|
|
|
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<()> {
|
|
env_logger::init_from_env(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(())
|
|
// }
|