[WIP] paths

This commit is contained in:
Alex-Emmet 2026-07-24 01:36:14 +02:00
commit 3bc5cc959a
20 changed files with 817 additions and 241 deletions

View file

@ -7,6 +7,7 @@ edition = "2024"
iota-logger = { path = "../iota-logger" }
iota-state = { path = "../iota-state" }
iota-util = { path = "../iota-util" }
iota-paths = { path = "../iota-paths" }
mtp = { git = "https://git.methanium.net/Methanium/mtp.git" }

View file

@ -1,8 +1,10 @@
use arc_swap::ArcSwap;
use iota_util::file_util::{load_file, save_file};
use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize};
use std::fs;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::sync::OnceLock;
pub static CONFIG: Lazy<ArcSwap<IotaConfig>> =
Lazy::new(|| ArcSwap::new(Arc::new(IotaConfig::default())));
@ -19,11 +21,11 @@ pub struct IotaConfig {
pub omikron_host: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub omikron_port: Option<u16>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(skip_serializing)]
pub keyring: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(skip_serializing)]
pub public_key: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(skip_serializing)]
pub private_key: Option<String>,
#[serde(default = "default_read_receipts_enabled")]
pub read_receipts_enabled: bool,
@ -61,7 +63,7 @@ fn default_web_bind() -> String {
"127.0.0.1".into()
}
fn default_web_asset_dir() -> String {
"web".into()
String::new()
}
impl Default for WebSettings {
fn default() -> Self {
@ -102,17 +104,27 @@ impl Default for IotaConfig {
}
pub fn load_config() {
let s = load_file("", "config.yaml");
if s.is_empty() {
return;
}
load_config_from(&default_config_path());
}
/// Loading is intentionally side-effect free: a missing configuration means
/// documented defaults, not a newly-created file.
pub fn load_config_from(path: &Path) {
let s = match fs::read_to_string(path) {
Ok(contents) => contents,
Err(error) if error.kind() == std::io::ErrorKind::NotFound => return,
Err(error) => {
eprintln!("Failed to read {}: {error}", path.display());
return;
}
};
match serde_yaml::from_str::<IotaConfig>(&s) {
Ok(parsed) => {
CONFIG.store(Arc::new(parsed));
}
Err(e) => {
eprintln!("Failed to parse config.yaml: {}. Content: '{}'", e, s);
eprintln!("Failed to parse {}: {e}", path.display());
}
}
}
@ -123,14 +135,45 @@ pub fn clear_config() {
}
pub fn save_config() {
save_config_to(&default_config_path());
}
pub fn save_config_to(path: &Path) {
if let Ok(yaml) = serde_yaml::to_string(&**CONFIG.load()) {
save_file("", "config.yaml", &yaml);
if let Some(parent) = path.parent() {
if let Err(error) = fs::create_dir_all(parent) {
eprintln!(
"Cannot create configuration directory {}: {error}",
parent.display()
);
return;
}
}
let temporary = path.with_extension("yaml.tmp");
if let Err(error) = fs::write(&temporary, yaml).and_then(|_| fs::rename(&temporary, path)) {
eprintln!("Cannot save {}: {error}", path.display());
let _ = fs::remove_file(temporary);
}
}
}
fn default_config_path() -> PathBuf {
if let Some(path) = CONFIG_PATH.get() {
return path.clone();
}
iota_paths::IotaPaths::resolve(iota_paths::Scope::User)
.expect("resolve Iota user paths")
.config_file
}
pub fn modify_config(f: impl FnOnce(&mut IotaConfig)) {
let mut cfg = IotaConfig::clone(&**CONFIG.load());
f(&mut cfg);
CONFIG.store(Arc::new(cfg));
save_config();
}
static CONFIG_PATH: OnceLock<PathBuf> = OnceLock::new();
pub fn configure_config_path(path: PathBuf) {
let _ = CONFIG_PATH.set(path);
}

View file

@ -1,4 +1,3 @@
use iota_util::file_util::get_directory;
use once_cell::sync::Lazy;
use r2d2::ManageConnection;
use rusqlite::Connection;
@ -56,10 +55,12 @@ where
f(&conn)
}
fn db_file_path(db_name: &str) -> String {
let mut p = PathBuf::from(get_directory());
p.push(format!("{db_name}.sqlite3"));
p.to_string_lossy().to_string()
fn db_file_path(db_name: &str) -> PathBuf {
let storage_dir = iota_util::file_util::storage_directory();
// Creating storage belongs to initialization/connection setup, never to a
// configuration read.
std::fs::create_dir_all(&storage_dir).expect("create Iota storage directory");
storage_dir.join(format!("{db_name}.sqlite3"))
}
fn run_migrations(pool: &r2d2::Pool<SqliteManager>) -> Result<(), StorageError> {