sofie 0.0.3

🌟 The elegant full-stack web framework that makes Rust web development effortless
Documentation
use std::{fs::read_to_string, future::Future, path::Path};

use log::error;
use vetis::{
    config::{ListenerConfig, ServerConfig, VirtualHostConfig},
    errors::VetisError,
    server::{
        path::HandlerPath,
        virtual_host::{handler_fn, VirtualHost},
    },
    Vetis,
};

use crate::{config::Config, errors::SofieError};

pub static CONFIG: &str = "sofie.toml";

pub mod config;
pub mod errors;
mod tests;

pub type Request = vetis::Request;
pub type Response = vetis::Response;

pub struct App {
    config: Config,
    server: vetis::Vetis,
}

impl Default for App {
    fn default() -> Self {
        let config = if Path::exists(Path::new(CONFIG)) {
            let file = read_to_string(CONFIG);
            if let Ok(file) = file {
                let config = toml::from_str(&file);
                if let Ok(config) = config {
                    config
                } else {
                    error!("Failed to parse config file");
                    Config::default()
                }
            } else {
                Config::default()
            }
        } else {
            Config::default()
        };

        let port = config.port();
        let interface = config.interface();

        let listener_config = ListenerConfig::builder()
            .port(port)
            .interface(interface)
            .build();

        let server_config = ServerConfig::builder()
            .add_listener(listener_config)
            .build();

        App { config, server: Vetis::new(server_config) }
    }
}

impl App {
    pub async fn serve<H, Fut>(&mut self, handler: H) -> Result<(), SofieError>
    where
        H: Fn(Request) -> Fut + Clone + Send + Sync + 'static,
        Fut: Future<Output = Result<Response, VetisError>> + Send + Sync + 'static,
    {
        let localhost_config = VirtualHostConfig::builder()
            .hostname("localhost")
            .port(self.config.port())
            .build()
            .map_err(|e| SofieError::ServerStart(e.to_string()))?;

        let mut virtual_host = VirtualHost::new(localhost_config);
        virtual_host.add_path(
            HandlerPath::builder()
                .uri("/")
                .handler(handler_fn(move |_req| {
                    let value = handler.clone();
                    async move { value(_req).await }
                }))
                .build()
                .map_err(|e| SofieError::ServerStart(e.to_string()))?,
        );

        self.server
            .add_virtual_host(virtual_host)
            .await;

        let result = self
            .server
            .run()
            .await;

        if let Err(e) = result {
            error!("Failed to start server: {}", e);
            return Err(SofieError::ServerStart(e.to_string()));
        }

        Ok(())
    }
}