tina-core 0.0.2

Tina platform
Documentation
//! 服务器server mod
pub mod application;
pub mod grpc;
pub mod http;
pub mod session;

use crate::tina::data::number::RandomNumber;
use crate::tina::server::application::{AppConfig, Application};
use crate::tina::{data::AppResult, util::not_empty::INotEmpty};
use config::Config;
use futures_util::future::BoxFuture;
use futures_util::FutureExt;
use once_cell::sync::Lazy;
use std::{future::Future, net::SocketAddr, str::FromStr, sync::Mutex};

/// 初始化
pub type ServerInitFunction = Box<dyn FnOnce(AppConfig, Config) -> BoxFuture<'static, AppResult<AppConfig>> + Send>;
/// 后初始化
pub type ServerPostInitFuction = Box<dyn FnOnce(Application) -> BoxFuture<'static, AppResult<()>> + Send>;
/// 后初始化
pub type ServerAfterStartFuction = Box<dyn FnOnce(Application) -> BoxFuture<'static, AppResult<()>> + Send>;
/// shutdown钩子
pub type ServerShutdownHook = Box<dyn FnOnce(Application) -> BoxFuture<'static, AppResult<()>> + Send>;

/// 自定义HttpServer
pub struct Server {
    init: Option<ServerInitFunction>,
    post_init: Option<ServerPostInitFuction>,
    after_start: Option<ServerAfterStartFuction>,
    shutdown_hook: Option<ServerShutdownHook>,
}

impl Default for Server {
    fn default() -> Self {
        Self::new()
    }
}

impl Server {
    /// 构建
    pub fn new() -> Server {
        Server {
            init: None,
            post_init: None,
            after_start: None,
            shutdown_hook: None,
        }
    }

    /// 启动前初始化
    pub fn init<F, R>(mut self, f: F) -> Self
    where
        F: FnOnce(AppConfig, Config) -> R + Send + 'static,
        R: Future<Output = AppResult<AppConfig>> + Send + 'static,
    {
        self.init = Some(Box::new(box_fn2(f)));
        self
    }

    /// 启动后初始化
    pub fn post_init<F, R>(mut self, f: F) -> Self
    where
        F: FnOnce(Application) -> R + Send + 'static,
        R: Future<Output = AppResult<()>> + Send + 'static,
    {
        self.post_init = Some(Box::new(box_fn(f)));
        self
    }

    /// 启动成功后执行
    pub fn after_start<F, R>(mut self, f: F) -> Self
    where
        F: FnOnce(Application) -> R + Send + 'static,
        R: Future<Output = AppResult<()>> + Send + 'static,
    {
        self.after_start = Some(Box::new(box_fn(f)));
        self
    }

    /// 设置系统停止时的调用
    pub fn with_shutdown_hook<F, R>(mut self, f: F) -> Self
    where
        F: FnOnce(Application) -> R + Send + 'static,
        R: Future<Output = AppResult<()>> + Send + 'static,
    {
        self.shutdown_hook = Some(Box::new(box_fn(f)));
        self
    }
}

fn box_fn<T, F, Arg, R>(f: F) -> impl FnOnce(Arg) -> BoxFuture<'static, R>
where
    T: Future<Output = R> + Send + 'static,
    F: FnOnce(Arg) -> T + Send + 'static,
    Arg: Send + 'static,
    R: Send + 'static,
{
    move |arg: Arg| async move { f(arg).await }.boxed()
}

fn box_fn2<T, F, Arg1, Arg2, R>(f: F) -> impl FnOnce(Arg1, Arg2) -> BoxFuture<'static, R>
where
    T: Future<Output = R> + Send + 'static,
    F: FnOnce(Arg1, Arg2) -> T + Send + 'static,
    Arg1: Send + 'static,
    Arg2: Send + 'static,
    R: Send + 'static,
{
    move |arg1, arg2| async move { f(arg1, arg2).await }.boxed()
}

/// 随机端口
pub fn random_address_and_port(address: &str) -> SocketAddr {
    static CACHE: Lazy<Mutex<Vec<i32>>> = Lazy::new(|| Mutex::new(vec![]));
    loop {
        let port = i32::random(10000, 60000);
        {
            let mut cache = CACHE.lock().expect("locl cache failed");
            if cache.contains(&port) {
                continue;
            }
            cache.push(port);
        }
        let address = address.trim();
        let address = match address.not_empty() {
            true => address,
            false => "0.0.0.0",
        };
        if let Ok(addr) = SocketAddr::from_str(format!("{address}:{port}").as_str()) {
            return addr;
        }
        std::thread::sleep(std::time::Duration::from_millis(25));
    }
}