mirror of
https://github.com/MCSManager/MCSManager.git
synced 2025-04-06 17:10:29 +08:00
Feat: API cache optimize
This commit is contained in:
parent
e5a04cc759
commit
20cd9fb06d
6
common/global.d.ts
vendored
6
common/global.d.ts
vendored
@ -49,3 +49,9 @@ export interface GlobalInstanceConfig {
|
||||
openFrpToken?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface PanelResponseProtocol {
|
||||
data: any;
|
||||
timestamp: number;
|
||||
status: number;
|
||||
}
|
||||
|
14
frontend/package-lock.json
generated
14
frontend/package-lock.json
generated
@ -9042,14 +9042,6 @@
|
||||
"xterm": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/xterm-addon-web-links": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/xterm-addon-web-links/-/xterm-addon-web-links-0.4.0.tgz",
|
||||
"integrity": "sha512-xv8GeiINmx0zENO9hf5k+5bnkaE8mRzF+OBAr9WeFq2eLaQSudioQSiT34M1ofKbzcdjSsKiZm19Rw3i4eXamg==",
|
||||
"peerDependencies": {
|
||||
"xterm": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/yallist": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
||||
@ -15411,12 +15403,6 @@
|
||||
"integrity": "sha512-DsS9fqhXHacEmsPxBJZvfj2la30Iz9xk+UKjhQgnYNkrUIN5CYLbw7WEfz117c7+S86S/tpHPfvNxJsF5/G8wQ==",
|
||||
"requires": {}
|
||||
},
|
||||
"xterm-addon-web-links": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/xterm-addon-web-links/-/xterm-addon-web-links-0.4.0.tgz",
|
||||
"integrity": "sha512-xv8GeiINmx0zENO9hf5k+5bnkaE8mRzF+OBAr9WeFq2eLaQSudioQSiT34M1ofKbzcdjSsKiZm19Rw3i4eXamg==",
|
||||
"requires": {}
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
||||
|
@ -28,7 +28,6 @@ export const ORIGIN_LAYOUT_CONFIG: PageLayoutConfig[] = [
|
||||
type: "StatusBlock",
|
||||
title: t("节点在线数1"),
|
||||
meta: {
|
||||
title: "在线节点 / 总节点",
|
||||
type: "node"
|
||||
},
|
||||
width: 3,
|
||||
@ -40,7 +39,6 @@ export const ORIGIN_LAYOUT_CONFIG: PageLayoutConfig[] = [
|
||||
type: "StatusBlock",
|
||||
title: t("实例运行状态"),
|
||||
meta: {
|
||||
title: "正在运行数 / 全部实例总数",
|
||||
type: "instance"
|
||||
},
|
||||
width: 3,
|
||||
@ -52,7 +50,6 @@ export const ORIGIN_LAYOUT_CONFIG: PageLayoutConfig[] = [
|
||||
type: "StatusBlock",
|
||||
title: t("面板登录次数"),
|
||||
meta: {
|
||||
title: "登录失败次数 : 登录成功次数",
|
||||
type: "users"
|
||||
},
|
||||
width: 3,
|
||||
@ -64,7 +61,6 @@ export const ORIGIN_LAYOUT_CONFIG: PageLayoutConfig[] = [
|
||||
type: "StatusBlock",
|
||||
title: t("系统资源信息"),
|
||||
meta: {
|
||||
title: "面板所在主机 CPU,RAM 百分比",
|
||||
type: "system"
|
||||
},
|
||||
width: 3,
|
||||
|
@ -1,5 +1,6 @@
|
||||
import type { PanelResponseProtocol } from "./../../../common/global.d";
|
||||
import { useAppStateStore } from "@/stores/useAppStateStore";
|
||||
import type { AxiosRequestConfig } from "axios";
|
||||
import type { AxiosError, AxiosRequestConfig } from "axios";
|
||||
import axios from "axios";
|
||||
import EventEmitter from "events";
|
||||
import _ from "lodash";
|
||||
@ -15,11 +16,25 @@ axios.interceptors.request.use(async (config) => {
|
||||
export interface RequestConfig extends AxiosRequestConfig {
|
||||
forceRequest?: boolean;
|
||||
}
|
||||
interface ResponseDataRecord {
|
||||
timestamp: number;
|
||||
data: any;
|
||||
}
|
||||
|
||||
class ApiService {
|
||||
private readonly event = new EventEmitter();
|
||||
private readonly responseMap = new Map<string, ResponseDataRecord>();
|
||||
private readonly RESPONSE_CACHE_TIME = 1000 * 2;
|
||||
private readonly REQUEST_CACHE_TIME = 100;
|
||||
|
||||
public async subscribe<T>(config: RequestConfig): Promise<T | undefined> {
|
||||
// filter and clean up expired cache tables
|
||||
this.responseMap.forEach((value, key) => {
|
||||
if (value.timestamp + this.RESPONSE_CACHE_TIME < Date.now()) {
|
||||
this.responseMap.delete(key);
|
||||
}
|
||||
});
|
||||
|
||||
const reqId = encodeURIComponent(
|
||||
[
|
||||
String(config.method),
|
||||
@ -47,18 +62,46 @@ class ApiService {
|
||||
|
||||
private async sendRequest(reqId: string, config: AxiosRequestConfig) {
|
||||
try {
|
||||
console.debug(`[ApiService] Request: ${config.url} \n Full AxiosRequestConfig:`, config);
|
||||
const startTime = Date.now();
|
||||
|
||||
if (this.responseMap.has(reqId)) {
|
||||
const cache = this.responseMap.get(reqId) as ResponseDataRecord;
|
||||
if (cache.timestamp + this.RESPONSE_CACHE_TIME > Date.now()) {
|
||||
return this.event.emit(reqId, cache.data);
|
||||
}
|
||||
}
|
||||
|
||||
console.debug(`[ApiService] Request: ${config.url} \n Full AxiosRequestConfig:`, config);
|
||||
const result = await axios(config);
|
||||
const endTime = Date.now();
|
||||
const reqSpeed = endTime - startTime;
|
||||
const INV = 100;
|
||||
if (reqSpeed < INV) await this.wait(INV - reqSpeed);
|
||||
if (reqSpeed < this.REQUEST_CACHE_TIME) await this.wait(this.REQUEST_CACHE_TIME - reqSpeed);
|
||||
let realData = result.data;
|
||||
if (realData.data) realData = realData.data;
|
||||
|
||||
this.responseMap.set(reqId, {
|
||||
timestamp: Date.now(),
|
||||
data: realData
|
||||
});
|
||||
|
||||
console.debug("请求响应缓存表长度:", this.responseMap.size);
|
||||
|
||||
this.event.emit(reqId, realData);
|
||||
} catch (error) {
|
||||
this.event.emit(reqId, error);
|
||||
} catch (error: AxiosError | Error | any) {
|
||||
console.error("Request Error:", error);
|
||||
const axiosErr = error as AxiosError;
|
||||
const otherErr = error as Error | any;
|
||||
if (axiosErr?.response?.data) {
|
||||
const protocol = axiosErr?.response?.data as PanelResponseProtocol;
|
||||
if (protocol.data && protocol.status !== 200) {
|
||||
throw new Error(String(protocol.data));
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
throw new Error(otherErr?.message ? otherErr?.message : String(otherErr));
|
||||
} finally {
|
||||
this.event.emit(reqId, undefined);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,3 +69,10 @@ export const setSettingInfo = useDefineApi<
|
||||
url: "/api/overview/setting",
|
||||
method: "PUT"
|
||||
});
|
||||
|
||||
// 获取总览
|
||||
|
||||
// 获取设置信息
|
||||
export const overviewInfo = useDefineApi<any, Settings>({
|
||||
url: "/api/overview"
|
||||
});
|
||||
|
11
frontend/src/services/overviewService.ts
Normal file
11
frontend/src/services/overviewService.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { createGlobalState } from "@vueuse/core";
|
||||
import { overviewInfo } from "./apis";
|
||||
import { onMounted } from "vue";
|
||||
|
||||
export const useAppToolsStore = createGlobalState(() => {
|
||||
const { execute, state } = overviewInfo();
|
||||
|
||||
return {
|
||||
overviewData: state
|
||||
};
|
||||
});
|
@ -1,4 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { useLayoutCardTools } from "@/hooks/useCardTools";
|
||||
import { t } from "@/lang/i18n";
|
||||
import type { LayoutCard } from "@/types";
|
||||
|
||||
@ -6,7 +7,18 @@ const props = defineProps<{
|
||||
card: LayoutCard;
|
||||
}>();
|
||||
|
||||
const { title } = props.card.meta ?? {};
|
||||
const { getMetaValue, setMetaValue } = useLayoutCardTools(props.card);
|
||||
|
||||
const type = getMetaValue<string>("type");
|
||||
|
||||
const subTitleMap: Record<string, string> = {
|
||||
node: "在线节点 / 总节点",
|
||||
instance: "正在运行数 / 全部实例总数",
|
||||
users: "登录失败次数 : 登录成功次数",
|
||||
system: "面板所在主机 CPU,RAM 百分比"
|
||||
};
|
||||
|
||||
const subTitle = subTitleMap[type] || "";
|
||||
|
||||
const value = "10/11";
|
||||
</script>
|
||||
@ -16,7 +28,7 @@ const value = "10/11";
|
||||
<template #title>{{ card.title }}</template>
|
||||
<template #body>
|
||||
<a-typography-text class="color-info">
|
||||
{{ title }}
|
||||
{{ subTitle }}
|
||||
</a-typography-text>
|
||||
|
||||
<div class="value">{{ value }}</div>
|
||||
|
@ -96,7 +96,7 @@ const handleSendCommand = () => {
|
||||
const initTerminal = () => {
|
||||
const dom = document.getElementById(terminalDomId.value);
|
||||
if (dom) {
|
||||
initTerminalWindow(dom);
|
||||
return initTerminalWindow(dom);
|
||||
}
|
||||
throw new Error("init terminal failed");
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user