diff --git a/src/components/connection-item.tsx b/src/components/connection-item.tsx
new file mode 100644
index 0000000..34fa09b
--- /dev/null
+++ b/src/components/connection-item.tsx
@@ -0,0 +1,13 @@
+import { ApiType } from "../services/types";
+
+interface Props {
+ value: ApiType.ConnectionsItem;
+}
+
+const ConnectionItem = (props: Props) => {
+ const { value } = props;
+
+ return
{value.metadata.host || value.metadata.destinationIP}
;
+};
+
+export default ConnectionItem;
diff --git a/src/components/list-item-link.tsx b/src/components/layout-item.tsx
similarity index 94%
rename from src/components/list-item-link.tsx
rename to src/components/layout-item.tsx
index 3e45320..545b36e 100644
--- a/src/components/list-item-link.tsx
+++ b/src/components/layout-item.tsx
@@ -2,7 +2,7 @@ import { alpha, ListItem, ListItemButton, ListItemText } from "@mui/material";
import { useMatch, useResolvedPath, useNavigate } from "react-router-dom";
import type { LinkProps } from "react-router-dom";
-const ListItemLink = (props: LinkProps) => {
+const LayoutItem = (props: LinkProps) => {
const { to, children } = props;
const resolved = useResolvedPath(to);
@@ -41,4 +41,4 @@ const ListItemLink = (props: LinkProps) => {
);
};
-export default ListItemLink;
+export default LayoutItem;
diff --git a/src/components/log-item.tsx b/src/components/log-item.tsx
index 89e6629..5a4da19 100644
--- a/src/components/log-item.tsx
+++ b/src/components/log-item.tsx
@@ -1,6 +1,7 @@
import { styled, Box } from "@mui/material";
+import { ApiType } from "../services/types";
-const LogItem = styled(Box)(({ theme }) => ({
+const Item = styled(Box)(({ theme }) => ({
padding: "8px 0",
margin: "0 12px",
lineHeight: 1.35,
@@ -8,8 +9,7 @@ const LogItem = styled(Box)(({ theme }) => ({
"& .time": {},
"& .type": {
display: "inline-block",
- width: 50,
- margin: "0 4px",
+ padding: "0 6px",
textAlign: "center",
borderRadius: 2,
textTransform: "uppercase",
@@ -18,4 +18,20 @@ const LogItem = styled(Box)(({ theme }) => ({
"& .data": {},
}));
+interface Props {
+ value: ApiType.LogItem;
+}
+
+const LogItem = (props: Props) => {
+ const { value } = props;
+
+ return (
+ -
+ {value.time}
+ {value.type}
+ {value.payload}
+
+ );
+};
+
export default LogItem;
diff --git a/src/components/profile-item.tsx b/src/components/profile-item.tsx
index 1140b62..cbc5e6a 100644
--- a/src/components/profile-item.tsx
+++ b/src/components/profile-item.tsx
@@ -10,7 +10,7 @@ import {
IconButton,
} from "@mui/material";
import { MenuRounded } from "@mui/icons-material";
-import { ProfileItem } from "../services/command";
+import { CmdType } from "../services/types";
import parseTraffic from "../utils/parse-traffic";
import relativeTime from "dayjs/plugin/relativeTime";
@@ -29,7 +29,7 @@ const Wrapper = styled(Box)(({ theme }) => ({
interface Props {
selected: boolean;
- itemData: ProfileItem;
+ itemData: CmdType.ProfileItem;
onClick: () => void;
onUpdate: () => void;
}
diff --git a/src/components/proxy-group.tsx b/src/components/proxy-group.tsx
index bf3bb4e..e20441c 100644
--- a/src/components/proxy-group.tsx
+++ b/src/components/proxy-group.tsx
@@ -20,11 +20,11 @@ import {
NetworkCheckRounded,
CheckCircleOutlineRounded,
} from "@mui/icons-material";
-import services from "../services";
-import type { ProxyItem, ProxyGroupItem } from "../services/proxy";
+import { updateProxy } from "../services/api";
+import { ApiType } from "../services/types";
interface ItemProps {
- proxy: ProxyItem;
+ proxy: ApiType.ProxyItem;
selected: boolean;
onClick?: (name: string) => void;
}
@@ -66,7 +66,7 @@ const Item = ({ proxy, selected, onClick }: ItemProps) => {
};
interface Props {
- group: ProxyGroupItem;
+ group: ApiType.ProxyGroupItem;
}
const ProxyGroup = ({ group }: Props) => {
@@ -85,7 +85,7 @@ const ProxyGroup = ({ group }: Props) => {
const oldValue = now;
try {
setNow(name);
- await services.updateProxy(group.name, name);
+ await updateProxy(group.name, name);
} catch {
setNow(oldValue);
// Todo
diff --git a/src/components/setting-clash.tsx b/src/components/setting-clash.tsx
index 72092c7..9b6fdcf 100644
--- a/src/components/setting-clash.tsx
+++ b/src/components/setting-clash.tsx
@@ -8,8 +8,9 @@ import {
Select,
MenuItem,
} from "@mui/material";
-import { ConfigType, getClashConfig, updateConfigs } from "../services/common";
-import { patchClashConfig } from "../services/command";
+import { getClashConfig, updateConfigs } from "../services/api";
+import { patchClashConfig } from "../services/cmds";
+import { ApiType } from "../services/types";
import GuardState from "./guard-state";
import SettingItem from "./setting-item";
@@ -30,11 +31,11 @@ const SettingClash = ({ onError }: Props) => {
const onSwitchFormat = (_e: any, value: boolean) => value;
- const onChangeData = (patch: Partial) => {
+ const onChangeData = (patch: Partial) => {
mutate("getClashConfig", { ...clashConfig, ...patch }, false);
};
- const onUpdateData = async (patch: Partial) => {
+ const onUpdateData = async (patch: Partial) => {
await updateConfigs(patch);
await patchClashConfig(patch);
};
diff --git a/src/components/setting-verge.tsx b/src/components/setting-verge.tsx
index ccfecdc..2f9fedb 100644
--- a/src/components/setting-verge.tsx
+++ b/src/components/setting-verge.tsx
@@ -4,8 +4,8 @@ import {
getVergeConfig,
patchVergeConfig,
setSysProxy,
- VergeConfig,
-} from "../services/command";
+} from "../services/cmds";
+import { CmdType } from "../services/types";
import GuardState from "./guard-state";
import SettingItem from "./setting-item";
import PaletteSwitch from "./palette-switch";
@@ -26,7 +26,7 @@ const SettingVerge = ({ onError }: Props) => {
const onSwitchFormat = (_e: any, value: boolean) => value;
- const onChangeData = (patch: Partial) => {
+ const onChangeData = (patch: Partial) => {
mutate("getVergeConfig", { ...vergeConfig, ...patch }, false);
};
diff --git a/src/components/traffic.tsx b/src/components/traffic.tsx
index 2786306..caee800 100644
--- a/src/components/traffic.tsx
+++ b/src/components/traffic.tsx
@@ -1,32 +1,22 @@
-import { CancelTokenSource } from "axios";
import { useEffect, useState } from "react";
import { Box, Typography } from "@mui/material";
import { ArrowDownward, ArrowUpward } from "@mui/icons-material";
+import { getInfomation } from "../services/api";
+import { ApiType } from "../services/types";
import parseTraffic from "../utils/parse-traffic";
-import services from "../services";
const Traffic = () => {
const [traffic, setTraffic] = useState({ up: 0, down: 0 });
useEffect(() => {
- let timer: any = null;
- let source: CancelTokenSource | null = null;
+ const { server, secret } = getInfomation();
+ const ws = new WebSocket(`ws://${server}/traffic?token=${secret}`);
- async function onTraffic() {
- timer = null;
- try {
- source = await services.getTraffic(setTraffic);
- } catch {
- timer = setTimeout(onTraffic, 500);
- }
- }
+ ws.addEventListener("message", (event) => {
+ setTraffic(JSON.parse(event.data) as ApiType.TrafficItem);
+ });
- onTraffic();
-
- return () => {
- if (timer) clearTimeout(timer);
- source?.cancel();
- };
+ return () => ws.close();
}, []);
const [up, upUnit] = parseTraffic(traffic.up);
diff --git a/src/pages/_layout.tsx b/src/pages/_layout.tsx
index 72a61f2..1939610 100644
--- a/src/pages/_layout.tsx
+++ b/src/pages/_layout.tsx
@@ -4,7 +4,8 @@ import { Route, Routes } from "react-router-dom";
import { useRecoilState } from "recoil";
import { createTheme, List, Paper, ThemeProvider } from "@mui/material";
import { atomPaletteMode } from "../states/setting";
-import { getVergeConfig } from "../services/command";
+import { getClashInfo, getVergeConfig } from "../services/cmds";
+import { initAxios } from "../services/api";
import LogoSvg from "../assets/image/logo.svg";
import LogPage from "./log";
import HomePage from "./home";
@@ -12,7 +13,7 @@ import ProfilePage from "./profile";
import ProxyPage from "./proxy";
import SettingPage from "./setting";
import ConnectionsPage from "./connections";
-import ListItemLink from "../components/list-item-link";
+import LayoutItem from "../components/layout-item";
import Traffic from "../components/traffic";
const routers = [
@@ -42,6 +43,12 @@ const Layout = () => {
const [mode, setMode] = useRecoilState(atomPaletteMode);
const { data: vergeConfig } = useSWR("getVergeConfig", getVergeConfig);
+ useEffect(() => {
+ getClashInfo()
+ .then((result) => initAxios(result?.controller ?? {}))
+ .catch(() => console.error("can not initialize clash verge"));
+ }, []);
+
useEffect(() => {
setMode(vergeConfig?.theme_mode ?? "light");
}, [vergeConfig?.theme_mode]);
@@ -95,9 +102,9 @@ const Layout = () => {
{routers.map((router) => (
-
+
{router.label}
-
+
))}
diff --git a/src/pages/connections.tsx b/src/pages/connections.tsx
index 2bd1695..8a7b534 100644
--- a/src/pages/connections.tsx
+++ b/src/pages/connections.tsx
@@ -1,21 +1,45 @@
-import { useEffect } from "react";
-import { Box, Typography } from "@mui/material";
-import services from "../services";
+import { useEffect, useState } from "react";
+import { Box, Paper, Typography } from "@mui/material";
+import { Virtuoso } from "react-virtuoso";
+import { getInfomation } from "../services/api";
+import { ApiType } from "../services/types";
+import ConnectionItem from "../components/connection-item";
const ConnectionsPage = () => {
- useEffect(() => {
- const sourcePromise = services.getLogs(console.log);
+ const initConn = { uploadTotal: 0, downloadTotal: 0, connections: [] };
+ const [conn, setConn] = useState(initConn);
- return () => {
- sourcePromise.then((src) => src.cancel());
- };
+ useEffect(() => {
+ const { server, secret } = getInfomation();
+ const ws = new WebSocket(`ws://${server}/connections?token=${secret}`);
+
+ ws.addEventListener("message", (event) => {
+ const data = JSON.parse(event.data) as ApiType.Connections;
+ setConn(data);
+ });
+
+ return () => ws.close();
}, []);
return (
-
+
Connections
+
+
+ }
+ />
+
);
};
diff --git a/src/pages/log.tsx b/src/pages/log.tsx
index cf26566..f10a58c 100644
--- a/src/pages/log.tsx
+++ b/src/pages/log.tsx
@@ -2,24 +2,26 @@ import dayjs from "dayjs";
import { useEffect, useRef, useState } from "react";
import { Box, Button, Paper, Typography } from "@mui/material";
import { Virtuoso } from "react-virtuoso";
+import { ApiType } from "../services/types";
+import { getInfomation } from "../services/api";
import LogItem from "../components/log-item";
-import services from "../services";
-let logCache: any[] = [];
+let logCache: ApiType.LogItem[] = [];
const LogPage = () => {
- const [logData, setLogData] = useState(logCache);
+ const [logData, setLogData] = useState(logCache);
useEffect(() => {
- const sourcePromise = services.getLogs((t) => {
+ const info = getInfomation();
+ const ws = new WebSocket(`ws://${info.server}/logs?token=${info.secret}`);
+
+ ws.addEventListener("message", (event) => {
+ const data = JSON.parse(event.data) as ApiType.LogItem;
const time = dayjs().format("MM-DD HH:mm:ss");
- const item = { ...t, time };
- setLogData((l) => (logCache = [...l, item]));
+ setLogData((l) => (logCache = [...l, { ...data, time }]));
});
- return () => {
- sourcePromise.then((src) => src.cancel("cancel"));
- };
+ return () => ws.close();
}, []);
return (
@@ -52,15 +54,7 @@ const LogPage = () => {
{
- return (
-
- {logItem.time}
- {logItem.type}
- {logItem.payload}
-
- );
- }}
+ itemContent={(index, item) => }
followOutput={"smooth"}
/>
diff --git a/src/pages/profile.tsx b/src/pages/profile.tsx
index 0e23174..8cac0c4 100644
--- a/src/pages/profile.tsx
+++ b/src/pages/profile.tsx
@@ -1,13 +1,13 @@
import { useRef, useState } from "react";
import useSWR, { useSWRConfig } from "swr";
import { Box, Button, Grid, TextField, Typography } from "@mui/material";
-import services from "../services";
import {
getProfiles,
importProfile,
putProfiles,
updateProfile,
-} from "../services/command";
+} from "../services/cmds";
+import { getProxies } from "../services/api";
import ProfileItemComp from "../components/profile-item";
import useNotice from "../utils/use-notice";
import noop from "../utils/noop";
@@ -44,7 +44,7 @@ const ProfilePage = () => {
putProfiles(index)
.then(() => {
mutate("getProfiles", { ...profiles, current: index }, true);
- mutate("getProxies", services.getProxies());
+ mutate("getProxies", getProxies());
})
.catch((err) => {
console.error(err);
diff --git a/src/pages/proxy.tsx b/src/pages/proxy.tsx
index defaa07..98a236f 100644
--- a/src/pages/proxy.tsx
+++ b/src/pages/proxy.tsx
@@ -1,10 +1,10 @@
import useSWR from "swr";
import { Box, List, Paper, Typography } from "@mui/material";
-import services from "../services";
+import { getProxies } from "../services/api";
import ProxyGroup from "../components/proxy-group";
const ProxyPage = () => {
- const { data } = useSWR("getProxies", services.getProxies);
+ const { data } = useSWR("getProxies", getProxies);
const { groups = [] } = data ?? {};
return (
diff --git a/src/services/api.ts b/src/services/api.ts
new file mode 100644
index 0000000..f4cdb5c
--- /dev/null
+++ b/src/services/api.ts
@@ -0,0 +1,87 @@
+import axios, { AxiosInstance } from "axios";
+import { ApiType } from "./types";
+
+let axiosIns: AxiosInstance = null!;
+let server = "127.0.0.1:9090";
+let secret = "";
+
+type Callback = (data: T) => void;
+
+/// initialize some infomation
+export function initAxios(info: { server?: string; secret?: string }) {
+ if (info.server) server = info.server;
+ if (info.secret) secret = info.secret;
+
+ axiosIns = axios.create({
+ baseURL: `http://${server}`,
+ headers: secret ? { Authorization: `Bearer ${secret}` } : {},
+ });
+ axiosIns.interceptors.response.use((r) => r.data);
+}
+
+/// get infomation
+export function getInfomation() {
+ return { server, secret };
+}
+
+/// Get Version
+export async function getVersion() {
+ return axiosIns.get("/version") as Promise<{
+ premium: boolean;
+ version: string;
+ }>;
+}
+
+/// Get current base configs
+export async function getClashConfig() {
+ return axiosIns.get("/configs") as Promise;
+}
+
+/// Update current configs
+export async function updateConfigs(config: Partial) {
+ return axiosIns.patch("/configs", config);
+}
+
+/// Get current rules
+export async function getRules() {
+ return axiosIns.get("/rules") as Promise;
+}
+
+/// Update the Proxy Choose
+export async function updateProxy(group: string, proxy: string) {
+ return axiosIns.put(`/proxies/${group}`, { name: proxy });
+}
+
+/// Get the Proxy infomation
+export async function getProxies() {
+ const response = await axiosIns.get("/proxies");
+ const proxies = (response?.proxies ?? {}) as Record<
+ string,
+ ApiType.ProxyItem
+ >;
+
+ const global = proxies["GLOBAL"];
+ const order = global?.all;
+
+ let groups: ApiType.ProxyGroupItem[] = [];
+
+ if (order) {
+ groups = order
+ .filter((name) => proxies[name]?.all)
+ .map((name) => proxies[name])
+ .map((each) => ({
+ ...each,
+ all: each.all!.map((item) => proxies[item]),
+ }));
+ } else {
+ groups = Object.values(proxies)
+ .filter((each) => each.name !== "GLOBAL" && each.all)
+ .map((each) => ({
+ ...each,
+ all: each.all!.map((item) => proxies[item]),
+ }));
+ groups.sort((a, b) => b.name.localeCompare(a.name));
+ }
+
+ return { global, groups, proxies };
+}
diff --git a/src/services/base.ts b/src/services/base.ts
deleted file mode 100644
index 952d36e..0000000
--- a/src/services/base.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import axios, { AxiosInstance } from "axios";
-import { getClashInfo } from "./command";
-
-let axiosIns: AxiosInstance | null = null;
-
-export async function getAxios() {
- if (axiosIns) return axiosIns;
-
- let server = "127.0.0.1:9090";
- let secret = "";
-
- try {
- const info = await getClashInfo();
- const { server: server_, secret: secret_ } = info?.controller ?? {};
- if (server_) server = server_;
- if (secret_) secret = secret_;
- } catch {}
-
- axiosIns = axios.create({
- baseURL: `http://${server}`,
- headers: secret ? { Authorization: `Bearer ${secret}` } : {},
- });
- axiosIns.interceptors.response.use((r) => r.data);
-
- return axiosIns;
-}
diff --git a/src/services/cmds.ts b/src/services/cmds.ts
new file mode 100644
index 0000000..4ca2495
--- /dev/null
+++ b/src/services/cmds.ts
@@ -0,0 +1,49 @@
+import { invoke } from "@tauri-apps/api/tauri";
+import { ApiType, CmdType } from "./types";
+
+export async function restartSidecar() {
+ return invoke("restart_sidecar");
+}
+
+export async function getClashInfo() {
+ return invoke("get_clash_info");
+}
+
+export async function patchClashConfig(payload: Partial) {
+ return invoke("patch_clash_config", { payload });
+}
+
+export async function importProfile(url: string) {
+ return invoke("import_profile", { url });
+}
+
+export async function updateProfile(index: number) {
+ return invoke("update_profile", { index });
+}
+
+export async function getProfiles() {
+ return (await invoke("get_profiles")) ?? {};
+}
+
+export async function setProfiles(
+ current: number,
+ profile: CmdType.ProfileItem
+) {
+ return invoke("set_profiles", { current, profile });
+}
+
+export async function putProfiles(current: number) {
+ return invoke("put_profiles", { current });
+}
+
+export async function setSysProxy(enable: boolean) {
+ return invoke("set_sys_proxy", { enable });
+}
+
+export async function getVergeConfig() {
+ return invoke("get_verge_config");
+}
+
+export async function patchVergeConfig(payload: CmdType.VergeConfig) {
+ return invoke("patch_verge_config", { payload });
+}
diff --git a/src/services/command.ts b/src/services/command.ts
deleted file mode 100644
index d6d3c36..0000000
--- a/src/services/command.ts
+++ /dev/null
@@ -1,78 +0,0 @@
-import { invoke } from "@tauri-apps/api/tauri";
-import { ConfigType } from "./common";
-
-export async function restartSidecar() {
- return invoke("restart_sidecar");
-}
-
-export interface ClashInfo {
- status: string;
- controller?: { server?: string; secret?: string };
- message?: string;
-}
-
-export async function getClashInfo() {
- return invoke("get_clash_info");
-}
-
-export async function patchClashConfig(payload: Partial) {
- return invoke("patch_clash_config", { payload });
-}
-
-export async function importProfile(url: string) {
- return invoke("import_profile", { url });
-}
-
-export async function updateProfile(index: number) {
- return invoke("update_profile", { index });
-}
-
-export interface ProfileItem {
- name?: string;
- file?: string;
- mode?: string;
- url?: string;
- updated?: number;
- selected?: { name?: string; now?: string }[];
- extra?: {
- upload: number;
- download: number;
- total: number;
- expire: number;
- };
-}
-
-export interface ProfilesConfig {
- current?: number;
- items?: ProfileItem[];
-}
-
-export async function getProfiles() {
- return (await invoke("get_profiles")) ?? {};
-}
-
-export async function setProfiles(current: number, profile: ProfileItem) {
- return invoke("set_profiles", { current, profile });
-}
-
-export async function putProfiles(current: number) {
- return invoke("put_profiles", { current });
-}
-
-export async function setSysProxy(enable: boolean) {
- return invoke("set_sys_proxy", { enable });
-}
-
-export interface VergeConfig {
- theme_mode?: "light" | "dark";
- enable_self_startup?: boolean;
- enable_system_proxy?: boolean;
-}
-
-export async function getVergeConfig() {
- return invoke("get_verge_config");
-}
-
-export async function patchVergeConfig(payload: VergeConfig) {
- return invoke("patch_verge_config", { payload });
-}
diff --git a/src/services/common.ts b/src/services/common.ts
deleted file mode 100644
index 604a85e..0000000
--- a/src/services/common.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-import axios from "axios";
-import { getAxios } from "./base";
-
-/// Get Version
-export async function getVersion() {
- return (await getAxios()).get("/version") as Promise<{
- premium: boolean;
- version: string;
- }>;
-}
-
-export interface ConfigType {
- port: number;
- mode: string;
- ipv6: boolean;
- "socket-port": number;
- "allow-lan": boolean;
- "log-level": string;
- "mixed-port": number;
- "redir-port": number;
- "socks-port": number;
- "tproxy-port": number;
-}
-
-/// Get current base configs
-export async function getClashConfig() {
- return (await getAxios()).get("/configs") as Promise;
-}
-
-/// Update current configs
-export async function updateConfigs(config: Partial) {
- return (await getAxios()).patch("/configs", config);
-}
-
-interface RuleItem {
- type: string;
- payload: string;
- proxy: string;
-}
-
-/// Get current rules
-export async function getRules() {
- return (await getAxios()).get("/rules") as Promise;
-}
-
-/// Get logs stream
-export async function getLogs(callback: (t: any) => void) {
- const source = axios.CancelToken.source();
-
- (await getAxios()).get("/logs", {
- cancelToken: source.token,
- onDownloadProgress: (progressEvent) => {
- const data = progressEvent.currentTarget.response || "";
- const lastData = data.slice(data.trim().lastIndexOf("\n") + 1);
- callback(JSON.parse(lastData));
- },
- });
-
- return source;
-}
diff --git a/src/services/index.ts b/src/services/index.ts
deleted file mode 100644
index 434a9d3..0000000
--- a/src/services/index.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import * as common from "./common";
-import * as proxy from "./proxy";
-import * as traffic from "./traffic";
-
-export default {
- ...common,
- ...proxy,
- ...traffic,
-};
diff --git a/src/services/proxy.ts b/src/services/proxy.ts
deleted file mode 100644
index 1f29ac9..0000000
--- a/src/services/proxy.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-import { getAxios } from "./base";
-
-export interface ProxyItem {
- name: string;
- type: string;
- udp: boolean;
- history: {
- time: string;
- delay: number;
- }[];
- all?: string[];
- now?: string;
-}
-
-export type ProxyGroupItem = Omit & {
- all: ProxyItem[];
-};
-
-/// Get the Proxy infomation
-export async function getProxies() {
- const axiosIns = await getAxios();
- const response = await axiosIns.get("/proxies");
- const proxies = (response?.proxies ?? {}) as Record;
-
- const global = proxies["GLOBAL"];
- const order = global?.all;
-
- let groups: ProxyGroupItem[] = [];
-
- if (order) {
- groups = order
- .filter((name) => proxies[name]?.all)
- .map((name) => proxies[name])
- .map((each) => ({
- ...each,
- all: each.all!.map((item) => proxies[item]),
- }));
- } else {
- groups = Object.values(proxies)
- .filter((each) => each.name !== "GLOBAL" && each.all)
- .map((each) => ({
- ...each,
- all: each.all!.map((item) => proxies[item]),
- }));
- groups.sort((a, b) => b.name.localeCompare(a.name));
- }
-
- return { global, groups, proxies };
-}
-
-/// Update the Proxy Choose
-export async function updateProxy(group: string, proxy: string) {
- return (await getAxios()).put(`/proxies/${group}`, { name: proxy });
-}
diff --git a/src/services/traffic.ts b/src/services/traffic.ts
deleted file mode 100644
index a4c760f..0000000
--- a/src/services/traffic.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import axios from "axios";
-import { getAxios } from "./base";
-
-export interface TrafficData {
- up: number;
- down: number;
-}
-
-/// Get the traffic stream
-export async function getTraffic(callback: (data: TrafficData) => void) {
- const source = axios.CancelToken.source();
-
- (await getAxios()).get("/traffic", {
- cancelToken: source.token,
- onDownloadProgress: (progressEvent) => {
- const data = progressEvent.currentTarget.response || "";
- const lastData = data.slice(data.trim().lastIndexOf("\n") + 1);
-
- if (!lastData) callback({ up: 0, down: 0 });
- try {
- callback(JSON.parse(lastData) as TrafficData);
- } catch {
- callback({ up: 0, down: 0 });
- }
- },
- });
-
- return source;
-}
diff --git a/src/services/types.ts b/src/services/types.ts
new file mode 100644
index 0000000..3544c42
--- /dev/null
+++ b/src/services/types.ts
@@ -0,0 +1,115 @@
+/**
+ * Some interface for clash api
+ */
+export namespace ApiType {
+ export interface ConfigData {
+ port: number;
+ mode: string;
+ ipv6: boolean;
+ "socket-port": number;
+ "allow-lan": boolean;
+ "log-level": string;
+ "mixed-port": number;
+ "redir-port": number;
+ "socks-port": number;
+ "tproxy-port": number;
+ }
+
+ export interface RuleItem {
+ type: string;
+ payload: string;
+ proxy: string;
+ }
+
+ export interface ProxyItem {
+ name: string;
+ type: string;
+ udp: boolean;
+ history: {
+ time: string;
+ delay: number;
+ }[];
+ all?: string[];
+ now?: string;
+ }
+
+ export type ProxyGroupItem = Omit & {
+ all: ProxyItem[];
+ };
+
+ export interface TrafficItem {
+ up: number;
+ down: number;
+ }
+
+ export interface LogItem {
+ type: string;
+ time?: string;
+ payload: string;
+ }
+
+ export interface ConnectionsItem {
+ id: string;
+ metadata: {
+ network: string;
+ type: string;
+ host: string;
+ sourceIP: string;
+ sourcePort: string;
+ destinationPort: string;
+ destinationIP?: string;
+ };
+ upload: number;
+ download: number;
+ start: string;
+ chains: string[];
+ rule: string;
+ rulePayload: string;
+ }
+
+ export interface Connections {
+ downloadTotal: number;
+ uploadTotal: number;
+ connections: ConnectionsItem[];
+ }
+}
+
+/**
+ * Some interface for command
+ */
+export namespace CmdType {
+ export interface ClashInfo {
+ status: string;
+ controller?: { server?: string; secret?: string };
+ message?: string;
+ }
+
+ export interface ProfileItem {
+ name?: string;
+ file?: string;
+ mode?: string;
+ url?: string;
+ updated?: number;
+ selected?: {
+ name?: string;
+ now?: string;
+ }[];
+ extra?: {
+ upload: number;
+ download: number;
+ total: number;
+ expire: number;
+ };
+ }
+
+ export interface ProfilesConfig {
+ current?: number;
+ items?: ProfileItem[];
+ }
+
+ export interface VergeConfig {
+ theme_mode?: "light" | "dark";
+ enable_self_startup?: boolean;
+ enable_system_proxy?: boolean;
+ }
+}