diff --git a/Cargo.toml b/Cargo.toml index c9c6905..246973f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,9 +18,9 @@ clap = "4.4.18" clap-num = "1.0.2" clap-verbosity-flag = "2.1.2" libpt = { version = "0.3.10", features = ["net"] } -threadpool = "1.8.1" +mio = { version = "0.8.10", features = ["net", "os-poll"] } +threadpool = { version = "1.8.1", optional = true } [features] -default = ["server", "client"] -client = [] -server = [] +default = ["server"] +server = ["dep:threadpool"] diff --git a/src/common/args.rs b/src/common/args.rs index 65a1085..9b39244 100644 --- a/src/common/args.rs +++ b/src/common/args.rs @@ -41,10 +41,17 @@ pub(crate) struct Cli { #[arg(long)] pub(crate) meta: bool, + // host a server instead of connecting to one #[cfg(feature = "server")] #[arg(short, long, default_value_t = false)] pub(crate) server: bool, + + // how much threads the server should use + #[cfg(feature = "server")] + #[arg(short, long, default_value_t = 4)] + pub(crate) threads: usize, + #[arg(short, long, default_value_t = Mode::Tcp, ignore_case = true)] pub(crate) mode: Mode, diff --git a/src/common/conf.rs b/src/common/conf.rs index 514f588..0756095 100644 --- a/src/common/conf.rs +++ b/src/common/conf.rs @@ -1,6 +1,6 @@ -use std::fmt::Display; -use clap::ValueEnum; use crate::common::args::Cli; +use clap::ValueEnum; +use std::fmt::Display; #[derive(Debug, Clone, Copy)] pub enum Mode { Tcp, @@ -37,13 +37,18 @@ impl Display for Mode { } } -pub(crate) struct Config { - cli: Cli, - addr: std::net::SocketAddr, +pub struct Config { + pub addr: std::net::SocketAddr, + pub mode: Mode, + pub threads: usize } impl Config { - pub fn new(cli: Cli, addr: std::net::SocketAddr) -> Self { - Config { cli, addr } + pub fn new(cli: &Cli) -> Self { + Config { + addr: cli.addr.clone(), + mode: cli.mode.clone(), + threads: cli.threads + } } } diff --git a/src/common/mod.rs b/src/common/mod.rs index 8d2493b..f4200ec 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -1,6 +1,2 @@ - pub mod args; -use args::*; - pub mod conf; -use conf::*; diff --git a/src/main.rs b/src/main.rs index 3b1d87d..0b621d9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ //! over a connection, while letting a server reply pong to //! every connection. But I had to make it for some reason. +use anyhow::Result; use libpt::log::*; mod client; @@ -11,15 +12,21 @@ mod server; use common::{args::Cli, conf::*}; -fn main() { +use crate::server::Server; + +fn main() -> Result<()> { let cli = Cli::cli_parse(); debug!("dumping cli args:\n{:#?}", cli); + + let cfg = Config::new(&cli); + #[cfg(feature = "server")] if cli.server { info!("starting server"); - - return; + Server::build(cfg)?.run()?; + return Ok(()); } // implicit else, so we can work without the server feature info!("starting client"); + Ok(()) } diff --git a/src/server/listener.rs b/src/server/listener.rs new file mode 100644 index 0000000..0abbcae --- /dev/null +++ b/src/server/listener.rs @@ -0,0 +1,6 @@ +use std::net::TcpListener; + +pub trait Listener {} +pub trait Stream {} + +impl Listener for TcpListener {} diff --git a/src/server/mod.rs b/src/server/mod.rs index e69de29..9aaf850 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -0,0 +1,66 @@ +#![cfg(feature = "server")] +use anyhow::Result; +use libpt::log::{error, info}; +use mio::{self, event::Event, net::TcpListener, Events, Interest, Poll, Token}; +use std::{ + io::{prelude::*, BufReader}, + time::Duration, +}; +use threadpool::ThreadPool; + +use crate::common::conf::{Config, Mode}; + +pub mod listener; +use listener::*; + +const EVENT_CAPACITY: usize = 128; +const SERVER: Token = Token(0); + +pub struct Server { + cfg: Config, + work: Poll, + events: Events, + pool: ThreadPool, + pub timeout: Option, + server: TcpListener, +} + +impl Server { + pub fn build(cfg: Config) -> Result { + let mut server = TcpListener::bind(cfg.addr)?; + let poll: Poll = Poll::new()?; + poll.registry() + .register(&mut server, SERVER, Interest::READABLE | Interest::WRITABLE); + let events: Events = Events::with_capacity(EVENT_CAPACITY); + let pool = ThreadPool::new(cfg.threads); + let timeout = Some(Duration::from_secs(5)); + Ok(Server { + cfg, + work: poll, + events, + pool, + timeout, + server, + }) + } + pub fn run(&mut self) -> Result<()> { + loop { + self.work.poll(&mut self.events, self.timeout)?; + for event in self.events.iter() { + // self.pool.execute(|| { + let result = self.handle_event(event); + if let Err(err) = result { + error!("Error while handling server event {:?}: {:?}", event, err); + } + // }); + } + } + } + + fn handle_event(&self, event: &Event) -> Result<()> { + dbg!(event); + let connection = self.server.accept()?; + info!("received a connection!"); + Ok(()) + } +}