|
|
|
@ -18,39 +18,29 @@ package org.thingsboard.server.service.edge.rpc; |
|
|
|
import com.datastax.driver.core.utils.UUIDs; |
|
|
|
import com.fasterxml.jackson.core.JsonProcessingException; |
|
|
|
import com.fasterxml.jackson.databind.ObjectMapper; |
|
|
|
import com.fasterxml.jackson.databind.node.ObjectNode; |
|
|
|
import com.google.common.util.concurrent.FutureCallback; |
|
|
|
import com.google.common.util.concurrent.Futures; |
|
|
|
import com.google.common.util.concurrent.ListenableFuture; |
|
|
|
import com.google.common.util.concurrent.MoreExecutors; |
|
|
|
import com.google.common.util.concurrent.SettableFuture; |
|
|
|
import com.google.gson.Gson; |
|
|
|
import com.google.gson.JsonElement; |
|
|
|
import com.google.gson.JsonObject; |
|
|
|
import io.grpc.stub.StreamObserver; |
|
|
|
import lombok.Data; |
|
|
|
import lombok.extern.slf4j.Slf4j; |
|
|
|
import org.apache.commons.lang.RandomStringUtils; |
|
|
|
import org.checkerframework.checker.nullness.qual.Nullable; |
|
|
|
import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg; |
|
|
|
import org.thingsboard.server.common.data.AdminSettings; |
|
|
|
import org.thingsboard.server.common.data.Customer; |
|
|
|
import org.thingsboard.server.common.data.Dashboard; |
|
|
|
import org.thingsboard.server.common.data.DataConstants; |
|
|
|
import org.thingsboard.server.common.data.Device; |
|
|
|
import org.thingsboard.server.common.data.EntityType; |
|
|
|
import org.thingsboard.server.common.data.EntityView; |
|
|
|
import org.thingsboard.server.common.data.HasCustomerId; |
|
|
|
import org.thingsboard.server.common.data.User; |
|
|
|
import org.thingsboard.server.common.data.alarm.Alarm; |
|
|
|
import org.thingsboard.server.common.data.alarm.AlarmSeverity; |
|
|
|
import org.thingsboard.server.common.data.alarm.AlarmStatus; |
|
|
|
import org.thingsboard.server.common.data.asset.Asset; |
|
|
|
import org.thingsboard.server.common.data.audit.ActionType; |
|
|
|
import org.thingsboard.server.common.data.edge.Edge; |
|
|
|
import org.thingsboard.server.common.data.edge.EdgeEvent; |
|
|
|
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; |
|
|
|
import org.thingsboard.server.common.data.exception.ThingsboardException; |
|
|
|
import org.thingsboard.server.common.data.edge.EdgeEventType; |
|
|
|
import org.thingsboard.server.common.data.id.AlarmId; |
|
|
|
import org.thingsboard.server.common.data.id.AssetId; |
|
|
|
import org.thingsboard.server.common.data.id.CustomerId; |
|
|
|
@ -58,38 +48,28 @@ import org.thingsboard.server.common.data.id.DashboardId; |
|
|
|
import org.thingsboard.server.common.data.id.DeviceId; |
|
|
|
import org.thingsboard.server.common.data.id.EdgeId; |
|
|
|
import org.thingsboard.server.common.data.id.EntityId; |
|
|
|
import org.thingsboard.server.common.data.id.EntityIdFactory; |
|
|
|
import org.thingsboard.server.common.data.id.EntityViewId; |
|
|
|
import org.thingsboard.server.common.data.id.RuleChainId; |
|
|
|
import org.thingsboard.server.common.data.id.TenantId; |
|
|
|
import org.thingsboard.server.common.data.id.UserId; |
|
|
|
import org.thingsboard.server.common.data.id.WidgetTypeId; |
|
|
|
import org.thingsboard.server.common.data.id.WidgetsBundleId; |
|
|
|
import org.thingsboard.server.common.data.kv.AttributeKey; |
|
|
|
import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
|
|
|
import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; |
|
|
|
import org.thingsboard.server.common.data.kv.LongDataEntry; |
|
|
|
import org.thingsboard.server.common.data.page.TimePageData; |
|
|
|
import org.thingsboard.server.common.data.page.TimePageLink; |
|
|
|
import org.thingsboard.server.common.data.relation.EntityRelation; |
|
|
|
import org.thingsboard.server.common.data.relation.RelationTypeGroup; |
|
|
|
import org.thingsboard.server.common.data.rule.RuleChain; |
|
|
|
import org.thingsboard.server.common.data.rule.RuleChainMetaData; |
|
|
|
import org.thingsboard.server.common.data.security.DeviceCredentials; |
|
|
|
import org.thingsboard.server.common.data.security.DeviceCredentialsType; |
|
|
|
import org.thingsboard.server.common.data.security.UserCredentials; |
|
|
|
import org.thingsboard.server.common.data.widget.WidgetType; |
|
|
|
import org.thingsboard.server.common.data.widget.WidgetsBundle; |
|
|
|
import org.thingsboard.server.common.msg.TbMsg; |
|
|
|
import org.thingsboard.server.common.msg.TbMsgMetaData; |
|
|
|
import org.thingsboard.server.common.msg.queue.ServiceType; |
|
|
|
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; |
|
|
|
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|
|
|
import org.thingsboard.server.common.transport.util.JsonUtils; |
|
|
|
import org.thingsboard.server.gen.edge.AdminSettingsUpdateMsg; |
|
|
|
import org.thingsboard.server.gen.edge.AlarmUpdateMsg; |
|
|
|
import org.thingsboard.server.gen.edge.AssetUpdateMsg; |
|
|
|
import org.thingsboard.server.gen.edge.AttributeDeleteMsg; |
|
|
|
import org.thingsboard.server.gen.edge.AttributesRequestMsg; |
|
|
|
import org.thingsboard.server.gen.edge.ConnectRequestMsg; |
|
|
|
import org.thingsboard.server.gen.edge.ConnectResponseCode; |
|
|
|
@ -119,20 +99,13 @@ import org.thingsboard.server.gen.edge.UserCredentialsRequestMsg; |
|
|
|
import org.thingsboard.server.gen.edge.UserCredentialsUpdateMsg; |
|
|
|
import org.thingsboard.server.gen.edge.WidgetTypeUpdateMsg; |
|
|
|
import org.thingsboard.server.gen.edge.WidgetsBundleUpdateMsg; |
|
|
|
import org.thingsboard.server.gen.transport.TransportProtos; |
|
|
|
import org.thingsboard.server.queue.TbQueueCallback; |
|
|
|
import org.thingsboard.server.queue.TbQueueMsgMetadata; |
|
|
|
import org.thingsboard.server.queue.TbQueueProducer; |
|
|
|
import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
|
|
|
import org.thingsboard.server.service.edge.EdgeContextComponent; |
|
|
|
|
|
|
|
import java.io.Closeable; |
|
|
|
import java.util.ArrayList; |
|
|
|
import java.util.Collections; |
|
|
|
import java.util.HashSet; |
|
|
|
import java.util.List; |
|
|
|
import java.util.Optional; |
|
|
|
import java.util.Set; |
|
|
|
import java.util.UUID; |
|
|
|
import java.util.concurrent.CountDownLatch; |
|
|
|
import java.util.concurrent.ExecutionException; |
|
|
|
@ -145,12 +118,8 @@ import java.util.function.Consumer; |
|
|
|
@Data |
|
|
|
public final class EdgeGrpcSession implements Closeable { |
|
|
|
|
|
|
|
private static final ReentrantLock deviceCreationLock = new ReentrantLock(); |
|
|
|
|
|
|
|
private static final ReentrantLock responseMsgLock = new ReentrantLock(); |
|
|
|
|
|
|
|
private final Gson gson = new Gson(); |
|
|
|
|
|
|
|
private static final String QUEUE_START_TS_ATTR_KEY = "queueStartTs"; |
|
|
|
|
|
|
|
private final UUID sessionId; |
|
|
|
@ -166,8 +135,6 @@ public final class EdgeGrpcSession implements Closeable { |
|
|
|
|
|
|
|
private CountDownLatch latch; |
|
|
|
|
|
|
|
private TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToRuleEngineMsg>> ruleEngineMsgProducer; |
|
|
|
|
|
|
|
EdgeGrpcSession(EdgeContextComponent ctx, StreamObserver<ResponseMsg> outputStream, BiConsumer<EdgeId, EdgeGrpcSession> sessionOpenListener, |
|
|
|
Consumer<EdgeId> sessionCloseListener, ObjectMapper mapper) { |
|
|
|
this.sessionId = UUID.randomUUID(); |
|
|
|
@ -176,7 +143,6 @@ public final class EdgeGrpcSession implements Closeable { |
|
|
|
this.sessionOpenListener = sessionOpenListener; |
|
|
|
this.sessionCloseListener = sessionCloseListener; |
|
|
|
this.mapper = mapper; |
|
|
|
this.ruleEngineMsgProducer = ctx.getProducerProvider().getRuleEngineMsgProducer(); |
|
|
|
initInputStream(); |
|
|
|
} |
|
|
|
|
|
|
|
@ -361,6 +327,12 @@ public final class EdgeGrpcSession implements Closeable { |
|
|
|
case TIMESERIES_UPDATED: |
|
|
|
downlinkMsg = processTelemetryMessage(edgeEvent); |
|
|
|
break; |
|
|
|
case CREDENTIALS_REQUEST: |
|
|
|
downlinkMsg = processCredentialsRequestMessage(edgeEvent); |
|
|
|
break; |
|
|
|
case ENTITY_EXISTS_REQUEST: |
|
|
|
downlinkMsg = processEntityExistsRequestMessage(edgeEvent); |
|
|
|
break; |
|
|
|
} |
|
|
|
if (downlinkMsg != null) { |
|
|
|
result.add(downlinkMsg); |
|
|
|
@ -372,6 +344,36 @@ public final class EdgeGrpcSession implements Closeable { |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
private DownlinkMsg processEntityExistsRequestMessage(EdgeEvent edgeEvent) { |
|
|
|
DownlinkMsg downlinkMsg = null; |
|
|
|
if (EdgeEventType.DEVICE.equals(edgeEvent.getEdgeEventType())) { |
|
|
|
DeviceId deviceId = new DeviceId(edgeEvent.getEntityId()); |
|
|
|
Device device = ctx.getDeviceService().findDeviceById(edge.getTenantId(), deviceId); |
|
|
|
CustomerId customerId = getCustomerIdIfEdgeAssignedToCustomer(device); |
|
|
|
DeviceUpdateMsg d = ctx.getDeviceMsgConstructor().constructDeviceUpdatedMsg(UpdateMsgType.DEVICE_CONFLICT_RPC_MESSAGE, device, customerId); |
|
|
|
downlinkMsg = DownlinkMsg.newBuilder() |
|
|
|
.addAllDeviceUpdateMsg(Collections.singletonList(d)) |
|
|
|
.build(); |
|
|
|
} |
|
|
|
return downlinkMsg; |
|
|
|
} |
|
|
|
|
|
|
|
private DownlinkMsg processCredentialsRequestMessage(EdgeEvent edgeEvent) { |
|
|
|
DownlinkMsg downlinkMsg = null; |
|
|
|
if (EdgeEventType.DEVICE.equals(edgeEvent.getEdgeEventType())) { |
|
|
|
DeviceId deviceId = new DeviceId(edgeEvent.getEntityId()); |
|
|
|
DeviceCredentialsRequestMsg deviceCredentialsRequestMsg = DeviceCredentialsRequestMsg.newBuilder() |
|
|
|
.setDeviceIdMSB(deviceId.getId().getMostSignificantBits()) |
|
|
|
.setDeviceIdLSB(deviceId.getId().getLeastSignificantBits()) |
|
|
|
.build(); |
|
|
|
DownlinkMsg.Builder builder = DownlinkMsg.newBuilder() |
|
|
|
.addAllDeviceCredentialsRequestMsg(Collections.singletonList(deviceCredentialsRequestMsg)); |
|
|
|
downlinkMsg = builder.build(); |
|
|
|
} |
|
|
|
return downlinkMsg; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private ListenableFuture<Long> getQueueStartTs() { |
|
|
|
ListenableFuture<Optional<AttributeKvEntry>> future = |
|
|
|
ctx.getAttributesService().find(edge.getTenantId(), edge.getId(), DataConstants.SERVER_SCOPE, QUEUE_START_TS_ATTR_KEY); |
|
|
|
@ -479,7 +481,7 @@ public final class EdgeGrpcSession implements Closeable { |
|
|
|
if (device != null) { |
|
|
|
CustomerId customerId = getCustomerIdIfEdgeAssignedToCustomer(device); |
|
|
|
DeviceUpdateMsg deviceUpdateMsg = |
|
|
|
ctx.getDeviceUpdateMsgConstructor().constructDeviceUpdatedMsg(msgType, device, customerId); |
|
|
|
ctx.getDeviceMsgConstructor().constructDeviceUpdatedMsg(msgType, device, customerId); |
|
|
|
downlinkMsg = DownlinkMsg.newBuilder() |
|
|
|
.addAllDeviceUpdateMsg(Collections.singletonList(deviceUpdateMsg)) |
|
|
|
.build(); |
|
|
|
@ -488,7 +490,7 @@ public final class EdgeGrpcSession implements Closeable { |
|
|
|
case DELETED: |
|
|
|
case UNASSIGNED_FROM_EDGE: |
|
|
|
DeviceUpdateMsg deviceUpdateMsg = |
|
|
|
ctx.getDeviceUpdateMsgConstructor().constructDeviceDeleteMsg(deviceId); |
|
|
|
ctx.getDeviceMsgConstructor().constructDeviceDeleteMsg(deviceId); |
|
|
|
downlinkMsg = DownlinkMsg.newBuilder() |
|
|
|
.addAllDeviceUpdateMsg(Collections.singletonList(deviceUpdateMsg)) |
|
|
|
.build(); |
|
|
|
@ -497,7 +499,7 @@ public final class EdgeGrpcSession implements Closeable { |
|
|
|
DeviceCredentials deviceCredentials = ctx.getDeviceCredentialsService().findDeviceCredentialsByDeviceId(edge.getTenantId(), deviceId); |
|
|
|
if (deviceCredentials != null) { |
|
|
|
DeviceCredentialsUpdateMsg deviceCredentialsUpdateMsg = |
|
|
|
ctx.getDeviceUpdateMsgConstructor().constructDeviceCredentialsUpdatedMsg(deviceCredentials); |
|
|
|
ctx.getDeviceMsgConstructor().constructDeviceCredentialsUpdatedMsg(deviceCredentials); |
|
|
|
downlinkMsg = DownlinkMsg.newBuilder() |
|
|
|
.addAllDeviceCredentialsUpdateMsg(Collections.singletonList(deviceCredentialsUpdateMsg)) |
|
|
|
.build(); |
|
|
|
@ -520,7 +522,7 @@ public final class EdgeGrpcSession implements Closeable { |
|
|
|
if (asset != null) { |
|
|
|
CustomerId customerId = getCustomerIdIfEdgeAssignedToCustomer(asset); |
|
|
|
AssetUpdateMsg assetUpdateMsg = |
|
|
|
ctx.getAssetUpdateMsgConstructor().constructAssetUpdatedMsg(msgType, asset, customerId); |
|
|
|
ctx.getAssetMsgConstructor().constructAssetUpdatedMsg(msgType, asset, customerId); |
|
|
|
downlinkMsg = DownlinkMsg.newBuilder() |
|
|
|
.addAllAssetUpdateMsg(Collections.singletonList(assetUpdateMsg)) |
|
|
|
.build(); |
|
|
|
@ -529,7 +531,7 @@ public final class EdgeGrpcSession implements Closeable { |
|
|
|
case DELETED: |
|
|
|
case UNASSIGNED_FROM_EDGE: |
|
|
|
AssetUpdateMsg assetUpdateMsg = |
|
|
|
ctx.getAssetUpdateMsgConstructor().constructAssetDeleteMsg(assetId); |
|
|
|
ctx.getAssetMsgConstructor().constructAssetDeleteMsg(assetId); |
|
|
|
downlinkMsg = DownlinkMsg.newBuilder() |
|
|
|
.addAllAssetUpdateMsg(Collections.singletonList(assetUpdateMsg)) |
|
|
|
.build(); |
|
|
|
@ -551,7 +553,7 @@ public final class EdgeGrpcSession implements Closeable { |
|
|
|
if (entityView != null) { |
|
|
|
CustomerId customerId = getCustomerIdIfEdgeAssignedToCustomer(entityView); |
|
|
|
EntityViewUpdateMsg entityViewUpdateMsg = |
|
|
|
ctx.getEntityViewUpdateMsgConstructor().constructEntityViewUpdatedMsg(msgType, entityView, customerId); |
|
|
|
ctx.getEntityViewMsgConstructor().constructEntityViewUpdatedMsg(msgType, entityView, customerId); |
|
|
|
downlinkMsg = DownlinkMsg.newBuilder() |
|
|
|
.addAllEntityViewUpdateMsg(Collections.singletonList(entityViewUpdateMsg)) |
|
|
|
.build(); |
|
|
|
@ -560,7 +562,7 @@ public final class EdgeGrpcSession implements Closeable { |
|
|
|
case DELETED: |
|
|
|
case UNASSIGNED_FROM_EDGE: |
|
|
|
EntityViewUpdateMsg entityViewUpdateMsg = |
|
|
|
ctx.getEntityViewUpdateMsgConstructor().constructEntityViewDeleteMsg(entityViewId); |
|
|
|
ctx.getEntityViewMsgConstructor().constructEntityViewDeleteMsg(entityViewId); |
|
|
|
downlinkMsg = DownlinkMsg.newBuilder() |
|
|
|
.addAllEntityViewUpdateMsg(Collections.singletonList(entityViewUpdateMsg)) |
|
|
|
.build(); |
|
|
|
@ -585,7 +587,7 @@ public final class EdgeGrpcSession implements Closeable { |
|
|
|
customerId = edge.getCustomerId(); |
|
|
|
} |
|
|
|
DashboardUpdateMsg dashboardUpdateMsg = |
|
|
|
ctx.getDashboardUpdateMsgConstructor().constructDashboardUpdatedMsg(msgType, dashboard, customerId); |
|
|
|
ctx.getDashboardMsgConstructor().constructDashboardUpdatedMsg(msgType, dashboard, customerId); |
|
|
|
downlinkMsg = DownlinkMsg.newBuilder() |
|
|
|
.addAllDashboardUpdateMsg(Collections.singletonList(dashboardUpdateMsg)) |
|
|
|
.build(); |
|
|
|
@ -594,7 +596,7 @@ public final class EdgeGrpcSession implements Closeable { |
|
|
|
case DELETED: |
|
|
|
case UNASSIGNED_FROM_EDGE: |
|
|
|
DashboardUpdateMsg dashboardUpdateMsg = |
|
|
|
ctx.getDashboardUpdateMsgConstructor().constructDashboardDeleteMsg(dashboardId); |
|
|
|
ctx.getDashboardMsgConstructor().constructDashboardDeleteMsg(dashboardId); |
|
|
|
downlinkMsg = DownlinkMsg.newBuilder() |
|
|
|
.addAllDashboardUpdateMsg(Collections.singletonList(dashboardUpdateMsg)) |
|
|
|
.build(); |
|
|
|
@ -612,7 +614,7 @@ public final class EdgeGrpcSession implements Closeable { |
|
|
|
Customer customer = ctx.getCustomerService().findCustomerById(edgeEvent.getTenantId(), customerId); |
|
|
|
if (customer != null) { |
|
|
|
CustomerUpdateMsg customerUpdateMsg = |
|
|
|
ctx.getCustomerUpdateMsgConstructor().constructCustomerUpdatedMsg(msgType, customer); |
|
|
|
ctx.getCustomerMsgConstructor().constructCustomerUpdatedMsg(msgType, customer); |
|
|
|
downlinkMsg = DownlinkMsg.newBuilder() |
|
|
|
.addAllCustomerUpdateMsg(Collections.singletonList(customerUpdateMsg)) |
|
|
|
.build(); |
|
|
|
@ -620,7 +622,7 @@ public final class EdgeGrpcSession implements Closeable { |
|
|
|
break; |
|
|
|
case DELETED: |
|
|
|
CustomerUpdateMsg customerUpdateMsg = |
|
|
|
ctx.getCustomerUpdateMsgConstructor().constructCustomerDeleteMsg(customerId); |
|
|
|
ctx.getCustomerMsgConstructor().constructCustomerDeleteMsg(customerId); |
|
|
|
downlinkMsg = DownlinkMsg.newBuilder() |
|
|
|
.addAllCustomerUpdateMsg(Collections.singletonList(customerUpdateMsg)) |
|
|
|
.build(); |
|
|
|
@ -639,7 +641,7 @@ public final class EdgeGrpcSession implements Closeable { |
|
|
|
RuleChain ruleChain = ctx.getRuleChainService().findRuleChainById(edgeEvent.getTenantId(), ruleChainId); |
|
|
|
if (ruleChain != null) { |
|
|
|
RuleChainUpdateMsg ruleChainUpdateMsg = |
|
|
|
ctx.getRuleChainUpdateMsgConstructor().constructRuleChainUpdatedMsg(edge.getRootRuleChainId(), msgType, ruleChain); |
|
|
|
ctx.getRuleChainMsgConstructor().constructRuleChainUpdatedMsg(edge.getRootRuleChainId(), msgType, ruleChain); |
|
|
|
downlinkMsg = DownlinkMsg.newBuilder() |
|
|
|
.addAllRuleChainUpdateMsg(Collections.singletonList(ruleChainUpdateMsg)) |
|
|
|
.build(); |
|
|
|
@ -648,7 +650,7 @@ public final class EdgeGrpcSession implements Closeable { |
|
|
|
case DELETED: |
|
|
|
case UNASSIGNED_FROM_EDGE: |
|
|
|
downlinkMsg = DownlinkMsg.newBuilder() |
|
|
|
.addAllRuleChainUpdateMsg(Collections.singletonList(ctx.getRuleChainUpdateMsgConstructor().constructRuleChainDeleteMsg(ruleChainId))) |
|
|
|
.addAllRuleChainUpdateMsg(Collections.singletonList(ctx.getRuleChainMsgConstructor().constructRuleChainDeleteMsg(ruleChainId))) |
|
|
|
.build(); |
|
|
|
break; |
|
|
|
} |
|
|
|
@ -662,7 +664,7 @@ public final class EdgeGrpcSession implements Closeable { |
|
|
|
if (ruleChain != null) { |
|
|
|
RuleChainMetaData ruleChainMetaData = ctx.getRuleChainService().loadRuleChainMetaData(edgeEvent.getTenantId(), ruleChainId); |
|
|
|
RuleChainMetadataUpdateMsg ruleChainMetadataUpdateMsg = |
|
|
|
ctx.getRuleChainUpdateMsgConstructor().constructRuleChainMetadataUpdatedMsg(msgType, ruleChainMetaData); |
|
|
|
ctx.getRuleChainMsgConstructor().constructRuleChainMetadataUpdatedMsg(msgType, ruleChainMetaData); |
|
|
|
if (ruleChainMetadataUpdateMsg != null) { |
|
|
|
downlinkMsg = DownlinkMsg.newBuilder() |
|
|
|
.addAllRuleChainMetadataUpdateMsg(Collections.singletonList(ruleChainMetadataUpdateMsg)) |
|
|
|
@ -682,20 +684,20 @@ public final class EdgeGrpcSession implements Closeable { |
|
|
|
if (user != null) { |
|
|
|
CustomerId customerId = getCustomerIdIfEdgeAssignedToCustomer(user); |
|
|
|
downlinkMsg = DownlinkMsg.newBuilder() |
|
|
|
.addAllUserUpdateMsg(Collections.singletonList(ctx.getUserUpdateMsgConstructor().constructUserUpdatedMsg(msgType, user, customerId))) |
|
|
|
.addAllUserUpdateMsg(Collections.singletonList(ctx.getUserMsgConstructor().constructUserUpdatedMsg(msgType, user, customerId))) |
|
|
|
.build(); |
|
|
|
} |
|
|
|
break; |
|
|
|
case DELETED: |
|
|
|
downlinkMsg = DownlinkMsg.newBuilder() |
|
|
|
.addAllUserUpdateMsg(Collections.singletonList(ctx.getUserUpdateMsgConstructor().constructUserDeleteMsg(userId))) |
|
|
|
.addAllUserUpdateMsg(Collections.singletonList(ctx.getUserMsgConstructor().constructUserDeleteMsg(userId))) |
|
|
|
.build(); |
|
|
|
break; |
|
|
|
case CREDENTIALS_UPDATED: |
|
|
|
UserCredentials userCredentialsByUserId = ctx.getUserService().findUserCredentialsByUserId(edge.getTenantId(), userId); |
|
|
|
if (userCredentialsByUserId != null && userCredentialsByUserId.isEnabled()) { |
|
|
|
UserCredentialsUpdateMsg userCredentialsUpdateMsg = |
|
|
|
ctx.getUserUpdateMsgConstructor().constructUserCredentialsUpdatedMsg(userCredentialsByUserId); |
|
|
|
ctx.getUserMsgConstructor().constructUserCredentialsUpdatedMsg(userCredentialsByUserId); |
|
|
|
downlinkMsg = DownlinkMsg.newBuilder() |
|
|
|
.addAllUserCredentialsUpdateMsg(Collections.singletonList(userCredentialsUpdateMsg)) |
|
|
|
.build(); |
|
|
|
@ -714,7 +716,7 @@ public final class EdgeGrpcSession implements Closeable { |
|
|
|
|
|
|
|
private DownlinkMsg processRelation(EdgeEvent edgeEvent, UpdateMsgType msgType) { |
|
|
|
EntityRelation entityRelation = mapper.convertValue(edgeEvent.getEntityBody(), EntityRelation.class); |
|
|
|
RelationUpdateMsg r = ctx.getRelationUpdateMsgConstructor().constructRelationUpdatedMsg(msgType, entityRelation); |
|
|
|
RelationUpdateMsg r = ctx.getRelationMsgConstructor().constructRelationUpdatedMsg(msgType, entityRelation); |
|
|
|
return DownlinkMsg.newBuilder() |
|
|
|
.addAllRelationUpdateMsg(Collections.singletonList(r)) |
|
|
|
.build(); |
|
|
|
@ -727,7 +729,7 @@ public final class EdgeGrpcSession implements Closeable { |
|
|
|
Alarm alarm = ctx.getAlarmService().findAlarmByIdAsync(edgeEvent.getTenantId(), alarmId).get(); |
|
|
|
if (alarm != null) { |
|
|
|
downlinkMsg = DownlinkMsg.newBuilder() |
|
|
|
.addAllAlarmUpdateMsg(Collections.singletonList(ctx.getAlarmUpdateMsgConstructor().constructAlarmUpdatedMsg(edge.getTenantId(), msgType, alarm))) |
|
|
|
.addAllAlarmUpdateMsg(Collections.singletonList(ctx.getAlarmMsgConstructor().constructAlarmUpdatedMsg(edge.getTenantId(), msgType, alarm))) |
|
|
|
.build(); |
|
|
|
} |
|
|
|
} catch (Exception e) { |
|
|
|
@ -745,7 +747,7 @@ public final class EdgeGrpcSession implements Closeable { |
|
|
|
WidgetsBundle widgetsBundle = ctx.getWidgetsBundleService().findWidgetsBundleById(edgeEvent.getTenantId(), widgetsBundleId); |
|
|
|
if (widgetsBundle != null) { |
|
|
|
WidgetsBundleUpdateMsg widgetsBundleUpdateMsg = |
|
|
|
ctx.getWidgetsBundleUpdateMsgConstructor().constructWidgetsBundleUpdateMsg(msgType, widgetsBundle); |
|
|
|
ctx.getWidgetsBundleMsgConstructor().constructWidgetsBundleUpdateMsg(msgType, widgetsBundle); |
|
|
|
downlinkMsg = DownlinkMsg.newBuilder() |
|
|
|
.addAllWidgetsBundleUpdateMsg(Collections.singletonList(widgetsBundleUpdateMsg)) |
|
|
|
.build(); |
|
|
|
@ -753,7 +755,7 @@ public final class EdgeGrpcSession implements Closeable { |
|
|
|
break; |
|
|
|
case DELETED: |
|
|
|
WidgetsBundleUpdateMsg widgetsBundleUpdateMsg = |
|
|
|
ctx.getWidgetsBundleUpdateMsgConstructor().constructWidgetsBundleDeleteMsg(widgetsBundleId); |
|
|
|
ctx.getWidgetsBundleMsgConstructor().constructWidgetsBundleDeleteMsg(widgetsBundleId); |
|
|
|
downlinkMsg = DownlinkMsg.newBuilder() |
|
|
|
.addAllWidgetsBundleUpdateMsg(Collections.singletonList(widgetsBundleUpdateMsg)) |
|
|
|
.build(); |
|
|
|
@ -771,7 +773,7 @@ public final class EdgeGrpcSession implements Closeable { |
|
|
|
WidgetType widgetType = ctx.getWidgetTypeService().findWidgetTypeById(edgeEvent.getTenantId(), widgetTypeId); |
|
|
|
if (widgetType != null) { |
|
|
|
WidgetTypeUpdateMsg widgetTypeUpdateMsg = |
|
|
|
ctx.getWidgetTypeUpdateMsgConstructor().constructWidgetTypeUpdateMsg(msgType, widgetType); |
|
|
|
ctx.getWidgetTypeMsgConstructor().constructWidgetTypeUpdateMsg(msgType, widgetType); |
|
|
|
downlinkMsg = DownlinkMsg.newBuilder() |
|
|
|
.addAllWidgetTypeUpdateMsg(Collections.singletonList(widgetTypeUpdateMsg)) |
|
|
|
.build(); |
|
|
|
@ -779,10 +781,10 @@ public final class EdgeGrpcSession implements Closeable { |
|
|
|
break; |
|
|
|
case DELETED: |
|
|
|
WidgetTypeUpdateMsg widgetTypeUpdateMsg = |
|
|
|
ctx.getWidgetTypeUpdateMsgConstructor().constructWidgetTypeDeleteMsg(widgetTypeId); |
|
|
|
downlinkMsg = DownlinkMsg.newBuilder() |
|
|
|
.addAllWidgetTypeUpdateMsg(Collections.singletonList(widgetTypeUpdateMsg)) |
|
|
|
.build(); |
|
|
|
ctx.getWidgetTypeMsgConstructor().constructWidgetTypeDeleteMsg(widgetTypeId); |
|
|
|
downlinkMsg = DownlinkMsg.newBuilder() |
|
|
|
.addAllWidgetTypeUpdateMsg(Collections.singletonList(widgetTypeUpdateMsg)) |
|
|
|
.build(); |
|
|
|
break; |
|
|
|
} |
|
|
|
return downlinkMsg; |
|
|
|
@ -790,7 +792,7 @@ public final class EdgeGrpcSession implements Closeable { |
|
|
|
|
|
|
|
private DownlinkMsg processAdminSettings(EdgeEvent edgeEvent) { |
|
|
|
AdminSettings adminSettings = mapper.convertValue(edgeEvent.getEntityBody(), AdminSettings.class); |
|
|
|
AdminSettingsUpdateMsg t = ctx.getAdminSettingsUpdateMsgConstructor().constructAdminSettingsUpdateMsg(adminSettings); |
|
|
|
AdminSettingsUpdateMsg t = ctx.getAdminSettingsMsgConstructor().constructAdminSettingsUpdateMsg(adminSettings); |
|
|
|
return DownlinkMsg.newBuilder() |
|
|
|
.addAllAdminSettingsUpdateMsg(Collections.singletonList(t)) |
|
|
|
.build(); |
|
|
|
@ -832,42 +834,28 @@ public final class EdgeGrpcSession implements Closeable { |
|
|
|
try { |
|
|
|
if (uplinkMsg.getEntityDataList() != null && !uplinkMsg.getEntityDataList().isEmpty()) { |
|
|
|
for (EntityDataProto entityData : uplinkMsg.getEntityDataList()) { |
|
|
|
EntityId entityId = constructEntityId(entityData); |
|
|
|
if ((entityData.hasPostAttributesMsg() || entityData.hasPostTelemetryMsg()) && entityId != null) { |
|
|
|
TbMsgMetaData metaData = constructBaseMsgMetadata(entityId); |
|
|
|
metaData.putValue(DataConstants.MSG_SOURCE_KEY, DataConstants.EDGE_MSG_SOURCE); |
|
|
|
if (entityData.hasPostAttributesMsg()) { |
|
|
|
metaData.putValue("scope", entityData.getPostAttributeScope()); |
|
|
|
result.add(processPostAttributes(entityId, entityData.getPostAttributesMsg(), metaData)); |
|
|
|
} |
|
|
|
if (entityData.hasPostTelemetryMsg()) { |
|
|
|
result.add(processPostTelemetry(entityId, entityData.getPostTelemetryMsg(), metaData)); |
|
|
|
} |
|
|
|
} |
|
|
|
if (entityData.hasAttributeDeleteMsg()) { |
|
|
|
result.add(processAttributeDeleteMsg(entityId, entityData.getAttributeDeleteMsg(), entityData.getEntityType())); |
|
|
|
} |
|
|
|
result.addAll(ctx.getTelemetryProcessor().onTelemetryUpdate(edge.getTenantId(), entityData)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (uplinkMsg.getDeviceUpdateMsgList() != null && !uplinkMsg.getDeviceUpdateMsgList().isEmpty()) { |
|
|
|
for (DeviceUpdateMsg deviceUpdateMsg : uplinkMsg.getDeviceUpdateMsgList()) { |
|
|
|
result.add(onDeviceUpdate(deviceUpdateMsg)); |
|
|
|
result.add(ctx.getDeviceProcessor().onDeviceUpdate(edge.getTenantId(), edge, deviceUpdateMsg)); |
|
|
|
} |
|
|
|
} |
|
|
|
if (uplinkMsg.getDeviceCredentialsUpdateMsgList() != null && !uplinkMsg.getDeviceCredentialsUpdateMsgList().isEmpty()) { |
|
|
|
for (DeviceCredentialsUpdateMsg deviceCredentialsUpdateMsg : uplinkMsg.getDeviceCredentialsUpdateMsgList()) { |
|
|
|
result.add(onDeviceCredentialsUpdate(deviceCredentialsUpdateMsg)); |
|
|
|
result.add(ctx.getDeviceProcessor().onDeviceCredentialsUpdate(edge.getTenantId(), deviceCredentialsUpdateMsg)); |
|
|
|
} |
|
|
|
} |
|
|
|
if (uplinkMsg.getAlarmUpdateMsgList() != null && !uplinkMsg.getAlarmUpdateMsgList().isEmpty()) { |
|
|
|
for (AlarmUpdateMsg alarmUpdateMsg : uplinkMsg.getAlarmUpdateMsgList()) { |
|
|
|
result.add(onAlarmUpdate(alarmUpdateMsg)); |
|
|
|
result.add(ctx.getAlarmProcessor().onAlarmUpdate(edge.getTenantId(), alarmUpdateMsg)); |
|
|
|
} |
|
|
|
} |
|
|
|
if (uplinkMsg.getRelationUpdateMsgList() != null && !uplinkMsg.getRelationUpdateMsgList().isEmpty()) { |
|
|
|
for (RelationUpdateMsg relationUpdateMsg: uplinkMsg.getRelationUpdateMsgList()) { |
|
|
|
result.add(onRelationUpdate(relationUpdateMsg)); |
|
|
|
for (RelationUpdateMsg relationUpdateMsg : uplinkMsg.getRelationUpdateMsgList()) { |
|
|
|
result.add(ctx.getRelationProcessor().onRelationUpdate(edge.getTenantId(), relationUpdateMsg)); |
|
|
|
} |
|
|
|
} |
|
|
|
if (uplinkMsg.getRuleChainMetadataRequestMsgList() != null && !uplinkMsg.getRuleChainMetadataRequestMsgList().isEmpty()) { |
|
|
|
@ -901,430 +889,6 @@ public final class EdgeGrpcSession implements Closeable { |
|
|
|
return Futures.allAsList(result); |
|
|
|
} |
|
|
|
|
|
|
|
private TbMsgMetaData constructBaseMsgMetadata(EntityId entityId) { |
|
|
|
TbMsgMetaData metaData = new TbMsgMetaData(); |
|
|
|
switch (entityId.getEntityType()) { |
|
|
|
case DEVICE: |
|
|
|
Device device = ctx.getDeviceService().findDeviceById(edge.getTenantId(), new DeviceId(entityId.getId())); |
|
|
|
if (device != null) { |
|
|
|
metaData.putValue("deviceName", device.getName()); |
|
|
|
metaData.putValue("deviceType", device.getType()); |
|
|
|
} |
|
|
|
break; |
|
|
|
case ASSET: |
|
|
|
Asset asset = ctx.getAssetService().findAssetById(edge.getTenantId(), new AssetId(entityId.getId())); |
|
|
|
if (asset != null) { |
|
|
|
metaData.putValue("assetName", asset.getName()); |
|
|
|
metaData.putValue("assetType", asset.getType()); |
|
|
|
} |
|
|
|
break; |
|
|
|
case ENTITY_VIEW: |
|
|
|
EntityView entityView = ctx.getEntityViewService().findEntityViewById(edge.getTenantId(), new EntityViewId(entityId.getId())); |
|
|
|
if (entityView != null) { |
|
|
|
metaData.putValue("entityViewName", entityView.getName()); |
|
|
|
metaData.putValue("entityViewType", entityView.getType()); |
|
|
|
} |
|
|
|
break; |
|
|
|
default: |
|
|
|
log.debug("Using empty metadata for entityId [{}]", entityId); |
|
|
|
break; |
|
|
|
} |
|
|
|
return metaData; |
|
|
|
} |
|
|
|
|
|
|
|
private EntityId constructEntityId(EntityDataProto entityData) { |
|
|
|
EntityType entityType = EntityType.valueOf(entityData.getEntityType()); |
|
|
|
switch (entityType) { |
|
|
|
case DEVICE: |
|
|
|
return new DeviceId(new UUID(entityData.getEntityIdMSB(), entityData.getEntityIdLSB())); |
|
|
|
case ASSET: |
|
|
|
return new AssetId(new UUID(entityData.getEntityIdMSB(), entityData.getEntityIdLSB())); |
|
|
|
case ENTITY_VIEW: |
|
|
|
return new EntityViewId(new UUID(entityData.getEntityIdMSB(), entityData.getEntityIdLSB())); |
|
|
|
case DASHBOARD: |
|
|
|
return new DashboardId(new UUID(entityData.getEntityIdMSB(), entityData.getEntityIdLSB())); |
|
|
|
case TENANT: |
|
|
|
return new TenantId(new UUID(entityData.getEntityIdMSB(), entityData.getEntityIdLSB())); |
|
|
|
case CUSTOMER: |
|
|
|
return new CustomerId(new UUID(entityData.getEntityIdMSB(), entityData.getEntityIdLSB())); |
|
|
|
case USER: |
|
|
|
return new UserId(new UUID(entityData.getEntityIdMSB(), entityData.getEntityIdLSB())); |
|
|
|
default: |
|
|
|
log.warn("Unsupported entity type [{}] during construct of entity id. EntityDataProto [{}]", entityData.getEntityType(), entityData); |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private ListenableFuture<Void> processPostTelemetry(EntityId entityId, TransportProtos.PostTelemetryMsg msg, TbMsgMetaData metaData) { |
|
|
|
SettableFuture<Void> futureToSet = SettableFuture.create(); |
|
|
|
for (TransportProtos.TsKvListProto tsKv : msg.getTsKvListList()) { |
|
|
|
JsonObject json = JsonUtils.getJsonObject(tsKv.getKvList()); |
|
|
|
metaData.putValue("ts", tsKv.getTs() + ""); |
|
|
|
TbMsg tbMsg = TbMsg.newMsg(SessionMsgType.POST_TELEMETRY_REQUEST.name(), entityId, metaData, gson.toJson(json)); |
|
|
|
ctx.getTbClusterService().pushMsgToRuleEngine(edge.getTenantId(), tbMsg.getOriginator(), tbMsg, new TbQueueCallback() { |
|
|
|
@Override |
|
|
|
public void onSuccess(TbQueueMsgMetadata metadata) { |
|
|
|
futureToSet.set(null); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public void onFailure(Throwable t) { |
|
|
|
log.error("Can't process post telemetry [{}]", msg, t); |
|
|
|
futureToSet.setException(t); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
return futureToSet; |
|
|
|
} |
|
|
|
|
|
|
|
private ListenableFuture<Void> processPostAttributes(EntityId entityId, TransportProtos.PostAttributeMsg msg, TbMsgMetaData metaData) { |
|
|
|
SettableFuture<Void> futureToSet = SettableFuture.create(); |
|
|
|
JsonObject json = JsonUtils.getJsonObject(msg.getKvList()); |
|
|
|
TbMsg tbMsg = TbMsg.newMsg(SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), entityId, metaData, gson.toJson(json)); |
|
|
|
ctx.getTbClusterService().pushMsgToRuleEngine(edge.getTenantId(), tbMsg.getOriginator(), tbMsg, new TbQueueCallback() { |
|
|
|
@Override |
|
|
|
public void onSuccess(TbQueueMsgMetadata metadata) { |
|
|
|
futureToSet.set(null); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public void onFailure(Throwable t) { |
|
|
|
log.error("Can't process post attributes [{}]", msg, t); |
|
|
|
futureToSet.setException(t); |
|
|
|
} |
|
|
|
}); |
|
|
|
return futureToSet; |
|
|
|
} |
|
|
|
|
|
|
|
private ListenableFuture<Void> processAttributeDeleteMsg(EntityId entityId, AttributeDeleteMsg attributeDeleteMsg, String entityType) { |
|
|
|
SettableFuture<Void> futureToSet = SettableFuture.create(); |
|
|
|
String scope = attributeDeleteMsg.getScope(); |
|
|
|
List<String> attributeNames = attributeDeleteMsg.getAttributeNamesList(); |
|
|
|
ctx.getAttributesService().removeAll(edge.getTenantId(), entityId, scope, attributeNames); |
|
|
|
if (EntityType.DEVICE.name().equals(entityType)) { |
|
|
|
Set<AttributeKey> attributeKeys = new HashSet<>(); |
|
|
|
for (String attributeName : attributeNames) { |
|
|
|
attributeKeys.add(new AttributeKey(scope, attributeName)); |
|
|
|
} |
|
|
|
ctx.getTbClusterService().pushMsgToCore(DeviceAttributesEventNotificationMsg.onDelete( |
|
|
|
edge.getTenantId(), (DeviceId) entityId, attributeKeys), new TbQueueCallback() { |
|
|
|
@Override |
|
|
|
public void onSuccess(TbQueueMsgMetadata metadata) { |
|
|
|
futureToSet.set(null); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public void onFailure(Throwable t) { |
|
|
|
log.error("Can't process attribute delete msg [{}]", attributeDeleteMsg, t); |
|
|
|
futureToSet.setException(t); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
return futureToSet; |
|
|
|
} |
|
|
|
|
|
|
|
private ListenableFuture<Void> onDeviceUpdate(DeviceUpdateMsg deviceUpdateMsg) { |
|
|
|
DeviceId edgeDeviceId = new DeviceId(new UUID(deviceUpdateMsg.getIdMSB(), deviceUpdateMsg.getIdLSB())); |
|
|
|
switch (deviceUpdateMsg.getMsgType()) { |
|
|
|
case ENTITY_CREATED_RPC_MESSAGE: |
|
|
|
String deviceName = deviceUpdateMsg.getName(); |
|
|
|
Device device = ctx.getDeviceService().findDeviceByTenantIdAndName(edge.getTenantId(), deviceName); |
|
|
|
if (device != null) { |
|
|
|
// device with this name already exists on the cloud - update ID on the edge
|
|
|
|
if (!device.getId().equals(edgeDeviceId)) { |
|
|
|
CustomerId customerId = getCustomerIdIfEdgeAssignedToCustomer(device); |
|
|
|
DeviceUpdateMsg d = ctx.getDeviceUpdateMsgConstructor().constructDeviceUpdatedMsg(UpdateMsgType.DEVICE_CONFLICT_RPC_MESSAGE, device, customerId); |
|
|
|
DownlinkMsg downlinkMsg = DownlinkMsg.newBuilder() |
|
|
|
.addAllDeviceUpdateMsg(Collections.singletonList(d)) |
|
|
|
.build(); |
|
|
|
sendResponseMsg(ResponseMsg.newBuilder() |
|
|
|
.setDownlinkMsg(downlinkMsg) |
|
|
|
.build()); |
|
|
|
} |
|
|
|
} else { |
|
|
|
Device deviceById = ctx.getDeviceService().findDeviceById(edge.getTenantId(), edgeDeviceId); |
|
|
|
if (deviceById != null) { |
|
|
|
// this ID already used by other device - create new device and update ID on the edge
|
|
|
|
device = createDevice(deviceUpdateMsg); |
|
|
|
CustomerId customerId = getCustomerIdIfEdgeAssignedToCustomer(device); |
|
|
|
DeviceUpdateMsg d = ctx.getDeviceUpdateMsgConstructor().constructDeviceUpdatedMsg(UpdateMsgType.DEVICE_CONFLICT_RPC_MESSAGE, device, customerId); |
|
|
|
DownlinkMsg downlinkMsg = DownlinkMsg.newBuilder() |
|
|
|
.addAllDeviceUpdateMsg(Collections.singletonList(d)) |
|
|
|
.build(); |
|
|
|
sendResponseMsg(ResponseMsg.newBuilder() |
|
|
|
.setDownlinkMsg(downlinkMsg) |
|
|
|
.build()); |
|
|
|
} else { |
|
|
|
device = createDevice(deviceUpdateMsg); |
|
|
|
} |
|
|
|
} |
|
|
|
// TODO: voba - assign device only in case device is not assigned yet. Missing functionality to check this relation prior assignment
|
|
|
|
ctx.getDeviceService().assignDeviceToEdge(edge.getTenantId(), device.getId(), edge.getId()); |
|
|
|
break; |
|
|
|
case ENTITY_UPDATED_RPC_MESSAGE: |
|
|
|
updateDevice(deviceUpdateMsg); |
|
|
|
break; |
|
|
|
case ENTITY_DELETED_RPC_MESSAGE: |
|
|
|
Device deviceToDelete = ctx.getDeviceService().findDeviceById(edge.getTenantId(), edgeDeviceId); |
|
|
|
if (deviceToDelete != null) { |
|
|
|
ctx.getDeviceService().unassignDeviceFromEdge(edge.getTenantId(), edgeDeviceId, edge.getId()); |
|
|
|
} |
|
|
|
break; |
|
|
|
case UNRECOGNIZED: |
|
|
|
log.error("Unsupported msg type {}", deviceUpdateMsg.getMsgType()); |
|
|
|
return Futures.immediateFailedFuture(new RuntimeException("Unsupported msg type " + deviceUpdateMsg.getMsgType())); |
|
|
|
} |
|
|
|
return Futures.immediateFuture(null); |
|
|
|
} |
|
|
|
|
|
|
|
private void updateDevice(DeviceUpdateMsg deviceUpdateMsg) { |
|
|
|
DeviceId deviceId = new DeviceId(new UUID(deviceUpdateMsg.getIdMSB(), deviceUpdateMsg.getIdLSB())); |
|
|
|
Device device = ctx.getDeviceService().findDeviceById(edge.getTenantId(), deviceId); |
|
|
|
device.setName(deviceUpdateMsg.getName()); |
|
|
|
device.setType(deviceUpdateMsg.getType()); |
|
|
|
device.setLabel(deviceUpdateMsg.getLabel()); |
|
|
|
device = ctx.getDeviceService().saveDevice(device); |
|
|
|
|
|
|
|
requestDeviceCredentialsFromEdge(device); |
|
|
|
} |
|
|
|
|
|
|
|
private ListenableFuture<Void> onDeviceCredentialsUpdate(DeviceCredentialsUpdateMsg deviceCredentialsUpdateMsg) { |
|
|
|
log.debug("Executing onDeviceCredentialsUpdate, deviceCredentialsUpdateMsg [{}]", deviceCredentialsUpdateMsg); |
|
|
|
DeviceId deviceId = new DeviceId(new UUID(deviceCredentialsUpdateMsg.getDeviceIdMSB(), deviceCredentialsUpdateMsg.getDeviceIdLSB())); |
|
|
|
ListenableFuture<Device> deviceFuture = ctx.getDeviceService().findDeviceByIdAsync(edge.getTenantId(), deviceId); |
|
|
|
return Futures.transform(deviceFuture, device -> { |
|
|
|
if (device != null) { |
|
|
|
log.debug("Updating device credentials for device [{}]. New device credentials Id [{}], value [{}]", |
|
|
|
device.getName(), deviceCredentialsUpdateMsg.getCredentialsId(), deviceCredentialsUpdateMsg.getCredentialsValue()); |
|
|
|
try { |
|
|
|
DeviceCredentials deviceCredentials = ctx.getDeviceCredentialsService().findDeviceCredentialsByDeviceId(edge.getTenantId(), device.getId()); |
|
|
|
deviceCredentials.setCredentialsType(DeviceCredentialsType.valueOf(deviceCredentialsUpdateMsg.getCredentialsType())); |
|
|
|
deviceCredentials.setCredentialsId(deviceCredentialsUpdateMsg.getCredentialsId()); |
|
|
|
deviceCredentials.setCredentialsValue(deviceCredentialsUpdateMsg.getCredentialsValue()); |
|
|
|
ctx.getDeviceCredentialsService().updateDeviceCredentials(edge.getTenantId(), deviceCredentials); |
|
|
|
} catch (Exception e) { |
|
|
|
log.error("Can't update device credentials for device [{}], deviceCredentialsUpdateMsg [{}]", device.getName(), deviceCredentialsUpdateMsg, e); |
|
|
|
throw new RuntimeException(e); |
|
|
|
} |
|
|
|
} |
|
|
|
return null; |
|
|
|
}, ctx.getDbCallbackExecutor()); |
|
|
|
} |
|
|
|
|
|
|
|
private void requestDeviceCredentialsFromEdge(Device device) { |
|
|
|
log.debug("Executing requestDeviceCredentialsFromEdge device [{}]", device); |
|
|
|
|
|
|
|
DownlinkMsg downlinkMsg = constructDeviceCredentialsRequestMsg(device.getId()); |
|
|
|
sendResponseMsg(ResponseMsg.newBuilder() |
|
|
|
.setDownlinkMsg(downlinkMsg) |
|
|
|
.build()); |
|
|
|
} |
|
|
|
|
|
|
|
private DownlinkMsg constructDeviceCredentialsRequestMsg(DeviceId deviceId) { |
|
|
|
DeviceCredentialsRequestMsg deviceCredentialsRequestMsg = DeviceCredentialsRequestMsg.newBuilder() |
|
|
|
.setDeviceIdMSB(deviceId.getId().getMostSignificantBits()) |
|
|
|
.setDeviceIdLSB(deviceId.getId().getLeastSignificantBits()) |
|
|
|
.build(); |
|
|
|
DownlinkMsg.Builder builder = DownlinkMsg.newBuilder() |
|
|
|
.addAllDeviceCredentialsRequestMsg(Collections.singletonList(deviceCredentialsRequestMsg)); |
|
|
|
return builder.build(); |
|
|
|
} |
|
|
|
|
|
|
|
private Device createDevice(DeviceUpdateMsg deviceUpdateMsg) { |
|
|
|
Device device; |
|
|
|
try { |
|
|
|
deviceCreationLock.lock(); |
|
|
|
DeviceId deviceId = new DeviceId(new UUID(deviceUpdateMsg.getIdMSB(), deviceUpdateMsg.getIdLSB())); |
|
|
|
device = new Device(); |
|
|
|
device.setTenantId(edge.getTenantId()); |
|
|
|
device.setCustomerId(edge.getCustomerId()); |
|
|
|
device.setId(deviceId); |
|
|
|
device.setName(deviceUpdateMsg.getName()); |
|
|
|
device.setType(deviceUpdateMsg.getType()); |
|
|
|
device.setLabel(deviceUpdateMsg.getLabel()); |
|
|
|
device = ctx.getDeviceService().saveDevice(device); |
|
|
|
createDeviceCredentials(device); |
|
|
|
createRelationFromEdge(device.getId()); |
|
|
|
ctx.getDeviceStateService().onDeviceAdded(device); |
|
|
|
pushDeviceCreatedEventToRuleEngine(device); |
|
|
|
requestDeviceCredentialsFromEdge(device); |
|
|
|
} finally { |
|
|
|
deviceCreationLock.unlock(); |
|
|
|
} |
|
|
|
return device; |
|
|
|
} |
|
|
|
|
|
|
|
private void createDeviceCredentials(Device device) { |
|
|
|
DeviceCredentials deviceCredentials = new DeviceCredentials(); |
|
|
|
deviceCredentials.setDeviceId(device.getId()); |
|
|
|
deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN); |
|
|
|
deviceCredentials.setCredentialsId(RandomStringUtils.randomAlphanumeric(20)); |
|
|
|
ctx.getDeviceCredentialsService().createDeviceCredentials(device.getTenantId(), deviceCredentials); |
|
|
|
} |
|
|
|
|
|
|
|
private void pushDeviceCreatedEventToRuleEngine(Device device) { |
|
|
|
try { |
|
|
|
ObjectNode entityNode = mapper.valueToTree(device); |
|
|
|
TbMsg tbMsg = TbMsg.newMsg(DataConstants.ENTITY_CREATED, device.getId(), getActionTbMsgMetaData(device.getCustomerId()), mapper.writeValueAsString(entityNode)); |
|
|
|
sendToRuleEngine(edge.getTenantId(), tbMsg, new TbQueueCallback() { |
|
|
|
@Override |
|
|
|
public void onSuccess(TbQueueMsgMetadata metadata) { |
|
|
|
// TODO: voba - handle success
|
|
|
|
log.debug("Successfully send ENTITY_CREATED EVENT to rule engine [{}]", device); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public void onFailure(Throwable t) { |
|
|
|
// TODO: voba - handle failure
|
|
|
|
log.debug("Failed to send ENTITY_CREATED EVENT to rule engine [{}]", device, t); |
|
|
|
} |
|
|
|
}); |
|
|
|
} catch (JsonProcessingException | IllegalArgumentException e) { |
|
|
|
log.warn("[{}] Failed to push device action to rule engine: {}", device.getId(), DataConstants.ENTITY_CREATED, e); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
protected void sendToRuleEngine(TenantId tenantId, TbMsg tbMsg, TbQueueCallback callback) { |
|
|
|
TopicPartitionInfo tpi = ctx.getPartitionService().resolve(ServiceType.TB_RULE_ENGINE, tenantId, tbMsg.getOriginator()); |
|
|
|
TransportProtos.ToRuleEngineMsg msg = TransportProtos.ToRuleEngineMsg.newBuilder().setTbMsg(TbMsg.toByteString(tbMsg)) |
|
|
|
.setTenantIdMSB(tenantId.getId().getMostSignificantBits()) |
|
|
|
.setTenantIdLSB(tenantId.getId().getLeastSignificantBits()).build(); |
|
|
|
ruleEngineMsgProducer.send(tpi, new TbProtoQueueMsg<>(tbMsg.getId(), msg), callback); |
|
|
|
} |
|
|
|
|
|
|
|
private TbMsgMetaData getActionTbMsgMetaData(CustomerId customerId) { |
|
|
|
TbMsgMetaData metaData = getTbMsgMetaData(edge); |
|
|
|
if (customerId != null && !customerId.isNullUid()) { |
|
|
|
metaData.putValue("customerId", customerId.toString()); |
|
|
|
} |
|
|
|
return metaData; |
|
|
|
} |
|
|
|
|
|
|
|
private TbMsgMetaData getTbMsgMetaData(Edge edge) { |
|
|
|
TbMsgMetaData metaData = new TbMsgMetaData(); |
|
|
|
metaData.putValue("edgeId", edge.getId().toString()); |
|
|
|
metaData.putValue("edgeName", edge.getName()); |
|
|
|
return metaData; |
|
|
|
} |
|
|
|
|
|
|
|
private EntityId getAlarmOriginator(String entityName, org.thingsboard.server.common.data.EntityType entityType) { |
|
|
|
switch (entityType) { |
|
|
|
case DEVICE: |
|
|
|
return ctx.getDeviceService().findDeviceByTenantIdAndName(edge.getTenantId(), entityName).getId(); |
|
|
|
case ASSET: |
|
|
|
return ctx.getAssetService().findAssetByTenantIdAndName(edge.getTenantId(), entityName).getId(); |
|
|
|
case ENTITY_VIEW: |
|
|
|
return ctx.getEntityViewService().findEntityViewByTenantIdAndName(edge.getTenantId(), entityName).getId(); |
|
|
|
default: |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private ListenableFuture<Void> onAlarmUpdate(AlarmUpdateMsg alarmUpdateMsg) { |
|
|
|
EntityId originatorId = getAlarmOriginator(alarmUpdateMsg.getOriginatorName(), org.thingsboard.server.common.data.EntityType.valueOf(alarmUpdateMsg.getOriginatorType())); |
|
|
|
if (originatorId == null) { |
|
|
|
return Futures.immediateFuture(null); |
|
|
|
} |
|
|
|
try { |
|
|
|
Alarm existentAlarm = ctx.getAlarmService().findLatestByOriginatorAndType(edge.getTenantId(), originatorId, alarmUpdateMsg.getType()).get(); |
|
|
|
switch (alarmUpdateMsg.getMsgType()) { |
|
|
|
case ENTITY_CREATED_RPC_MESSAGE: |
|
|
|
case ENTITY_UPDATED_RPC_MESSAGE: |
|
|
|
if (existentAlarm == null || existentAlarm.getStatus().isCleared()) { |
|
|
|
existentAlarm = new Alarm(); |
|
|
|
existentAlarm.setTenantId(edge.getTenantId()); |
|
|
|
existentAlarm.setType(alarmUpdateMsg.getName()); |
|
|
|
existentAlarm.setOriginator(originatorId); |
|
|
|
existentAlarm.setSeverity(AlarmSeverity.valueOf(alarmUpdateMsg.getSeverity())); |
|
|
|
existentAlarm.setStartTs(alarmUpdateMsg.getStartTs()); |
|
|
|
existentAlarm.setClearTs(alarmUpdateMsg.getClearTs()); |
|
|
|
existentAlarm.setPropagate(alarmUpdateMsg.getPropagate()); |
|
|
|
} |
|
|
|
existentAlarm.setStatus(AlarmStatus.valueOf(alarmUpdateMsg.getStatus())); |
|
|
|
existentAlarm.setAckTs(alarmUpdateMsg.getAckTs()); |
|
|
|
existentAlarm.setEndTs(alarmUpdateMsg.getEndTs()); |
|
|
|
existentAlarm.setDetails(mapper.readTree(alarmUpdateMsg.getDetails())); |
|
|
|
ctx.getAlarmService().createOrUpdateAlarm(existentAlarm); |
|
|
|
break; |
|
|
|
case ALARM_ACK_RPC_MESSAGE: |
|
|
|
if (existentAlarm != null) { |
|
|
|
ctx.getAlarmService().ackAlarm(edge.getTenantId(), existentAlarm.getId(), alarmUpdateMsg.getAckTs()); |
|
|
|
} |
|
|
|
break; |
|
|
|
case ALARM_CLEAR_RPC_MESSAGE: |
|
|
|
if (existentAlarm != null) { |
|
|
|
ctx.getAlarmService().clearAlarm(edge.getTenantId(), existentAlarm.getId(), mapper.readTree(alarmUpdateMsg.getDetails()), alarmUpdateMsg.getAckTs()); |
|
|
|
} |
|
|
|
break; |
|
|
|
case ENTITY_DELETED_RPC_MESSAGE: |
|
|
|
if (existentAlarm != null) { |
|
|
|
ctx.getAlarmService().deleteAlarm(edge.getTenantId(), existentAlarm.getId()); |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
return Futures.immediateFuture(null); |
|
|
|
} catch (Exception e) { |
|
|
|
log.error("Failed to process alarm update msg [{}]", alarmUpdateMsg, e); |
|
|
|
return Futures.immediateFailedFuture(new RuntimeException("Failed to process alarm update msg", e)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private ListenableFuture<Void> onRelationUpdate(RelationUpdateMsg relationUpdateMsg) { |
|
|
|
log.info("onRelationUpdate {}", relationUpdateMsg); |
|
|
|
try { |
|
|
|
EntityRelation entityRelation = new EntityRelation(); |
|
|
|
|
|
|
|
UUID fromUUID = new UUID(relationUpdateMsg.getFromIdMSB(), relationUpdateMsg.getFromIdLSB()); |
|
|
|
EntityId fromId = EntityIdFactory.getByTypeAndUuid(EntityType.valueOf(relationUpdateMsg.getFromEntityType()), fromUUID); |
|
|
|
entityRelation.setFrom(fromId); |
|
|
|
|
|
|
|
UUID toUUID = new UUID(relationUpdateMsg.getToIdMSB(), relationUpdateMsg.getToIdLSB()); |
|
|
|
EntityId toId = EntityIdFactory.getByTypeAndUuid(EntityType.valueOf(relationUpdateMsg.getToEntityType()), toUUID); |
|
|
|
entityRelation.setTo(toId); |
|
|
|
|
|
|
|
entityRelation.setType(relationUpdateMsg.getType()); |
|
|
|
entityRelation.setTypeGroup(RelationTypeGroup.valueOf(relationUpdateMsg.getTypeGroup())); |
|
|
|
entityRelation.setAdditionalInfo(mapper.readTree(relationUpdateMsg.getAdditionalInfo())); |
|
|
|
switch (relationUpdateMsg.getMsgType()) { |
|
|
|
case ENTITY_CREATED_RPC_MESSAGE: |
|
|
|
case ENTITY_UPDATED_RPC_MESSAGE: |
|
|
|
if (isEntityExists(edge.getTenantId(), entityRelation.getTo()) |
|
|
|
&& isEntityExists(edge.getTenantId(), entityRelation.getFrom())) { |
|
|
|
ctx.getRelationService().saveRelationAsync(edge.getTenantId(), entityRelation); |
|
|
|
} |
|
|
|
break; |
|
|
|
case ENTITY_DELETED_RPC_MESSAGE: |
|
|
|
ctx.getRelationService().deleteRelation(edge.getTenantId(), entityRelation); |
|
|
|
break; |
|
|
|
case UNRECOGNIZED: |
|
|
|
log.error("Unsupported msg type"); |
|
|
|
} |
|
|
|
return Futures.immediateFuture(null); |
|
|
|
} catch (Exception e) { |
|
|
|
log.error("Failed to process relation update msg [{}]", relationUpdateMsg, e); |
|
|
|
return Futures.immediateFailedFuture(new RuntimeException("Failed to process relation update msg", e)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private boolean isEntityExists(TenantId tenantId, EntityId entityId) throws ThingsboardException { |
|
|
|
switch (entityId.getEntityType()) { |
|
|
|
case DEVICE: |
|
|
|
return ctx.getDeviceService().findDeviceById(tenantId, new DeviceId(entityId.getId())) != null; |
|
|
|
case ASSET: |
|
|
|
return ctx.getAssetService().findAssetById(tenantId, new AssetId(entityId.getId())) != null; |
|
|
|
case ENTITY_VIEW: |
|
|
|
return ctx.getEntityViewService().findEntityViewById(tenantId, new EntityViewId(entityId.getId())) != null; |
|
|
|
case CUSTOMER: |
|
|
|
return ctx.getCustomerService().findCustomerById(tenantId, new CustomerId(entityId.getId())) != null; |
|
|
|
case USER: |
|
|
|
return ctx.getUserService().findUserById(tenantId, new UserId(entityId.getId())) != null; |
|
|
|
case DASHBOARD: |
|
|
|
return ctx.getDashboardService().findDashboardById(tenantId, new DashboardId(entityId.getId())) != null; |
|
|
|
default: |
|
|
|
throw new ThingsboardException("Unsupported entity type " + entityId.getEntityType(), ThingsboardErrorCode.INVALID_ARGUMENTS); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private ConnectResponseMsg processConnect(ConnectRequestMsg request) { |
|
|
|
Optional<Edge> optional = ctx.getEdgeService().findEdgeByRoutingKey(TenantId.SYS_TENANT_ID, request.getEdgeRoutingKey()); |
|
|
|
if (optional.isPresent()) { |
|
|
|
@ -1355,15 +919,6 @@ public final class EdgeGrpcSession implements Closeable { |
|
|
|
.setConfiguration(EdgeConfiguration.getDefaultInstance()).build(); |
|
|
|
} |
|
|
|
|
|
|
|
private void createRelationFromEdge(EntityId entityId) { |
|
|
|
EntityRelation relation = new EntityRelation(); |
|
|
|
relation.setFrom(edge.getId()); |
|
|
|
relation.setTo(entityId); |
|
|
|
relation.setTypeGroup(RelationTypeGroup.COMMON); |
|
|
|
relation.setType(EntityRelation.EDGE_TYPE); |
|
|
|
ctx.getRelationService().saveRelation(edge.getTenantId(), relation); |
|
|
|
} |
|
|
|
|
|
|
|
private EdgeConfiguration constructEdgeConfigProto(Edge edge) throws JsonProcessingException { |
|
|
|
return EdgeConfiguration.newBuilder() |
|
|
|
.setEdgeIdMSB(edge.getId().getId().getMostSignificantBits()) |
|
|
|
|