use crate::base_config::BaseConfig;
use crate::card_service::replay::RePlayClickHouseDB;
use crate::config::Config;
use crate::database;
use crate::database::mysql::{ConfigValueCache, GameSetting, GameSlotsLevel, SlotsBetRatios};
use crate::robot_service::RobotManager;
use crate::services::{BroadcastService, MasterService, ProxyService};
use crate::timer::{CommitReplayTimer, Timer, TimerManager};
use aqueue::{Actor, RwModel};
use once_cell::sync::{Lazy, OnceCell};
use std::collections::hash_map::Values;
use std::collections::HashMap;
use std::env::current_dir;
use std::path::{Path, PathBuf};
use std::{env, fs};
pub static CURRENT_EXE_PATH: Lazy<String> = Lazy::new(|| match env::current_exe() {
Ok(path) => {
if let Some(current_exe_path) = path.parent() {
return current_exe_path.to_string_lossy().to_string();
}
panic!("current_exe_path get error: is none");
}
Err(err) => panic!("current_exe_path get error:{err:?}"),
});
pub static DOTENV: Lazy<bool> = Lazy::new(|| dotenv::dotenv().is_ok());
#[cfg(feature = "remote_load")]
pub static PEM_FILE: Lazy<PathBuf> = Lazy::new(|| {
if *DOTENV {
let pem_file = env::var("cert").expect("env key cert not found!,Please write in .env file");
load_path(&pem_file)
} else {
let pem_file = env::var("cert").expect("env key cert not found!,Not found .env file");
load_path(&pem_file)
}
});
#[cfg(feature = "remote_load")]
pub static URL: Lazy<String> = Lazy::new(|| {
if *DOTENV {
env::var("url").expect("env url not found!,Please write in .env file")
} else {
env::var("url").expect("env url not found!,Not found .env file")
}
});
#[cfg(feature = "remote_load")]
pub static CONFIG: Lazy<Config> =
Lazy::new(|| CONFIG_CELL.get().expect("CONFIG_CELL not set!").clone());
#[cfg(feature = "remote_load")]
pub static CONFIG_CELL: OnceCell<Config> = OnceCell::new();
#[cfg(feature = "remote_load")]
pub async fn load_config() -> anyhow::Result<Config> {
let cert = fs::read(&*PEM_FILE).expect("read client_cert_key.pem file error");
let identity = reqwest::Identity::from_pem(&cert).expect("load client_cert_key.pem error");
let client = reqwest::Client::builder()
.use_rustls_tls()
.identity(identity)
.danger_accept_invalid_certs(true)
.danger_accept_invalid_hostnames(true)
.build()?;
let path = format!("{}/cfg/game/config.toml", *URL);
log::trace!("load config url:{path}");
let resp = client.get(&path).send().await?;
let context = resp.text().await?;
Config::load_config(&context)
}
#[cfg(feature = "remote_load")]
pub static BASE_CONFIG: Lazy<BaseConfig> = Lazy::new(|| {
BASE_CONFIG_CELL
.get()
.expect("BASE_CONFIG_CELL not set!")
.clone()
});
#[cfg(feature = "remote_load")]
pub static BASE_CONFIG_CELL: OnceCell<BaseConfig> = OnceCell::new();
#[cfg(feature = "remote_load")]
pub async fn load_base_config() -> anyhow::Result<BaseConfig> {
let cert = fs::read(&*PEM_FILE).expect("read client_cert_key.pem file error");
let identity = reqwest::Identity::from_pem(&cert).expect("load client_cert_key.pem error");
let client = reqwest::Client::builder()
.use_rustls_tls()
.identity(identity)
.danger_accept_invalid_certs(true)
.danger_accept_invalid_hostnames(true)
.build()?;
let game_dir = current_exe_dir_name();
let path = format!("{}/cfg/game/{game_dir}/base_config.toml", *URL);
log::trace!("load config url:{path}");
let resp = client.get(&path).send().await?;
let context = resp.text().await?;
BaseConfig::load_config(&context)
}
#[cfg(all(feature = "local_load", not(feature = "remote_load")))]
pub static BASE_CONFIG: Lazy<BaseConfig> = Lazy::new(|| {
BaseConfig::load_config(
&load_content("base_config.toml").expect("read base_config.toml file error"),
)
.expect("toml base_config.toml error")
});
#[cfg(all(feature = "local_load", not(feature = "remote_load")))]
pub static CONFIG: Lazy<Config> = Lazy::new(|| {
Config::load_config(&load_content("config.toml").expect("read config.toml file error"))
.expect("toml config.toml error")
});
pub static PROXY: Lazy<RwModel<ProxyService>> = Lazy::new(|| RwModel::new(ProxyService::default()));
pub static BROADCAST_SERVICE: Lazy<BroadcastService> = Lazy::new(|| BroadcastService);
pub static MASTER_SERVICE: Lazy<MasterService> =
Lazy::new(|| MasterService::new(BASE_CONFIG.master.clone()));
pub static DATABASE: Lazy<database::mysql::Database> =
Lazy::new(|| database::mysql::Database::new(&CONFIG.master_db).expect("load db error"));
pub static DB_CONFIG: Lazy<Actor<ConfigValueCache>> =
Lazy::new(|| Actor::new(ConfigValueCache::new()));
pub static REPLAY_DB: Lazy<Actor<RePlayClickHouseDB>> =
Lazy::new(|| Actor::new(RePlayClickHouseDB::new(&CONFIG.clickhouse_replay)));
pub static GAME_SETTING: OnceCell<GameSetting> = OnceCell::new();
pub static GAME_SLOT_LEVEL_SETTING: OnceCell<HashMap<i32, GameSlotsLevel>> = OnceCell::new();
pub static GAME_SLOT_BET_RATIOS: OnceCell<Vec<SlotsBetRatios>> = OnceCell::new();
pub static ROBOT_MANAGER: Lazy<Actor<RobotManager>> = Lazy::new(|| Actor::new(RobotManager::new()));
pub static TIMER_MANAGER: Lazy<TimerManager> = Lazy::new(|| {
let ts = vec![Box::new(CommitReplayTimer) as Box<dyn Timer>];
TimerManager::new(ts)
});
pub async fn load_db_setting() -> anyhow::Result<()> {
GAME_SETTING
.set(
DATABASE
.get_game_setting(BASE_CONFIG.base.server_id)
.await?,
)
.expect("GAME_SETTING reset");
log::info!("load db game setting info:{:?}", GAME_SETTING.get());
GAME_SLOT_LEVEL_SETTING
.set(
DATABASE
.load_slots_levels(GAME_SETTING.get().unwrap().game_id)
.await?
.into_iter()
.map(|info| (info.level_id, info))
.collect(),
)
.expect("GAME_SLOT_LEVEL_SETTING reset");
GAME_SLOT_BET_RATIOS
.set(
DATABASE
.load_slots_bet_ratios(GAME_SETTING.get().unwrap().game_id)
.await?,
)
.expect("GAME_SLOT_BET_RATIOS reset");
Ok(())
}
#[inline]
pub fn get_game_setting() -> &'static GameSetting {
unsafe { GAME_SETTING.get_unchecked() }
}
#[inline]
pub fn get_game_slot_level(level_id: i32) -> Option<&'static GameSlotsLevel> {
unsafe { GAME_SLOT_LEVEL_SETTING.get_unchecked().get(&level_id) }
}
#[inline]
pub fn game_slot_level_iter() -> Values<'static, i32, GameSlotsLevel> {
unsafe { GAME_SLOT_LEVEL_SETTING.get_unchecked().values() }
}
#[inline]
pub fn game_slot_bet_ratios() -> &'static [SlotsBetRatios] {
unsafe { GAME_SLOT_BET_RATIOS.get_unchecked() }
}
#[inline]
fn load_path(filename: &str) -> PathBuf {
let exe_path = format!("{}/{}", CURRENT_EXE_PATH.as_str(), filename);
let config_path = Path::new(&exe_path);
let path = {
if !config_path.exists() {
let json_path = format!(
"{}/{}",
current_dir().expect("not found current dir").display(),
filename
);
let path = Path::new(&json_path);
if !path.exists() {
let json_path = format!(
"{}/{}",
current_dir()
.expect("not found current dir")
.parent()
.expect("not found config file")
.display(),
filename
);
let path = Path::new(&json_path);
if !path.exists() {
panic!("not found config file:{path:?}");
} else {
path.to_path_buf()
}
} else {
path.to_path_buf()
}
} else {
config_path.to_path_buf()
}
};
path
}
#[inline]
pub fn load_content(filename: &str) -> std::io::Result<String> {
let path = load_path(filename);
fs::read_to_string(path)
}
#[inline]
pub fn current_exe_dir_name() -> String {
match env::current_exe() {
Ok(path) => {
if let Some(parent) = path.parent() {
if let Some(dir_name) = parent.file_name() {
return dir_name.to_string_lossy().to_string();
}
}
panic!("current_exe_dir_name get error: is none");
}
Err(err) => panic!("current_exe_dir_name get error:{err:?}"),
}
}
#[cfg(feature = "remote_load")]
pub async fn load_game_config() -> anyhow::Result<Vec<u8>> {
let cert = fs::read(&*PEM_FILE)?;
let identity = reqwest::Identity::from_pem(&cert)?;
let client = reqwest::Client::builder()
.use_rustls_tls()
.identity(identity)
.danger_accept_invalid_certs(true)
.danger_accept_invalid_hostnames(true)
.build()?;
let game_dir = current_exe_dir_name();
let path = format!("{}/cfg/game/{game_dir}/GameConfig.jsonc", *URL);
let resp = client.get(&path).send().await?;
let context = resp.bytes().await?;
Ok(context.to_vec())
}