forked from github/dataease
feat(插件管理): 集群环境依赖redis的插件操作功能
This commit is contained in:
parent
563b57faa5
commit
e8eee03422
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<PluginOperate> msg = new RedisMessage();
|
||||
msg.setType(RedisConstants.PLUGIN_INSTALL_MSG);
|
||||
msg.setData(operate);
|
||||
redisTemplate.convertAndSend(RedisConstants.GLOBAL_REDIS_TOPIC, msg);
|
||||
}
|
||||
}
|
@ -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<String, Object> localInstall(MultipartFile file) throws Exception{
|
||||
public Map<String, Object> 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");
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user