diff --git a/src/cmd.rs b/src/cmd.rs index 43fe05a..f1dec1c 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -1,8 +1,7 @@ -use clap::Parser; -use clap::Subcommand; +use clap::{Parser, Subcommand}; #[derive(Parser)] -#[command(author, about, version)] +#[command(author, about, version, arg_required_else_help(true))] pub struct Args { /// Path to mihoro config file #[clap(short, long, default_value = "~/.config/mihoro.toml")] @@ -13,30 +12,30 @@ pub struct Args { #[derive(Subcommand)] pub enum Commands { - #[command(about = "Setup mihoro by downloading mihomo binary and remote config")] + /// Setup mihoro by downloading mihomo binary and remote config Setup, - #[command(about = "Update mihomo remote config and restart mihomo.service")] + /// Update mihomo remote config and restart mihomo.service Update, - #[command(about = "Apply mihomo config overrides and restart mihomo.service")] + /// Apply mihomo config overrides and restart mihomo.service Apply, - #[command(about = "Start mihomo.service with systemctl")] + /// Start mihomo.service with systemctl Start, - #[command(about = "Check mihomo.service status with systemctl")] + /// Check mihomo.service status with systemctl Status, - #[command(about = "Stop mihomo.service with systemctl")] + /// Stop mihomo.service with systemctl Stop, - #[command(about = "Restart mihomo.service with systemctl")] + /// Restart mihomo.service with systemctl Restart, - #[command(about = "Check mihomo.service logs with journalctl")] + /// Check mihomo.service logs with journalctl Log, - #[command(about = "Proxy export commands, `mihoro proxy --help` for details")] + /// Output proxy export commands Proxy { - #[command(subcommand)] + #[clap(subcommand)] proxy: Option, }, - #[command(about = "Uninstall and remove mihomo and config")] + /// Uninstall and remove mihoro and config Uninstall, - #[command(about = "Generate shell completions for mihoro")] + /// Generate shell completions for mihoro Completions { #[clap(subcommand)] shell: Option, @@ -44,22 +43,24 @@ pub enum Commands { } #[derive(Subcommand)] +#[command(arg_required_else_help(true))] pub enum ProxyCommands { - #[command(about = "Output and copy proxy export shell commands")] + /// Output and copy proxy export shell commands Export, - #[command(about = "Output and copy proxy export shell commands for LAN access")] + /// Output and copy proxy export shell commands for LAN access ExportLan, - #[command(about = "Output and copy proxy unset shell commands")] + /// Output and copy proxy unset shell commands Unset, } #[derive(Subcommand)] +#[command(arg_required_else_help(true))] pub enum ClapShell { - #[command(about = "Generate bash completions")] + /// Generate bash completions Bash, - #[command(about = "Generate fish completions")] + /// Generate fish completions Fish, - #[command(about = "Generate zsh completions")] + /// Generate zsh completions Zsh, // #[command(about = "Generate powershell completions")] // Powershell, diff --git a/src/config.rs b/src/config.rs index 2ff4ea7..d5335ca 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,17 +1,13 @@ -use std::collections::HashMap; -use std::fs; -use std::path::Path; +use crate::utils::create_parent_dir; -use anyhow::bail; -use anyhow::Result; -use colored::Colorize; -use serde::Deserialize; -use serde::Serialize; +use std::{collections::HashMap, fs, path::Path}; -use crate::utils::create_parent_dir; +use anyhow::{bail, Result}; +use colored::Colorize; +use serde::{Deserialize, Serialize}; /// `mihoro` configurations. -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Clone)] pub struct Config { pub remote_mihomo_binary_url: String, pub remote_config_url: String, @@ -24,7 +20,7 @@ pub struct Config { /// `mihomo` configurations (partial). /// /// Referenced from https://github.com/Dreamacro/mihomo/wiki/configuration -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Clone)] pub struct MihomoConfig { pub port: u16, pub socks_port: u16, diff --git a/src/main.rs b/src/main.rs index 3bf6793..62f8ebc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,40 +1,23 @@ mod cmd; mod config; +mod mihoro; +mod proxy; mod systemctl; mod utils; -use std::fs; -use std::io; -use std::os::unix::prelude::PermissionsExt; -use std::process::Command; - -use anyhow::bail; use anyhow::Result; -use clap::CommandFactory; -use clap::Parser; -use clap_complete::generate; -use clap_complete::shells::Bash; -use clap_complete::shells::Fish; -use clap_complete::shells::Zsh; +use clap::{CommandFactory, Parser}; +use clap_complete::{ + generate, + shells::{Bash, Fish, Zsh}, +}; use colored::Colorize; -use local_ip_address::local_ip; use reqwest::Client; -use shellexpand::tilde; +use std::{io, process::Command}; -use cmd::Args; -use cmd::ClapShell; -use cmd::Commands; -use cmd::ProxyCommands; -use config::apply_mihomo_override; -use config::parse_config; -use config::Config; +use cmd::{Args, ClapShell, Commands}; +use mihoro::Mihoro; use systemctl::Systemctl; -use utils::create_mihomo_service; -use utils::delete_file; -use utils::download_file; -use utils::extract_gzip; -use utils::proxy_export_cmd; -use utils::proxy_unset_cmd; #[tokio::main] async fn main() { @@ -46,132 +29,40 @@ async fn main() { async fn cli() -> Result<()> { let args = Args::parse(); - let prefix = "mihoro:"; - let config_path = tilde(&args.mihoro_config).to_string(); - - // Initial setup and parse config file - let config: Config = parse_config(&config_path)?; - - // Expand mihomo related paths and target directories - let mihomo_gzipped_path = "mihomo.tar.gz"; - - let mihomo_target_binary_path = tilde(&config.mihomo_binary_path).to_string(); - let mihomo_target_config_root = tilde(&config.mihomo_config_root).to_string(); - let mihomo_target_config_path = - tilde(&format!("{}/config.yaml", config.mihomo_config_root)).to_string(); - let mihomo_target_service_path = - tilde(&format!("{}/mihomo.service", config.user_systemd_root)).to_string(); - - // Reuse http client for file download let client = Client::new(); + let mihoro = Mihoro::new(&args.mihoro_config)?; match &args.command { - Some(Commands::Setup) => { - println!( - "{} Setting up mihomo's binary, config, and systemd service...", - prefix.cyan() - ); - - // Attempt to download and setup mihomo binary if needed - if fs::metadata(&mihomo_target_binary_path).is_ok() { - // If mihomo binary already exists at `mihomo_target_binary_path`, then skip setup - println!( - "{} Assuming mihomo binary already installed at {}, skipping setup", - prefix.yellow(), - mihomo_target_binary_path.underline().green() - ); - } else { - // Abort if `remote_mihomo_binary_url` is not defined in config - if config.remote_mihomo_binary_url.is_empty() { - bail!("`remote_mihomo_binary_url` undefined"); - } - - // Download mihomo binary and set permission to executable - download_file( - &client, - &config.remote_mihomo_binary_url, - mihomo_gzipped_path, - ) - .await?; - extract_gzip(mihomo_gzipped_path, &mihomo_target_binary_path, prefix)?; - - let executable = fs::Permissions::from_mode(0o755); - fs::set_permissions(&mihomo_target_binary_path, executable)?; - } - - // Download remote mihomo config and apply override - download_file( - &client, - &config.remote_config_url, - &mihomo_target_config_path, - ) - .await?; - apply_mihomo_override(&mihomo_target_config_path, &config.mihomo_config)?; + Some(Commands::Setup) => mihoro.setup(client).await?, + Some(Commands::Update) => mihoro.update(client).await?, + Some(Commands::Apply) => mihoro.apply().await?, + Some(Commands::Uninstall) => mihoro.uninstall()?, + Some(Commands::Proxy { proxy }) => mihoro.proxy_commands(proxy)?, + + Some(Commands::Start) => Systemctl::new() + .start("mihomo.service") + .execute() + .map(|_| { + println!("{} Started mihomo.service", mihoro.prefix.green()); + })?, - // Create mihomo.service systemd file - create_mihomo_service( - &mihomo_target_binary_path, - &mihomo_target_config_root, - &mihomo_target_service_path, - prefix, - )?; - - Systemctl::new().enable("mihomo.service").execute()?; - Systemctl::new().start("mihomo.service").execute()?; - } - Some(Commands::Update) => { - // Download remote mihomo config and apply override - download_file( - &client, - &config.remote_config_url, - &mihomo_target_config_path, - ) - .await?; - apply_mihomo_override(&mihomo_target_config_path, &config.mihomo_config)?; - println!("{} Updated and applied config overrides", prefix.yellow()); - - // Restart mihomo systemd service - println!("{} Restart mihomo.service", prefix.green()); - Systemctl::new().restart("mihomo.service").execute()?; - } - Some(Commands::Apply) => { - // Apply mihomo config override - apply_mihomo_override(&mihomo_target_config_path, &config.mihomo_config).map(|_| { - println!("{} Applied mihomo config overrides", prefix.green().bold()); - })?; - - // Restart mihomo systemd service - Systemctl::new() - .restart("mihomo.service") - .execute() - .map(|_| { - println!("{} Restarted mihomo.service", prefix.green().bold()); - })?; - } - Some(Commands::Start) => { - Systemctl::new() - .start("mihomo.service") - .execute() - .map(|_| { - println!("{} Started mihomo.service", prefix.green()); - })?; - } Some(Commands::Status) => { Systemctl::new().status("mihomo.service").execute()?; } - Some(Commands::Stop) => { - Systemctl::new().stop("mihomo.service").execute().map(|_| { - println!("{} Stopped mihomo.service", prefix.green()); - })?; - } + + Some(Commands::Stop) => Systemctl::new().stop("mihomo.service").execute().map(|_| { + println!("{} Stopped mihomo.service", mihoro.prefix.green()); + })?, + Some(Commands::Restart) => { Systemctl::new() .restart("mihomo.service") .execute() .map(|_| { - println!("{} Restarted mihomo.service", prefix.green()); - })?; + println!("{} Restarted mihomo.service", mihoro.prefix.green()); + })? } + Some(Commands::Log) => { Command::new("journalctl") .arg("--user") @@ -184,68 +75,7 @@ async fn cli() -> Result<()> { .expect("failed to execute process") .wait()?; } - Some(Commands::Proxy { proxy }) => match proxy { - Some(ProxyCommands::Export) => { - println!( - "{}", - proxy_export_cmd( - "127.0.0.1", - &config.mihomo_config.port, - &config.mihomo_config.socks_port - ) - ) - } - Some(ProxyCommands::ExportLan) => { - if !config.mihomo_config.allow_lan.unwrap_or(false) { - bail!( - "`allow_lan` is false, edit {} and `mihoro apply` to enable", - config_path.underline().yellow() - ); - } - let hostname = local_ip(); - if let Ok(hostname) = hostname { - println!( - "{}", - proxy_export_cmd( - &hostname.to_string(), - &config.mihomo_config.port, - &config.mihomo_config.socks_port - ) - ) - } else { - println!("{} Failed to get local IP address", prefix.red()); - } - } - Some(ProxyCommands::Unset) => { - println!("{}", proxy_unset_cmd()) - } - _ => { - println!("{} No proxy command, --help for usage", prefix.red()); - } - }, - Some(Commands::Uninstall) => { - Systemctl::new().stop("mihomo.service").execute()?; - Systemctl::new().disable("mihomo.service").execute()?; - - // delete_file(&mihomo_target_binary_path, prefix); - delete_file(&mihomo_target_service_path, prefix)?; - delete_file(&mihomo_target_config_path, prefix)?; - - Systemctl::new().daemon_reload().execute()?; - Systemctl::new().reset_failed().execute()?; - println!("{} Disabled and reloaded systemd services", prefix.green()); - println!( - "{} You may need to remove mihomo binary and config directory manually", - prefix.green() - ); - - let remove_cmd = format!( - "rm -R {} {}", - mihomo_target_binary_path, mihomo_target_config_root - ); - println!("{} `{}`", "->".dimmed(), remove_cmd.underline().bold()); - } Some(Commands::Completions { shell }) => match shell { Some(ClapShell::Bash) => { generate(Bash, &mut Args::command(), "mihoro", &mut io::stdout()) @@ -256,9 +86,10 @@ async fn cli() -> Result<()> { Some(ClapShell::Fish) => { generate(Fish, &mut Args::command(), "mihoro", &mut io::stdout()) } - _ => println!("{} No shell specified, --help for usage", prefix.red()), + _ => (), }, - None => println!("{} No command specified, --help for usage", prefix.yellow()), + + None => (), } Ok(()) } diff --git a/src/mihoro.rs b/src/mihoro.rs new file mode 100644 index 0000000..8b53eec --- /dev/null +++ b/src/mihoro.rs @@ -0,0 +1,250 @@ +use crate::cmd::ProxyCommands; +use crate::config::{apply_mihomo_override, parse_config, Config}; +use crate::proxy::{proxy_export_cmd, proxy_unset_cmd}; +use crate::systemctl::Systemctl; +use crate::utils::{create_parent_dir, delete_file, download_file, extract_gzip}; + +use std::fs; +use std::os::unix::prelude::PermissionsExt; + +use anyhow::Result; +use colored::Colorize; +use local_ip_address::local_ip; +use reqwest::Client; +use shellexpand::tilde; + +#[derive(Debug)] +pub struct Mihoro { + // global mihoro config + pub prefix: String, + pub config: Config, + + // mihomo global variables derived from mihoro config + pub mihomo_target_binary_path: String, + pub mihomo_target_config_root: String, + pub mihomo_target_config_path: String, + pub mihomo_target_service_path: String, +} + +impl Mihoro { + pub fn new(config_path: &String) -> Result { + let config = parse_config(tilde(&config_path).as_ref())?; + return Ok(Mihoro { + prefix: String::from("mihoro:"), + config: config.clone(), + mihomo_target_binary_path: tilde(&config.mihomo_binary_path).to_string(), + mihomo_target_config_root: tilde(&config.mihomo_config_root).to_string(), + mihomo_target_config_path: tilde(&format!("{}/config.yaml", config.mihomo_config_root)) + .to_string(), + mihomo_target_service_path: tilde(&format!( + "{}/mihomo.service", + config.user_systemd_root + )) + .to_string(), + }); + } + + pub async fn setup(self, client: Client) -> Result<()> { + println!( + "{} Setting up mihomo's binary, config, and systemd service...", + &self.prefix.cyan() + ); + + // Attempt to download and setup mihomo binary if needed + if fs::metadata(&self.mihomo_target_binary_path).is_ok() { + // If mihomo binary already exists at `mihomo_target_binary_path`, then skip setup + println!( + "{} Assuming mihomo binary already installed at {}, skipping setup", + self.prefix.yellow(), + self.mihomo_target_binary_path.underline().green() + ); + } else { + // Download mihomo binary and set permission to executable + download_file( + &client, + &self.config.remote_mihomo_binary_url, + "mihomo-downloaded-binary.tar.gz", + ) + .await?; + extract_gzip( + "mihomo-downloaded-binary.tar.gz", + &self.mihomo_target_binary_path, + &self.prefix, + )?; + + let executable = fs::Permissions::from_mode(0o755); + fs::set_permissions(&self.mihomo_target_binary_path, executable)?; + } + + // Download remote mihomo config and apply override + download_file( + &client, + &self.config.remote_config_url, + &self.mihomo_target_config_path, + ) + .await?; + apply_mihomo_override(&self.mihomo_target_config_path, &self.config.mihomo_config)?; + + // Create mihomo.service systemd file + create_mihomo_service( + &self.mihomo_target_binary_path, + &self.mihomo_target_config_root, + &self.mihomo_target_service_path, + &self.prefix, + )?; + + Systemctl::new().enable("mihomo.service").execute()?; + Systemctl::new().start("mihomo.service").execute()?; + Ok(()) + } + + pub async fn update(self, client: Client) -> Result<()> { + // Download remote mihomo config and apply override + download_file( + &client, + &self.config.remote_config_url, + &self.mihomo_target_config_path, + ) + .await?; + apply_mihomo_override(&self.mihomo_target_config_path, &self.config.mihomo_config)?; + println!( + "{} Updated and applied config overrides", + self.prefix.yellow() + ); + + // Restart mihomo systemd service + println!("{} Restart mihomo.service", self.prefix.green()); + Systemctl::new().restart("mihomo.service").execute()?; + Ok(()) + } + + pub async fn apply(self) -> Result<()> { + // Apply mihomo config override + apply_mihomo_override(&self.mihomo_target_config_path, &self.config.mihomo_config).map( + |_| { + println!( + "{} Applied mihomo config overrides", + self.prefix.green().bold() + ); + }, + )?; + + // Restart mihomo systemd service + Systemctl::new() + .restart("mihomo.service") + .execute() + .map(|_| { + println!("{} Restarted mihomo.service", self.prefix.green().bold()); + })?; + Ok(()) + } + + pub fn uninstall(self) -> Result<()> { + Systemctl::new().stop("mihomo.service").execute()?; + Systemctl::new().disable("mihomo.service").execute()?; + + delete_file(&self.mihomo_target_service_path, &self.prefix)?; + delete_file(&self.mihomo_target_config_path, &self.prefix)?; + + Systemctl::new().daemon_reload().execute()?; + Systemctl::new().reset_failed().execute()?; + println!( + "{} Disabled and reloaded systemd services", + self.prefix.green() + ); + println!( + "{} You may need to remove mihomo binary and config directory manually", + self.prefix.yellow() + ); + + let remove_cmd = format!( + "rm -R {} {}", + self.mihomo_target_binary_path, self.mihomo_target_config_root + ); + println!("{} `{}`", "->".dimmed(), remove_cmd.underline().bold()); + Ok(()) + } + + pub fn proxy_commands(self, proxy: &Option) -> Result<()> { + match proxy { + Some(ProxyCommands::Export) => { + println!( + "{}", + proxy_export_cmd( + "127.0.0.1", + &self.config.mihomo_config.port, + &self.config.mihomo_config.socks_port + ) + ) + } + Some(ProxyCommands::ExportLan) => { + if !self.config.mihomo_config.allow_lan.unwrap_or(false) { + println!( + "{} `{}` is false, proxy is not available for LAN", + "warning:".yellow(), + "allow_lan".bold() + ); + } + + println!( + "{}", + proxy_export_cmd( + &local_ip()?.to_string(), + &self.config.mihomo_config.port, + &self.config.mihomo_config.socks_port + ) + ); + } + Some(ProxyCommands::Unset) => { + println!("{}", proxy_unset_cmd()) + } + _ => (), + } + Ok(()) + } +} + +/// Create a systemd service file for running mihomo as a service. +/// +/// By default, user systemd services are created under `~/.config/systemd/user/mihomo.service` and +/// invoked with `systemctl --user start mihomo.service`. Directory is created if not present. +/// +/// Reference: https://wiki.metacubex.one/startup/service/ +fn create_mihomo_service( + mihomo_binary_path: &str, + mihomo_config_root: &str, + mihomo_service_path: &str, + prefix: &str, +) -> Result<()> { + let service = format!( + "[Unit] +Description=mihomo Daemon, Another Clash Kernel. +After=network.target NetworkManager.service systemd-networkd.service iwd.service + +[Service] +Type=simple +LimitNPROC=500 +LimitNOFILE=1000000 +Restart=always +ExecStartPre=/usr/bin/sleep 1s +ExecStart={} -d {} +ExecReload=/bin/kill -HUP $MAINPID + +[Install] +WantedBy=default.target", + mihomo_binary_path, mihomo_config_root + ); + + // Create mihomo service directory if not exists + create_parent_dir(mihomo_service_path)?; + + // Write mihomo.service contents to file + fs::write(mihomo_service_path, service)?; + + println!( + "{} Created mihomo.service at {}", + prefix.green(), + mihomo_service_path.underline().yellow() + ); + Ok(()) +} diff --git a/src/proxy.rs b/src/proxy.rs new file mode 100644 index 0000000..3355aa5 --- /dev/null +++ b/src/proxy.rs @@ -0,0 +1,39 @@ +use clap_complete::shells::Shell; + +pub fn proxy_export_cmd(hostname: &str, http_port: &u16, socks_port: &u16) -> String { + // Check current shell + let shell = Shell::from_env().unwrap_or(Shell::Bash); + match shell { + Shell::Fish => { + // For fish, use `set -gx $ENV_VAR value` to set environment variables + format!( + "set -gx https_proxy http://{hostname}:{http_port} \ + set -gx http_proxy http://{hostname}:{http_port} \ + set -gx all_proxy socks5://{hostname}:{socks_port}" + ) + } + _ => { + // For all other shells (bash/zsh), use `export $ENV_VAR=value` + format!( + "export https_proxy=http://{hostname}:{http_port} \ + http_proxy=http://{hostname}:{http_port} \ + all_proxy=socks5://{hostname}:{socks_port}" + ) + } + } +} + +pub fn proxy_unset_cmd() -> String { + // Check current shell + let shell = Shell::from_env().unwrap_or(Shell::Bash); + match shell { + Shell::Fish => { + // For fish, use `set -e $ENV_VAR` to unset environment variables + "set -e https_proxy http_proxy all_proxy".to_owned() + } + _ => { + // For all other shells (bash/zsh), use `unset $ENV_VAR` + "unset https_proxy http_proxy all_proxy".to_owned() + } + } +} diff --git a/src/systemctl.rs b/src/systemctl.rs index 82e9ca7..8f2cc1b 100644 --- a/src/systemctl.rs +++ b/src/systemctl.rs @@ -1,8 +1,6 @@ -use std::process::Command; -use std::process::ExitStatus; +use std::process::{Command, ExitStatus}; -use anyhow::Context; -use anyhow::Result; +use anyhow::{Context, Result}; pub struct Systemctl { systemctl: Command, diff --git a/src/utils.rs b/src/utils.rs index f9419c0..4e778a6 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,21 +1,23 @@ -use std::cmp::min; -use std::fs; -use std::fs::File; -use std::io; -use std::io::Write; -use std::path::Path; - -use anyhow::Context; -use anyhow::Result; -use clap_complete::shells::Shell; +use std::{ + cmp::min, + fs::{self, File}, + io::{self, Write}, + path::Path, +}; + +use anyhow::{Context, Result}; use colored::Colorize; use flate2::read::GzDecoder; use futures_util::StreamExt; -use indicatif::ProgressBar; -use indicatif::ProgressStyle; +use indicatif::{ProgressBar, ProgressStyle}; use reqwest::Client; use truncatable::Truncatable; +/// Creates the parent directory for a given path if it does not exist. +/// +/// # Arguments +/// +/// * `path` - A string slice that holds the path for which the parent directory should be created. pub fn create_parent_dir(path: &str) -> Result<()> { let parent_dir = Path::new(path) .parent() @@ -102,7 +104,7 @@ pub fn delete_file(path: &str, prefix: &str) -> Result<()> { // Delete file if exists if Path::new(path).exists() { fs::remove_file(path).map(|_| { - println!("{} Removed {}", prefix.red(), path.underline().yellow()); + println!("{} Removed {}", prefix.cyan(), path.underline().yellow()); })?; } Ok(()) @@ -124,86 +126,3 @@ pub fn extract_gzip(gzip_path: &str, filename: &str, prefix: &str) -> Result<()> ); Ok(()) } - -/// Create a systemd service file for running mihomo as a service. -/// -/// By default, user systemd services are created under `~/.config/systemd/user/mihomo.service` and -/// invoked with `systemctl --user start mihomo.service`. Directory is created if not present. -/// -/// Reference: https://wiki.metacubex.one/startup/service/ -pub fn create_mihomo_service( - mihomo_binary_path: &str, - mihomo_config_root: &str, - mihomo_service_path: &str, - prefix: &str, -) -> Result<()> { - let service = format!( - "[Unit] -Description=mihomo Daemon, Another Clash Kernel. -After=network.target NetworkManager.service systemd-networkd.service iwd.service - -[Service] -Type=simple -LimitNPROC=500 -LimitNOFILE=1000000 -Restart=always -ExecStartPre=/usr/bin/sleep 1s -ExecStart={} -d {} -ExecReload=/bin/kill -HUP $MAINPID - -[Install] -WantedBy=default.target", - mihomo_binary_path, mihomo_config_root - ); - - // Create mihomo service directory if not exists - create_parent_dir(mihomo_service_path)?; - - // Write mihomo.service contents to file - fs::write(mihomo_service_path, service)?; - - println!( - "{} Created mihomo.service at {}", - prefix.green(), - mihomo_service_path.underline().yellow() - ); - Ok(()) -} - -pub fn proxy_export_cmd(hostname: &str, http_port: &u16, socks_port: &u16) -> String { - // Check current shell - let shell = Shell::from_env().unwrap_or(Shell::Bash); - match shell { - Shell::Fish => { - // For fish, use `set -gx $ENV_VAR value` to set environment variables - format!( - "set -gx https_proxy http://{hostname}:{http_port} \ - set -gx http_proxy http://{hostname}:{http_port} \ - set -gx all_proxy socks5://{hostname}:{socks_port}" - ) - } - _ => { - // For all other shells (bash/zsh), use `export $ENV_VAR=value` - format!( - "export https_proxy=http://{hostname}:{http_port} \ - http_proxy=http://{hostname}:{http_port} \ - all_proxy=socks5://{hostname}:{socks_port}" - ) - } - } -} - -pub fn proxy_unset_cmd() -> String { - // Check current shell - let shell = Shell::from_env().unwrap_or(Shell::Bash); - match shell { - Shell::Fish => { - // For fish, use `set -e $ENV_VAR` to unset environment variables - "set -e https_proxy http_proxy all_proxy".to_owned() - } - _ => { - // For all other shells (bash/zsh), use `unset $ENV_VAR` - "unset https_proxy http_proxy all_proxy".to_owned() - } - } -}