567 lines
17 KiB
Rust
567 lines
17 KiB
Rust
|
|
// 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("Unknown error: {0}")]
|
|||
|
|
Unknown(String),
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Реализация преобразования из rlua::Error в FutriixError
|
|||
|
|
impl From<rlua::Error> for FutriixError {
|
|||
|
|
fn from(error: rlua::Error) -> Self {
|
|||
|
|
FutriixError::LuaError(error.to_string())
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Тип результата для Futriix
|
|||
|
|
pub type Result<T> = std::result::Result<T, FutriixError>;
|
|||
|
|
|
|||
|
|
// Модуль конфигурации
|
|||
|
|
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,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Конфигурация серверных параметров
|
|||
|
|
#[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<u16>,
|
|||
|
|
#[serde(default)]
|
|||
|
|
pub https_port: Option<u16>,
|
|||
|
|
#[serde(default)]
|
|||
|
|
pub http2_enabled: Option<bool>,
|
|||
|
|
#[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<String>,
|
|||
|
|
#[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<String>,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Конфигурация ACL
|
|||
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|||
|
|
pub struct AclConfig {
|
|||
|
|
#[serde(default)]
|
|||
|
|
pub enabled: bool,
|
|||
|
|
#[serde(default = "default_allowed_ips")]
|
|||
|
|
pub allowed_ips: Vec<String>,
|
|||
|
|
#[serde(default)]
|
|||
|
|
pub denied_ips: Vec<String>,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Конфигурация 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,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Функции для значений по умолчанию
|
|||
|
|
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<String> {
|
|||
|
|
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<String> {
|
|||
|
|
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
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
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 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(),
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
impl Config {
|
|||
|
|
/// Загрузка конфигурации из файла
|
|||
|
|
pub fn load(path: &str) -> Result<Self> {
|
|||
|
|
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();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
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<u8>,
|
|||
|
|
},
|
|||
|
|
Read {
|
|||
|
|
collection: String,
|
|||
|
|
id: String,
|
|||
|
|
},
|
|||
|
|
Update {
|
|||
|
|
collection: String,
|
|||
|
|
id: String,
|
|||
|
|
document: Vec<u8>,
|
|||
|
|
},
|
|||
|
|
Delete {
|
|||
|
|
collection: String,
|
|||
|
|
id: String,
|
|||
|
|
},
|
|||
|
|
Query {
|
|||
|
|
collection: String,
|
|||
|
|
filter: Vec<u8>,
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// Команды для процедур и транзакций
|
|||
|
|
CreateProcedure {
|
|||
|
|
name: String,
|
|||
|
|
code: Vec<u8>,
|
|||
|
|
},
|
|||
|
|
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<u8>,
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// Команды для шардинга с 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<u8>,
|
|||
|
|
},
|
|||
|
|
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<u8>,
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// Новые команды для 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<u8>),
|
|||
|
|
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<String>,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Структура для информации о 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<ShardInfo>,
|
|||
|
|
pub total_capacity: u64,
|
|||
|
|
pub total_used: u64,
|
|||
|
|
pub rebalance_needed: bool,
|
|||
|
|
pub cluster_formed: bool, // Новое поле: собран ли кластер
|
|||
|
|
pub leader_exists: bool, // Новое поле: существует ли лидер
|
|||
|
|
pub raft_nodes: Vec<RaftNodeInfo>, // Новое поле: список Raft узлов
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Wait-Free сериализация сообщений
|
|||
|
|
pub fn serialize<T: serde::Serialize>(value: &T) -> crate::common::Result<Vec<u8>> {
|
|||
|
|
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<T> {
|
|||
|
|
rmp_serde::from_slice(bytes)
|
|||
|
|
.map_err(|e| crate::common::FutriixError::SerializationError(e.to_string()))
|
|||
|
|
}
|
|||
|
|
}
|