175 lines
5.4 KiB
Rust
175 lines
5.4 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,
|
|
}
|
|
}
|
|
|
|
/// 设置配置项
|
|
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())
|
|
);
|
|
}
|
|
}
|