diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/handler/host/exec/command/TimeOutCheckerFix.java b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/handler/host/exec/command/TimeOutCheckerFix.java new file mode 100644 index 00000000..61d30385 --- /dev/null +++ b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/handler/host/exec/command/TimeOutCheckerFix.java @@ -0,0 +1,55 @@ +package com.orion.ops.module.asset.handler.host.exec.command; + +import com.orion.lang.support.timeout.TimeoutChecker; +import com.orion.lang.support.timeout.TimeoutEndpoint; +import com.orion.lang.utils.Threads; + +import java.util.ArrayList; +import java.util.List; + +/** + * TODO KIT + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2024/3/20 16:50 + */ +public class TimeOutCheckerFix implements TimeoutChecker { + + private final List tasks = new ArrayList<>(); + + private final long delay; + + private boolean run; + + public TimeOutCheckerFix() { + this(DEFAULT_DELAY); + } + + public TimeOutCheckerFix(long delay) { + this.delay = delay; + this.run = true; + } + + @Override + public void addTask(T task) { + tasks.add(task); + } + + @Override + public void run() { + while (run) { + // 完成或超时 直接移除 + tasks.removeIf(ch -> ch.isDone() || ch.checkTimeout()); + // 等待 + // 不为空则休眠 + Threads.sleep(delay); + } + } + + @Override + public void close() { + this.run = false; + } + +} diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/handler/host/exec/command/handler/ExecTaskHandler.java b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/handler/host/exec/command/handler/ExecTaskHandler.java index 0b2771d3..aa17844b 100644 --- a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/handler/host/exec/command/handler/ExecTaskHandler.java +++ b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/handler/host/exec/command/handler/ExecTaskHandler.java @@ -4,11 +4,11 @@ import com.orion.lang.support.timeout.TimeoutChecker; import com.orion.lang.utils.Threads; import com.orion.lang.utils.collect.Lists; import com.orion.lang.utils.io.Streams; -import com.orion.ops.framework.common.constant.Const; import com.orion.ops.module.asset.dao.ExecLogDAO; import com.orion.ops.module.asset.define.AssetThreadPools; import com.orion.ops.module.asset.entity.domain.ExecLogDO; import com.orion.ops.module.asset.enums.ExecStatusEnum; +import com.orion.ops.module.asset.handler.host.exec.command.TimeOutCheckerFix; import com.orion.ops.module.asset.handler.host.exec.command.dto.ExecCommandDTO; import com.orion.ops.module.asset.handler.host.exec.command.dto.ExecCommandHostDTO; import com.orion.ops.module.asset.handler.host.exec.command.manager.ExecTaskManager; @@ -32,7 +32,7 @@ public class ExecTaskHandler implements IExecTaskHandler { private static final ExecLogDAO execLogDAO = SpringHolder.getBean(ExecLogDAO.class); - private static final ExecTaskManager EXEC_TASK_MANAGER = SpringHolder.getBean(ExecTaskManager.class); + private static final ExecTaskManager execTaskManager = SpringHolder.getBean(ExecTaskManager.class); private final ExecCommandDTO execCommand; @@ -50,7 +50,7 @@ public class ExecTaskHandler implements IExecTaskHandler { public void run() { Long id = execCommand.getLogId(); // 添加任务 - EXEC_TASK_MANAGER.addTask(id, this); + execTaskManager.addTask(id, this); log.info("ExecTaskHandler.run start id: {}", id); // 更新状态 this.updateStatus(ExecStatusEnum.RUNNING); @@ -68,7 +68,7 @@ public class ExecTaskHandler implements IExecTaskHandler { // 释放资源 Streams.close(this); // 移除任务 - EXEC_TASK_MANAGER.removeTask(id); + execTaskManager.removeTask(id); } } @@ -87,7 +87,7 @@ public class ExecTaskHandler implements IExecTaskHandler { private void runHostCommand(List hosts) throws Exception { // 超时检查 if (execCommand.getTimeout() != 0) { - this.timeoutChecker = TimeoutChecker.create(Const.MS_S_1); + this.timeoutChecker = new TimeOutCheckerFix(); AssetThreadPools.TIMEOUT_CHECK.execute(this.timeoutChecker); } if (hosts.size() == 1) { diff --git a/orion-ops-ui/src/components/xtrem/log-appender/appender.const.ts b/orion-ops-ui/src/components/xtrem/log-appender/appender.const.ts index 4f7809da..7f6fa055 100644 --- a/orion-ops-ui/src/components/xtrem/log-appender/appender.const.ts +++ b/orion-ops-ui/src/components/xtrem/log-appender/appender.const.ts @@ -27,13 +27,14 @@ export const AppenderOptions: ITerminalOptions & ITerminalInitOnlyOptions = { export interface LogDomRef { id: number; el: HTMLElement; + openSearch: () => {}; } // appender 配置 export interface LogAppenderConf { id: number; el: HTMLElement; - fixed: boolean; + openSearch: () => {}; terminal: Terminal; addons: LogAddons; } @@ -53,14 +54,17 @@ export interface ILogAppender { // 设置当前元素 setCurrent(id: number): void; + // 打开搜索 + openSearch(): void; + // 查找关键字 find(word: string, next: boolean, options: any): void; // 聚焦 focus(): void; - // 设置固定 - setFixed(fixed: boolean): void; + // 自适应 + fitAll(): void; // 去顶部 toTop(): void; diff --git a/orion-ops-ui/src/components/xtrem/log-appender/log-appender.ts b/orion-ops-ui/src/components/xtrem/log-appender/log-appender.ts index 7dc440e2..a9c3b0a8 100644 --- a/orion-ops-ui/src/components/xtrem/log-appender/log-appender.ts +++ b/orion-ops-ui/src/components/xtrem/log-appender/log-appender.ts @@ -59,7 +59,6 @@ export default class LogAppender implements ILogAppender { addons.fit.fit(); this.appenderRel[logDomRef.id] = { ...logDomRef, - fixed: false, terminal, addons }; @@ -94,7 +93,7 @@ export default class LogAppender implements ILogAppender { } else if (e.ctrlKey && e.code === 'KeyF') { // 搜索 e.preventDefault(); - // TODO open search + this.current.openSearch(); return false; } return true; @@ -147,13 +146,14 @@ export default class LogAppender implements ILogAppender { this.current = rel; // 自适应 rel.addons.fit.fit(); - // 非固定跳转到最底部 - if (!rel.fixed) { - rel.terminal.scrollToBottom(); - } this.focus(); } + // 打开搜索 + openSearch() { + this.current.openSearch(); + } + // 查找关键字 find(word: string, next: boolean, options: any) { if (next) { @@ -163,12 +163,6 @@ export default class LogAppender implements ILogAppender { } } - // 设置固定 - setFixed(fixed: boolean): void { - this.current.fixed = fixed; - this.focus(); - } - // 去顶部 toTop(): void { this.current.terminal.scrollToTop(); diff --git a/orion-ops-ui/src/views/exec/exec-command/components/log-panel-appender.vue b/orion-ops-ui/src/views/exec/exec-command/components/log-panel-appender.vue new file mode 100644 index 00000000..54e7b698 --- /dev/null +++ b/orion-ops-ui/src/views/exec/exec-command/components/log-panel-appender.vue @@ -0,0 +1,271 @@ + + + + + + + diff --git a/orion-ops-ui/src/views/exec/exec-command/components/log-panel-view.vue b/orion-ops-ui/src/views/exec/exec-command/components/log-panel-view.vue index e2417175..6593db52 100644 --- a/orion-ops-ui/src/views/exec/exec-command/components/log-panel-view.vue +++ b/orion-ops-ui/src/views/exec/exec-command/components/log-panel-view.vue @@ -1,166 +1,14 @@ @@ -174,40 +22,34 @@ import type { VNodeRef } from 'vue'; import type { ExecCommandResponse } from '@/api/exec/exec'; import type { LogDomRef, ILogAppender } from '@/components/xtrem/log-appender/appender.const'; - import { nextTick, ref, watch } from 'vue'; - import { downloadExecLogFile } from '@/api/exec/exec'; - import { downloadFile } from '@/utils/file'; - import { formatDuration } from '@/utils'; - import { execHostStatus, execHostStatusKey } from '@/views/exec/exec-log/types/const'; - import { useDictStore } from '@/store'; + import { nextTick, onBeforeMount, ref, watch } from 'vue'; import LogAppender from '@/components/xtrem/log-appender/log-appender'; - import XtermSearchModal from '@/components/xtrem/search-modal/index.vue'; - import 'xterm/css/xterm.css'; + import LogPanelAppender from './log-panel-appender.vue'; const props = defineProps<{ current: number; command: ExecCommandResponse; }>(); - const { getDictValue } = useDictStore(); - const logRefs = ref>([]); const appender = ref(); - const searchModal = ref(); // 切换标签 watch(() => props.current, (val) => { nextTick(() => { - appender.value?.setCurrent(val); + setTimeout(() => { + appender.value?.setCurrent(val); + }, 50); }); }); // 打开 const open = () => { nextTick(async () => { - appender.value = new LogAppender({ execId: props.command.id }); - // 初始化 - await appender.value.init(logRefs.value); + if (appender.value) { + // 初始化 + await appender.value.init(logRefs.value); + } }); }; @@ -219,96 +61,37 @@ // 关闭全部 const closeAll = () => { appender.value?.close(); + logRefs.value = []; + appender.value = undefined; }; defineExpose({ open, closeClient, closeAll }); // 添加 ref - const addRef = (id: number, el: HTMLElement) => { + const addRef = (ref: any) => { + if (!ref) { + return; + } nextTick(() => { - logRefs.value.push({ id, el }); + logRefs.value.push({ + id: ref.id, + el: ref.appenderRef, + openSearch: ref.openSearch + }); }); }; - // 搜索关键字 - const searchWords = (word: string, next: boolean, options: any) => { - appender.value?.find(word, next, options); - }; - - // 关闭搜索框 - const searchClose = () => { - appender.value?.focus(); - }; - - // 下载文件 - const downloadLogFile = async (id: number) => { - const data = await downloadExecLogFile(id); - downloadFile(data); - }; + onBeforeMount(() => { + appender.value = new LogAppender({ execId: props.command.id }); + }); diff --git a/orion-ops-ui/src/views/exec/exec-command/components/log-panel.vue b/orion-ops-ui/src/views/exec/exec-command/components/log-panel.vue index 60eafd41..0ea0bcf9 100644 --- a/orion-ops-ui/src/views/exec/exec-command/components/log-panel.vue +++ b/orion-ops-ui/src/views/exec/exec-command/components/log-panel.vue @@ -7,7 +7,7 @@ @selected="selectedHost" @back="emits('back')" /> - @@ -30,7 +30,7 @@ const emits = defineEmits(['back']); - const logContainer = ref(); + const logView = ref(); const currentHostExecId = ref(); const statusIntervalId = ref(); const finishIntervalId = ref(); @@ -46,7 +46,7 @@ finishIntervalId.value = setInterval(setTaskFinishTime, 1000); // 打开日志 nextTick(() => { - logContainer.value?.open(); + logView.value?.open(); }); }; @@ -68,7 +68,9 @@ if (hostStatus) { host.status = hostStatus.status; host.startTime = hostStatus.startTime; - host.finishTime = hostStatus.finishTime; + if (hostStatus.finishTime) { + host.finishTime = hostStatus.finishTime; + } host.exitStatus = hostStatus.exitStatus; host.errorMessage = hostStatus.errorMessage; } @@ -108,7 +110,7 @@ // 关闭连接 const closeClient = () => { // 关闭日志 - logContainer.value?.closeClient(); + logView.value?.closeClient(); // 清理轮询 clearAllInterval(); }; @@ -116,7 +118,7 @@ // 清理并且关闭 const closeAll = () => { // 关闭日志 - logContainer.value?.closeAll(); + logView.value?.closeAll(); // 清理轮询 clearAllInterval(); };