diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/asset/AssetMsgConstructorV1.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/asset/AssetMsgConstructorV1.java index 95e1e0e597..ddf975d4ab 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/asset/AssetMsgConstructorV1.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/asset/AssetMsgConstructorV1.java @@ -16,10 +16,12 @@ package org.thingsboard.server.service.edge.rpc.constructor.asset; import com.google.protobuf.ByteString; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.AssetProfile; +import org.thingsboard.server.dao.resource.ImageService; import org.thingsboard.server.gen.edge.v1.AssetProfileUpdateMsg; import org.thingsboard.server.gen.edge.v1.AssetUpdateMsg; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; @@ -31,6 +33,9 @@ import java.nio.charset.StandardCharsets; @TbCoreComponent public class AssetMsgConstructorV1 extends BaseAssetMsgConstructor { + @Autowired + private ImageService imageService; + @Override public AssetUpdateMsg constructAssetUpdatedMsg(UpdateMsgType msgType, Asset asset) { AssetUpdateMsg.Builder builder = AssetUpdateMsg.newBuilder() @@ -58,6 +63,7 @@ public class AssetMsgConstructorV1 extends BaseAssetMsgConstructor { @Override public AssetProfileUpdateMsg constructAssetProfileUpdatedMsg(UpdateMsgType msgType, AssetProfile assetProfile) { + imageService.inlineImageForEdge(assetProfile); AssetProfileUpdateMsg.Builder builder = AssetProfileUpdateMsg.newBuilder() .setMsgType(msgType) .setIdMSB(assetProfile.getId().getId().getMostSignificantBits()) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/dashboard/DashboardMsgConstructorV1.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/dashboard/DashboardMsgConstructorV1.java index 6a3bb43797..548b1e1fd0 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/dashboard/DashboardMsgConstructorV1.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/dashboard/DashboardMsgConstructorV1.java @@ -15,9 +15,11 @@ */ package org.thingsboard.server.service.edge.rpc.constructor.dashboard; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Dashboard; +import org.thingsboard.server.dao.resource.ImageService; import org.thingsboard.server.gen.edge.v1.DashboardUpdateMsg; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; import org.thingsboard.server.queue.util.TbCoreComponent; @@ -26,8 +28,12 @@ import org.thingsboard.server.queue.util.TbCoreComponent; @TbCoreComponent public class DashboardMsgConstructorV1 extends BaseDashboardMsgConstructor { + @Autowired + private ImageService imageService; + @Override public DashboardUpdateMsg constructDashboardUpdatedMsg(UpdateMsgType msgType, Dashboard dashboard) { + imageService.inlineImagesForEdge(dashboard); DashboardUpdateMsg.Builder builder = DashboardUpdateMsg.newBuilder() .setMsgType(msgType) .setIdMSB(dashboard.getId().getId().getMostSignificantBits()) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/device/DeviceMsgConstructorV1.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/device/DeviceMsgConstructorV1.java index 4442387b21..04f23f25b4 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/device/DeviceMsgConstructorV1.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/device/DeviceMsgConstructorV1.java @@ -22,6 +22,7 @@ import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.security.DeviceCredentials; +import org.thingsboard.server.dao.resource.ImageService; import org.thingsboard.server.gen.edge.v1.DeviceCredentialsUpdateMsg; import org.thingsboard.server.gen.edge.v1.DeviceProfileUpdateMsg; import org.thingsboard.server.gen.edge.v1.DeviceUpdateMsg; @@ -38,6 +39,9 @@ public class DeviceMsgConstructorV1 extends BaseDeviceMsgConstructor { @Autowired private DataDecodingEncodingService dataDecodingEncodingService; + @Autowired + private ImageService imageService; + @Override public DeviceUpdateMsg constructDeviceUpdatedMsg(UpdateMsgType msgType, Device device) { DeviceUpdateMsg.Builder builder = DeviceUpdateMsg.newBuilder() @@ -91,6 +95,7 @@ public class DeviceMsgConstructorV1 extends BaseDeviceMsgConstructor { @Override public DeviceProfileUpdateMsg constructDeviceProfileUpdatedMsg(UpdateMsgType msgType, DeviceProfile deviceProfile) { + imageService.inlineImageForEdge(deviceProfile); DeviceProfileUpdateMsg.Builder builder = DeviceProfileUpdateMsg.newBuilder() .setMsgType(msgType) .setIdMSB(deviceProfile.getId().getId().getMostSignificantBits()) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/resource/ResourceMsgConstructorV1.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/resource/ResourceMsgConstructorV1.java index d110076bea..f58f0b7c25 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/resource/ResourceMsgConstructorV1.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/resource/ResourceMsgConstructorV1.java @@ -15,8 +15,8 @@ */ package org.thingsboard.server.service.edge.rpc.constructor.resource; -import com.google.protobuf.ByteString; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.ResourceType; import org.thingsboard.server.common.data.TbResource; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.gen.edge.v1.ResourceUpdateMsg; @@ -29,6 +29,11 @@ public class ResourceMsgConstructorV1 extends BaseResourceMsgConstructor { @Override public ResourceUpdateMsg constructResourceUpdatedMsg(UpdateMsgType msgType, TbResource tbResource) { + if (ResourceType.IMAGE.equals(tbResource.getResourceType())) { + // Exclude support for a recently added resource type when dealing with older Edges + // to maintain compatibility and avoid potential issues. + return null; + } ResourceUpdateMsg.Builder builder = ResourceUpdateMsg.newBuilder() .setMsgType(msgType) .setIdMSB(tbResource.getId().getId().getMostSignificantBits()) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/tenant/TenantMsgConstructorV1.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/tenant/TenantMsgConstructorV1.java index a3f815cc18..b454a3b971 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/tenant/TenantMsgConstructorV1.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/tenant/TenantMsgConstructorV1.java @@ -78,7 +78,7 @@ public class TenantMsgConstructorV1 implements TenantMsgConstructor { @Override public TenantProfileUpdateMsg constructTenantProfileUpdateMsg(UpdateMsgType msgType, TenantProfile tenantProfile, EdgeVersion edgeVersion) { - ByteString profileData = EdgeVersionUtils.isEdgeVersionOlderThan(edgeVersion, EdgeVersion.V_3_6_1) ? + ByteString profileData = EdgeVersionUtils.isEdgeVersionOlderThan(edgeVersion, EdgeVersion.V_3_6_2) ? ByteString.empty() : ByteString.copyFrom(dataDecodingEncodingService.encode(tenantProfile.getProfileData())); TenantProfileUpdateMsg.Builder builder = TenantProfileUpdateMsg.newBuilder() .setMsgType(msgType) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/widget/WidgetMsgConstructorV1.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/widget/WidgetMsgConstructorV1.java index 67bdbf1f54..1bc6857863 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/widget/WidgetMsgConstructorV1.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/widget/WidgetMsgConstructorV1.java @@ -16,11 +16,13 @@ package org.thingsboard.server.service.edge.rpc.constructor.widget; import com.google.protobuf.ByteString; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.id.TenantId; 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.gen.edge.v1.EdgeVersion; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; import org.thingsboard.server.gen.edge.v1.WidgetTypeUpdateMsg; @@ -36,8 +38,12 @@ import java.util.List; @TbCoreComponent public class WidgetMsgConstructorV1 extends BaseWidgetMsgConstructor { + @Autowired + private ImageService imageService; + @Override public WidgetsBundleUpdateMsg constructWidgetsBundleUpdateMsg(UpdateMsgType msgType, WidgetsBundle widgetsBundle, List widgets) { + imageService.inlineImageForEdge(widgetsBundle); WidgetsBundleUpdateMsg.Builder builder = WidgetsBundleUpdateMsg.newBuilder() .setMsgType(msgType) .setIdMSB(widgetsBundle.getId().getId().getMostSignificantBits()) @@ -62,6 +68,7 @@ public class WidgetMsgConstructorV1 extends BaseWidgetMsgConstructor { @Override public WidgetTypeUpdateMsg constructWidgetTypeUpdateMsg(UpdateMsgType msgType, WidgetTypeDetails widgetTypeDetails, EdgeVersion edgeVersion) { + imageService.inlineImagesForEdge(widgetTypeDetails); WidgetTypeUpdateMsg.Builder builder = WidgetTypeUpdateMsg.newBuilder() .setMsgType(msgType) .setIdMSB(widgetTypeDetails.getId().getId().getMostSignificantBits()) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/resource/ResourceEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/resource/ResourceEdgeProcessor.java index f06991fd0f..f0da087472 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/resource/ResourceEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/resource/ResourceEdgeProcessor.java @@ -81,10 +81,10 @@ public abstract class ResourceEdgeProcessor extends BaseResourceProcessor implem UpdateMsgType msgType = getUpdateMsgType(edgeEvent.getAction()); ResourceUpdateMsg resourceUpdateMsg = ((ResourceMsgConstructor) resourceMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion)).constructResourceUpdatedMsg(msgType, tbResource); - downlinkMsg = DownlinkMsg.newBuilder() + downlinkMsg = resourceUpdateMsg != null ? DownlinkMsg.newBuilder() .setDownlinkMsgId(EdgeUtils.nextPositiveInt()) .addResourceUpdateMsg(resourceUpdateMsg) - .build(); + .build() : null; } break; case DELETED: diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/resource/ResourceEdgeProcessorV1.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/resource/ResourceEdgeProcessorV1.java index dd105729fe..56b1d5507c 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/resource/ResourceEdgeProcessorV1.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/resource/ResourceEdgeProcessorV1.java @@ -41,7 +41,7 @@ public class ResourceEdgeProcessorV1 extends ResourceEdgeProcessor { resource.setResourceKey(resourceUpdateMsg.getResourceKey()); resource.setResourceType(ResourceType.valueOf(resourceUpdateMsg.getResourceType())); resource.setFileName(resourceUpdateMsg.getFileName()); - resource.setData(resourceUpdateMsg.hasData() ? resourceUpdateMsg.getData().getBytes() : null); + resource.setEncodedData(resourceUpdateMsg.hasData() ? resourceUpdateMsg.getData() : null); resource.setEtag(resourceUpdateMsg.hasEtag() ? resourceUpdateMsg.getEtag() : null); return resource; } 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 f51f83d2f0..7e5542919b 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 @@ -47,7 +47,9 @@ public interface ImageService { TbResourceInfo findSystemOrTenantImageByEtag(TenantId tenantId, String etag); boolean replaceBase64WithImageUrl(HasImage entity, String type); + boolean replaceBase64WithImageUrl(Dashboard dashboard); + boolean replaceBase64WithImageUrl(WidgetTypeDetails widgetType); void inlineImage(HasImage entity); @@ -55,4 +57,10 @@ public interface ImageService { void inlineImages(Dashboard dashboard); void inlineImages(WidgetTypeDetails widgetTypeDetails); + + void inlineImageForEdge(HasImage entity); + + void inlineImagesForEdge(Dashboard dashboard); + + void inlineImagesForEdge(WidgetTypeDetails widgetTypeDetails); } 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 ad3934f76e..b2da580009 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 @@ -517,17 +517,37 @@ public class BaseImageService extends BaseResourceService implements ImageServic public void inlineImages(Dashboard dashboard) { log.trace("Executing inlineImage [{}] [Dashboard] [{}]", dashboard.getTenantId(), dashboard.getId()); inlineImage(dashboard); - inlineIntoJson(dashboard.getTenantId(), dashboard.getConfiguration()); + inlineIntoJson(dashboard.getTenantId(), dashboard.getConfiguration(), true); } @Override public void inlineImages(WidgetTypeDetails widgetTypeDetails) { log.trace("Executing inlineImage [{}] [WidgetTypeDetails] [{}]", widgetTypeDetails.getTenantId(), widgetTypeDetails.getId()); inlineImage(widgetTypeDetails); - inlineIntoJson(widgetTypeDetails.getTenantId(), widgetTypeDetails.getDescriptor()); + inlineIntoJson(widgetTypeDetails.getTenantId(), widgetTypeDetails.getDescriptor(), true); } - private void inlineIntoJson(TenantId tenantId, JsonNode root) { + @Override + public void inlineImageForEdge(HasImage entity) { + log.trace("Executing inlineImageForEdge [{}] [{}] [{}]", entity.getTenantId(), entity.getClass().getSimpleName(), entity.getName()); + entity.setImage(inlineImage(entity.getTenantId(), "image", entity.getImage(), false)); + } + + @Override + public void inlineImagesForEdge(Dashboard dashboard) { + log.trace("Executing inlineImagesForEdge [{}] [Dashboard] [{}]", dashboard.getTenantId(), dashboard.getId()); + inlineImageForEdge(dashboard); + inlineIntoJson(dashboard.getTenantId(), dashboard.getConfiguration(), false); + } + + @Override + public void inlineImagesForEdge(WidgetTypeDetails widgetTypeDetails) { + log.trace("Executing inlineImage [{}] [WidgetTypeDetails] [{}]", widgetTypeDetails.getTenantId(), widgetTypeDetails.getId()); + inlineImageForEdge(widgetTypeDetails); + inlineIntoJson(widgetTypeDetails.getTenantId(), widgetTypeDetails.getDescriptor(), false); + } + + private void inlineIntoJson(TenantId tenantId, JsonNode root, boolean addTbImagePrefix) { Queue tasks = new LinkedList<>(); tasks.add(new JsonNodeProcessingTask("", root)); while (!tasks.isEmpty()) { @@ -543,7 +563,7 @@ public class BaseImageService extends BaseResourceService implements ImageServic String childName = it.next(); JsonNode childValue = on.get(childName); if (childValue.isTextual()) { - on.put(childName, inlineImage(tenantId, currentPath + childName, childValue.asText())); + on.put(childName, inlineImage(tenantId, currentPath + childName, childValue.asText(), addTbImagePrefix)); } else if (childValue.isObject() || childValue.isArray()) { tasks.add(new JsonNodeProcessingTask(currentPath + childName, childValue)); } @@ -555,7 +575,7 @@ public class BaseImageService extends BaseResourceService implements ImageServic if (element.isObject()) { tasks.add(new JsonNodeProcessingTask(currentPath + "." + i, element)); } else if (element.isTextual()) { - childArray.set(i, inlineImage(tenantId, currentPath + "." + i, element.asText())); + childArray.set(i, inlineImage(tenantId, currentPath + "." + i, element.asText(), addTbImagePrefix)); } } } @@ -563,6 +583,10 @@ public class BaseImageService extends BaseResourceService implements ImageServic } private String inlineImage(TenantId tenantId, String path, String url) { + return inlineImage(tenantId, path, url, true); + } + + private String inlineImage(TenantId tenantId, String path, String url, boolean addTbImagePrefix) { try { ImageCacheKey key = getKeyFromUrl(tenantId, url); if (key != null) { @@ -570,8 +594,11 @@ public class BaseImageService extends BaseResourceService implements ImageServic if (imageInfo != null) { byte[] data = key.isPreview() ? getImagePreview(tenantId, imageInfo.getId()) : getImageData(tenantId, imageInfo.getId()); ImageDescriptor descriptor = getImageDescriptor(imageInfo, key.isPreview()); - String tbImagePrefix = "tb-image:" + Base64Utils.encodeToString(imageInfo.getResourceKey().getBytes(StandardCharsets.UTF_8)) + ":" - + Base64Utils.encodeToString(imageInfo.getName().getBytes(StandardCharsets.UTF_8)) + ";"; + String tbImagePrefix = ""; + if (addTbImagePrefix) { + tbImagePrefix = "tb-image:" + Base64Utils.encodeToString(imageInfo.getResourceKey().getBytes(StandardCharsets.UTF_8)) + ":" + + Base64Utils.encodeToString(imageInfo.getName().getBytes(StandardCharsets.UTF_8)) + ";"; + } return tbImagePrefix + "data:" + descriptor.getMediaType() + ";base64," + Base64Utils.encodeToString(data); } }