Refactor proxy routing and session management

This commit is contained in:
2026-07-08 00:09:38 +03:00
parent c5bdb10445
commit b45dd2ae05
26 changed files with 5193 additions and 307 deletions

View File

@@ -6,8 +6,9 @@ mod models;
mod storage;
use models::{
ActivityEntry, ActivityLevel, ComponentId, ComponentState, ComponentStatus, Profile,
ProfileItem, ProfileItemType, Protocol, ProxyProtocol, Target, TargetKind,
ActivityEntry, ActivityLevel, ComponentId, ComponentState, ComponentStatus, LocalSingBoxConfig,
Profile, ProfileItem, ProfileItemType, Protocol, ProxyProtocol, SubscriptionCache,
SubscriptionServer, Target, TargetKind,
};
use std::fs;
use std::path::{Path, PathBuf};
@@ -54,6 +55,86 @@ fn roundtrips_profiles_targets_components_and_activity() {
cleanup(&root);
}
#[test]
fn roundtrips_local_singbox_config_and_subscription_cache() {
let root = test_root("local-singbox");
let storage = JsonStorage::new(root.clone());
let config = LocalSingBoxConfig {
subscription_url: Some("https://sub.example.test/path?token=secret".to_string()),
selected_server_tag: Some("nl-1".to_string()),
listen_host: "127.0.0.1".to_string(),
listen_port: 1080,
service_name: "VpnProxySingBox".to_string(),
install_root: r"C:\Program Files\VpnProxy\sing-box".to_string(),
updated_at: Some("2026-07-07T10:00:00Z".to_string()),
};
let cache = sample_subscription_cache();
storage
.write_local_singbox_config(&config)
.expect("write local sing-box config");
storage
.write_singbox_subscription_cache(&cache)
.expect("write subscription cache");
assert_eq!(
storage
.read_local_singbox_config()
.expect("read local sing-box config"),
config
);
assert_eq!(
storage
.read_singbox_subscription_cache()
.expect("read subscription cache"),
Some(cache)
);
assert_eq!(
config.subscription_display_url(),
Some("https://sub.example.test/...".to_string())
);
cleanup(&root);
}
#[test]
fn missing_local_singbox_config_defaults_to_optional_empty_state() {
let root = test_root("local-singbox-default");
let storage = JsonStorage::new(root.clone());
let config = storage
.read_local_singbox_config()
.expect("read default local sing-box config");
assert_eq!(config.subscription_url, None);
assert_eq!(config.selected_server_tag, None);
assert_eq!(config.listen_host, "127.0.0.1");
assert_eq!(config.listen_port, 1080);
assert_eq!(config.service_name, "VpnProxySingBox");
cleanup(&root);
}
#[test]
fn invalid_subscription_cache_falls_back_to_none() {
let root = test_root("invalid-subscription-cache");
let storage = JsonStorage::new(root.clone());
storage.ensure_dirs().expect("create storage dirs");
fs::write(
&storage.paths().singbox_subscription_cache_file,
"{not valid json",
)
.expect("write invalid cache");
assert_eq!(
storage
.read_singbox_subscription_cache()
.expect("invalid cache fallback"),
None
);
cleanup(&root);
}
#[test]
fn invalid_json_falls_back_to_empty_collection() {
let root = test_root("invalid-json");
@@ -187,6 +268,29 @@ fn sample_component() -> ComponentStatus {
}
}
fn sample_subscription_cache() -> SubscriptionCache {
SubscriptionCache {
config: serde_json::json!({
"outbounds": [
{
"type": "vless",
"tag": "nl-1",
"server": "nl.example.test",
"server_port": 443
}
]
}),
servers: vec![SubscriptionServer {
tag: "nl-1".to_string(),
server_type: "vless".to_string(),
server: "nl.example.test".to_string(),
server_port: 443,
}],
user_info: serde_json::Map::new(),
fetched_at: "2026-07-07T10:00:00Z".to_string(),
}
}
fn sample_activity(id: &str, at: &str, level: ActivityLevel) -> ActivityEntry {
ActivityEntry {
id: id.to_string(),