Refactor proxy handling and update related UI flows

This commit is contained in:
2026-07-08 09:01:10 +03:00
parent b45dd2ae05
commit 288acbf0c8
14 changed files with 2655 additions and 552 deletions

View File

@@ -219,6 +219,13 @@ pub struct PingSingBoxServerInputDto {
pub tag: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PingProxyTargetInputDto {
pub host: String,
pub port: u16,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PingServerResponse {
@@ -619,6 +626,11 @@ pub fn ping_all_singbox_servers(
ping_all_singbox_servers_in_storage(&state.storage())
}
#[tauri::command]
pub fn ping_proxy_target(input: PingProxyTargetInputDto) -> Result<PingServerResponse, CommandError> {
ping_proxy_target_endpoint(input)
}
#[tauri::command]
pub fn generate_singbox_config(
state: tauri::State<'_, CommandState>,
@@ -1115,6 +1127,20 @@ pub fn ping_all_singbox_servers_in_storage(
Ok(cache.servers.iter().map(ping_subscription_server).collect())
}
pub fn ping_proxy_target_endpoint(
input: PingProxyTargetInputDto,
) -> Result<PingServerResponse, CommandError> {
let host = input.host.trim();
if host.is_empty() {
return Err(CommandError::new(
"proxy_target_host_missing",
"Хост внешнего прокси не указан.",
));
}
Ok(ping_endpoint("external-proxy", host, input.port))
}
pub fn generate_singbox_config_with_services<C>(
storage: &JsonStorage,
adapter: &SingBoxAdapter,
@@ -1196,14 +1222,18 @@ fn validate_subscription_url(subscription_url: &str) -> Result<(), CommandError>
}
fn ping_subscription_server(server: &SubscriptionServer) -> PingServerResponse {
ping_endpoint(&server.tag, &server.server, server.server_port)
}
fn ping_endpoint(tag: &str, server: &str, server_port: u16) -> PingServerResponse {
let started = Instant::now();
let addresses = match (server.server.as_str(), server.server_port).to_socket_addrs() {
let addresses = match (server, server_port).to_socket_addrs() {
Ok(addresses) => addresses.collect::<Vec<_>>(),
Err(error) => {
return PingServerResponse {
tag: server.tag.clone(),
server: server.server.clone(),
server_port: server.server_port,
tag: tag.to_string(),
server: server.to_string(),
server_port,
ok: false,
latency: None,
error: Some(format!("DNS/адрес недоступен: {error}")),
@@ -1213,9 +1243,9 @@ fn ping_subscription_server(server: &SubscriptionServer) -> PingServerResponse {
if addresses.is_empty() {
return PingServerResponse {
tag: server.tag.clone(),
server: server.server.clone(),
server_port: server.server_port,
tag: tag.to_string(),
server: server.to_string(),
server_port,
ok: false,
latency: None,
error: Some("DNS не вернул адреса".to_string()),
@@ -1228,9 +1258,9 @@ fn ping_subscription_server(server: &SubscriptionServer) -> PingServerResponse {
match TcpStream::connect_timeout(&address, timeout) {
Ok(_) => {
return PingServerResponse {
tag: server.tag.clone(),
server: server.server.clone(),
server_port: server.server_port,
tag: tag.to_string(),
server: server.to_string(),
server_port,
ok: true,
latency: Some(started.elapsed().as_millis()),
error: None,
@@ -1241,9 +1271,9 @@ fn ping_subscription_server(server: &SubscriptionServer) -> PingServerResponse {
}
PingServerResponse {
tag: server.tag.clone(),
server: server.server.clone(),
server_port: server.server_port,
tag: tag.to_string(),
server: server.to_string(),
server_port,
ok: false,
latency: None,
error: last_error,

View File

@@ -52,6 +52,7 @@ fn main() {
commands::select_singbox_server,
commands::ping_singbox_server,
commands::ping_all_singbox_servers,
commands::ping_proxy_target,
commands::generate_singbox_config,
commands::apply_profiles,
commands::get_logs,

View File

@@ -37,6 +37,7 @@ use models::{
use proxifyre::ProxiFyreAdapter;
use std::collections::HashSet;
use std::fs;
use std::net::TcpListener;
use std::path::{Path, PathBuf};
#[cfg(windows)]
use std::process::Command as ProcessCommand;
@@ -127,6 +128,24 @@ fn resolve_preview_returns_structured_apps_without_filesystem_scan() {
.any(|warning| warning.contains("Сканирование папок отложено")));
}
#[test]
fn ping_proxy_target_reports_open_tcp_endpoint() {
let listener = TcpListener::bind("127.0.0.1:0").expect("bind local listener");
let port = listener.local_addr().expect("read local addr").port();
let result = commands::ping_proxy_target_endpoint(commands::PingProxyTargetInputDto {
host: "127.0.0.1".to_string(),
port,
})
.expect("ping should return response");
assert_eq!(result.tag, "external-proxy");
assert_eq!(result.server, "127.0.0.1");
assert_eq!(result.server_port, port);
assert!(result.ok);
assert!(result.latency.is_some());
}
#[test]
#[cfg(windows)]
fn proxifyre_install_script_parses_as_powershell() {