Added support for RPC call for edge devices
This commit is contained in:
parent
c526d13e45
commit
85fcfef8a5
@ -255,12 +255,15 @@ public class ActorSystemContext {
|
|||||||
@Getter
|
@Getter
|
||||||
private TbCoreDeviceRpcService tbCoreDeviceRpcService;
|
private TbCoreDeviceRpcService tbCoreDeviceRpcService;
|
||||||
|
|
||||||
|
@Lazy
|
||||||
@Autowired(required = false)
|
@Autowired(required = false)
|
||||||
@Getter private EdgeService edgeService;
|
@Getter private EdgeService edgeService;
|
||||||
|
|
||||||
|
@Lazy
|
||||||
@Autowired(required = false)
|
@Autowired(required = false)
|
||||||
@Getter private EdgeEventService edgeEventService;
|
@Getter private EdgeEventService edgeEventService;
|
||||||
|
|
||||||
|
@Lazy
|
||||||
@Autowired(required = false)
|
@Autowired(required = false)
|
||||||
@Getter private EdgeRpcService edgeRpcService;
|
@Getter private EdgeRpcService edgeRpcService;
|
||||||
|
|
||||||
|
|||||||
@ -78,6 +78,7 @@ import org.thingsboard.server.gen.edge.CustomerUpdateMsg;
|
|||||||
import org.thingsboard.server.gen.edge.DashboardUpdateMsg;
|
import org.thingsboard.server.gen.edge.DashboardUpdateMsg;
|
||||||
import org.thingsboard.server.gen.edge.DeviceCredentialsRequestMsg;
|
import org.thingsboard.server.gen.edge.DeviceCredentialsRequestMsg;
|
||||||
import org.thingsboard.server.gen.edge.DeviceCredentialsUpdateMsg;
|
import org.thingsboard.server.gen.edge.DeviceCredentialsUpdateMsg;
|
||||||
|
import org.thingsboard.server.gen.edge.DeviceRpcCallMsg;
|
||||||
import org.thingsboard.server.gen.edge.DeviceUpdateMsg;
|
import org.thingsboard.server.gen.edge.DeviceUpdateMsg;
|
||||||
import org.thingsboard.server.gen.edge.DownlinkMsg;
|
import org.thingsboard.server.gen.edge.DownlinkMsg;
|
||||||
import org.thingsboard.server.gen.edge.DownlinkResponseMsg;
|
import org.thingsboard.server.gen.edge.DownlinkResponseMsg;
|
||||||
@ -333,6 +334,9 @@ public final class EdgeGrpcSession implements Closeable {
|
|||||||
case ENTITY_EXISTS_REQUEST:
|
case ENTITY_EXISTS_REQUEST:
|
||||||
downlinkMsg = processEntityExistsRequestMessage(edgeEvent);
|
downlinkMsg = processEntityExistsRequestMessage(edgeEvent);
|
||||||
break;
|
break;
|
||||||
|
case RPC_CALL:
|
||||||
|
downlinkMsg = processRpcCallMsg(edgeEvent);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (downlinkMsg != null) {
|
if (downlinkMsg != null) {
|
||||||
result.add(downlinkMsg);
|
result.add(downlinkMsg);
|
||||||
@ -358,6 +362,15 @@ public final class EdgeGrpcSession implements Closeable {
|
|||||||
return downlinkMsg;
|
return downlinkMsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private DownlinkMsg processRpcCallMsg(EdgeEvent edgeEvent) {
|
||||||
|
log.trace("Executing processRpcCall, edgeEvent [{}]", edgeEvent);
|
||||||
|
DeviceRpcCallMsg deviceRpcCallMsg =
|
||||||
|
ctx.getDeviceMsgConstructor().constructDeviceRpcCallMsg(edgeEvent.getEntityBody());
|
||||||
|
return DownlinkMsg.newBuilder()
|
||||||
|
.addAllDeviceRpcCallMsg(Collections.singletonList(deviceRpcCallMsg))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
private DownlinkMsg processCredentialsRequestMessage(EdgeEvent edgeEvent) {
|
private DownlinkMsg processCredentialsRequestMessage(EdgeEvent edgeEvent) {
|
||||||
DownlinkMsg downlinkMsg = null;
|
DownlinkMsg downlinkMsg = null;
|
||||||
if (EdgeEventType.DEVICE.equals(edgeEvent.getEdgeEventType())) {
|
if (EdgeEventType.DEVICE.equals(edgeEvent.getEdgeEventType())) {
|
||||||
@ -883,6 +896,11 @@ public final class EdgeGrpcSession implements Closeable {
|
|||||||
result.add(ctx.getSyncEdgeService().processDeviceCredentialsRequestMsg(edge, deviceCredentialsRequestMsg));
|
result.add(ctx.getSyncEdgeService().processDeviceCredentialsRequestMsg(edge, deviceCredentialsRequestMsg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (uplinkMsg.getDeviceRpcCallMsgList() != null && !uplinkMsg.getDeviceRpcCallMsgList().isEmpty()) {
|
||||||
|
for (DeviceRpcCallMsg deviceRpcCallMsg: uplinkMsg.getDeviceRpcCallMsgList()) {
|
||||||
|
result.add(ctx.getDeviceProcessor().processDeviceRpcCallResponseMsg(edge.getTenantId(), deviceRpcCallMsg));
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Can't process uplink msg [{}]", uplinkMsg, e);
|
log.error("Can't process uplink msg [{}]", uplinkMsg, e);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,21 +15,27 @@
|
|||||||
*/
|
*/
|
||||||
package org.thingsboard.server.service.edge.rpc.constructor;
|
package org.thingsboard.server.service.edge.rpc.constructor;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.thingsboard.rule.engine.api.RuleEngineDeviceRpcRequest;
|
||||||
import org.thingsboard.server.common.data.Device;
|
import org.thingsboard.server.common.data.Device;
|
||||||
import org.thingsboard.server.common.data.id.CustomerId;
|
import org.thingsboard.server.common.data.id.CustomerId;
|
||||||
import org.thingsboard.server.common.data.id.DeviceId;
|
import org.thingsboard.server.common.data.id.DeviceId;
|
||||||
import org.thingsboard.server.common.data.id.EntityId;
|
|
||||||
import org.thingsboard.server.common.data.security.DeviceCredentials;
|
import org.thingsboard.server.common.data.security.DeviceCredentials;
|
||||||
import org.thingsboard.server.gen.edge.DeviceCredentialsUpdateMsg;
|
import org.thingsboard.server.gen.edge.DeviceCredentialsUpdateMsg;
|
||||||
|
import org.thingsboard.server.gen.edge.DeviceRpcCallMsg;
|
||||||
import org.thingsboard.server.gen.edge.DeviceUpdateMsg;
|
import org.thingsboard.server.gen.edge.DeviceUpdateMsg;
|
||||||
|
import org.thingsboard.server.gen.edge.RpcRequestMsg;
|
||||||
import org.thingsboard.server.gen.edge.UpdateMsgType;
|
import org.thingsboard.server.gen.edge.UpdateMsgType;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class DeviceMsgConstructor {
|
public class DeviceMsgConstructor {
|
||||||
|
|
||||||
|
protected static final ObjectMapper mapper = new ObjectMapper();
|
||||||
|
|
||||||
public DeviceUpdateMsg constructDeviceUpdatedMsg(UpdateMsgType msgType, Device device, CustomerId customerId) {
|
public DeviceUpdateMsg constructDeviceUpdatedMsg(UpdateMsgType msgType, Device device, CustomerId customerId) {
|
||||||
DeviceUpdateMsg.Builder builder = DeviceUpdateMsg.newBuilder()
|
DeviceUpdateMsg.Builder builder = DeviceUpdateMsg.newBuilder()
|
||||||
.setMsgType(msgType)
|
.setMsgType(msgType)
|
||||||
@ -67,4 +73,21 @@ public class DeviceMsgConstructor {
|
|||||||
.setIdMSB(deviceId.getId().getMostSignificantBits())
|
.setIdMSB(deviceId.getId().getMostSignificantBits())
|
||||||
.setIdLSB(deviceId.getId().getLeastSignificantBits()).build();
|
.setIdLSB(deviceId.getId().getLeastSignificantBits()).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DeviceRpcCallMsg constructDeviceRpcCallMsg(JsonNode body) {
|
||||||
|
RuleEngineDeviceRpcRequest request = mapper.convertValue(body, RuleEngineDeviceRpcRequest.class);
|
||||||
|
RpcRequestMsg.Builder requestBuilder = RpcRequestMsg.newBuilder();
|
||||||
|
requestBuilder.setMethod(request.getMethod());
|
||||||
|
requestBuilder.setParams(request.getBody());
|
||||||
|
DeviceRpcCallMsg.Builder builder = DeviceRpcCallMsg.newBuilder()
|
||||||
|
.setDeviceIdMSB(request.getDeviceId().getId().getMostSignificantBits())
|
||||||
|
.setDeviceIdLSB(request.getDeviceId().getId().getLeastSignificantBits())
|
||||||
|
.setRequestIdMSB(request.getRequestUUID().getMostSignificantBits())
|
||||||
|
.setRequestIdLSB(request.getRequestUUID().getLeastSignificantBits())
|
||||||
|
.setExpirationTime(request.getExpirationTime())
|
||||||
|
.setOriginServiceId(request.getOriginServiceId())
|
||||||
|
.setOneway(request.isOneway())
|
||||||
|
.setRequestMsg(requestBuilder.build());
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,6 +39,7 @@ import org.thingsboard.server.dao.relation.RelationService;
|
|||||||
import org.thingsboard.server.dao.user.UserService;
|
import org.thingsboard.server.dao.user.UserService;
|
||||||
import org.thingsboard.server.service.executors.DbCallbackExecutorService;
|
import org.thingsboard.server.service.executors.DbCallbackExecutorService;
|
||||||
import org.thingsboard.server.service.queue.TbClusterService;
|
import org.thingsboard.server.service.queue.TbClusterService;
|
||||||
|
import org.thingsboard.server.service.rpc.TbRuleEngineDeviceRpcService;
|
||||||
import org.thingsboard.server.service.state.DeviceStateService;
|
import org.thingsboard.server.service.state.DeviceStateService;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -46,6 +47,9 @@ public abstract class BaseProcessor {
|
|||||||
|
|
||||||
protected static final ObjectMapper mapper = new ObjectMapper();
|
protected static final ObjectMapper mapper = new ObjectMapper();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
protected TbRuleEngineDeviceRpcService tbDeviceRpcService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
protected AlarmService alarmService;
|
protected AlarmService alarmService;
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,9 @@ import com.google.common.util.concurrent.Futures;
|
|||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang.RandomStringUtils;
|
import org.apache.commons.lang.RandomStringUtils;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.thingsboard.rule.engine.api.RpcError;
|
||||||
import org.thingsboard.server.common.data.DataConstants;
|
import org.thingsboard.server.common.data.DataConstants;
|
||||||
import org.thingsboard.server.common.data.Device;
|
import org.thingsboard.server.common.data.Device;
|
||||||
import org.thingsboard.server.common.data.audit.ActionType;
|
import org.thingsboard.server.common.data.audit.ActionType;
|
||||||
@ -40,9 +42,11 @@ import org.thingsboard.server.common.msg.TbMsg;
|
|||||||
import org.thingsboard.server.common.msg.TbMsgDataType;
|
import org.thingsboard.server.common.msg.TbMsgDataType;
|
||||||
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
||||||
import org.thingsboard.server.gen.edge.DeviceCredentialsUpdateMsg;
|
import org.thingsboard.server.gen.edge.DeviceCredentialsUpdateMsg;
|
||||||
|
import org.thingsboard.server.gen.edge.DeviceRpcCallMsg;
|
||||||
import org.thingsboard.server.gen.edge.DeviceUpdateMsg;
|
import org.thingsboard.server.gen.edge.DeviceUpdateMsg;
|
||||||
import org.thingsboard.server.queue.TbQueueCallback;
|
import org.thingsboard.server.queue.TbQueueCallback;
|
||||||
import org.thingsboard.server.queue.TbQueueMsgMetadata;
|
import org.thingsboard.server.queue.TbQueueMsgMetadata;
|
||||||
|
import org.thingsboard.server.service.rpc.FromDeviceRpcResponse;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
@ -213,4 +217,17 @@ public class DeviceProcessor extends BaseProcessor {
|
|||||||
metaData.putValue("edgeName", edge.getName());
|
metaData.putValue("edgeName", edge.getName());
|
||||||
return metaData;
|
return metaData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ListenableFuture<Void> processDeviceRpcCallResponseMsg(TenantId tenantId, DeviceRpcCallMsg deviceRpcCallMsg) {
|
||||||
|
UUID uuid = new UUID(deviceRpcCallMsg.getRequestIdMSB(), deviceRpcCallMsg.getRequestIdLSB());
|
||||||
|
FromDeviceRpcResponse response;
|
||||||
|
if (!StringUtils.isEmpty(deviceRpcCallMsg.getResponseMsg().getError())) {
|
||||||
|
response = new FromDeviceRpcResponse(uuid, null, RpcError.valueOf(deviceRpcCallMsg.getResponseMsg().getError()));
|
||||||
|
} else {
|
||||||
|
response = new FromDeviceRpcResponse(uuid, deviceRpcCallMsg.getResponseMsg().getResponse(), null);
|
||||||
|
}
|
||||||
|
tbDeviceRpcService.sendRpcResponseToTbCore(deviceRpcCallMsg.getOriginServiceId(), response);
|
||||||
|
return Futures.immediateFuture(null);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -151,7 +151,8 @@ public class DefaultTbRuleEngineRpcService implements TbRuleEngineDeviceRpcServi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendRpcResponseToTbCore(String originServiceId, FromDeviceRpcResponse response) {
|
@Override
|
||||||
|
public void sendRpcResponseToTbCore(String originServiceId, FromDeviceRpcResponse response) {
|
||||||
if (serviceId.equals(originServiceId)) {
|
if (serviceId.equals(originServiceId)) {
|
||||||
if (tbCoreRpcService.isPresent()) {
|
if (tbCoreRpcService.isPresent()) {
|
||||||
tbCoreRpcService.get().processRpcResponseFromRuleEngine(response);
|
tbCoreRpcService.get().processRpcResponseFromRuleEngine(response);
|
||||||
|
|||||||
@ -29,4 +29,7 @@ public interface TbRuleEngineDeviceRpcService extends RuleEngineRpcService {
|
|||||||
*/
|
*/
|
||||||
void processRpcResponseFromDevice(FromDeviceRpcResponse response);
|
void processRpcResponseFromDevice(FromDeviceRpcResponse response);
|
||||||
|
|
||||||
|
|
||||||
|
void sendRpcResponseToTbCore(String originServiceId, FromDeviceRpcResponse response);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -588,7 +588,7 @@ transport:
|
|||||||
# Edges parameters
|
# Edges parameters
|
||||||
edges:
|
edges:
|
||||||
rpc:
|
rpc:
|
||||||
enabled: "${EDGES_RPC_ENABLED:true}"
|
enabled: "${EDGES_RPC_ENABLED:false}"
|
||||||
port: "${EDGES_RPC_PORT:7070}"
|
port: "${EDGES_RPC_PORT:7070}"
|
||||||
ssl:
|
ssl:
|
||||||
# Enable/disable SSL support
|
# Enable/disable SSL support
|
||||||
|
|||||||
@ -322,6 +322,28 @@ message DeviceCredentialsRequestMsg {
|
|||||||
int64 deviceIdLSB = 2;
|
int64 deviceIdLSB = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message DeviceRpcCallMsg {
|
||||||
|
int64 deviceIdMSB = 1;
|
||||||
|
int64 deviceIdLSB = 2;
|
||||||
|
int64 requestIdMSB = 3;
|
||||||
|
int64 requestIdLSB = 4;
|
||||||
|
int64 expirationTime = 5;
|
||||||
|
bool oneway = 6;
|
||||||
|
string originServiceId = 7;
|
||||||
|
RpcRequestMsg requestMsg = 8;
|
||||||
|
RpcResponseMsg responseMsg = 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
message RpcRequestMsg {
|
||||||
|
string method = 1;
|
||||||
|
string params = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message RpcResponseMsg {
|
||||||
|
string response = 1;
|
||||||
|
string error = 2;
|
||||||
|
}
|
||||||
|
|
||||||
enum EdgeEntityType {
|
enum EdgeEntityType {
|
||||||
DEVICE = 0;
|
DEVICE = 0;
|
||||||
ASSET = 1;
|
ASSET = 1;
|
||||||
@ -343,6 +365,7 @@ message UplinkMsg {
|
|||||||
repeated RelationRequestMsg relationRequestMsg = 9;
|
repeated RelationRequestMsg relationRequestMsg = 9;
|
||||||
repeated UserCredentialsRequestMsg userCredentialsRequestMsg = 10;
|
repeated UserCredentialsRequestMsg userCredentialsRequestMsg = 10;
|
||||||
repeated DeviceCredentialsRequestMsg deviceCredentialsRequestMsg = 11;
|
repeated DeviceCredentialsRequestMsg deviceCredentialsRequestMsg = 11;
|
||||||
|
repeated DeviceRpcCallMsg deviceRpcCallMsg = 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
message UplinkResponseMsg {
|
message UplinkResponseMsg {
|
||||||
@ -374,6 +397,6 @@ message DownlinkMsg {
|
|||||||
repeated WidgetsBundleUpdateMsg widgetsBundleUpdateMsg = 16;
|
repeated WidgetsBundleUpdateMsg widgetsBundleUpdateMsg = 16;
|
||||||
repeated WidgetTypeUpdateMsg widgetTypeUpdateMsg = 17;
|
repeated WidgetTypeUpdateMsg widgetTypeUpdateMsg = 17;
|
||||||
repeated AdminSettingsUpdateMsg adminSettingsUpdateMsg = 18;
|
repeated AdminSettingsUpdateMsg adminSettingsUpdateMsg = 18;
|
||||||
|
repeated DeviceRpcCallMsg deviceRpcCallMsg = 19;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -425,38 +425,43 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ListenableFuture<List<EdgeId>> findRelatedEdgeIdsByEntityId(TenantId tenantId, EntityId entityId) {
|
public ListenableFuture<List<EdgeId>> findRelatedEdgeIdsByEntityId(TenantId tenantId, EntityId entityId) {
|
||||||
switch (entityId.getEntityType()) {
|
if (EntityType.TENANT.equals(entityId.getEntityType())) {
|
||||||
case DEVICE:
|
TextPageData<Edge> edgesByTenantId = findEdgesByTenantId(tenantId, new TextPageLink(Integer.MAX_VALUE));
|
||||||
case ASSET:
|
return Futures.immediateFuture(edgesByTenantId.getData().stream().map(IdBased::getId).collect(Collectors.toList()));
|
||||||
case ENTITY_VIEW:
|
} else {
|
||||||
ListenableFuture<List<EntityRelation>> originatorEdgeRelationsFuture =
|
switch (entityId.getEntityType()) {
|
||||||
relationService.findByToAndTypeAsync(tenantId, entityId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE);
|
case DEVICE:
|
||||||
return Futures.transform(originatorEdgeRelationsFuture, originatorEdgeRelations -> {
|
case ASSET:
|
||||||
if (originatorEdgeRelations != null && originatorEdgeRelations.size() > 0 &&
|
case ENTITY_VIEW:
|
||||||
originatorEdgeRelations.get(0).getFrom() != null) {
|
ListenableFuture<List<EntityRelation>> originatorEdgeRelationsFuture =
|
||||||
return Collections.singletonList(new EdgeId(originatorEdgeRelations.get(0).getFrom().getId()));
|
relationService.findByToAndTypeAsync(tenantId, entityId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE);
|
||||||
} else {
|
return Futures.transform(originatorEdgeRelationsFuture, originatorEdgeRelations -> {
|
||||||
return Collections.emptyList();
|
if (originatorEdgeRelations != null && originatorEdgeRelations.size() > 0 &&
|
||||||
|
originatorEdgeRelations.get(0).getFrom() != null) {
|
||||||
|
return Collections.singletonList(new EdgeId(originatorEdgeRelations.get(0).getFrom().getId()));
|
||||||
|
} else {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}, MoreExecutors.directExecutor());
|
||||||
|
case DASHBOARD:
|
||||||
|
return convertToEdgeIds(findEdgesByTenantIdAndDashboardId(tenantId, new DashboardId(entityId.getId())));
|
||||||
|
case RULE_CHAIN:
|
||||||
|
return convertToEdgeIds(findEdgesByTenantIdAndRuleChainId(tenantId, new RuleChainId(entityId.getId())));
|
||||||
|
case USER:
|
||||||
|
User userById = userService.findUserById(tenantId, new UserId(entityId.getId()));
|
||||||
|
if (userById == null) {
|
||||||
|
return Futures.immediateFuture(Collections.emptyList());
|
||||||
}
|
}
|
||||||
}, MoreExecutors.directExecutor());
|
TextPageData<Edge> edges;
|
||||||
case DASHBOARD:
|
if (userById.getCustomerId() == null || userById.getCustomerId().isNullUid()) {
|
||||||
return convertToEdgeIds(findEdgesByTenantIdAndDashboardId(tenantId, new DashboardId(entityId.getId())));
|
edges = findEdgesByTenantId(tenantId, new TextPageLink(Integer.MAX_VALUE));
|
||||||
case RULE_CHAIN:
|
} else {
|
||||||
return convertToEdgeIds(findEdgesByTenantIdAndRuleChainId(tenantId, new RuleChainId(entityId.getId())));
|
edges = findEdgesByTenantIdAndCustomerId(tenantId, new CustomerId(entityId.getId()), new TextPageLink(Integer.MAX_VALUE));
|
||||||
case USER:
|
}
|
||||||
User userById = userService.findUserById(tenantId, new UserId(entityId.getId()));
|
return convertToEdgeIds(Futures.immediateFuture(edges.getData()));
|
||||||
if (userById == null) {
|
default:
|
||||||
return Futures.immediateFuture(Collections.emptyList());
|
return Futures.immediateFuture(Collections.emptyList());
|
||||||
}
|
}
|
||||||
TextPageData<Edge> edges;
|
|
||||||
if (userById.getCustomerId() == null || userById.getCustomerId().isNullUid()) {
|
|
||||||
edges = findEdgesByTenantId(tenantId, new TextPageLink(Integer.MAX_VALUE));
|
|
||||||
} else {
|
|
||||||
edges = findEdgesByTenantIdAndCustomerId(tenantId, new CustomerId(entityId.getId()), new TextPageLink(Integer.MAX_VALUE));
|
|
||||||
}
|
|
||||||
return convertToEdgeIds(Futures.immediateFuture(edges.getData()));
|
|
||||||
default:
|
|
||||||
return Futures.immediateFuture(Collections.emptyList());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -33,29 +33,20 @@ import org.thingsboard.server.common.data.DataConstants;
|
|||||||
import org.thingsboard.server.common.data.EdgeUtils;
|
import org.thingsboard.server.common.data.EdgeUtils;
|
||||||
import org.thingsboard.server.common.data.EntityType;
|
import org.thingsboard.server.common.data.EntityType;
|
||||||
import org.thingsboard.server.common.data.audit.ActionType;
|
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.edge.EdgeEvent;
|
||||||
import org.thingsboard.server.common.data.edge.EdgeEventType;
|
import org.thingsboard.server.common.data.edge.EdgeEventType;
|
||||||
import org.thingsboard.server.common.data.id.EdgeId;
|
import org.thingsboard.server.common.data.id.EdgeId;
|
||||||
import org.thingsboard.server.common.data.id.EntityId;
|
|
||||||
import org.thingsboard.server.common.data.id.IdBased;
|
|
||||||
import org.thingsboard.server.common.data.id.TenantId;
|
import org.thingsboard.server.common.data.id.TenantId;
|
||||||
import org.thingsboard.server.common.data.page.TextPageData;
|
|
||||||
import org.thingsboard.server.common.data.page.TextPageLink;
|
|
||||||
import org.thingsboard.server.common.data.plugin.ComponentType;
|
import org.thingsboard.server.common.data.plugin.ComponentType;
|
||||||
import org.thingsboard.server.common.data.relation.EntityRelation;
|
|
||||||
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
|
|
||||||
import org.thingsboard.server.common.data.rule.RuleChainType;
|
import org.thingsboard.server.common.data.rule.RuleChainType;
|
||||||
import org.thingsboard.server.common.msg.TbMsg;
|
import org.thingsboard.server.common.msg.TbMsg;
|
||||||
import org.thingsboard.server.common.msg.session.SessionMsgType;
|
import org.thingsboard.server.common.msg.session.SessionMsgType;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
|
import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
|
||||||
|
|
||||||
@ -86,51 +77,12 @@ public class TbMsgPushToEdgeNode implements TbNode {
|
|||||||
public void onMsg(TbContext ctx, TbMsg msg) {
|
public void onMsg(TbContext ctx, TbMsg msg) {
|
||||||
if (DataConstants.EDGE_MSG_SOURCE.equalsIgnoreCase(msg.getMetaData().getValue(DataConstants.MSG_SOURCE_KEY))) {
|
if (DataConstants.EDGE_MSG_SOURCE.equalsIgnoreCase(msg.getMetaData().getValue(DataConstants.MSG_SOURCE_KEY))) {
|
||||||
log.debug("Ignoring msg from the cloud, msg [{}]", msg);
|
log.debug("Ignoring msg from the cloud, msg [{}]", msg);
|
||||||
|
ctx.ack(msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isSupportedOriginator(msg.getOriginator().getEntityType())) {
|
if (isSupportedOriginator(msg.getOriginator().getEntityType())) {
|
||||||
if (isSupportedMsgType(msg.getType())) {
|
if (isSupportedMsgType(msg.getType())) {
|
||||||
ListenableFuture<List<EdgeId>> getEdgeIdsFuture = getEdgeIdsByOriginatorId(ctx, ctx.getTenantId(), msg.getOriginator());
|
processMsg(ctx, msg);
|
||||||
Futures.addCallback(getEdgeIdsFuture, new FutureCallback<List<EdgeId>>() {
|
|
||||||
@Override
|
|
||||||
public void onSuccess(@Nullable List<EdgeId> edgeIds) {
|
|
||||||
if (edgeIds != null && !edgeIds.isEmpty()) {
|
|
||||||
for (EdgeId edgeId : edgeIds) {
|
|
||||||
try {
|
|
||||||
EdgeEvent edgeEvent = buildEdgeEvent(msg, ctx);
|
|
||||||
if (edgeEvent == null) {
|
|
||||||
log.debug("Edge event type is null. Entity Type {}", msg.getOriginator().getEntityType());
|
|
||||||
ctx.tellFailure(msg, new RuntimeException("Edge event type is null. Entity Type '" + msg.getOriginator().getEntityType() + "'"));
|
|
||||||
} else {
|
|
||||||
edgeEvent.setEdgeId(edgeId);
|
|
||||||
ListenableFuture<EdgeEvent> saveFuture = ctx.getEdgeEventService().saveAsync(edgeEvent);
|
|
||||||
Futures.addCallback(saveFuture, new FutureCallback<EdgeEvent>() {
|
|
||||||
@Override
|
|
||||||
public void onSuccess(@Nullable EdgeEvent event) {
|
|
||||||
ctx.tellNext(msg, SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(Throwable th) {
|
|
||||||
log.error("Could not save edge event", th);
|
|
||||||
ctx.tellFailure(msg, th);
|
|
||||||
}
|
|
||||||
}, ctx.getDbCallbackExecutor());
|
|
||||||
}
|
|
||||||
} catch (JsonProcessingException e) {
|
|
||||||
log.error("Failed to build edge event", e);
|
|
||||||
ctx.tellFailure(msg, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(Throwable t) {
|
|
||||||
ctx.tellFailure(msg, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
}, ctx.getDbCallbackExecutor());
|
|
||||||
} else {
|
} else {
|
||||||
log.debug("Unsupported msg type {}", msg.getType());
|
log.debug("Unsupported msg type {}", msg.getType());
|
||||||
ctx.tellFailure(msg, new RuntimeException("Unsupported msg type '" + msg.getType() + "'"));
|
ctx.tellFailure(msg, new RuntimeException("Unsupported msg type '" + msg.getType() + "'"));
|
||||||
@ -141,6 +93,50 @@ public class TbMsgPushToEdgeNode implements TbNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void processMsg(TbContext ctx, TbMsg msg) {
|
||||||
|
ListenableFuture<List<EdgeId>> getEdgeIdsFuture = ctx.getEdgeService().findRelatedEdgeIdsByEntityId(ctx.getTenantId(), msg.getOriginator());
|
||||||
|
Futures.addCallback(getEdgeIdsFuture, new FutureCallback<List<EdgeId>>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(@Nullable List<EdgeId> edgeIds) {
|
||||||
|
if (edgeIds != null && !edgeIds.isEmpty()) {
|
||||||
|
for (EdgeId edgeId : edgeIds) {
|
||||||
|
try {
|
||||||
|
EdgeEvent edgeEvent = buildEdgeEvent(msg, ctx);
|
||||||
|
if (edgeEvent == null) {
|
||||||
|
log.debug("Edge event type is null. Entity Type {}", msg.getOriginator().getEntityType());
|
||||||
|
ctx.tellFailure(msg, new RuntimeException("Edge event type is null. Entity Type '" + msg.getOriginator().getEntityType() + "'"));
|
||||||
|
} else {
|
||||||
|
edgeEvent.setEdgeId(edgeId);
|
||||||
|
ListenableFuture<EdgeEvent> saveFuture = ctx.getEdgeEventService().saveAsync(edgeEvent);
|
||||||
|
Futures.addCallback(saveFuture, new FutureCallback<EdgeEvent>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(@Nullable EdgeEvent event) {
|
||||||
|
ctx.tellNext(msg, SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable th) {
|
||||||
|
log.error("Could not save edge event", th);
|
||||||
|
ctx.tellFailure(msg, th);
|
||||||
|
}
|
||||||
|
}, ctx.getDbCallbackExecutor());
|
||||||
|
}
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
log.error("Failed to build edge event", e);
|
||||||
|
ctx.tellFailure(msg, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable t) {
|
||||||
|
ctx.tellFailure(msg, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
}, ctx.getDbCallbackExecutor());
|
||||||
|
}
|
||||||
|
|
||||||
private EdgeEvent buildEdgeEvent(TbMsg msg, TbContext ctx) throws JsonProcessingException {
|
private EdgeEvent buildEdgeEvent(TbMsg msg, TbContext ctx) throws JsonProcessingException {
|
||||||
if (DataConstants.ALARM.equals(msg.getType())) {
|
if (DataConstants.ALARM.equals(msg.getType())) {
|
||||||
return buildEdgeEvent(ctx.getTenantId(), ActionType.ADDED, getUUIDFromMsgData(msg), EdgeEventType.ALARM, null);
|
return buildEdgeEvent(ctx.getTenantId(), ActionType.ADDED, getUUIDFromMsgData(msg), EdgeEventType.ALARM, null);
|
||||||
@ -227,15 +223,6 @@ public class TbMsgPushToEdgeNode implements TbNode {
|
|||||||
|| DataConstants.ALARM.equals(msgType);
|
|| DataConstants.ALARM.equals(msgType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ListenableFuture<List<EdgeId>> getEdgeIdsByOriginatorId(TbContext ctx, TenantId tenantId, EntityId originatorId) {
|
|
||||||
if (EntityType.TENANT.equals(originatorId.getEntityType())) {
|
|
||||||
TextPageData<Edge> edgesByTenantId = ctx.getEdgeService().findEdgesByTenantId(tenantId, new TextPageLink(Integer.MAX_VALUE));
|
|
||||||
return Futures.immediateFuture(edgesByTenantId.getData().stream().map(IdBased::getId).collect(Collectors.toList()));
|
|
||||||
} else {
|
|
||||||
return ctx.getEdgeService().findRelatedEdgeIdsByEntityId(tenantId, originatorId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,13 +16,16 @@
|
|||||||
package org.thingsboard.rule.engine.rpc;
|
package org.thingsboard.rule.engine.rpc;
|
||||||
|
|
||||||
import com.datastax.driver.core.utils.UUIDs;
|
import com.datastax.driver.core.utils.UUIDs;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.google.common.util.concurrent.FutureCallback;
|
||||||
|
import com.google.common.util.concurrent.Futures;
|
||||||
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
|
|
||||||
import org.thingsboard.rule.engine.api.RuleEngineDeviceRpcRequest;
|
import org.thingsboard.rule.engine.api.RuleEngineDeviceRpcRequest;
|
||||||
import org.thingsboard.rule.engine.api.RuleNode;
|
import org.thingsboard.rule.engine.api.RuleNode;
|
||||||
import org.thingsboard.rule.engine.api.TbContext;
|
import org.thingsboard.rule.engine.api.TbContext;
|
||||||
@ -30,13 +33,21 @@ import org.thingsboard.rule.engine.api.TbNode;
|
|||||||
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
|
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
|
||||||
import org.thingsboard.rule.engine.api.TbNodeException;
|
import org.thingsboard.rule.engine.api.TbNodeException;
|
||||||
import org.thingsboard.rule.engine.api.TbRelationTypes;
|
import org.thingsboard.rule.engine.api.TbRelationTypes;
|
||||||
|
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
|
||||||
import org.thingsboard.server.common.data.DataConstants;
|
import org.thingsboard.server.common.data.DataConstants;
|
||||||
import org.thingsboard.server.common.data.EntityType;
|
import org.thingsboard.server.common.data.EntityType;
|
||||||
|
import org.thingsboard.server.common.data.audit.ActionType;
|
||||||
|
import org.thingsboard.server.common.data.edge.EdgeEvent;
|
||||||
|
import org.thingsboard.server.common.data.edge.EdgeEventType;
|
||||||
import org.thingsboard.server.common.data.id.DeviceId;
|
import org.thingsboard.server.common.data.id.DeviceId;
|
||||||
|
import org.thingsboard.server.common.data.id.EdgeId;
|
||||||
import org.thingsboard.server.common.data.plugin.ComponentType;
|
import org.thingsboard.server.common.data.plugin.ComponentType;
|
||||||
import org.thingsboard.server.common.data.rule.RuleChainType;
|
import org.thingsboard.server.common.data.relation.EntityRelation;
|
||||||
|
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
|
||||||
import org.thingsboard.server.common.msg.TbMsg;
|
import org.thingsboard.server.common.msg.TbMsg;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@ -55,6 +66,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
)
|
)
|
||||||
public class TbSendRPCRequestNode implements TbNode {
|
public class TbSendRPCRequestNode implements TbNode {
|
||||||
|
|
||||||
|
private static final ObjectMapper json = new ObjectMapper();
|
||||||
private Random random = new Random();
|
private Random random = new Random();
|
||||||
private Gson gson = new Gson();
|
private Gson gson = new Gson();
|
||||||
private JsonParser jsonParser = new JsonParser();
|
private JsonParser jsonParser = new JsonParser();
|
||||||
@ -111,19 +123,57 @@ public class TbSendRPCRequestNode implements TbNode {
|
|||||||
.restApiCall(restApiCall)
|
.restApiCall(restApiCall)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
ctx.getRpcService().sendRpcRequestToDevice(request, ruleEngineDeviceRpcResponse -> {
|
EdgeId edgeId = findRelatedEdgeId(ctx, msg);
|
||||||
if (!ruleEngineDeviceRpcResponse.getError().isPresent()) {
|
if (edgeId != null) {
|
||||||
TbMsg next = ctx.newMsg(msg.getQueueName(), msg.getType(), msg.getOriginator(), msg.getMetaData(), ruleEngineDeviceRpcResponse.getResponse().orElse("{}"));
|
sendRpcRequestToEdgeDevice(ctx, msg, edgeId, request);
|
||||||
ctx.enqueueForTellNext(next, TbRelationTypes.SUCCESS);
|
} else {
|
||||||
} else {
|
ctx.getRpcService().sendRpcRequestToDevice(request, ruleEngineDeviceRpcResponse -> {
|
||||||
TbMsg next = ctx.newMsg(msg.getQueueName(), msg.getType(), msg.getOriginator(), msg.getMetaData(), wrap("error", ruleEngineDeviceRpcResponse.getError().get().name()));
|
if (!ruleEngineDeviceRpcResponse.getError().isPresent()) {
|
||||||
ctx.tellFailure(next, new RuntimeException(ruleEngineDeviceRpcResponse.getError().get().name()));
|
TbMsg next = ctx.newMsg(msg.getQueueName(), msg.getType(), msg.getOriginator(), msg.getMetaData(), ruleEngineDeviceRpcResponse.getResponse().orElse("{}"));
|
||||||
}
|
ctx.enqueueForTellNext(next, TbRelationTypes.SUCCESS);
|
||||||
});
|
} else {
|
||||||
|
TbMsg next = ctx.newMsg(msg.getQueueName(), msg.getType(), msg.getOriginator(), msg.getMetaData(), wrap("error", ruleEngineDeviceRpcResponse.getError().get().name()));
|
||||||
|
ctx.tellFailure(next, new RuntimeException(ruleEngineDeviceRpcResponse.getError().get().name()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
ctx.ack(msg);
|
ctx.ack(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private EdgeId findRelatedEdgeId(TbContext ctx, TbMsg msg) {
|
||||||
|
List<EntityRelation> result =
|
||||||
|
ctx.getRelationService().findByToAndType(ctx.getTenantId(), msg.getOriginator(), EntityRelation.EDGE_TYPE, RelationTypeGroup.COMMON);
|
||||||
|
if (result != null && result.size() > 0) {
|
||||||
|
return new EdgeId(result.get(0).getFrom().getId());
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendRpcRequestToEdgeDevice(TbContext ctx, TbMsg msg, EdgeId edgeId, RuleEngineDeviceRpcRequest request) {
|
||||||
|
EdgeEvent edgeEvent = new EdgeEvent();
|
||||||
|
edgeEvent.setTenantId(ctx.getTenantId());
|
||||||
|
edgeEvent.setEdgeEventAction(ActionType.RPC_CALL.name());
|
||||||
|
edgeEvent.setEntityId(request.getDeviceId().getId());
|
||||||
|
edgeEvent.setEdgeEventType(EdgeEventType.DEVICE);
|
||||||
|
edgeEvent.setEntityBody(json.valueToTree(request));
|
||||||
|
edgeEvent.setEdgeId(edgeId);
|
||||||
|
ListenableFuture<EdgeEvent> saveFuture = ctx.getEdgeEventService().saveAsync(edgeEvent);
|
||||||
|
Futures.addCallback(saveFuture, new FutureCallback<EdgeEvent>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(@Nullable EdgeEvent event) {
|
||||||
|
ctx.tellSuccess(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable th) {
|
||||||
|
log.error("Could not save edge event", th);
|
||||||
|
ctx.tellFailure(msg, th);
|
||||||
|
}
|
||||||
|
}, ctx.getDbCallbackExecutor());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user