NAC_Blockchain/nac-cli/src/config.rs

180 lines
5.5 KiB
Rust

use crate::error::{CliError, Result};
use serde::{Deserialize, Serialize};
use std::fs;
use std::path::PathBuf;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
pub network: NetworkConfig,
pub account: AccountConfig,
pub transaction: TransactionConfig,
pub logging: LoggingConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NetworkConfig {
pub rpc_url: String,
pub chain_id: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AccountConfig {
pub default_account: Option<String>,
pub keystore_dir: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TransactionConfig {
pub gas_limit: u64,
pub gas_price: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LoggingConfig {
pub level: String,
}
impl Default for Config {
fn default() -> Self {
Self {
network: NetworkConfig {
rpc_url: "http://localhost:8545".to_string(),
chain_id: 1,
},
account: AccountConfig {
default_account: None,
keystore_dir: Self::default_keystore_dir()
.to_str()
.expect("Failed to convert path to string")
.to_string(),
},
transaction: TransactionConfig {
gas_limit: 21000,
gas_price: 1000000000,
},
logging: LoggingConfig {
level: "info".to_string(),
},
}
}
}
impl Config {
/// 获取配置文件路径
pub fn config_path() -> PathBuf {
let home = dirs::home_dir().expect("无法获取用户主目录");
home.join(".nac").join("config.toml")
}
/// 获取默认keystore目录
pub fn default_keystore_dir() -> PathBuf {
let home = dirs::home_dir().expect("无法获取用户主目录");
home.join(".nac").join("keystore")
}
/// 加载配置
pub fn load() -> Result<Self> {
let path = Self::config_path();
if !path.exists() {
return Ok(Self::default());
}
let content = fs::read_to_string(&path)
.map_err(|e| CliError::Config(format!("读取配置文件失败: {}", e)))?;
toml::from_str(&content)
.map_err(|e| CliError::Config(format!("解析配置文件失败: {}", e)))
}
/// 保存配置
pub fn save(&self) -> Result<()> {
let path = Self::config_path();
// 创建目录
if let Some(parent) = path.parent() {
fs::create_dir_all(parent)
.map_err(|e| CliError::Config(format!("创建配置目录失败: {}", e)))?;
}
// 序列化配置
let content = toml::to_string_pretty(self)
.map_err(|e| CliError::Config(format!("序列化配置失败: {}", e)))?;
// 写入文件
fs::write(&path, content)
.map_err(|e| CliError::Config(format!("写入配置文件失败: {}", e)))?;
Ok(())
}
/// 获取配置项
pub fn get(&self, key: &str) -> Option<String> {
match key {
"network.rpc_url" => Some(self.network.rpc_url.clone()),
"network.chain_id" => Some(self.network.chain_id.to_string()),
"account.default_account" => self.account.default_account.clone(),
"account.keystore_dir" => Some(self.account.keystore_dir.clone()),
"transaction.gas_limit" => Some(self.transaction.gas_limit.to_string()),
"transaction.gas_price" => Some(self.transaction.gas_price.to_string()),
"logging.level" => Some(self.logging.level.clone()),
_ => None,
}
}
/// 获取当前RPC URL
pub fn get_current_rpc_url(&self) -> String {
self.network.rpc_url.clone()
}
/// 设置配置项
pub fn set(&mut self, key: &str, value: &str) -> Result<()> {
match key {
"network.rpc_url" => self.network.rpc_url = value.to_string(),
"network.chain_id" => {
self.network.chain_id = value
.parse()
.map_err(|_| CliError::Config("无效的chain_id".to_string()))?;
}
"account.default_account" => self.account.default_account = Some(value.to_string()),
"account.keystore_dir" => self.account.keystore_dir = value.to_string(),
"transaction.gas_limit" => {
self.transaction.gas_limit = value
.parse()
.map_err(|_| CliError::Config("无效的gas_limit".to_string()))?;
}
"transaction.gas_price" => {
self.transaction.gas_price = value
.parse()
.map_err(|_| CliError::Config("无效的gas_price".to_string()))?;
}
"logging.level" => self.logging.level = value.to_string(),
_ => return Err(CliError::Config(format!("未知的配置项: {}", key))),
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config() {
let config = Config::default();
assert_eq!(config.network.rpc_url, "http://localhost:8545");
assert_eq!(config.network.chain_id, 1);
}
#[test]
fn test_get_set_config() {
let mut config = Config::default();
config
.set("network.rpc_url", "http://example.com")
.expect("Failed to set config");
assert_eq!(
config.get("network.rpc_url"),
Some("http://example.com".to_string())
);
}
}