diff --git a/docs/about/change-log.md b/docs/about/change-log.md index 02538ad2..24e64007 100644 --- a/docs/about/change-log.md +++ b/docs/about/change-log.md @@ -14,6 +14,14 @@ * 执行 升级的 `bash` 脚本 * 进入 代码目录执行 `sh docker-upgrade.sh` 进行容器升级 `down` > `pull` > `up -d` +### v2.0.1 + +`2024-05-2` `release` + +* 🩰 修改 logo +* 🐞 修复 批量执行后日志偶尔不展示的问题 +* 🐞 修复 批量上传进度条显示异常的问题 + ### v2.0.0 `2024-05-17` `release` diff --git a/orion-visor-framework/orion-visor-spring-boot-starter-websocket/src/main/java/com/orion/visor/framework/websocket/core/session/WebSocketSyncSession.java b/orion-visor-framework/orion-visor-spring-boot-starter-websocket/src/main/java/com/orion/visor/framework/websocket/core/session/WebSocketSyncSession.java new file mode 100644 index 00000000..481fbf8f --- /dev/null +++ b/orion-visor-framework/orion-visor-spring-boot-starter-websocket/src/main/java/com/orion/visor/framework/websocket/core/session/WebSocketSyncSession.java @@ -0,0 +1,116 @@ +package com.orion.visor.framework.websocket.core.session; + +import org.springframework.http.HttpHeaders; +import org.springframework.web.socket.CloseStatus; +import org.springframework.web.socket.WebSocketExtension; +import org.springframework.web.socket.WebSocketMessage; +import org.springframework.web.socket.WebSocketSession; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.URI; +import java.security.Principal; +import java.util.List; +import java.util.Map; + +/** + * web socket 同步会话 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2024/5/20 10:12 + */ +public class WebSocketSyncSession implements WebSocketSession { + + private final WebSocketSession delegate; + + public WebSocketSyncSession(WebSocketSession delegate) { + this.delegate = delegate; + } + + @Override + public String getId() { + return this.delegate.getId(); + } + + @Override + public URI getUri() { + return this.delegate.getUri(); + } + + @Override + public HttpHeaders getHandshakeHeaders() { + return this.delegate.getHandshakeHeaders(); + } + + @Override + public Map getAttributes() { + return this.delegate.getAttributes(); + } + + @Override + public Principal getPrincipal() { + return this.delegate.getPrincipal(); + } + + @Override + public InetSocketAddress getLocalAddress() { + return this.delegate.getLocalAddress(); + } + + @Override + public InetSocketAddress getRemoteAddress() { + return this.delegate.getRemoteAddress(); + } + + @Override + public String getAcceptedProtocol() { + return this.delegate.getAcceptedProtocol(); + } + + @Override + public void setTextMessageSizeLimit(int messageSizeLimit) { + this.delegate.setTextMessageSizeLimit(messageSizeLimit); + } + + @Override + public int getTextMessageSizeLimit() { + return this.delegate.getTextMessageSizeLimit(); + } + + @Override + public void setBinaryMessageSizeLimit(int messageSizeLimit) { + this.delegate.setBinaryMessageSizeLimit(messageSizeLimit); + } + + @Override + public int getBinaryMessageSizeLimit() { + return this.delegate.getBinaryMessageSizeLimit(); + } + + @Override + public List getExtensions() { + return this.delegate.getExtensions(); + } + + @Override + public synchronized void sendMessage(WebSocketMessage message) throws IOException { + this.delegate.sendMessage(message); + } + + @Override + public boolean isOpen() { + return this.delegate.isOpen(); + } + + @Override + public void close() throws IOException { + this.delegate.close(); + } + + @Override + public void close(CloseStatus status) throws IOException { + this.delegate.close(status); + } + +} diff --git a/orion-visor-framework/orion-visor-spring-boot-starter-websocket/src/main/java/com/orion/visor/framework/websocket/core/utils/WebSockets.java b/orion-visor-framework/orion-visor-spring-boot-starter-websocket/src/main/java/com/orion/visor/framework/websocket/core/utils/WebSockets.java index 38aebc04..9177734b 100644 --- a/orion-visor-framework/orion-visor-spring-boot-starter-websocket/src/main/java/com/orion/visor/framework/websocket/core/utils/WebSockets.java +++ b/orion-visor-framework/orion-visor-spring-boot-starter-websocket/src/main/java/com/orion/visor/framework/websocket/core/utils/WebSockets.java @@ -3,7 +3,9 @@ package com.orion.visor.framework.websocket.core.utils; import com.alibaba.fastjson.JSON; import com.orion.lang.utils.Exceptions; import com.orion.lang.utils.Threads; +import com.orion.visor.framework.common.constant.Const; import com.orion.visor.framework.websocket.core.constant.WsCloseCode; +import com.orion.visor.framework.websocket.core.session.WebSocketSyncSession; import lombok.extern.slf4j.Slf4j; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.TextMessage; @@ -24,6 +26,16 @@ public class WebSockets { private WebSockets() { } + /** + * 创建同步会话 + * + * @param session session + * @return session + */ + public static WebSocketSession createSyncSession(WebSocketSession session) { + return new WebSocketSyncSession(session); + } + /** * 获取属性 * @@ -58,13 +70,13 @@ public class WebSockets { return; } try { - // 发重消息 + // 发送消息 session.sendMessage(new TextMessage(message)); } catch (IllegalStateException e) { // 并发异常 log.error("发送消息失败, 准备进行重试 {}", Exceptions.getDigest(e)); // 并发重试 - retrySendText(session, message, 50); + retrySendText(session, message, Const.MS_100); } catch (IOException e) { throw Exceptions.ioRuntime(e); } diff --git a/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/com/orion/visor/module/asset/handler/host/exec/log/ExecLogTailHandler.java b/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/com/orion/visor/module/asset/handler/host/exec/log/ExecLogTailHandler.java index 4be35660..ed538797 100644 --- a/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/com/orion/visor/module/asset/handler/host/exec/log/ExecLogTailHandler.java +++ b/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/com/orion/visor/module/asset/handler/host/exec/log/ExecLogTailHandler.java @@ -46,7 +46,10 @@ public class ExecLogTailHandler extends AbstractWebSocketHandler { String trackerId = this.getTrackerId(id, info, host); String absolutePath = logsFileClient.getAbsolutePath(host.getPath()); // 追踪器 - ExecLogTracker tracker = new ExecLogTracker(trackerId, absolutePath, session, host); + ExecLogTracker tracker = new ExecLogTracker(trackerId, + absolutePath, + WebSockets.createSyncSession(session), + host); // 执行 AssetThreadPools.EXEC_LOG.execute(tracker); // 添加追踪器 diff --git a/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/com/orion/visor/module/asset/handler/host/exec/log/tracker/ExecLogTracker.java b/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/com/orion/visor/module/asset/handler/host/exec/log/tracker/ExecLogTracker.java index 3ce8fd87..9d41baf0 100644 --- a/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/com/orion/visor/module/asset/handler/host/exec/log/tracker/ExecLogTracker.java +++ b/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/com/orion/visor/module/asset/handler/host/exec/log/tracker/ExecLogTracker.java @@ -5,6 +5,7 @@ import com.orion.ext.tail.delay.DelayTrackerListener; import com.orion.ext.tail.mode.FileNotFoundMode; import com.orion.ext.tail.mode.FileOffsetMode; import com.orion.spring.SpringHolder; +import com.orion.visor.framework.common.constant.Const; import com.orion.visor.framework.websocket.core.utils.WebSockets; import com.orion.visor.module.asset.define.config.AppTrackerConfig; import com.orion.visor.module.asset.entity.dto.ExecHostLogTailDTO; @@ -79,7 +80,20 @@ public class ExecLogTracker implements IExecLogTracker { @Override public void read(byte[] bytes, int len, Tracker tracker) { - WebSockets.sendText(session, config.getId() + LogConst.SEPARATOR + new String(bytes, 0, len)); + // 发送消息 + String message = config.getId() + LogConst.SEPARATOR + new String(bytes, 0, len); + try { + WebSockets.sendText(session, message); + return; + } catch (Exception e) { + log.error("ExecLogTracker.send error", e); + } + // 重试 + try { + WebSockets.retrySendText(session, message, Const.MS_100); + } catch (Exception e) { + log.error("ExecLogTracker.resend error fk", e); + } } @Override diff --git a/orion-visor-ui/src/components/app/app-footer/index.vue b/orion-visor-ui/src/components/app/app-footer/index.vue index 0fc6b73e..204f6be9 100644 --- a/orion-visor-ui/src/components/app/app-footer/index.vue +++ b/orion-visor-ui/src/components/app/app-footer/index.vue @@ -8,10 +8,10 @@ gitee 文档 License - v{{ version }} Community + V{{ version }} 社区版 - Copyright {{ new Date().getFullYear() }} Li Jiahang All rights reserved. + Copyright 2023 - {{ new Date().getFullYear() }} Li Jiahang, All rights reserved. diff --git a/orion-visor-ui/src/views/authentication/login/locale/zh-CN.ts b/orion-visor-ui/src/views/authentication/login/locale/zh-CN.ts index 5921b647..68045dd8 100644 --- a/orion-visor-ui/src/views/authentication/login/locale/zh-CN.ts +++ b/orion-visor-ui/src/views/authentication/login/locale/zh-CN.ts @@ -7,10 +7,10 @@ export default { 'login.form.userName.placeholder': '用户名', 'login.form.password.placeholder': '密码', 'login.form.login': '登录', - 'login.banner.slogan1': '开箱即用的一站式智能运维平台', - 'login.banner.subSlogan1': '一站式操作 智能运维 让运维变得更简单', - 'login.banner.slogan2': '内置权限角色管理', - 'login.banner.subSlogan2': '让每一次操作都安全可控可追溯', - 'login.banner.slogan3': '终端操作无障碍', - 'login.banner.subSlogan3': '高效稳定 远程操作 让工作更高效', + 'login.banner.slogan1': '现代化的智能运维平台', + 'login.banner.subSlogan1': '一站式操作 让运维变得更简单', + 'login.banner.slogan2': '高颜值的轻量堡垒机平台', + 'login.banner.subSlogan2': '内置批量处理模块 让工作更高效', + 'login.banner.slogan3': '动态权限角色管理', + 'login.banner.subSlogan3': '让每一次操作都可追溯', }; diff --git a/orion-visor-ui/src/views/exec/batch-upload/components/upload-panel.vue b/orion-visor-ui/src/views/exec/batch-upload/components/upload-panel.vue index e4c81fa9..ff438127 100644 --- a/orion-visor-ui/src/views/exec/batch-upload/components/upload-panel.vue +++ b/orion-visor-ui/src/views/exec/batch-upload/components/upload-panel.vue @@ -157,6 +157,7 @@ await cancelUploadTask(taskId.value, false); taskStatus.value = UploadTaskStepStatus.WAITING; Message.success('已取消'); + taskId.value = undefined; } catch (e) { } finally { setLoading(false); @@ -171,6 +172,8 @@ // 上传请求结束 const uploadRequestEnd = async () => { + // 上传请求结束后重置文件进度 + resetSelectedFileProgress(); if (taskStatus.value.value === UploadTaskStepStatus.REQUESTING.value) { // 如果结束后还是请求中则代表请求完毕 setLoading(true); @@ -196,6 +199,8 @@ // 上传请求失败 const uploadRequestError = async () => { + // 上传请求结束后重置文件进度 + resetSelectedFileProgress(); setLoading(true); try { // 开始上传 @@ -264,6 +269,11 @@ fileList.value = []; }; + // 重置选择的文件进度 + const resetSelectedFileProgress = () => { + fileList.value.forEach(s => s.percent = 0); + }; + // 设置轮询状态 onMounted(() => { pullIntervalId.value = setInterval(pullTaskStatus, 5000);