diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/ResourceMsgConstructor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/ResourceMsgConstructor.java index 02f2d5e000..96dd5220bc 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/ResourceMsgConstructor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/ResourceMsgConstructor.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.service.edge.rpc.constructor; +import com.google.protobuf.ByteString; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.TbResource; import org.thingsboard.server.common.data.id.TbResourceId; @@ -42,6 +43,12 @@ public class ResourceMsgConstructor { if (tbResource.getEtag() != null) { builder.setEtag(tbResource.getEtag()); } + if (tbResource.getDescriptor() != null) { + builder.setDescriptorJson(tbResource.getDescriptor().toString()); + } + if (tbResource.getPreview() != null) { + builder.setPreview(ByteString.copyFrom(tbResource.getPreview())); + } if (tbResource.getTenantId().equals(TenantId.SYS_TENANT_ID)) { builder.setIsSystem(true); } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/resource/BaseResourceProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/resource/BaseResourceProcessor.java index b28e6000d2..5d6d98469c 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/resource/BaseResourceProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/resource/BaseResourceProcessor.java @@ -17,6 +17,7 @@ package org.thingsboard.server.service.edge.rpc.processor.resource; import com.datastax.oss.driver.api.core.uuid.Uuids; import lombok.extern.slf4j.Slf4j; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.ResourceType; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.TbResource; @@ -61,7 +62,9 @@ public abstract class BaseResourceProcessor extends BaseEdgeProcessor { resource.setResourceKey(resourceKey); resource.setResourceType(resourceType); resource.setFileName(resourceUpdateMsg.getFileName()); + resource.setDescriptor(resourceUpdateMsg.hasDescriptorJson() ? JacksonUtil.toJsonNode(resourceUpdateMsg.getDescriptorJson()) : null); resource.setEncodedData(resourceUpdateMsg.hasData() ? resourceUpdateMsg.getData() : null); + resource.setPreview(resourceUpdateMsg.hasPreview() ? resourceUpdateMsg.getPreview().toByteArray() : null); resource.setEtag(resourceUpdateMsg.hasEtag() ? resourceUpdateMsg.getEtag() : null); resourceValidator.validate(resource, TbResourceInfo::getTenantId); if (created) { diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/ImagesUpdater.java b/application/src/main/java/org/thingsboard/server/service/install/update/ImagesUpdater.java index bb5da33631..81374f7a58 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/ImagesUpdater.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/ImagesUpdater.java @@ -30,14 +30,15 @@ import org.thingsboard.server.common.data.ResourceType; import org.thingsboard.server.common.data.TbResource; import org.thingsboard.server.common.data.TbResourceInfo; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.dao.util.ImageUtils; import org.thingsboard.server.common.data.widget.WidgetTypeDetails; import org.thingsboard.server.common.data.widget.WidgetsBundle; import org.thingsboard.server.dao.resource.ImageService; +import org.thingsboard.server.dao.util.ImageUtils; import java.nio.file.Files; import java.nio.file.Path; import java.util.Base64; +import java.util.List; import java.util.Map; import java.util.Optional; @@ -58,10 +59,10 @@ public class ImagesUpdater { @SneakyThrows public void updateSystemImage(Path imageFile, Map imageNames) { - String imageKey = imageFile.getFileName().toString(); + String imageKey = imageFile.getFileName().toString(); // TODO: add subdir to image key String imageName = imageNames.get(imageKey); if (imageName == null) { - throw new IllegalArgumentException("Image name is missing for " + imageKey + ". Please add it to names.json file"); + imageName = imageKey; } byte[] imageData = Files.readAllBytes(imageFile); String mediaType = ImageUtils.fileExtensionToMediaType("image", StringUtils.substringAfterLast(imageKey, ".")); @@ -203,17 +204,19 @@ public class ImagesUpdater { String existingImageQuery) { TbResourceInfo imageInfo = imageService.getImageInfoByTenantIdAndKey(tenantId, key); if (imageInfo == null && !tenantId.isSysTenantId() && existingImageQuery != null) { - // TODO: need to search among tenant images too (custom widgets) -// List existingSystemImages = imageService.findByTenantIdAndDataAndKeyStartingWith(TenantId.SYS_TENANT_ID, imageData, existingImageQuery); -// if (!existingSystemImages.isEmpty()) { -// imageInfo = existingSystemImages.get(0); -// if (existingSystemImages.size() > 1) { -// log.warn("Found more than one system image resources for key {}", existingImageQuery); -// } -// String link = imageService.getImageLink(imageInfo); -// log.info("Using system image {} for {}", link, key); -// return link; -// } + List similarImages = imageService.findSimilarImagesByTenantIdAndKeyStartingWith(TenantId.SYS_TENANT_ID, imageData, existingImageQuery); + if (similarImages.isEmpty()) { + similarImages = imageService.findSimilarImagesByTenantIdAndKeyStartingWith(tenantId, imageData, existingImageQuery); + } + if (!similarImages.isEmpty()) { + imageInfo = similarImages.get(0); + if (similarImages.size() > 1) { + log.debug("Found more than one image resources for key {}: {}", existingImageQuery, similarImages); + } + String link = imageInfo.getLink(); + log.info("[{}] Using image {} for {}", tenantId, link, key); + return link; + } } TbResource image; if (imageInfo == null) { @@ -224,7 +227,7 @@ public class ImagesUpdater { } else if (tenantId.isSysTenantId()) { image = new TbResource(imageInfo); } else { - return imageService.getImageLink(imageInfo); + return imageInfo.getLink(); } image.setTitle(name); image.setFileName(key); @@ -235,7 +238,7 @@ public class ImagesUpdater { TbResourceInfo savedImage = imageService.saveImage(image); log.info("[{}] {} image '{}' ({})", tenantId, imageInfo == null ? "Created" : "Updated", image.getTitle(), image.getResourceKey()); - return imageService.getImageLink(savedImage); + return savedImage.getLink(); } private String getText(JsonNode jsonNode, String field) { diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ImageService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ImageService.java index 3ae45e86c5..f294083290 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ImageService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ImageService.java @@ -22,6 +22,8 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import java.util.List; + public interface ImageService { TbResourceInfo saveImage(TbResource image) throws Exception; @@ -40,6 +42,6 @@ public interface ImageService { void deleteImage(TenantId tenantId, TbResourceId imageId); - String getImageLink(TbResourceInfo imageInfo); + List findSimilarImagesByTenantIdAndKeyStartingWith(TenantId tenantId, byte[] data, String imageKeyStartingWith); } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ResourceService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ResourceService.java index 21b83d17bd..8614b74502 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ResourceService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ResourceService.java @@ -60,6 +60,4 @@ public interface ResourceService extends EntityDaoService { long sumDataSizeByTenantId(TenantId tenantId); - List findByTenantIdAndDataAndKeyStartingWith(TenantId tenantId, byte[] data, String query); - } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/TbResourceInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/TbResourceInfo.java index 11e21c6451..61df84af44 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/TbResourceInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/TbResourceInfo.java @@ -106,6 +106,14 @@ public class TbResourceInfo extends BaseData implements HasName, H return title; } + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + public String getLink() { + if (resourceType == ResourceType.IMAGE) { + return "/api/images/" + (tenantId.isSysTenantId() ? "system" : "tenant") + "/" + resourceKey; + } + return null; + } + @JsonIgnore public String getSearchText() { return searchText != null ? searchText : title; diff --git a/common/edge-api/src/main/proto/edge.proto b/common/edge-api/src/main/proto/edge.proto index 71e84304ed..2411b0af53 100644 --- a/common/edge-api/src/main/proto/edge.proto +++ b/common/edge-api/src/main/proto/edge.proto @@ -436,6 +436,8 @@ message ResourceUpdateMsg { optional string data = 8; optional string etag = 9; bool isSystem = 10; + optional string descriptorJson = 11; + optional bytes preview = 12; } message RuleChainMetadataRequestMsg { diff --git a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseImageService.java b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseImageService.java index 857296b9b5..500fe37d33 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseImageService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseImageService.java @@ -20,7 +20,6 @@ import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.RegexUtils; import org.thingsboard.server.common.data.ImageDescriptor; import org.thingsboard.server.common.data.ResourceType; @@ -35,6 +34,7 @@ import org.thingsboard.server.dao.service.validator.ResourceDataValidator; import org.thingsboard.server.dao.util.ImageUtils; import org.thingsboard.server.dao.util.ImageUtils.ProcessedImage; +import java.util.List; import java.util.Objects; import java.util.Set; import java.util.regex.Pattern; @@ -152,15 +152,9 @@ public class BaseImageService extends BaseResourceService implements ImageServic } @Override - public String getImageLink(TbResourceInfo imageInfo) { - String link = "/api/images/"; - if (imageInfo.getTenantId().isSysTenantId()) { - link += "system/"; - } else { - link += "tenant/"; - } - link += imageInfo.getResourceKey(); - return link; + public List findSimilarImagesByTenantIdAndKeyStartingWith(TenantId tenantId, byte[] data, String imageKeyStartingWith) { + String etag = calculateEtag(data); + return resourceInfoDao.findByTenantIdAndEtagAndKeyStartingWith(tenantId, etag, imageKeyStartingWith); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java index 9be95db9e7..13ed98b461 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java @@ -216,12 +216,6 @@ public class BaseResourceService extends AbstractCachedEntityService findByTenantIdAndDataAndKeyStartingWith(TenantId tenantId, byte[] data, String query) { - String etag = calculateEtag(data); - return resourceInfoDao.findByTenantIdAndEtagAndKeyStartingWith(tenantId, etag, query); - } - protected String calculateEtag(byte[] data) { return Hashing.sha256().hashBytes(data).toString(); }