s5x 0.1.1

SOCKS5 proxy server
#![warn(clippy::pedantic)]

mod socks5;
mod prelude;

use prelude::*;
use tokio::net::TcpListener;
use tracing_subscriber::fmt;
use crate::socks5::{config::Config, session::Socks5Session};

#[tokio::main]
async fn main() -> Result<(), AppError> {
    setup_tracing();

    let mut config = Config::new()?;
    config.validate()?;

    let listener = TcpListener::bind(format!("{}:{}", config.host, config.port)).await
        .map_err(|_| AppError::Socks5(format!("port {} is busy or cannot be used", config.port)))?;

    info!(config = ?config, "socks5 started");

    loop {
        let config = config.clone();
        let (stream, client_addr) = listener.accept().await?;
        info!(%client_addr, "new connection");
        tokio::spawn(async move {
            let mut session = Socks5Session::new(config, stream);
            if let Err(error) = session.start().await {
                error!(%error, %client_addr);
            }
            info!(%client_addr, "connection closed");
        });
    }
}

#[cfg(debug_assertions)]
fn setup_tracing() {
    use tracing::Level;

    fmt()
        .with_target(false)
        .with_max_level(Level::TRACE)
        .init();
}

#[cfg(not(debug_assertions))]
fn setup_tracing() {
    use tracing_subscriber::EnvFilter;

    fmt()
        .with_target(false)
        .with_env_filter(
            EnvFilter::try_from_default_env()
                .unwrap_or_else(|_| EnvFilter::new("s5x=info"))
        )
        .init();
}