Skip to content

Commit 3f8cafd

Browse files
authored
feat(server): use cli structure and start subcommand (#451)
1 parent cdebf9c commit 3f8cafd

File tree

6 files changed

+95
-38
lines changed

6 files changed

+95
-38
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
mod start;
2+
3+
use clap::Parser;
4+
5+
use self::start::StartOpt;
6+
7+
#[derive(Debug, Parser)]
8+
pub enum Command {
9+
/// Start the HTTP server
10+
Start(StartOpt),
11+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
use std::net::IpAddr;
2+
use std::process::exit;
3+
use std::sync::Arc;
4+
5+
use anyhow::Result;
6+
use clap::Parser;
7+
use tokio::runtime::Builder;
8+
use tracing::{error, info};
9+
10+
use crate::config::Config;
11+
use crate::server::Server;
12+
13+
const THREAD_NAME: &str = "http-server";
14+
15+
#[derive(Debug, Parser)]
16+
pub struct StartOpt {
17+
/// Host (IP) to bind the server
18+
#[clap(long, default_value = "0.0.0.0")]
19+
pub host: IpAddr,
20+
/// Port to bind the server
21+
#[clap(short = 'p', long, default_value = "7878")]
22+
pub port: u16,
23+
}
24+
25+
impl StartOpt {
26+
pub fn exec(&self) -> Result<()> {
27+
let rt = Builder::new_multi_thread()
28+
.enable_all()
29+
.thread_name(THREAD_NAME)
30+
.build()?;
31+
let rt = Arc::new(rt);
32+
let config = Config {
33+
host: self.host,
34+
port: self.port,
35+
};
36+
let server = Server::new(config);
37+
38+
rt.block_on(async {
39+
match server.run(Arc::clone(&rt)).await {
40+
Ok(_) => {
41+
info!("Server exited successfuly");
42+
Ok(())
43+
}
44+
Err(error) => {
45+
error!(%error, "Server exited with error");
46+
exit(1);
47+
}
48+
}
49+
})
50+
}
51+
}
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1-
use std::net::IpAddr;
1+
pub mod command;
22

33
use clap::Parser;
44

5+
use self::command::Command;
6+
57
#[derive(Debug, Parser)]
68
#[command(
79
name = "http-server",
810
author = "Esteban Borai <[email protected]>",
9-
about = "Simple and configurable command-line HTTP server\nSource: https://github.com/EstebanBorai/http-server",
10-
next_line_help = true
11+
about = "Simple and configurable command-line HTTP server\nSource: https://github.com/http-server-rs/http-server"
1112
)]
1213
pub struct Cli {
13-
pub host: IpAddr,
14-
pub port: u16,
14+
#[command(subcommand)]
15+
pub command: Command,
1516
}

crates/http-server/src/config.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use std::net::IpAddr;
22

33
pub struct Config {
4+
/// The IP address to bind to.
45
pub host: IpAddr,
6+
/// The port to bind to.
57
pub port: u16,
68
}

crates/http-server/src/main.rs

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,21 @@ pub mod config;
33
pub mod plugin;
44
pub mod server;
55

6-
use std::{process::exit, sync::Arc};
7-
86
use anyhow::Result;
9-
use tokio::runtime::Builder;
7+
use clap::Parser;
108

11-
use self::server::Server;
9+
use self::cli::command::Command;
10+
use self::cli::Cli;
1211

1312
fn main() -> Result<()> {
14-
let rt = Builder::new_multi_thread()
15-
.enable_all()
16-
.thread_name("http-server")
17-
.build()?;
18-
let rt = Arc::new(rt);
19-
2013
tracing_subscriber::fmt()
2114
.with_max_level(tracing::Level::DEBUG)
2215
.init();
16+
let args = Cli::parse();
17+
18+
match args.command {
19+
Command::Start(opt) => opt.exec()?,
20+
}
2321

24-
rt.block_on(async {
25-
match Server::run(Arc::clone(&rt)).await {
26-
Ok(_) => {
27-
println!("Server exited successfuly");
28-
Ok(())
29-
}
30-
Err(error) => {
31-
eprint!("{:?}", error);
32-
exit(1);
33-
}
34-
}
35-
})
22+
Ok(())
3623
}

crates/http-server/src/server/mod.rs

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
use std::{convert::Infallible, net::SocketAddr, path::PathBuf, str::FromStr, sync::Arc};
1+
use std::convert::Infallible;
2+
use std::net::SocketAddr;
3+
use std::path::PathBuf;
4+
use std::str::FromStr;
5+
use std::sync::Arc;
26

37
use anyhow::Result;
48
use http_body_util::{BodyExt, Full};
@@ -7,28 +11,32 @@ use hyper::{
711
server::conn::http1,
812
Method, Request, Response,
913
};
10-
use hyper_util::{rt::TokioIo, service::TowerToHyperService};
14+
use hyper_util::rt::TokioIo;
15+
use hyper_util::service::TowerToHyperService;
1116
use tokio::net::TcpListener;
1217
use tokio::runtime::Runtime;
1318
use tower::ServiceBuilder;
1419
use tower_http::cors::{Any, CorsLayer};
15-
use tracing::info;
1620

21+
use crate::config::Config;
1722
use crate::plugin::ExternalFunctions;
1823

19-
pub struct Server {}
24+
pub struct Server {
25+
config: Config,
26+
}
2027

2128
impl Server {
22-
pub async fn run(rt: Arc<Runtime>) -> Result<()> {
23-
info!("Initializing server");
29+
pub fn new(config: Config) -> Self {
30+
Server { config }
31+
}
2432

25-
let addr = SocketAddr::from(([0, 0, 0, 0], 3000));
33+
pub async fn run(self, rt: Arc<Runtime>) -> Result<()> {
34+
let addr = SocketAddr::from((self.config.host, self.config.port));
2635
let listener = TcpListener::bind(addr).await?;
2736
let functions = Arc::new(ExternalFunctions::new());
2837
let plugin_library = PathBuf::from_str("./target/debug/libfile_explorer.dylib").unwrap();
2938
let config = PathBuf::from_str("./config.toml").unwrap();
3039
let handle = Arc::new(rt.handle().to_owned());
31-
let local_ip = local_ip_address::local_ip();
3240

3341
unsafe {
3442
functions
@@ -37,9 +45,6 @@ impl Server {
3745
.expect("Function loading failed");
3846
}
3947

40-
info!(%addr, "Server Listening");
41-
info!(?local_ip, "Local Network");
42-
4348
loop {
4449
let (stream, _) = listener.accept().await?;
4550
let io = TokioIo::new(stream);

0 commit comments

Comments
 (0)