fix 节点管理功能迁移到资产管理中

This commit is contained in:
bwcx_jzy 2023-12-27 08:56:39 +08:00
parent 54f7c4df0a
commit e229879157
No known key found for this signature in database
GPG Key ID: E187D6E9DDDE8C53
26 changed files with 341 additions and 169 deletions

View File

@ -11,7 +11,9 @@
2. 【all】下架 全面下架项目副本功能(请使用 DSL 模式代替)
3. 【all】下架 全面节点证书管理功能(请使用工作空间证书代替)
4. 【all】下架 全下架节点 NGINX 管理功能(请使用 DSL 模式代替)
5. 【server】优化 节点管理仅保留项目管理、脚本管理、脚本日志(其他功能迁移到机器资产管理)
5. 【server】优化 **节点管理仅保留项目管理、脚本管理、脚本日志(其他功能迁移到机器资产管理)**
6. 【server】修复 项目复制按钮点击无响应
7. 【all】优化 查看插件端和服务端的系统日志 websocket 地址
### ⚠️ 注意

View File

@ -28,7 +28,6 @@ import cn.hutool.core.map.SafeConcurrentHashMap;
import cn.keepbx.jpom.model.JsonMessage;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.dromara.jpom.common.Const;
import org.dromara.jpom.system.AgentConfig;
import org.dromara.jpom.system.LogbackConfig;
import org.dromara.jpom.util.SocketSessionUtil;
@ -47,10 +46,10 @@ import java.util.Map;
* @author bwcx_jzy
* @since 2019/4/16
*/
@ServerEndpoint(value = "/tomcat_log")
@ServerEndpoint(value = "/system_log")
@Component
@Slf4j
public class AgentWebSocketTomcatHandle extends BaseAgentWebSocketHandle {
public class AgentWebSocketSystemLogHandle extends BaseAgentWebSocketHandle {
private static AgentConfig.SystemConfig systemConfig;
@ -58,7 +57,7 @@ public class AgentWebSocketTomcatHandle extends BaseAgentWebSocketHandle {
@Autowired
public void init(AgentConfig agentConfig) {
AgentWebSocketTomcatHandle.systemConfig = agentConfig.getSystem();
AgentWebSocketSystemLogHandle.systemConfig = agentConfig.getSystem();
}
@OnOpen
@ -67,14 +66,7 @@ public class AgentWebSocketTomcatHandle extends BaseAgentWebSocketHandle {
if (super.checkAuthorize(session)) {
return;
}
String tomcatId = super.getParameters(session, "tomcatId");
if (!Const.SYSTEM_ID.equalsIgnoreCase(tomcatId)) {
SocketSessionUtil.send(session, "获取tomcat信息错误");
session.close();
return;
}
SocketSessionUtil.send(session, "连接成功:");
SocketSessionUtil.send(session, "连接成功:插件端日志");
} catch (Exception e) {
log.error("socket 错误", e);
try {
@ -94,10 +86,7 @@ public class AgentWebSocketTomcatHandle extends BaseAgentWebSocketHandle {
if (consoleCommandOp == ConsoleCommandOp.heart) {
return;
}
String tomcatId = json.getString("tomcatId");
if (Const.SYSTEM_ID.equalsIgnoreCase(tomcatId)) {
runMsg(session, json);
}
runMsg(session, json);
}
private void runMsg(Session session, JSONObject reqJson) throws Exception {

View File

@ -78,11 +78,17 @@ public abstract class BaseServerController extends BaseJpomController {
return nodeService.getByKey(nodeId);
}
protected <T> JsonMessage<T> tryRequestNode(String machineId, HttpServletRequest request, NodeUrl nodeUrl, String... pars) {
NodeModel nodeModel = tryGetNode();
if (nodeModel != null) {
return NodeForward.request(nodeModel, request, nodeUrl, new String[]{}, pars);
}
/**
* 判断是否传入机器 id
*
* @param machineId 机器id
* @param request 请求
* @param nodeUrl 节点 url
* @param pars 参数
* @param <T> 泛型
* @return data
*/
protected <T> JsonMessage<T> tryRequestMachine(String machineId, HttpServletRequest request, NodeUrl nodeUrl, String... pars) {
if (StrUtil.isNotEmpty(machineId)) {
MachineNodeModel model = machineNodeServer.getByKey(machineId);
Assert.notNull(model, "没有找到对应的机器");

View File

@ -62,9 +62,9 @@ public enum NodeUrl {
*/
FreeScriptRun("/free-script-run"),
/**
* Tomcat
* 系统日志
*/
Tomcat_Socket("/tomcat_log"),
Socket_SystemLog("/system_log"),
/**
* 节点升级
*/

View File

@ -112,7 +112,7 @@ public class WhitelistDirectoryController extends BaseServerController {
@RequestMapping(value = "whitelistDirectory_submit", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
@SystemPermission
public IJsonMessage<String> whitelistDirectorySubmit(HttpServletRequest request, String machineId) {
JsonMessage<String> objectJsonMessage = this.tryRequestNode(machineId, request, NodeUrl.WhitelistDirectory_Submit);
JsonMessage<String> objectJsonMessage = this.tryRequestMachine(machineId, request, NodeUrl.WhitelistDirectory_Submit);
Assert.notNull(objectJsonMessage, "请选择节点");
return objectJsonMessage;
}

View File

@ -30,12 +30,12 @@ import cn.hutool.core.io.FileUtil;
import cn.keepbx.jpom.IJsonMessage;
import cn.keepbx.jpom.event.ICacheTask;
import cn.keepbx.jpom.model.JsonMessage;
import com.alibaba.fastjson2.JSONObject;
import org.dromara.jpom.JpomApplication;
import org.dromara.jpom.build.BuildExecuteManage;
import org.dromara.jpom.build.BuildUtil;
import org.dromara.jpom.common.BaseServerController;
import org.dromara.jpom.common.JpomManifest;
import org.dromara.jpom.common.forward.NodeForward;
import org.dromara.jpom.common.forward.NodeUrl;
import org.dromara.jpom.common.validator.ValidatorItem;
import org.dromara.jpom.common.validator.ValidatorRule;
@ -134,8 +134,14 @@ public class CacheManageController extends BaseServerController implements ICach
*/
@RequestMapping(value = "node_cache.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.LIST)
public String nodeCache(HttpServletRequest request) {
return NodeForward.request(getNode(), request, NodeUrl.Cache).toString();
public IJsonMessage<JSONObject> nodeCache(HttpServletRequest request, @ValidatorItem String machineId) {
return this.tryRequestMachine(machineId, request, NodeUrl.Cache);
// return Optional.ofNullable(message).orElseGet(() -> {
// List<JSONObject> data = DirTreeUtil.getTreeData(LogbackConfig.getPath());
// return JsonMessage.success("", data);
// });
// return NodeForward.request(getNode(), request, NodeUrl.Cache).toString();
}
/**
@ -146,7 +152,9 @@ public class CacheManageController extends BaseServerController implements ICach
*/
@RequestMapping(value = "clearCache.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.DEL)
public IJsonMessage<String> clearCache(@ValidatorItem(value = ValidatorRule.NOT_BLANK, msg = "类型错误") String type, HttpServletRequest request) {
public IJsonMessage<String> clearCache(@ValidatorItem(value = ValidatorRule.NOT_BLANK, msg = "类型错误") String type,
String machineId,
HttpServletRequest request) {
switch (type) {
case "serviceCacheFileSize": {
File tempPath = JpomApplication.getInstance().getTempPath();
@ -164,8 +172,7 @@ public class CacheManageController extends BaseServerController implements ICach
break;
}
default:
return NodeForward.request(getNode(), request, NodeUrl.ClearCache);
return this.tryRequestMachine(machineId, request, NodeUrl.ClearCache);
}
return JsonMessage.success("清空成功");
}

View File

@ -50,6 +50,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
/**
@ -67,12 +68,12 @@ public class LogManageController extends BaseServerController {
@RequestMapping(value = "log_data.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.LIST)
public IJsonMessage<List<JSONObject>> logData(String nodeId) {
if (StrUtil.isNotEmpty(nodeId)) {
return NodeForward.request(getNode(), getRequest(), NodeUrl.SystemLog);
}
List<JSONObject> data = DirTreeUtil.getTreeData(LogbackConfig.getPath());
return JsonMessage.success("", data);
public IJsonMessage<List<JSONObject>> logData(String machineId, HttpServletRequest request) {
IJsonMessage<List<JSONObject>> message = this.tryRequestMachine(machineId, request, NodeUrl.SystemLog);
return Optional.ofNullable(message).orElseGet(() -> {
List<JSONObject> data = DirTreeUtil.getTreeData(LogbackConfig.getPath());
return JsonMessage.success("", data);
});
}
/**
@ -85,7 +86,7 @@ public class LogManageController extends BaseServerController {
@RequestMapping(value = "log_del.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.DEL)
public IJsonMessage<String> logData(String nodeId,
@ValidatorItem(value = ValidatorRule.NOT_BLANK, msg = "path错误") String path) {
@ValidatorItem(value = ValidatorRule.NOT_BLANK, msg = "path错误") String path) {
if (StrUtil.isNotEmpty(nodeId)) {
return NodeForward.request(getNode(), getRequest(), NodeUrl.DelSystemLog);
}

View File

@ -108,7 +108,7 @@ public class SystemConfigController extends BaseServerController {
@RequestMapping(value = "config-data", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.LIST)
public IJsonMessage<JSONObject> configData(String machineId, HttpServletRequest request) {
IJsonMessage<JSONObject> message = this.tryRequestNode(machineId, request, NodeUrl.SystemGetConfig);
IJsonMessage<JSONObject> message = this.tryRequestMachine(machineId, request, NodeUrl.SystemGetConfig);
return Optional.ofNullable(message).orElseGet(() -> {
JSONObject jsonObject = new JSONObject();
Resource resource = ExtConfigBean.getResource();
@ -127,7 +127,7 @@ public class SystemConfigController extends BaseServerController {
@Feature(method = MethodFeature.EDIT)
@SystemPermission(superUser = true)
public IJsonMessage<String> saveConfig(String machineId, String content, String restart, HttpServletRequest request) throws SQLException, IOException {
JsonMessage<String> jsonMessage = this.tryRequestNode(machineId, request, NodeUrl.SystemSaveConfig);
JsonMessage<String> jsonMessage = this.tryRequestMachine(machineId, request, NodeUrl.SystemSaveConfig);
if (jsonMessage != null) {
return jsonMessage;
}

View File

@ -40,7 +40,6 @@ import org.dromara.jpom.common.*;
import org.dromara.jpom.common.forward.NodeForward;
import org.dromara.jpom.common.forward.NodeUrl;
import org.dromara.jpom.func.assets.model.MachineNodeModel;
import org.dromara.jpom.model.data.NodeModel;
import org.dromara.jpom.permission.ClassFeature;
import org.dromara.jpom.permission.Feature;
import org.dromara.jpom.permission.MethodFeature;
@ -96,7 +95,7 @@ public class SystemUpdateController extends BaseServerController implements ILoa
@PostMapping(value = "info", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.LIST)
public IJsonMessage<JSONObject> info(HttpServletRequest request, String machineId) {
IJsonMessage<JSONObject> message = this.tryRequestNode(machineId, request, NodeUrl.Info);
IJsonMessage<JSONObject> message = this.tryRequestMachine(machineId, request, NodeUrl.Info);
return Optional.ofNullable(message).orElseGet(() -> {
JpomManifest instance = JpomManifest.getInstance();
cn.keepbx.jpom.RemoteVersion remoteVersion = RemoteVersion.cacheInfo();
@ -132,7 +131,7 @@ public class SystemUpdateController extends BaseServerController implements ILoa
@PostMapping(value = "change_log", produces = MediaType.APPLICATION_JSON_VALUE)
public IJsonMessage<String> changeLog(HttpServletRequest request, String machineId) {
boolean betaRelease = RemoteVersion.betaRelease();
JsonMessage<String> message = this.tryRequestNode(machineId, request, NodeUrl.CHANGE_LOG, "beta", String.valueOf(betaRelease));
JsonMessage<String> message = this.tryRequestMachine(machineId, request, NodeUrl.CHANGE_LOG, "beta", String.valueOf(betaRelease));
if (message != null) {
return message;
}
@ -150,17 +149,12 @@ public class SystemUpdateController extends BaseServerController implements ILoa
@PostMapping(value = "upload-jar-sharding", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.EXECUTE, log = false)
public IJsonMessage<String> uploadJarSharding(MultipartFile file,
String machineId,
String sliceId,
Integer totalSlice,
Integer nowSlice,
String fileSumMd5) throws IOException {
String machineId,
String sliceId,
Integer totalSlice,
Integer nowSlice,
String fileSumMd5) throws IOException {
MultipartHttpServletRequest multiRequest = getMultiRequest();
NodeModel nodeModel = tryGetNode();
if (nodeModel != null) {
Assert.state(BaseServerController.SHARDING_IDS.containsKey(sliceId), "不合法的分片id");
return NodeForward.requestMultipart(nodeModel, multiRequest, NodeUrl.SystemUploadJar);
}
if (StrUtil.isNotEmpty(machineId)) {
MachineNodeModel model = machineNodeServer.getByKey(machineId);
Assert.notNull(model, "没有找到对应的机器");
@ -174,11 +168,11 @@ public class SystemUpdateController extends BaseServerController implements ILoa
@PostMapping(value = "upload-jar-sharding-merge", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.EXECUTE)
public IJsonMessage<String> uploadJar(String sliceId,
Integer totalSlice,
String fileSumMd5,
HttpServletRequest request,
String machineId) throws IOException {
JsonMessage<String> message = this.tryRequestNode(machineId, request, NodeUrl.SystemUploadJarMerge);
Integer totalSlice,
String fileSumMd5,
HttpServletRequest request,
String machineId) throws IOException {
JsonMessage<String> message = this.tryRequestMachine(machineId, request, NodeUrl.SystemUploadJarMerge);
if (message != null) {
// 判断-删除分片id
BaseServerController.SHARDING_IDS.remove(sliceId);
@ -215,8 +209,8 @@ public class SystemUpdateController extends BaseServerController implements ILoa
*/
@PostMapping(value = "check_version.json", produces = MediaType.APPLICATION_JSON_VALUE)
public IJsonMessage<cn.keepbx.jpom.RemoteVersion> checkVersion(HttpServletRequest request,
String machineId) {
IJsonMessage<cn.keepbx.jpom.RemoteVersion> message = this.tryRequestNode(machineId, request, NodeUrl.CHECK_VERSION);
String machineId) {
IJsonMessage<cn.keepbx.jpom.RemoteVersion> message = this.tryRequestMachine(machineId, request, NodeUrl.CHECK_VERSION);
return Optional.ofNullable(message).orElseGet(() -> {
cn.keepbx.jpom.RemoteVersion remoteVersion = RemoteVersion.loadRemoteInfo();
return JsonMessage.success("", remoteVersion);
@ -232,9 +226,9 @@ public class SystemUpdateController extends BaseServerController implements ILoa
@GetMapping(value = "remote_upgrade.json", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.DOWNLOAD)
public IJsonMessage<String> upgrade(HttpServletRequest request,
String machineId) throws IOException {
String machineId) throws IOException {
IJsonMessage<String> message = this.tryRequestNode(machineId, request, NodeUrl.REMOTE_UPGRADE);
IJsonMessage<String> message = this.tryRequestMachine(machineId, request, NodeUrl.REMOTE_UPGRADE);
return Optional.ofNullable(message).orElseGet(() -> {
try {
RemoteVersion.upgrade(JpomApplication.getInstance().getTempPath().getAbsolutePath(), objects -> backupInfoService.autoBackup());

View File

@ -69,8 +69,10 @@ public abstract class BaseHandler extends TextWebSocketHandler {
protected void showHelloMsg(Map<String, Object> attributes, WebSocketSession session) {
UserModel userInfo = (UserModel) attributes.get("userInfo");
String payload = StrUtil.format("欢迎加入:{} 会话id:{} ", userInfo.getName(), session.getId() + StrUtil.CRLF);
this.sendMsg(session, payload);
if (userInfo != null) {
String payload = StrUtil.format("欢迎加入:{} 会话id:{} ", userInfo.getName(), session.getId() + StrUtil.CRLF);
this.sendMsg(session, payload);
}
}
/**

View File

@ -27,6 +27,8 @@ import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.dromara.jpom.common.forward.NodeForward;
import org.dromara.jpom.common.forward.NodeUrl;
import org.dromara.jpom.func.assets.model.MachineNodeModel;
import org.dromara.jpom.model.BaseWorkspaceModel;
import org.dromara.jpom.model.data.NodeModel;
import org.dromara.jpom.transport.*;
import org.dromara.jpom.util.SocketSessionUtil;
@ -36,6 +38,7 @@ import org.springframework.web.socket.WebSocketSession;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Map;
import java.util.Optional;
/**
* 服务端socket 基本类
@ -81,23 +84,31 @@ public abstract class BaseProxyHandler extends BaseHandler {
return;
}
NodeModel nodeModel = (NodeModel) attributes.get("nodeInfo");
// UserModel userInfo = (UserModel) attributes.get("userInfo");
MachineNodeModel machine = (MachineNodeModel) attributes.get("machine");
if (nodeModel != null) {
Object[] parameters = this.getParameters(attributes);
// 连接节点
INodeInfo nodeInfo = NodeForward.parseNodeInfo(nodeModel);
IUrlItem urlItem = NodeForward.parseUrlItem(nodeInfo, nodeModel.getWorkspaceId(), this.nodeUrl, DataContentType.FORM_URLENCODED);
IProxyWebSocket proxySession = TransportServerFactory.get().websocket(nodeInfo, urlItem, parameters);
proxySession.onMessage(s -> sendMsg(session, s));
if (!proxySession.connectBlocking()) {
this.sendMsg(session, "插件端连接失败");
this.destroy(session);
return;
}
session.getAttributes().put("proxySession", proxySession);
Object[] parameters = this.getParameters(attributes);
// 连接节点
INodeInfo nodeInfo = Optional.ofNullable(machine)
.map(NodeForward::coverNodeInfo)
.orElseGet(() -> Optional.ofNullable(nodeModel)
.map(NodeForward::parseNodeInfo)
.orElse(null)
);
if (nodeInfo == null) {
return;
}
String workspaceId = Optional.ofNullable(nodeModel).map(BaseWorkspaceModel::getWorkspaceId).orElse(StrUtil.EMPTY);
IUrlItem urlItem = NodeForward.parseUrlItem(nodeInfo, workspaceId, this.nodeUrl, DataContentType.FORM_URLENCODED);
IProxyWebSocket proxySession = TransportServerFactory.get().websocket(nodeInfo, urlItem, parameters);
proxySession.onMessage(s -> sendMsg(session, s));
if (!proxySession.connectBlocking()) {
this.sendMsg(session, "插件端连接失败");
this.destroy(session);
return;
}
session.getAttributes().put("proxySession", proxySession);
attributes.put("init", true);
}

View File

@ -45,9 +45,13 @@ public enum HandlerType {
*/
nodeScript(NodeScriptHandler.class, NodeScriptServer.class),
/**
* tomcat
* 系统日志
*/
tomcat(TomcatHandler.class, null),
systemLog(SystemLogHandler.class, null),
/**
* 插件端日志
*/
agentLog(AgentLogHandler.class, null),
/**
* 项目控制台和首页监控
*/

View File

@ -63,8 +63,11 @@ public class ServerWebSocketConfig implements WebSocketConfigurer {
// 节点脚本模板
registry.addHandler(new NodeScriptHandler(), "/socket/node/script_run")
.addInterceptors(serverWebSocketInterceptor).setAllowedOrigins("*");
// tomcat
registry.addHandler(new TomcatHandler(), "/socket/tomcat_log")
// 系统日志
registry.addHandler(new SystemLogHandler(), "/socket/system_log")
.addInterceptors(serverWebSocketInterceptor).setAllowedOrigins("*");
// 插件端日志
registry.addHandler(new AgentLogHandler(), "/socket/agent_log")
.addInterceptors(serverWebSocketInterceptor).setAllowedOrigins("*");
// ssh
registry.addHandler(new SshHandler(), "/socket/ssh")

View File

@ -31,9 +31,12 @@ import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.extra.spring.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.dromara.jpom.common.Const;
import org.dromara.jpom.common.ServerConst;
import org.dromara.jpom.common.interceptor.PermissionInterceptor;
import org.dromara.jpom.func.assets.model.MachineNodeModel;
import org.dromara.jpom.func.assets.server.MachineNodeServer;
import org.dromara.jpom.model.BaseWorkspaceModel;
import org.dromara.jpom.model.data.NodeModel;
import org.dromara.jpom.model.user.UserBindWorkspaceModel;
@ -71,13 +74,16 @@ public class ServerWebSocketInterceptor implements HandshakeInterceptor {
private final UserService userService;
private final NodeService nodeService;
private final UserBindWorkspaceService userBindWorkspaceService;
private final MachineNodeServer machineNodeServer;
public ServerWebSocketInterceptor(UserService userService,
NodeService nodeService,
UserBindWorkspaceService userBindWorkspaceService) {
UserBindWorkspaceService userBindWorkspaceService,
MachineNodeServer machineNodeServer) {
this.userService = userService;
this.nodeService = nodeService;
this.userBindWorkspaceService = userBindWorkspaceService;
this.machineNodeServer = machineNodeServer;
}
private boolean checkNode(HttpServletRequest httpServletRequest, Map<String, Object> attributes, UserModel userModel) {
@ -91,6 +97,19 @@ public class ServerWebSocketInterceptor implements HandshakeInterceptor {
//
attributes.put("nodeInfo", nodeModel);
}
// 验证机器权限
String machineId = httpServletRequest.getParameter("machineId");
if (StringUtils.isNotEmpty(machineId)) {
if (!userModel.isSystemUser()) {
// 没有权限
return false;
}
MachineNodeModel machine = machineNodeServer.getByKey(machineId);
if (machine == null) {
return false;
}
attributes.put("machine", machine);
}
return true;
}
@ -137,10 +156,8 @@ public class ServerWebSocketInterceptor implements HandshakeInterceptor {
attributes.put("scriptId", BeanUtil.getProperty(dataItem, "id"));
break;
}
case tomcat:
String tomcatId = httpServletRequest.getParameter("tomcatId");
attributes.put("tomcatId", tomcatId);
case systemLog:
case agentLog:
break;
case dockerLog: {
Tuple dataItem = this.checkAssetsData(handlerType, userModel, httpServletRequest);
@ -194,12 +211,16 @@ public class ServerWebSocketInterceptor implements HandshakeInterceptor {
attributes.put("permissionMsg", "用户不存在");
return true;
}
boolean checkNode = this.checkNode(httpServletRequest, attributes, userModel);
HandlerType handlerType = this.fromType(httpServletRequest);
if (!checkNode || handlerType == null) {
if (handlerType == null) {
attributes.put("permissionMsg", "未匹配到合适的处理类型");
return true;
}
boolean checkNode = this.checkNode(httpServletRequest, attributes, userModel);
if (!checkNode) {
attributes.put("permissionMsg", "未匹配到合适的权限不足");
return true;
}
if (!this.checkHandlerType(handlerType, userModel, httpServletRequest, attributes)) {
attributes.put("permissionMsg", "未找到匹配的数据");
return true;

View File

@ -0,0 +1,62 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Code Technology Studio
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package org.dromara.jpom.socket.handler;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.dromara.jpom.common.forward.NodeUrl;
import org.dromara.jpom.permission.ClassFeature;
import org.dromara.jpom.permission.Feature;
import org.dromara.jpom.permission.MethodFeature;
import org.dromara.jpom.socket.BaseProxyHandler;
import org.dromara.jpom.socket.ConsoleCommandOp;
import org.dromara.jpom.transport.IProxyWebSocket;
import java.io.IOException;
import java.util.Map;
/**
* 插件端系统日志消息控制器
*
* @author bwcx_jzy
* @since 2023/12/26
*/
@Feature(cls = ClassFeature.AGENT_LOG, method = MethodFeature.EXECUTE)
@Slf4j
public class AgentLogHandler extends BaseProxyHandler {
public AgentLogHandler() {
super(NodeUrl.Socket_SystemLog);
}
@Override
protected Object[] getParameters(Map<String, Object> attributes) {
return new Object[]{};
}
@Override
protected String handleTextMessage(Map<String, Object> attributes, IProxyWebSocket proxySession, JSONObject json, ConsoleCommandOp consoleCommandOp) throws IOException {
proxySession.send(json.toString());
return null;
}
}

View File

@ -25,8 +25,6 @@ package org.dromara.jpom.socket.handler;
import cn.hutool.core.io.FileUtil;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.dromara.jpom.common.Const;
import org.dromara.jpom.common.forward.NodeUrl;
import org.dromara.jpom.permission.ClassFeature;
import org.dromara.jpom.permission.Feature;
import org.dromara.jpom.permission.MethodFeature;
@ -34,7 +32,6 @@ import org.dromara.jpom.socket.BaseProxyHandler;
import org.dromara.jpom.socket.ConsoleCommandOp;
import org.dromara.jpom.socket.ServiceFileTailWatcher;
import org.dromara.jpom.system.LogbackConfig;
import org.dromara.jpom.transport.IProxyWebSocket;
import org.dromara.jpom.util.SocketSessionUtil;
import org.springframework.web.socket.WebSocketSession;
@ -48,24 +45,24 @@ import java.util.Map;
* @author bwcx_jzy
* @since 2019/4/24
*/
@Feature(cls = ClassFeature.AGENT_LOG, method = MethodFeature.EXECUTE)
@Feature(cls = ClassFeature.SYSTEM_LOG, method = MethodFeature.EXECUTE)
@Slf4j
public class TomcatHandler extends BaseProxyHandler {
public class SystemLogHandler extends BaseProxyHandler {
public TomcatHandler() {
super(NodeUrl.Tomcat_Socket);
public SystemLogHandler() {
super(null);
}
@Override
protected Object[] getParameters(Map<String, Object> attributes) {
return new Object[]{"tomcatId", attributes.get("tomcatId")};
return new Object[]{};
}
@Override
protected String handleTextMessage(Map<String, Object> attributes, WebSocketSession session, JSONObject json, ConsoleCommandOp consoleCommandOp) throws IOException {
String tomcatId = (String) attributes.get("tomcatId");
String fileName = json.getString("fileName");
if (!Const.SYSTEM_ID.equals(tomcatId) && consoleCommandOp == ConsoleCommandOp.heart) {
if (consoleCommandOp == ConsoleCommandOp.heart) {
// 服务端心跳
return null;
}
@ -73,7 +70,7 @@ public class TomcatHandler extends BaseProxyHandler {
super.logOpt(this.getClass(), attributes, json);
//
if (consoleCommandOp == ConsoleCommandOp.showlog && Const.SYSTEM_ID.equals(tomcatId)) {
if (consoleCommandOp == ConsoleCommandOp.showlog) {
// 进入管理页面后需要实时加载日志
File file = FileUtil.file(LogbackConfig.getPath(), fileName);
@ -94,12 +91,6 @@ public class TomcatHandler extends BaseProxyHandler {
return null;
}
@Override
protected String handleTextMessage(Map<String, Object> attributes, IProxyWebSocket proxySession, JSONObject json, ConsoleCommandOp consoleCommandOp) throws IOException {
proxySession.send(json.toString());
return null;
}
@Override
public void destroy(WebSocketSession session) {
super.destroy(session);

View File

@ -48,11 +48,11 @@ export function getServerCache() {
* 节点缓存数据
* @param {String} nodeId
*/
export function getNodeCache(nodeId) {
export function getNodeCache(data) {
return axios({
url: "/system/node_cache.json",
method: "post",
data: { nodeId },
data,
});
}

View File

@ -21,6 +21,7 @@
v-model="current"
:tabBarStyle="{
margin: '0',
borderBottom: '0',
}"
>
<a-tab-pane key="project" tab="项目管理"></a-tab-pane>

View File

@ -1,6 +1,6 @@
<template>
<div class="node-full-content">
<a-tabs default-active-key="1">
<a-tabs default-active-key="1" tab-position="left">
<a-tab-pane key="1" tab="缓存信息">
<a-alert message="请勿手动删除数据目录下面文件,如果需要删除需要提前备份或者已经确定对应文件弃用后才能删除" style="margin-top: 10px; margin-bottom: 40px" banner />
<a-timeline>
@ -53,7 +53,7 @@
</a-timeline-item>
</a-timeline>
</a-tab-pane>
<a-tab-pane key="2" tab="运行中的定时任务"> <task-stat :taskList="taskList" @refresh="loadData" /></a-tab-pane>
<a-tab-pane key="2" tab="定时任务"> <task-stat :taskList="taskList" @refresh="loadData" /></a-tab-pane>
</a-tabs>
</div>
</template>
@ -66,8 +66,8 @@ export default {
TaskStat,
},
props: {
node: {
type: Object,
machineId: {
type: String,
},
},
data() {
@ -84,7 +84,9 @@ export default {
renderSize,
// load data
loadData() {
getNodeCache(this.node.id).then((res) => {
getNodeCache({
machineId: this.machineId,
}).then((res) => {
if (res.code === 200) {
this.temp = res.data;
this.taskList = res.data?.taskList;
@ -95,7 +97,7 @@ export default {
clear(type) {
const params = {
type: type,
nodeId: this.node.id,
machineId: this.machineId,
};
clearCache(params).then((res) => {
if (res.code === 200) {

View File

@ -24,8 +24,8 @@ export default {
codeEditor,
},
props: {
node: {
type: Object,
machineId: {
type: String,
},
},
data() {
@ -44,7 +44,7 @@ export default {
methods: {
// load data
loadData() {
getConfigData({ nodeId: this.node.id }).then((res) => {
getConfigData({ machineId: this.machineId }).then((res) => {
if (res.code === 200) {
this.temp.content = res.data;
this.temp.content = res.data.content;
@ -56,7 +56,7 @@ export default {
onSubmit(restart) {
// disabled submit button
this.submitAble = true;
this.temp.nodeId = this.node.id;
this.temp.machineId = this.machineId;
this.temp.restart = restart;
editConfig(this.temp).then((res) => {
if (res.code === 200) {
@ -81,7 +81,7 @@ export default {
setTimeout(() => {
//
this.timer = setInterval(() => {
systemInfo(this.node.id)
systemInfo(this.machineId)
.then((res) => {
if (res.code === 200) {
clearInterval(this.timer);

View File

@ -43,8 +43,8 @@ export default {
LogView,
},
props: {
node: {
type: Object,
machineId: {
type: String,
},
},
data() {
@ -53,7 +53,7 @@ export default {
socket: null,
//
logContext: "choose file loading context...",
tomcatId: "system",
replaceFields: {
children: "children",
title: "title",
@ -64,9 +64,9 @@ export default {
};
},
computed: {
...mapGetters(["getLongTermToken", "getWorkspaceId"]),
...mapGetters(["getLongTermToken"]),
socketUrl() {
return getWebSocketUrl("/socket/tomcat_log", `userId=${this.getLongTermToken}&tomcatId=${this.tomcatId}&nodeId=${this.node.id}&type=tomcat&workspaceId=${this.getWorkspaceId}`);
return getWebSocketUrl("/socket/agent_log", `userId=${this.getLongTermToken}&machineId=${this.machineId}&nodeId=system&type=agentLog`);
},
},
watch: {},
@ -87,7 +87,7 @@ export default {
//
loadData() {
this.list = [];
const params = { nodeId: this.node.id };
const params = { machineId: this.machineId };
getLogList(params).then((res) => {
if (res.code === 200) {
res.data.forEach((element) => {
@ -163,7 +163,7 @@ export default {
downloadLog() {
//
const params = {
nodeId: this.node.id,
machineId: this.machineId,
path: this.temp.path,
};
// blob
@ -178,7 +178,7 @@ export default {
cancelText: "取消",
onOk: () => {
const params = {
nodeId: this.node.id,
machineId: this.machineId,
path: this.temp.path,
};
//

View File

@ -28,8 +28,8 @@ import { editWhiteList, getWhiteList } from "@/api/node-system";
export default {
props: {
node: {
type: Object,
machineId: {
type: String,
},
},
data() {
@ -45,7 +45,7 @@ export default {
// load data
loadData() {
getWhiteList({
nodeId: this.node.id,
machineId: this.machineId,
}).then((res) => {
if (res.code === 200) {
this.temp = res.data;
@ -56,7 +56,7 @@ export default {
onSubmit() {
// disabled submit button
this.submitAble = true;
this.temp.nodeId = this.node.id;
this.temp.machineId = this.machineId;
editWhiteList(this.temp).then((res) => {
if (res.code === 200) {
//

View File

@ -0,0 +1,83 @@
<template>
<a-drawer
destroyOnClose
placement="right"
:width="`${this.getCollapsed ? 'calc(100vw - 80px)' : 'calc(100vw - 200px)'}`"
:visible="true"
@close="
() => {
$emit('close');
}
"
>
<template slot="title">
<a-space>
{{ name }}
<div style="display: inline-block">
<a-tabs
v-model="current"
:tabBarStyle="{
margin: '0',
borderBottom: '0',
}"
>
<a-tab-pane key="info" tab="基本信息"></a-tab-pane>
<a-tab-pane key="cache" tab="缓存监控"></a-tab-pane>
<a-tab-pane key="config" tab="系统配置"></a-tab-pane>
<a-tab-pane key="path-config" tab="授权配置"></a-tab-pane>
<a-tab-pane key="upgrade" tab="在线升级"></a-tab-pane>
<a-tab-pane key="log" tab="系统日志"></a-tab-pane>
</a-tabs>
</div>
</a-space>
</template>
<!-- 机器信息组件 -->
<machine-info v-if="current === 'info'" :machineId="machineId" />
<upgrade v-if="current === 'upgrade'" :machineId="machineId" />
<white-list v-if="current === 'path-config'" :machineId="machineId" />
<cache v-if="current === 'cache'" :machineId="machineId" />
<log v-if="current === 'log'" :machineId="machineId" />
<config-file v-if="current === 'config'" :machineId="machineId" />
</a-drawer>
</template>
<script>
import { mapGetters } from "vuex";
import machineInfo from "./machine-info";
import upgrade from "@/components/upgrade";
import WhiteList from "@/pages/node/node-layout/system/white-list.vue";
import Cache from "@/pages/node/node-layout/system/cache";
import Log from "@/pages/node/node-layout/system/log.vue";
import ConfigFile from "@/pages/node/node-layout/system/config-file.vue";
export default {
props: {
machineId: {
type: String,
},
name: {
type: String,
},
tab: {
type: String,
default: "",
},
},
components: {
machineInfo,
upgrade,
WhiteList,
Cache,
ConfigFile,
Log,
},
computed: {
...mapGetters(["getCollapsed"]),
},
data() {
return {
current: this.tab || "info",
};
},
mounted() {},
};
</script>

View File

@ -1,12 +1,12 @@
<template>
<div>
<a-tabs @change="changeTabs">
<a-tabs @change="changeTabs" tab-position="left">
<template slot="tabBarExtraContent">
<a-space>
<a-statistic-countdown format=" s 秒" title="刷新倒计时" :value="countdownTime" @finish="pullNodeData" />
<a-statistic-countdown format=" s 秒后刷新" title="" :value="countdownTime" @finish="pullNodeData" />
</a-space>
</template>
<a-tab-pane key="info" tab="信息">
<a-tab-pane key="info" tab="基础信息">
<a-card size="small">
<template slot="title">
{{ machineInfo && machineInfo.name }}
@ -122,7 +122,7 @@
</a-card>
</a-space>
</a-tab-pane>
<a-tab-pane key="process" tab="进程">
<a-tab-pane key="process" tab="系统进程">
<a-card size="small">
<template #title>
<a-row>
@ -214,7 +214,7 @@
</a-table>
</a-table>
</a-tab-pane>
<a-tab-pane key="networkInterfaces" tab="网">
<a-tab-pane key="networkInterfaces" tab="网卡信息">
<a-collapse v-if="networkInterfaces && networkInterfaces.length">
<a-collapse-panel :key="index" v-for="(item, index) in networkInterfaces">
<template #header>

View File

@ -262,21 +262,30 @@
</a-form-model>
</a-modal>
<!-- 机器信息组件 -->
<a-drawer
destroyOnClose
title="机器详情"
placement="right"
:width="`${this.getCollapsed ? 'calc(100vw - 80px)' : 'calc(100vw - 200px)'}`"
:visible="drawerVisible"
<machine-info
v-if="drawerVisible"
:machineId="temp.id"
:name="temp.name"
@close="
() => {
this.drawerVisible = false;
}
"
>
<!-- 机器信息组件 -->
<machine-info v-if="drawerVisible" :machineId="temp.id" />
</a-drawer>
/>
<!-- 机器在线升级相关信息 -->
<machine-info
v-if="drawerUpgradeVisible"
:machineId="temp.id"
:name="temp.name"
tab="upgrade"
@close="
() => {
this.drawerUpgradeVisible = false;
}
"
/>
<!-- 分配到其他工作空间 -->
<a-modal destroyOnClose v-model="syncToWorkspaceVisible" title="分配到其他工作空间" @ok="handleSyncToWorkspace" :maskClosable="false">
<!-- <a-alert message="温馨提示" type="warning">
@ -291,22 +300,7 @@
</a-form-model-item>
</a-form-model>
</a-modal>
<!-- 机器在线升级相关信息 -->
<a-drawer
destroyOnClose
:title="`${temp.name} 插件版本信息`"
placement="right"
:width="`${this.getCollapsed ? 'calc(100vw - 80px)' : 'calc(100vw - 200px)'}`"
:visible="drawerUpgradeVisible"
@close="
() => {
this.drawerUpgradeVisible = false;
}
"
>
<!-- 在线升级 -->
<upgrade v-if="drawerUpgradeVisible" :machineId="temp.id" />
</a-drawer>
<!-- 查看机器关联节点 -->
<a-modal destroyOnClose v-model="viewLinkNode" width="50%" title="关联节点" :footer="null" :maskClosable="false">
<a-list bordered :data-source="nodeList">
@ -387,10 +381,10 @@ import {
import { CHANGE_PAGE, COMPUTED_PAGINATION, PAGE_DEFAULT_LIST_QUERY, PAGE_DEFAULT_SHOW_TOTAL, formatDuration, parseTime, formatPercent2Number, getCachePageLimit } from "@/utils/const";
import CustomSelect from "@/components/customSelect";
import { mapGetters } from "vuex";
import machineInfo from "./machine-info.vue";
import machineInfo from "./machine-func";
import { getWorkSpaceListAll } from "@/api/workspace";
// import Upgrade from "@/pages/node/node-layout/system/upgrade.vue";
import upgrade from "@/components/upgrade";
import { getWhiteList } from "@/api/node-system";
import { getConfigData } from "@/api/system";
import codeEditor from "@/components/codeEditor";
@ -399,7 +393,7 @@ export default {
components: {
CustomSelect,
machineInfo,
upgrade,
codeEditor,
},
data() {

View File

@ -47,8 +47,7 @@ export default {
socket: null,
//
// logContext: "choose file loading context...",
tomcatId: "system",
nodeId: "system",
replaceFields: {
children: "children",
title: "title",
@ -61,7 +60,7 @@ export default {
computed: {
...mapGetters(["getLongTermToken"]),
socketUrl() {
return getWebSocketUrl("/socket/tomcat_log", `userId=${this.getLongTermToken}&tomcatId=${this.tomcatId}&nodeId=${this.nodeId}&type=tomcat`);
return getWebSocketUrl("/socket/system_log", `userId=${this.getLongTermToken}&nodeId=system&type=systemLog`);
},
},
watch: {},