From e8eee0342297bf4b2dd305f22380c9de28005e9d Mon Sep 17 00:00:00 2001 From: fit2cloud-chenyw Date: Fri, 16 Dec 2022 16:33:19 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E6=8F=92=E4=BB=B6=E7=AE=A1=E7=90=86):=20?= =?UTF-8?q?=E9=9B=86=E7=BE=A4=E7=8E=AF=E5=A2=83=E4=BE=9D=E8=B5=96redis?= =?UTF-8?q?=E7=9A=84=E6=8F=92=E4=BB=B6=E6=93=8D=E4=BD=9C=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../io/dataease/commons/utils/IPUtils.java | 9 +++ .../plugins/entity/PluginOperate.java | 20 ++++++ .../service/redis/impl/PluginMsgService.java | 44 ++++++++++++ .../service/sys/DistributedPluginService.java | 32 +++++++++ .../dataease/service/sys/PluginService.java | 72 +++++++++++++++++-- 5 files changed, 170 insertions(+), 7 deletions(-) create mode 100644 backend/src/main/java/io/dataease/plugins/entity/PluginOperate.java create mode 100644 backend/src/main/java/io/dataease/service/sys/DistributedPluginService.java diff --git a/backend/src/main/java/io/dataease/commons/utils/IPUtils.java b/backend/src/main/java/io/dataease/commons/utils/IPUtils.java index 8a9cc8088e..19f0655cd6 100644 --- a/backend/src/main/java/io/dataease/commons/utils/IPUtils.java +++ b/backend/src/main/java/io/dataease/commons/utils/IPUtils.java @@ -3,6 +3,7 @@ package io.dataease.commons.utils; import org.apache.commons.lang3.StringUtils; import javax.servlet.http.HttpServletRequest; +import java.net.InetAddress; import java.util.Arrays; public class IPUtils { @@ -42,4 +43,12 @@ public class IPUtils { ipStr = Arrays.stream(ipStr.split(",")).filter(item -> StringUtils.isNotBlank(item) && !StringUtils.equalsIgnoreCase(UNKNOWN, item.trim())).findFirst().orElse(ipStr); return StringUtils.equals(LOCAL_IP_KEY, ipStr) ? LOCAL_IP_VAL : ipStr; } + + public static String domain() { + try { + return InetAddress.getLocalHost().getHostAddress(); + } catch (Exception e) { + return LOCAL_IP_VAL; + } + } } diff --git a/backend/src/main/java/io/dataease/plugins/entity/PluginOperate.java b/backend/src/main/java/io/dataease/plugins/entity/PluginOperate.java new file mode 100644 index 0000000000..8229a55ac3 --- /dev/null +++ b/backend/src/main/java/io/dataease/plugins/entity/PluginOperate.java @@ -0,0 +1,20 @@ +package io.dataease.plugins.entity; + +import io.dataease.plugins.common.base.domain.MyPlugin; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PluginOperate implements Serializable { + + private String type; + + private MyPlugin plugin; + + private String senderIp; +} diff --git a/backend/src/main/java/io/dataease/service/redis/impl/PluginMsgService.java b/backend/src/main/java/io/dataease/service/redis/impl/PluginMsgService.java index 05751316b0..21e55c9980 100644 --- a/backend/src/main/java/io/dataease/service/redis/impl/PluginMsgService.java +++ b/backend/src/main/java/io/dataease/service/redis/impl/PluginMsgService.java @@ -1,13 +1,57 @@ package io.dataease.service.redis.impl; +import com.google.gson.Gson; +import io.dataease.commons.utils.IPUtils; +import io.dataease.commons.utils.LogUtil; +import io.dataease.plugins.common.base.domain.MyPlugin; +import io.dataease.plugins.entity.PluginOperate; import io.dataease.service.redis.RedisMessageBroadcast; +import io.dataease.service.sys.PluginService; +import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; +import javax.annotation.Resource; + @Service public class PluginMsgService implements RedisMessageBroadcast { + private static Gson json = new Gson(); + + @Resource + private PluginService pluginService; + @Override public void messageCallBack(Object arg) { + PluginOperate operate = json.fromJson(json.toJson(arg), PluginOperate.class); + String domain = IPUtils.domain(); + if (StringUtils.equals(domain, operate.getSenderIp())) return; + String operateType = operate.getType(); + MyPlugin plugin = operate.getPlugin(); + if (StringUtils.equals("install", operateType)) { + LogUtil.info("start install plugin [{}] in domain {}", plugin.getName(), domain); + install(plugin); + } + if (StringUtils.equals("uninstall", operateType)) { + LogUtil.info("start uninstall plugin [{}] in domain {}", plugin.getName(), domain); + uninstall(plugin); + } + if (StringUtils.equals("update", operateType)) { + LogUtil.info("start update plugin [{}] in domain {}", plugin.getName(), domain); + updateInstall(plugin); + } + } + private void install(MyPlugin plugin) { + pluginService.redisBroadcastInstall(plugin); + } + + private void uninstall(MyPlugin plugin) { + pluginService.redisBroadcastUnInstall(plugin); + } + + private void updateInstall(MyPlugin plugin) { + if (pluginService.redisBroadcastUnInstall(plugin)) { + pluginService.redisBroadcastInstall(plugin); + } } } diff --git a/backend/src/main/java/io/dataease/service/sys/DistributedPluginService.java b/backend/src/main/java/io/dataease/service/sys/DistributedPluginService.java new file mode 100644 index 0000000000..3309b871d6 --- /dev/null +++ b/backend/src/main/java/io/dataease/service/sys/DistributedPluginService.java @@ -0,0 +1,32 @@ +package io.dataease.service.sys; + +import io.dataease.commons.condition.RedisStatusCondition; +import io.dataease.commons.constants.RedisConstants; +import io.dataease.commons.model.RedisMessage; +import io.dataease.plugins.entity.PluginOperate; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.context.annotation.Conditional; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +@Component +@Conditional({RedisStatusCondition.class}) +public class DistributedPluginService { + + @Resource + private RedisTemplate redisTemplate; + + + public void pushBroadcast(PluginOperate operate) { + if (ObjectUtils.isEmpty(operate) || ObjectUtils.isEmpty(operate.getPlugin()) || StringUtils.isBlank(operate.getSenderIp())) + return; + + RedisMessage msg = new RedisMessage(); + msg.setType(RedisConstants.PLUGIN_INSTALL_MSG); + msg.setData(operate); + redisTemplate.convertAndSend(RedisConstants.GLOBAL_REDIS_TOPIC, msg); + } +} diff --git a/backend/src/main/java/io/dataease/service/sys/PluginService.java b/backend/src/main/java/io/dataease/service/sys/PluginService.java index 9c570f4cfb..9dd9f5ccd6 100644 --- a/backend/src/main/java/io/dataease/service/sys/PluginService.java +++ b/backend/src/main/java/io/dataease/service/sys/PluginService.java @@ -3,6 +3,7 @@ package io.dataease.service.sys; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.ZipUtil; import com.google.gson.Gson; +import io.dataease.commons.utils.IPUtils; import io.dataease.dto.MyPluginDTO; import io.dataease.ext.ExtSysPluginMapper; import io.dataease.ext.query.GridExample; @@ -17,6 +18,7 @@ import io.dataease.listener.util.CacheUtils; import io.dataease.plugins.common.base.domain.MyPlugin; import io.dataease.plugins.common.base.mapper.MyPluginMapper; import io.dataease.plugins.config.LoadjarUtil; +import io.dataease.plugins.entity.PluginOperate; import io.dataease.service.datasource.DatasourceService; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ArrayUtils; @@ -56,6 +58,9 @@ public class PluginService { @Autowired private LoadjarUtil loadjarUtil; + @Autowired(required = false) + private DistributedPluginService distributedPluginService; + @Value("${version}") private String version; @@ -71,7 +76,7 @@ public class PluginService { * @param file * @return */ - public Map localInstall(MultipartFile file) throws Exception{ + public Map localInstall(MultipartFile file) throws Exception { //1.上传文件到服务器pluginDir目录下 File dest = DeFileUtils.upload(file, pluginDir + "temp/"); //2.解压目标文件dest 得到plugin.json和jar @@ -113,7 +118,7 @@ public class PluginService { } if (pluginExist(myPlugin)) { - String msg = "插件【"+myPlugin.getName()+"】已存在,请先卸载"; + String msg = "插件【" + myPlugin.getName() + "】已存在,请先卸载"; LogUtil.error(msg); DEException.throwException(msg); } @@ -123,7 +128,7 @@ public class PluginService { targetDir = makeTargetDir(myPlugin); String jarPath; jarPath = DeFileUtils.copy(jarFile, targetDir); - if(myPlugin.getCategory().equalsIgnoreCase("datasource")){ + if (myPlugin.getCategory().equalsIgnoreCase("datasource")) { DeFileUtils.copyFolder(folder + "/" + myPlugin.getDsType() + "Driver", targetDir + myPlugin.getDsType() + "Driver"); } loadJar(jarPath, myPlugin); @@ -142,13 +147,49 @@ public class PluginService { DeFileUtils.deleteFile(pluginDir + "temp/"); DeFileUtils.deleteFile(folder); } + distributeOperate(myPlugin, "install"); return null; } + public void distributeOperate(MyPlugin plugin, String type) { + + if (ObjectUtils.isNotEmpty(distributedPluginService)) { + PluginOperate operate = new PluginOperate(); + operate.setPlugin(plugin); + operate.setSenderIp(IPUtils.domain()); + operate.setType(type); + if (ObjectUtils.isEmpty(plugin) || StringUtils.isBlank(type) || StringUtils.isBlank(operate.getSenderIp())) + return; + distributedPluginService.pushBroadcast(operate); + } + } + public void loadJar(String jarPath, MyPlugin myPlugin) throws Exception { loadjarUtil.loadJar(jarPath, myPlugin); } + public void redisBroadcastInstall(MyPlugin plugin) { + String path = getPath(plugin); + try { + if (FileUtil.exist(path)) { + loadJar(path, plugin); + } else { + LogUtil.error("插件路径不存在 {} ", path); + } + } catch (Exception e) { + LogUtil.error(e); + } + } + + public String getPath(MyPlugin plugin) { + String store = plugin.getStore(); + String version = plugin.getVersion(); + String moduleName = plugin.getModuleName(); + String fileName = moduleName + "-" + version + ".jar"; + String path = pluginDir + store + "/" + fileName; + return path; + } + private String makeTargetDir(MyPlugin myPlugin) { String store = myPlugin.getStore(); String dir = pluginDir + store + "/"; @@ -161,6 +202,7 @@ public class PluginService { /** * 检测插件是否已存在 + * * @param myPlugin * @return */ @@ -190,13 +232,29 @@ public class PluginService { CacheUtils.removeAll(AuthConstants.USER_ROLE_CACHE_NAME); CacheUtils.removeAll(AuthConstants.USER_PERMISSION_CACHE_NAME); - if(myPlugin.getCategory().equalsIgnoreCase("datasource")){ - if(CollectionUtils.isNotEmpty(datasourceService.selectByType(myPlugin.getDsType()))){ + if (myPlugin.getCategory().equalsIgnoreCase("datasource")) { + if (CollectionUtils.isNotEmpty(datasourceService.selectByType(myPlugin.getDsType()))) { DEException.throwException(Translator.get("i18n_plugin_not_allow_delete")); } loadjarUtil.deleteModule(myPlugin.getModuleName() + "-" + myPlugin.getVersion()); } myPluginMapper.deleteByPrimaryKey(pluginId); + distributeOperate(myPlugin, "uninstall"); + return true; + } + + public Boolean redisBroadcastUnInstall(MyPlugin myPlugin) { + CacheUtils.removeAll(AuthConstants.USER_ROLE_CACHE_NAME); + CacheUtils.removeAll(AuthConstants.USER_CACHE_NAME); + CacheUtils.removeAll(AuthConstants.USER_PERMISSION_CACHE_NAME); + + if (myPlugin.getCategory().equalsIgnoreCase("datasource")) { + if (CollectionUtils.isNotEmpty(datasourceService.selectByType(myPlugin.getDsType()))) { + DEException.throwException(Translator.get("i18n_plugin_not_allow_delete")); + } + loadjarUtil.deleteModule(myPlugin.getModuleName() + "-" + myPlugin.getVersion()); + } + myPluginMapper.deleteByPrimaryKey(myPlugin.getPluginId()); return true; } @@ -208,7 +266,7 @@ public class PluginService { File jarFile = new File(path); FileUtil.del(jarFile); - if(plugin.getCategory().equalsIgnoreCase("datasource")){ + if (plugin.getCategory().equalsIgnoreCase("datasource")) { File driverFile = new File(pluginDir + plugin.getStore() + "/" + plugin.getDsType() + "Driver"); FileUtil.del(driverFile); } @@ -259,7 +317,7 @@ public class PluginService { } catch (InvocationTargetException e) { e.printStackTrace(); } - if(result.getCategory().equalsIgnoreCase("datasource") && (StringUtils.isEmpty(result.getStore()) || !result.getStore().equalsIgnoreCase("default"))){ + if (result.getCategory().equalsIgnoreCase("datasource") && (StringUtils.isEmpty(result.getStore()) || !result.getStore().equalsIgnoreCase("default"))) { result.setStore("thirdpart"); }