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>;
pub type ServerShutdownHook = Box<dyn FnOnce(Application) -> BoxFuture<'static, AppResult<()>> + Send>;
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));
}
}