Feat: API cache optimize

This commit is contained in:
unitwk 2023-09-01 21:45:46 +08:00
parent e5a04cc759
commit 20cd9fb06d
8 changed files with 88 additions and 27 deletions

6
common/global.d.ts vendored
View File

@ -49,3 +49,9 @@ export interface GlobalInstanceConfig {
openFrpToken?: string;
};
}
export interface PanelResponseProtocol {
data: any;
timestamp: number;
status: number;
}

View File

@ -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",

View File

@ -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: "面板所在主机 CPURAM 百分比",
type: "system"
},
width: 3,

View File

@ -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);
}
}

View File

@ -69,3 +69,10 @@ export const setSettingInfo = useDefineApi<
url: "/api/overview/setting",
method: "PUT"
});
// 获取总览
// 获取设置信息
export const overviewInfo = useDefineApi<any, Settings>({
url: "/api/overview"
});

View 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
};
});

View File

@ -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: "面板所在主机 CPURAM 百分比"
};
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>

View File

@ -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");
};