Add handling logic for backward compatibility with previous Edges

This commit is contained in:
Andrii Landiak 2023-12-08 13:46:42 +02:00
parent 607c04f59d
commit 2378f2ec2d
10 changed files with 76 additions and 12 deletions

View File

@ -16,10 +16,12 @@
package org.thingsboard.server.service.edge.rpc.constructor.asset; package org.thingsboard.server.service.edge.rpc.constructor.asset;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.asset.AssetProfile; 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.AssetProfileUpdateMsg;
import org.thingsboard.server.gen.edge.v1.AssetUpdateMsg; import org.thingsboard.server.gen.edge.v1.AssetUpdateMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType; import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
@ -31,6 +33,9 @@ import java.nio.charset.StandardCharsets;
@TbCoreComponent @TbCoreComponent
public class AssetMsgConstructorV1 extends BaseAssetMsgConstructor { public class AssetMsgConstructorV1 extends BaseAssetMsgConstructor {
@Autowired
private ImageService imageService;
@Override @Override
public AssetUpdateMsg constructAssetUpdatedMsg(UpdateMsgType msgType, Asset asset) { public AssetUpdateMsg constructAssetUpdatedMsg(UpdateMsgType msgType, Asset asset) {
AssetUpdateMsg.Builder builder = AssetUpdateMsg.newBuilder() AssetUpdateMsg.Builder builder = AssetUpdateMsg.newBuilder()
@ -58,6 +63,7 @@ public class AssetMsgConstructorV1 extends BaseAssetMsgConstructor {
@Override @Override
public AssetProfileUpdateMsg constructAssetProfileUpdatedMsg(UpdateMsgType msgType, AssetProfile assetProfile) { public AssetProfileUpdateMsg constructAssetProfileUpdatedMsg(UpdateMsgType msgType, AssetProfile assetProfile) {
imageService.inlineImageForEdge(assetProfile);
AssetProfileUpdateMsg.Builder builder = AssetProfileUpdateMsg.newBuilder() AssetProfileUpdateMsg.Builder builder = AssetProfileUpdateMsg.newBuilder()
.setMsgType(msgType) .setMsgType(msgType)
.setIdMSB(assetProfile.getId().getId().getMostSignificantBits()) .setIdMSB(assetProfile.getId().getId().getMostSignificantBits())

View File

@ -15,9 +15,11 @@
*/ */
package org.thingsboard.server.service.edge.rpc.constructor.dashboard; package org.thingsboard.server.service.edge.rpc.constructor.dashboard;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.Dashboard; 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.DashboardUpdateMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType; import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
@ -26,8 +28,12 @@ import org.thingsboard.server.queue.util.TbCoreComponent;
@TbCoreComponent @TbCoreComponent
public class DashboardMsgConstructorV1 extends BaseDashboardMsgConstructor { public class DashboardMsgConstructorV1 extends BaseDashboardMsgConstructor {
@Autowired
private ImageService imageService;
@Override @Override
public DashboardUpdateMsg constructDashboardUpdatedMsg(UpdateMsgType msgType, Dashboard dashboard) { public DashboardUpdateMsg constructDashboardUpdatedMsg(UpdateMsgType msgType, Dashboard dashboard) {
imageService.inlineImagesForEdge(dashboard);
DashboardUpdateMsg.Builder builder = DashboardUpdateMsg.newBuilder() DashboardUpdateMsg.Builder builder = DashboardUpdateMsg.newBuilder()
.setMsgType(msgType) .setMsgType(msgType)
.setIdMSB(dashboard.getId().getId().getMostSignificantBits()) .setIdMSB(dashboard.getId().getId().getMostSignificantBits())

View File

@ -22,6 +22,7 @@ import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.security.DeviceCredentials; 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.DeviceCredentialsUpdateMsg;
import org.thingsboard.server.gen.edge.v1.DeviceProfileUpdateMsg; import org.thingsboard.server.gen.edge.v1.DeviceProfileUpdateMsg;
import org.thingsboard.server.gen.edge.v1.DeviceUpdateMsg; import org.thingsboard.server.gen.edge.v1.DeviceUpdateMsg;
@ -38,6 +39,9 @@ public class DeviceMsgConstructorV1 extends BaseDeviceMsgConstructor {
@Autowired @Autowired
private DataDecodingEncodingService dataDecodingEncodingService; private DataDecodingEncodingService dataDecodingEncodingService;
@Autowired
private ImageService imageService;
@Override @Override
public DeviceUpdateMsg constructDeviceUpdatedMsg(UpdateMsgType msgType, Device device) { public DeviceUpdateMsg constructDeviceUpdatedMsg(UpdateMsgType msgType, Device device) {
DeviceUpdateMsg.Builder builder = DeviceUpdateMsg.newBuilder() DeviceUpdateMsg.Builder builder = DeviceUpdateMsg.newBuilder()
@ -91,6 +95,7 @@ public class DeviceMsgConstructorV1 extends BaseDeviceMsgConstructor {
@Override @Override
public DeviceProfileUpdateMsg constructDeviceProfileUpdatedMsg(UpdateMsgType msgType, DeviceProfile deviceProfile) { public DeviceProfileUpdateMsg constructDeviceProfileUpdatedMsg(UpdateMsgType msgType, DeviceProfile deviceProfile) {
imageService.inlineImageForEdge(deviceProfile);
DeviceProfileUpdateMsg.Builder builder = DeviceProfileUpdateMsg.newBuilder() DeviceProfileUpdateMsg.Builder builder = DeviceProfileUpdateMsg.newBuilder()
.setMsgType(msgType) .setMsgType(msgType)
.setIdMSB(deviceProfile.getId().getId().getMostSignificantBits()) .setIdMSB(deviceProfile.getId().getId().getMostSignificantBits())

View File

@ -15,8 +15,8 @@
*/ */
package org.thingsboard.server.service.edge.rpc.constructor.resource; package org.thingsboard.server.service.edge.rpc.constructor.resource;
import com.google.protobuf.ByteString;
import org.springframework.stereotype.Component; 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.TbResource;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.gen.edge.v1.ResourceUpdateMsg; import org.thingsboard.server.gen.edge.v1.ResourceUpdateMsg;
@ -29,6 +29,11 @@ public class ResourceMsgConstructorV1 extends BaseResourceMsgConstructor {
@Override @Override
public ResourceUpdateMsg constructResourceUpdatedMsg(UpdateMsgType msgType, TbResource tbResource) { 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() ResourceUpdateMsg.Builder builder = ResourceUpdateMsg.newBuilder()
.setMsgType(msgType) .setMsgType(msgType)
.setIdMSB(tbResource.getId().getId().getMostSignificantBits()) .setIdMSB(tbResource.getId().getId().getMostSignificantBits())

View File

@ -78,7 +78,7 @@ public class TenantMsgConstructorV1 implements TenantMsgConstructor {
@Override @Override
public TenantProfileUpdateMsg constructTenantProfileUpdateMsg(UpdateMsgType msgType, TenantProfile tenantProfile, EdgeVersion edgeVersion) { 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())); ByteString.empty() : ByteString.copyFrom(dataDecodingEncodingService.encode(tenantProfile.getProfileData()));
TenantProfileUpdateMsg.Builder builder = TenantProfileUpdateMsg.newBuilder() TenantProfileUpdateMsg.Builder builder = TenantProfileUpdateMsg.newBuilder()
.setMsgType(msgType) .setMsgType(msgType)

View File

@ -16,11 +16,13 @@
package org.thingsboard.server.service.edge.rpc.constructor.widget; package org.thingsboard.server.service.edge.rpc.constructor.widget;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.widget.WidgetTypeDetails; import org.thingsboard.server.common.data.widget.WidgetTypeDetails;
import org.thingsboard.server.common.data.widget.WidgetsBundle; 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.EdgeVersion;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType; import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.gen.edge.v1.WidgetTypeUpdateMsg; import org.thingsboard.server.gen.edge.v1.WidgetTypeUpdateMsg;
@ -36,8 +38,12 @@ import java.util.List;
@TbCoreComponent @TbCoreComponent
public class WidgetMsgConstructorV1 extends BaseWidgetMsgConstructor { public class WidgetMsgConstructorV1 extends BaseWidgetMsgConstructor {
@Autowired
private ImageService imageService;
@Override @Override
public WidgetsBundleUpdateMsg constructWidgetsBundleUpdateMsg(UpdateMsgType msgType, WidgetsBundle widgetsBundle, List<String> widgets) { public WidgetsBundleUpdateMsg constructWidgetsBundleUpdateMsg(UpdateMsgType msgType, WidgetsBundle widgetsBundle, List<String> widgets) {
imageService.inlineImageForEdge(widgetsBundle);
WidgetsBundleUpdateMsg.Builder builder = WidgetsBundleUpdateMsg.newBuilder() WidgetsBundleUpdateMsg.Builder builder = WidgetsBundleUpdateMsg.newBuilder()
.setMsgType(msgType) .setMsgType(msgType)
.setIdMSB(widgetsBundle.getId().getId().getMostSignificantBits()) .setIdMSB(widgetsBundle.getId().getId().getMostSignificantBits())
@ -62,6 +68,7 @@ public class WidgetMsgConstructorV1 extends BaseWidgetMsgConstructor {
@Override @Override
public WidgetTypeUpdateMsg constructWidgetTypeUpdateMsg(UpdateMsgType msgType, WidgetTypeDetails widgetTypeDetails, EdgeVersion edgeVersion) { public WidgetTypeUpdateMsg constructWidgetTypeUpdateMsg(UpdateMsgType msgType, WidgetTypeDetails widgetTypeDetails, EdgeVersion edgeVersion) {
imageService.inlineImagesForEdge(widgetTypeDetails);
WidgetTypeUpdateMsg.Builder builder = WidgetTypeUpdateMsg.newBuilder() WidgetTypeUpdateMsg.Builder builder = WidgetTypeUpdateMsg.newBuilder()
.setMsgType(msgType) .setMsgType(msgType)
.setIdMSB(widgetTypeDetails.getId().getId().getMostSignificantBits()) .setIdMSB(widgetTypeDetails.getId().getId().getMostSignificantBits())

View File

@ -81,10 +81,10 @@ public abstract class ResourceEdgeProcessor extends BaseResourceProcessor implem
UpdateMsgType msgType = getUpdateMsgType(edgeEvent.getAction()); UpdateMsgType msgType = getUpdateMsgType(edgeEvent.getAction());
ResourceUpdateMsg resourceUpdateMsg = ((ResourceMsgConstructor) ResourceUpdateMsg resourceUpdateMsg = ((ResourceMsgConstructor)
resourceMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion)).constructResourceUpdatedMsg(msgType, tbResource); resourceMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion)).constructResourceUpdatedMsg(msgType, tbResource);
downlinkMsg = DownlinkMsg.newBuilder() downlinkMsg = resourceUpdateMsg != null ? DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt()) .setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addResourceUpdateMsg(resourceUpdateMsg) .addResourceUpdateMsg(resourceUpdateMsg)
.build(); .build() : null;
} }
break; break;
case DELETED: case DELETED:

View File

@ -41,7 +41,7 @@ public class ResourceEdgeProcessorV1 extends ResourceEdgeProcessor {
resource.setResourceKey(resourceUpdateMsg.getResourceKey()); resource.setResourceKey(resourceUpdateMsg.getResourceKey());
resource.setResourceType(ResourceType.valueOf(resourceUpdateMsg.getResourceType())); resource.setResourceType(ResourceType.valueOf(resourceUpdateMsg.getResourceType()));
resource.setFileName(resourceUpdateMsg.getFileName()); 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); resource.setEtag(resourceUpdateMsg.hasEtag() ? resourceUpdateMsg.getEtag() : null);
return resource; return resource;
} }

View File

@ -47,7 +47,9 @@ public interface ImageService {
TbResourceInfo findSystemOrTenantImageByEtag(TenantId tenantId, String etag); TbResourceInfo findSystemOrTenantImageByEtag(TenantId tenantId, String etag);
boolean replaceBase64WithImageUrl(HasImage entity, String type); boolean replaceBase64WithImageUrl(HasImage entity, String type);
boolean replaceBase64WithImageUrl(Dashboard dashboard); boolean replaceBase64WithImageUrl(Dashboard dashboard);
boolean replaceBase64WithImageUrl(WidgetTypeDetails widgetType); boolean replaceBase64WithImageUrl(WidgetTypeDetails widgetType);
void inlineImage(HasImage entity); void inlineImage(HasImage entity);
@ -55,4 +57,10 @@ public interface ImageService {
void inlineImages(Dashboard dashboard); void inlineImages(Dashboard dashboard);
void inlineImages(WidgetTypeDetails widgetTypeDetails); void inlineImages(WidgetTypeDetails widgetTypeDetails);
void inlineImageForEdge(HasImage entity);
void inlineImagesForEdge(Dashboard dashboard);
void inlineImagesForEdge(WidgetTypeDetails widgetTypeDetails);
} }

View File

@ -517,17 +517,37 @@ public class BaseImageService extends BaseResourceService implements ImageServic
public void inlineImages(Dashboard dashboard) { public void inlineImages(Dashboard dashboard) {
log.trace("Executing inlineImage [{}] [Dashboard] [{}]", dashboard.getTenantId(), dashboard.getId()); log.trace("Executing inlineImage [{}] [Dashboard] [{}]", dashboard.getTenantId(), dashboard.getId());
inlineImage(dashboard); inlineImage(dashboard);
inlineIntoJson(dashboard.getTenantId(), dashboard.getConfiguration()); inlineIntoJson(dashboard.getTenantId(), dashboard.getConfiguration(), true);
} }
@Override @Override
public void inlineImages(WidgetTypeDetails widgetTypeDetails) { public void inlineImages(WidgetTypeDetails widgetTypeDetails) {
log.trace("Executing inlineImage [{}] [WidgetTypeDetails] [{}]", widgetTypeDetails.getTenantId(), widgetTypeDetails.getId()); log.trace("Executing inlineImage [{}] [WidgetTypeDetails] [{}]", widgetTypeDetails.getTenantId(), widgetTypeDetails.getId());
inlineImage(widgetTypeDetails); 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<JsonNodeProcessingTask> tasks = new LinkedList<>(); Queue<JsonNodeProcessingTask> tasks = new LinkedList<>();
tasks.add(new JsonNodeProcessingTask("", root)); tasks.add(new JsonNodeProcessingTask("", root));
while (!tasks.isEmpty()) { while (!tasks.isEmpty()) {
@ -543,7 +563,7 @@ public class BaseImageService extends BaseResourceService implements ImageServic
String childName = it.next(); String childName = it.next();
JsonNode childValue = on.get(childName); JsonNode childValue = on.get(childName);
if (childValue.isTextual()) { 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()) { } else if (childValue.isObject() || childValue.isArray()) {
tasks.add(new JsonNodeProcessingTask(currentPath + childName, childValue)); tasks.add(new JsonNodeProcessingTask(currentPath + childName, childValue));
} }
@ -555,7 +575,7 @@ public class BaseImageService extends BaseResourceService implements ImageServic
if (element.isObject()) { if (element.isObject()) {
tasks.add(new JsonNodeProcessingTask(currentPath + "." + i, element)); tasks.add(new JsonNodeProcessingTask(currentPath + "." + i, element));
} else if (element.isTextual()) { } 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) { 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 { try {
ImageCacheKey key = getKeyFromUrl(tenantId, url); ImageCacheKey key = getKeyFromUrl(tenantId, url);
if (key != null) { if (key != null) {
@ -570,8 +594,11 @@ public class BaseImageService extends BaseResourceService implements ImageServic
if (imageInfo != null) { if (imageInfo != null) {
byte[] data = key.isPreview() ? getImagePreview(tenantId, imageInfo.getId()) : getImageData(tenantId, imageInfo.getId()); byte[] data = key.isPreview() ? getImagePreview(tenantId, imageInfo.getId()) : getImageData(tenantId, imageInfo.getId());
ImageDescriptor descriptor = getImageDescriptor(imageInfo, key.isPreview()); ImageDescriptor descriptor = getImageDescriptor(imageInfo, key.isPreview());
String tbImagePrefix = "tb-image:" + Base64Utils.encodeToString(imageInfo.getResourceKey().getBytes(StandardCharsets.UTF_8)) + ":" String tbImagePrefix = "";
+ Base64Utils.encodeToString(imageInfo.getName().getBytes(StandardCharsets.UTF_8)) + ";"; 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); return tbImagePrefix + "data:" + descriptor.getMediaType() + ";base64," + Base64Utils.encodeToString(data);
} }
} }