diff --git a/src/utils/config.rs b/src/utils/config.rs deleted file mode 100644 index 0ab352d..0000000 --- a/src/utils/config.rs +++ /dev/null @@ -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, - - /// Запрещенные функции Lua - #[serde(default = "default_blocked_functions")] - pub blocked_functions: Vec, -} - -/// Значения по умолчанию для 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 { - vec![ - "database".to_string(), - "table".to_string(), - "query".to_string(), - "index".to_string(), - "event".to_string(), - "log".to_string(), - ] -} -fn default_blocked_functions() -> Vec { - 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, - - /// Путь к приватному ключу TLS - #[serde(default)] - pub tls_key_path: Option, -} - -/// Значения по умолчанию для 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, - - /// Список слейв-серверов - #[serde(default)] - pub slaves: Vec, -} - -/// Значения по умолчанию для 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, -} - -/// Значения по умолчанию для 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, -} - -/// Значения по умолчанию для 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, -} - -/// Значения по умолчанию для 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 { - 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, - - /// Интервал 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 { - 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 { - // Сначала пробуем загрузить из переменной окружения - 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), -}