feat: migrate mihomo to use kode-bridge IPC on Windows and Unix (#4051)
* Refactor Mihomo API integration and remove crate_mihomo_api - Removed the `mihomo_api` crate and its dependencies from the project. - Introduced `IpcManager` for handling IPC communication with Mihomo. - Implemented IPC methods for managing proxies, connections, and configurations. - Updated `MihomoManager` to utilize `IpcManager` instead of the removed crate. - Added platform-specific IPC socket path handling for macOS, Linux, and Windows. - Cleaned up related tests and configuration files. * fix: remove duplicate permission entry in desktop capabilities * refactor: replace MihomoManager with IpcManager and remove Mihomo module * fix: restore tempfile dependency in dev-dependencies * fix: update kode-bridge dependency to use git source from the dev branch * feat: migrate mihomo to use kode-bridge IPC on Windows This commit implements a comprehensive migration from legacy service IPC to the kode-bridge library for Windows IPC communication. Key changes include: Replace service_ipc with kode-bridge IpcManager for all mihomo communications Simplify proxy commands using new caching mechanism with ProxyRequestCache Add Windows named pipe (\.\pipe\mihomo) and Unix socket IPC endpoint configuration Update Tauri permissions and dependencies (dashmap, tauri-plugin-notification) Add IPC logging support and improve error handling Fix Windows IPC path handling in directory utilities This migration enables better cross-platform IPC support and improved performance for mihomo proxy core communication. * doc: add IPC communication with Mihomo kernel, removing Restful API dependency * fix: standardize logging type naming from IPC to Ipc for consistency * refactor: clean up and optimize code structure across multiple components and services - Removed unnecessary comments and whitespace in various files. - Improved code readability and maintainability by restructuring functions and components. - Updated localization files for consistency and accuracy. - Enhanced performance by optimizing hooks and utility functions. - General code cleanup in settings, pages, and services to adhere to best practices. * fix: simplify URL formatting in test_proxy_delay method * fix: update kode-bridge dependency to version 0.1.3 and change source to crates.io * fix: update macOS target versions in development workflow * Revert "fix: update macOS target versions in development workflow" This reverts commit b9831357e462e0f308d11a9a53cb718f98ae1295. * feat: enhance IPC path handling for Unix systems and improve directory safety checks * feat: add conditional compilation for Unix-specific IPC path handling * chore: update cagro.lock * feat: add external controller configuration and UI support * Refactor proxy and connection management to use IPC-based commands - Updated `get_proxies` function in `proxy.rs` to call the new IPC command. - Renamed `get_refresh_proxies` to `get_proxies` in `ipc/general.rs` for consistency. - Added new IPC commands for managing proxies, connections, and configurations in `cmds.ts`. - Refactored API calls in various components to use the new IPC commands instead of HTTP requests. - Improved error handling and response management in the new IPC functions. - Cleaned up unused API functions in `api.ts` and redirected relevant calls to `cmds.ts`. - Enhanced connection management features including health checks and updates for proxy providers. * chore: update dependencies and improve error handling in IPC manager * fix: downgrade zip dependency from 4.3.0 to 4.2.0 * feat: Implement traffic and memory data monitoring service - Added `TrafficService` and `TrafficManager` to manage traffic and memory data collection. - Introduced commands to get traffic and memory data, start and stop the traffic service. - Integrated IPC calls for traffic and memory data retrieval in the frontend. - Updated `AppDataProvider` and `EnhancedTrafficStats` components to utilize new data fetching methods. - Removed WebSocket connections for traffic and memory data, replaced with IPC polling. - Added logging for better traceability of data fetching and service status. * refactor: unify external controller handling and improve IPC path resolution * fix: replace direct IPC path retrieval with guard function for external controller * fix: convert external controller IPC path to string for proper insertion in config map * fix: update dependencies and improve IPC response handling * fix: remove unnecessary unix conditional for ipc path import * Refactor traffic and memory monitoring to use IPC stream; remove TrafficService and TrafficManager. Introduce new IPC-based data retrieval methods for traffic and memory, including formatted data and system overview. Update frontend components to utilize new APIs for enhanced data display and management. * chore: bump crate rand version to 0.9.2 * feat: Implement enhanced traffic monitoring system with data compression and sampling - Introduced `useTrafficMonitorEnhanced` hook for advanced traffic data management. - Added `TrafficDataSampler` class for handling raw and compressed traffic data. - Implemented reference counting to manage data collection based on component usage. - Enhanced data validation with `SystemMonitorValidator` for API responses. - Created diagnostic tools for monitoring performance and error tracking. - Updated existing hooks to utilize the new enhanced monitoring features. - Added utility functions for generating and formatting diagnostic reports. * feat(ipc): improve URL encoding and error handling for IPC requests - Add percent-encoding for URL paths to handle special characters properly - Enhance error handling in update_proxy with proper logging - Remove excessive debug logging to reduce noise - Update kode-bridge dependency to v0.1.5 - Fix JSON parsing error handling in PUT requests Changes include: - Proper URL encoding for connection IDs, proxy names, and test URLs - Enhanced error handling with fallback responses in updateProxy - Comment out verbose debug logs in traffic monitoring and data validation - Update dependency version for improved IPC functionality * feat: major improvements in architecture, traffic monitoring, and data validation * Refactor traffic graph components: Replace EnhancedTrafficGraph with EnhancedCanvasTrafficGraph, improve rendering performance, and enhance visual elements. Remove deprecated code and ensure compatibility with global data management. * chore: update UPDATELOG.md for v2.4.0 release, refine traffic monitoring system details, and enhance IPC functionality * chore: update UPDATELOG.md to reflect removal of deprecated MihomoManager and unify IPC control * refactor: remove global traffic service testing method from cmds.ts * Update src/components/home/enhanced-canvas-traffic-graph.tsx * Update src/hooks/use-traffic-monitor-enhanced.ts * Update src/components/layout/layout-traffic.tsx * refactor: remove debug state management from LayoutTraffic component ---------
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import axios, { AxiosInstance } from "axios";
|
||||
import { getClashInfo } from "./cmds";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { getClashInfo } from "./cmds";
|
||||
|
||||
let instancePromise: Promise<AxiosInstance> = null!;
|
||||
|
||||
@@ -39,292 +39,6 @@ export const getAxios = async (force: boolean = false) => {
|
||||
return instancePromise;
|
||||
};
|
||||
|
||||
/// Get Version
|
||||
export const getVersion = async () => {
|
||||
const instance = await getAxios();
|
||||
return instance.get("/version") as Promise<{
|
||||
premium: boolean;
|
||||
meta?: boolean;
|
||||
version: string;
|
||||
}>;
|
||||
};
|
||||
|
||||
/// Get current base configs
|
||||
export const getClashConfig = async () => {
|
||||
const instance = await getAxios();
|
||||
return instance.get("/configs") as Promise<IConfigData>;
|
||||
};
|
||||
|
||||
/// Update geo data
|
||||
export const updateGeoData = async () => {
|
||||
const instance = await getAxios();
|
||||
return instance.post("/configs/geo");
|
||||
};
|
||||
|
||||
/// Upgrade clash core
|
||||
export const upgradeCore = async () => {
|
||||
const instance = await getAxios();
|
||||
return instance.post("/upgrade");
|
||||
};
|
||||
|
||||
/// Get current rules
|
||||
export const getRules = async () => {
|
||||
const instance = await getAxios();
|
||||
const response = await instance.get<any, any>("/rules");
|
||||
return response?.rules as IRuleItem[];
|
||||
};
|
||||
|
||||
/// Get Proxy delay
|
||||
export const getProxyDelay = async (
|
||||
name: string,
|
||||
url?: string,
|
||||
timeout?: number,
|
||||
) => {
|
||||
const params = {
|
||||
timeout: timeout || 10000,
|
||||
url: url || "https://cp.cloudflare.com/generate_204",
|
||||
};
|
||||
const instance = await getAxios();
|
||||
const result = await instance.get(
|
||||
`/proxies/${encodeURIComponent(name)}/delay`,
|
||||
{ params },
|
||||
);
|
||||
return result as any as { delay: number };
|
||||
};
|
||||
|
||||
/// Update the Proxy Choose
|
||||
export const updateProxy = async (group: string, proxy: string) => {
|
||||
const instance = await getAxios();
|
||||
return instance.put(`/proxies/${encodeURIComponent(group)}`, { name: proxy });
|
||||
};
|
||||
|
||||
// get proxy
|
||||
export const getProxiesInner = async () => {
|
||||
const response = await invoke<{ proxies: Record<string, IProxyItem> }>(
|
||||
"get_proxies",
|
||||
);
|
||||
return response.proxies as Record<string, IProxyItem>;
|
||||
};
|
||||
|
||||
/// Get the Proxy information
|
||||
export const getProxies = async (): Promise<{
|
||||
global: IProxyGroupItem;
|
||||
direct: IProxyItem;
|
||||
groups: IProxyGroupItem[];
|
||||
records: Record<string, IProxyItem>;
|
||||
proxies: IProxyItem[];
|
||||
}> => {
|
||||
const [proxyRecord, providerRecord] = await Promise.all([
|
||||
getProxiesInner(),
|
||||
getProxyProviders(),
|
||||
]);
|
||||
// provider name map
|
||||
const providerMap = Object.fromEntries(
|
||||
Object.entries(providerRecord).flatMap(([provider, item]) =>
|
||||
item.proxies.map((p) => [p.name, { ...p, provider }]),
|
||||
),
|
||||
);
|
||||
|
||||
// compatible with proxy-providers
|
||||
const generateItem = (name: string) => {
|
||||
if (proxyRecord[name]) return proxyRecord[name];
|
||||
if (providerMap[name]) return providerMap[name];
|
||||
return {
|
||||
name,
|
||||
type: "unknown",
|
||||
udp: false,
|
||||
xudp: false,
|
||||
tfo: false,
|
||||
mptcp: false,
|
||||
smux: false,
|
||||
history: [],
|
||||
};
|
||||
};
|
||||
|
||||
const { GLOBAL: global, DIRECT: direct, REJECT: reject } = proxyRecord;
|
||||
|
||||
let groups: IProxyGroupItem[] = Object.values(proxyRecord).reduce<
|
||||
IProxyGroupItem[]
|
||||
>((acc, each) => {
|
||||
if (each.name !== "GLOBAL" && each.all) {
|
||||
acc.push({
|
||||
...each,
|
||||
all: each.all!.map((item) => generateItem(item)),
|
||||
});
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
if (global?.all) {
|
||||
let globalGroups: IProxyGroupItem[] = global.all.reduce<IProxyGroupItem[]>(
|
||||
(acc, name) => {
|
||||
if (proxyRecord[name]?.all) {
|
||||
acc.push({
|
||||
...proxyRecord[name],
|
||||
all: proxyRecord[name].all!.map((item) => generateItem(item)),
|
||||
});
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
let globalNames = new Set(globalGroups.map((each) => each.name));
|
||||
groups = groups
|
||||
.filter((group) => {
|
||||
return !globalNames.has(group.name);
|
||||
})
|
||||
.concat(globalGroups);
|
||||
}
|
||||
|
||||
const proxies = [direct, reject].concat(
|
||||
Object.values(proxyRecord).filter(
|
||||
(p) => !p.all?.length && p.name !== "DIRECT" && p.name !== "REJECT",
|
||||
),
|
||||
);
|
||||
|
||||
const _global: IProxyGroupItem = {
|
||||
...global,
|
||||
all: global?.all?.map((item) => generateItem(item)) || [],
|
||||
};
|
||||
|
||||
return { global: _global, direct, groups, records: proxyRecord, proxies };
|
||||
};
|
||||
|
||||
// get proxy providers
|
||||
export const getProxyProviders = async () => {
|
||||
const response = await invoke<{
|
||||
providers: Record<string, IProxyProviderItem>;
|
||||
}>("get_providers_proxies");
|
||||
if (!response || !response.providers) {
|
||||
console.warn(
|
||||
"getProxyProviders: Invalid response structure, returning empty object",
|
||||
);
|
||||
return {};
|
||||
}
|
||||
|
||||
const providers = response.providers as Record<string, IProxyProviderItem>;
|
||||
|
||||
return Object.fromEntries(
|
||||
Object.entries(providers).filter(([key, item]) => {
|
||||
const type = item.vehicleType.toLowerCase();
|
||||
return type === "http" || type === "file";
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
export const getRuleProviders = async () => {
|
||||
const instance = await getAxios();
|
||||
const response = await instance.get<any, any>("/providers/rules");
|
||||
|
||||
const providers = (response.providers || {}) as Record<
|
||||
string,
|
||||
IRuleProviderItem
|
||||
>;
|
||||
|
||||
return Object.fromEntries(
|
||||
Object.entries(providers).filter(([key, item]) => {
|
||||
const type = item.vehicleType.toLowerCase();
|
||||
return type === "http" || type === "file";
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
// proxy providers health check
|
||||
export const providerHealthCheck = async (name: string) => {
|
||||
const instance = await getAxios();
|
||||
return instance.get(
|
||||
`/providers/proxies/${encodeURIComponent(name)}/healthcheck`,
|
||||
);
|
||||
};
|
||||
|
||||
export const proxyProviderUpdate = async (name: string) => {
|
||||
const instance = await getAxios();
|
||||
return instance.put(`/providers/proxies/${encodeURIComponent(name)}`);
|
||||
};
|
||||
|
||||
export const ruleProviderUpdate = async (name: string) => {
|
||||
const instance = await getAxios();
|
||||
return instance.put(`/providers/rules/${encodeURIComponent(name)}`);
|
||||
};
|
||||
|
||||
export const getConnections = async () => {
|
||||
const instance = await getAxios();
|
||||
const result = await instance.get("/connections");
|
||||
return result as any as IConnections;
|
||||
};
|
||||
|
||||
// Close specific connection
|
||||
export const deleteConnection = async (id: string) => {
|
||||
const instance = await getAxios();
|
||||
await instance.delete<any, any>(`/connections/${encodeURIComponent(id)}`);
|
||||
};
|
||||
|
||||
// Close all connections
|
||||
export const closeAllConnections = async () => {
|
||||
const instance = await getAxios();
|
||||
await instance.delete("/connections");
|
||||
};
|
||||
|
||||
// Get Group Proxy Delays
|
||||
export const getGroupProxyDelays = async (
|
||||
groupName: string,
|
||||
url?: string,
|
||||
timeout?: number,
|
||||
) => {
|
||||
const params = {
|
||||
timeout: timeout || 10000,
|
||||
url: url || "https://cp.cloudflare.com/generate_204",
|
||||
};
|
||||
|
||||
console.log(
|
||||
`[API] 获取代理组延迟,组: ${groupName}, URL: ${params.url}, 超时: ${params.timeout}ms`,
|
||||
);
|
||||
|
||||
try {
|
||||
const instance = await getAxios();
|
||||
console.log(
|
||||
`[API] 发送HTTP请求: GET /group/${encodeURIComponent(groupName)}/delay`,
|
||||
);
|
||||
|
||||
const result = await instance.get(
|
||||
`/group/${encodeURIComponent(groupName)}/delay`,
|
||||
{ params },
|
||||
);
|
||||
|
||||
console.log(
|
||||
`[API] 获取代理组延迟成功,组: ${groupName}, 结果数量:`,
|
||||
Object.keys(result || {}).length,
|
||||
);
|
||||
return result as any as Record<string, number>;
|
||||
} catch (error) {
|
||||
console.error(`[API] 获取代理组延迟失败,组: ${groupName}`, error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// Is debug enabled
|
||||
export const isDebugEnabled = async () => {
|
||||
try {
|
||||
const instance = await getAxios();
|
||||
await instance.get("/debug/pprof");
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// GC
|
||||
export const gc = async () => {
|
||||
try {
|
||||
const instance = await getAxios();
|
||||
await instance.put("/debug/gc");
|
||||
} catch (error) {
|
||||
console.error(`Error gcing: ${error}`);
|
||||
}
|
||||
};
|
||||
|
||||
// Get current IP and geolocation information (refactored IP detection with service-specific mappings)
|
||||
interface IpInfo {
|
||||
ip: string;
|
||||
|
||||
@@ -94,6 +94,320 @@ export async function patchClashMode(payload: String) {
|
||||
return invoke<void>("patch_clash_mode", { payload });
|
||||
}
|
||||
|
||||
// New IPC-based API functions to replace HTTP API calls
|
||||
export async function getVersion() {
|
||||
return invoke<{
|
||||
premium: boolean;
|
||||
meta?: boolean;
|
||||
version: string;
|
||||
}>("get_clash_version");
|
||||
}
|
||||
|
||||
export async function getClashConfig() {
|
||||
return invoke<IConfigData>("get_clash_config");
|
||||
}
|
||||
|
||||
export async function updateGeoData() {
|
||||
return invoke<void>("update_geo_data");
|
||||
}
|
||||
|
||||
export async function upgradeCore() {
|
||||
return invoke<void>("upgrade_clash_core");
|
||||
}
|
||||
|
||||
export async function getRules() {
|
||||
const response = await invoke<{ rules: IRuleItem[] }>("get_clash_rules");
|
||||
return response?.rules || [];
|
||||
}
|
||||
|
||||
export async function getProxyDelay(
|
||||
name: string,
|
||||
url?: string,
|
||||
timeout?: number,
|
||||
) {
|
||||
return invoke<{ delay: number }>("clash_api_get_proxy_delay", {
|
||||
name,
|
||||
url,
|
||||
timeout: timeout || 10000,
|
||||
});
|
||||
}
|
||||
|
||||
export async function updateProxy(group: string, proxy: string) {
|
||||
return await invoke<void>("update_proxy_choice", { group, proxy });
|
||||
}
|
||||
|
||||
export async function getProxies(): Promise<{
|
||||
global: IProxyGroupItem;
|
||||
direct: IProxyItem;
|
||||
groups: IProxyGroupItem[];
|
||||
records: Record<string, IProxyItem>;
|
||||
proxies: IProxyItem[];
|
||||
}> {
|
||||
const [proxyResponse, providerResponse] = await Promise.all([
|
||||
invoke<{ proxies: Record<string, IProxyItem> }>("get_proxies"),
|
||||
invoke<{ providers: Record<string, IProxyProviderItem> }>(
|
||||
"get_providers_proxies",
|
||||
),
|
||||
]);
|
||||
|
||||
const proxyRecord = proxyResponse.proxies;
|
||||
const providerRecord = providerResponse.providers || {};
|
||||
|
||||
// provider name map
|
||||
const providerMap = Object.fromEntries(
|
||||
Object.entries(providerRecord).flatMap(([provider, item]) =>
|
||||
item.proxies.map((p) => [p.name, { ...p, provider }]),
|
||||
),
|
||||
);
|
||||
|
||||
// compatible with proxy-providers
|
||||
const generateItem = (name: string) => {
|
||||
if (proxyRecord[name]) return proxyRecord[name];
|
||||
if (providerMap[name]) return providerMap[name];
|
||||
return {
|
||||
name,
|
||||
type: "unknown",
|
||||
udp: false,
|
||||
xudp: false,
|
||||
tfo: false,
|
||||
mptcp: false,
|
||||
smux: false,
|
||||
history: [],
|
||||
};
|
||||
};
|
||||
|
||||
const { GLOBAL: global, DIRECT: direct, REJECT: reject } = proxyRecord;
|
||||
|
||||
let groups: IProxyGroupItem[] = Object.values(proxyRecord).reduce<
|
||||
IProxyGroupItem[]
|
||||
>((acc, each) => {
|
||||
if (each.name !== "GLOBAL" && each.all) {
|
||||
acc.push({
|
||||
...each,
|
||||
all: each.all!.map((item) => generateItem(item)),
|
||||
});
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
if (global?.all) {
|
||||
let globalGroups: IProxyGroupItem[] = global.all.reduce<IProxyGroupItem[]>(
|
||||
(acc, name) => {
|
||||
if (proxyRecord[name]?.all) {
|
||||
acc.push({
|
||||
...proxyRecord[name],
|
||||
all: proxyRecord[name].all!.map((item) => generateItem(item)),
|
||||
});
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
let globalNames = new Set(globalGroups.map((each) => each.name));
|
||||
groups = groups
|
||||
.filter((group) => {
|
||||
return !globalNames.has(group.name);
|
||||
})
|
||||
.concat(globalGroups);
|
||||
}
|
||||
|
||||
const proxies = [direct, reject].concat(
|
||||
Object.values(proxyRecord).filter(
|
||||
(p) => !p.all?.length && p.name !== "DIRECT" && p.name !== "REJECT",
|
||||
),
|
||||
);
|
||||
|
||||
const _global: IProxyGroupItem = {
|
||||
...global,
|
||||
all: global?.all?.map((item) => generateItem(item)) || [],
|
||||
};
|
||||
|
||||
return { global: _global, direct, groups, records: proxyRecord, proxies };
|
||||
}
|
||||
|
||||
export async function getProxyProviders() {
|
||||
const response = await invoke<{
|
||||
providers: Record<string, IProxyProviderItem>;
|
||||
}>("get_providers_proxies");
|
||||
if (!response || !response.providers) {
|
||||
console.warn(
|
||||
"getProxyProviders: Invalid response structure, returning empty object",
|
||||
);
|
||||
return {};
|
||||
}
|
||||
|
||||
const providers = response.providers as Record<string, IProxyProviderItem>;
|
||||
|
||||
return Object.fromEntries(
|
||||
Object.entries(providers).filter(([key, item]) => {
|
||||
const type = item.vehicleType.toLowerCase();
|
||||
return type === "http" || type === "file";
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function getRuleProviders() {
|
||||
const response = await invoke<{
|
||||
providers: Record<string, IRuleProviderItem>;
|
||||
}>("get_rule_providers");
|
||||
|
||||
const providers = (response.providers || {}) as Record<
|
||||
string,
|
||||
IRuleProviderItem
|
||||
>;
|
||||
|
||||
return Object.fromEntries(
|
||||
Object.entries(providers).filter(([key, item]) => {
|
||||
const type = item.vehicleType.toLowerCase();
|
||||
return type === "http" || type === "file";
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function providerHealthCheck(name: string) {
|
||||
return invoke<void>("proxy_provider_health_check", { name });
|
||||
}
|
||||
|
||||
export async function proxyProviderUpdate(name: string) {
|
||||
return invoke<void>("update_proxy_provider", { name });
|
||||
}
|
||||
|
||||
export async function ruleProviderUpdate(name: string) {
|
||||
return invoke<void>("update_rule_provider", { name });
|
||||
}
|
||||
|
||||
export async function getConnections() {
|
||||
return invoke<IConnections>("get_clash_connections");
|
||||
}
|
||||
|
||||
export async function deleteConnection(id: string) {
|
||||
return invoke<void>("delete_clash_connection", { id });
|
||||
}
|
||||
|
||||
export async function closeAllConnections() {
|
||||
return invoke<void>("close_all_clash_connections");
|
||||
}
|
||||
|
||||
export async function getGroupProxyDelays(
|
||||
groupName: string,
|
||||
url?: string,
|
||||
timeout?: number,
|
||||
) {
|
||||
return invoke<Record<string, number>>("get_group_proxy_delays", {
|
||||
groupName,
|
||||
url,
|
||||
timeout,
|
||||
});
|
||||
}
|
||||
|
||||
export async function getTrafficData() {
|
||||
// console.log("[Traffic][Service] 开始调用 get_traffic_data");
|
||||
const result = await invoke<ITrafficItem>("get_traffic_data");
|
||||
// console.log("[Traffic][Service] get_traffic_data 返回结果:", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function getMemoryData() {
|
||||
console.log("[Memory][Service] 开始调用 get_memory_data");
|
||||
const result = await invoke<{
|
||||
inuse: number;
|
||||
oslimit?: number;
|
||||
usage_percent?: number;
|
||||
last_updated?: number;
|
||||
}>("get_memory_data");
|
||||
console.log("[Memory][Service] get_memory_data 返回结果:", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function getFormattedTrafficData() {
|
||||
console.log("[Traffic][Service] 开始调用 get_formatted_traffic_data");
|
||||
const result = await invoke<IFormattedTrafficData>(
|
||||
"get_formatted_traffic_data",
|
||||
);
|
||||
console.log(
|
||||
"[Traffic][Service] get_formatted_traffic_data 返回结果:",
|
||||
result,
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function getFormattedMemoryData() {
|
||||
console.log("[Memory][Service] 开始调用 get_formatted_memory_data");
|
||||
const result = await invoke<IFormattedMemoryData>(
|
||||
"get_formatted_memory_data",
|
||||
);
|
||||
console.log("[Memory][Service] get_formatted_memory_data 返回结果:", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function getSystemMonitorOverview() {
|
||||
console.log("[Monitor][Service] 开始调用 get_system_monitor_overview");
|
||||
const result = await invoke<ISystemMonitorOverview>(
|
||||
"get_system_monitor_overview",
|
||||
);
|
||||
console.log(
|
||||
"[Monitor][Service] get_system_monitor_overview 返回结果:",
|
||||
result,
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 带数据验证的安全版本
|
||||
export async function getSystemMonitorOverviewSafe() {
|
||||
// console.log(
|
||||
// "[Monitor][Service] 开始调用安全版本 get_system_monitor_overview",
|
||||
// );
|
||||
try {
|
||||
const result = await invoke<any>("get_system_monitor_overview");
|
||||
// console.log("[Monitor][Service] 原始数据:", result);
|
||||
|
||||
// 导入验证器(动态导入避免循环依赖)
|
||||
const { systemMonitorValidator } = await import("@/utils/data-validator");
|
||||
|
||||
if (systemMonitorValidator.validate(result)) {
|
||||
// console.log("[Monitor][Service] 数据验证通过");
|
||||
return result as ISystemMonitorOverview;
|
||||
} else {
|
||||
// console.warn("[Monitor][Service] 数据验证失败,使用清理后的数据");
|
||||
return systemMonitorValidator.sanitize(result);
|
||||
}
|
||||
} catch (error) {
|
||||
// console.error("[Monitor][Service] API调用失败:", error);
|
||||
// 返回安全的默认值
|
||||
const { systemMonitorValidator } = await import("@/utils/data-validator");
|
||||
return systemMonitorValidator.sanitize(null);
|
||||
}
|
||||
}
|
||||
|
||||
export async function startTrafficService() {
|
||||
console.log("[Traffic][Service] 开始调用 start_traffic_service");
|
||||
try {
|
||||
const result = await invoke<void>("start_traffic_service");
|
||||
console.log("[Traffic][Service] start_traffic_service 调用成功");
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error("[Traffic][Service] start_traffic_service 调用失败:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function stopTrafficService() {
|
||||
console.log("[Traffic][Service] 开始调用 stop_traffic_service");
|
||||
const result = await invoke<void>("stop_traffic_service");
|
||||
console.log("[Traffic][Service] stop_traffic_service 调用成功");
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function isDebugEnabled() {
|
||||
return invoke<boolean>("is_clash_debug_enabled");
|
||||
}
|
||||
|
||||
export async function gc() {
|
||||
return invoke<void>("clash_gc");
|
||||
}
|
||||
|
||||
export async function getVergeConfig() {
|
||||
return invoke<IVergeConfig>("get_verge_config");
|
||||
}
|
||||
@@ -233,7 +547,9 @@ export async function cmdGetProxyDelay(
|
||||
/// 用于profile切换等场景
|
||||
export async function forceRefreshProxies() {
|
||||
console.log("[API] 强制刷新代理缓存");
|
||||
return invoke<any>("force_refresh_proxies");
|
||||
const result = await invoke<any>("force_refresh_proxies");
|
||||
console.log("[API] 代理缓存刷新完成");
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function cmdTestDelay(url: string) {
|
||||
|
||||
58
src/services/types.d.ts
vendored
58
src/services/types.d.ts
vendored
@@ -131,6 +131,63 @@ interface IRuleProviderItem {
|
||||
interface ITrafficItem {
|
||||
up: number;
|
||||
down: number;
|
||||
up_rate?: number;
|
||||
down_rate?: number;
|
||||
last_updated?: number;
|
||||
}
|
||||
|
||||
interface IFormattedTrafficData {
|
||||
up_rate_formatted: string;
|
||||
down_rate_formatted: string;
|
||||
total_up_formatted: string;
|
||||
total_down_formatted: string;
|
||||
is_fresh: boolean;
|
||||
}
|
||||
|
||||
interface IFormattedMemoryData {
|
||||
inuse_formatted: string;
|
||||
oslimit_formatted: string;
|
||||
usage_percent: number;
|
||||
is_fresh: boolean;
|
||||
}
|
||||
|
||||
// 增强的类型安全接口定义,确保所有字段必需
|
||||
interface ISystemMonitorOverview {
|
||||
traffic: {
|
||||
raw: {
|
||||
up: number;
|
||||
down: number;
|
||||
up_rate: number;
|
||||
down_rate: number;
|
||||
};
|
||||
formatted: {
|
||||
up_rate: string;
|
||||
down_rate: string;
|
||||
total_up: string;
|
||||
total_down: string;
|
||||
};
|
||||
is_fresh: boolean;
|
||||
};
|
||||
memory: {
|
||||
raw: {
|
||||
inuse: number;
|
||||
oslimit: number;
|
||||
usage_percent: number;
|
||||
};
|
||||
formatted: {
|
||||
inuse: string;
|
||||
oslimit: string;
|
||||
usage_percent: number;
|
||||
};
|
||||
is_fresh: boolean;
|
||||
};
|
||||
overall_status: "active" | "inactive" | "error" | "unknown";
|
||||
}
|
||||
|
||||
// 类型安全的数据验证器
|
||||
interface ISystemMonitorOverviewValidator {
|
||||
validate(data: any): data is ISystemMonitorOverview;
|
||||
sanitize(data: any): ISystemMonitorOverview;
|
||||
}
|
||||
|
||||
interface ILogItem {
|
||||
@@ -800,6 +857,7 @@ interface IVergeConfig {
|
||||
webdav_password?: string;
|
||||
home_cards?: Record<string, boolean>;
|
||||
enable_hover_jump_navigator?: boolean;
|
||||
enable_external_controller?: boolean;
|
||||
}
|
||||
|
||||
interface IWebDavFile {
|
||||
|
||||
Reference in New Issue
Block a user