Commit 3c7295ee8e2ca2a085ff3a7338ad4f8c84437436

Authored by Andrew Shvayka
1 parent 69aac973

RPC

Showing 30 changed files with 754 additions and 149 deletions
@@ -199,6 +199,10 @@ public class ActorSystemContext { @@ -199,6 +199,10 @@ public class ActorSystemContext {
199 @Getter 199 @Getter
200 private long queuePersistenceTimeout; 200 private long queuePersistenceTimeout;
201 201
  202 + @Value("${actors.client_side_rpc.timeout}")
  203 + @Getter
  204 + private long clientSideRpcTimeout;
  205 +
202 @Value("${actors.rule.chain.error_persist_frequency}") 206 @Value("${actors.rule.chain.error_persist_frequency}")
203 @Getter 207 @Getter
204 private long ruleChainErrorPersistFrequency; 208 private long ruleChainErrorPersistFrequency;
@@ -25,12 +25,13 @@ import org.thingsboard.server.common.data.id.TenantId; @@ -25,12 +25,13 @@ import org.thingsboard.server.common.data.id.TenantId;
25 import org.thingsboard.server.common.msg.TbActorMsg; 25 import org.thingsboard.server.common.msg.TbActorMsg;
26 import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; 26 import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
27 import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; 27 import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg;
  28 +import org.thingsboard.server.common.msg.timeout.DeviceActorClientSideRpcTimeoutMsg;
28 import org.thingsboard.server.common.msg.timeout.DeviceActorQueueTimeoutMsg; 29 import org.thingsboard.server.common.msg.timeout.DeviceActorQueueTimeoutMsg;
29 -import org.thingsboard.server.common.msg.timeout.DeviceActorRpcTimeoutMsg; 30 +import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg;
30 import org.thingsboard.server.extensions.api.device.DeviceAttributesEventNotificationMsg; 31 import org.thingsboard.server.extensions.api.device.DeviceAttributesEventNotificationMsg;
31 import org.thingsboard.server.extensions.api.device.DeviceNameOrTypeUpdateMsg; 32 import org.thingsboard.server.extensions.api.device.DeviceNameOrTypeUpdateMsg;
32 -import org.thingsboard.server.common.msg.timeout.TimeoutMsg;  
33 -import org.thingsboard.server.service.rpc.ToDeviceRpcRequestMsg; 33 +import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg;
  34 +import org.thingsboard.server.service.rpc.ToServerRpcResponseActorMsg;
34 35
35 public class DeviceActor extends ContextAwareActor { 36 public class DeviceActor extends ContextAwareActor {
36 37
@@ -62,10 +63,16 @@ public class DeviceActor extends ContextAwareActor { @@ -62,10 +63,16 @@ public class DeviceActor extends ContextAwareActor {
62 processor.processNameOrTypeUpdate((DeviceNameOrTypeUpdateMsg) msg); 63 processor.processNameOrTypeUpdate((DeviceNameOrTypeUpdateMsg) msg);
63 break; 64 break;
64 case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG: 65 case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG:
65 - processor.processRpcRequest(context(), (ToDeviceRpcRequestMsg) msg); 66 + processor.processRpcRequest(context(), (ToDeviceRpcRequestActorMsg) msg);
66 break; 67 break;
67 - case DEVICE_ACTOR_RPC_TIMEOUT_MSG:  
68 - processor.processRpcTimeout(context(), (DeviceActorRpcTimeoutMsg) msg); 68 + case SERVER_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG:
  69 + processor.processToServerRPCResponse(context(), (ToServerRpcResponseActorMsg) msg);
  70 + break;
  71 + case DEVICE_ACTOR_SERVER_SIDE_RPC_TIMEOUT_MSG:
  72 + processor.processServerSideRpcTimeout(context(), (DeviceActorServerSideRpcTimeoutMsg) msg);
  73 + break;
  74 + case DEVICE_ACTOR_CLIENT_SIDE_RPC_TIMEOUT_MSG:
  75 + processor.processClientSideRpcTimeout(context(), (DeviceActorClientSideRpcTimeoutMsg) msg);
69 break; 76 break;
70 case DEVICE_ACTOR_QUEUE_TIMEOUT_MSG: 77 case DEVICE_ACTOR_QUEUE_TIMEOUT_MSG:
71 processor.processQueueTimeout(context(), (DeviceActorQueueTimeoutMsg) msg); 78 processor.processQueueTimeout(context(), (DeviceActorQueueTimeoutMsg) msg);
1 /** 1 /**
2 * Copyright © 2016-2018 The Thingsboard Authors 2 * Copyright © 2016-2018 The Thingsboard Authors
3 - * 3 + * <p>
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at 6 * You may obtain a copy of the License at
7 - *  
8 - * http://www.apache.org/licenses/LICENSE-2.0  
9 - * 7 + * <p>
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + * <p>
10 * Unless required by applicable law or agreed to in writing, software 10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, 11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -25,6 +25,7 @@ import com.google.common.util.concurrent.ListenableFuture; @@ -25,6 +25,7 @@ import com.google.common.util.concurrent.ListenableFuture;
25 import com.google.gson.Gson; 25 import com.google.gson.Gson;
26 import com.google.gson.JsonArray; 26 import com.google.gson.JsonArray;
27 import com.google.gson.JsonObject; 27 import com.google.gson.JsonObject;
  28 +import com.google.gson.JsonParser;
28 import org.thingsboard.server.actors.ActorSystemContext; 29 import org.thingsboard.server.actors.ActorSystemContext;
29 import org.thingsboard.server.actors.shared.AbstractContextAwareMsgProcessor; 30 import org.thingsboard.server.actors.shared.AbstractContextAwareMsgProcessor;
30 import org.thingsboard.server.common.data.DataConstants; 31 import org.thingsboard.server.common.data.DataConstants;
@@ -53,28 +54,28 @@ import org.thingsboard.server.common.msg.core.RuleEngineErrorMsg; @@ -53,28 +54,28 @@ import org.thingsboard.server.common.msg.core.RuleEngineErrorMsg;
53 import org.thingsboard.server.common.msg.core.SessionCloseMsg; 54 import org.thingsboard.server.common.msg.core.SessionCloseMsg;
54 import org.thingsboard.server.common.msg.core.SessionCloseNotification; 55 import org.thingsboard.server.common.msg.core.SessionCloseNotification;
55 import org.thingsboard.server.common.msg.core.SessionOpenMsg; 56 import org.thingsboard.server.common.msg.core.SessionOpenMsg;
56 -import org.thingsboard.server.common.msg.core.StatusCodeResponse;  
57 import org.thingsboard.server.common.msg.core.TelemetryUploadRequest; 57 import org.thingsboard.server.common.msg.core.TelemetryUploadRequest;
58 import org.thingsboard.server.common.msg.core.ToDeviceRpcRequestMsg; 58 import org.thingsboard.server.common.msg.core.ToDeviceRpcRequestMsg;
59 import org.thingsboard.server.common.msg.core.ToDeviceRpcResponseMsg; 59 import org.thingsboard.server.common.msg.core.ToDeviceRpcResponseMsg;
60 import org.thingsboard.server.common.msg.core.ToDeviceSessionActorMsg; 60 import org.thingsboard.server.common.msg.core.ToDeviceSessionActorMsg;
  61 +import org.thingsboard.server.common.msg.core.ToServerRpcRequestMsg;
61 import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; 62 import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg;
62 import org.thingsboard.server.common.msg.kv.BasicAttributeKVMsg; 63 import org.thingsboard.server.common.msg.kv.BasicAttributeKVMsg;
63 import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; 64 import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest;
64 import org.thingsboard.server.common.msg.session.FromDeviceMsg; 65 import org.thingsboard.server.common.msg.session.FromDeviceMsg;
65 import org.thingsboard.server.common.msg.session.FromDeviceRequestMsg; 66 import org.thingsboard.server.common.msg.session.FromDeviceRequestMsg;
66 import org.thingsboard.server.common.msg.session.SessionMsgType; 67 import org.thingsboard.server.common.msg.session.SessionMsgType;
67 -import org.thingsboard.server.common.msg.session.SessionMsgType;  
68 import org.thingsboard.server.common.msg.session.SessionType; 68 import org.thingsboard.server.common.msg.session.SessionType;
69 import org.thingsboard.server.common.msg.session.ToDeviceMsg; 69 import org.thingsboard.server.common.msg.session.ToDeviceMsg;
  70 +import org.thingsboard.server.common.msg.timeout.DeviceActorClientSideRpcTimeoutMsg;
70 import org.thingsboard.server.common.msg.timeout.DeviceActorQueueTimeoutMsg; 71 import org.thingsboard.server.common.msg.timeout.DeviceActorQueueTimeoutMsg;
71 -import org.thingsboard.server.common.msg.timeout.DeviceActorRpcTimeoutMsg; 72 +import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg;
72 import org.thingsboard.server.extensions.api.device.DeviceAttributesEventNotificationMsg; 73 import org.thingsboard.server.extensions.api.device.DeviceAttributesEventNotificationMsg;
73 import org.thingsboard.server.extensions.api.device.DeviceNameOrTypeUpdateMsg; 74 import org.thingsboard.server.extensions.api.device.DeviceNameOrTypeUpdateMsg;
74 -import org.thingsboard.server.extensions.api.plugins.PluginCallback;  
75 -import org.thingsboard.server.extensions.api.plugins.PluginContext;  
76 import org.thingsboard.server.extensions.api.plugins.msg.FromDeviceRpcResponse; 75 import org.thingsboard.server.extensions.api.plugins.msg.FromDeviceRpcResponse;
77 import org.thingsboard.server.extensions.api.plugins.msg.RpcError; 76 import org.thingsboard.server.extensions.api.plugins.msg.RpcError;
  77 +import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg;
  78 +import org.thingsboard.server.service.rpc.ToServerRpcResponseActorMsg;
78 79
79 import javax.annotation.Nullable; 80 import javax.annotation.Nullable;
80 import java.util.ArrayList; 81 import java.util.ArrayList;
@@ -87,7 +88,6 @@ import java.util.Map; @@ -87,7 +88,6 @@ import java.util.Map;
87 import java.util.Optional; 88 import java.util.Optional;
88 import java.util.Set; 89 import java.util.Set;
89 import java.util.UUID; 90 import java.util.UUID;
90 -import java.util.concurrent.ExecutionException;  
91 import java.util.concurrent.TimeoutException; 91 import java.util.concurrent.TimeoutException;
92 import java.util.function.Consumer; 92 import java.util.function.Consumer;
93 import java.util.function.Predicate; 93 import java.util.function.Predicate;
@@ -103,10 +103,12 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso @@ -103,10 +103,12 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
103 private final Map<SessionId, SessionInfo> sessions; 103 private final Map<SessionId, SessionInfo> sessions;
104 private final Map<SessionId, SessionInfo> attributeSubscriptions; 104 private final Map<SessionId, SessionInfo> attributeSubscriptions;
105 private final Map<SessionId, SessionInfo> rpcSubscriptions; 105 private final Map<SessionId, SessionInfo> rpcSubscriptions;
106 - private final Map<Integer, ToDeviceRpcRequestMetadata> rpcPendingMap; 106 + private final Map<Integer, ToDeviceRpcRequestMetadata> toDeviceRpcPendingMap;
  107 + private final Map<Integer, ToServerRpcRequestMetadata> toServerRpcPendingMap;
107 private final Map<UUID, PendingSessionMsgData> pendingMsgs; 108 private final Map<UUID, PendingSessionMsgData> pendingMsgs;
108 109
109 private final Gson gson = new Gson(); 110 private final Gson gson = new Gson();
  111 + private final JsonParser jsonParser = new JsonParser();
110 112
111 private int rpcSeq = 0; 113 private int rpcSeq = 0;
112 private String deviceName; 114 private String deviceName;
@@ -120,7 +122,8 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso @@ -120,7 +122,8 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
120 this.sessions = new HashMap<>(); 122 this.sessions = new HashMap<>();
121 this.attributeSubscriptions = new HashMap<>(); 123 this.attributeSubscriptions = new HashMap<>();
122 this.rpcSubscriptions = new HashMap<>(); 124 this.rpcSubscriptions = new HashMap<>();
123 - this.rpcPendingMap = new HashMap<>(); 125 + this.toDeviceRpcPendingMap = new HashMap<>();
  126 + this.toServerRpcPendingMap = new HashMap<>();
124 this.pendingMsgs = new HashMap<>(); 127 this.pendingMsgs = new HashMap<>();
125 initAttributes(); 128 initAttributes();
126 } 129 }
@@ -134,7 +137,7 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso @@ -134,7 +137,7 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
134 this.defaultMetaData.putValue("deviceType", deviceType); 137 this.defaultMetaData.putValue("deviceType", deviceType);
135 } 138 }
136 139
137 - void processRpcRequest(ActorContext context, org.thingsboard.server.service.rpc.ToDeviceRpcRequestMsg msg) { 140 + void processRpcRequest(ActorContext context, ToDeviceRpcRequestActorMsg msg) {
138 ToDeviceRpcRequest request = msg.getMsg(); 141 ToDeviceRpcRequest request = msg.getMsg();
139 ToDeviceRpcRequestBody body = request.getBody(); 142 ToDeviceRpcRequestBody body = request.getBody();
140 ToDeviceRpcRequestMsg rpcRequest = new ToDeviceRpcRequestMsg( 143 ToDeviceRpcRequestMsg rpcRequest = new ToDeviceRpcRequestMsg(
@@ -174,14 +177,14 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso @@ -174,14 +177,14 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
174 177
175 } 178 }
176 179
177 - private void registerPendingRpcRequest(ActorContext context, org.thingsboard.server.service.rpc.ToDeviceRpcRequestMsg msg, boolean sent, ToDeviceRpcRequestMsg rpcRequest, long timeout) {  
178 - rpcPendingMap.put(rpcRequest.getRequestId(), new ToDeviceRpcRequestMetadata(msg, sent));  
179 - DeviceActorRpcTimeoutMsg timeoutMsg = new DeviceActorRpcTimeoutMsg(rpcRequest.getRequestId(), timeout); 180 + private void registerPendingRpcRequest(ActorContext context, ToDeviceRpcRequestActorMsg msg, boolean sent, ToDeviceRpcRequestMsg rpcRequest, long timeout) {
  181 + toDeviceRpcPendingMap.put(rpcRequest.getRequestId(), new ToDeviceRpcRequestMetadata(msg, sent));
  182 + DeviceActorServerSideRpcTimeoutMsg timeoutMsg = new DeviceActorServerSideRpcTimeoutMsg(rpcRequest.getRequestId(), timeout);
180 scheduleMsgWithDelay(context, timeoutMsg, timeoutMsg.getTimeout()); 183 scheduleMsgWithDelay(context, timeoutMsg, timeoutMsg.getTimeout());
181 } 184 }
182 185
183 - void processRpcTimeout(ActorContext context, DeviceActorRpcTimeoutMsg msg) {  
184 - ToDeviceRpcRequestMetadata requestMd = rpcPendingMap.remove(msg.getId()); 186 + void processServerSideRpcTimeout(ActorContext context, DeviceActorServerSideRpcTimeoutMsg msg) {
  187 + ToDeviceRpcRequestMetadata requestMd = toDeviceRpcPendingMap.remove(msg.getId());
185 if (requestMd != null) { 188 if (requestMd != null) {
186 logger.debug("[{}] RPC request [{}] timeout detected!", deviceId, msg.getId()); 189 logger.debug("[{}] RPC request [{}] timeout detected!", deviceId, msg.getId());
187 systemContext.getDeviceRpcService().process(new FromDeviceRpcResponse(requestMd.getMsg().getMsg().getId(), 190 systemContext.getDeviceRpcService().process(new FromDeviceRpcResponse(requestMd.getMsg().getMsg().getId(),
@@ -200,7 +203,7 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso @@ -200,7 +203,7 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
200 203
201 void processQueueAck(ActorContext context, RuleEngineQueuePutAckMsg msg) { 204 void processQueueAck(ActorContext context, RuleEngineQueuePutAckMsg msg) {
202 PendingSessionMsgData data = pendingMsgs.remove(msg.getId()); 205 PendingSessionMsgData data = pendingMsgs.remove(msg.getId());
203 - if (data != null) { 206 + if (data != null && data.isReplyOnQueueAck()) {
204 logger.debug("[{}] Queue put [{}] ack detected!", deviceId, msg.getId()); 207 logger.debug("[{}] Queue put [{}] ack detected!", deviceId, msg.getId());
205 ToDeviceMsg toDeviceMsg = BasicStatusCodeResponse.onSuccess(data.getSessionMsgType(), data.getRequestId()); 208 ToDeviceMsg toDeviceMsg = BasicStatusCodeResponse.onSuccess(data.getSessionMsgType(), data.getRequestId());
206 sendMsgToSessionActor(new BasicToDeviceSessionActorMsg(toDeviceMsg, data.getSessionId()), data.getServerAddress()); 209 sendMsgToSessionActor(new BasicToDeviceSessionActorMsg(toDeviceMsg, data.getSessionId()), data.getServerAddress());
@@ -208,8 +211,8 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso @@ -208,8 +211,8 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
208 } 211 }
209 212
210 private void sendPendingRequests(ActorContext context, SessionId sessionId, SessionType type, Optional<ServerAddress> server) { 213 private void sendPendingRequests(ActorContext context, SessionId sessionId, SessionType type, Optional<ServerAddress> server) {
211 - if (!rpcPendingMap.isEmpty()) {  
212 - logger.debug("[{}] Pushing {} pending RPC messages to new async session [{}]", deviceId, rpcPendingMap.size(), sessionId); 214 + if (!toDeviceRpcPendingMap.isEmpty()) {
  215 + logger.debug("[{}] Pushing {} pending RPC messages to new async session [{}]", deviceId, toDeviceRpcPendingMap.size(), sessionId);
213 if (type == SessionType.SYNC) { 216 if (type == SessionType.SYNC) {
214 logger.debug("[{}] Cleanup sync rpc session [{}]", deviceId, sessionId); 217 logger.debug("[{}] Cleanup sync rpc session [{}]", deviceId, sessionId);
215 rpcSubscriptions.remove(sessionId); 218 rpcSubscriptions.remove(sessionId);
@@ -219,12 +222,12 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso @@ -219,12 +222,12 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
219 } 222 }
220 Set<Integer> sentOneWayIds = new HashSet<>(); 223 Set<Integer> sentOneWayIds = new HashSet<>();
221 if (type == SessionType.ASYNC) { 224 if (type == SessionType.ASYNC) {
222 - rpcPendingMap.entrySet().forEach(processPendingRpc(context, sessionId, server, sentOneWayIds)); 225 + toDeviceRpcPendingMap.entrySet().forEach(processPendingRpc(context, sessionId, server, sentOneWayIds));
223 } else { 226 } else {
224 - rpcPendingMap.entrySet().stream().findFirst().ifPresent(processPendingRpc(context, sessionId, server, sentOneWayIds)); 227 + toDeviceRpcPendingMap.entrySet().stream().findFirst().ifPresent(processPendingRpc(context, sessionId, server, sentOneWayIds));
225 } 228 }
226 229
227 - sentOneWayIds.forEach(rpcPendingMap::remove); 230 + sentOneWayIds.forEach(toDeviceRpcPendingMap::remove);
228 } 231 }
229 232
230 private Consumer<Map.Entry<Integer, ToDeviceRpcRequestMetadata>> processPendingRpc(ActorContext context, SessionId sessionId, Optional<ServerAddress> server, Set<Integer> sentOneWayIds) { 233 private Consumer<Map.Entry<Integer, ToDeviceRpcRequestMetadata>> processPendingRpc(ActorContext context, SessionId sessionId, Optional<ServerAddress> server, Set<Integer> sentOneWayIds) {
@@ -263,8 +266,8 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso @@ -263,8 +266,8 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
263 handlePostTelemetryRequest(context, msg); 266 handlePostTelemetryRequest(context, msg);
264 break; 267 break;
265 case TO_SERVER_RPC_REQUEST: 268 case TO_SERVER_RPC_REQUEST:
  269 + handleClientSideRPCRequest(context, msg);
266 break; 270 break;
267 - //TODO: push to queue and start processing!  
268 } 271 }
269 } 272 }
270 } 273 }
@@ -345,11 +348,47 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso @@ -345,11 +348,47 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
345 pushToRuleEngineWithTimeout(context, tbMsg, src, request); 348 pushToRuleEngineWithTimeout(context, tbMsg, src, request);
346 } 349 }
347 350
  351 + private void handleClientSideRPCRequest(ActorContext context, DeviceToDeviceActorMsg src) {
  352 + ToServerRpcRequestMsg request = (ToServerRpcRequestMsg) src.getPayload();
  353 +
  354 + JsonObject json = new JsonObject();
  355 + json.addProperty("method", request.getMethod());
  356 + json.add("params", jsonParser.parse(request.getParams()));
  357 +
  358 + TbMsgMetaData requestMetaData = defaultMetaData.copy();
  359 + requestMetaData.putValue("requestId", Integer.toString(request.getRequestId()));
  360 + TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.TO_SERVER_RPC_REQUEST.name(), deviceId, requestMetaData, TbMsgDataType.JSON, gson.toJson(json));
  361 + pushToRuleEngineWithTimeout(context, tbMsg, src, request);
  362 +
  363 + scheduleMsgWithDelay(context, new DeviceActorClientSideRpcTimeoutMsg(request.getRequestId(), systemContext.getClientSideRpcTimeout()), systemContext.getClientSideRpcTimeout());
  364 + toServerRpcPendingMap.put(request.getRequestId(), new ToServerRpcRequestMetadata(src.getSessionId(), src.getSessionType(), src.getServerAddress()));
  365 + }
  366 +
  367 + public void processClientSideRpcTimeout(ActorContext context, DeviceActorClientSideRpcTimeoutMsg msg) {
  368 + ToServerRpcRequestMetadata data = toServerRpcPendingMap.remove(msg.getId());
  369 + if (data != null) {
  370 + logger.debug("[{}] Client side RPC request [{}] timeout detected!", deviceId, msg.getId());
  371 + ToDeviceMsg toDeviceMsg = new RuleEngineErrorMsg(SessionMsgType.TO_SERVER_RPC_REQUEST, RuleEngineError.TIMEOUT);
  372 + sendMsgToSessionActor(new BasicToDeviceSessionActorMsg(toDeviceMsg, data.getSessionId()), data.getServer());
  373 + }
  374 + }
  375 +
  376 + void processToServerRPCResponse(ActorContext context, ToServerRpcResponseActorMsg msg) {
  377 + ToServerRpcRequestMetadata data = toServerRpcPendingMap.remove(msg.getMsg().getRequestId());
  378 + if (data != null) {
  379 + sendMsgToSessionActor(new BasicToDeviceSessionActorMsg(msg.getMsg(), data.getSessionId()), data.getServer());
  380 + }
  381 + }
  382 +
348 private void pushToRuleEngineWithTimeout(ActorContext context, TbMsg tbMsg, DeviceToDeviceActorMsg src, FromDeviceRequestMsg fromDeviceRequestMsg) { 383 private void pushToRuleEngineWithTimeout(ActorContext context, TbMsg tbMsg, DeviceToDeviceActorMsg src, FromDeviceRequestMsg fromDeviceRequestMsg) {
  384 + pushToRuleEngineWithTimeout(context, tbMsg, src, fromDeviceRequestMsg, true);
  385 + }
  386 +
  387 + private void pushToRuleEngineWithTimeout(ActorContext context, TbMsg tbMsg, DeviceToDeviceActorMsg src, FromDeviceRequestMsg fromDeviceRequestMsg, boolean replyOnAck) {
349 SessionMsgType sessionMsgType = fromDeviceRequestMsg.getMsgType(); 388 SessionMsgType sessionMsgType = fromDeviceRequestMsg.getMsgType();
350 int requestId = fromDeviceRequestMsg.getRequestId(); 389 int requestId = fromDeviceRequestMsg.getRequestId();
351 if (systemContext.isQueuePersistenceEnabled()) { 390 if (systemContext.isQueuePersistenceEnabled()) {
352 - pendingMsgs.put(tbMsg.getId(), new PendingSessionMsgData(src.getSessionId(), src.getServerAddress(), sessionMsgType, requestId)); 391 + pendingMsgs.put(tbMsg.getId(), new PendingSessionMsgData(src.getSessionId(), src.getServerAddress(), sessionMsgType, requestId, replyOnAck));
353 scheduleMsgWithDelay(context, new DeviceActorQueueTimeoutMsg(tbMsg.getId(), systemContext.getQueuePersistenceTimeout()), systemContext.getQueuePersistenceTimeout()); 392 scheduleMsgWithDelay(context, new DeviceActorQueueTimeoutMsg(tbMsg.getId(), systemContext.getQueuePersistenceTimeout()), systemContext.getQueuePersistenceTimeout());
354 } else { 393 } else {
355 ToDeviceSessionActorMsg response = new BasicToDeviceSessionActorMsg(BasicStatusCodeResponse.onSuccess(sessionMsgType, requestId), src.getSessionId()); 394 ToDeviceSessionActorMsg response = new BasicToDeviceSessionActorMsg(BasicStatusCodeResponse.onSuccess(sessionMsgType, requestId), src.getSessionId());
@@ -394,7 +433,7 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso @@ -394,7 +433,7 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
394 if (inMsg.getMsgType() == SessionMsgType.TO_DEVICE_RPC_RESPONSE) { 433 if (inMsg.getMsgType() == SessionMsgType.TO_DEVICE_RPC_RESPONSE) {
395 logger.debug("[{}] Processing rpc command response [{}]", deviceId, sessionId); 434 logger.debug("[{}] Processing rpc command response [{}]", deviceId, sessionId);
396 ToDeviceRpcResponseMsg responseMsg = (ToDeviceRpcResponseMsg) inMsg; 435 ToDeviceRpcResponseMsg responseMsg = (ToDeviceRpcResponseMsg) inMsg;
397 - ToDeviceRpcRequestMetadata requestMd = rpcPendingMap.remove(responseMsg.getRequestId()); 436 + ToDeviceRpcRequestMetadata requestMd = toDeviceRpcPendingMap.remove(responseMsg.getRequestId());
398 boolean success = requestMd != null; 437 boolean success = requestMd != null;
399 if (success) { 438 if (success) {
400 systemContext.getDeviceRpcService().process(new FromDeviceRpcResponse(requestMd.getMsg().getMsg().getId(), responseMsg.getData(), null)); 439 systemContext.getDeviceRpcService().process(new FromDeviceRpcResponse(requestMd.getMsg().getMsg().getId(), responseMsg.getData(), null));
@@ -32,5 +32,6 @@ public final class PendingSessionMsgData { @@ -32,5 +32,6 @@ public final class PendingSessionMsgData {
32 private final Optional<ServerAddress> serverAddress; 32 private final Optional<ServerAddress> serverAddress;
33 private final SessionMsgType sessionMsgType; 33 private final SessionMsgType sessionMsgType;
34 private final int requestId; 34 private final int requestId;
  35 + private final boolean replyOnQueueAck;
35 36
36 } 37 }
@@ -16,13 +16,13 @@ @@ -16,13 +16,13 @@
16 package org.thingsboard.server.actors.device; 16 package org.thingsboard.server.actors.device;
17 17
18 import lombok.Data; 18 import lombok.Data;
19 -import org.thingsboard.server.service.rpc.ToDeviceRpcRequestMsg; 19 +import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg;
20 20
21 /** 21 /**
22 * @author Andrew Shvayka 22 * @author Andrew Shvayka
23 */ 23 */
24 @Data 24 @Data
25 public class ToDeviceRpcRequestMetadata { 25 public class ToDeviceRpcRequestMetadata {
26 - private final ToDeviceRpcRequestMsg msg; 26 + private final ToDeviceRpcRequestActorMsg msg;
27 private final boolean sent; 27 private final boolean sent;
28 } 28 }
  1 +/**
  2 + * Copyright © 2016-2018 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.actors.device;
  17 +
  18 +import lombok.Data;
  19 +import org.thingsboard.server.common.data.id.SessionId;
  20 +import org.thingsboard.server.common.msg.cluster.ServerAddress;
  21 +import org.thingsboard.server.common.msg.session.SessionType;
  22 +
  23 +import java.util.Optional;
  24 +
  25 +/**
  26 + * @author Andrew Shvayka
  27 + */
  28 +@Data
  29 +public class ToServerRpcRequestMetadata {
  30 + private final SessionId sessionId;
  31 + private final SessionType type;
  32 + private final Optional<ServerAddress> server;
  33 +}
@@ -37,7 +37,7 @@ import org.thingsboard.server.extensions.api.plugins.rpc.RpcMsg; @@ -37,7 +37,7 @@ import org.thingsboard.server.extensions.api.plugins.rpc.RpcMsg;
37 import org.thingsboard.server.gen.cluster.ClusterAPIProtos; 37 import org.thingsboard.server.gen.cluster.ClusterAPIProtos;
38 import org.thingsboard.server.service.cluster.rpc.GrpcSession; 38 import org.thingsboard.server.service.cluster.rpc.GrpcSession;
39 import org.thingsboard.server.service.cluster.rpc.GrpcSessionListener; 39 import org.thingsboard.server.service.cluster.rpc.GrpcSessionListener;
40 -import org.thingsboard.server.service.rpc.ToDeviceRpcRequestMsg; 40 +import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg;
41 41
42 import java.io.Serializable; 42 import java.io.Serializable;
43 import java.util.UUID; 43 import java.util.UUID;
@@ -142,14 +142,14 @@ public class BasicRpcSessionListener implements GrpcSessionListener { @@ -142,14 +142,14 @@ public class BasicRpcSessionListener implements GrpcSessionListener {
142 return new UUID(uid.getPluginUuidMsb(), uid.getPluginUuidLsb()); 142 return new UUID(uid.getPluginUuidMsb(), uid.getPluginUuidLsb());
143 } 143 }
144 144
145 - private static ToDeviceRpcRequestMsg deserialize(ServerAddress serverAddress, ClusterAPIProtos.ToDeviceRpcRequestRpcMessage msg) { 145 + private static ToDeviceRpcRequestActorMsg deserialize(ServerAddress serverAddress, ClusterAPIProtos.ToDeviceRpcRequestRpcMessage msg) {
146 TenantId deviceTenantId = new TenantId(toUUID(msg.getDeviceTenantId())); 146 TenantId deviceTenantId = new TenantId(toUUID(msg.getDeviceTenantId()));
147 DeviceId deviceId = new DeviceId(toUUID(msg.getDeviceId())); 147 DeviceId deviceId = new DeviceId(toUUID(msg.getDeviceId()));
148 148
149 ToDeviceRpcRequestBody requestBody = new ToDeviceRpcRequestBody(msg.getMethod(), msg.getParams()); 149 ToDeviceRpcRequestBody requestBody = new ToDeviceRpcRequestBody(msg.getMethod(), msg.getParams());
150 ToDeviceRpcRequest request = new ToDeviceRpcRequest(toUUID(msg.getMsgId()), deviceTenantId, deviceId, msg.getOneway(), msg.getExpTime(), requestBody); 150 ToDeviceRpcRequest request = new ToDeviceRpcRequest(toUUID(msg.getMsgId()), deviceTenantId, deviceId, msg.getOneway(), msg.getExpTime(), requestBody);
151 151
152 - return new ToDeviceRpcRequestMsg(serverAddress, request); 152 + return new ToDeviceRpcRequestActorMsg(serverAddress, request);
153 } 153 }
154 154
155 private static ToPluginRpcResponseDeviceMsg deserialize(ServerAddress serverAddress, ClusterAPIProtos.ToPluginRpcResponseRpcMessage msg) { 155 private static ToPluginRpcResponseDeviceMsg deserialize(ServerAddress serverAddress, ClusterAPIProtos.ToPluginRpcResponseRpcMessage msg) {
1 /** 1 /**
2 * Copyright © 2016-2018 The Thingsboard Authors 2 * Copyright © 2016-2018 The Thingsboard Authors
3 - * 3 + * <p>
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at 6 * You may obtain a copy of the License at
7 - *  
8 - * http://www.apache.org/licenses/LICENSE-2.0  
9 - * 7 + * <p>
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + * <p>
10 * Unless required by applicable law or agreed to in writing, software 10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, 11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -16,15 +16,20 @@ @@ -16,15 +16,20 @@
16 package org.thingsboard.server.actors.ruleChain; 16 package org.thingsboard.server.actors.ruleChain;
17 17
18 import akka.actor.ActorRef; 18 import akka.actor.ActorRef;
19 -import akka.actor.Cancellable; 19 +import com.datastax.driver.core.utils.UUIDs;
20 import com.google.common.base.Function; 20 import com.google.common.base.Function;
21 import org.thingsboard.rule.engine.api.*; 21 import org.thingsboard.rule.engine.api.*;
22 import org.thingsboard.server.actors.ActorSystemContext; 22 import org.thingsboard.server.actors.ActorSystemContext;
  23 +import org.thingsboard.server.common.data.id.DeviceId;
  24 +import org.thingsboard.server.common.data.id.EntityId;
23 import org.thingsboard.server.common.data.id.RuleNodeId; 25 import org.thingsboard.server.common.data.id.RuleNodeId;
24 import org.thingsboard.server.common.data.id.TenantId; 26 import org.thingsboard.server.common.data.id.TenantId;
  27 +import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody;
25 import org.thingsboard.server.common.data.rule.RuleNode; 28 import org.thingsboard.server.common.data.rule.RuleNode;
26 import org.thingsboard.server.common.msg.TbMsg; 29 import org.thingsboard.server.common.msg.TbMsg;
  30 +import org.thingsboard.server.common.msg.TbMsgMetaData;
27 import org.thingsboard.server.common.msg.cluster.ServerAddress; 31 import org.thingsboard.server.common.msg.cluster.ServerAddress;
  32 +import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest;
28 import org.thingsboard.server.dao.alarm.AlarmService; 33 import org.thingsboard.server.dao.alarm.AlarmService;
29 import org.thingsboard.server.dao.asset.AssetService; 34 import org.thingsboard.server.dao.asset.AssetService;
30 import org.thingsboard.server.dao.attributes.AttributesService; 35 import org.thingsboard.server.dao.attributes.AttributesService;
@@ -41,6 +46,7 @@ import scala.concurrent.duration.Duration; @@ -41,6 +46,7 @@ import scala.concurrent.duration.Duration;
41 import java.util.List; 46 import java.util.List;
42 import java.util.Set; 47 import java.util.Set;
43 import java.util.concurrent.TimeUnit; 48 import java.util.concurrent.TimeUnit;
  49 +import java.util.function.Consumer;
44 50
45 /** 51 /**
46 * Created by ashvayka on 19.03.18. 52 * Created by ashvayka on 19.03.18.
@@ -113,6 +119,11 @@ class DefaultTbContext implements TbContext { @@ -113,6 +119,11 @@ class DefaultTbContext implements TbContext {
113 } 119 }
114 120
115 @Override 121 @Override
  122 + public TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data) {
  123 + return new TbMsg(UUIDs.timeBased(), type, originator, metaData, data);
  124 + }
  125 +
  126 + @Override
116 public RuleNodeId getSelfId() { 127 public RuleNodeId getSelfId() {
117 return nodeCtx.getSelf().getId(); 128 return nodeCtx.getSelf().getId();
118 } 129 }
@@ -206,4 +217,29 @@ class DefaultTbContext implements TbContext { @@ -206,4 +217,29 @@ class DefaultTbContext implements TbContext {
206 public MailService getMailService() { 217 public MailService getMailService() {
207 return mainCtx.getMailService(); 218 return mainCtx.getMailService();
208 } 219 }
  220 +
  221 + @Override
  222 + public RuleEngineRpcService getRpcService() {
  223 + return new RuleEngineRpcService() {
  224 + @Override
  225 + public void sendRpcReply(DeviceId deviceId, int requestId, String body) {
  226 + mainCtx.getDeviceRpcService().sendRpcReplyToDevice(nodeCtx.getTenantId(), deviceId, requestId, body);
  227 + }
  228 +
  229 + @Override
  230 + public void sendRpcRequest(RuleEngineDeviceRpcRequest src, Consumer<RuleEngineDeviceRpcResponse> consumer) {
  231 + ToDeviceRpcRequest request = new ToDeviceRpcRequest(UUIDs.timeBased(), nodeCtx.getTenantId(), src.getDeviceId(),
  232 + src.isOneway(), System.currentTimeMillis() + src.getTimeout(), new ToDeviceRpcRequestBody(src.getMethod(), src.getBody()));
  233 + mainCtx.getDeviceRpcService().process(request, response -> {
  234 + consumer.accept(RuleEngineDeviceRpcResponse.builder()
  235 + .deviceId(src.getDeviceId())
  236 + .requestId(src.getRequestId())
  237 + .error(response.getError())
  238 + .response(response.getResponse())
  239 + .build());
  240 + });
  241 + }
  242 +
  243 + };
  244 + }
209 } 245 }
@@ -23,6 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired; @@ -23,6 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired;
23 import org.springframework.http.HttpStatus; 23 import org.springframework.http.HttpStatus;
24 import org.springframework.http.ResponseEntity; 24 import org.springframework.http.ResponseEntity;
25 import org.springframework.security.access.prepost.PreAuthorize; 25 import org.springframework.security.access.prepost.PreAuthorize;
  26 +import org.springframework.util.StringUtils;
26 import org.springframework.web.bind.annotation.PathVariable; 27 import org.springframework.web.bind.annotation.PathVariable;
27 import org.springframework.web.bind.annotation.RequestBody; 28 import org.springframework.web.bind.annotation.RequestBody;
28 import org.springframework.web.bind.annotation.RequestMapping; 29 import org.springframework.web.bind.annotation.RequestMapping;
@@ -30,18 +31,22 @@ import org.springframework.web.bind.annotation.RequestMethod; @@ -30,18 +31,22 @@ import org.springframework.web.bind.annotation.RequestMethod;
30 import org.springframework.web.bind.annotation.ResponseBody; 31 import org.springframework.web.bind.annotation.ResponseBody;
31 import org.springframework.web.bind.annotation.RestController; 32 import org.springframework.web.bind.annotation.RestController;
32 import org.springframework.web.context.request.async.DeferredResult; 33 import org.springframework.web.context.request.async.DeferredResult;
33 -import org.thingsboard.server.actors.plugin.ValidationResult; 34 +import org.thingsboard.server.common.data.audit.ActionType;
34 import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; 35 import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
35 import org.thingsboard.server.common.data.exception.ThingsboardException; 36 import org.thingsboard.server.common.data.exception.ThingsboardException;
36 import org.thingsboard.server.common.data.id.DeviceId; 37 import org.thingsboard.server.common.data.id.DeviceId;
  38 +import org.thingsboard.server.common.data.id.EntityId;
37 import org.thingsboard.server.common.data.id.TenantId; 39 import org.thingsboard.server.common.data.id.TenantId;
  40 +import org.thingsboard.server.common.data.id.UUIDBased;
  41 +import org.thingsboard.server.common.data.rpc.RpcRequest;
38 import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody; 42 import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody;
39 import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; 43 import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest;
40 import org.thingsboard.server.extensions.api.exception.ToErrorResponseEntity; 44 import org.thingsboard.server.extensions.api.exception.ToErrorResponseEntity;
41 import org.thingsboard.server.extensions.api.plugins.PluginConstants; 45 import org.thingsboard.server.extensions.api.plugins.PluginConstants;
42 -import org.thingsboard.server.common.data.rpc.RpcRequest;  
43 -import org.thingsboard.server.service.rpc.LocalRequestMetaData; 46 +import org.thingsboard.server.extensions.api.plugins.msg.FromDeviceRpcResponse;
  47 +import org.thingsboard.server.extensions.api.plugins.msg.RpcError;
44 import org.thingsboard.server.service.rpc.DeviceRpcService; 48 import org.thingsboard.server.service.rpc.DeviceRpcService;
  49 +import org.thingsboard.server.service.rpc.LocalRequestMetaData;
45 import org.thingsboard.server.service.security.AccessValidator; 50 import org.thingsboard.server.service.security.AccessValidator;
46 import org.thingsboard.server.service.security.model.SecurityUser; 51 import org.thingsboard.server.service.security.model.SecurityUser;
47 52
@@ -53,6 +58,7 @@ import java.util.Optional; @@ -53,6 +58,7 @@ import java.util.Optional;
53 import java.util.UUID; 58 import java.util.UUID;
54 import java.util.concurrent.ExecutorService; 59 import java.util.concurrent.ExecutorService;
55 import java.util.concurrent.Executors; 60 import java.util.concurrent.Executors;
  61 +import java.util.function.Consumer;
56 62
57 /** 63 /**
58 * Created by ashvayka on 22.03.18. 64 * Created by ashvayka on 22.03.18.
@@ -117,7 +123,6 @@ public class RpcController extends BaseController { @@ -117,7 +123,6 @@ public class RpcController extends BaseController {
117 accessValidator.validate(currentUser, deviceId, new HttpValidationCallback(response, new FutureCallback<DeferredResult<ResponseEntity>>() { 123 accessValidator.validate(currentUser, deviceId, new HttpValidationCallback(response, new FutureCallback<DeferredResult<ResponseEntity>>() {
118 @Override 124 @Override
119 public void onSuccess(@Nullable DeferredResult<ResponseEntity> result) { 125 public void onSuccess(@Nullable DeferredResult<ResponseEntity> result) {
120 -  
121 ToDeviceRpcRequest rpcRequest = new ToDeviceRpcRequest(UUID.randomUUID(), 126 ToDeviceRpcRequest rpcRequest = new ToDeviceRpcRequest(UUID.randomUUID(),
122 tenantId, 127 tenantId,
123 deviceId, 128 deviceId,
@@ -125,7 +130,13 @@ public class RpcController extends BaseController { @@ -125,7 +130,13 @@ public class RpcController extends BaseController {
125 timeout, 130 timeout,
126 body 131 body
127 ); 132 );
128 - deviceRpcService.process(rpcRequest, new LocalRequestMetaData(rpcRequest, currentUser, result)); 133 + deviceRpcService.process(rpcRequest, new Consumer<FromDeviceRpcResponse>(){
  134 +
  135 + @Override
  136 + public void accept(FromDeviceRpcResponse fromDeviceRpcResponse) {
  137 + reply(new LocalRequestMetaData(rpcRequest, currentUser, result), fromDeviceRpcResponse);
  138 + }
  139 + });
129 } 140 }
130 141
131 @Override 142 @Override
@@ -136,7 +147,7 @@ public class RpcController extends BaseController { @@ -136,7 +147,7 @@ public class RpcController extends BaseController {
136 } else { 147 } else {
137 entity = new ResponseEntity(HttpStatus.UNAUTHORIZED); 148 entity = new ResponseEntity(HttpStatus.UNAUTHORIZED);
138 } 149 }
139 - deviceRpcService.logRpcCall(currentUser, deviceId, body, oneWay, Optional.empty(), e); 150 + logRpcCall(currentUser, deviceId, body, oneWay, Optional.empty(), e);
140 response.setResult(entity); 151 response.setResult(entity);
141 } 152 }
142 })); 153 }));
@@ -146,4 +157,69 @@ public class RpcController extends BaseController { @@ -146,4 +157,69 @@ public class RpcController extends BaseController {
146 } 157 }
147 } 158 }
148 159
  160 + public void reply(LocalRequestMetaData rpcRequest, FromDeviceRpcResponse response) {
  161 + Optional<RpcError> rpcError = response.getError();
  162 + DeferredResult<ResponseEntity> responseWriter = rpcRequest.getResponseWriter();
  163 + if (rpcError.isPresent()) {
  164 + logRpcCall(rpcRequest, rpcError, null);
  165 + RpcError error = rpcError.get();
  166 + switch (error) {
  167 + case TIMEOUT:
  168 + responseWriter.setResult(new ResponseEntity<>(HttpStatus.REQUEST_TIMEOUT));
  169 + break;
  170 + case NO_ACTIVE_CONNECTION:
  171 + responseWriter.setResult(new ResponseEntity<>(HttpStatus.CONFLICT));
  172 + break;
  173 + default:
  174 + responseWriter.setResult(new ResponseEntity<>(HttpStatus.REQUEST_TIMEOUT));
  175 + break;
  176 + }
  177 + } else {
  178 + Optional<String> responseData = response.getResponse();
  179 + if (responseData.isPresent() && !StringUtils.isEmpty(responseData.get())) {
  180 + String data = responseData.get();
  181 + try {
  182 + logRpcCall(rpcRequest, rpcError, null);
  183 + responseWriter.setResult(new ResponseEntity<>(jsonMapper.readTree(data), HttpStatus.OK));
  184 + } catch (IOException e) {
  185 + log.debug("Failed to decode device response: {}", data, e);
  186 + logRpcCall(rpcRequest, rpcError, e);
  187 + responseWriter.setResult(new ResponseEntity<>(HttpStatus.NOT_ACCEPTABLE));
  188 + }
  189 + } else {
  190 + logRpcCall(rpcRequest, rpcError, null);
  191 + responseWriter.setResult(new ResponseEntity<>(HttpStatus.OK));
  192 + }
  193 + }
  194 + }
  195 +
  196 + private void logRpcCall(LocalRequestMetaData rpcRequest, Optional<RpcError> rpcError, Throwable e) {
  197 + logRpcCall(rpcRequest.getUser(), rpcRequest.getRequest().getDeviceId(), rpcRequest.getRequest().getBody(), rpcRequest.getRequest().isOneway(), rpcError, null);
  198 + }
  199 +
  200 +
  201 + private void logRpcCall(SecurityUser user, EntityId entityId, ToDeviceRpcRequestBody body, boolean oneWay, Optional<RpcError> rpcError, Throwable e) {
  202 + String rpcErrorStr = "";
  203 + if (rpcError.isPresent()) {
  204 + rpcErrorStr = "RPC Error: " + rpcError.get().name();
  205 + }
  206 + String method = body.getMethod();
  207 + String params = body.getParams();
  208 +
  209 + auditLogService.logEntityAction(
  210 + user.getTenantId(),
  211 + user.getCustomerId(),
  212 + user.getId(),
  213 + user.getName(),
  214 + (UUIDBased & EntityId) entityId,
  215 + null,
  216 + ActionType.RPC_CALL,
  217 + BaseController.toException(e),
  218 + rpcErrorStr,
  219 + oneWay,
  220 + method,
  221 + params);
  222 + }
  223 +
  224 +
149 } 225 }
@@ -40,7 +40,7 @@ import org.thingsboard.server.gen.cluster.ClusterAPIProtos; @@ -40,7 +40,7 @@ import org.thingsboard.server.gen.cluster.ClusterAPIProtos;
40 import org.thingsboard.server.gen.cluster.ClusterRpcServiceGrpc; 40 import org.thingsboard.server.gen.cluster.ClusterRpcServiceGrpc;
41 import org.thingsboard.server.service.cluster.discovery.ServerInstance; 41 import org.thingsboard.server.service.cluster.discovery.ServerInstance;
42 import org.thingsboard.server.service.cluster.discovery.ServerInstanceService; 42 import org.thingsboard.server.service.cluster.discovery.ServerInstanceService;
43 -import org.thingsboard.server.service.rpc.ToDeviceRpcRequestMsg; 43 +import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg;
44 44
45 import javax.annotation.PreDestroy; 45 import javax.annotation.PreDestroy;
46 import java.io.IOException; 46 import java.io.IOException;
@@ -132,7 +132,7 @@ public class ClusterGrpcService extends ClusterRpcServiceGrpc.ClusterRpcServiceI @@ -132,7 +132,7 @@ public class ClusterGrpcService extends ClusterRpcServiceGrpc.ClusterRpcServiceI
132 } 132 }
133 133
134 @Override 134 @Override
135 - public void tell(ServerAddress serverAddress, ToDeviceRpcRequestMsg toForward) { 135 + public void tell(ServerAddress serverAddress, ToDeviceRpcRequestActorMsg toForward) {
136 ClusterAPIProtos.ToRpcServerMessage msg = ClusterAPIProtos.ToRpcServerMessage.newBuilder() 136 ClusterAPIProtos.ToRpcServerMessage msg = ClusterAPIProtos.ToRpcServerMessage.newBuilder()
137 .setToDeviceRpcRequestRpcMsg(toProtoMsg(toForward)).build(); 137 .setToDeviceRpcRequestRpcMsg(toProtoMsg(toForward)).build();
138 tell(serverAddress, msg); 138 tell(serverAddress, msg);
@@ -196,7 +196,7 @@ public class ClusterGrpcService extends ClusterRpcServiceGrpc.ClusterRpcServiceI @@ -196,7 +196,7 @@ public class ClusterGrpcService extends ClusterRpcServiceGrpc.ClusterRpcServiceI
196 ).build(); 196 ).build();
197 } 197 }
198 198
199 - private static ClusterAPIProtos.ToDeviceRpcRequestRpcMessage toProtoMsg(ToDeviceRpcRequestMsg msg) { 199 + private static ClusterAPIProtos.ToDeviceRpcRequestRpcMessage toProtoMsg(ToDeviceRpcRequestActorMsg msg) {
200 ClusterAPIProtos.ToDeviceRpcRequestRpcMessage.Builder builder = ClusterAPIProtos.ToDeviceRpcRequestRpcMessage.newBuilder(); 200 ClusterAPIProtos.ToDeviceRpcRequestRpcMessage.Builder builder = ClusterAPIProtos.ToDeviceRpcRequestRpcMessage.newBuilder();
201 ToDeviceRpcRequest request = msg.getMsg(); 201 ToDeviceRpcRequest request = msg.getMsg();
202 202
@@ -24,7 +24,7 @@ import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg @@ -24,7 +24,7 @@ import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg
24 import org.thingsboard.server.extensions.api.plugins.msg.ToPluginRpcResponseDeviceMsg; 24 import org.thingsboard.server.extensions.api.plugins.msg.ToPluginRpcResponseDeviceMsg;
25 import org.thingsboard.server.extensions.api.plugins.rpc.PluginRpcMsg; 25 import org.thingsboard.server.extensions.api.plugins.rpc.PluginRpcMsg;
26 import org.thingsboard.server.gen.cluster.ClusterAPIProtos; 26 import org.thingsboard.server.gen.cluster.ClusterAPIProtos;
27 -import org.thingsboard.server.service.rpc.ToDeviceRpcRequestMsg; 27 +import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg;
28 28
29 import java.util.UUID; 29 import java.util.UUID;
30 30
@@ -41,7 +41,7 @@ public interface ClusterRpcService { @@ -41,7 +41,7 @@ public interface ClusterRpcService {
41 41
42 void tell(ServerAddress serverAddress, ToDeviceActorNotificationMsg toForward); 42 void tell(ServerAddress serverAddress, ToDeviceActorNotificationMsg toForward);
43 43
44 - void tell(ServerAddress serverAddress, ToDeviceRpcRequestMsg toForward); 44 + void tell(ServerAddress serverAddress, ToDeviceRpcRequestActorMsg toForward);
45 45
46 void tell(ServerAddress serverAddress, ToPluginRpcResponseDeviceMsg toForward); 46 void tell(ServerAddress serverAddress, ToPluginRpcResponseDeviceMsg toForward);
47 47
1 /** 1 /**
2 * Copyright © 2016-2018 The Thingsboard Authors 2 * Copyright © 2016-2018 The Thingsboard Authors
3 - * 3 + * <p>
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at 6 * You may obtain a copy of the License at
7 - *  
8 - * http://www.apache.org/licenses/LICENSE-2.0  
9 - * 7 + * <p>
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + * <p>
10 * Unless required by applicable law or agreed to in writing, software 10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, 11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -15,7 +15,6 @@ @@ -15,7 +15,6 @@
15 */ 15 */
16 package org.thingsboard.server.service.rpc; 16 package org.thingsboard.server.service.rpc;
17 17
18 -import akka.actor.ActorRef;  
19 import com.fasterxml.jackson.databind.ObjectMapper; 18 import com.fasterxml.jackson.databind.ObjectMapper;
20 import lombok.extern.slf4j.Slf4j; 19 import lombok.extern.slf4j.Slf4j;
21 import org.springframework.beans.factory.annotation.Autowired; 20 import org.springframework.beans.factory.annotation.Autowired;
@@ -28,12 +27,15 @@ import org.thingsboard.server.actors.service.ActorService; @@ -28,12 +27,15 @@ import org.thingsboard.server.actors.service.ActorService;
28 import org.thingsboard.server.common.data.audit.ActionType; 27 import org.thingsboard.server.common.data.audit.ActionType;
29 import org.thingsboard.server.common.data.id.DeviceId; 28 import org.thingsboard.server.common.data.id.DeviceId;
30 import org.thingsboard.server.common.data.id.EntityId; 29 import org.thingsboard.server.common.data.id.EntityId;
  30 +import org.thingsboard.server.common.data.id.TenantId;
31 import org.thingsboard.server.common.data.id.UUIDBased; 31 import org.thingsboard.server.common.data.id.UUIDBased;
32 import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody; 32 import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody;
33 import org.thingsboard.server.common.msg.cluster.ServerAddress; 33 import org.thingsboard.server.common.msg.cluster.ServerAddress;
  34 +import org.thingsboard.server.common.msg.core.ToServerRpcResponseMsg;
34 import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; 35 import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest;
35 import org.thingsboard.server.controller.BaseController; 36 import org.thingsboard.server.controller.BaseController;
36 import org.thingsboard.server.dao.audit.AuditLogService; 37 import org.thingsboard.server.dao.audit.AuditLogService;
  38 +import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg;
37 import org.thingsboard.server.extensions.api.plugins.msg.FromDeviceRpcResponse; 39 import org.thingsboard.server.extensions.api.plugins.msg.FromDeviceRpcResponse;
38 import org.thingsboard.server.extensions.api.plugins.msg.RpcError; 40 import org.thingsboard.server.extensions.api.plugins.msg.RpcError;
39 import org.thingsboard.server.service.cluster.routing.ClusterRoutingService; 41 import org.thingsboard.server.service.cluster.routing.ClusterRoutingService;
@@ -51,6 +53,7 @@ import java.util.concurrent.Executors; @@ -51,6 +53,7 @@ import java.util.concurrent.Executors;
51 import java.util.concurrent.ScheduledExecutorService; 53 import java.util.concurrent.ScheduledExecutorService;
52 import java.util.concurrent.TimeUnit; 54 import java.util.concurrent.TimeUnit;
53 import java.util.function.BiConsumer; 55 import java.util.function.BiConsumer;
  56 +import java.util.function.Consumer;
54 57
55 /** 58 /**
56 * Created by ashvayka on 27.03.18. 59 * Created by ashvayka on 27.03.18.
@@ -59,8 +62,6 @@ import java.util.function.BiConsumer; @@ -59,8 +62,6 @@ import java.util.function.BiConsumer;
59 @Slf4j 62 @Slf4j
60 public class DefaultDeviceRpcService implements DeviceRpcService { 63 public class DefaultDeviceRpcService implements DeviceRpcService {
61 64
62 - private static final ObjectMapper jsonMapper = new ObjectMapper();  
63 -  
64 @Autowired 65 @Autowired
65 private ClusterRoutingService routingService; 66 private ClusterRoutingService routingService;
66 67
@@ -75,7 +76,7 @@ public class DefaultDeviceRpcService implements DeviceRpcService { @@ -75,7 +76,7 @@ public class DefaultDeviceRpcService implements DeviceRpcService {
75 76
76 private ScheduledExecutorService rpcCallBackExecutor; 77 private ScheduledExecutorService rpcCallBackExecutor;
77 78
78 - private final ConcurrentMap<UUID, LocalRequestMetaData> localRpcRequests = new ConcurrentHashMap<>(); 79 + private final ConcurrentMap<UUID, Consumer<FromDeviceRpcResponse>> localRpcRequests = new ConcurrentHashMap<>();
79 80
80 81
81 @PostConstruct 82 @PostConstruct
@@ -91,18 +92,18 @@ public class DefaultDeviceRpcService implements DeviceRpcService { @@ -91,18 +92,18 @@ public class DefaultDeviceRpcService implements DeviceRpcService {
91 } 92 }
92 93
93 @Override 94 @Override
94 - public void process(ToDeviceRpcRequest request, LocalRequestMetaData metaData) { 95 + public void process(ToDeviceRpcRequest request, Consumer<FromDeviceRpcResponse> responseConsumer) {
95 log.trace("[{}] Processing local rpc call for device [{}]", request.getTenantId(), request.getDeviceId()); 96 log.trace("[{}] Processing local rpc call for device [{}]", request.getTenantId(), request.getDeviceId());
96 sendRpcRequest(request); 97 sendRpcRequest(request);
97 UUID requestId = request.getId(); 98 UUID requestId = request.getId();
98 - localRpcRequests.put(requestId, metaData); 99 + localRpcRequests.put(requestId, responseConsumer);
99 long timeout = Math.max(0, request.getExpirationTime() - System.currentTimeMillis()); 100 long timeout = Math.max(0, request.getExpirationTime() - System.currentTimeMillis());
100 log.error("[{}] processing the request: [{}]", this.hashCode(), requestId); 101 log.error("[{}] processing the request: [{}]", this.hashCode(), requestId);
101 rpcCallBackExecutor.schedule(() -> { 102 rpcCallBackExecutor.schedule(() -> {
102 log.error("[{}] timeout the request: [{}]", this.hashCode(), requestId); 103 log.error("[{}] timeout the request: [{}]", this.hashCode(), requestId);
103 - LocalRequestMetaData localMetaData = localRpcRequests.remove(requestId);  
104 - if (localMetaData != null) {  
105 - reply(localMetaData, new FromDeviceRpcResponse(requestId, null, RpcError.TIMEOUT)); 104 + Consumer<FromDeviceRpcResponse> consumer = localRpcRequests.remove(requestId);
  105 + if (consumer != null) {
  106 + consumer.accept(new FromDeviceRpcResponse(requestId, null, RpcError.TIMEOUT));
106 } 107 }
107 }, timeout, TimeUnit.MILLISECONDS); 108 }, timeout, TimeUnit.MILLISECONDS);
108 } 109 }
@@ -123,58 +124,27 @@ public class DefaultDeviceRpcService implements DeviceRpcService { @@ -123,58 +124,27 @@ public class DefaultDeviceRpcService implements DeviceRpcService {
123 log.error("[{}] response the request: [{}]", this.hashCode(), response.getId()); 124 log.error("[{}] response the request: [{}]", this.hashCode(), response.getId());
124 //TODO: send to another server if needed. 125 //TODO: send to another server if needed.
125 UUID requestId = response.getId(); 126 UUID requestId = response.getId();
126 - LocalRequestMetaData md = localRpcRequests.remove(requestId);  
127 - if (md != null) {  
128 - log.trace("[{}] Processing local rpc response from device [{}]", requestId, md.getRequest().getDeviceId());  
129 - reply(md, response); 127 + Consumer<FromDeviceRpcResponse> consumer = localRpcRequests.remove(requestId);
  128 + if (consumer != null) {
  129 + consumer.accept(response);
130 } else { 130 } else {
131 log.trace("[{}] Unknown or stale rpc response received [{}]", requestId, response); 131 log.trace("[{}] Unknown or stale rpc response received [{}]", requestId, response);
132 } 132 }
133 } 133 }
134 134
135 - public void reply(LocalRequestMetaData rpcRequest, FromDeviceRpcResponse response) {  
136 - Optional<RpcError> rpcError = response.getError();  
137 - DeferredResult<ResponseEntity> responseWriter = rpcRequest.getResponseWriter();  
138 - if (rpcError.isPresent()) {  
139 - logRpcCall(rpcRequest, rpcError, null);  
140 - RpcError error = rpcError.get();  
141 - switch (error) {  
142 - case TIMEOUT:  
143 - responseWriter.setResult(new ResponseEntity<>(HttpStatus.REQUEST_TIMEOUT));  
144 - break;  
145 - case NO_ACTIVE_CONNECTION:  
146 - responseWriter.setResult(new ResponseEntity<>(HttpStatus.CONFLICT));  
147 - break;  
148 - default:  
149 - responseWriter.setResult(new ResponseEntity<>(HttpStatus.REQUEST_TIMEOUT));  
150 - break;  
151 - }  
152 - } else {  
153 - Optional<String> responseData = response.getResponse();  
154 - if (responseData.isPresent() && !StringUtils.isEmpty(responseData.get())) {  
155 - String data = responseData.get();  
156 - try {  
157 - logRpcCall(rpcRequest, rpcError, null);  
158 - responseWriter.setResult(new ResponseEntity<>(jsonMapper.readTree(data), HttpStatus.OK));  
159 - } catch (IOException e) {  
160 - log.debug("Failed to decode device response: {}", data, e);  
161 - logRpcCall(rpcRequest, rpcError, e);  
162 - responseWriter.setResult(new ResponseEntity<>(HttpStatus.NOT_ACCEPTABLE));  
163 - }  
164 - } else {  
165 - logRpcCall(rpcRequest, rpcError, null);  
166 - responseWriter.setResult(new ResponseEntity<>(HttpStatus.OK));  
167 - }  
168 - } 135 + @Override
  136 + public void sendRpcReplyToDevice(TenantId tenantId, DeviceId deviceId, int requestId, String body) {
  137 + ToServerRpcResponseActorMsg rpcMsg = new ToServerRpcResponseActorMsg(tenantId, deviceId, new ToServerRpcResponseMsg(requestId, body));
  138 + forward(deviceId, rpcMsg, rpcService::tell);
169 } 139 }
170 140
171 private void sendRpcRequest(ToDeviceRpcRequest msg) { 141 private void sendRpcRequest(ToDeviceRpcRequest msg) {
172 log.trace("[{}] Forwarding msg {} to device actor!", msg.getDeviceId(), msg); 142 log.trace("[{}] Forwarding msg {} to device actor!", msg.getDeviceId(), msg);
173 - ToDeviceRpcRequestMsg rpcMsg = new ToDeviceRpcRequestMsg(msg); 143 + ToDeviceRpcRequestActorMsg rpcMsg = new ToDeviceRpcRequestActorMsg(msg);
174 forward(msg.getDeviceId(), rpcMsg, rpcService::tell); 144 forward(msg.getDeviceId(), rpcMsg, rpcService::tell);
175 } 145 }
176 146
177 - private void forward(DeviceId deviceId, ToDeviceRpcRequestMsg msg, BiConsumer<ServerAddress, ToDeviceRpcRequestMsg> rpcFunction) { 147 + private <T extends ToDeviceActorNotificationMsg> void forward(DeviceId deviceId, T msg, BiConsumer<ServerAddress, T> rpcFunction) {
178 Optional<ServerAddress> instance = routingService.resolveById(deviceId); 148 Optional<ServerAddress> instance = routingService.resolveById(deviceId);
179 if (instance.isPresent()) { 149 if (instance.isPresent()) {
180 log.trace("[{}] Forwarding msg {} to remote device actor!", msg.getTenantId(), msg); 150 log.trace("[{}] Forwarding msg {} to remote device actor!", msg.getTenantId(), msg);
@@ -184,32 +154,4 @@ public class DefaultDeviceRpcService implements DeviceRpcService { @@ -184,32 +154,4 @@ public class DefaultDeviceRpcService implements DeviceRpcService {
184 actorService.onMsg(msg); 154 actorService.onMsg(msg);
185 } 155 }
186 } 156 }
187 -  
188 - private void logRpcCall(LocalRequestMetaData rpcRequest, Optional<RpcError> rpcError, Throwable e) {  
189 - logRpcCall(rpcRequest.getUser(), rpcRequest.getRequest().getDeviceId(), rpcRequest.getRequest().getBody(), rpcRequest.getRequest().isOneway(), rpcError, null);  
190 - }  
191 -  
192 - @Override  
193 - public void logRpcCall(SecurityUser user, EntityId entityId, ToDeviceRpcRequestBody body, boolean oneWay, Optional<RpcError> rpcError, Throwable e) {  
194 - String rpcErrorStr = "";  
195 - if (rpcError.isPresent()) {  
196 - rpcErrorStr = "RPC Error: " + rpcError.get().name();  
197 - }  
198 - String method = body.getMethod();  
199 - String params = body.getParams();  
200 -  
201 - auditLogService.logEntityAction(  
202 - user.getTenantId(),  
203 - user.getCustomerId(),  
204 - user.getId(),  
205 - user.getName(),  
206 - (UUIDBased & EntityId) entityId,  
207 - null,  
208 - ActionType.RPC_CALL,  
209 - BaseController.toException(e),  
210 - rpcErrorStr,  
211 - oneWay,  
212 - method,  
213 - params);  
214 - }  
215 } 157 }
@@ -15,26 +15,25 @@ @@ -15,26 +15,25 @@
15 */ 15 */
16 package org.thingsboard.server.service.rpc; 16 package org.thingsboard.server.service.rpc;
17 17
18 -import org.thingsboard.server.common.data.id.EntityId;  
19 -import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody; 18 +import org.thingsboard.server.common.data.id.DeviceId;
  19 +import org.thingsboard.server.common.data.id.TenantId;
20 import org.thingsboard.server.common.msg.cluster.ServerAddress; 20 import org.thingsboard.server.common.msg.cluster.ServerAddress;
21 import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; 21 import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest;
22 import org.thingsboard.server.extensions.api.plugins.msg.FromDeviceRpcResponse; 22 import org.thingsboard.server.extensions.api.plugins.msg.FromDeviceRpcResponse;
23 -import org.thingsboard.server.extensions.api.plugins.msg.RpcError;  
24 -import org.thingsboard.server.service.security.model.SecurityUser;  
25 23
26 -import java.util.Optional; 24 +import java.util.function.Consumer;
27 25
28 /** 26 /**
29 * Created by ashvayka on 16.04.18. 27 * Created by ashvayka on 16.04.18.
30 */ 28 */
31 public interface DeviceRpcService { 29 public interface DeviceRpcService {
32 30
33 - void process(ToDeviceRpcRequest request, LocalRequestMetaData metaData); 31 + void process(ToDeviceRpcRequest request, Consumer<FromDeviceRpcResponse> responseConsumer);
34 32
35 void process(ToDeviceRpcRequest request, ServerAddress originator); 33 void process(ToDeviceRpcRequest request, ServerAddress originator);
36 34
37 void process(FromDeviceRpcResponse response); 35 void process(FromDeviceRpcResponse response);
38 36
39 - void logRpcCall(SecurityUser user, EntityId entityId, ToDeviceRpcRequestBody body, boolean oneWay, Optional<RpcError> rpcError, Throwable e); 37 + void sendRpcReplyToDevice(TenantId tenantId, DeviceId deviceId, int requestId, String body);
  38 +
40 } 39 }
application/src/main/java/org/thingsboard/server/service/rpc/ToDeviceRpcRequestActorMsg.java renamed from application/src/main/java/org/thingsboard/server/service/rpc/ToDeviceRpcRequestMsg.java
@@ -32,13 +32,13 @@ import java.util.Optional; @@ -32,13 +32,13 @@ import java.util.Optional;
32 */ 32 */
33 @ToString 33 @ToString
34 @RequiredArgsConstructor 34 @RequiredArgsConstructor
35 -public class ToDeviceRpcRequestMsg implements ToDeviceActorNotificationMsg { 35 +public class ToDeviceRpcRequestActorMsg implements ToDeviceActorNotificationMsg {
36 36
37 private final ServerAddress serverAddress; 37 private final ServerAddress serverAddress;
38 @Getter 38 @Getter
39 private final ToDeviceRpcRequest msg; 39 private final ToDeviceRpcRequest msg;
40 40
41 - public ToDeviceRpcRequestMsg(ToDeviceRpcRequest msg) { 41 + public ToDeviceRpcRequestActorMsg(ToDeviceRpcRequest msg) {
42 this(null, msg); 42 this(null, msg);
43 } 43 }
44 44
  1 +/**
  2 + * Copyright © 2016-2018 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.service.rpc;
  17 +
  18 +import lombok.Getter;
  19 +import lombok.RequiredArgsConstructor;
  20 +import lombok.ToString;
  21 +import org.thingsboard.server.common.data.id.DeviceId;
  22 +import org.thingsboard.server.common.data.id.TenantId;
  23 +import org.thingsboard.server.common.msg.MsgType;
  24 +import org.thingsboard.server.common.msg.cluster.ServerAddress;
  25 +import org.thingsboard.server.common.msg.core.ToServerRpcResponseMsg;
  26 +import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg;
  27 +
  28 +import java.util.Optional;
  29 +
  30 +/**
  31 + * Created by ashvayka on 16.04.18.
  32 + */
  33 +@ToString
  34 +@RequiredArgsConstructor
  35 +public class ToServerRpcResponseActorMsg implements ToDeviceActorNotificationMsg {
  36 +
  37 + private final ServerAddress serverAddress;
  38 +
  39 + @Getter
  40 + private final TenantId tenantId;
  41 +
  42 + @Getter
  43 + private final DeviceId deviceId;
  44 +
  45 + @Getter
  46 + private final ToServerRpcResponseMsg msg;
  47 +
  48 + public ToServerRpcResponseActorMsg(TenantId tenantId, DeviceId deviceId, ToServerRpcResponseMsg msg) {
  49 + this(null, tenantId, deviceId, msg);
  50 + }
  51 +
  52 + public Optional<ServerAddress> getServerAddress() {
  53 + return Optional.ofNullable(serverAddress);
  54 + }
  55 +
  56 + @Override
  57 + public MsgType getMsgType() {
  58 + return MsgType.SERVER_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG;
  59 + }
  60 +}
@@ -229,6 +229,8 @@ actors: @@ -229,6 +229,8 @@ actors:
229 enabled: "${ACTORS_QUEUE_ENABLED:true}" 229 enabled: "${ACTORS_QUEUE_ENABLED:true}"
230 # Maximum allowed timeout for persistence into the queue 230 # Maximum allowed timeout for persistence into the queue
231 timeout: "${ACTORS_QUEUE_PERSISTENCE_TIMEOUT:30000}" 231 timeout: "${ACTORS_QUEUE_PERSISTENCE_TIMEOUT:30000}"
  232 + client_side_rpc:
  233 + timeout: "${CLIENT_SIDE_RPC_TIMEOUT:60000}"
232 234
233 cache: 235 cache:
234 # caffeine or redis 236 # caffeine or redis
@@ -75,7 +75,11 @@ public enum MsgType { @@ -75,7 +75,11 @@ public enum MsgType {
75 75
76 DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG, 76 DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG,
77 77
78 - DEVICE_ACTOR_RPC_TIMEOUT_MSG, 78 + SERVER_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG,
  79 +
  80 + DEVICE_ACTOR_SERVER_SIDE_RPC_TIMEOUT_MSG,
  81 +
  82 + DEVICE_ACTOR_CLIENT_SIDE_RPC_TIMEOUT_MSG,
79 83
80 DEVICE_ACTOR_QUEUE_TIMEOUT_MSG, 84 DEVICE_ACTOR_QUEUE_TIMEOUT_MSG,
81 85
@@ -21,7 +21,7 @@ package org.thingsboard.server.common.msg.core; @@ -21,7 +21,7 @@ package org.thingsboard.server.common.msg.core;
21 21
22 public enum RuleEngineError { 22 public enum RuleEngineError {
23 23
24 - QUEUE_PUT_TIMEOUT(true), SERVER_ERROR(true); 24 + QUEUE_PUT_TIMEOUT(true), SERVER_ERROR(true), TIMEOUT;
25 25
26 private final boolean critical; 26 private final boolean critical;
27 27
@@ -44,6 +44,8 @@ public class RuleEngineErrorMsg implements ToDeviceMsg { @@ -44,6 +44,8 @@ public class RuleEngineErrorMsg implements ToDeviceMsg {
44 return "Timeout during persistence of the message to the queue!"; 44 return "Timeout during persistence of the message to the queue!";
45 case SERVER_ERROR: 45 case SERVER_ERROR:
46 return "Error during processing of message by the server!"; 46 return "Error during processing of message by the server!";
  47 + case TIMEOUT:
  48 + return "Timeout during processing of message by the server!";
47 default: 49 default:
48 throw new RuntimeException("Error " + error + " is not supported!"); 50 throw new RuntimeException("Error " + error + " is not supported!");
49 } 51 }
common/message/src/main/java/org/thingsboard/server/common/msg/timeout/DeviceActorClientSideRpcTimeoutMsg.java renamed from common/message/src/main/java/org/thingsboard/server/common/msg/timeout/DeviceActorRpcTimeoutMsg.java
@@ -20,14 +20,14 @@ import org.thingsboard.server.common.msg.MsgType; @@ -20,14 +20,14 @@ import org.thingsboard.server.common.msg.MsgType;
20 /** 20 /**
21 * @author Andrew Shvayka 21 * @author Andrew Shvayka
22 */ 22 */
23 -public final class DeviceActorRpcTimeoutMsg extends TimeoutMsg<Integer> { 23 +public final class DeviceActorClientSideRpcTimeoutMsg extends TimeoutMsg<Integer> {
24 24
25 - public DeviceActorRpcTimeoutMsg(Integer id, long timeout) { 25 + public DeviceActorClientSideRpcTimeoutMsg(Integer id, long timeout) {
26 super(id, timeout); 26 super(id, timeout);
27 } 27 }
28 28
29 @Override 29 @Override
30 public MsgType getMsgType() { 30 public MsgType getMsgType() {
31 - return MsgType.DEVICE_ACTOR_RPC_TIMEOUT_MSG; 31 + return MsgType.DEVICE_ACTOR_CLIENT_SIDE_RPC_TIMEOUT_MSG;
32 } 32 }
33 } 33 }
  1 +/**
  2 + * Copyright © 2016-2018 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.msg.timeout;
  17 +
  18 +import org.thingsboard.server.common.msg.MsgType;
  19 +
  20 +/**
  21 + * @author Andrew Shvayka
  22 + */
  23 +public final class DeviceActorServerSideRpcTimeoutMsg extends TimeoutMsg<Integer> {
  24 +
  25 + public DeviceActorServerSideRpcTimeoutMsg(Integer id, long timeout) {
  26 + super(id, timeout);
  27 + }
  28 +
  29 + @Override
  30 + public MsgType getMsgType() {
  31 + return MsgType.DEVICE_ACTOR_SERVER_SIDE_RPC_TIMEOUT_MSG;
  32 + }
  33 +}
  1 +/**
  2 + * Copyright © 2016-2018 The Thingsboard Authors
  3 + * <p>
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + * <p>
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + * <p>
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.rule.engine.api;
  17 +
  18 +import lombok.Builder;
  19 +import lombok.Data;
  20 +import org.thingsboard.server.common.data.id.DeviceId;
  21 +
  22 +/**
  23 + * Created by ashvayka on 02.04.18.
  24 + */
  25 +@Data
  26 +@Builder
  27 +public final class RuleEngineDeviceRpcRequest {
  28 +
  29 + private final DeviceId deviceId;
  30 + private final int requestId;
  31 + private final boolean oneway;
  32 + private final String method;
  33 + private final String body;
  34 + private final long timeout;
  35 +
  36 +}
  1 +/**
  2 + * Copyright © 2016-2018 The Thingsboard Authors
  3 + * <p>
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + * <p>
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + * <p>
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.rule.engine.api;
  17 +
  18 +import lombok.Builder;
  19 +import lombok.Data;
  20 +import org.thingsboard.server.common.data.id.DeviceId;
  21 +import org.thingsboard.server.extensions.api.plugins.msg.RpcError;
  22 +
  23 +import java.util.Optional;
  24 +
  25 +/**
  26 + * Created by ashvayka on 02.04.18.
  27 + */
  28 +@Data
  29 +@Builder
  30 +public final class RuleEngineDeviceRpcResponse {
  31 +
  32 + private final DeviceId deviceId;
  33 + private final int requestId;
  34 + private final Optional<String> response;
  35 + private final Optional<RpcError> error;
  36 +
  37 +}
  1 +/**
  2 + * Copyright © 2016-2018 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.rule.engine.api;
  17 +
  18 +import org.thingsboard.server.common.data.id.DeviceId;
  19 +import java.util.function.Consumer;
  20 +
  21 +/**
  22 + * Created by ashvayka on 02.04.18.
  23 + */
  24 +public interface RuleEngineRpcService {
  25 +
  26 + void sendRpcReply(DeviceId deviceId, int requestId, String body);
  27 +
  28 + void sendRpcRequest(RuleEngineDeviceRpcRequest request, Consumer<RuleEngineDeviceRpcResponse> consumer);
  29 +
  30 +}
@@ -15,10 +15,12 @@ @@ -15,10 +15,12 @@
15 */ 15 */
16 package org.thingsboard.rule.engine.api; 16 package org.thingsboard.rule.engine.api;
17 17
  18 +import org.thingsboard.server.common.data.id.EntityId;
18 import org.thingsboard.server.common.data.id.RuleNodeId; 19 import org.thingsboard.server.common.data.id.RuleNodeId;
19 import org.thingsboard.server.common.data.id.TenantId; 20 import org.thingsboard.server.common.data.id.TenantId;
20 import org.thingsboard.server.common.data.rule.RuleNode; 21 import org.thingsboard.server.common.data.rule.RuleNode;
21 import org.thingsboard.server.common.msg.TbMsg; 22 import org.thingsboard.server.common.msg.TbMsg;
  23 +import org.thingsboard.server.common.msg.TbMsgMetaData;
22 import org.thingsboard.server.common.msg.cluster.ServerAddress; 24 import org.thingsboard.server.common.msg.cluster.ServerAddress;
23 import org.thingsboard.server.dao.alarm.AlarmService; 25 import org.thingsboard.server.dao.alarm.AlarmService;
24 import org.thingsboard.server.dao.asset.AssetService; 26 import org.thingsboard.server.dao.asset.AssetService;
@@ -58,6 +60,8 @@ public interface TbContext { @@ -58,6 +60,8 @@ public interface TbContext {
58 60
59 void updateSelf(RuleNode self); 61 void updateSelf(RuleNode self);
60 62
  63 + TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data);
  64 +
61 RuleNodeId getSelfId(); 65 RuleNodeId getSelfId();
62 66
63 TenantId getTenantId(); 67 TenantId getTenantId();
@@ -78,6 +82,8 @@ public interface TbContext { @@ -78,6 +82,8 @@ public interface TbContext {
78 82
79 RuleChainService getRuleChainService(); 83 RuleChainService getRuleChainService();
80 84
  85 + RuleEngineRpcService getRpcService();
  86 +
81 RuleEngineTelemetryService getTelemetryService(); 87 RuleEngineTelemetryService getTelemetryService();
82 88
83 TimeseriesService getTimeseriesService(); 89 TimeseriesService getTimeseriesService();
  1 +/**
  2 + * Copyright © 2016-2018 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.rule.engine.api;
  17 +
  18 +/**
  19 + * Created by ashvayka on 19.01.18.
  20 + */
  21 +public final class TbRelationTypes {
  22 +
  23 + public static String SUCCESS = "Success";
  24 + public static String FAILURE = "Failure";
  25 +
  26 +}
  1 +/**
  2 + * Copyright © 2016-2018 The Thingsboard Authors
  3 + * <p>
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + * <p>
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + * <p>
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.rule.engine.rpc;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.springframework.util.StringUtils;
  20 +import org.thingsboard.rule.engine.TbNodeUtils;
  21 +import org.thingsboard.rule.engine.api.RuleNode;
  22 +import org.thingsboard.rule.engine.api.TbContext;
  23 +import org.thingsboard.rule.engine.api.TbNode;
  24 +import org.thingsboard.rule.engine.api.TbNodeConfiguration;
  25 +import org.thingsboard.rule.engine.api.TbNodeException;
  26 +import org.thingsboard.server.common.data.EntityType;
  27 +import org.thingsboard.server.common.data.id.DeviceId;
  28 +import org.thingsboard.server.common.data.plugin.ComponentType;
  29 +import org.thingsboard.server.common.msg.TbMsg;
  30 +
  31 +@Slf4j
  32 +@RuleNode(
  33 + type = ComponentType.ACTION,
  34 + name = "rpc call reply",
  35 + configClazz = TbSendRpcReplyNodeConfiguration.class,
  36 + nodeDescription = "Sends reply to the RPC call from device",
  37 + nodeDetails = "Expects messages with any message type. Will forward message body to the device."
  38 +)
  39 +public class TbSendRPCReplyNode implements TbNode {
  40 +
  41 + private TbSendRpcReplyNodeConfiguration config;
  42 +
  43 + @Override
  44 + public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
  45 + this.config = TbNodeUtils.convert(configuration, TbSendRpcReplyNodeConfiguration.class);
  46 + }
  47 +
  48 + @Override
  49 + public void onMsg(TbContext ctx, TbMsg msg) {
  50 + String requestIdStr = msg.getMetaData().getValue(config.getRequestIdMetaDataAttribute());
  51 + if (msg.getOriginator().getEntityType() != EntityType.DEVICE) {
  52 + ctx.tellError(msg, new RuntimeException("Message originator is not a device entity!"));
  53 + } else if (StringUtils.isEmpty(requestIdStr)) {
  54 + ctx.tellError(msg, new RuntimeException("Request id is not present in the metadata!"));
  55 + } else if (StringUtils.isEmpty(msg.getData())) {
  56 + ctx.tellError(msg, new RuntimeException("Request body is empty!"));
  57 + } else {
  58 + ctx.getRpcService().sendRpcReply(new DeviceId(msg.getOriginator().getId()), Integer.parseInt(requestIdStr), msg.getData());
  59 + }
  60 + }
  61 +
  62 + @Override
  63 + public void destroy() {
  64 + }
  65 +
  66 +}
  1 +/**
  2 + * Copyright © 2016-2018 The Thingsboard Authors
  3 + * <p>
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + * <p>
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + * <p>
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.rule.engine.rpc;
  17 +
  18 +import com.google.gson.Gson;
  19 +import com.google.gson.JsonObject;
  20 +import com.google.gson.JsonParser;
  21 +import lombok.extern.slf4j.Slf4j;
  22 +import org.thingsboard.rule.engine.TbNodeUtils;
  23 +import org.thingsboard.rule.engine.api.RuleEngineDeviceRpcRequest;
  24 +import org.thingsboard.rule.engine.api.RuleNode;
  25 +import org.thingsboard.rule.engine.api.TbContext;
  26 +import org.thingsboard.rule.engine.api.TbNode;
  27 +import org.thingsboard.rule.engine.api.TbNodeConfiguration;
  28 +import org.thingsboard.rule.engine.api.TbNodeException;
  29 +import org.thingsboard.rule.engine.api.TbRelationTypes;
  30 +import org.thingsboard.server.common.data.EntityType;
  31 +import org.thingsboard.server.common.data.id.DeviceId;
  32 +import org.thingsboard.server.common.data.plugin.ComponentType;
  33 +import org.thingsboard.server.common.msg.TbMsg;
  34 +
  35 +import java.util.Random;
  36 +import java.util.concurrent.TimeUnit;
  37 +
  38 +@Slf4j
  39 +@RuleNode(
  40 + type = ComponentType.ACTION,
  41 + name = "rpc call request",
  42 + configClazz = TbSendRpcReplyNodeConfiguration.class,
  43 + nodeDescription = "Sends one-way RPC call to device",
  44 + nodeDetails = "Expects messages with \"method\" and \"params\". Will forward response from device to next nodes."
  45 +)
  46 +public class TbSendRPCRequestNode implements TbNode {
  47 +
  48 + private Random random = new Random();
  49 + private Gson gson = new Gson();
  50 + private JsonParser jsonParser = new JsonParser();
  51 + private TbSendRpcRequestNodeConfiguration config;
  52 +
  53 + @Override
  54 + public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
  55 + this.config = TbNodeUtils.convert(configuration, TbSendRpcRequestNodeConfiguration.class);
  56 + }
  57 +
  58 + @Override
  59 + public void onMsg(TbContext ctx, TbMsg msg) {
  60 + JsonObject json = jsonParser.parse(msg.getData()).getAsJsonObject();
  61 +
  62 + if (msg.getOriginator().getEntityType() != EntityType.DEVICE) {
  63 + ctx.tellError(msg, new RuntimeException("Message originator is not a device entity!"));
  64 + } else if (!json.has("method")) {
  65 + ctx.tellError(msg, new RuntimeException("Method is not present in the message!"));
  66 + } else if (!json.has("params")) {
  67 + ctx.tellError(msg, new RuntimeException("Params are not present in the message!"));
  68 + } else {
  69 + int requestId = json.has("requestId") ? json.get("requestId").getAsInt() : random.nextInt();
  70 + RuleEngineDeviceRpcRequest request = RuleEngineDeviceRpcRequest.builder()
  71 + .method(gson.toJson(json.get("method")))
  72 + .body(gson.toJson(json.get("params")))
  73 + .deviceId(new DeviceId(msg.getOriginator().getId()))
  74 + .requestId(requestId)
  75 + .timeout(TimeUnit.SECONDS.toMillis(config.getTimeoutInSeconds()))
  76 + .build();
  77 +
  78 + ctx.getRpcService().sendRpcRequest(request, ruleEngineDeviceRpcResponse -> {
  79 + if (!ruleEngineDeviceRpcResponse.getError().isPresent()) {
  80 + TbMsg next = ctx.newMsg(msg.getType(), msg.getOriginator(), msg.getMetaData(), ruleEngineDeviceRpcResponse.getResponse().get());
  81 + ctx.tellNext(next, TbRelationTypes.SUCCESS);
  82 + } else {
  83 + TbMsg next = ctx.newMsg(msg.getType(), msg.getOriginator(), msg.getMetaData(), wrap("error", ruleEngineDeviceRpcResponse.getError().get().name()));
  84 + ctx.tellNext(next, TbRelationTypes.FAILURE);
  85 + ctx.tellError(msg, new RuntimeException(ruleEngineDeviceRpcResponse.getError().get().name()));
  86 + }
  87 + });
  88 + }
  89 + }
  90 +
  91 + @Override
  92 + public void destroy() {
  93 + }
  94 +
  95 + private String wrap(String name, String body) {
  96 + JsonObject json = new JsonObject();
  97 + json.addProperty(name, body);
  98 + return gson.toJson(json);
  99 + }
  100 +
  101 +}
  1 +/**
  2 + * Copyright © 2016-2018 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.rule.engine.rpc;
  17 +
  18 +import lombok.Data;
  19 +import org.thingsboard.rule.engine.api.NodeConfiguration;
  20 +import org.thingsboard.server.common.data.DataConstants;
  21 +
  22 +@Data
  23 +public class TbSendRpcReplyNodeConfiguration implements NodeConfiguration<TbSendRpcReplyNodeConfiguration> {
  24 +
  25 + private String requestIdMetaDataAttribute;
  26 +
  27 + @Override
  28 + public TbSendRpcReplyNodeConfiguration defaultConfiguration() {
  29 + TbSendRpcReplyNodeConfiguration configuration = new TbSendRpcReplyNodeConfiguration();
  30 + configuration.setRequestIdMetaDataAttribute("requestId");
  31 + return configuration;
  32 + }
  33 +}
  1 +/**
  2 + * Copyright © 2016-2018 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.rule.engine.rpc;
  17 +
  18 +import lombok.Data;
  19 +import org.thingsboard.rule.engine.api.NodeConfiguration;
  20 +
  21 +@Data
  22 +public class TbSendRpcRequestNodeConfiguration implements NodeConfiguration<TbSendRpcRequestNodeConfiguration> {
  23 +
  24 + private int timeoutInSeconds;
  25 +
  26 + @Override
  27 + public TbSendRpcRequestNodeConfiguration defaultConfiguration() {
  28 + TbSendRpcRequestNodeConfiguration configuration = new TbSendRpcRequestNodeConfiguration();
  29 + configuration.setTimeoutInSeconds(60);
  30 + return configuration;
  31 + }
  32 +}