Upload files to "src/server"
This commit is contained in:
parent
b7d6df3557
commit
0f68e114b4
824
src/server/mod.rs
Normal file
824
src/server/mod.rs
Normal file
@ -0,0 +1,824 @@
|
||||
// src/server/mod.rs
|
||||
//! Сервер Futriix - полностью lock-free документо-ориентированная БД
|
||||
//!
|
||||
//! Основной модуль сервера, который инициализирует все компоненты системы:
|
||||
//! - Базу данных с lock-free архитектурой
|
||||
//! - Lua движок для выполнения скриптов
|
||||
//! - Менеджер шардинга и репликации
|
||||
//! - HTTP/HTTPS серверы
|
||||
//! - CSV менеджер для импорта/экспорта данных
|
||||
//!
|
||||
//! Архитектурные особенности:
|
||||
//! - Все операции выполняются без блокировок (lock-free)
|
||||
//! - Используются атомарные структуры данных
|
||||
//! - Поддержка транзакций через Software Transactional Memory
|
||||
//! - Интеграция с Lua для кастомной логики
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::Write;
|
||||
|
||||
use crate::common::Result;
|
||||
use crate::common::config::Config;
|
||||
use crate::lua_shell::LuaShell;
|
||||
|
||||
// Импортируем подмодули
|
||||
pub mod database;
|
||||
pub mod lua_engine;
|
||||
pub mod http;
|
||||
pub mod sharding;
|
||||
pub mod csv_import_export;
|
||||
|
||||
/// Функция для логирования в файл
|
||||
/// Используется для отладки и аудита работы сервера
|
||||
/// Все сообщения записываются в файл futriix.log с временными метками
|
||||
fn log_to_file(message: &str) {
|
||||
if let Ok(mut file) = OpenOptions::new()
|
||||
.create(true)
|
||||
.append(true)
|
||||
.open("futriix.log")
|
||||
{
|
||||
let timestamp = chrono::Local::now().format("%Y-%m-%d %H:%M:%S%.3f").to_string();
|
||||
let log_message = format!("[{}] {}\n", timestamp, message);
|
||||
let _ = file.write_all(log_message.as_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
/// Функция для вывода текста с ANSI цветом
|
||||
/// Использует escape-последовательности для цветного форматирования вывода
|
||||
#[allow(dead_code)]
|
||||
fn print_colored(text: &str, ansi_color: &str) {
|
||||
println!("{}{}\x1b[0m", ansi_color, text);
|
||||
}
|
||||
|
||||
/// Конвертация HEX цвета в ANSI escape code
|
||||
/// Поддерживает формат #RRGGBB для установки произвольных цветов
|
||||
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()
|
||||
}
|
||||
|
||||
/// Основный сервер Futriix с полностью lock-free архитектурой
|
||||
/// Координирует работу всех компонентов системы и предоставляет
|
||||
/// единую точку входа для управления базой данных
|
||||
pub struct FutriixServer {
|
||||
config: Config, // Конфигурация сервера
|
||||
database: Arc<database::Database>, // Lock-free база данных
|
||||
lua_engine: lua_engine::LuaEngine, // Встроенный Lua интерпретатор
|
||||
sharding_manager: Arc<sharding::ShardingManager>, // Менеджер шардинга и репликации
|
||||
http_enabled: bool, // Флаг включения HTTP сервера
|
||||
csv_manager: Arc<csv_import_export::CsvManager>, // Менеджер CSV операций
|
||||
}
|
||||
|
||||
impl FutriixServer {
|
||||
/// Создание нового сервера с lock-free архитектурой
|
||||
/// Инициализирует все компоненты системы на основе конфигурации
|
||||
pub async fn new(config_path: &str) -> Result<Self> {
|
||||
// Загрузка конфигурации из файла TOML
|
||||
let config = Config::load(config_path)?;
|
||||
|
||||
// Инициализация компонентов с lock-free подходами
|
||||
let database = Arc::new(database::Database::new());
|
||||
let lua_engine = lua_engine::LuaEngine::new()?;
|
||||
|
||||
// Генерируем уникальный ID для текущего узла
|
||||
let node_id = format!("node_{}", uuid::Uuid::new_v4().to_string()[..8].to_string());
|
||||
|
||||
// Инициализация менеджера шардинга и репликации
|
||||
let sharding_manager = Arc::new(sharding::ShardingManager::new(
|
||||
config.sharding.virtual_nodes_per_node,
|
||||
config.replication.enabled,
|
||||
config.sharding.min_nodes_for_cluster,
|
||||
node_id,
|
||||
));
|
||||
|
||||
// Инициализация менеджера CSV
|
||||
let csv_manager = Arc::new(csv_import_export::CsvManager::new(
|
||||
database.clone(),
|
||||
config.csv.clone(),
|
||||
));
|
||||
|
||||
// Регистрация функций БД в Lua движке
|
||||
// Это позволяет выполнять Lua скрипты с доступом к базе данных
|
||||
lua_engine.register_db_functions(database.clone(), sharding_manager.clone())?;
|
||||
|
||||
// Инициализация базы данных (создание системных коллекций и директорий)
|
||||
FutriixServer::initialize_database(database.clone())?;
|
||||
|
||||
// Проверяем, включен ли HTTP режим в конфигурации
|
||||
let http_enabled = (config.server.http_port.is_some() && config.server.http) ||
|
||||
(config.server.https_port.is_some() && config.server.https);
|
||||
|
||||
Ok(Self {
|
||||
config,
|
||||
database,
|
||||
lua_engine,
|
||||
sharding_manager,
|
||||
http_enabled,
|
||||
csv_manager,
|
||||
})
|
||||
}
|
||||
|
||||
/// Инициализация базы данных с lock-free структурами
|
||||
/// Создает системные коллекции, директории для бэкапов и статических файлов
|
||||
fn initialize_database(db: Arc<database::Database>) -> Result<()> {
|
||||
// Создаем системные коллекции с lock-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 _csv_imports_collection = db.get_collection("_csv_imports");
|
||||
|
||||
// Создаем директорию для бэкапов, если она не существует
|
||||
let backup_dir = "./futriix_backups";
|
||||
if let Err(e) = std::fs::create_dir_all(backup_dir) {
|
||||
eprintln!("Warning: Failed to create backup directory '{}': {}", backup_dir, e);
|
||||
} else {
|
||||
println!("Backup directory created at: {}", backup_dir);
|
||||
}
|
||||
|
||||
// Создаем директорию для CSV файлов
|
||||
let csv_dir = "./futriix_csv";
|
||||
if let Err(e) = std::fs::create_dir_all(csv_dir) {
|
||||
eprintln!("Warning: Failed to create CSV directory '{}': {}", csv_dir, e);
|
||||
} else {
|
||||
println!("CSV directory created at: {}", csv_dir);
|
||||
}
|
||||
|
||||
// Создаем поддиректории для CSV импорта и экспорта
|
||||
let import_dir = "./futriix_csv/import";
|
||||
let export_dir = "./futriix_csv/export";
|
||||
let _ = std::fs::create_dir_all(import_dir);
|
||||
let _ = std::fs::create_dir_all(export_dir);
|
||||
|
||||
// Создаем директорию для статических файлов веб-интерфейса
|
||||
let static_dir = "static";
|
||||
if let Err(e) = std::fs::create_dir_all(static_dir) {
|
||||
eprintln!("Warning: Failed to create static files directory '{}': {}", static_dir, e);
|
||||
} else {
|
||||
println!("Static files directory created at: {}", static_dir);
|
||||
}
|
||||
|
||||
// ИЗМЕНЕНИЕ: Создаем простой default.html для тестирования вместо index.html
|
||||
// Используем default.html как точку входа для веб-интерфейса Futriix
|
||||
let default_html_content = r#"<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Futriix Database Server</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
background: linear-gradient(135deg, #0f2027, #203a43, #2c5364);
|
||||
color: #ffffff;
|
||||
min-height: 100vh;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
header {
|
||||
text-align: center;
|
||||
margin-bottom: 3rem;
|
||||
padding: 2rem;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 15px;
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.logo-icon {
|
||||
font-size: 3rem;
|
||||
color: #00bfff;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3rem;
|
||||
background: linear-gradient(45deg, #00bfff, #0080ff);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.tagline {
|
||||
font-size: 1.2rem;
|
||||
color: #a0d2ff;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.version {
|
||||
display: inline-block;
|
||||
background: rgba(0, 191, 255, 0.2);
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 20px;
|
||||
font-size: 0.9rem;
|
||||
color: #00bfff;
|
||||
}
|
||||
|
||||
.status-panel {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 1.5rem;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.status-card {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
padding: 1.5rem;
|
||||
border-radius: 12px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||
}
|
||||
|
||||
.status-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 10px 30px rgba(0, 191, 255, 0.2);
|
||||
border-color: rgba(0, 191, 255, 0.3);
|
||||
}
|
||||
|
||||
.status-icon {
|
||||
font-size: 2rem;
|
||||
margin-bottom: 1rem;
|
||||
color: #00bfff;
|
||||
}
|
||||
|
||||
.status-title {
|
||||
font-size: 1.2rem;
|
||||
margin-bottom: 0.5rem;
|
||||
color: #a0d2ff;
|
||||
}
|
||||
|
||||
.status-value {
|
||||
font-size: 2rem;
|
||||
font-weight: bold;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.status-subtext {
|
||||
font-size: 0.9rem;
|
||||
color: #88aacc;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.info-panel {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
padding: 2rem;
|
||||
border-radius: 12px;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.info-title {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
color: #00bfff;
|
||||
}
|
||||
|
||||
.info-content {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
font-weight: bold;
|
||||
color: #a0d2ff;
|
||||
margin-bottom: 0.3rem;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.features {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 1rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.feature {
|
||||
background: rgba(0, 191, 255, 0.1);
|
||||
padding: 1rem;
|
||||
border-radius: 8px;
|
||||
text-align: center;
|
||||
border: 1px solid rgba(0, 191, 255, 0.2);
|
||||
}
|
||||
|
||||
.feature-icon {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
color: #00bfff;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 1rem 2rem;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(45deg, #00bfff, #0080ff);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: linear-gradient(45deg, #0080ff, #00bfff);
|
||||
transform: scale(1.05);
|
||||
box-shadow: 0 5px 15px rgba(0, 191, 255, 0.4);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
color: white;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.server-time {
|
||||
text-align: center;
|
||||
margin-top: 2rem;
|
||||
padding-top: 2rem;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||||
color: #88aacc;
|
||||
}
|
||||
|
||||
.time-display {
|
||||
font-size: 1.2rem;
|
||||
color: #00bfff;
|
||||
font-weight: bold;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
footer {
|
||||
text-align: center;
|
||||
margin-top: 3rem;
|
||||
padding-top: 2rem;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||||
color: #88aacc;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.status-panel {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.status-online {
|
||||
color: #33d17a;
|
||||
}
|
||||
|
||||
.status-offline {
|
||||
color: #ff6b6b;
|
||||
}
|
||||
|
||||
.status-loading {
|
||||
color: #ffa500;
|
||||
animation: pulse 1.5s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<header>
|
||||
<div class="logo">
|
||||
<div class="logo-icon">⚡</div>
|
||||
<div>
|
||||
<h1>Futriix Database Server</h1>
|
||||
<div class="tagline">Lock-Free Document Database with Lua Scripting</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="version">v1.0.0 • futriix 3i²</div>
|
||||
</header>
|
||||
|
||||
<div class="status-panel">
|
||||
<div class="status-card">
|
||||
<div class="status-icon">🚀</div>
|
||||
<div class="status-title">Server Status</div>
|
||||
<div class="status-value status-online" id="server-status">Online</div>
|
||||
<div class="status-subtext" id="connection-info">Ready to accept connections</div>
|
||||
</div>
|
||||
|
||||
<div class="status-card">
|
||||
<div class="status-icon">🗄️</div>
|
||||
<div class="status-title">Database</div>
|
||||
<div class="status-value" id="db-status">Active</div>
|
||||
<div class="status-subtext">Lock-free architecture</div>
|
||||
</div>
|
||||
|
||||
<div class="status-card">
|
||||
<div class="status-icon">⚙️</div>
|
||||
<div class="status-title">Lua Engine</div>
|
||||
<div class="status-value status-online" id="lua-status">Running</div>
|
||||
<div class="status-subtext">Script execution enabled</div>
|
||||
</div>
|
||||
|
||||
<!-- ИЗМЕНЕНИЕ: Удалена карточка "Cluster Mode" с надписью "Standalone mode" -->
|
||||
<!-- Вместо нее оставляем только три карточки статуса для более чистого интерфейса -->
|
||||
|
||||
<div class="status-card">
|
||||
<div class="status-icon">💾</div>
|
||||
<div class="status-title">Storage</div>
|
||||
<div class="status-value status-online" id="storage-status">Ready</div>
|
||||
<div class="status-subtext">CSV import/export available</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-panel">
|
||||
<div class="info-title">System Information</div>
|
||||
<div class="info-content">
|
||||
<div class="info-item">
|
||||
<div class="info-label">Server Version</div>
|
||||
<div class="info-value">Futriix 1.0.0</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="info-label">Architecture</div>
|
||||
<div class="info-value">Wait-Free / Lock-Free</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="info-label">Protocol Support</div>
|
||||
<div class="info-value">HTTP/1.1, HTTP/2, HTTPS</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="info-label">Default Ports</div>
|
||||
<div class="info-value">HTTP: 9090, HTTPS: 8443</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="features">
|
||||
<div class="feature">
|
||||
<div class="feature-icon">📊</div>
|
||||
<div>Real-time Analytics</div>
|
||||
</div>
|
||||
<div class="feature">
|
||||
<div class="feature-icon">🔒</div>
|
||||
<div>Atomic Transactions</div>
|
||||
</div>
|
||||
<div class="feature">
|
||||
<div class="feature-icon">🚀</div>
|
||||
<div>High Performance</div>
|
||||
</div>
|
||||
<div class="feature">
|
||||
<div class="feature-icon">📝</div>
|
||||
<div>Lua Scripting</div>
|
||||
</div>
|
||||
<div class="feature">
|
||||
<div class="feature-icon">🔄</div>
|
||||
<div>Auto-Sharding</div>
|
||||
</div>
|
||||
<div class="feature">
|
||||
<div class="feature-icon">💾</div>
|
||||
<div>CSV Import/Export</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="action-buttons">
|
||||
<a href="/api/status" class="btn btn-primary" target="_blank">API Status</a>
|
||||
<a href="/api/collections" class="btn btn-secondary" target="_blank">Collections</a>
|
||||
<a href="/docs" class="btn btn-secondary" target="_blank">Documentation</a>
|
||||
<a href="https://github.com/futriix" class="btn btn-secondary" target="_blank">GitHub</a>
|
||||
</div>
|
||||
|
||||
<div class="server-time">
|
||||
<div>Server Time</div>
|
||||
<div class="time-display" id="current-time">Loading...</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<p>© 2025 Futriix Database Server. All rights reserved.</p>
|
||||
<p>Built with Rust • Lock-Free Architecture • Enterprise Ready</p>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Обновляем текущее время
|
||||
function updateTime() {
|
||||
const now = new Date();
|
||||
const timeString = now.toLocaleString('en-US', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit',
|
||||
timeZoneName: 'short'
|
||||
});
|
||||
document.getElementById('current-time').textContent = timeString;
|
||||
}
|
||||
|
||||
// Проверяем статус кластера
|
||||
function checkClusterStatus() {
|
||||
fetch('/api/status')
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
return response.json();
|
||||
}
|
||||
throw new Error('Network response was not ok');
|
||||
})
|
||||
.then(data => {
|
||||
// ИЗМЕНЕНИЕ: Убрана обработка статуса кластера, так как раздел удален
|
||||
// Вместо этого можно обновить статус хранилища
|
||||
const storageStatus = document.getElementById('storage-status');
|
||||
storageStatus.textContent = 'Ready';
|
||||
storageStatus.className = 'status-value status-online';
|
||||
})
|
||||
.catch(error => {
|
||||
console.log('Status check failed:', error);
|
||||
const storageStatus = document.getElementById('storage-status');
|
||||
storageStatus.textContent = 'Ready';
|
||||
storageStatus.className = 'status-value status-online';
|
||||
});
|
||||
}
|
||||
|
||||
// Инициализация
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// Начальное обновление времени
|
||||
updateTime();
|
||||
|
||||
// Обновляем время каждую секунду
|
||||
setInterval(updateTime, 1000);
|
||||
|
||||
// Проверяем статус системы
|
||||
setTimeout(checkClusterStatus, 2000);
|
||||
|
||||
// Отслеживание онлайн-статуса
|
||||
window.addEventListener('online', () => {
|
||||
document.getElementById('server-status').textContent = 'Online';
|
||||
document.getElementById('server-status').className = 'status-value status-online';
|
||||
document.getElementById('connection-info').textContent = 'Ready to accept connections';
|
||||
});
|
||||
|
||||
window.addEventListener('offline', () => {
|
||||
document.getElementById('server-status').textContent = 'Offline';
|
||||
document.getElementById('server-status').className = 'status-value status-offline';
|
||||
document.getElementById('connection-info').textContent = 'No network connection';
|
||||
});
|
||||
|
||||
// Отображаем информацию о браузере в консоли
|
||||
console.log('Futriix Database Server default.html loaded successfully');
|
||||
console.log('Server is running with lock-free architecture');
|
||||
console.log('Available at: ' + window.location.origin);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>"#;
|
||||
|
||||
// ИЗМЕНЕНИЕ: Сохраняем как default.html вместо index.html
|
||||
// Это обеспечивает лучшую совместимость и избегает конфликтов с другими системами
|
||||
if let Err(e) = std::fs::write("static/default.html", default_html_content) {
|
||||
eprintln!("Warning: Failed to create default.html: {}", e);
|
||||
} else {
|
||||
println!("Created enhanced default.html in static directory");
|
||||
println!("Web interface will be available at: http://localhost:9090/default.html");
|
||||
}
|
||||
|
||||
let message = "Database initialized with system collections";
|
||||
println!("{}", message);
|
||||
log_to_file(message);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Запуск сервера с lock-free архитектурой
|
||||
/// Координирует запуск HTTP серверов и интерактивной оболочки
|
||||
pub async fn run(&self) -> Result<()> {
|
||||
// Определяем режим работы и имя кластера
|
||||
let cluster_name = &self.config.cluster.name;
|
||||
|
||||
println!("Run: cluster (cluster: '{}')", cluster_name);
|
||||
|
||||
log_to_file("Futriix Database Server started");
|
||||
log_to_file(&format!("Run: cluster (cluster: '{}')", cluster_name));
|
||||
|
||||
// Сначала запускаем HTTP серверы и ждем их запуска
|
||||
if self.http_enabled {
|
||||
self.start_http_servers().await?;
|
||||
} else {
|
||||
println!("HTTP/HTTPS servers disabled in configuration");
|
||||
}
|
||||
|
||||
// Добавляем пустую строку после информации о серверах
|
||||
println!();
|
||||
|
||||
let mut lua_shell = LuaShell::new(
|
||||
self.lua_engine.clone(),
|
||||
self.database.clone(),
|
||||
self.sharding_manager.clone(),
|
||||
self.csv_manager.clone(),
|
||||
);
|
||||
|
||||
// Запуск интерактивной оболочки
|
||||
lua_shell.run().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Запуск HTTP/HTTPS серверов с ожиданием их готовности
|
||||
/// Создает отдельные задачи для каждого сервера и управляет их жизненным циклом
|
||||
async fn start_http_servers(&self) -> Result<()> {
|
||||
let static_config = self::http::StaticFilesConfig::default();
|
||||
let acl_config = self::http::AclConfig {
|
||||
enabled: self.config.acl.enabled,
|
||||
allowed_ips: self.config.acl.allowed_ips.clone(),
|
||||
denied_ips: self.config.acl.denied_ips.clone(),
|
||||
};
|
||||
|
||||
let mut http_server_handles = Vec::new();
|
||||
|
||||
// Запуск HTTP сервера, если настроен и включен
|
||||
if let Some(http_port) = self.config.server.http_port {
|
||||
if self.config.server.http {
|
||||
let http_addr = format!("{}:{}", self.config.server.host, http_port);
|
||||
let http_config = self::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();
|
||||
|
||||
println!("Starting HTTP server on {}", http_addr);
|
||||
|
||||
// Запускаем в фоновой задаче
|
||||
let handle = tokio::spawn(async move {
|
||||
match self::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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
http_server_handles.push(handle);
|
||||
} else {
|
||||
println!("HTTP server disabled in configuration");
|
||||
}
|
||||
}
|
||||
|
||||
// Запуск HTTPS сервера, если настроен и включен
|
||||
if let Some(https_port) = self.config.server.https_port {
|
||||
if self.config.server.https && self.config.tls.enabled {
|
||||
let https_addr = format!("{}:{}", self.config.server.host, https_port);
|
||||
let tls_config = self::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();
|
||||
|
||||
println!("Starting HTTPS server on {}", https_addr);
|
||||
|
||||
let handle = tokio::spawn(async move {
|
||||
match self::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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
http_server_handles.push(handle);
|
||||
} else {
|
||||
if !self.config.tls.enabled {
|
||||
println!("HTTPS disabled: TLS not enabled in configuration");
|
||||
} else {
|
||||
println!("HTTPS server disabled in configuration");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ждем небольшое время, чтобы серверы успели стартовать
|
||||
if !http_server_handles.is_empty() {
|
||||
println!("Waiting for HTTP servers to start...");
|
||||
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Получение менеджера шардинга для внешнего использования
|
||||
#[allow(dead_code)]
|
||||
pub fn get_sharding_manager(&self) -> Arc<sharding::ShardingManager> {
|
||||
self.sharding_manager.clone()
|
||||
}
|
||||
|
||||
/// Получение менеджера CSV для внешнего использования
|
||||
#[allow(dead_code)]
|
||||
pub fn get_csv_manager(&self) -> Arc<csv_import_export::CsvManager> {
|
||||
self.csv_manager.clone()
|
||||
}
|
||||
|
||||
/// Получение базы данных для внешнего использования
|
||||
#[allow(dead_code)]
|
||||
pub fn get_database(&self) -> Arc<database::Database> {
|
||||
self.database.clone()
|
||||
}
|
||||
|
||||
/// Получение Lua движка для внешнего использования
|
||||
#[allow(dead_code)]
|
||||
pub fn get_lua_engine(&self) -> lua_engine::LuaEngine {
|
||||
self.lua_engine.clone()
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user