From c3a7a509e0f6384c9b4e627d0d0c5a3223920cdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=93=D1=80=D0=B8=D0=B3=D0=BE=D1=80=D0=B8=D0=B9=20=D0=A1?= =?UTF-8?q?=D0=B0=D1=84=D1=80=D0=BE=D0=BD=D0=BE=D0=B2?= Date: Thu, 4 Dec 2025 19:13:38 +0000 Subject: [PATCH] Upload files to "src/common" --- src/common/mod.rs | 628 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 628 insertions(+) create mode 100644 src/common/mod.rs diff --git a/src/common/mod.rs b/src/common/mod.rs new file mode 100644 index 0000000..aa319b0 --- /dev/null +++ b/src/common/mod.rs @@ -0,0 +1,628 @@ +// src/common/mod.rs +//! Общие модули для Futriix +//! +//! Содержит общие структуры данных, ошибки, протоколы и конфигурацию, +//! используемые во всех компонентах системы с wait-free архитектурой. + +use thiserror::Error; +use serde::{Deserialize, Serialize}; +use std::fs; +use std::path::Path; + +/// Основной тип ошибки для Futriix +#[derive(Error, Debug)] +pub enum FutriixError { + #[error("Configuration error: {0}")] + ConfigError(String), + + #[error("Database error: {0}")] + DatabaseError(String), + + #[error("Lua error: {0}")] + LuaError(String), + + #[error("Network error: {0}")] + NetworkError(String), + + #[error("Replication error: {0}")] + ReplicationError(String), + + #[error("HTTP error: {0}")] + HttpError(String), + + #[error("Serialization error: {0}")] + SerializationError(String), + + #[error("IO error: {0}")] + IoError(#[from] std::io::Error), + + #[error("CSV error: {0}")] + CsvError(String), + + #[error("Sharding error: {0}")] + ShardingError(String), + + #[error("Transaction error: {0}")] + TransactionError(String), + + #[error("Unknown error: {0}")] + Unknown(String), +} + +// Реализация преобразования из rlua::Error в FutriixError +impl From for FutriixError { + fn from(error: rlua::Error) -> Self { + FutriixError::LuaError(error.to_string()) + } +} + +// Реализация преобразования из serde_json::Error в FutriixError +impl From for FutriixError { + fn from(error: serde_json::Error) -> Self { + FutriixError::SerializationError(error.to_string()) + } +} + +// Реализация преобразования из csv::Error в FutriixError +impl From for FutriixError { + fn from(error: csv::Error) -> Self { + FutriixError::CsvError(error.to_string()) + } +} + +/// Тип результата для Futriix +pub type Result = std::result::Result; + +// Модуль конфигурации +pub mod config { + use super::*; + + /// Конфигурация сервера + #[derive(Debug, Serialize, Deserialize, Clone)] + pub struct Config { + #[serde(default = "ServerConfig::default")] + pub server: ServerConfig, + #[serde(default = "ReplicationConfig::default")] + pub replication: ReplicationConfig, + #[serde(default = "ClusterConfig::default")] // Новая секция кластера + pub cluster: ClusterConfig, + #[serde(default = "LuaConfig::default")] + pub lua: LuaConfig, + #[serde(default = "AclConfig::default")] + pub acl: AclConfig, + #[serde(default = "TlsConfig::default")] + pub tls: TlsConfig, + #[serde(default = "CsvConfig::default")] + pub csv: CsvConfig, + #[serde(default = "ShardingConfig::default")] + pub sharding: ShardingConfig, + } + + /// Конфигурация серверных параметров + #[derive(Debug, Serialize, Deserialize, Clone)] + pub struct ServerConfig { + #[serde(default = "default_host")] + pub host: String, + #[serde(default = "default_port")] + pub port: u16, + #[serde(default)] + pub http_port: Option, + #[serde(default)] + pub https_port: Option, + #[serde(default)] + pub http2_enabled: Option, + #[serde(default = "default_http_enabled")] // Новая директива + pub http: bool, + #[serde(default = "default_https_enabled")] // Новая директива + pub https: bool, + } + + /// Конфигурация репликации + #[derive(Debug, Serialize, Deserialize, Clone)] + pub struct ReplicationConfig { + #[serde(default)] + pub enabled: bool, + #[serde(default = "default_master_nodes")] + pub master_nodes: Vec, + #[serde(default = "default_sync_interval")] + pub sync_interval: u64, + } + + /// Конфигурация кластера + #[derive(Debug, Serialize, Deserialize, Clone)] + pub struct ClusterConfig { + #[serde(default)] + pub enabled: bool, + #[serde(default = "default_cluster_name")] + pub name: String, + } + + /// Конфигурация Lua + #[derive(Debug, Serialize, Deserialize, Clone)] + pub struct LuaConfig { + #[serde(default = "default_scripts_dir")] + pub scripts_dir: String, + #[serde(default)] + pub auto_execute: Vec, + } + + /// Конфигурация ACL + #[derive(Debug, Serialize, Deserialize, Clone)] + pub struct AclConfig { + #[serde(default)] + pub enabled: bool, + #[serde(default = "default_allowed_ips")] + pub allowed_ips: Vec, + #[serde(default)] + pub denied_ips: Vec, + } + + /// Конфигурация TLS + #[derive(Debug, Serialize, Deserialize, Clone)] + pub struct TlsConfig { + #[serde(default)] + pub enabled: bool, + #[serde(default = "default_cert_path")] + pub cert_path: String, + #[serde(default = "default_key_path")] + pub key_path: String, + } + + /// Конфигурация CSV + #[derive(Debug, Serialize, Deserialize, Clone)] + pub struct CsvConfig { + #[serde(default = "default_csv_import_dir")] + pub import_dir: String, + #[serde(default = "default_csv_export_dir")] + pub export_dir: String, + #[serde(default = "default_max_csv_file_size")] + pub max_file_size: u64, + } + + /// Конфигурация шардинга + #[derive(Debug, Serialize, Deserialize, Clone)] + pub struct ShardingConfig { + #[serde(default = "default_sharding_enabled")] + pub enabled: bool, + #[serde(default = "default_virtual_nodes_per_node")] + pub virtual_nodes_per_node: usize, + #[serde(default = "default_min_nodes_for_cluster")] + pub min_nodes_for_cluster: usize, + } + + // Функции для значений по умолчанию + fn default_host() -> String { + "127.0.0.1".to_string() + } + + fn default_port() -> u16 { + 8081 + } + + fn default_http_enabled() -> bool { + true + } + + fn default_https_enabled() -> bool { + false + } + + fn default_master_nodes() -> Vec { + vec!["127.0.0.1:8081".to_string(), "127.0.0.1:8083".to_string()] + } + + fn default_sync_interval() -> u64 { + 5000 + } + + fn default_cluster_name() -> String { + "futriix-default-cluster".to_string() + } + + fn default_scripts_dir() -> String { + "lua_scripts".to_string() + } + + fn default_allowed_ips() -> Vec { + vec!["127.0.0.1".to_string(), "::1".to_string()] + } + + fn default_cert_path() -> String { + "certs/cert.pem".to_string() + } + + fn default_key_path() -> String { + "certs/key.pem".to_string() + } + + fn default_csv_import_dir() -> String { + "./futriix_csv/import".to_string() + } + + fn default_csv_export_dir() -> String { + "./futriix_csv/export".to_string() + } + + fn default_max_csv_file_size() -> u64 { + 104857600 // 100MB + } + + fn default_sharding_enabled() -> bool { + false + } + + fn default_virtual_nodes_per_node() -> usize { + 160 + } + + fn default_min_nodes_for_cluster() -> usize { + 3 + } + + impl Default for ServerConfig { + fn default() -> Self { + Self { + host: default_host(), + port: default_port(), + http_port: Some(8082), + https_port: None, + http2_enabled: Some(false), + http: default_http_enabled(), + https: default_https_enabled(), + } + } + } + + impl Default for ReplicationConfig { + fn default() -> Self { + Self { + enabled: false, + master_nodes: default_master_nodes(), + sync_interval: default_sync_interval(), + } + } + } + + impl Default for ClusterConfig { + fn default() -> Self { + Self { + enabled: false, + name: default_cluster_name(), + } + } + } + + impl Default for LuaConfig { + fn default() -> Self { + Self { + scripts_dir: default_scripts_dir(), + auto_execute: vec!["init.lua".to_string()], + } + } + } + + impl Default for AclConfig { + fn default() -> Self { + Self { + enabled: false, + allowed_ips: default_allowed_ips(), + denied_ips: vec![], + } + } + } + + impl Default for TlsConfig { + fn default() -> Self { + Self { + enabled: false, + cert_path: default_cert_path(), + key_path: default_key_path(), + } + } + } + + impl Default for CsvConfig { + fn default() -> Self { + Self { + import_dir: default_csv_import_dir(), + export_dir: default_csv_export_dir(), + max_file_size: default_max_csv_file_size(), + } + } + } + + impl Default for ShardingConfig { + fn default() -> Self { + Self { + enabled: default_sharding_enabled(), + virtual_nodes_per_node: default_virtual_nodes_per_node(), + min_nodes_for_cluster: default_min_nodes_for_cluster(), + } + } + } + + impl Default for Config { + fn default() -> Self { + Self { + server: ServerConfig::default(), + replication: ReplicationConfig::default(), + cluster: ClusterConfig::default(), + lua: LuaConfig::default(), + acl: AclConfig::default(), + tls: TlsConfig::default(), + csv: CsvConfig::default(), + sharding: ShardingConfig::default(), + } + } + } + + impl Config { + /// Загрузка конфигурации из файла + pub fn load(path: &str) -> Result { + let path = Path::new(path); + + if !path.exists() { + // Создание конфигурации по умолчанию + let default_config = Config::default(); + let toml_content = toml::to_string_pretty(&default_config) + .map_err(|e| FutriixError::ConfigError(e.to_string()))?; + + fs::write(path, toml_content) + .map_err(|e| FutriixError::ConfigError(e.to_string()))?; + + println!("Created default configuration file: {}", path.display()); + return Ok(default_config); + } + + let content = fs::read_to_string(path) + .map_err(|e| FutriixError::ConfigError(e.to_string()))?; + + // Парсим конфигурацию с использованием значений по умолчанию + let mut config: Config = toml::from_str(&content) + .map_err(|e| FutriixError::ConfigError(e.to_string()))?; + + // Убеждаемся, что все поля имеют значения по умолчанию, если они отсутствуют + if config.server.host.is_empty() { + config.server.host = default_host(); + } + if config.server.port == 0 { + config.server.port = default_port(); + } + if config.replication.master_nodes.is_empty() { + config.replication.master_nodes = default_master_nodes(); + } + if config.replication.sync_interval == 0 { + config.replication.sync_interval = default_sync_interval(); + } + if config.cluster.name.is_empty() { + config.cluster.name = default_cluster_name(); + } + if config.lua.scripts_dir.is_empty() { + config.lua.scripts_dir = default_scripts_dir(); + } + if config.acl.allowed_ips.is_empty() { + config.acl.allowed_ips = default_allowed_ips(); + } + if config.tls.cert_path.is_empty() { + config.tls.cert_path = default_cert_path(); + } + if config.tls.key_path.is_empty() { + config.tls.key_path = default_key_path(); + } + if config.csv.import_dir.is_empty() { + config.csv.import_dir = default_csv_import_dir(); + } + if config.csv.export_dir.is_empty() { + config.csv.export_dir = default_csv_export_dir(); + } + if config.csv.max_file_size == 0 { + config.csv.max_file_size = default_max_csv_file_size(); + } + if config.sharding.virtual_nodes_per_node == 0 { + config.sharding.virtual_nodes_per_node = default_virtual_nodes_per_node(); + } + if config.sharding.min_nodes_for_cluster == 0 { + config.sharding.min_nodes_for_cluster = default_min_nodes_for_cluster(); + } + + Ok(config) + } + + /// Сохранение конфигурации в файл + #[allow(dead_code)] + pub fn save(&self, path: &str) -> Result<()> { + let toml_content = toml::to_string_pretty(self) + .map_err(|e| FutriixError::ConfigError(e.to_string()))?; + + fs::write(path, toml_content) + .map_err(|e| FutriixError::ConfigError(e.to_string())) + } + } +} + +// Модуль протокола +pub mod protocol { + use serde::{Deserialize, Serialize}; + + /// Команды для выполнения в базе данных + #[derive(Debug, Clone, Serialize, Deserialize)] + pub enum Command { + // Базовые CRUD команды + Create { + collection: String, + document: Vec, + }, + Read { + collection: String, + id: String, + }, + Update { + collection: String, + id: String, + document: Vec, + }, + Delete { + collection: String, + id: String, + }, + Query { + collection: String, + filter: Vec, + }, + + // Команды для процедур и транзакций + CreateProcedure { + name: String, + code: Vec, + }, + CallProcedure { + name: String, + }, + BeginTransaction { + transaction_id: String, + }, + CommitTransaction { + transaction_id: String, + }, + RollbackTransaction { + transaction_id: String, + }, + + // Команды для индексов + CreateIndex { + collection: String, + index: crate::server::database::Index, + }, + QueryByIndex { + collection: String, + index_name: String, + value: Vec, + }, + + // Команды для шардинга с Raft + AddShardNode { + node_id: String, + address: String, + capacity: u64, + }, + RemoveShardNode { + node_id: String, + }, + MigrateShard { + collection: String, + from_node: String, + to_node: String, + shard_key: String, + }, + RebalanceCluster, + GetClusterStatus, + StartElection, // Новая команда для Raft выборов + GetRaftNodes, // Новая команда для получения Raft узлов + + // Команды для constraints + AddConstraint { + collection: String, + constraint_name: String, + constraint_type: String, + field: String, + value: Vec, + }, + RemoveConstraint { + collection: String, + constraint_name: String, + }, + + // Команды для компрессии + EnableCompression { + collection: String, + algorithm: String, + }, + DisableCompression { + collection: String, + }, + + // Команды для глобальных индексов + CreateGlobalIndex { + name: String, + field: String, + unique: bool, + }, + QueryGlobalIndex { + index_name: String, + value: Vec, + }, + + // Новые команды для CSV импорта/экспорта + ImportCsv { + collection: String, + file_path: String, + }, + ExportCsv { + collection: String, + file_path: String, + }, + ListCsvFiles, + GetImportProgress { + collection: String, + }, + } + + /// Ответы от базы данных + #[derive(Debug, Clone, Serialize, Deserialize)] + pub enum Response { + Success(Vec), + Error(String), + } + + /// Сообщение для репликации + #[derive(Debug, Clone, Serialize, Deserialize)] + pub struct ReplicationMessage { + pub sequence: u64, + pub command: Command, + pub timestamp: i64, + } + + /// Структура для информации о шарде + #[derive(Debug, Clone, Serialize, Deserialize)] + pub struct ShardInfo { + pub node_id: String, + pub address: String, + pub capacity: u64, + pub used: u64, + pub collections: Vec, + } + + /// Структура для информации о Raft узле + #[derive(Debug, Clone, Serialize, Deserialize)] + pub struct RaftNodeInfo { + pub node_id: String, + pub address: String, + pub state: String, // "leader", "follower", "candidate" + pub term: u64, + pub last_heartbeat: i64, + } + + /// Структура для статуса кластера + #[derive(Debug, Clone, Serialize, Deserialize)] + pub struct ClusterStatus { + pub nodes: Vec, + pub total_capacity: u64, + pub total_used: u64, + pub rebalance_needed: bool, + pub cluster_formed: bool, // Новое поле: собран ли кластер + pub leader_exists: bool, // Новое поле: существует ли лидер + pub raft_nodes: Vec, // Новое поле: список Raft узлов + } + + /// Wait-Free сериализация сообщений + pub fn serialize(value: &T) -> crate::common::Result> { + rmp_serde::to_vec(value) + .map_err(|e| crate::common::FutriixError::SerializationError(e.to_string())) + } + + /// Wait-Free десериализация сообщений + pub fn deserialize<'a, T: serde::Deserialize<'a>>(bytes: &'a [u8]) -> crate::common::Result { + rmp_serde::from_slice(bytes) + .map_err(|e| crate::common::FutriixError::SerializationError(e.to_string())) + } +}