Delete src/utils/config.rs

This commit is contained in:
Григорий Сафронов 2026-01-14 20:59:33 +00:00
parent 542c8a69e0
commit ec97bbde89

View File

@ -1,750 +0,0 @@
//! Конфигурационный модуль для flusql
//!
//! Этот модуль отвечает за загрузку и управление конфигурацией
//! сервера flusql из файла config.toml и переменных окружения.
use serde::{Deserialize, Serialize};
use std::fs;
use std::path::Path;
use thiserror::Error;
/// Основная конфигурация flusql
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
/// Общие настройки сервера
#[serde(default = "default_server_config")]
pub server: ServerConfig,
/// Настройки базы данных
#[serde(default = "default_database_config")]
pub database: DatabaseConfig,
/// Настройки логгера
#[serde(default = "default_logging_config")]
pub logging: LoggingConfig,
/// Настройки Lua интерпретатора
#[serde(default = "default_lua_config")]
pub lua: LuaConfig,
/// Настройки кластера
#[serde(default = "default_cluster_config")]
pub cluster: ClusterConfig,
/// Настройки плагинов
#[serde(default = "default_plugins_config")]
pub plugins: PluginsConfig,
/// Настройки HTTP сервера (если включен)
#[serde(default = "default_http_config")]
pub http: HttpConfig,
/// Настройки репликации
#[serde(default = "default_replication_config")]
pub replication: ReplicationConfig,
/// Настройки сети
#[serde(default = "default_network_config")]
pub network: NetworkConfig,
}
/// Конфигурация сети
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NetworkConfig {
/// IP-адрес для прослушивания
#[serde(default = "default_network_host")]
pub host: String,
/// Порт для прослушивания
#[serde(default = "default_network_port")]
pub port: u16,
/// Разрешить удаленные подключения
#[serde(default = "default_allow_remote")]
pub allow_remote: bool,
/// Таймаут соединения в секундах
#[serde(default = "default_connection_timeout")]
pub connection_timeout: u64,
/// Максимальное количество соединений
#[serde(default = "default_max_connections")]
pub max_connections: u32,
/// Размер буфера для сетевых операций в байтах
#[serde(default = "default_buffer_size")]
pub buffer_size: usize,
}
/// Значения по умолчанию для NetworkConfig
fn default_network_config() -> NetworkConfig {
NetworkConfig {
host: default_network_host(),
port: default_network_port(),
allow_remote: default_allow_remote(),
connection_timeout: default_connection_timeout(),
max_connections: default_max_connections(),
buffer_size: default_buffer_size(),
}
}
fn default_network_host() -> String { "127.0.0.1".to_string() }
fn default_network_port() -> u16 { 8080 }
fn default_allow_remote() -> bool { false }
fn default_connection_timeout() -> u64 { 30 }
fn default_max_connections() -> u32 { 100 }
fn default_buffer_size() -> usize { 8192 }
/// Конфигурация плагинов
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PluginsConfig {
/// Включена ли система плагинов
#[serde(default = "default_plugins_enabled")]
pub enabled: bool,
/// Директория для плагинов
#[serde(default = "default_plugins_dir")]
pub plugins_dir: String,
/// Включить изоляцию плагинов (sandbox)
#[serde(default = "default_sandbox_enabled")]
pub sandbox_enabled: bool,
/// Максимальное количество плагинов
#[serde(default = "default_max_plugins")]
pub max_plugins: usize,
/// Автозагрузка плагинов при старте
#[serde(default = "default_auto_load")]
pub auto_load: bool,
/// Включить горячую перезагрузку плагинов
#[serde(default = "default_hot_reload")]
pub hot_reload: bool,
/// Таймаут выполнения плагина в секундах
#[serde(default = "default_plugin_timeout")]
pub plugin_timeout_sec: u64,
/// Максимальный размер памяти плагина в МБ
#[serde(default = "default_max_memory_mb")]
pub max_memory_mb: u64,
/// Разрешенные API для плагинов
#[serde(default = "default_allowed_apis")]
pub allowed_apis: Vec<String>,
/// Запрещенные функции Lua
#[serde(default = "default_blocked_functions")]
pub blocked_functions: Vec<String>,
}
/// Значения по умолчанию для PluginsConfig
fn default_plugins_config() -> PluginsConfig {
PluginsConfig {
enabled: default_plugins_enabled(),
plugins_dir: default_plugins_dir(),
sandbox_enabled: default_sandbox_enabled(),
max_plugins: default_max_plugins(),
auto_load: default_auto_load(),
hot_reload: default_hot_reload(),
plugin_timeout_sec: default_plugin_timeout(),
max_memory_mb: default_max_memory_mb(),
allowed_apis: default_allowed_apis(),
blocked_functions: default_blocked_functions(),
}
}
fn default_plugins_enabled() -> bool { true }
fn default_plugins_dir() -> String { "./plugins".to_string() }
fn default_sandbox_enabled() -> bool { true }
fn default_max_plugins() -> usize { 50 }
fn default_auto_load() -> bool { true }
fn default_hot_reload() -> bool { false }
fn default_plugin_timeout() -> u64 { 30 }
fn default_max_memory_mb() -> u64 { 100 }
fn default_allowed_apis() -> Vec<String> {
vec![
"database".to_string(),
"table".to_string(),
"query".to_string(),
"index".to_string(),
"event".to_string(),
"log".to_string(),
]
}
fn default_blocked_functions() -> Vec<String> {
vec![
"io.popen".to_string(),
"os.execute".to_string(),
"os.exit".to_string(),
"debug.debug".to_string(),
"debug.getregistry".to_string(),
"debug.setmetatable".to_string(),
]
}
/// Конфигурация HTTP сервера
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HttpConfig {
/// Включен ли HTTP сервер
pub enabled: bool,
/// Хост для HTTP сервера
#[serde(default = "default_http_host")]
pub host: String,
/// Порт HTTP сервера
#[serde(default = "default_http_port")]
pub port: u16,
/// Порт HTTPS сервера
#[serde(default = "default_https_port")]
pub https_port: u16,
/// Включена ли поддержка HTTP/2
#[serde(default)]
pub http2_enabled: bool,
/// Включена ли поддержка TLS
#[serde(default)]
pub tls_enabled: bool,
/// Путь к сертификату TLS
#[serde(default)]
pub tls_cert_path: Option<String>,
/// Путь к приватному ключу TLS
#[serde(default)]
pub tls_key_path: Option<String>,
}
/// Значения по умолчанию для HttpConfig
fn default_http_config() -> HttpConfig {
HttpConfig {
enabled: false,
host: default_http_host(),
port: default_http_port(),
https_port: default_https_port(),
http2_enabled: false,
tls_enabled: false,
tls_cert_path: None,
tls_key_path: None,
}
}
fn default_http_host() -> String { "127.0.0.1".to_string() }
fn default_http_port() -> u16 { 8080 }
fn default_https_port() -> u16 { 8443 }
/// Конфигурация репликации
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReplicationConfig {
/// Включена ли репликация
pub enabled: bool,
/// Режим репликации
#[serde(default = "default_replication_mode")]
pub mode: String,
/// Мастер-сервер для репликации
#[serde(default)]
pub master: Option<String>,
/// Список слейв-серверов
#[serde(default)]
pub slaves: Vec<String>,
}
/// Значения по умолчанию для ReplicationConfig
fn default_replication_config() -> ReplicationConfig {
ReplicationConfig {
enabled: false,
mode: default_replication_mode(),
master: None,
slaves: vec![],
}
}
fn default_replication_mode() -> String { "async".to_string() }
/// Конфигурация сервера
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerConfig {
/// Порт сервера
#[serde(default = "default_server_port")]
pub port: u16,
/// Хост сервера
#[serde(default = "default_server_host")]
pub host: String,
/// Максимальное количество одновременных соединений
#[serde(default = "default_server_max_connections")]
pub max_connections: u32,
/// Таймаут соединения в секундах
#[serde(default = "default_server_timeout")]
pub timeout: u64,
/// Размер пула потоков
#[serde(default = "default_thread_pool_size")]
pub thread_pool_size: usize,
/// Включить отладку
#[serde(default = "default_debug_enabled")]
pub debug: bool,
/// Путь к PID файлу
#[serde(default)]
pub pid_file: Option<String>,
}
/// Значения по умолчанию для ServerConfig
fn default_server_config() -> ServerConfig {
ServerConfig {
port: default_server_port(),
host: default_server_host(),
max_connections: default_server_max_connections(),
timeout: default_server_timeout(),
thread_pool_size: default_thread_pool_size(),
debug: default_debug_enabled(),
pid_file: None,
}
}
fn default_server_port() -> u16 { 5432 }
fn default_server_host() -> String { "127.0.0.1".to_string() }
fn default_server_max_connections() -> u32 { 100 }
fn default_server_timeout() -> u64 { 30 }
fn default_thread_pool_size() -> usize { 4 }
fn default_debug_enabled() -> bool { false }
/// Конфигурация базы данных
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DatabaseConfig {
/// Директория для хранения данных
#[serde(default = "default_data_dir")]
pub data_dir: String,
/// Автоматически создавать базу данных при первом подключении
#[serde(default = "default_auto_create")]
pub auto_create: bool,
/// Режим транзакций
#[serde(default = "default_transaction_mode")]
pub transaction_mode: String,
/// Размер кэша в МБ
#[serde(default = "default_cache_size")]
pub cache_size_mb: u64,
/// Размер страницы в байтах
#[serde(default = "default_page_size")]
pub page_size: u32,
/// Включить MVCC (Multi-Version Concurrency Control)
#[serde(default = "default_mvcc_enabled")]
pub mvcc_enabled: bool,
/// Включить WAL (Write-Ahead Logging)
#[serde(default = "default_wal_enabled")]
pub wal_enabled: bool,
/// Максимальный размер WAL в МБ
#[serde(default = "default_max_wal_size")]
pub max_wal_size_mb: u64,
/// Автоматическая проверка целостности при запуске
#[serde(default = "default_integrity_check")]
pub integrity_check: bool,
/// Частота автоматического сохранения в секундах
#[serde(default = "default_auto_save_interval")]
pub auto_save_interval: u64,
/// Максимальное количество открытых файлов БД
#[serde(default = "default_max_open_files")]
pub max_open_files: u32,
}
/// Значения по умолчанию для DatabaseConfig
fn default_database_config() -> DatabaseConfig {
DatabaseConfig {
data_dir: default_data_dir(),
auto_create: default_auto_create(),
transaction_mode: default_transaction_mode(),
cache_size_mb: default_cache_size(),
page_size: default_page_size(),
mvcc_enabled: default_mvcc_enabled(),
wal_enabled: default_wal_enabled(),
max_wal_size_mb: default_max_wal_size(),
integrity_check: default_integrity_check(),
auto_save_interval: default_auto_save_interval(),
max_open_files: default_max_open_files(),
}
}
fn default_data_dir() -> String { "./data".to_string() }
fn default_auto_create() -> bool { true }
fn default_transaction_mode() -> String { "write_ahead_log".to_string() }
fn default_cache_size() -> u64 { 100 }
fn default_page_size() -> u32 { 8192 } // 8KB страницы по умолчанию
fn default_mvcc_enabled() -> bool { true }
fn default_wal_enabled() -> bool { true }
fn default_max_wal_size() -> u64 { 100 }
fn default_integrity_check() -> bool { true }
fn default_auto_save_interval() -> u64 { 60 } // 60 секунд
fn default_max_open_files() -> u32 { 1000 }
/// Конфигурация логгера
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LoggingConfig {
/// Уровень логирования
#[serde(default = "default_log_level")]
pub level: String,
/// Путь к файлу логов
#[serde(default = "default_log_path")]
pub log_file: String,
/// Максимальный размер файла логов в МБ
#[serde(default = "default_max_log_size")]
pub max_size_mb: u64,
/// Количество ротируемых файлов
#[serde(default = "default_backup_count")]
pub backup_count: u32,
/// Формат логов
#[serde(default = "default_log_format")]
pub format: String,
/// Включить логирование в stdout
#[serde(default = "default_stdout_enabled")]
pub stdout_enabled: bool,
/// Включить логирование в stderr
#[serde(default = "default_stderr_enabled")]
pub stderr_enabled: bool,
/// Включить логирование SQL запросов
#[serde(default = "default_sql_logging")]
pub sql_logging: bool,
/// Включить медленный лог (запросы дольше N секунд)
#[serde(default)]
pub slow_query_threshold_sec: Option<u64>,
}
/// Значения по умолчанию для LoggingConfig
fn default_logging_config() -> LoggingConfig {
LoggingConfig {
level: default_log_level(),
log_file: default_log_path(),
max_size_mb: default_max_log_size(),
backup_count: default_backup_count(),
format: default_log_format(),
stdout_enabled: default_stdout_enabled(),
stderr_enabled: default_stderr_enabled(),
sql_logging: default_sql_logging(),
slow_query_threshold_sec: None,
}
}
fn default_log_level() -> String { "info".to_string() }
fn default_log_path() -> String { "flusql.log".to_string() }
fn default_max_log_size() -> u64 { 10 }
fn default_backup_count() -> u32 { 5 }
fn default_log_format() -> String { "json".to_string() }
fn default_stdout_enabled() -> bool { true }
fn default_stderr_enabled() -> bool { false }
fn default_sql_logging() -> bool { true }
/// Конфигурация Lua интерпретатора
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LuaConfig {
/// Включен ли Lua интерпретатор
#[serde(default = "default_lua_enabled")]
pub enabled: bool,
/// Путь к директории со скриптами
#[serde(default = "default_lua_scripts_dir")]
pub scripts_dir: String,
/// Максимальное время выполнения скрипта в секундах
#[serde(default = "default_lua_timeout")]
pub timeout_seconds: u64,
/// Максимальная память для Lua VM в МБ
#[serde(default = "default_lua_memory_limit")]
pub memory_limit_mb: u64,
/// Разрешить доступ к файловой системе
#[serde(default = "default_lua_filesystem_access")]
pub filesystem_access: bool,
/// Разрешить сетевые операции
#[serde(default = "default_lua_network_access")]
pub network_access: bool,
/// Список разрешенных модулей
#[serde(default = "default_lua_allowed_modules")]
pub allowed_modules: Vec<String>,
}
/// Значения по умолчанию для LuaConfig
fn default_lua_config() -> LuaConfig {
LuaConfig {
enabled: default_lua_enabled(),
scripts_dir: default_lua_scripts_dir(),
timeout_seconds: default_lua_timeout(),
memory_limit_mb: default_lua_memory_limit(),
filesystem_access: default_lua_filesystem_access(),
network_access: default_lua_network_access(),
allowed_modules: default_lua_allowed_modules(),
}
}
fn default_lua_enabled() -> bool { true }
fn default_lua_scripts_dir() -> String { "./lua-scripts".to_string() }
fn default_lua_timeout() -> u64 { 30 }
fn default_lua_memory_limit() -> u64 { 100 }
fn default_lua_filesystem_access() -> bool { false }
fn default_lua_network_access() -> bool { false }
fn default_lua_allowed_modules() -> Vec<String> {
vec![
"string".to_string(),
"table".to_string(),
"math".to_string(),
"os".to_string(),
]
}
/// Конфигурация кластера
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClusterConfig {
/// Включен ли режим кластера
#[serde(default = "default_cluster_enabled")]
pub enabled: bool,
/// Идентификатор узла
#[serde(default = "default_node_id")]
pub node_id: String,
/// Адрес узла
#[serde(default = "default_node_address")]
pub node_address: String,
/// Режим кластера
#[serde(default = "default_cluster_mode")]
pub mode: String,
/// Список узлов кластера
#[serde(default)]
pub nodes: Vec<String>,
/// Интервал heartbeat в секундах
#[serde(default = "default_heartbeat_interval")]
pub heartbeat_interval: u64,
/// Таймаут heartbeat в секундах
#[serde(default = "default_heartbeat_timeout")]
pub heartbeat_timeout: u64,
/// Включить автоматическое восстановление
#[serde(default = "default_auto_recovery")]
pub auto_recovery: bool,
/// Максимальное количество реплик
#[serde(default = "default_max_replicas")]
pub max_replicas: u32,
}
/// Значения по умолчанию для ClusterConfig
fn default_cluster_config() -> ClusterConfig {
ClusterConfig {
enabled: default_cluster_enabled(),
node_id: default_node_id(),
node_address: default_node_address(),
mode: default_cluster_mode(),
nodes: vec![],
heartbeat_interval: default_heartbeat_interval(),
heartbeat_timeout: default_heartbeat_timeout(),
auto_recovery: default_auto_recovery(),
max_replicas: default_max_replicas(),
}
}
fn default_cluster_enabled() -> bool { false }
fn default_node_id() -> String { "node_1".to_string() }
fn default_node_address() -> String { "127.0.0.1:8080".to_string() }
fn default_cluster_mode() -> String { "single".to_string() }
fn default_heartbeat_interval() -> u64 { 5 }
fn default_heartbeat_timeout() -> u64 { 30 }
fn default_auto_recovery() -> bool { true }
fn default_max_replicas() -> u32 { 3 }
impl Default for Config {
fn default() -> Self {
Self {
server: default_server_config(),
database: default_database_config(),
logging: default_logging_config(),
lua: default_lua_config(),
cluster: default_cluster_config(),
plugins: default_plugins_config(),
http: default_http_config(),
replication: default_replication_config(),
network: default_network_config(),
}
}
}
impl Config {
/// Загрузка конфигурации из файла
pub fn load(path: &str) -> Result<Self, ConfigError> {
let config_content = fs::read_to_string(path)
.map_err(|e| ConfigError::IoError(e))?;
let config: Config = toml::from_str(&config_content)
.map_err(|e| ConfigError::ParseError(e))?;
Ok(config)
}
/// Создание конфигурации по умолчанию
pub fn default_with_path(data_dir: &str) -> Self {
let mut config = Self::default();
config.database.data_dir = data_dir.to_string();
config
}
/// Получение пути к директории данных для базы данных
pub fn get_data_path(&self, db_name: &str) -> String {
format!("{}/{}", self.database.data_dir, db_name)
}
/// Сохранение конфигурации в файл
pub fn save(&self, path: &str) -> Result<(), ConfigError> {
let config_content = toml::to_string_pretty(self)
.map_err(|e| ConfigError::SerializeError(e))?;
// Создаем директорию если она не существует
if let Some(parent) = Path::new(path).parent() {
fs::create_dir_all(parent)
.map_err(|e| ConfigError::IoError(e))?;
}
fs::write(path, config_content)
.map_err(|e| ConfigError::IoError(e))
}
/// Создание файла конфигурации по умолчанию
pub fn create_default_config(path: &str) -> Result<(), ConfigError> {
let default_config = Self::default();
default_config.save(path)
}
/// Получение конфигурации из переменных окружения или файла
pub fn from_env_or_file(default_path: &str) -> Result<Self, ConfigError> {
// Сначала пробуем загрузить из переменной окружения
if let Ok(config_path) = std::env::var("FLUSQL_CONFIG") {
return Self::load(&config_path);
}
// Пробуем загрузить из текущей директории
if Path::new(default_path).exists() {
return Self::load(default_path);
}
// Пробуем загрузить из домашней директории
if let Ok(home_dir) = std::env::var("HOME") {
let home_config = format!("{}/.config/flusql/config.toml", home_dir);
if Path::new(&home_config).exists() {
return Self::load(&home_config);
}
}
// Пробуем загрузить из /etc
let etc_config = "/etc/flusql/config.toml";
if Path::new(etc_config).exists() {
return Self::load(etc_config);
}
// Создаем конфигурацию по умолчанию
Ok(Self::default())
}
/// Проверка валидности конфигурации
pub fn validate(&self) -> Result<(), ConfigError> {
// Проверяем размер страницы (должен быть степенью двойки и в разумных пределах)
if self.database.page_size < 512 || self.database.page_size > 65536 {
return Err(ConfigError::Invalid(format!(
"Page size must be between 512 and 65536 bytes, got {}",
self.database.page_size
)));
}
// Проверяем что page_size является степенью двойки
if self.database.page_size & (self.database.page_size - 1) != 0 {
return Err(ConfigError::Invalid(format!(
"Page size must be a power of two, got {}",
self.database.page_size
)));
}
// Проверяем порты
// Исправление: убраны все проверки на > 65535, так как тип u16 гарантирует этот предел
// Оставляем только проверку на 0 (порт 0 недопустим для сервера)
if self.server.port == 0 {
return Err(ConfigError::Invalid(
"Server port cannot be 0".to_string()
));
}
if self.http.enabled {
// Исправление: убраны все проверки на > 65535, так как тип u16 гарантирует этот предел
// Оставляем только проверку на 0 (порт 0 недопустим для HTTP сервера)
if self.http.port == 0 {
return Err(ConfigError::Invalid(
"HTTP port cannot be 0".to_string()
));
}
if self.http.tls_enabled {
if self.http.tls_cert_path.is_none() || self.http.tls_key_path.is_none() {
return Err(ConfigError::Invalid(
"TLS requires both certificate and key paths".to_string()
));
}
}
}
// Проверяем директорию данных
if self.database.data_dir.trim().is_empty() {
return Err(ConfigError::Invalid("Data directory cannot be empty".to_string()));
}
Ok(())
}
}
/// Ошибки конфигурации
#[derive(Debug, Error)]
pub enum ConfigError {
#[error("IO error: {0}")]
IoError(std::io::Error),
#[error("Parse error: {0}")]
ParseError(toml::de::Error),
#[error("Serialize error: {0}")]
SerializeError(toml::ser::Error),
#[error("Configuration not found")]
NotFound,
#[error("Invalid configuration: {0}")]
Invalid(String),
}