diff --git a/context/Cargo.toml b/context/Cargo.toml index 7c7419019..d88453ba2 100644 --- a/context/Cargo.toml +++ b/context/Cargo.toml @@ -17,3 +17,4 @@ jupiter = { workspace = true } vault = { workspace = true } gemini = { workspace = true, optional = true } +tokio = "1.45.1" diff --git a/context/src/lib.rs b/context/src/lib.rs index b168e19a0..a22e49117 100644 --- a/context/src/lib.rs +++ b/context/src/lib.rs @@ -22,9 +22,17 @@ pub struct AppContext { impl AppContext { /// Creates a new application context with the given configuration. pub async fn new(config: common::config::Config) -> Self { + let config = Arc::new(config); + let storage = jupiter::storage::Storage::new(config.clone()).await; - let vault = vault::integration::vault_core::VaultCore::new(storage.clone()); + + let storage_for_vault = storage.clone(); + let vault = tokio::task::spawn_blocking(move || { + vault::integration::vault_core::VaultCore::new(storage_for_vault) + }).await.expect("VaultCore::new panicked"); + + #[cfg(feature = "p2p")] let client = gemini::p2p::client::P2PClient::new(storage.clone(), vault.clone()); @@ -41,9 +49,12 @@ impl AppContext { #[cfg(feature = "p2p")] client, } + + } pub fn wrapped_context(&self) -> Arc { Arc::new(self.clone()) } } + diff --git a/monobean/Cargo.toml b/monobean/Cargo.toml index 21f621928..9d5a4e9f1 100644 --- a/monobean/Cargo.toml +++ b/monobean/Cargo.toml @@ -25,6 +25,7 @@ vault = { path = "../vault" } gateway = { path = "../gateway" } ceres = { path = "../ceres" } mercury = { path = "../mercury" } +context = {path = "../context"} thiserror = { version = "2.0.11", features = ["default"] } tracing-subscriber = { version = "0.3.19", features = ["default", "env-filter"] } diff --git a/monobean/src/application.rs b/monobean/src/application.rs index 03cd320c1..9058346ea 100644 --- a/monobean/src/application.rs +++ b/monobean/src/application.rs @@ -294,7 +294,7 @@ impl MonobeanApplication { glib::LogLevel::Debug => tracing::Level::DEBUG, }; - println!("{}: {}", level, fields); + println!("{level}: {fields}"); }, ); } diff --git a/monobean/src/components/hello_page.rs b/monobean/src/components/hello_page.rs index 7af4792d6..dcc9a04cf 100644 --- a/monobean/src/components/hello_page.rs +++ b/monobean/src/components/hello_page.rs @@ -89,7 +89,7 @@ impl HelloPage { fn setup_logo(&self) { let logo = self.imp().logo.clone(); let id = random_int_range(1, 6); - logo.set_icon_name(Some(format!("walrus-{}", id).as_str())); + logo.set_icon_name(Some(format!("walrus-{id}").as_str())); let gesture = gtk::GestureClick::new(); gesture.connect_pressed(clone!( @@ -97,7 +97,7 @@ impl HelloPage { logo, move |_, _, _, _| { let id = random_int_range(1, 6); - logo.set_icon_name(Some(format!("walrus-{}", id).as_str())); + logo.set_icon_name(Some(format!("walrus-{id}").as_str())); } )); logo.add_controller(gesture); diff --git a/monobean/src/config.rs b/monobean/src/config.rs index 08f4de201..470a3eccd 100644 --- a/monobean/src/config.rs +++ b/monobean/src/config.rs @@ -95,7 +95,7 @@ macro_rules! get_setting { pub fn monobean_base() -> PathBuf { // Get the base directory from the environment variable or use the default std::env::var("MONOBEAN_BASE_DIR") - .map(|inner| PathBuf::from(inner)) + .map(PathBuf::from) .unwrap_or_else(|_| common::config::mega_base().join("monobean")) } @@ -119,7 +119,7 @@ pub fn monobean_base() -> PathBuf { pub fn monobean_cache() -> PathBuf { // Get the cache directory from the environment variable or use the default std::env::var("MONOBEAN_CACHE_DIR") - .map(|inner| PathBuf::from(inner)) + .map(PathBuf::from) .unwrap_or_else(|_| common::config::mega_cache().join("monobean")) } diff --git a/monobean/src/core/mega_core.rs b/monobean/src/core/mega_core.rs index cadba8386..0268396de 100644 --- a/monobean/src/core/mega_core.rs +++ b/monobean/src/core/mega_core.rs @@ -9,7 +9,7 @@ use ceres::api_service::ApiHandler; use ceres::protocol::repo::Repo; use common::config::Config; use common::model::P2pOptions; -use jupiter::context::Context as MegaContext; +use context::AppContext as MegaContext; use mercury::internal::object::tree::Tree; use std::fmt; use std::fmt::{Debug, Formatter}; @@ -18,6 +18,7 @@ use std::path::{Component, Path, PathBuf}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; use tokio::sync::{oneshot, OnceCell, RwLock}; +use vault::integration::vault_core::VaultCore; use vault::pgp::{SignedPublicKey, SignedSecretKey}; pub struct MegaCore { @@ -146,19 +147,28 @@ impl MegaCore { return; } - if let Some(pk) = vault::pgp::load_pub_key().await { - let sk = vault::pgp::load_sec_key().await.unwrap(); + let guard = self.running_context.read().await; + let vault_core = if let Some(ctx) = guard.as_ref() { + &ctx.vault + } else { + let err_msg = "Mega core is not running, failed to get vault core"; + tracing::error!(err_msg); + return; + }; + + if let Some(pk) = vault_core.load_pub_key() { + let sk = vault_core.load_sec_key().await.unwrap(); chan.send(Ok(())).unwrap(); self.pgp.set((pk, sk)).unwrap(); } else { - let uid = format!("{} <{}>", user_name, user_email); - let params = vault::pgp::params( + let uid = format!("{user_name} <{user_email}>"); + let params = VaultCore::params( vault::pgp::KeyType::Rsa(2048), passwd.clone(), uid.as_ref(), ); - let (pk, sk) = vault::pgp::gen_pgp_keypair(params, passwd); - vault::pgp::save_keys(pk.clone(), sk.clone()).await; + let (pk, sk) = vault_core.gen_pgp_keypair(params, passwd); + vault_core.save_keys(pk.clone(), sk.clone()); chan.send(Ok(())).unwrap(); self.pgp.set((pk, sk)).unwrap(); } @@ -190,9 +200,18 @@ impl MegaCore { self.initialized.store(true, Ordering::Release); } + let guard = self.running_context.read().await; + let vault_core = if let Some(ctx) = guard.as_ref() { + &ctx.vault + } else { + let err_msg = "Mega core is not running, failed to get vault core"; + tracing::error!(err_msg); + return; + }; + // Try to load pgp keys from vault. - if let Some(pk) = vault::pgp::load_pub_key().await { - let sk = vault::pgp::load_sec_key().await.unwrap(); + if let Some(pk) = vault_core.load_pub_key() { + let sk = vault_core.load_sec_key().await.unwrap(); self.pgp.set((pk, sk)).unwrap(); tracing::debug!("Loaded pgp keys from vault"); } @@ -211,13 +230,9 @@ impl MegaCore { return Err(MonoBeanError::MegaCoreError(err.to_string())); } - let config: Arc = self.config.read().await.clone().into(); + let config = self.config.read().await.clone(); + let inner = MegaContext::new(config.clone()).await; - inner - .services - .mono_storage - .init_monorepo(&config.monorepo) - .await; let http_ctx = inner.clone(); *self.http_options.write().await = http_addr @@ -281,7 +296,9 @@ impl MegaCore { if path.as_ref().starts_with(&import_dir) && path.as_ref() != import_dir { if let Some(model) = ctx + .storage .services + .as_ref() .git_db_storage .find_git_repo_like_path(path.as_ref().to_string_lossy().as_ref()) .await @@ -289,13 +306,13 @@ impl MegaCore { { let repo: Repo = model.into(); return Ok(Box::new(ImportApiService { - context: ctx.clone(), + storage: ctx.storage.clone(), repo, })); } } let ret: Box = Box::new(MonoApiService { - context: ctx.clone(), + storage: ctx.storage.clone(), }); // Rust-analyzer cannot infer the type of `ret` correctly and always reports an error. @@ -319,7 +336,7 @@ impl MegaCore { match tree { Ok(Some(tree)) => Ok(tree), _ => { - let err_msg = format!("Failed to load tree: {:?}", path); + let err_msg = format!("Failed to load tree: {path:?}"); tracing::error!(err_msg); Err(MonoBeanError::MegaCoreError(err_msg)) } @@ -328,7 +345,9 @@ impl MegaCore { async fn load_blob(&self, id: impl AsRef) -> MonoBeanResult { let ctx = self.running_context.read().await.clone().unwrap(); - let mono = MonoApiService { context: ctx }; + let mono = MonoApiService { + storage: ctx.storage, + }; let raw = mono .get_raw_blob_by_hash(id.as_ref()) .await @@ -338,7 +357,7 @@ impl MegaCore { Some(data) => match String::from_utf8(data) { Ok(string) => Ok(string), Err(err) => { - let err_msg = format!("Invalid UTF-8 data: {}", err); + let err_msg = format!("Invalid UTF-8 data: {err}"); tracing::error!(err_msg); Err(MonoBeanError::MegaCoreError(err_msg)) } @@ -500,7 +519,14 @@ mod tests { #[tokio::test] async fn test_launch_http() { let temp_base = TempDir::new().unwrap(); + + // 设置环境变量,让 mega_base() 返回临时目录 + unsafe { + std::env::set_var("MEGA_BASE_DIR", temp_base.path()); + } + let core = test_core(&temp_base).await; + core.process_command(MegaCommands::MegaStart( Some(SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 8080)), None, @@ -515,9 +541,12 @@ mod tests { assert!(core.ssh_options.read().await.is_none()); } - #[tokio::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn test_launch_ssh() { let temp_base = TempDir::new().unwrap(); + unsafe { + std::env::set_var("MEGA_BASE_DIR", temp_base.path()); + } let core = test_core(&temp_base).await; core.process_command(MegaCommands::MegaStart( None, diff --git a/monobean/src/core/servers.rs b/monobean/src/core/servers.rs index 4c8358489..fe110a9d8 100644 --- a/monobean/src/core/servers.rs +++ b/monobean/src/core/servers.rs @@ -1,8 +1,8 @@ use crate::error::MonoBeanResult; use bytes::BytesMut; use common::model::P2pOptions; +use context::AppContext as MegaContext; use gateway::https_server::{app, check_run_with_p2p}; -use jupiter::context::Context as MegaContext; use mono::git_protocol::ssh::SshServer; use russh::server::Server; use std::collections::HashMap; @@ -31,7 +31,7 @@ impl HttpOptions { pub async fn run_server(&self, mega_ctx: MegaContext) -> MonoBeanResult<()> { let app = app( - mega_ctx.clone(), + mega_ctx.storage.clone(), self.addr.ip().to_string(), self.addr.port(), self.p2p.clone(), @@ -88,7 +88,7 @@ impl SshOptions { // Use rusty vault configurations... let (tx, mut rx) = mpsc::channel::<()>(1); self.abort.set(tx).unwrap(); - let key = mono::server::ssh_server::load_key().await; + let key = mono::server::ssh_server::load_key(mega_ctx.clone()); let ssh_config = russh::server::Config { auth_rejection_time: std::time::Duration::from_secs(3), keys: vec![key], @@ -100,7 +100,7 @@ impl SshOptions { let mut ssh_server = SshServer { clients: Arc::new(Mutex::new(HashMap::new())), id: 0, - context: mega_ctx, + storage: mega_ctx.storage.clone(), smart_protocol: None, data_combined: BytesMut::new(), }; diff --git a/monobean/src/window.rs b/monobean/src/window.rs index 3004e4bc6..0fb48cbe4 100644 --- a/monobean/src/window.rs +++ b/monobean/src/window.rs @@ -253,7 +253,7 @@ fn load_css() { .into_iter() .map(|f| { let provider = CssProvider::new(); - provider.load_from_resource(&format!("{}/css/{}", PREFIX, f)); + provider.load_from_resource(&format!("{PREFIX}/css/{f}")); style_context_add_provider_for_display( >k::gdk::Display::default().expect("Could not connect to a display."), &provider, diff --git a/vault/src/integration/vault_core.rs b/vault/src/integration/vault_core.rs index ee07f5651..ca24c9d82 100644 --- a/vault/src/integration/vault_core.rs +++ b/vault/src/integration/vault_core.rs @@ -1,8 +1,4 @@ -use std::{ - path::PathBuf, - sync::{Arc, RwLock}, -}; - +use std::{path::PathBuf, sync::{Arc, RwLock}}; use crate::integration::jupiter_backend::JupiterBackend; use common::errors::MegaError; use jupiter::storage::Storage; @@ -18,6 +14,8 @@ use tracing::log; const CORE_KEY_FILE: &str = "core_key.json"; // where the core key is stored, like `root_token` + + #[derive(Debug, Clone, Serialize, Deserialize)] struct CoreKey { secret_shares: Vec>, @@ -51,9 +49,10 @@ impl VaultCore { pub fn new(ctx: Storage) -> Self { let dir = common::config::mega_base().join("vault"); let key_path = dir.join(CORE_KEY_FILE); - + println!("{:?}", key_path); std::fs::create_dir_all(&dir).expect("Failed to create vault directory"); - Self::config(ctx, key_path) + let result = Self::config(ctx.clone(), key_path); + result } fn config(ctx: Storage, key_path: PathBuf) -> Self { @@ -71,6 +70,7 @@ impl VaultCore { }; let core = Arc::new(RwLock::new(core)); + let key = { let mut managed_core = core.write().unwrap(); managed_core @@ -78,6 +78,8 @@ impl VaultCore { .expect("Failed to configure vault core"); let core_key = if !key_path.exists() { + + let result = managed_core .init(&seal_config) .expect("Failed to initialize vault"); @@ -85,9 +87,9 @@ impl VaultCore { secret_shares: Vec::from(&result.secret_shares[..]), root_token: result.root_token, }; - let file = std::fs::File::create(key_path).unwrap(); + println!("[vault] Creating new core_key.json at: {}", key_path.display()); + let file = std::fs::File::create(&key_path).unwrap(); serde_json::to_writer_pretty(file, &core_key).unwrap(); - core_key } else { println!("Using existing vault core key file: {}", key_path.display()); @@ -110,7 +112,6 @@ impl VaultCore { core_key.into() }; - Self { core, key } } } @@ -187,6 +188,7 @@ mod tests { async fn test_vault_core_initialization() { let temp_dir = tempfile::tempdir().expect("Failed to create temporary directory"); let key_path = temp_dir.path().join(CORE_KEY_FILE); + println!("Key path: {:?}", key_path); let storage = test_storage(temp_dir.path()).await; let vault_core = VaultCore::config(storage, key_path); @@ -199,7 +201,8 @@ mod tests { "Vault core should be initialized" ); } - + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn test_vault_api() { let temp_dir = tempfile::tempdir().expect("Failed to create temporary directory");