From 505fcaf52d4b50e32e8df5717fd62f32f42e3585 Mon Sep 17 00:00:00 2001 From: mxd <838425805@qq.com> Date: Sat, 1 Jan 2022 23:17:47 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E3=80=81=E5=A4=87=E4=BB=BD?= =?UTF-8?q?=E8=BF=98=E5=8E=9F=E3=80=81=E6=B3=A8=E5=86=8C=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../adapter/resource/ZipResource.java | 2 +- .../controller/MagicBackupController.java | 59 ++++-- .../controller/MagicWorkbenchController.java | 3 +- .../ssssssss/magicapi/event/EventAction.java | 2 +- .../magicapi/model/JsonCodeConstants.java | 2 + .../magicapi/provider/MagicAPIService.java | 2 +- .../magicapi/provider/MagicBackupService.java | 3 + .../provider/impl/DefaultMagicAPIService.java | 7 +- .../impl/MagicDatabaseBackupService.java | 16 ++ .../service/AbstractMagicDynamicRegistry.java | 25 +-- .../service/MagicDynamicRegistry.java | 5 - .../service/MagicResourceService.java | 3 + .../service/MagicSynchronizationService.java | 6 + .../AbstractPathMagicResourceStorage.java | 6 + .../impl/ApiInfoMagicResourceStorage.java | 4 +- .../impl/DataSourceMagicDynamicRegistry.java | 6 + .../impl/DefaultMagicResourceService.java | 169 ++++++++++++++---- .../FunctionInfoMagicResourceStorage.java | 3 +- .../impl/FunctionMagicDynamicRegistry.java | 14 ++ .../org/ssssssss/magicapi/utils/IoUtils.java | 9 + 20 files changed, 273 insertions(+), 73 deletions(-) diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/adapter/resource/ZipResource.java b/magic-api/src/main/java/org/ssssssss/magicapi/adapter/resource/ZipResource.java index 59631a97..5974b9a5 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/adapter/resource/ZipResource.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/adapter/resource/ZipResource.java @@ -82,7 +82,7 @@ public class ZipResource implements Resource { public String name() { String name = this.path; if (isDirectory()) { - name = this.path.substring(0, name.length() - 1); + name = this.path.length() > 0 ? this.path.substring(0, name.length() - 1) : ""; } int index = name.lastIndexOf("/"); return index > -1 ? name.substring(index + 1) : name; diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/controller/MagicBackupController.java b/magic-api/src/main/java/org/ssssssss/magicapi/controller/MagicBackupController.java index 4af50c5f..a406788d 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/controller/MagicBackupController.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/controller/MagicBackupController.java @@ -4,15 +4,17 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.ssssssss.magicapi.config.MagicConfiguration; -import org.ssssssss.magicapi.model.Backup; -import org.ssssssss.magicapi.model.JsonBean; +import org.ssssssss.magicapi.model.*; import org.ssssssss.magicapi.provider.MagicBackupService; +import org.ssssssss.magicapi.service.MagicDynamicRegistry; +import org.ssssssss.magicapi.utils.JsonUtils; +import org.ssssssss.magicapi.utils.WebUtils; -import java.io.ByteArrayOutputStream; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.List; -public class MagicBackupController extends MagicController { +public class MagicBackupController extends MagicController implements MagicExceptionHandler{ private final MagicBackupService service; @@ -27,18 +29,45 @@ public class MagicBackupController extends MagicController { return new JsonBean<>(service.backupList(timestamp == null ? System.currentTimeMillis() : timestamp)); } - @PostMapping("/backup") + @GetMapping("/backup/rollback") @ResponseBody - public JsonBean doBackup(String tag) throws IOException { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - MagicConfiguration.getMagicResourceService().export(null, null, baos); - Backup backup = new Backup(); - backup.setId("full"); - backup.setType("full"); - backup.setName("全量备份"); - backup.setContent(baos.toByteArray()); - backup.setTag(tag); - service.doBackup(backup); + public JsonBean rollback(String id, Long timestamp) throws IOException { + Backup backup = service.backupInfo(id, timestamp); + if("full".equals(id)){ + service.doBackupAll("还原全量备份前,系统自动全量备份", WebUtils.currentUserName()); + configuration.getMagicAPIService().upload(new ByteArrayInputStream(backup.getContent()), Constants.UPLOAD_MODE_FULL); + return new JsonBean<>(true); + } + if(backup.getType().endsWith("-group")){ + Group group = JsonUtils.readValue(backup.getContent(), Group.class); + return new JsonBean<>(MagicConfiguration.getMagicResourceService().saveGroup(group)); + } + MagicEntity entity = configuration.getMagicDynamicRegistries().stream() + .map(MagicDynamicRegistry::getMagicResourceStorage) + .filter(it -> it.folder().equals(backup.getType())) + .map(it -> it.read(backup.getContent())) + .findFirst() + .orElse(null); + if(entity != null){ + return new JsonBean<>(MagicConfiguration.getMagicResourceService().saveFile(entity)); + } + return new JsonBean<>(false); + } + + @GetMapping("/backup") + @ResponseBody + public JsonBean backup(Long timestamp, String id) { + notBlank(id, PARAMETER_INVALID); + notNull(timestamp, PARAMETER_INVALID); + Backup backup = service.backupInfo(id, timestamp); + MagicEntity entity = JsonUtils.readValue(backup.getContent(), MagicEntity.class); + return new JsonBean<>(entity == null ? null : entity.getScript()); + } + + @PostMapping("/backup/full") + @ResponseBody + public JsonBean doBackup() throws IOException { + service.doBackupAll("主动全量备份", WebUtils.currentUserName()); return new JsonBean<>(true); } } diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/controller/MagicWorkbenchController.java b/magic-api/src/main/java/org/ssssssss/magicapi/controller/MagicWorkbenchController.java index 2a709db8..7f392592 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/controller/MagicWorkbenchController.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/controller/MagicWorkbenchController.java @@ -244,8 +244,7 @@ public class MagicWorkbenchController extends MagicController implements MagicEx @ResponseBody public JsonBean upload(MultipartFile file, String mode) throws IOException { notNull(file, FILE_IS_REQUIRED); - magicAPIService.upload(file.getInputStream(), mode); - return new JsonBean<>(SUCCESS, true); + return new JsonBean<>(magicAPIService.upload(file.getInputStream(), mode)); } @RequestMapping("/push") diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/event/EventAction.java b/magic-api/src/main/java/org/ssssssss/magicapi/event/EventAction.java index d8b16a31..c6ed1af4 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/event/EventAction.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/event/EventAction.java @@ -2,5 +2,5 @@ package org.ssssssss.magicapi.event; public enum EventAction { - CREATE, SAVE, DELETE, MOVE, LOAD, WS_C_S, WS_S_C, RELOAD + CREATE, SAVE, DELETE, MOVE, LOAD, WS_C_S, WS_S_C, RELOAD, CLEAR } diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/model/JsonCodeConstants.java b/magic-api/src/main/java/org/ssssssss/magicapi/model/JsonCodeConstants.java index 921b1cbe..607b4ea4 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/model/JsonCodeConstants.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/model/JsonCodeConstants.java @@ -31,6 +31,8 @@ public interface JsonCodeConstants { JsonCode PATH_CONFLICT = new JsonCode(0, "该路径已被使用,请换一个路径在试"); + JsonCode RESOURCE_PATH_CONFLICT = new JsonCode(0, "资源中[%s]有冲突,请检查"); + JsonCode MOVE_PATH_CONFLICT = new JsonCode(0, "移动后路径会冲突,请换一个路径在试"); JsonCode FUNCTION_PATH_CONFLICT = new JsonCode(0, "该路径已被映射,请换一个请求方法或路径"); diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/provider/MagicAPIService.java b/magic-api/src/main/java/org/ssssssss/magicapi/provider/MagicAPIService.java index db994d7b..978a7c03 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/provider/MagicAPIService.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/provider/MagicAPIService.java @@ -83,7 +83,7 @@ public interface MagicAPIService extends MagicModule { /** * 上传 */ - void upload(InputStream inputStream, String mode) throws IOException; + boolean upload(InputStream inputStream, String mode) throws IOException; /** * 下载 diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/provider/MagicBackupService.java b/magic-api/src/main/java/org/ssssssss/magicapi/provider/MagicBackupService.java index 25d98960..2aca6ee2 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/provider/MagicBackupService.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/provider/MagicBackupService.java @@ -2,6 +2,7 @@ package org.ssssssss.magicapi.provider; import org.ssssssss.magicapi.model.Backup; +import java.io.IOException; import java.util.List; /** @@ -20,6 +21,8 @@ public interface MagicBackupService { */ void doBackup(Backup backup); + void doBackupAll(String name, String createBy) throws IOException; + /** * 根据时间戳查询最近的 FETCH_SIZE 条记录 * diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/provider/impl/DefaultMagicAPIService.java b/magic-api/src/main/java/org/ssssssss/magicapi/provider/impl/DefaultMagicAPIService.java index 0b47d496..9cd81aef 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/provider/impl/DefaultMagicAPIService.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/provider/impl/DefaultMagicAPIService.java @@ -12,6 +12,8 @@ import org.springframework.util.MultiValueMap; import org.springframework.web.client.RestTemplate; import org.ssssssss.magicapi.config.WebSocketSessionManager; import org.ssssssss.magicapi.controller.MagicWebSocketDispatcher; +import org.ssssssss.magicapi.event.EventAction; +import org.ssssssss.magicapi.event.MagicEvent; import org.ssssssss.magicapi.exception.MagicResourceNotFoundException; import org.ssssssss.magicapi.model.*; import org.ssssssss.magicapi.provider.MagicAPIService; @@ -132,7 +134,8 @@ public class DefaultMagicAPIService implements MagicAPIService, JsonCodeConstant } @Override - public void upload(InputStream inputStream, String mode) throws IOException { + public boolean upload(InputStream inputStream, String mode) throws IOException { + return resourceService.upload(inputStream, Constants.UPLOAD_MODE_FULL.equals(mode)); } @Override @@ -184,6 +187,8 @@ public class DefaultMagicAPIService implements MagicAPIService, JsonCodeConstant return processWebSocketMessageReceived(magicNotify.getSessionId(), magicNotify.getContent()); case WS_S_C: return processWebSocketSendMessage(magicNotify.getSessionId(), magicNotify.getContent()); + case CLEAR: + publisher.publishEvent(new MagicEvent("clear", EventAction.CLEAR, Constants.EVENT_SOURCE_NOTIFY)); } return resourceService.processNotify(magicNotify); } diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/provider/impl/MagicDatabaseBackupService.java b/magic-api/src/main/java/org/ssssssss/magicapi/provider/impl/MagicDatabaseBackupService.java index 652be4dc..eaea496c 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/provider/impl/MagicDatabaseBackupService.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/provider/impl/MagicDatabaseBackupService.java @@ -5,6 +5,7 @@ import org.slf4j.LoggerFactory; import org.springframework.context.event.EventListener; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; +import org.ssssssss.magicapi.config.MagicConfiguration; import org.ssssssss.magicapi.event.FileEvent; import org.ssssssss.magicapi.event.GroupEvent; import org.ssssssss.magicapi.model.Backup; @@ -14,6 +15,8 @@ import org.ssssssss.magicapi.provider.MagicBackupService; import org.ssssssss.magicapi.utils.JsonUtils; import org.ssssssss.magicapi.utils.WebUtils; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -58,6 +61,19 @@ public class MagicDatabaseBackupService implements MagicBackupService { this.FIND_BY_ID_AND_TIMESTAMP = String.format("select * from %s where id = ? and create_date = ?", tableName); } + @Override + public void doBackupAll(String name, String createBy) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + MagicConfiguration.getMagicResourceService().export(null, null, baos); + Backup backup = new Backup(); + backup.setId("full"); + backup.setType("full"); + backup.setName(name); + backup.setCreateBy(createBy); + backup.setContent(baos.toByteArray()); + doBackup(backup); + } + @Override public void doBackup(Backup backup) { try { diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/service/AbstractMagicDynamicRegistry.java b/magic-api/src/main/java/org/ssssssss/magicapi/service/AbstractMagicDynamicRegistry.java index 36dd30ff..f1b11381 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/service/AbstractMagicDynamicRegistry.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/service/AbstractMagicDynamicRegistry.java @@ -1,13 +1,15 @@ package org.ssssssss.magicapi.service; +import org.springframework.context.event.EventListener; import org.ssssssss.magicapi.event.EventAction; import org.ssssssss.magicapi.event.FileEvent; import org.ssssssss.magicapi.event.GroupEvent; +import org.ssssssss.magicapi.event.MagicEvent; import org.ssssssss.magicapi.exception.MagicAPIException; import org.ssssssss.magicapi.model.MagicEntity; import org.ssssssss.magicapi.provider.MagicResourceStorage; -import java.util.List; +import java.util.Iterator; import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; @@ -55,6 +57,17 @@ public abstract class AbstractMagicDynamicRegistry implem return false; } + @EventListener(condition = "#event.action == T(org.ssssssss.magicapi.event.EventAction).CLEAR") + public void clear(MagicEvent event){ + Iterator>> iterator = mappings.entrySet().iterator(); + while (iterator.hasNext()){ + Map.Entry> entry = iterator.next(); + unregister(entry.getValue()); + iterator.remove(); + } + + } + protected void processEvent(FileEvent event) { T info = (T) event.getEntity(); if (event.getAction() == EventAction.DELETE) { @@ -102,16 +115,6 @@ public abstract class AbstractMagicDynamicRegistry implem } - public boolean register(List entities) { - mappings.values().stream().distinct().forEach(node -> { - unregister(node); - mappings.remove(node.getMappingKey()); - mappings.remove(node.getEntity().getId()); - }); - entities.forEach(this::register); - return true; - } - protected MappingNode buildMappingNode(T entity) { MappingNode mappingNode = new MappingNode<>(entity); mappingNode.setMappingKey(this.magicResourceStorage.buildKey(entity)); diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/service/MagicDynamicRegistry.java b/magic-api/src/main/java/org/ssssssss/magicapi/service/MagicDynamicRegistry.java index 7c6641a7..87c0f2d4 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/service/MagicDynamicRegistry.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/service/MagicDynamicRegistry.java @@ -12,11 +12,6 @@ public interface MagicDynamicRegistry { */ boolean register(T entity); - /** - * 注册全部 - */ - boolean register(List entities); - /** * 取消注册 */ diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/service/MagicResourceService.java b/magic-api/src/main/java/org/ssssssss/magicapi/service/MagicResourceService.java index fbe628bb..f2660eea 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/service/MagicResourceService.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/service/MagicResourceService.java @@ -4,6 +4,7 @@ import org.ssssssss.magicapi.adapter.Resource; import org.ssssssss.magicapi.model.*; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.util.List; import java.util.Map; @@ -98,6 +99,8 @@ public interface MagicResourceService { boolean unlock(String id); + boolean upload(InputStream inputStream, boolean full) throws IOException; + public String getGroupPath(String groupId); diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/service/MagicSynchronizationService.java b/magic-api/src/main/java/org/ssssssss/magicapi/service/MagicSynchronizationService.java index f3ede7f4..5d9253aa 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/service/MagicSynchronizationService.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/service/MagicSynchronizationService.java @@ -3,6 +3,7 @@ package org.ssssssss.magicapi.service; import org.springframework.context.event.EventListener; import org.ssssssss.magicapi.event.FileEvent; import org.ssssssss.magicapi.event.GroupEvent; +import org.ssssssss.magicapi.event.MagicEvent; import org.ssssssss.magicapi.model.Constants; import org.ssssssss.magicapi.model.MagicNotify; import org.ssssssss.magicapi.provider.MagicNotifyService; @@ -47,4 +48,9 @@ public class MagicSynchronizationService { break; } } + + @EventListener(condition = "#event.action == T(org.ssssssss.magicapi.event.EventAction).CLEAR && #event.source != T(org.ssssssss.magicapi.model.Constants).EVENT_SOURCE_NOTIFY") + public void onClearEvent(MagicEvent event){ + magicNotifyService.sendNotify(new MagicNotify(instanceId, null, event.getAction(), null)); + } } diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/service/impl/AbstractPathMagicResourceStorage.java b/magic-api/src/main/java/org/ssssssss/magicapi/service/impl/AbstractPathMagicResourceStorage.java index c52d926e..4deb9606 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/service/impl/AbstractPathMagicResourceStorage.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/service/impl/AbstractPathMagicResourceStorage.java @@ -5,6 +5,8 @@ import org.ssssssss.magicapi.provider.MagicResourceStorage; import org.ssssssss.magicapi.service.MagicResourceService; import org.ssssssss.magicapi.utils.PathUtils; +import java.util.Objects; + public abstract class AbstractPathMagicResourceStorage implements MagicResourceStorage { @@ -25,6 +27,10 @@ public abstract class AbstractPathMagicResourceStorage { @@ -17,6 +16,7 @@ public class ApiInfoMagicResourceStorage extends AbstractPathMagicResourceStorag @Override public String buildMappingKey(ApiInfo info) { - return info.getMethod().toUpperCase() + ":" + PathUtils.replaceSlash("/" + magicResourceService.getGroupPath(info.getGroupId()) + "/" + info.getPath()); + return info.getMethod().toUpperCase() + ":" + buildMappingKey(info, magicResourceService.getGroupPath(info.getGroupId())); } + } diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/service/impl/DataSourceMagicDynamicRegistry.java b/magic-api/src/main/java/org/ssssssss/magicapi/service/impl/DataSourceMagicDynamicRegistry.java index 2cce9b09..6f591c38 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/service/impl/DataSourceMagicDynamicRegistry.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/service/impl/DataSourceMagicDynamicRegistry.java @@ -1,6 +1,8 @@ package org.ssssssss.magicapi.service.impl; import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.BeanUtils; import org.springframework.boot.context.properties.bind.Bindable; import org.springframework.boot.context.properties.bind.Binder; @@ -25,6 +27,8 @@ public class DataSourceMagicDynamicRegistry extends AbstractMagicDynamicRegistry private final MagicDynamicDataSource magicDynamicDataSource; + private static final Logger logger = LoggerFactory.getLogger(DataSourceMagicDynamicRegistry.class); + private static final ClassLoader CLASSLOADER = DataSourceMagicDynamicRegistry.class.getClassLoader(); // copy from DataSourceBuilder @@ -57,12 +61,14 @@ public class DataSourceMagicDynamicRegistry extends AbstractMagicDynamicRegistry } DataSource datasource = createDataSource(getDataSourceType(info.getType()), properties); magicDynamicDataSource.put(info.getId(), info.getKey(), info.getName(), datasource, info.getMaxRows()); + logger.debug("注册数据源:{}", info.getKey()); return true; } @Override public boolean unregister(DataSourceInfo info) { + logger.debug("取消注册数据源:{}", info.getKey()); return magicDynamicDataSource.delete(info.getKey()); } diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/service/impl/DefaultMagicResourceService.java b/magic-api/src/main/java/org/ssssssss/magicapi/service/impl/DefaultMagicResourceService.java index 4a919f5f..41e44815 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/service/impl/DefaultMagicResourceService.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/service/impl/DefaultMagicResourceService.java @@ -5,9 +5,11 @@ import org.springframework.boot.context.event.ApplicationStartedEvent; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationListener; import org.ssssssss.magicapi.adapter.Resource; +import org.ssssssss.magicapi.adapter.resource.ZipResource; import org.ssssssss.magicapi.event.EventAction; import org.ssssssss.magicapi.event.FileEvent; import org.ssssssss.magicapi.event.GroupEvent; +import org.ssssssss.magicapi.event.MagicEvent; import org.ssssssss.magicapi.exception.InvalidArgumentException; import org.ssssssss.magicapi.model.*; import org.ssssssss.magicapi.provider.MagicResourceStorage; @@ -17,6 +19,7 @@ import org.ssssssss.magicapi.utils.JsonUtils; import org.ssssssss.magicapi.utils.WebUtils; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.util.*; import java.util.concurrent.locks.ReadWriteLock; @@ -96,34 +99,37 @@ public class DefaultMagicResourceService implements MagicResourceService, JsonCo return false; } + private void init(){ + groupMappings.clear(); + groupCache.clear(); + fileMappings.clear(); + fileCache.clear(); + pathCache.clear(); + storages.forEach((key, registry) -> { + if (registry.requirePath()) { + pathCache.put(registry.folder(), new HashMap<>(32)); + } + Resource folder = root.getDirectory(key); + if (registry.allowRoot()) { + String rootId = key + ":0"; + Group group = new Group(); + group.setId(rootId); + group.setType(key); + group.setParentId("0"); + putGroup(group, folder); + } + if (!folder.exists()) { + folder.mkdir(); + } + }); + } + @Override public void refresh() { writeLock(() -> { - groupMappings.clear(); - groupCache.clear(); - fileMappings.clear(); - fileCache.clear(); - pathCache.clear(); + this.init(); this.root.readAll(); - storages.forEach((key, registry) -> { - if (registry.requirePath()) { - pathCache.put(registry.folder(), new HashMap<>(32)); - } - Resource folder = root.getDirectory(key); - if (registry.allowRoot()) { - String rootId = key + ":0"; - Group group = new Group(); - group.setId(rootId); - group.setType(key); - group.setParentId("0"); - putGroup(group, folder); - } - if (!folder.exists()) { - folder.mkdir(); - } else { - refreshGroup(folder, registry); - } - }); + storages.forEach((key, registry) -> refreshGroup(root.getDirectory(key), registry)); fileCache.values().forEach(entity -> { Group group = groupCache.get(entity.getGroupId()); publisher.publishEvent(new FileEvent(group.getType(), EventAction.LOAD, entity)); @@ -173,9 +179,11 @@ public class DefaultMagicResourceService implements MagicResourceService, JsonCo } Resource groupResource; GroupEvent event = new GroupEvent(group.getType(), group.getId() == null ? EventAction.CREATE : EventAction.SAVE, group); - if (group.getId() == null) { + if (group.getId() == null || !groupCache.containsKey(group.getId())) { // 添加分组 - group.setId(UUID.randomUUID().toString().replace("-", "")); + if(group.getId() == null){ + group.setId(UUID.randomUUID().toString().replace("-", "")); + } groupResource = resource.getDirectory(group.getName()); // 判断分组文件夹需要不存在 isTrue(!groupResource.exists(), FILE_SAVE_FAILURE); @@ -186,7 +194,7 @@ public class DefaultMagicResourceService implements MagicResourceService, JsonCo groupResource = resource.getDirectory(group.getName()); isTrue(oldResource != null && oldResource.exists(), GROUP_NOT_FOUND); // 名字不一样时重命名 - if (!oldResource.name().equals(resource.name())) { + if (!oldResource.getFilePath().equals(resource.getFilePath())) { isTrue(oldResource.renameTo(groupResource), FILE_SAVE_FAILURE); } } @@ -433,13 +441,14 @@ public class DefaultMagicResourceService implements MagicResourceService, JsonCo String filename = entity.getName() + storage.suffix(); // 获取修改前的信息 Resource fileResource = groupResource.getResource(filename); - if (entity.getId() == null) { - isTrue(!fileResource.exists(), FILE_SAVE_FAILURE); - // 新增操作赋值 - entity.setId(UUID.randomUUID().toString().replace("-", "")); + if (entity.getId() == null || !fileCache.containsKey(entity.getId())) { + if(entity.getId() == null){ + isTrue(!fileResource.exists(), FILE_SAVE_FAILURE); + // 新增操作赋值 + entity.setId(UUID.randomUUID().toString().replace("-", "")); + } entity.setCreateTime(System.currentTimeMillis()); entity.setCreateBy(WebUtils.currentUserName()); - } else { // 修改操作赋值 entity.setUpdateTime(System.currentTimeMillis()); @@ -612,6 +621,102 @@ public class DefaultMagicResourceService implements MagicResourceService, JsonCo return doLockResource(id, Constants.UNLOCK); } + @Override + public boolean upload(InputStream inputStream, boolean full) throws IOException { + try { + ZipResource zipResource = new ZipResource(inputStream); + Set groups = new LinkedHashSet<>(); + Set entities = new LinkedHashSet<>(); + return writeLock(() -> { + readAllResource(zipResource, groups, entities, !full); + if(full){ + // 全量模式先删除处理。 + root.delete(); + this.init(); + publisher.publishEvent(new MagicEvent("clear", EventAction.CLEAR)); + } + for (Group group : groups) { + saveGroup(group); + } + for (MagicEntity entity : entities) { + saveFile(entity); + } + return true; + }); + } finally { + IoUtils.close(inputStream); + } + + } + + private void readAllResource(Resource root, Set groups, Set entities, boolean checked){ + readAllResource(root, null, groups, entities, null, "/", checked); + } + + private void readAllResource(Resource root, MagicResourceStorage storage, Set groups, Set entities, Set mappingKeys, String path, boolean checked){ + storage = storage == null ? storages.get(root.name()) : storage; + if(storage != null){ + mappingKeys = mappingKeys == null ? new HashSet<>() : mappingKeys; + if(!storage.allowRoot()){ + Resource resource = root.getResource(Constants.GROUP_METABASE); + // 分组信息不存在时,直接返回不处理 + if(resource.exists()){ + // 读取分组信息 + Group group = JsonUtils.readValue(resource.read(), Group.class); + group.setType(mappingV1Type(group.getType())); + groups.add(group); + if(storage.requirePath()){ + path = path + Objects.toString(group.getPath(), "") + "/"; + } + } + + } + for(Resource file : root.files(storage.suffix())){ + MagicEntity entity = storage.read(file.read()); + if(storage.allowRoot()){ + entity.setGroupId(storage.folder() + ":0"); + } + String mappingKey; + if(storage instanceof AbstractPathMagicResourceStorage){ + mappingKey = ((AbstractPathMagicResourceStorage) storage).buildMappingKey((PathMagicEntity) entity, path); + }else{ + mappingKey = storage.buildKey(entity); + } + if(checked){ + String groupId = entity.getGroupId(); + // 名字和路径冲突检查 + fileCache.values().stream() + // 同一分组 + .filter(it -> Objects.equals(it.getGroupId(), groupId)) + // 非自身 + .filter(it -> !it.getId().equals(entity.getId())) + .forEach(it -> isTrue(!Objects.equals(it.getName(), entity.getName()), RESOURCE_PATH_CONFLICT.format(entity.getName()))); + + } + // 自检 + isTrue(mappingKeys.add(mappingKey), RESOURCE_PATH_CONFLICT.format(mappingKey)); + entities.add(entity); + } + + } + for (Resource directory : root.dirs()) { + readAllResource(directory, storage, groups, entities, mappingKeys, path, checked); + } + } + + /** + * 兼容1.x版本 + */ + private String mappingV1Type(String type){ + if("1".equals(type)){ + return "api"; + } else if ("2".equals(type)){ + return "function"; + } + return type; + + } + @Override public String getGroupName(String groupId) { return findGroups(groupId).stream() diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/service/impl/FunctionInfoMagicResourceStorage.java b/magic-api/src/main/java/org/ssssssss/magicapi/service/impl/FunctionInfoMagicResourceStorage.java index 193d6791..52191e3b 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/service/impl/FunctionInfoMagicResourceStorage.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/service/impl/FunctionInfoMagicResourceStorage.java @@ -1,7 +1,6 @@ package org.ssssssss.magicapi.service.impl; import org.ssssssss.magicapi.model.FunctionInfo; -import org.ssssssss.magicapi.utils.PathUtils; public class FunctionInfoMagicResourceStorage extends AbstractPathMagicResourceStorage { @@ -17,6 +16,6 @@ public class FunctionInfoMagicResourceStorage extends AbstractPathMagicResourceS @Override public String buildMappingKey(FunctionInfo info) { - return PathUtils.replaceSlash("/" + magicResourceService.getGroupPath(info.getGroupId()) + "/" + info.getPath()); + return buildMappingKey(info, magicResourceService.getGroupPath(info.getGroupId())); } } diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/service/impl/FunctionMagicDynamicRegistry.java b/magic-api/src/main/java/org/ssssssss/magicapi/service/impl/FunctionMagicDynamicRegistry.java index 28d77d96..f5f2cff2 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/service/impl/FunctionMagicDynamicRegistry.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/service/impl/FunctionMagicDynamicRegistry.java @@ -1,5 +1,7 @@ package org.ssssssss.magicapi.service.impl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.context.event.EventListener; import org.ssssssss.magicapi.event.FileEvent; import org.ssssssss.magicapi.event.GroupEvent; @@ -18,6 +20,8 @@ import java.util.function.Function; public class FunctionMagicDynamicRegistry extends AbstractMagicDynamicRegistry { + private static final Logger logger = LoggerFactory.getLogger(FunctionMagicDynamicRegistry.class); + public FunctionMagicDynamicRegistry(MagicResourceStorage magicResourceStorage) { super(magicResourceStorage); MagicResourceLoader.addFunctionLoader(this::lookupLambdaFunction); @@ -56,4 +60,14 @@ public class FunctionMagicDynamicRegistry extends AbstractMagicDynamicRegistry mappingNode) { + logger.debug("注册函数:{}", mappingNode.getMappingKey()); + return true; + } + + @Override + protected void unregister(MappingNode mappingNode) { + logger.debug("取消注册函数:{}", mappingNode.getMappingKey()); + } } diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/utils/IoUtils.java b/magic-api/src/main/java/org/ssssssss/magicapi/utils/IoUtils.java index 0047352b..2bda0045 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/utils/IoUtils.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/utils/IoUtils.java @@ -158,4 +158,13 @@ public class IoUtils { } } } + + public static void close(Closeable closeable){ + try { + if(closeable != null){ + closeable.close(); + } + } catch (IOException ignored) { + } + } }