Refactor VPN proxy routing and session handling
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
#[path = "../src/activity.rs"]
|
||||
mod activity;
|
||||
#[path = "../src/component_detection.rs"]
|
||||
mod component_detection;
|
||||
#[path = "../src/commands.rs"]
|
||||
mod commands;
|
||||
#[path = "../src/component_detection.rs"]
|
||||
mod component_detection;
|
||||
#[path = "../src/models.rs"]
|
||||
mod models;
|
||||
#[path = "../src/adapters/proxifyre.rs"]
|
||||
@@ -17,9 +17,9 @@ mod validation;
|
||||
|
||||
use commands::{
|
||||
apply_profiles_with_services, build_status, resolve_component_statuses, resolve_preview,
|
||||
save_profile_to_storage, save_target_to_storage, Clock, CommandError,
|
||||
DetectedProxyApplyHelper, HelperApplyRequest, HelperApplyResult, ProfileInputDto,
|
||||
ProfileItemInputDto, ProxyApplyHelper, TargetInputDto,
|
||||
save_profile_to_storage, save_target_to_storage, Clock, CommandError, DetectedProxyApplyHelper,
|
||||
HelperApplyRequest, HelperApplyResult, ProfileInputDto, ProfileItemInputDto, ProxyApplyHelper,
|
||||
TargetInputDto,
|
||||
};
|
||||
use component_detection::{
|
||||
DetectedProxyfier, ProxyfierDetectionHost, ProxyfierEngine, RegistryInstallEntry,
|
||||
@@ -240,8 +240,8 @@ fn detected_proxy_apply_helper_writes_proxifyre_app_config() {
|
||||
})
|
||||
.expect("detected helper should apply");
|
||||
|
||||
let applied = fs::read_to_string(install_dir.join("app-config.json"))
|
||||
.expect("read applied app-config");
|
||||
let applied =
|
||||
fs::read_to_string(install_dir.join("app-config.json")).expect("read applied app-config");
|
||||
|
||||
assert!(result.success);
|
||||
assert!(result.changed);
|
||||
@@ -276,7 +276,9 @@ fn detected_proxy_apply_helper_ignores_plain_proxifier_install() {
|
||||
assert!(result.success);
|
||||
assert!(result.changed);
|
||||
assert_eq!(result.action, "proxifyre.stage-generated-config");
|
||||
assert!(result.message.contains("совместимая установка ProxiFyre не найдена"));
|
||||
assert!(result
|
||||
.message
|
||||
.contains("совместимая установка ProxiFyre не найдена"));
|
||||
|
||||
cleanup(&root);
|
||||
}
|
||||
@@ -358,7 +360,10 @@ impl ProxyfierDetectionHost for DetectionHost {
|
||||
}
|
||||
|
||||
fn normalize_path(path: &Path) -> String {
|
||||
path.display().to_string().replace('/', "\\").to_ascii_lowercase()
|
||||
path.display()
|
||||
.to_string()
|
||||
.replace('/', "\\")
|
||||
.to_ascii_lowercase()
|
||||
}
|
||||
|
||||
fn test_root(name: &str) -> PathBuf {
|
||||
|
||||
@@ -7,7 +7,7 @@ use component_detection::{
|
||||
detect_proxyfier_install_with_host, proxyfier_component_from_detection, ProxyfierDetectionHost,
|
||||
ProxyfierEngine, RegistryInstallEntry,
|
||||
};
|
||||
use models::{ComponentState};
|
||||
use models::ComponentState;
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
path::{Path, PathBuf},
|
||||
@@ -25,7 +25,10 @@ fn detects_existing_proxifyre_from_registry_install_location() {
|
||||
|
||||
assert_eq!(detected.engine, ProxyfierEngine::ProxiFyre);
|
||||
assert_eq!(detected.install_dir, PathBuf::from(r"C:\Tools\ProxiFyre"));
|
||||
assert_eq!(detected.config_path, Some(PathBuf::from(r"C:\Tools\ProxiFyre\app-config.json")));
|
||||
assert_eq!(
|
||||
detected.config_path,
|
||||
Some(PathBuf::from(r"C:\Tools\ProxiFyre\app-config.json"))
|
||||
);
|
||||
assert!(detected.running);
|
||||
|
||||
let component = proxyfier_component_from_detection(Some(&detected));
|
||||
@@ -56,7 +59,10 @@ fn env_override_can_point_to_portable_proxifyre_install() {
|
||||
.expect("env override should be checked before common paths");
|
||||
|
||||
assert_eq!(detected.engine, ProxyfierEngine::ProxiFyre);
|
||||
assert_eq!(detected.executable_path, PathBuf::from(r"D:\Portable\ProxiFyre\ProxiFyre.exe"));
|
||||
assert_eq!(
|
||||
detected.executable_path,
|
||||
PathBuf::from(r"D:\Portable\ProxiFyre\ProxiFyre.exe")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -118,17 +124,16 @@ impl ProxyfierDetectionHost for MockHost {
|
||||
}
|
||||
|
||||
fn path_exists(&self, path: &Path) -> bool {
|
||||
self.paths.contains(&normalize_path(&path.display().to_string()))
|
||||
self.paths
|
||||
.contains(&normalize_path(&path.display().to_string()))
|
||||
}
|
||||
|
||||
fn process_running(&self, process_name: &str) -> bool {
|
||||
self.processes
|
||||
.contains(&process_name.to_ascii_lowercase())
|
||||
self.processes.contains(&process_name.to_ascii_lowercase())
|
||||
}
|
||||
|
||||
fn service_running(&self, service_name: &str) -> bool {
|
||||
self.services
|
||||
.contains(&service_name.to_ascii_lowercase())
|
||||
self.services.contains(&service_name.to_ascii_lowercase())
|
||||
}
|
||||
|
||||
fn registry_install_entries(&self) -> Vec<RegistryInstallEntry> {
|
||||
|
||||
@@ -124,7 +124,5 @@ fn rejects_malformed_target_fields() {
|
||||
assert!(error.iter().any(|item| item.field == "host"));
|
||||
assert!(error.iter().any(|item| item.field == "port"));
|
||||
assert!(error.iter().any(|item| item.field == "protocol"));
|
||||
assert!(error
|
||||
.iter()
|
||||
.any(|item| item.field == "requires_component"));
|
||||
assert!(error.iter().any(|item| item.field == "requires_component"));
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#[path = "../src/models.rs"]
|
||||
mod models;
|
||||
#[path = "../src/adapters/proxy_router.rs"]
|
||||
mod proxy_router;
|
||||
#[path = "../src/adapters/proxifyre.rs"]
|
||||
mod proxifyre;
|
||||
#[path = "../src/adapters/proxy_router.rs"]
|
||||
mod proxy_router;
|
||||
|
||||
use models::{
|
||||
ComponentId, ComponentState, ComponentStatus, Profile, ProfileItem, ProfileItemType, Protocol,
|
||||
@@ -33,7 +33,10 @@ fn generates_proxifyre_config_for_discord_external_socks5_target() {
|
||||
assert!(config.bypass_lan);
|
||||
assert_eq!(config.proxies.len(), 1);
|
||||
assert_eq!(config.proxies[0].app_names, vec!["Discord"]);
|
||||
assert_eq!(config.proxies[0].socks5_proxy_endpoint, "192.168.50.111:8080");
|
||||
assert_eq!(
|
||||
config.proxies[0].socks5_proxy_endpoint,
|
||||
"192.168.50.111:8080"
|
||||
);
|
||||
assert_eq!(config.proxies[0].supported_protocols, vec!["TCP", "UDP"]);
|
||||
}
|
||||
|
||||
@@ -57,6 +60,32 @@ fn skips_disabled_profiles_when_generating_proxifyre_config() {
|
||||
assert!(config.proxies.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn includes_folder_paths_when_generating_proxifyre_config() {
|
||||
let adapter = ProxiFyreAdapter::default();
|
||||
let mut profile = discord_profile("home-gateway");
|
||||
profile.items.push(ProfileItem {
|
||||
item_type: ProfileItemType::Folder,
|
||||
value: r"C:\Games\MyGame".to_string(),
|
||||
recursive: true,
|
||||
});
|
||||
let profiles = vec![profile];
|
||||
let targets = vec![external_socks5_target()];
|
||||
let components = Vec::new();
|
||||
|
||||
let generated = adapter
|
||||
.generate_config(ProxyRouterRequest::new(&profiles, &targets, &components))
|
||||
.expect("folder paths should be accepted by ProxiFyre config generation");
|
||||
let config: ProxiFyreConfig =
|
||||
serde_json::from_str(&generated.contents).expect("generated config json");
|
||||
|
||||
assert_eq!(generated.routed_apps, 2);
|
||||
assert_eq!(
|
||||
config.proxies[0].app_names,
|
||||
vec!["Discord", r"C:\Games\MyGame"]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn blocks_local_singbox_target_when_required_component_is_missing() {
|
||||
let adapter = ProxiFyreAdapter::default();
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#[path = "../src/models.rs"]
|
||||
mod models;
|
||||
#[path = "../src/adapters/proxy_router.rs"]
|
||||
mod proxy_router;
|
||||
#[path = "../src/adapters/proxifyre.rs"]
|
||||
mod proxifyre;
|
||||
#[path = "../src/adapters/proxy_router.rs"]
|
||||
mod proxy_router;
|
||||
#[path = "../src/adapters/singbox.rs"]
|
||||
mod singbox;
|
||||
|
||||
@@ -14,8 +14,8 @@ use models::{
|
||||
use proxifyre::{ProxiFyreAdapter, ProxiFyreConfig};
|
||||
use proxy_router::{ProxyRouterAdapter, ProxyRouterRequest};
|
||||
use singbox::{
|
||||
SingBoxAdapter, SingBoxCheckResult, SingBoxConfig, SingBoxConfigChecker,
|
||||
SingBoxConfigError, SingBoxConfigErrorKind, SingBoxGenerationRequest, SINGBOX_OUTPUT_FILE,
|
||||
SingBoxAdapter, SingBoxCheckResult, SingBoxConfig, SingBoxConfigChecker, SingBoxConfigError,
|
||||
SingBoxConfigErrorKind, SingBoxGenerationRequest, SINGBOX_OUTPUT_FILE,
|
||||
};
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
@@ -116,7 +116,10 @@ fn blocks_local_singbox_config_when_component_is_not_running() {
|
||||
)
|
||||
.expect_err("local sing-box target requires running component");
|
||||
|
||||
assert_eq!(error.kind, SingBoxConfigErrorKind::RequiredComponentNotRunning);
|
||||
assert_eq!(
|
||||
error.kind,
|
||||
SingBoxConfigErrorKind::RequiredComponentNotRunning
|
||||
);
|
||||
assert!(checker.calls.borrow().is_empty());
|
||||
}
|
||||
|
||||
@@ -129,11 +132,7 @@ fn propagates_failed_singbox_check_as_structured_error() {
|
||||
|
||||
let error = adapter
|
||||
.generate_config(
|
||||
SingBoxGenerationRequest::new(
|
||||
&targets,
|
||||
&components,
|
||||
Some(Path::new("sing-box.exe")),
|
||||
),
|
||||
SingBoxGenerationRequest::new(&targets, &components, Some(Path::new("sing-box.exe"))),
|
||||
&checker,
|
||||
)
|
||||
.expect_err("failed sing-box check should block generated config");
|
||||
@@ -156,7 +155,10 @@ fn external_proxifyre_apply_does_not_require_singbox_component() {
|
||||
serde_json::from_str(&generated.contents).expect("generated proxifyre json");
|
||||
|
||||
assert_eq!(config.proxies.len(), 1);
|
||||
assert_eq!(config.proxies[0].socks5_proxy_endpoint, "192.168.50.111:8080");
|
||||
assert_eq!(
|
||||
config.proxies[0].socks5_proxy_endpoint,
|
||||
"192.168.50.111:8080"
|
||||
);
|
||||
}
|
||||
|
||||
struct RecordingChecker {
|
||||
|
||||
@@ -45,7 +45,10 @@ fn roundtrips_profiles_targets_components_and_activity() {
|
||||
|
||||
assert_eq!(storage.read_profiles().expect("read profiles"), profiles);
|
||||
assert_eq!(storage.read_targets().expect("read targets"), targets);
|
||||
assert_eq!(storage.read_components().expect("read components"), components);
|
||||
assert_eq!(
|
||||
storage.read_components().expect("read components"),
|
||||
components
|
||||
);
|
||||
assert_eq!(storage.read_activity().expect("read activity"), activity);
|
||||
|
||||
cleanup(&root);
|
||||
|
||||
Reference in New Issue
Block a user