233 lines
9.0 KiB
Rust
233 lines
9.0 KiB
Rust
// src/server/mod.rs
|
||
//! Сервер Falcot - документо-ориентированная БД с wait-free архитектурой
|
||
//!
|
||
//! Основной модуль сервера, реализующий wait-free доступ к данным,
|
||
//! синхронную master-master репликацию и поддержку HTTP/HTTPS.
|
||
|
||
#![allow(dead_code)]
|
||
|
||
use std::sync::Arc;
|
||
use std::fs::OpenOptions;
|
||
use std::io::Write;
|
||
|
||
use crate::common::error::Result;
|
||
use crate::lua_shell::LuaShell;
|
||
|
||
// Импортируем подмодули
|
||
pub mod database;
|
||
pub mod replication;
|
||
pub mod lua_engine;
|
||
pub mod messagepack;
|
||
pub mod config;
|
||
pub mod http;
|
||
pub mod sharding; // Добавляем модуль шардинга
|
||
|
||
/// Функция для логирования в файл
|
||
fn log_to_file(message: &str) {
|
||
if let Ok(mut file) = OpenOptions::new()
|
||
.create(true)
|
||
.append(true)
|
||
.open("falcot.log")
|
||
{
|
||
let timestamp = chrono::Local::now().format("%Y-%m-%d %H:%M:%S");
|
||
let log_message = format!("[{}] {}\n", timestamp, message);
|
||
let _ = file.write_all(log_message.as_bytes());
|
||
}
|
||
}
|
||
|
||
/// Функция для вывода текста с ANSI цветом
|
||
#[allow(dead_code)]
|
||
fn print_colored(text: &str, ansi_color: &str) {
|
||
println!("{}{}\x1b[0m", ansi_color, text);
|
||
}
|
||
|
||
/// Конвертация HEX цвета в ANSI escape code
|
||
fn hex_to_ansi(hex_color: &str) -> String {
|
||
let hex = hex_color.trim_start_matches('#');
|
||
|
||
if hex.len() == 6 {
|
||
if let (Ok(r), Ok(g), Ok(b)) = (
|
||
u8::from_str_radix(&hex[0..2], 16),
|
||
u8::from_str_radix(&hex[2..4], 16),
|
||
u8::from_str_radix(&hex[4..6], 16),
|
||
) {
|
||
return format!("\x1b[38;2;{};{};{}m", r, g, b);
|
||
}
|
||
}
|
||
|
||
"\x1b[38;2;255;255;255m".to_string()
|
||
}
|
||
|
||
/// Основный сервер Falcot с wait-free архитектурой
|
||
pub struct FalcotServer {
|
||
config: config::Config,
|
||
database: Arc<database::Database>,
|
||
lua_engine: lua_engine::LuaEngine,
|
||
replication: Arc<replication::ReplicationManager>,
|
||
http_enabled: bool,
|
||
}
|
||
|
||
impl FalcotServer {
|
||
/// Создание нового сервера с wait-free архитектурой
|
||
pub async fn new(config_path: &str) -> Result<Self> {
|
||
// Загрузка конфигурации
|
||
let config = config::Config::load(config_path)?;
|
||
|
||
// Инициализация компонентов с wait-free подходами
|
||
let database = Arc::new(database::Database::new());
|
||
let lua_engine = lua_engine::LuaEngine::new()?;
|
||
let replication = Arc::new(replication::ReplicationManager::new(
|
||
config.replication.master_nodes.iter()
|
||
.map(|addr| addr.to_string())
|
||
.collect(),
|
||
config.replication.sync_interval,
|
||
config.replication.enabled,
|
||
));
|
||
|
||
// Регистрация функций БД в Lua
|
||
lua_engine.register_db_functions(database.clone())?;
|
||
|
||
// Инициализация базы данных
|
||
FalcotServer::initialize_database(database.clone())?;
|
||
|
||
// Проверяем, включен ли HTTP режим
|
||
let http_enabled = config.server.http_port.is_some() || config.server.https_port.is_some();
|
||
|
||
Ok(Self {
|
||
config,
|
||
database,
|
||
lua_engine,
|
||
replication,
|
||
http_enabled,
|
||
})
|
||
}
|
||
|
||
/// Инициализация базы данных с wait-free структурами
|
||
fn initialize_database(db: Arc<database::Database>) -> Result<()> {
|
||
// Создаем системные коллекции с wait-free доступом
|
||
let _system_collection = db.get_collection("_system");
|
||
let _users_collection = db.get_collection("_users");
|
||
let _logs_collection = db.get_collection("_logs");
|
||
let _procedures_collection = db.get_collection("_procedures");
|
||
let _triggers_collection = db.get_collection("_triggers");
|
||
|
||
// Создаем директорию для бэкапов
|
||
let backup_dir = "/falcot/backups";
|
||
if let Err(e) = std::fs::create_dir_all(backup_dir) {
|
||
eprintln!("Warning: Failed to create backup directory: {}", e);
|
||
}
|
||
|
||
let message = "Database initialized with system collections";
|
||
println!("{}", message);
|
||
log_to_file(message);
|
||
|
||
Ok(())
|
||
}
|
||
|
||
/// Запуск сервера с wait-free архитектурой
|
||
pub async fn run(&self) -> Result<()> {
|
||
// Вывод приветственного сообщения с цветом #00bfff
|
||
println!();
|
||
let color_code = hex_to_ansi("#00bfff");
|
||
print_colored("Falcot Database Server", &color_code);
|
||
println!();
|
||
println!("Version: 1.0.0");
|
||
println!("Features: Wait-Free Architecture, Master-Master Replication, Lua Scripting, HTTP/HTTPS Support");
|
||
|
||
log_to_file("Falcot Database Server started");
|
||
log_to_file("Version: 1.0.0");
|
||
|
||
// Запуск HTTP/HTTPS серверов в отдельных задачах, если настроены
|
||
if self.http_enabled {
|
||
self.start_http_servers().await?;
|
||
}
|
||
|
||
// Запуск Lua интерпретатора
|
||
println!("Starting Lua interpreter...");
|
||
log_to_file("Starting Lua interpreter...");
|
||
|
||
let mut lua_shell = LuaShell::new(
|
||
self.lua_engine.clone(),
|
||
self.database.clone(),
|
||
self.replication.clone()
|
||
);
|
||
|
||
// Запуск интерактивной оболочки
|
||
lua_shell.run().await?;
|
||
|
||
Ok(())
|
||
}
|
||
|
||
/// Запуск HTTP/HTTPS серверов в отдельных задачах
|
||
async fn start_http_servers(&self) -> Result<()> {
|
||
let static_config = http::StaticFilesConfig::default();
|
||
let acl_config = http::AclConfig {
|
||
enabled: self.config.acl.enabled,
|
||
allowed_ips: self.config.acl.allowed_ips.clone(),
|
||
denied_ips: self.config.acl.denied_ips.clone(),
|
||
};
|
||
|
||
// Запуск HTTP сервера, если настроен
|
||
if let Some(http_port) = self.config.server.http_port {
|
||
let http_addr = format!("{}:{}", self.config.server.host, http_port);
|
||
let http_config = http::HttpConfig {
|
||
enabled: true,
|
||
port: http_port,
|
||
http2_enabled: self.config.server.http2_enabled.unwrap_or(false),
|
||
};
|
||
|
||
let db_clone = self.database.clone();
|
||
let static_config_clone = static_config.clone();
|
||
let acl_config_clone = acl_config.clone();
|
||
|
||
// Запускаем HTTP сервер в отдельной задаче (не блокирующей основной поток)
|
||
tokio::spawn(async move {
|
||
match http::start_http_server(&http_addr, db_clone, static_config_clone, http_config, acl_config_clone).await {
|
||
Ok(_) => {
|
||
let message = format!("HTTP server started on {}", http_addr);
|
||
println!("{}", message);
|
||
log_to_file(&message);
|
||
}
|
||
Err(e) => {
|
||
let message = format!("Failed to start HTTP server: {}", e);
|
||
eprintln!("{}", message);
|
||
log_to_file(&message);
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
// Запуск HTTPS сервера, если настроен
|
||
if let Some(https_port) = self.config.server.https_port {
|
||
let https_addr = format!("{}:{}", self.config.server.host, https_port);
|
||
let tls_config = http::TlsConfig {
|
||
enabled: self.config.tls.enabled,
|
||
cert_path: self.config.tls.cert_path.clone(),
|
||
key_path: self.config.tls.key_path.clone(),
|
||
};
|
||
|
||
let db_clone = self.database.clone();
|
||
let static_config_clone = static_config.clone();
|
||
let acl_config_clone = acl_config.clone();
|
||
|
||
// Запускаем HTTPS сервер в отдельной задаче
|
||
tokio::spawn(async move {
|
||
match http::start_https_server(&https_addr, db_clone, static_config_clone, tls_config, acl_config_clone).await {
|
||
Ok(_) => {
|
||
let message = format!("HTTPS server started on {}", https_addr);
|
||
println!("{}", message);
|
||
log_to_file(&message);
|
||
}
|
||
Err(e) => {
|
||
let message = format!("Failed to start HTTPS server: {}", e);
|
||
eprintln!("{}", message);
|
||
log_to_file(&message);
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
Ok(())
|
||
}
|
||
}
|