summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.woodpecker.yaml.fixme (renamed from .woodpecker.yaml)4
-rw-r--r--Cargo.toml4
-rw-r--r--shell.nix1
-rw-r--r--src/main.rs134
-rw-r--r--src/pkgtoolkit/install.rs80
-rw-r--r--src/router/manager.rs200
-rw-r--r--src/router/router.rs11
-rw-r--r--tests/router_funcs.rs78
-rw-r--r--tests/router_integration_tests.rs94
9 files changed, 369 insertions, 237 deletions
diff --git a/.woodpecker.yaml b/.woodpecker.yaml.fixme
index e89c972..8da4f0b 100644
--- a/.woodpecker.yaml
+++ b/.woodpecker.yaml.fixme
@@ -1,7 +1,7 @@
# Define the sequence of steps for the CI pipeline
steps:
dependencies:
- image: rust:1.91-bullseye
+ image: rust
environment:
RUST_BACKTRACE: 1
CARGO_TERM_COLOR: always
@@ -45,4 +45,4 @@ steps:
# - cargo test --verbose --jobs 2 -- --test-threads=2
# when:
# branch: main
-# event: [ push, pull_request ] \ No newline at end of file
+# event: [ push, pull_request ]
diff --git a/Cargo.toml b/Cargo.toml
index 4016a05..2748af4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -18,7 +18,6 @@ reqwest = { version = "0.12.24", features = ["stream"] }
emissary-util = { version = "0.3.0", features = ["tokio"] }
emissary-core = "0.3.0"
flate2 = "1.1.5"
-log = "0.4.28"
tar = "0.4.44"
url = "2.5.7"
indicatif = "0.18.3"
@@ -28,6 +27,7 @@ git2 = "0.19.0"
gpgme = "0.11.0"
glob = "0.3.3"
lazy_static = "1.5.0"
+log = "0.4.28"
[dev-dependencies]
env_logger = "0.11.8"
@@ -41,4 +41,4 @@ uuid = { version = "1.19.0", features = ["v4"] }
strip = true
lto = true
opt-level = 3
-codegen-units = 1 \ No newline at end of file
+codegen-units = 1
diff --git a/shell.nix b/shell.nix
index 09a5e2a..080a932 100644
--- a/shell.nix
+++ b/shell.nix
@@ -8,6 +8,7 @@ pkgs.mkShell {
openssl
openssl.dev
git
+ woodpecker-cli
pkg-config
];
}
diff --git a/src/main.rs b/src/main.rs
index dc238b1..0f6b6c6 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -12,54 +12,11 @@ use crate::pkgtoolkit::build::BuildOperations;
use crate::pkgtoolkit::git_source::GitSource;
use crate::pkgtoolkit::index::IndexOperations;
use crate::pkgtoolkit::install::InstallOperations;
-use crate::router::router::{Emissary, EmissaryConfig, RouterUtils};
-use emissary_core::router::Router;
-use emissary_util::runtime::tokio::Runtime as TokioRuntime;
-use std::sync::Arc;
-use tokio::sync::Mutex;
-
+use crate::router::manager::RouterManager;
use clap::{Args, Parser, Subcommand};
use std::io::Write;
use std::path::Path;
-lazy_static::lazy_static! {
- static ref ROUTER: Arc<Mutex<Option<Router<TokioRuntime>>>> = Arc::new(Mutex::new(None));
-}
-
-async fn init_router(
- config: &crate::cfg::config::Config,
-) -> Result<(), Box<dyn std::error::Error>> {
- if !config.router.integrated_router {
- return Ok(());
- }
-
- let router_config = EmissaryConfig {
- storage: Some(std::path::PathBuf::from(&config.router.storage_path)),
- auto_update: Some(config.router.auto_update),
- http_proxy_port: Some(config.router.http_proxy_port),
- socks_proxy_port: Some(config.router.socks_proxy_port),
- };
-
- let mut router = Emissary::new(router_config);
-
- // Check if router storage exists and is not empty
- let storage_path = std::path::Path::new(&config.router.storage_path);
- if !storage_path.exists() || storage_path.read_dir()?.next().is_none() {
- log::info!("Router storage is empty, performing initial reseed...");
- router.config().await?;
- router.reseed().await?;
- } else {
- router.config().await?;
- }
-
- // Start the router and store the Router instance
- let router = router.start().await?;
- *ROUTER.lock().await = Some(router);
-
- log::info!("Integrated router initialized successfully");
- Ok(())
-}
-
#[derive(Parser)]
struct Cli {
#[command(subcommand)]
@@ -76,7 +33,7 @@ enum Commands {
Upgrade { pkgname: Option<String> },
#[command(about = "Build package from .mesk ")]
Build { pkgname: String },
- #[command(about = "Install package from remote or local sources")]
+ #[command(about = "Install package")]
Install {
#[arg(help = "Package name or path to local .mesk file")]
pkgname: String,
@@ -124,6 +81,27 @@ struct RemoteInstallArgs {
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let cli: Cli = Cli::parse();
+ // Parse config once at the beginning
+ let config = Config::parse()?;
+
+ // Setup integrated router if enabled
+ let router_manager = if config.router.integrated_router {
+ println!("Starting integrated router...");
+ match RouterManager::new(&config).await {
+ Ok(manager) => {
+ println!("Router manager initialized");
+ Some(manager)
+ }
+ Err(e) => {
+ eprintln!("Failed to initialize router manager: {}", e);
+ return Err(e);
+ }
+ }
+ } else {
+ println!("Integrated router disabled");
+ None
+ };
+
let result = {
match &cli.command {
Commands::Validate { path } => {
@@ -138,7 +116,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
}
}
Err(e) => {
- log::error!("Failed to validate package '{}': {}", path, e);
+ eprintln!("Failed to validate package '{}': {}", path, e);
return Err(e.into());
}
}
@@ -165,7 +143,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Extracting archive...");
Package::extract_archive(pkgname)?;
- let config = Config::parse()?;
let cache_dir = &config.paths.cache_dir;
// Find the package directory (should be name-version format)
@@ -221,7 +198,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Extracting archive...");
Package::extract_archive(pkgname)?;
- let config = Config::parse()?;
let cache_dir = &config.paths.cache_dir;
let mut pkg_dir_name = None;
@@ -259,25 +235,34 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
pkg.install()?;
println!("Package '{}' installed successfully.", pkg.name);
} else {
- let config = Config::parse()?;
// Initialize router if it's needed for I2P connections and is enabled
if !args.http && config.router.integrated_router {
- init_router(&config).await?;
+ // Wait for router to be fully started
+ if let Some(ref manager) = router_manager {
+ println!("Waiting for router to be ready...");
+ tokio::time::sleep(std::time::Duration::from_secs(3)).await; // Give router time to start
+ if !manager.is_running() {
+ eprintln!(
+ "Router is not running, cannot proceed with I2P installation"
+ );
+ return Err(std::io::Error::other("Router not running").into());
+ }
+ }
}
if args.http {
- println!("Installing {} via HTTP", pkgname);
+ println!("Installing {} via non-i2p mirror", pkgname);
let mut http_client = HTTPPackage::new(config);
http_client.fetch_index_http().await?;
- log::info!("Index fetched successfully.");
+ println!("Index fetched successfully.");
http_client.fetch_package_http(pkgname).await?;
- log::info!("Package '{}' installed successfully.", pkgname);
+ println!("Package '{}' installed successfully.", pkgname);
} else {
println!("Installing {} via I2P", pkgname);
let mut i2p_client = I2PPackage::new(config);
i2p_client.fetch_index().await?;
- log::info!("Index fetched successfully.");
+ println!("Index fetched successfully.");
i2p_client.fetch_package(pkgname).await?;
- log::info!("Package '{}' installed successfully.", pkgname);
+ println!("Package '{}' installed successfully.", pkgname);
}
}
return Ok(());
@@ -286,7 +271,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Uninstalling package: {}", pkgname);
let installed_packages = Package::list_installed_packages().map_err(|e| {
- log::error!("Failed to list installed packages: {}", e);
+ eprintln!("Failed to list installed packages: {}", e);
e
})?;
@@ -309,23 +294,29 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}
Ok(false) => {
- log::warn!(
+ eprintln!(
"Some files could not be removed during uninstallation of {}",
pkgname
);
Err(std::io::Error::other("Partial uninstallation occurred").into())
}
Err(e) => {
- log::error!("Failed to uninstall package {}: {}", pkgname, e);
+ eprintln!("Failed to uninstall package {}: {}", pkgname, e);
Err(e.into())
}
}
}
Commands::GetSource { pkgname } => {
- let config = Config::parse()?;
// Initialize router for I2P connections if enabled
if config.router.integrated_router {
- init_router(&config).await?;
+ if let Some(ref manager) = router_manager {
+ println!("Waiting for router to be ready...");
+ tokio::time::sleep(std::time::Duration::from_secs(2)).await;
+ if !manager.is_running() {
+ eprintln!("Router is not running, cannot proceed with I2P operation");
+ return Err(std::io::Error::other("Router not running").into());
+ }
+ }
}
println!("Getting source of {}", pkgname);
@@ -347,7 +338,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("{}", config);
println!("---- End of generated config ----");
- log::warn!("Writing the default config to /etc/mesk/mesk.toml");
+ eprintln!("Writing the default config to /etc/mesk/mesk.toml");
let path = Path::new("/etc/mesk/mesk.toml");
std::fs::create_dir_all(path.parent().unwrap())?;
@@ -361,7 +352,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("{:?}", config);
println!("---- End of generated config ----");
- log::warn!("Writing the default config to /etc/mesk/mesk.toml");
+ eprintln!("Writing the default config to /etc/mesk/mesk.toml");
let path = Path::new("/etc/mesk/mesk.toml");
std::fs::create_dir_all(path.parent().unwrap())?;
@@ -372,11 +363,18 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
return Ok(());
}
Commands::Update => {
- let config = Config::parse()?;
// Initialize router for I2P connections if enabled
if config.router.integrated_router {
- init_router(&config).await?;
+ if let Some(ref manager) = router_manager {
+ println!("Waiting for router to be ready...");
+ tokio::time::sleep(std::time::Duration::from_secs(2)).await;
+ if !manager.is_running() {
+ eprintln!("Router is not running, cannot proceed with I2P operation");
+ return Err(std::io::Error::other("Router not running").into());
+ }
+ }
}
+
println!("Updating index from {}", config.repo.repo_url);
let mut i2p_client = I2PPackage::new(config);
@@ -407,9 +405,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
};
// Shutdown router if it was initialized
- if let Some(router) = ROUTER.lock().await.take() {
- // TODO: Add proper router shutdown when implemented
- log::info!("Shutting down integrated router...");
+ if let Some(ref manager) = router_manager {
+ println!("Shutting down integrated router...");
+ if let Err(e) = manager.stop().await {
+ eprintln!("Error stopping router: {}", e);
+ }
}
result
diff --git a/src/pkgtoolkit/install.rs b/src/pkgtoolkit/install.rs
index 7ba0598..13929e6 100644
--- a/src/pkgtoolkit/install.rs
+++ b/src/pkgtoolkit/install.rs
@@ -1,5 +1,4 @@
use crate::cfg::config::Config;
-use crate::router::manager::RouterManager;
use std::{
fs::{self, Permissions, create_dir_all, set_permissions},
os::unix::fs::PermissionsExt,
@@ -33,37 +32,9 @@ pub trait InstallOperations {
fn load_manifest(&self) -> Result<PackageManifest, std::io::Error>;
fn list_installed_packages() -> Result<Vec<PackageManifest>, std::io::Error>;
fn is_installed(&self) -> Result<bool, std::io::Error>;
-
- /// Installs a package using the specified parameters
- ///
- /// # Arguments
- /// * `pkgname` - Name of the package to install
- /// * `source` - Optional source URL or path
- /// * `is_path` - Whether the source is a local path
- /// * `args` - Additional installation arguments
- /// * `router_manager` - Optional router manager for I2P connections
- async fn install_package(
- pkgname: &str,
- source: Option<&str>,
- is_path: bool,
- args: &RemoteInstallArgs,
- router_manager: &RouterManager,
- ) -> Result<(), Box<dyn std::error::Error>>;
}
impl InstallOperations for Package {
- async fn install_package(
- pkgname: &str,
- source: Option<&str>,
- is_path: bool,
- args: &RemoteInstallArgs,
- router_manager: &RouterManager,
- ) -> Result<(), Box<dyn std::error::Error>> {
- // Implementation of install_package
- // TODO: Add actual implementation based on your requirements
- Ok(())
- }
-
/// Recursively collects all files from a directory and its subdirectories
/// and returns them as a vector of strings.
///
@@ -118,7 +89,7 @@ impl InstallOperations for Package {
let is_build_present_and_not_empty = build_meta.is_some();
if is_build_present_and_not_empty {
- log::info!(
+ println!(
"Found BUILD file, preparing to build and install package: {}",
self.name
);
@@ -203,7 +174,7 @@ impl InstallOperations for Package {
}
}
} else {
- log::info!(
+ println!(
"No BUILD file or it's empty. Treating as binary package. Installing via INSTALL config or custom script."
);
if let Some(ref script) = install_meta.install.custom_script {
@@ -211,7 +182,7 @@ impl InstallOperations for Package {
}
if let Some(ref script) = install_meta.install.custom_script {
- log::info!(
+ println!(
"Executing custom install script for {}",
install_meta.package.name
);
@@ -232,16 +203,16 @@ impl InstallOperations for Package {
"Custom script used; file list may be incomplete. Add manual tracking if needed."
);
} else {
- log::info!(
+ println!(
"No custom script. Running default install hook for {}",
install_meta.package.name
);
- log::info!("Starting default install process");
+ println!("Starting default install process");
let build_dir = Path::new(&config.paths.cache_dir)
.join(format!("{}-{}", self.name, self.version));
let dest_path = Path::new(&install_meta.install.path);
- log::info!(
+ println!(
"Install path: {:?}, is_dir: {}, ends_with_slash: {}",
dest_path,
dest_path.is_dir(),
@@ -249,7 +220,7 @@ impl InstallOperations for Package {
);
if dest_path.is_dir() || dest_path.to_string_lossy().ends_with('/') {
- log::info!("Taking multi-binary package path");
+ println!("Taking multi-binary package path");
let target_release = build_dir.join("target/release");
if !target_release.exists() {
return Err(std::io::Error::other(format!(
@@ -271,12 +242,12 @@ impl InstallOperations for Package {
&& let Ok(metadata) = fs::metadata(&path)
{
let mode = metadata.permissions().mode();
- log::debug!("Checking file: {:?}, mode: {:o}", path.file_name(), mode);
+ println!("Checking file: {:?}, mode: {:o}", path.file_name(), mode);
if mode & 0o111 != 0 {
let file_name = path.file_name().unwrap().to_string_lossy();
let dest_file = dest_path.join(&*file_name);
- log::info!(
+ println!(
"Copying executable: {} to {}",
file_name,
dest_file.display()
@@ -290,7 +261,7 @@ impl InstallOperations for Package {
copied_files.push(dest_file);
} else {
- log::debug!(
+ println!(
"File {:?} is not executable (mode: {:o})",
path.file_name(),
mode
@@ -337,7 +308,7 @@ impl InstallOperations for Package {
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
- log::warn!(
+ println!(
"Warning: 'chown' command failed for {} (requires root?):\n{}",
file_path.display(),
stderr
@@ -345,7 +316,7 @@ impl InstallOperations for Package {
}
}
} else {
- log::info!("Taking single binary package path");
+ println!("Taking single binary package path");
// Single binary package - copy specific file
let source_file_name = &self.name;
let src_path = build_dir.join(source_file_name);
@@ -393,10 +364,7 @@ impl InstallOperations for Package {
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
- log::warn!(
- "Warning: 'chown' command failed (requires root?):\n{}",
- stderr
- );
+ println!("Warning: 'chown' command failed:\n{}", stderr);
}
all_files = install_meta.files;
@@ -414,7 +382,7 @@ impl InstallOperations for Package {
toml::to_string_pretty(&manifest).map_err(|e| std::io::Error::other(e.to_string()))?;
fs::write(&manifest_path, manifest_toml)?;
- log::info!(
+ println!(
"Package {} installed successfully. Manifest generated at {:?} with {} files tracked",
self.name,
manifest_path,
@@ -448,10 +416,9 @@ impl InstallOperations for Package {
fn uninstall(&self) -> Result<bool, std::io::Error> {
let manifest = self.load_manifest()?;
- log::info!(
+ println!(
"Uninstalling package {}-{}",
- manifest.name,
- manifest.version
+ manifest.name, manifest.version
);
let mut removed_files = 0;
@@ -464,15 +431,15 @@ impl InstallOperations for Package {
match fs::remove_file(path) {
Ok(()) => {
removed_files += 1;
- log::debug!("Removed file: {:?}", path);
+ println!("Removed file: {:?}", path);
}
Err(e) => {
failed_removals += 1;
- log::warn!("Failed to remove file {:?}: {}", path, e);
+ println!("Failed to remove file {:?}: {}", path, e);
}
}
} else {
- log::debug!("File not found, skipping: {:?}", path);
+ println!("File not found, skipping: {:?}", path);
}
}
@@ -483,15 +450,12 @@ impl InstallOperations for Package {
if manifest_path.exists() {
fs::remove_file(&manifest_path)?;
- log::info!("Removed manifest file: {:?}", manifest_path);
+ println!("Removed manifest file: {:?}", manifest_path);
}
- log::info!(
+ println!(
"Package {}-{} uninstalled successfully. Removed {} files, {} failures",
- manifest.name,
- manifest.version,
- removed_files,
- failed_removals
+ manifest.name, manifest.version, removed_files, failed_removals
);
Ok(failed_removals == 0)
diff --git a/src/router/manager.rs b/src/router/manager.rs
index 23b7c69..5fb8868 100644
--- a/src/router/manager.rs
+++ b/src/router/manager.rs
@@ -1,21 +1,8 @@
-use crate::router::router::RouterUtils;
-use crate::router::router::{Emissary, EmissaryConfig};
-use log::{debug, error, info};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
-use tokio::sync::mpsc;
-use tokio::task::JoinHandle;
-
-#[derive(Debug)]
-pub enum RouterMessage {
- Start,
- Stop,
- Status,
-}
+// Simple RouterManager that just tracks status without complex state management
pub struct RouterManager {
- handle: Option<JoinHandle<()>>,
- tx: mpsc::Sender<RouterMessage>,
is_running: Arc<AtomicBool>,
}
@@ -25,104 +12,114 @@ impl RouterManager {
) -> Result<Self, Box<dyn std::error::Error>> {
if !config.router.integrated_router {
return Ok(Self {
- handle: None,
- tx: {
- let (tx, _) = mpsc::channel(1);
- tx
- },
is_running: Arc::new(AtomicBool::new(false)),
});
}
- let (tx, mut rx) = mpsc::channel::<RouterMessage>(1);
- let is_running = Arc::new(AtomicBool::new(false));
- let is_running_clone = is_running.clone();
+ // Initialize router synchronously to avoid Send issues
+ Self::init_router(config).await?;
- let router_config = config.router.clone();
- let handle = tokio::spawn(async move {
- info!("Router manager task started");
+ let manager = Self {
+ is_running: Arc::new(AtomicBool::new(true)),
+ };
- let mut router = Emissary::new(EmissaryConfig {
- storage: Some(std::path::PathBuf::from(&router_config.storage_path)),
- auto_update: Some(router_config.auto_update),
- http_proxy_port: Some(router_config.http_proxy_port),
- socks_proxy_port: Some(router_config.socks_proxy_port),
- });
+ // Give the router some time to initialize
+ tokio::time::sleep(std::time::Duration::from_secs(2)).await;
- if let Err(e) = router.config().await {
- error!("Failed to configure router: {}", e);
- return;
- }
-
- let storage_path = std::path::Path::new(&router_config.storage_path);
- if !storage_path.exists()
- || storage_path
- .read_dir()
- .ok()
- .is_none_or(|mut d| d.next().is_none())
- {
- info!("Router storage is empty, performing initial reseed...");
- if let Err(e) = router.reseed().await {
- error!("Failed to reseed router: {}", e);
- return;
- }
- }
-
- let router_task = tokio::spawn(async move {
- info!("Starting router service...");
- match router.start().await {
- Ok(_) => info!("Router service stopped"),
- Err(e) => error!("Router service error: {}", e),
- }
- });
+ Ok(manager)
+ }
- is_running_clone.store(true, Ordering::SeqCst);
- info!("Router manager is now running");
-
- while let Some(msg) = rx.recv().await {
- match msg {
- RouterMessage::Stop => {
- info!("Stopping router...");
- // TODO: Implement proper router shutdown
- is_running_clone.store(false, Ordering::SeqCst);
- break;
- }
- RouterMessage::Status => {
- debug!(
- "Router status: {}",
- if is_running_clone.load(Ordering::SeqCst) {
- "running"
- } else {
- "stopped"
- }
- );
- }
- _ => {}
- }
- }
-
- if let Err(e) = router_task.await {
- error!("Router task panicked: {}", e);
- }
-
- info!("Router manager task finished");
+ async fn init_router(
+ config: &crate::cfg::config::Config,
+ ) -> Result<(), Box<dyn std::error::Error>> {
+ use crate::router::router::{Emissary, EmissaryConfig, RouterUtils};
+ use std::path::Path;
+
+ let router_config = &config.router;
+ let mut router = Emissary::new(EmissaryConfig {
+ storage: Some(std::path::PathBuf::from(&router_config.storage_path)),
+ auto_update: Some(router_config.auto_update),
+ http_proxy_port: Some(router_config.http_proxy_port),
+ socks_proxy_port: Some(router_config.socks_proxy_port),
});
- tokio::time::sleep(std::time::Duration::from_secs(1)).await;
+ router.config().await?;
+
+ let storage_path = Path::new(&router_config.storage_path);
+ if !storage_path.exists() {
+ std::fs::create_dir_all(storage_path)?;
+ }
+
+ // Check if storage directory is empty
+ let should_reseed = match std::fs::read_dir(storage_path) {
+ Ok(mut entries) => entries.next().is_none(),
+ Err(_) => true, // if we can't read, reseed anyway
+ };
+
+ if should_reseed {
+ println!("Router storage is empty, performing initial reseed...");
+ router.reseed().await?;
+ }
+
+ let router_instance = router.start().await?;
+
+ // Store the router instance in the global static variable
+ *super::router::ROUTER.lock().await = Some(router_instance);
+ println!("Router service successfully initialized and stored globally");
- Ok(Self {
- handle: Some(handle),
- tx,
- is_running,
- })
+ Ok(())
}
- pub async fn stop(&self) {
+ /// Starts the integrated router if it is not currently running.
+ /// Note: The router is typically started automatically when the RouterManager is created,
+ /// so calling this method usually just prints a message indicating that the router
+ /// starts automatically.
+ ///
+ /// # Returns
+ ///
+ /// * `Ok(())` always returns OK as this is a compatibility method
+ pub async fn start(&self) -> Result<(), Box<dyn std::error::Error>> {
+ if !self.is_running.load(Ordering::SeqCst) {
+ println!("Router start functionality not implemented for this mode");
+ // We can't really control the router lifecycle since it's managed globally
+ }
+ Ok(())
+ }
+
+ /// Restarts the integrated router if it is currently running.
+ /// This stops the current router instance and starts a new one.
+ ///
+ /// # Returns
+ ///
+ /// * `Ok(())` when the restart is initiated
+ /// * `Err(Box<dyn std::error::Error>)` if the restart failed
+ pub async fn restart(&self) -> Result<(), Box<dyn std::error::Error>> {
+ println!("Restarting router...");
+
+ // Clear the global router instance
+ *super::router::ROUTER.lock().await = None;
+
+ // Get config again (this is not ideal but needed for restart)
+ let config = crate::cfg::config::Config::parse()
+ .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
+
+ Self::init_router(&config).await?;
+
+ println!("Router restarted successfully");
+ Ok(())
+ }
+
+ /// Stops the integrated router if it is currently running.
+ /// This clears the global router instance.
+ pub async fn stop(&self) -> Result<(), Box<dyn std::error::Error>> {
if self.is_running.load(Ordering::SeqCst) {
- if let Err(e) = self.tx.send(RouterMessage::Stop).await {
- error!("Failed to send stop message to router: {}", e);
- }
+ println!("Stopping router...");
+ // Clear the global router instance
+ *super::router::ROUTER.lock().await = None;
+ self.is_running.store(false, Ordering::SeqCst);
+ println!("Router stopped");
}
+ Ok(())
}
pub fn is_running(&self) -> bool {
@@ -132,13 +129,6 @@ impl RouterManager {
impl Drop for RouterManager {
fn drop(&mut self) {
- if self.is_running() {
- let tx = self.tx.clone();
- tokio::spawn(async move {
- if let Err(e) = tx.send(RouterMessage::Stop).await {
- error!("Failed to send stop message during drop: {}", e);
- }
- });
- }
+ //todooo
}
}
diff --git a/src/router/router.rs b/src/router/router.rs
index 65de900..3f1e629 100644
--- a/src/router/router.rs
+++ b/src/router/router.rs
@@ -4,9 +4,15 @@ use emissary_util::reseeder::Reseeder;
use emissary_util::runtime::tokio::Runtime as TokioRuntime;
use emissary_util::storage::{Storage, StorageBundle};
use serde::{Deserialize, Serialize};
+
use std::future::Future;
use std::path::PathBuf;
use std::sync::Arc;
+use tokio::sync::Mutex;
+
+lazy_static::lazy_static! {
+ pub static ref ROUTER: Arc<Mutex<Option<Router<TokioRuntime>>>> = Arc::new(Mutex::new(None));
+}
pub trait RouterUtils {
fn config(&mut self) -> impl Future<Output = Result<(), Box<dyn std::error::Error>>> + Send;
@@ -86,7 +92,7 @@ impl RouterUtils for Emissary {
.store_router_info(info.name.to_string(), info.router_info.clone())
.await
{
- log::warn!("Failed to store reseeded router info: {}", e);
+ println!("Failed to store reseeded router info: {}", e);
}
bundle.routers.push(info.router_info);
}
@@ -96,7 +102,7 @@ impl RouterUtils for Emissary {
self.storage_bundle = Some(bundle);
return Err(format!("Reseed failed and no routers available: {}", e).into());
} else {
- log::warn!("Reseed failed, but using existing routers: {}", e);
+ println!("Reseed failed, but using existing routers: {}", e);
}
}
}
@@ -142,7 +148,6 @@ impl RouterUtils for Emissary {
.await
.map_err(|e| format!("Router creation failed: {}", e))?;
- // Сохраняем router_info, если он новый
storage.store_local_router_info(router_info).await?;
Ok(router)
diff --git a/tests/router_funcs.rs b/tests/router_funcs.rs
new file mode 100644
index 0000000..7d0cce8
--- /dev/null
+++ b/tests/router_funcs.rs
@@ -0,0 +1,78 @@
+use mesk::cfg::config::{Config, RouterConfig};
+use mesk::router::manager::RouterManager;
+
+#[tokio::test]
+async fn test_router_manager_creation() {
+ let config = Config {
+ repo: mesk::cfg::config::Repo {
+ repo_url: "https://mesk.anthrill.i2p/repo/x86_64/".to_string(),
+ auto_update: true,
+ destination: (String::from("mesk"), String::from("mesk")),
+ repo_http_url: Some("http://github.com/Anthrill/repo-mirror/x86_64".to_string()),
+ i2p_http_proxy_port: 4444,
+ },
+ log: mesk::cfg::config::Log {
+ log_file: "/tmp/mesk_test.log".to_string(),
+ log_level: mesk::cfg::config::Loglevel::Debug,
+ },
+ paths: mesk::cfg::config::Paths {
+ cache_dir: "/tmp/mesk_cache".to_string(),
+ build_dir: "/tmp/mesk_build".to_string(),
+ installed_db: "/tmp/mesk_pkgdb".to_string(),
+ },
+ router: RouterConfig {
+ integrated_router: false, // Disable router for this test to avoid conflicts
+ storage_path: "/tmp/mesk_test_router/".to_string(),
+ http_proxy_port: 4447,
+ socks_proxy_port: 4448,
+ auto_update: false,
+ },
+ };
+
+ let result = RouterManager::new(&config).await;
+ assert!(result.is_ok());
+
+ let manager = result.unwrap();
+ assert_eq!(manager.is_running(), false);
+}
+
+#[tokio::test]
+async fn test_router_manager_with_disabled_router() {
+ let config = Config {
+ repo: mesk::cfg::config::Repo {
+ repo_url: "https://mesk.anthrill.i2p/repo/x86_64/".to_string(),
+ auto_update: true,
+ destination: (String::from("mesk"), String::from("mesk")),
+ repo_http_url: Some("http://github.com/Anthrill/repo-mirror/x86_64".to_string()),
+ i2p_http_proxy_port: 4444,
+ },
+ log: mesk::cfg::config::Log {
+ log_file: "/tmp/mesk_test.log".to_string(),
+ log_level: mesk::cfg::config::Loglevel::Debug,
+ },
+ paths: mesk::cfg::config::Paths {
+ cache_dir: "/tmp/mesk_cache".to_string(),
+ build_dir: "/tmp/mesk_build".to_string(),
+ installed_db: "/tmp/mesk_pkgdb".to_string(),
+ },
+ router: RouterConfig {
+ integrated_router: false, // Explicitly disable router
+ storage_path: "/tmp/mesk_test_router/".to_string(),
+ http_proxy_port: 4447,
+ socks_proxy_port: 4448,
+ auto_update: false,
+ },
+ };
+
+ let result = RouterManager::new(&config).await;
+ assert!(result.is_ok());
+
+ let manager = result.unwrap();
+ // When router is disabled, we shouldn't be able to start it
+ let start_result = manager.start().await;
+ // This test checks that disabled router behaves properly
+ // Actual start operations may not work when integrated_router is false
+ println!("Router start result when disabled: {:?}", start_result);
+
+ assert_eq!(manager.is_running(), false);
+}
diff --git a/tests/router_integration_tests.rs b/tests/router_integration_tests.rs
new file mode 100644
index 0000000..bf534f5
--- /dev/null
+++ b/tests/router_integration_tests.rs
@@ -0,0 +1,94 @@
+use mesk::cfg::config::{Config, RouterConfig};
+use mesk::router::manager::RouterManager;
+
+// Integration tests for router functionality
+// Note: These tests use a minimal configuration to avoid actually starting a full router
+
+#[tokio::test]
+async fn test_router_start_functionality() {
+ let config = create_test_config(true); // Enable router for this test
+
+ let result = RouterManager::new(&config).await;
+ assert!(result.is_ok());
+
+ let manager = result.unwrap();
+
+ // Initially should not be running
+ assert_eq!(manager.is_running(), false);
+
+ // Attempt to start (this won't fully work without actual router dependencies)
+ let start_result = manager.start().await;
+ // This might fail due to missing dependencies, but the call should be accepted
+ println!("Start result: {:?}", start_result);
+}
+
+#[tokio::test]
+async fn test_router_stop_functionality() {
+ let config = create_test_config(true); // Enable router for this test
+
+ let result = RouterManager::new(&config).await;
+ assert!(result.is_ok());
+
+ let manager = result.unwrap();
+
+ // Test stopping when not running
+ manager.stop().await;
+ assert_eq!(manager.is_running(), false);
+}
+
+#[tokio::test]
+async fn test_router_restart_functionality() {
+ let config = create_test_config(true); // Enable router for this test
+
+ let result = RouterManager::new(&config).await;
+ assert!(result.is_ok());
+
+ let manager = result.unwrap();
+
+ // Test restart (this won't fully work without actual router dependencies)
+ let restart_result = manager.restart().await;
+ // This might fail due to missing dependencies, but the call should be accepted
+ println!("Restart result: {:?}", restart_result);
+}
+
+#[tokio::test]
+async fn test_router_status_functionality() {
+ let config = create_test_config(false); // Disable router for this test
+
+ let result = RouterManager::new(&config).await;
+ assert!(result.is_ok());
+
+ let manager = result.unwrap();
+
+ // Should not be running when router is disabled
+ assert_eq!(manager.is_running(), false);
+}
+
+// Helper function to create test configuration
+fn create_test_config(integrated_router_enabled: bool) -> Config {
+ Config {
+ repo: mesk::cfg::config::Repo {
+ repo_url: "https://mesk.anthrill.i2p/repo/x86_64/".to_string(),
+ auto_update: true,
+ destination: (String::from("mesk"), String::from("mesk")),
+ repo_http_url: Some("http://github.com/Anthrill/repo-mirror/x86_64".to_string()),
+ i2p_http_proxy_port: 4444,
+ },
+ log: mesk::cfg::config::Log {
+ log_file: "/tmp/mesk_test.log".to_string(),
+ log_level: mesk::cfg::config::Loglevel::Debug,
+ },
+ paths: mesk::cfg::config::Paths {
+ cache_dir: "/tmp/mesk_cache".to_string(),
+ build_dir: "/tmp/mesk_build".to_string(),
+ installed_db: "/tmp/mesk_pkgdb".to_string(),
+ },
+ router: RouterConfig {
+ integrated_router: integrated_router_enabled,
+ storage_path: "/tmp/mesk_test_router/".to_string(),
+ http_proxy_port: 4447,
+ socks_proxy_port: 4448,
+ auto_update: false,
+ },
+ }
+}