From 9a6dade0096cd1cc547b0c266ae8d58322d64844 Mon Sep 17 00:00:00 2001 From: Eric Date: Wed, 16 Oct 2024 16:33:41 +0800 Subject: [PATCH 1/7] perf: update web sz --- ui/src/hooks/useZsentry.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ui/src/hooks/useZsentry.ts b/ui/src/hooks/useZsentry.ts index d3594812..7fb5adf9 100644 --- a/ui/src/hooks/useZsentry.ts +++ b/ui/src/hooks/useZsentry.ts @@ -181,6 +181,7 @@ export const useSentry = (lastSendTime?: Ref, t?: any): IUseSentry => { * @param terminal */ const handleReceiveSession = (zsession: ZmodemSession, terminal: Terminal) => { + zmodeSession.value = zsession; zsession.on('offer', (xfer: ZmodemTransfer) => { const buffer: Uint8Array[] = []; const detail = xfer.get_details(); @@ -208,7 +209,9 @@ export const useSentry = (lastSendTime?: Ref, t?: any): IUseSentry => { terminal.write('\r\n'); - if (zmodeSession.value) zmodeSession.value.abort(); + if (zmodeSession.value){ + zmodeSession.value.abort(); + } }) .catch((e: Error) => { message.error(`Error: ${e}`); From 46518163940fcd9aa69e69cb224b8076138b0c0e Mon Sep 17 00:00:00 2001 From: zhaojisen <1301338853@qq.com> Date: Wed, 16 Oct 2024 18:14:55 +0800 Subject: [PATCH 2/7] fixed: Fixed issues with termianl not adapting --- ui/package.json | 1 + ui/src/hooks/helper/index.ts | 2 ++ ui/src/hooks/useTerminal.ts | 17 ++++++++++++---- ui/src/hooks/useZsentry.ts | 2 +- ui/src/style/reset.scss | 2 +- ui/src/views/Connection/index.vue | 32 +++++++++++++++---------------- ui/yarn.lock | 5 +++++ 7 files changed, 39 insertions(+), 22 deletions(-) diff --git a/ui/package.json b/ui/package.json index a1ffb00f..e1af205a 100644 --- a/ui/package.json +++ b/ui/package.json @@ -14,6 +14,7 @@ "@vueuse/core": "^10.11.0", "@xterm/addon-fit": "^0.10.0", "@xterm/addon-search": "^0.15.0", + "@xterm/addon-webgl": "^0.18.0", "@xterm/xterm": "^5.5.0", "alova": "^3.0.2", "clipboard-polyfill": "^4.1.0", diff --git a/ui/src/hooks/helper/index.ts b/ui/src/hooks/helper/index.ts index 6175e0bc..535e3fef 100644 --- a/ui/src/hooks/helper/index.ts +++ b/ui/src/hooks/helper/index.ts @@ -106,6 +106,8 @@ export const handleTerminalResize = ( }; } + data = resizeData; + socket.send(formatMessage(terminalId, eventType, data)); }; diff --git a/ui/src/hooks/useTerminal.ts b/ui/src/hooks/useTerminal.ts index 74a208ed..d8d83cd0 100644 --- a/ui/src/hooks/useTerminal.ts +++ b/ui/src/hooks/useTerminal.ts @@ -2,6 +2,7 @@ import xtermTheme from 'xterm-theme'; import { Terminal } from '@xterm/xterm'; import { FitAddon } from '@xterm/addon-fit'; +// import { WebglAddon } from '@xterm/addon-webgl'; import { ISearchOptions, SearchAddon } from '@xterm/addon-search'; import { Sentry } from 'nora-zmodemjs/src/zmodem_browser'; import { defaultTheme } from '@/config'; @@ -9,7 +10,7 @@ import { defaultTheme } from '@/config'; // hook import { createDiscreteApi } from 'naive-ui'; import { useSentry } from '@/hooks/useZsentry.ts'; -import { useDebounceFn, useWebSocket } from '@vueuse/core'; +import { useWebSocket } from '@vueuse/core'; // store import { storeToRefs } from 'pinia'; @@ -98,6 +99,7 @@ export const useTerminal = async (el: HTMLElement, option: ICallbackOptions): Pr switch (msg.type) { case 'CONNECT': { + fitAddon.fit(); terminalId.value = msg.id; const terminalData = { @@ -246,7 +248,6 @@ export const useTerminal = async (el: HTMLElement, option: ICallbackOptions): Pr } console.log(e); } - } else { writeBufferToTerminal(enableZmodem.value, zmodemStatus.value, terminal!, event.data); } @@ -443,7 +444,13 @@ export const useTerminal = async (el: HTMLElement, option: ICallbackOptions): Pr } }); - window.addEventListener('resize', () => useDebounceFn(() => fitAddon.fit(), 500), false); + window.addEventListener( + 'resize', + () => { + fitAddon.fit(); + }, + false + ); if (option.type === 'k8s') { window.addEventListener('keydown', (event: KeyboardEvent) => { @@ -473,6 +480,7 @@ export const useTerminal = async (el: HTMLElement, option: ICallbackOptions): Pr if (terminal) { terminal.loadAddon(fitAddon); terminal.loadAddon(searchAddon); + // terminal.loadAddon(new WebglAddon()); terminal.open(el); terminal.focus(); @@ -489,7 +497,8 @@ export const useTerminal = async (el: HTMLElement, option: ICallbackOptions): Pr handleTerminalOnData(data, type, terminalId.value, lunaConfig, socket); }); terminal.onResize(({ cols, rows }) => { - useDebounceFn(() => handleTerminalResize(cols, rows, type, terminalId.value, socket), 500); + fitAddon.fit(); + handleTerminalResize(cols, rows, type, terminalId.value, socket); }); } }; diff --git a/ui/src/hooks/useZsentry.ts b/ui/src/hooks/useZsentry.ts index 7fb5adf9..81cf0133 100644 --- a/ui/src/hooks/useZsentry.ts +++ b/ui/src/hooks/useZsentry.ts @@ -209,7 +209,7 @@ export const useSentry = (lastSendTime?: Ref, t?: any): IUseSentry => { terminal.write('\r\n'); - if (zmodeSession.value){ + if (zmodeSession.value) { zmodeSession.value.abort(); } }) diff --git a/ui/src/style/reset.scss b/ui/src/style/reset.scss index ee30dadc..9d636508 100644 --- a/ui/src/style/reset.scss +++ b/ui/src/style/reset.scss @@ -26,7 +26,7 @@ body, height: 100%; padding: 0; margin: 0; - font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; + font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; } #app { diff --git a/ui/src/views/Connection/index.vue b/ui/src/views/Connection/index.vue index fdfd09c5..30d735c1 100644 --- a/ui/src/views/Connection/index.vue +++ b/ui/src/views/Connection/index.vue @@ -22,7 +22,7 @@ import { Terminal } from '@xterm/xterm'; import { storeToRefs } from 'pinia'; import { NMessageProvider } from 'naive-ui'; -import {computed, h, markRaw, nextTick, onUnmounted, reactive, Ref, ref} from 'vue'; +import { computed, h, markRaw, nextTick, onUnmounted, reactive, Ref, ref } from 'vue'; import xtermTheme from 'xterm-theme'; import mittBus from '@/utils/mittBus.ts'; @@ -69,7 +69,7 @@ const warningIntervalId = ref(0); const onlineUsersMap = reactive<{ [key: string]: any }>({}); onUnmounted(() => { - clearInterval(warningIntervalId.value); + clearInterval(warningIntervalId.value); }); const settings = computed((): ISettingProp[] => { @@ -371,20 +371,20 @@ const onSocketData = (msgType: string, msg: any, terminal: Terminal) => { message.info(`${data.user} ${t('ResumeSession')}`); break; } - case 'TERMINAL_PERM_VALID': { - clearInterval(warningIntervalId.value); - message.info(`${t('PermissionValid')}`); - break; - } - case 'TERMINAL_PERM_EXPIRED': { - const data = JSON.parse(msg.data); - const warningMsg = `${t('PermissionExpired')}: ${data.detail}`; - message.warning(warningMsg); - warningIntervalId.value = setInterval(() => { - message.warning(warningMsg); - }, 1000 * 60); - break; - } + case 'TERMINAL_PERM_VALID': { + clearInterval(warningIntervalId.value); + message.info(`${t('PermissionValid')}`); + break; + } + case 'TERMINAL_PERM_EXPIRED': { + const data = JSON.parse(msg.data); + const warningMsg = `${t('PermissionExpired')}: ${data.detail}`; + message.warning(warningMsg); + warningIntervalId.value = setInterval(() => { + message.warning(warningMsg); + }, 1000 * 60); + break; + } case 'CLOSE': { enableShare.value = false; diff --git a/ui/yarn.lock b/ui/yarn.lock index 5718128e..1617ef81 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -616,6 +616,11 @@ resolved "https://registry.yarnpkg.com/@xterm/addon-search/-/addon-search-0.15.0.tgz#5c772d5f14c26546c4bfbeb0c3d4b3333057411f" integrity sha512-ZBZKLQ+EuKE83CqCmSSz5y1tx+aNOCUaA7dm6emgOX+8J9H1FWXZyrKfzjwzV+V14TV3xToz1goIeRhXBS5qjg== +"@xterm/addon-webgl@^0.18.0": + version "0.18.0" + resolved "https://registry.yarnpkg.com/@xterm/addon-webgl/-/addon-webgl-0.18.0.tgz#9e927cee10af971595fb2a72fd4c3bc2819f0096" + integrity sha512-xCnfMBTI+/HKPdRnSOHaJDRqEpq2Ugy8LEj9GiY4J3zJObo3joylIFaMvzBwbYRg8zLtkO0KQaStCeSfoaI2/w== + "@xterm/xterm@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@xterm/xterm/-/xterm-5.5.0.tgz#275fb8f6e14afa6e8a0c05d4ebc94523ff775396" From 1e5b3a5bf584bbd6ba1aff0ad5cbc24d9f04abd7 Mon Sep 17 00:00:00 2001 From: zhaojisen <1301338853@qq.com> Date: Wed, 16 Oct 2024 18:17:09 +0800 Subject: [PATCH 3/7] fixed: Fixed issues with termianl not adapting --- ui/src/hooks/helper/index.ts | 448 +++++++++++++++++------------------ 1 file changed, 224 insertions(+), 224 deletions(-) diff --git a/ui/src/hooks/helper/index.ts b/ui/src/hooks/helper/index.ts index 535e3fef..a867438b 100644 --- a/ui/src/hooks/helper/index.ts +++ b/ui/src/hooks/helper/index.ts @@ -34,36 +34,36 @@ const { message } = createDiscreteApi(['message']); * @param k8s_id */ export const handleContextMenu = async ( - e: MouseEvent, - config: ILunaConfig, - socket: WebSocket, - terminalId: string, - termSelectionText: string, - k8s_id: string | undefined + e: MouseEvent, + config: ILunaConfig, + socket: WebSocket, + terminalId: string, + termSelectionText: string, + k8s_id: string | undefined ) => { - e.preventDefault(); - if (e.ctrlKey || config.quickPaste !== '1') return; - - let text: string = ''; - - try { - text = await readText(); - } catch (e) { - if (termSelectionText !== '') text = termSelectionText; - } - - if (k8s_id) { - socket.send( - JSON.stringify({ - id: terminalId, - k8s_id, - type: 'TERMINAL_K8S_DATA', - data: text - }) - ); - } else { - socket.send(formatMessage(terminalId, 'TERMINAL_DATA', text)); - } + e.preventDefault(); + if (e.ctrlKey || config.quickPaste !== '1') return; + + let text: string = ''; + + try { + text = await readText(); + } catch (e) { + if (termSelectionText !== '') text = termSelectionText; + } + + if (k8s_id) { + socket.send( + JSON.stringify({ + id: terminalId, + k8s_id, + type: 'TERMINAL_K8S_DATA', + data: text + }) + ); + } else { + socket.send(formatMessage(terminalId, 'TERMINAL_DATA', text)); + } }; /** @@ -76,39 +76,39 @@ export const handleContextMenu = async ( * @param socket */ export const handleTerminalResize = ( - cols: number, - rows: number, - type: string, - terminalId: string, - socket: WebSocket + cols: number, + rows: number, + type: string, + terminalId: string, + socket: WebSocket ) => { - let data; + let data; - info('Send Term Resize'); + info('Send Term Resize'); - const treeStore = useTreeStore(); - const { currentNode } = storeToRefs(treeStore); + const treeStore = useTreeStore(); + const { currentNode } = storeToRefs(treeStore); - const eventType = type === 'k8s' ? 'TERMINAL_K8S_RESIZE' : 'TERMINAL_RESIZE'; - const resizeData = JSON.stringify({ cols, rows }); - - if (type === 'k8s' && currentNode.value.children) { - const currentItem = currentNode.value.children[0]; - - data = { - k8s_id: currentItem.k8s_id, - namespace: currentItem.namespace, - pod: currentItem.pod, - container: currentItem.container, - type: eventType, - id: terminalId, - resizeData - }; - } + const eventType = type === 'k8s' ? 'TERMINAL_K8S_RESIZE' : 'TERMINAL_RESIZE'; + const resizeData = JSON.stringify({ cols, rows }); + + data = resizeData; + + if (type === 'k8s' && currentNode.value.children) { + const currentItem = currentNode.value.children[0]; - data = resizeData; + data = { + k8s_id: currentItem.k8s_id, + namespace: currentItem.namespace, + pod: currentItem.pod, + container: currentItem.container, + type: eventType, + id: terminalId, + resizeData + }; + } - socket.send(formatMessage(terminalId, eventType, data)); + socket.send(formatMessage(terminalId, eventType, data)); }; /** @@ -120,37 +120,37 @@ export const handleTerminalResize = ( * @param origin */ export const handleCustomKey = ( - e: KeyboardEvent, - terminal: Terminal, - lunaId: string, - origin: string + e: KeyboardEvent, + terminal: Terminal, + lunaId: string, + origin: string ): boolean => { - if (e.altKey && e.shiftKey && (e.key === 'ArrowRight' || e.key === 'ArrowLeft')) { - switch (e.key) { - case 'ArrowRight': - if (lunaId && origin) { - sendEventToLuna('KEYEVENT', 'alt+shift+right', lunaId, origin); - } else { - mittBus.emit('alt-shift-right'); - } - - break; - case 'ArrowLeft': - if (lunaId && origin) { - sendEventToLuna('KEYEVENT', 'alt+shift+left', lunaId, origin); - } else { - mittBus.emit('alt-shift-left'); - } - break; + if (e.altKey && e.shiftKey && (e.key === 'ArrowRight' || e.key === 'ArrowLeft')) { + switch (e.key) { + case 'ArrowRight': + if (lunaId && origin) { + sendEventToLuna('KEYEVENT', 'alt+shift+right', lunaId, origin); + } else { + mittBus.emit('alt-shift-right'); } - return false; - } - if (e.ctrlKey && e.key === 'c' && terminal.hasSelection()) { - return false; + break; + case 'ArrowLeft': + if (lunaId && origin) { + sendEventToLuna('KEYEVENT', 'alt+shift+left', lunaId, origin); + } else { + mittBus.emit('alt-shift-left'); + } + break; } + return false; + } + + if (e.ctrlKey && e.key === 'c' && terminal.hasSelection()) { + return false; + } - return !(e.ctrlKey && e.key === 'v'); + return !(e.ctrlKey && e.key === 'v'); }; /** @@ -160,18 +160,18 @@ export const handleCustomKey = ( * @param termSelectionText */ export const handleTerminalSelection = async (terminal: Terminal, termSelectionText: Ref) => { - termSelectionText.value = terminal.getSelection().trim(); - - if (termSelectionText.value !== '') { - clipboard - .writeText(termSelectionText.value) - .then(() => {}) - .catch(e => { - message.error(`Copy Error for ${e}`); - }); - } else { - // message.warning('Please select the text before copying'); - } + termSelectionText.value = terminal.getSelection().trim(); + + if (termSelectionText.value !== '') { + clipboard + .writeText(termSelectionText.value) + .then(() => {}) + .catch(e => { + message.error(`Copy Error for ${e}`); + }); + } else { + // message.warning('Please select the text before copying'); + } }; /** @@ -185,58 +185,58 @@ export const handleTerminalSelection = async (terminal: Terminal, termSelectionT */ // todo export const handleTerminalOnData = ( - data: string, - type: string, - terminalId: string, - config: ILunaConfig, - socket: WebSocket + data: string, + type: string, + terminalId: string, + config: ILunaConfig, + socket: WebSocket ) => { - const terminalStore = useTerminalStore(); - const { enableZmodem, zmodemStatus } = storeToRefs(terminalStore); + const terminalStore = useTerminalStore(); + const { enableZmodem, zmodemStatus } = storeToRefs(terminalStore); - // 如果未开启 Zmodem 且当前在 Zmodem 状态,不允许输入 - if (!enableZmodem.value && zmodemStatus.value) { - return message.warning('未开启 Zmodem 且当前在 Zmodem 状态,不允许输入'); - } + // 如果未开启 Zmodem 且当前在 Zmodem 状态,不允许输入 + if (!enableZmodem.value && zmodemStatus.value) { + return message.warning('未开启 Zmodem 且当前在 Zmodem 状态,不允许输入'); + } - data = preprocessInput(data, config); - const eventType = type === 'k8s' ? 'TERMINAL_K8S_DATA' : 'TERMINAL_DATA'; - - // 如果类型是 k8s,处理 k8s 的逻辑 - if (type === 'k8s') { - const treeStore = useTreeStore(); - const { currentNode } = storeToRefs(treeStore); - const node = currentNode.value; - - // 获取默认的消息体 - const messageData = { - data: data, - id: terminalId, - type: eventType, - pod: node.pod || '', - k8s_id: node.k8s_id, - namespace: node.namespace || '', - container: node.container || '' - }; - - // 如果有子节点但不是父节点,取第一个子节点的信息 - if (node.children && node.children.length > 0) { - const currentItem = node.children[0]; - Object.assign(messageData, { - pod: currentItem.pod, - k8s_id: currentItem.k8s_id, - namespace: currentItem.namespace, - container: currentItem.container - }); - } + data = preprocessInput(data, config); + const eventType = type === 'k8s' ? 'TERMINAL_K8S_DATA' : 'TERMINAL_DATA'; - // 发送消息 - return socket.send(JSON.stringify(messageData)); + // 如果类型是 k8s,处理 k8s 的逻辑 + if (type === 'k8s') { + const treeStore = useTreeStore(); + const { currentNode } = storeToRefs(treeStore); + const node = currentNode.value; + + // 获取默认的消息体 + const messageData = { + data: data, + id: terminalId, + type: eventType, + pod: node.pod || '', + k8s_id: node.k8s_id, + namespace: node.namespace || '', + container: node.container || '' + }; + + // 如果有子节点但不是父节点,取第一个子节点的信息 + if (node.children && node.children.length > 0) { + const currentItem = node.children[0]; + Object.assign(messageData, { + pod: currentItem.pod, + k8s_id: currentItem.k8s_id, + namespace: currentItem.namespace, + container: currentItem.container + }); } - // 处理非 k8s 的情况 - sendEventToLuna('KEYBOARDEVENT', ''); - socket.send(formatMessage(terminalId, eventType, data)); + // 发送消息 + return socket.send(JSON.stringify(messageData)); + } + + // 处理非 k8s 的情况 + sendEventToLuna('KEYBOARDEVENT', ''); + socket.send(formatMessage(terminalId, eventType, data)); }; /** @@ -249,96 +249,96 @@ export const handleTerminalOnData = ( * @param terminalId */ export const onWebsocketOpen = ( - socket: WebSocket, - lastSendTime: Date, - terminalId: string, - pingInterval: Ref, - lastReceiveTime: Ref + socket: WebSocket, + lastSendTime: Date, + terminalId: string, + pingInterval: Ref, + lastReceiveTime: Ref ) => { - socket.binaryType = 'arraybuffer'; - sendEventToLuna('CONNECTED', ''); + socket.binaryType = 'arraybuffer'; + sendEventToLuna('CONNECTED', ''); - if (pingInterval.value) clearInterval(pingInterval.value); + if (pingInterval.value) clearInterval(pingInterval.value); - pingInterval.value = setInterval(() => { - if (socket.CLOSED === socket.readyState || socket.CLOSING === socket.readyState) { - return clearInterval(pingInterval.value!); - } + pingInterval.value = setInterval(() => { + if (socket.CLOSED === socket.readyState || socket.CLOSING === socket.readyState) { + return clearInterval(pingInterval.value!); + } - let currentDate: Date = new Date(); + let currentDate: Date = new Date(); - if (lastReceiveTime.value.getTime() - currentDate.getTime() > MaxTimeout) { - message.info('More than 30s do not receive data'); - } + if (lastReceiveTime.value.getTime() - currentDate.getTime() > MaxTimeout) { + message.info('More than 30s do not receive data'); + } - let pingTimeout: number = currentDate.getTime() - lastSendTime.getTime(); + let pingTimeout: number = currentDate.getTime() - lastSendTime.getTime(); - if (pingTimeout < 0) return; + if (pingTimeout < 0) return; - socket.send(formatMessage(terminalId, 'PING', '')); - }, 25 * 1000); + socket.send(formatMessage(terminalId, 'PING', '')); + }, 25 * 1000); }; /** * 生成 Socket url */ export const generateWsURL = () => { - const route = useRoute(); + const route = useRoute(); - const routeName = route.name; - const urlParams = new URLSearchParams(window.location.search.slice(1)); + const routeName = route.name; + const urlParams = new URLSearchParams(window.location.search.slice(1)); - let connectURL; + let connectURL; - switch (routeName) { - case 'Token': { - const params = route.params; - const requireParams = new URLSearchParams(); + switch (routeName) { + case 'Token': { + const params = route.params; + const requireParams = new URLSearchParams(); - requireParams.append('type', 'token'); - requireParams.append('target_id', params.id ? params.id.toString() : ''); + requireParams.append('type', 'token'); + requireParams.append('target_id', params.id ? params.id.toString() : ''); - connectURL = BASE_WS_URL + '/koko/ws/token/?' + requireParams.toString(); - break; - } - case 'TokenParams': { - connectURL = urlParams ? `${BASE_WS_URL}/koko/ws/token/?${urlParams.toString()}` : ''; - break; - } - case 'kubernetes': { - connectURL = `${BASE_WS_URL}/koko/ws/terminal/?token=${route.query.token}&type=k8s`; - break; - } - case 'Share': { - const id = route.params.id as string; - const requireParams = new URLSearchParams(); + connectURL = BASE_WS_URL + '/koko/ws/token/?' + requireParams.toString(); + break; + } + case 'TokenParams': { + connectURL = urlParams ? `${BASE_WS_URL}/koko/ws/token/?${urlParams.toString()}` : ''; + break; + } + case 'kubernetes': { + connectURL = `${BASE_WS_URL}/koko/ws/terminal/?token=${route.query.token}&type=k8s`; + break; + } + case 'Share': { + const id = route.params.id as string; + const requireParams = new URLSearchParams(); - requireParams.append('type', 'share'); - requireParams.append('target_id', id); + requireParams.append('type', 'share'); + requireParams.append('target_id', id); - connectURL = BASE_WS_URL + '/koko/ws/terminal/?' + requireParams.toString(); - break; - } - case 'Monitor': { - const id = route.params.id as string; - const requireParams = new URLSearchParams(); + connectURL = BASE_WS_URL + '/koko/ws/terminal/?' + requireParams.toString(); + break; + } + case 'Monitor': { + const id = route.params.id as string; + const requireParams = new URLSearchParams(); - requireParams.append('type', 'monitor'); - requireParams.append('target_id', id); + requireParams.append('type', 'monitor'); + requireParams.append('target_id', id); - connectURL = BASE_WS_URL + '/koko/ws/terminal/?' + requireParams.toString(); - break; - } - default: { - connectURL = urlParams ? `${BASE_WS_URL}/koko/ws/terminal/?${urlParams.toString()}` : ''; - } + connectURL = BASE_WS_URL + '/koko/ws/terminal/?' + requireParams.toString(); + break; } - - if (!connectURL) { - message.error('Unable to generate WebSocket URL, missing parameters.'); + default: { + connectURL = urlParams ? `${BASE_WS_URL}/koko/ws/terminal/?${urlParams.toString()}` : ''; } + } + + if (!connectURL) { + message.error('Unable to generate WebSocket URL, missing parameters.'); + } - return connectURL; + return connectURL; }; /** @@ -349,19 +349,19 @@ export const generateWsURL = () => { * @param type */ export const onWebsocketWrong = (event: Event, type: string, terminal?: Terminal) => { - switch (type) { - case 'error': { - terminal ? terminal.write('Connection Websocket Error') : ''; - break; - } - case 'disconnected': { - terminal ? terminal.write('Connection Websocket Closed') : ''; - break; - } + switch (type) { + case 'error': { + terminal ? terminal.write('Connection Websocket Error') : ''; + break; + } + case 'disconnected': { + terminal ? terminal.write('Connection Websocket Closed') : ''; + break; } + } - fireEvent(new Event('CLOSE', {})); - handleError(event); + fireEvent(new Event('CLOSE', {})); + handleError(event); }; /** @@ -369,13 +369,13 @@ export const onWebsocketWrong = (event: Event, type: string, terminal?: Terminal * @param base64 */ export const base64ToUint8Array = (base64: string): Uint8Array => { - // 转为原始的二进制字符串(binaryString)。 - const binaryString = atob(base64); - const len = binaryString.length; - - const bytes = new Uint8Array(len); - for (let i = 0; i < len; i++) { - bytes[i] = binaryString.charCodeAt(i); - } - return bytes; + // 转为原始的二进制字符串(binaryString)。 + const binaryString = atob(base64); + const len = binaryString.length; + + const bytes = new Uint8Array(len); + for (let i = 0; i < len; i++) { + bytes[i] = binaryString.charCodeAt(i); + } + return bytes; }; From 27561efe51ad2b6e607abeeeb3fa457a9d9a3619 Mon Sep 17 00:00:00 2001 From: Aaron3S Date: Wed, 16 Oct 2024 19:35:57 +0800 Subject: [PATCH 4/7] =?UTF-8?q?feat:=20=E4=BF=AE=E6=94=B9=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=BA=93=20CLI=20=E8=BF=9E=E6=8E=A5=E6=96=B9=E5=BC=8F?= =?UTF-8?q?=20prompt1=20=E4=B8=BA=20schema?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/srvconn/conn_usql.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/srvconn/conn_usql.go b/pkg/srvconn/conn_usql.go index 61c3a63b..6bafb128 100644 --- a/pkg/srvconn/conn_usql.go +++ b/pkg/srvconn/conn_usql.go @@ -114,7 +114,7 @@ func (o *sqlOption) USQLCommandArgs() ([]string, error) { } dsn := dsnURL.String() - prompt1 := "--variable=PROMPT1=" + o.AssetName + "%R%#" + prompt1 := "--variable=PROMPT1=" + o.Schema + "%R%#" return []string{dsn, prompt1}, nil } From 529ac87f2e5ba83872d9e19d9d6d6f41f9c38711 Mon Sep 17 00:00:00 2001 From: Eric Date: Thu, 17 Oct 2024 10:28:38 +0800 Subject: [PATCH 5/7] perf: add lang code for api check --- pkg/jms-sdk-go/model/session.go | 1 + pkg/koko/token_check.go | 4 +++- pkg/proxy/server.go | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/jms-sdk-go/model/session.go b/pkg/jms-sdk-go/model/session.go index 05f17211..fe982b2f 100644 --- a/pkg/jms-sdk-go/model/session.go +++ b/pkg/jms-sdk-go/model/session.go @@ -58,6 +58,7 @@ type Session struct { Type LabelField `json:"type"` ErrReason LabelField `json:"error_reason,omitempty"` TokenId string `json:"token_id,omitempty"` + LangCode string `json:"lang_code,omitempty"` } type ReplayVersion string diff --git a/pkg/koko/token_check.go b/pkg/koko/token_check.go index 72fe0624..4978d080 100644 --- a/pkg/koko/token_check.go +++ b/pkg/koko/token_check.go @@ -11,6 +11,7 @@ import ( // RunConnectTokensCheck every 5 minutes check token status func RunConnectTokensCheck(jmsService *service.JMService) { + apiClient := jmsService.Copy() for { time.Sleep(5 * time.Minute) sessions := session.GetSessions() @@ -21,7 +22,8 @@ func RunConnectTokensCheck(jmsService *service.JMService) { handleTokenCheck(s, &ret) continue } - ret, err := jmsService.CheckTokenStatus(s.TokenId) + apiClient.SetCookie("django_language", s.LangCode) + ret, err := apiClient.CheckTokenStatus(s.TokenId) if err != nil && ret.Code == "" { logger.Errorf("Check token status failed: %s", err) continue diff --git a/pkg/proxy/server.go b/pkg/proxy/server.go index f5539206..b0efc09f 100644 --- a/pkg/proxy/server.go +++ b/pkg/proxy/server.go @@ -95,6 +95,7 @@ func NewServer(conn UserConnection, jmsService *service.JMService, opts ...Conne OrgID: connOpts.authInfo.OrgId, Type: model.NORMALType, TokenId: connOpts.authInfo.Id, + LangCode: connOpts.i18nLang, } if !connOpts.authInfo.Actions.EnableConnect() { From a6e2550eadd90b9580d6b29c89478ceefbe2afeb Mon Sep 17 00:00:00 2001 From: Eric Date: Thu, 17 Oct 2024 14:16:33 +0800 Subject: [PATCH 6/7] perf: web terminal contextmenu --- ui/src/hooks/helper/index.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ui/src/hooks/helper/index.ts b/ui/src/hooks/helper/index.ts index a867438b..3662f585 100644 --- a/ui/src/hooks/helper/index.ts +++ b/ui/src/hooks/helper/index.ts @@ -41,7 +41,6 @@ export const handleContextMenu = async ( termSelectionText: string, k8s_id: string | undefined ) => { - e.preventDefault(); if (e.ctrlKey || config.quickPaste !== '1') return; let text: string = ''; @@ -51,7 +50,7 @@ export const handleContextMenu = async ( } catch (e) { if (termSelectionText !== '') text = termSelectionText; } - + e.preventDefault(); if (k8s_id) { socket.send( JSON.stringify({ From 96eab328c25615471b8d4128816fb560f52ff658 Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Tue, 22 Oct 2024 18:21:16 +0800 Subject: [PATCH 7/7] perf: Optimize sftp upload and download speed --- pkg/handler/sftp.go | 37 +++++++++++++++++++------------------ pkg/proxy/recorder.go | 37 +------------------------------------ 2 files changed, 20 insertions(+), 54 deletions(-) diff --git a/pkg/handler/sftp.go b/pkg/handler/sftp.go index a340dc63..6d973e43 100644 --- a/pkg/handler/sftp.go +++ b/pkg/handler/sftp.go @@ -77,13 +77,24 @@ func (s *SftpHandler) Filewrite(r *sftp.Request) (io.WriterAt, error) { if err != nil { return nil, err } + go func() { <-r.Context().Done() + + fileInfo, err2 := f.Stat() + if err2 != nil { + logger.Errorf("Get file %s stat err: %s", r.Filepath, err2) + return + } + + if err1 := s.recorder.ChunkedRecord(f.FTPLog, f, 0, fileInfo.Size()); err1 != nil { + logger.Errorf("Record file %s err: %s", r.Filepath, err1) + } + if err := f.Close(); err != nil { logger.Errorf("Remote sftp file %s close err: %s", r.Filepath, err) } logger.Infof("Sftp file write %s done", r.Filepath) - s.recorder.FinishFTPFile(f.FTPLog.ID) }() return NewWriterAt(f, s.recorder), err } @@ -100,20 +111,18 @@ func (s *SftpHandler) Fileread(r *sftp.Request) (io.ReaderAt, error) { return nil, err } - if err1 := s.recorder.ChunkedRecord(f.FTPLog, f, 0, fileInfo.Size()); err1 != nil { - logger.Errorf("Record file %s err: %s", r.Filepath, err1) - } - - // 重置文件指针 - _, _ = f.Seek(0, io.SeekStart) go func() { <-r.Context().Done() + + if err1 := s.recorder.ChunkedRecord(f.FTPLog, f, 0, fileInfo.Size()); err1 != nil { + logger.Errorf("Record file %s err: %s", r.Filepath, err1) + } + if err2 := f.Close(); err2 != nil { logger.Errorf("Remote sftp file %s close err: %s", r.Filepath, err2) } - logger.Infof("Sftp File read %s done", r.Filepath) - s.recorder.FinishFTPFile(f.FTPLog.ID) + logger.Infof("Sftp File read %s done", r.Filepath) }() // 包裹一层,兼容 WinSCP 目录的批量下载 return NewReaderAt(f), err @@ -153,18 +162,10 @@ type clientReadWritAt struct { } func (c *clientReadWritAt) WriteAt(p []byte, off int64) (n int, err error) { - c.mu.Lock() - defer c.mu.Unlock() - if err1 := c.recorder.RecordFtpChunk(c.f.FTPLog, p, off); err1 != nil { - logger.Errorf("Record write err: %s", err1) - } - _, _ = c.f.Seek(off, 0) - return c.f.Write(p) + return c.f.WriteAt(p, off) } func (c *clientReadWritAt) ReadAt(p []byte, off int64) (n int, err error) { - c.mu.Lock() - defer c.mu.Unlock() return c.f.ReadAt(p, off) } diff --git a/pkg/proxy/recorder.go b/pkg/proxy/recorder.go index 7f56a933..e2e96d5e 100644 --- a/pkg/proxy/recorder.go +++ b/pkg/proxy/recorder.go @@ -351,24 +351,6 @@ func (r *FTPFileRecorder) CreateFTPFileInfo(logData *model.FTPLog) (info *FTPFil return info, nil } -func (r *FTPFileRecorder) RecordFtpChunk(ftpLog *model.FTPLog, p []byte, off int64) (err error) { - if r.isNullStorage() { - return - } - info := r.getFTPFile(ftpLog.ID) - if info == nil { - info, err = r.CreateFTPFileInfo(ftpLog) - } - if err != nil { - return - } - if info.isExceedWrittenSize() { - logger.Errorf("FTP file %s is exceeds the max limit and discard it", ftpLog.ID) - return nil - } - return info.WriteChunk(p, off) -} - func (r *FTPFileRecorder) FinishFTPFile(id string) { info := r.getFTPFile(id) if info == nil { @@ -409,7 +391,7 @@ func (r *FTPFileRecorder) ChunkedRecord(ftpLog *model.FTPLog, readerAt io.Reader return err } - if info.isExceedWrittenSize() { + if info.isExceedWrittenSize() || totalSize >= info.maxWrittenSize { logger.Errorf("FTP file %s is exceeds the max limit and discard it", ftpLog.ID) return nil } @@ -495,23 +477,6 @@ type FTPFileInfo struct { writtenBytes int64 } -func (f *FTPFileInfo) WriteChunk(p []byte, off int64) error { - var ( - nw int - err error - ) - _, err = f.fd.Seek(off, io.SeekStart) - if err != nil { - return err - } - nw, err = f.fd.Write(p) - if nw > 0 { - f.writtenBytes += int64(nw) - } - return err - -} - func (f *FTPFileInfo) WriteFromReader(r io.Reader) error { buf := make([]byte, 32*1024) var err error