Commit 950ec8d622cd5c0c851de63f715959e1a3a4e168

Authored by Andrew Shvayka
1 parent 5a80d755

MQTT API implementation

1 1 /**
2 2 * Copyright © 2016-2018 The Thingsboard Authors
3   - * <p>
  3 + *
4 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 5 * you may not use this file except in compliance with the License.
6 6 * You may obtain a copy of the License at
7   - * <p>
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - * <p>
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
10 10 * Unless required by applicable law or agreed to in writing, software
11 11 * distributed under the License is distributed on an "AS IS" BASIS,
12 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
... ... @@ -32,7 +32,6 @@ import org.thingsboard.server.actors.shared.AbstractContextAwareMsgProcessor;
32 32 import org.thingsboard.server.common.data.DataConstants;
33 33 import org.thingsboard.server.common.data.Device;
34 34 import org.thingsboard.server.common.data.id.DeviceId;
35   -import org.thingsboard.server.common.data.id.SessionId;
36 35 import org.thingsboard.server.common.data.id.TenantId;
37 36 import org.thingsboard.server.common.data.kv.AttributeKey;
38 37 import org.thingsboard.server.common.data.kv.AttributeKvEntry;
... ... @@ -44,18 +43,33 @@ import org.thingsboard.server.common.msg.TbMsgMetaData;
44 43 import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
45 44 import org.thingsboard.server.common.msg.cluster.ServerAddress;
46 45 import org.thingsboard.server.common.msg.core.ActorSystemToDeviceSessionActorMsg;
47   -import org.thingsboard.server.common.msg.core.AttributesUpdateNotification;
48 46 import org.thingsboard.server.common.msg.core.RuleEngineError;
49 47 import org.thingsboard.server.common.msg.core.RuleEngineErrorMsg;
50   -import org.thingsboard.server.common.msg.core.ToDeviceRpcRequestMsg;
51   -import org.thingsboard.server.common.msg.kv.BasicAttributeKVMsg;
52 48 import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest;
53 49 import org.thingsboard.server.common.msg.session.SessionMsgType;
54   -import org.thingsboard.server.common.msg.session.SessionType;
55 50 import org.thingsboard.server.common.msg.session.ToDeviceMsg;
56 51 import org.thingsboard.server.common.msg.timeout.DeviceActorClientSideRpcTimeoutMsg;
57 52 import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg;
58 53 import org.thingsboard.server.gen.transport.TransportProtos;
  54 +import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg;
  55 +import org.thingsboard.server.gen.transport.TransportProtos.DeviceActorToTransportMsg;
  56 +import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg;
  57 +import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg;
  58 +import org.thingsboard.server.gen.transport.TransportProtos.KeyValueProto;
  59 +import org.thingsboard.server.gen.transport.TransportProtos.KeyValueType;
  60 +import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg;
  61 +import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg;
  62 +import org.thingsboard.server.gen.transport.TransportProtos.SessionCloseNotificationProto;
  63 +import org.thingsboard.server.gen.transport.TransportProtos.SessionEvent;
  64 +import org.thingsboard.server.gen.transport.TransportProtos.SessionEventMsg;
  65 +import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
  66 +import org.thingsboard.server.gen.transport.TransportProtos.SubscribeToAttributeUpdatesMsg;
  67 +import org.thingsboard.server.gen.transport.TransportProtos.SubscribeToRPCMsg;
  68 +import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcRequestMsg;
  69 +import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcResponseMsg;
  70 +import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg;
  71 +import org.thingsboard.server.gen.transport.TransportProtos.TsKvListProto;
  72 +import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto;
59 73 import org.thingsboard.server.service.rpc.FromDeviceRpcResponse;
60 74 import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg;
61 75 import org.thingsboard.server.service.rpc.ToServerRpcResponseActorMsg;
... ... @@ -76,8 +90,6 @@ import java.util.UUID;
76 90 import java.util.function.Consumer;
77 91 import java.util.stream.Collectors;
78 92
79   -import org.thingsboard.server.gen.transport.TransportProtos.*;
80   -
81 93 /**
82 94 * @author Andrew Shvayka
83 95 */
... ... @@ -123,11 +135,8 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
123 135 void processRpcRequest(ActorContext context, ToDeviceRpcRequestActorMsg msg) {
124 136 ToDeviceRpcRequest request = msg.getMsg();
125 137 ToDeviceRpcRequestBody body = request.getBody();
126   - ToDeviceRpcRequestMsg rpcRequest = new ToDeviceRpcRequestMsg(
127   - rpcSeq++,
128   - body.getMethod(),
129   - body.getParams()
130   - );
  138 + ToDeviceRpcRequestMsg rpcRequest = ToDeviceRpcRequestMsg.newBuilder().setRequestId(
  139 + rpcSeq++).setMethodName(body.getMethod()).setParams(body.getParams()).build();
131 140
132 141 long timeout = request.getExpirationTime() - System.currentTimeMillis();
133 142 if (timeout <= 0) {
... ... @@ -136,13 +145,12 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
136 145 }
137 146
138 147 boolean sent = rpcSubscriptions.size() > 0;
139   - Set<SessionId> syncSessionSet = new HashSet<>();
  148 + Set<UUID> syncSessionSet = new HashSet<>();
140 149 rpcSubscriptions.entrySet().forEach(sub -> {
141   -// ActorSystemToDeviceSessionActorMsg response = new BasicActorSystemToDeviceSessionActorMsg(rpcRequest, sub.getKey());
142   -// sendMsgToSessionActor(response, sub.getValue().getServer());
143   -// if (SessionType.SYNC == sub.getValue().getType()) {
144   -// syncSessionSet.add(sub.getKey());
145   -// }
  150 + sendToTransport(rpcRequest, sub.getKey(), sub.getValue().getNodeId());
  151 + if (TransportProtos.SessionType.SYNC == sub.getValue().getType()) {
  152 + syncSessionSet.add(sub.getKey());
  153 + }
146 154 });
147 155 syncSessionSet.forEach(rpcSubscriptions::remove);
148 156
... ... @@ -175,10 +183,11 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
175 183 }
176 184 }
177 185
178   - private void sendPendingRequests(ActorContext context, SessionId sessionId, SessionType type, Optional<ServerAddress> server) {
  186 + private void sendPendingRequests(ActorContext context, UUID sessionId, SessionInfoProto sessionInfo) {
  187 + TransportProtos.SessionType sessionType = getSessionType(sessionId);
179 188 if (!toDeviceRpcPendingMap.isEmpty()) {
180 189 logger.debug("[{}] Pushing {} pending RPC messages to new async session [{}]", deviceId, toDeviceRpcPendingMap.size(), sessionId);
181   - if (type == SessionType.SYNC) {
  190 + if (sessionType == TransportProtos.SessionType.SYNC) {
182 191 logger.debug("[{}] Cleanup sync rpc session [{}]", deviceId, sessionId);
183 192 rpcSubscriptions.remove(sessionId);
184 193 }
... ... @@ -186,16 +195,16 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
186 195 logger.debug("[{}] No pending RPC messages for new async session [{}]", deviceId, sessionId);
187 196 }
188 197 Set<Integer> sentOneWayIds = new HashSet<>();
189   - if (type == SessionType.ASYNC) {
190   - toDeviceRpcPendingMap.entrySet().forEach(processPendingRpc(context, sessionId, server, sentOneWayIds));
  198 + if (sessionType == TransportProtos.SessionType.ASYNC) {
  199 + toDeviceRpcPendingMap.entrySet().forEach(processPendingRpc(context, sessionId, sessionInfo.getNodeId(), sentOneWayIds));
191 200 } else {
192   - toDeviceRpcPendingMap.entrySet().stream().findFirst().ifPresent(processPendingRpc(context, sessionId, server, sentOneWayIds));
  201 + toDeviceRpcPendingMap.entrySet().stream().findFirst().ifPresent(processPendingRpc(context, sessionId, sessionInfo.getNodeId(), sentOneWayIds));
193 202 }
194 203
195 204 sentOneWayIds.forEach(toDeviceRpcPendingMap::remove);
196 205 }
197 206
198   - private Consumer<Map.Entry<Integer, ToDeviceRpcRequestMetadata>> processPendingRpc(ActorContext context, SessionId sessionId, Optional<ServerAddress> server, Set<Integer> sentOneWayIds) {
  207 + private Consumer<Map.Entry<Integer, ToDeviceRpcRequestMetadata>> processPendingRpc(ActorContext context, UUID sessionId, String nodeId, Set<Integer> sentOneWayIds) {
199 208 return entry -> {
200 209 ToDeviceRpcRequestActorMsg requestActorMsg = entry.getValue().getMsg();
201 210 ToDeviceRpcRequest request = entry.getValue().getMsg().getMsg();
... ... @@ -204,19 +213,14 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
204 213 sentOneWayIds.add(entry.getKey());
205 214 systemContext.getDeviceRpcService().processRpcResponseFromDevice(new FromDeviceRpcResponse(request.getId(), requestActorMsg.getServerAddress(), null, null));
206 215 }
207   - ToDeviceRpcRequestMsg rpcRequest = new ToDeviceRpcRequestMsg(
208   - entry.getKey(),
209   - body.getMethod(),
210   - body.getParams()
211   - );
212   -// ActorSystemToDeviceSessionActorMsg response = new BasicActorSystemToDeviceSessionActorMsg(rpcRequest, sessionId);
213   -// sendMsgToSessionActor(response, server);
  216 + ToDeviceRpcRequestMsg rpcRequest = ToDeviceRpcRequestMsg.newBuilder().setRequestId(
  217 + entry.getKey()).setMethodName(body.getMethod()).setParams(body.getParams()).build();
  218 + sendToTransport(rpcRequest, sessionId, nodeId);
214 219 };
215 220 }
216 221
217 222 void process(ActorContext context, TransportToDeviceActorMsgWrapper wrapper) {
218 223 TransportToDeviceActorMsg msg = wrapper.getMsg();
219   -// processRpcResponses(context, msg);
220 224 if (msg.hasSessionEvent()) {
221 225 processSessionStateMsgs(msg.getSessionInfo(), msg.getSessionEvent());
222 226 }
... ... @@ -237,15 +241,13 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
237 241 if (msg.hasGetAttributes()) {
238 242 handleGetAttributesRequest(context, msg.getSessionInfo(), msg.getGetAttributes());
239 243 }
240   -// SessionMsgType sessionMsgType = msg.getPayload().getMsgType();
241   -// if (sessionMsgType.requiresRulesProcessing()) {
242   -// switch (sessionMsgType) {
243   -// case TO_SERVER_RPC_REQUEST:
244   -// handleClientSideRPCRequest(context, msg);
245   -// reportActivity();
246   -// break;
247   -// }
248   -// }
  244 + if (msg.hasToDeviceRPCCallResponse()) {
  245 + processRpcResponses(context, msg.getSessionInfo(), msg.getToDeviceRPCCallResponse());
  246 + }
  247 + if (msg.hasToServerRPCCallRequest()) {
  248 + handleClientSideRPCRequest(context, msg.getSessionInfo(), msg.getToServerRPCCallRequest());
  249 + reportActivity();
  250 + }
249 251 }
250 252
251 253 private void reportActivity() {
... ... @@ -314,36 +316,42 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
314 316 }
315 317 }
316 318
317   -// private void handleClientSideRPCRequest(ActorContext context, DeviceToDeviceActorMsg src) {
318   -// ToServerRpcRequestMsg request = (ToServerRpcRequestMsg) src.getPayload();
319   -//
320   -// JsonObject json = new JsonObject();
321   -// json.addProperty("method", request.getMethod());
322   -// json.add("params", jsonParser.parse(request.getParams()));
323   -//
324   -// TbMsgMetaData requestMetaData = defaultMetaData.copy();
325   -// requestMetaData.putValue("requestId", Integer.toString(request.getRequestId()));
326   -// TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.TO_SERVER_RPC_REQUEST.name(), deviceId, requestMetaData, TbMsgDataType.JSON, gson.toJson(json), null, null, 0L);
327   -// PendingSessionMsgData msgData = new PendingSessionMsgData(src.getSessionId(), src.getServerAddress(), SessionMsgType.TO_SERVER_RPC_REQUEST, request.getRequestId(), false, 1);
328   -// pushToRuleEngineWithTimeout(context, tbMsg, msgData);
329   -//
330   -// scheduleMsgWithDelay(context, new DeviceActorClientSideRpcTimeoutMsg(request.getRequestId(), systemContext.getClientSideRpcTimeout()), systemContext.getClientSideRpcTimeout());
331   -// toServerRpcPendingMap.put(request.getRequestId(), new ToServerRpcRequestMetadata(src.getSessionId(), src.getSessionType(), src.getServerAddress()));
332   -// }
  319 + private void handleClientSideRPCRequest(ActorContext context, SessionInfoProto sessionInfo, TransportProtos.ToServerRpcRequestMsg request) {
  320 + UUID sessionId = getSessionId(sessionInfo);
  321 + JsonObject json = new JsonObject();
  322 + json.addProperty("method", request.getMethodName());
  323 + json.add("params", jsonParser.parse(request.getParams()));
  324 +
  325 + TbMsgMetaData requestMetaData = defaultMetaData.copy();
  326 + requestMetaData.putValue("requestId", Integer.toString(request.getRequestId()));
  327 + TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.TO_SERVER_RPC_REQUEST.name(), deviceId, requestMetaData, TbMsgDataType.JSON, gson.toJson(json), null, null, 0L);
  328 + context.parent().tell(new DeviceActorToRuleEngineMsg(context.self(), tbMsg), context.self());
  329 +
  330 + scheduleMsgWithDelay(context, new DeviceActorClientSideRpcTimeoutMsg(request.getRequestId(), systemContext.getClientSideRpcTimeout()), systemContext.getClientSideRpcTimeout());
  331 + toServerRpcPendingMap.put(request.getRequestId(), new ToServerRpcRequestMetadata(sessionId, getSessionType(sessionId), sessionInfo.getNodeId()));
  332 + }
333 333
334   - public void processClientSideRpcTimeout(ActorContext context, DeviceActorClientSideRpcTimeoutMsg msg) {
  334 + private TransportProtos.SessionType getSessionType(UUID sessionId) {
  335 + return sessions.containsKey(sessionId) ? TransportProtos.SessionType.ASYNC : TransportProtos.SessionType.SYNC;
  336 + }
  337 +
  338 + void processClientSideRpcTimeout(ActorContext context, DeviceActorClientSideRpcTimeoutMsg msg) {
335 339 ToServerRpcRequestMetadata data = toServerRpcPendingMap.remove(msg.getId());
336 340 if (data != null) {
337 341 logger.debug("[{}] Client side RPC request [{}] timeout detected!", deviceId, msg.getId());
338   - ToDeviceMsg toDeviceMsg = new RuleEngineErrorMsg(SessionMsgType.TO_SERVER_RPC_REQUEST, RuleEngineError.TIMEOUT);
339   -// sendMsgToSessionActor(new BasicActorSystemToDeviceSessionActorMsg(toDeviceMsg, data.getSessionId()), data.getServer());
  342 + sendToTransport(TransportProtos.ToServerRpcResponseMsg.newBuilder()
  343 + .setRequestId(msg.getId()).setError("timeout").build()
  344 + , data.getSessionId(), data.getNodeId());
340 345 }
341 346 }
342 347
343 348 void processToServerRPCResponse(ActorContext context, ToServerRpcResponseActorMsg msg) {
344   - ToServerRpcRequestMetadata data = toServerRpcPendingMap.remove(msg.getMsg().getRequestId());
  349 + int requestId = msg.getMsg().getRequestId();
  350 + ToServerRpcRequestMetadata data = toServerRpcPendingMap.remove(requestId);
345 351 if (data != null) {
346   -// sendMsgToSessionActor(new BasicActorSystemToDeviceSessionActorMsg(msg.getMsg(), data.getSessionId()), data.getServer());
  352 + sendToTransport(TransportProtos.ToServerRpcResponseMsg.newBuilder()
  353 + .setRequestId(requestId).setPayload(msg.getMsg().getData()).build()
  354 + , data.getSessionId(), data.getNodeId());
347 355 }
348 356 }
349 357
... ... @@ -382,7 +390,7 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
382 390 if (hasNotificationData) {
383 391 AttributeUpdateNotificationMsg finalNotification = notification.build();
384 392 attributeSubscriptions.entrySet().forEach(sub -> {
385   - sendToTransport(finalNotification, sub.getKey(), sub.getValue());
  393 + sendToTransport(finalNotification, sub.getKey(), sub.getValue().getNodeId());
386 394 });
387 395 }
388 396 } else {
... ... @@ -390,6 +398,19 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
390 398 }
391 399 }
392 400
  401 + private void processRpcResponses(ActorContext context, SessionInfoProto sessionInfo, ToDeviceRpcResponseMsg responseMsg) {
  402 + UUID sessionId = getSessionId(sessionInfo);
  403 + logger.debug("[{}] Processing rpc command response [{}]", deviceId, sessionId);
  404 + ToDeviceRpcRequestMetadata requestMd = toDeviceRpcPendingMap.remove(responseMsg.getRequestId());
  405 + boolean success = requestMd != null;
  406 + if (success) {
  407 + systemContext.getDeviceRpcService().processRpcResponseFromDevice(new FromDeviceRpcResponse(requestMd.getMsg().getMsg().getId(),
  408 + requestMd.getMsg().getServerAddress(), responseMsg.getPayload(), null));
  409 + } else {
  410 + logger.debug("[{}] Rpc command response [{}] is stale!", deviceId, responseMsg.getRequestId());
  411 + }
  412 + }
  413 +
393 414 // private void processRpcResponses(ActorContext context, DeviceToDeviceActorMsg msg) {
394 415 // SessionId sessionId = msg.getSessionId();
395 416 // FromDeviceMsg inMsg = msg.getPayload();
... ... @@ -424,7 +445,7 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
424 445 }
425 446
426 447 private void processSubscriptionCommands(ActorContext context, SessionInfoProto sessionInfo, SubscribeToAttributeUpdatesMsg subscribeCmd) {
427   - UUID sessionId = new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB());
  448 + UUID sessionId = getSessionId(sessionInfo);
428 449 if (subscribeCmd.getUnsubscribe()) {
429 450 logger.debug("[{}] Canceling attributes subscription for session [{}]", deviceId, sessionId);
430 451 attributeSubscriptions.remove(sessionId);
... ... @@ -438,8 +459,12 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
438 459 }
439 460 }
440 461
  462 + private UUID getSessionId(SessionInfoProto sessionInfo) {
  463 + return new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB());
  464 + }
  465 +
441 466 private void processSubscriptionCommands(ActorContext context, SessionInfoProto sessionInfo, SubscribeToRPCMsg subscribeCmd) {
442   - UUID sessionId = new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB());
  467 + UUID sessionId = getSessionId(sessionInfo);
443 468 if (subscribeCmd.getUnsubscribe()) {
444 469 logger.debug("[{}] Canceling rpc subscription for session [{}]", deviceId, sessionId);
445 470 rpcSubscriptions.remove(sessionId);
... ... @@ -450,11 +475,12 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
450 475 }
451 476 logger.debug("[{}] Registering rpc subscription for session [{}]", deviceId, sessionId);
452 477 rpcSubscriptions.put(sessionId, session);
  478 + sendPendingRequests(context, sessionId, sessionInfo);
453 479 }
454 480 }
455 481
456 482 private void processSessionStateMsgs(SessionInfoProto sessionInfo, SessionEventMsg msg) {
457   - UUID sessionId = new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB());
  483 + UUID sessionId = getSessionId(sessionInfo);
458 484 if (msg.getEvent() == SessionEvent.OPEN) {
459 485 logger.debug("[{}] Processing new session [{}]", deviceId, sessionId);
460 486 if (sessions.size() >= systemContext.getMaxConcurrentSessionsPerDevice()) {
... ... @@ -548,14 +574,31 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
548 574 systemContext.getRuleEngineTransportService().process(sessionInfo.getNodeId(), msg);
549 575 }
550 576
551   - private void sendToTransport(AttributeUpdateNotificationMsg notificationMsg, UUID sessionId, SessionInfo sessionInfo) {
  577 + private void sendToTransport(AttributeUpdateNotificationMsg notificationMsg, UUID sessionId, String nodeId) {
552 578 DeviceActorToTransportMsg msg = DeviceActorToTransportMsg.newBuilder()
553 579 .setSessionIdMSB(sessionId.getMostSignificantBits())
554 580 .setSessionIdLSB(sessionId.getLeastSignificantBits())
555 581 .setAttributeUpdateNotification(notificationMsg).build();
556   - systemContext.getRuleEngineTransportService().process(sessionInfo.getNodeId(), msg);
  582 + systemContext.getRuleEngineTransportService().process(nodeId, msg);
557 583 }
558 584
  585 + private void sendToTransport(ToDeviceRpcRequestMsg rpcMsg, UUID sessionId, String nodeId) {
  586 + DeviceActorToTransportMsg msg = DeviceActorToTransportMsg.newBuilder()
  587 + .setSessionIdMSB(sessionId.getMostSignificantBits())
  588 + .setSessionIdLSB(sessionId.getLeastSignificantBits())
  589 + .setToDeviceRequest(rpcMsg).build();
  590 + systemContext.getRuleEngineTransportService().process(nodeId, msg);
  591 + }
  592 +
  593 + private void sendToTransport(TransportProtos.ToServerRpcResponseMsg rpcMsg, UUID sessionId, String nodeId) {
  594 + DeviceActorToTransportMsg msg = DeviceActorToTransportMsg.newBuilder()
  595 + .setSessionIdMSB(sessionId.getMostSignificantBits())
  596 + .setSessionIdLSB(sessionId.getLeastSignificantBits())
  597 + .setToServerResponse(rpcMsg).build();
  598 + systemContext.getRuleEngineTransportService().process(nodeId, msg);
  599 + }
  600 +
  601 +
559 602 private List<TsKvProto> toTsKvProtos(@Nullable List<AttributeKvEntry> result) {
560 603 List<TsKvProto> clientAttributes;
561 604 if (result == null || result.isEmpty()) {
... ...
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.AllArgsConstructor;
19   -import lombok.Data;
20   -import org.thingsboard.server.common.data.id.SessionId;
21   -import org.thingsboard.server.common.msg.cluster.ServerAddress;
22   -import org.thingsboard.server.common.msg.session.SessionMsgType;
23   -
24   -import java.util.Optional;
25   -import java.util.UUID;
26   -
27   -/**
28   - * Created by ashvayka on 17.04.18.
29   - */
30   -@Data
31   -@AllArgsConstructor
32   -public final class PendingSessionMsgData {
33   -
34   - private final UUID sessionId;
35   - private final Optional<ServerAddress> serverAddress;
36   - private final SessionMsgType sessionMsgType;
37   - private final int requestId;
38   - private final boolean replyOnQueueAck;
39   - private int ackMsgCount;
40   -
41   -}
... ... @@ -16,18 +16,16 @@
16 16 package org.thingsboard.server.actors.device;
17 17
18 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;
  19 +import org.thingsboard.server.gen.transport.TransportProtos;
22 20
23   -import java.util.Optional;
  21 +import java.util.UUID;
24 22
25 23 /**
26 24 * @author Andrew Shvayka
27 25 */
28 26 @Data
29 27 public class ToServerRpcRequestMetadata {
30   - private final SessionId sessionId;
31   - private final SessionType type;
32   - private final Optional<ServerAddress> server;
  28 + private final UUID sessionId;
  29 + private final TransportProtos.SessionType type;
  30 + private final String nodeId;
33 31 }
... ...
1 1 /**
2 2 * Copyright © 2016-2018 The Thingsboard Authors
3   - * <p>
  3 + *
4 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 5 * you may not use this file except in compliance with the License.
6 6 * You may obtain a copy of the License at
7   - * <p>
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - * <p>
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
10 10 * Unless required by applicable law or agreed to in writing, software
11 11 * distributed under the License is distributed on an "AS IS" BASIS,
12 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
... ... @@ -15,8 +15,11 @@
15 15 */
16 16 package org.thingsboard.server.common.transport;
17 17
  18 +import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcResponseMsg;
18 19 import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg;
19 20 import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg;
  21 +import org.thingsboard.server.gen.transport.TransportProtos.SessionCloseNotificationProto;
  22 +import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcRequestMsg;
20 23
21 24 /**
22 25 * Created by ashvayka on 04.10.18.
... ... @@ -26,4 +29,10 @@ public interface SessionMsgListener {
26 29 void onGetAttributesResponse(GetAttributeResponseMsg getAttributesResponse);
27 30
28 31 void onAttributeUpdate(AttributeUpdateNotificationMsg attributeUpdateNotification);
  32 +
  33 + void onRemoteSessionCloseCommand(SessionCloseNotificationProto sessionCloseNotification);
  34 +
  35 + void onToDeviceRpcRequest(ToDeviceRpcRequestMsg toDeviceRequest);
  36 +
  37 + void onToServerRpcResponse(ToServerRpcResponseMsg toServerResponse);
29 38 }
... ...
... ... @@ -15,6 +15,8 @@
15 15 */
16 16 package org.thingsboard.server.common.transport;
17 17
  18 +import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcRequestMsg;
  19 +import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcResponseMsg;
18 20 import org.thingsboard.server.gen.transport.TransportProtos.SubscribeToAttributeUpdatesMsg;
19 21 import org.thingsboard.server.gen.transport.TransportProtos.SubscribeToRPCMsg;
20 22 import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
... ... @@ -49,6 +51,10 @@ public interface TransportService {
49 51
50 52 void process(SessionInfoProto sessionInfo, SubscribeToRPCMsg msg, TransportServiceCallback<Void> callback);
51 53
  54 + void process(SessionInfoProto sessionInfo, ToDeviceRpcResponseMsg msg, TransportServiceCallback<Void> callback);
  55 +
  56 + void process(SessionInfoProto sessionInfo, ToServerRpcRequestMsg msg, TransportServiceCallback<Void> callback);
  57 +
52 58 void registerSession(SessionInfoProto sessionInfo, SessionMsgListener listener);
53 59
54 60 void deregisterSession(SessionInfoProto sessionInfo);
... ...
1 1 /**
2 2 * Copyright © 2016-2018 The Thingsboard Authors
3   - * <p>
  3 + *
4 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 5 * you may not use this file except in compliance with the License.
6 6 * You may obtain a copy of the License at
7   - * <p>
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - * <p>
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
10 10 * Unless required by applicable law or agreed to in writing, software
11 11 * distributed under the License is distributed on an "AS IS" BASIS,
12 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
... ... @@ -22,6 +22,7 @@ import com.google.gson.JsonObject;
22 22 import com.google.gson.JsonParser;
23 23 import com.google.gson.JsonPrimitive;
24 24 import com.google.gson.JsonSyntaxException;
  25 +import org.springframework.util.StringUtils;
25 26 import org.thingsboard.server.common.data.kv.AttributeKey;
26 27 import org.thingsboard.server.common.data.kv.AttributeKvEntry;
27 28 import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
... ... @@ -95,6 +96,15 @@ public class JsonConverter {
95 96 }
96 97 }
97 98
  99 + public static JsonElement toJson(TransportProtos.ToDeviceRpcRequestMsg msg, boolean includeRequestId) {
  100 + JsonObject result = new JsonObject();
  101 + if (includeRequestId) {
  102 + result.addProperty("id", msg.getRequestId());
  103 + }
  104 + result.addProperty("method", msg.getMethodName());
  105 + result.add("params", new JsonParser().parse(msg.getParams()));
  106 + return result;
  107 + }
98 108
99 109 private static void parseObject(PostTelemetryMsg.Builder builder, long systemTs, JsonElement jsonObject) {
100 110 JsonObject jo = jsonObject.getAsJsonObject();
... ... @@ -112,14 +122,14 @@ public class JsonConverter {
112 122 request.addTsKvList(builder.build());
113 123 }
114 124
115   - public static void parseWithTs(PostTelemetryMsg.Builder request, JsonObject jo) {
  125 + private static void parseWithTs(PostTelemetryMsg.Builder request, JsonObject jo) {
116 126 TsKvListProto.Builder builder = TsKvListProto.newBuilder();
117 127 builder.setTs(jo.get("ts").getAsLong());
118 128 builder.addAllKv(parseProtoValues(jo.get("values").getAsJsonObject()));
119 129 request.addTsKvList(builder.build());
120 130 }
121 131
122   - public static List<KeyValueProto> parseProtoValues(JsonObject valuesObject) {
  132 + private static List<KeyValueProto> parseProtoValues(JsonObject valuesObject) {
123 133 List<KeyValueProto> result = new ArrayList<>();
124 134 for (Entry<String, JsonElement> valueEntry : valuesObject.entrySet()) {
125 135 JsonElement element = valueEntry.getValue();
... ... @@ -172,9 +182,9 @@ public class JsonConverter {
172 182 return request;
173 183 }
174 184
175   - public static ToServerRpcRequestMsg convertToServerRpcRequest(JsonElement json, int requestId) throws JsonSyntaxException {
  185 + public static TransportProtos.ToServerRpcRequestMsg convertToServerRpcRequest(JsonElement json, int requestId) throws JsonSyntaxException {
176 186 JsonObject object = json.getAsJsonObject();
177   - return new ToServerRpcRequestMsg(requestId, object.get("method").getAsString(), GSON.toJson(object.get("params")));
  187 + return TransportProtos.ToServerRpcRequestMsg.newBuilder().setRequestId(requestId).setMethodName(object.get("method").getAsString()).setParams(GSON.toJson(object.get("params"))).build();
178 188 }
179 189
180 190 private static void parseObject(BasicTelemetryUploadRequest request, long systemTs, JsonElement jsonObject) {
... ... @@ -368,8 +378,14 @@ public class JsonConverter {
368 378 return result;
369 379 }
370 380
371   - public static JsonElement toJson(ToServerRpcResponseMsg msg) {
372   - return new JsonParser().parse(msg.getData());
  381 + public static JsonElement toJson(TransportProtos.ToServerRpcResponseMsg msg) {
  382 + if (StringUtils.isEmpty(msg.getError())) {
  383 + return new JsonParser().parse(msg.getPayload());
  384 + } else {
  385 + JsonObject errorMsg = new JsonObject();
  386 + errorMsg.addProperty("error", msg.getError());
  387 + return errorMsg;
  388 + }
373 389 }
374 390
375 391 public static JsonElement toErrorJson(String errorMsg) {
... ...
... ... @@ -137,6 +137,29 @@ message SubscribeToRPCMsg {
137 137 bool unsubscribe = 1;
138 138 }
139 139
  140 +message ToDeviceRpcRequestMsg {
  141 + int32 requestId = 1;
  142 + string methodName = 2;
  143 + string params = 3;
  144 +}
  145 +
  146 +message ToDeviceRpcResponseMsg {
  147 + int32 requestId = 1;
  148 + string payload = 2;
  149 +}
  150 +
  151 +message ToServerRpcRequestMsg {
  152 + int32 requestId = 1;
  153 + string methodName = 2;
  154 + string params = 3;
  155 +}
  156 +
  157 +message ToServerRpcResponseMsg {
  158 + int32 requestId = 1;
  159 + string payload = 2;
  160 + string error = 3;
  161 +}
  162 +
140 163 message TransportToDeviceActorMsg {
141 164 SessionInfoProto sessionInfo = 1;
142 165 SessionEventMsg sessionEvent = 2;
... ... @@ -144,7 +167,9 @@ message TransportToDeviceActorMsg {
144 167 PostAttributeMsg postAttributes = 4;
145 168 GetAttributeRequestMsg getAttributes = 5;
146 169 SubscribeToAttributeUpdatesMsg subscribeToAttributes = 6;
147   - SubscribeToRPCMsg subscribeToRPC= 7;
  170 + SubscribeToRPCMsg subscribeToRPC = 7;
  171 + ToDeviceRpcResponseMsg toDeviceRPCCallResponse = 8;
  172 + ToServerRpcRequestMsg toServerRPCCallRequest = 9;
148 173 }
149 174
150 175 message DeviceActorToTransportMsg {
... ... @@ -153,6 +178,8 @@ message DeviceActorToTransportMsg {
153 178 SessionCloseNotificationProto sessionCloseNotification = 3;
154 179 GetAttributeResponseMsg getAttributesResponse = 4;
155 180 AttributeUpdateNotificationMsg attributeUpdateNotification = 5;
  181 + ToDeviceRpcRequestMsg toDeviceRequest = 6;
  182 + ToServerRpcResponseMsg toServerResponse = 7;
156 183 }
157 184
158 185 /**
... ...
... ... @@ -98,7 +98,8 @@ public class JsonCoapAdaptor implements CoapTransportAdaptor {
98 98
99 99 String payload = validatePayload(ctx, inbound);
100 100
101   - return JsonConverter.convertToServerRpcRequest(new JsonParser().parse(payload), 0);
  101 +// return JsonConverter.convertToServerRpcRequest(new JsonParser().parse(payload), 0);
  102 + return null;
102 103 }
103 104
104 105 @Override
... ... @@ -225,8 +226,8 @@ public class JsonCoapAdaptor implements CoapTransportAdaptor {
225 226 private Response convertToServerRpcResponse(SessionContext ctx, ToServerRpcResponseMsg msg) {
226 227 if (msg.isSuccess()) {
227 228 Response response = new Response(ResponseCode.CONTENT);
228   - JsonElement result = JsonConverter.toJson(msg);
229   - response.setPayload(result.toString());
  229 +// JsonElement result = JsonConverter.toJson(msg);
  230 +// response.setPayload(result.toString());
230 231 return response;
231 232 } else {
232 233 return convertError(Optional.of(new RuntimeException("Server RPC response is empty!")));
... ...
... ... @@ -114,7 +114,7 @@ public class HttpSessionCtx extends DeviceAwareSessionContext {
114 114 }
115 115
116 116 private void reply(ToServerRpcResponseMsg msg) {
117   - responseWriter.setResult(new ResponseEntity<>(JsonConverter.toJson(msg).toString(), HttpStatus.OK));
  117 +// responseWriter.setResult(new ResponseEntity<>(JsonConverter.toJson(msg).toString(), HttpStatus.OK));
118 118 }
119 119
120 120 private void reply(AttributesUpdateNotification msg) {
... ...
1 1 /**
2 2 * Copyright © 2016-2018 The Thingsboard Authors
3   - * <p>
  3 + *
4 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 5 * you may not use this file except in compliance with the License.
6 6 * You may obtain a copy of the License at
7   - * <p>
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - * <p>
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
10 10 * Unless required by applicable law or agreed to in writing, software
11 11 * distributed under the License is distributed on an "AS IS" BASIS,
12 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
... ... @@ -223,43 +223,18 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
223 223 } else if (topicName.startsWith(MqttTopics.DEVICE_ATTRIBUTES_REQUEST_TOPIC_PREFIX)) {
224 224 TransportProtos.GetAttributeRequestMsg getAttributeMsg = adaptor.convertToGetAttributes(deviceSessionCtx, mqttMsg);
225 225 transportService.process(sessionInfo, getAttributeMsg, getPubAckCallback(ctx, msgId, getAttributeMsg));
  226 + } else if (topicName.startsWith(MqttTopics.DEVICE_RPC_RESPONSE_TOPIC)){
  227 + TransportProtos.ToDeviceRpcResponseMsg rpcResponseMsg = adaptor.convertToDeviceRpcResponse(deviceSessionCtx, mqttMsg);
  228 + transportService.process(sessionInfo, rpcResponseMsg, getPubAckCallback(ctx, msgId, rpcResponseMsg));
  229 + } else if (topicName.startsWith(MqttTopics.DEVICE_RPC_REQUESTS_TOPIC)){
  230 + TransportProtos.ToServerRpcRequestMsg rpcRequestMsg = adaptor.convertToServerRpcRequest(deviceSessionCtx, mqttMsg);
  231 + transportService.process(sessionInfo, rpcRequestMsg, getPubAckCallback(ctx, msgId, rpcRequestMsg));
226 232 }
227 233 } catch (AdaptorException e) {
228 234 log.warn("[{}] Failed to process publish msg [{}][{}]", sessionId, topicName, msgId, e);
229 235 log.info("[{}] Closing current session due to invalid publish msg [{}][{}]", sessionId, topicName, msgId);
230 236 ctx.close();
231 237 }
232   -// AdaptorToSessionActorMsg msg = null;
233   -// try {
234   -// if (topicName.equals(DEVICE_TELEMETRY_TOPIC)) {
235   -// msg = adaptor.convertToActorMsg(deviceSessionCtx, POST_TELEMETRY_REQUEST, mqttMsg);
236   -// } else if (topicName.equals(DEVICE_ATTRIBUTES_TOPIC)) {
237   -// msg = adaptor.convertToActorMsg(deviceSessionCtx, POST_ATTRIBUTES_REQUEST, mqttMsg);
238   -// } else if (topicName.startsWith(DEVICE_ATTRIBUTES_REQUEST_TOPIC_PREFIX)) {
239   -// msg = adaptor.convertToActorMsg(deviceSessionCtx, GET_ATTRIBUTES_REQUEST, mqttMsg);
240   -// if (msgId >= 0) {
241   -// ctx.writeAndFlush(createMqttPubAckMsg(msgId));
242   -// }
243   -// } else if (topicName.startsWith(DEVICE_RPC_RESPONSE_TOPIC)) {
244   -// msg = adaptor.convertToActorMsg(deviceSessionCtx, TO_DEVICE_RPC_RESPONSE, mqttMsg);
245   -// if (msgId >= 0) {
246   -// ctx.writeAndFlush(createMqttPubAckMsg(msgId));
247   -// }
248   -// } else if (topicName.startsWith(DEVICE_RPC_REQUESTS_TOPIC)) {
249   -// msg = adaptor.convertToActorMsg(deviceSessionCtx, TO_SERVER_RPC_REQUEST, mqttMsg);
250   -// if (msgId >= 0) {
251   -// ctx.writeAndFlush(createMqttPubAckMsg(msgId));
252   -// }
253   -// }
254   -// } catch (AdaptorException e) {
255   -// log.warn("[{}] Failed to process publish msg [{}][{}]", sessionId, topicName, msgId, e);
256   -// }
257   -// if (msg != null) {
258   -// processor.process(new BasicTransportToDeviceSessionActorMsg(deviceSessionCtx.getDevice(), msg));
259   -// } else {
260   -// log.info("[{}] Closing current session due to invalid publish msg [{}][{}]", sessionId, topicName, msgId);
261   -// ctx.close();
262   -// }
263 238 }
264 239
265 240 private <T> TransportServiceCallback<Void> getPubAckCallback(final ChannelHandlerContext ctx, final int msgId, final T msg) {
... ... @@ -555,4 +530,30 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
555 530 log.trace("[{}] Failed to convert device attributes update to MQTT msg", sessionId, e);
556 531 }
557 532 }
  533 +
  534 + @Override
  535 + public void onRemoteSessionCloseCommand(TransportProtos.SessionCloseNotificationProto sessionCloseNotification) {
  536 + log.trace("[{}] Received the remote command to close the session", sessionId);
  537 + processDisconnect(deviceSessionCtx.getChannel());
  538 + }
  539 +
  540 + @Override
  541 + public void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg rpcRequest) {
  542 + log.trace("[{}] Received RPC command to device", sessionId);
  543 + try {
  544 + adaptor.convertToPublish(deviceSessionCtx, rpcRequest).ifPresent(deviceSessionCtx.getChannel()::writeAndFlush);
  545 + } catch (Exception e) {
  546 + log.trace("[{}] Failed to convert device RPC commandto MQTT msg", sessionId, e);
  547 + }
  548 + }
  549 +
  550 + @Override
  551 + public void onToServerRpcResponse(TransportProtos.ToServerRpcResponseMsg rpcResponse) {
  552 + log.trace("[{}] Received RPC command to device", sessionId);
  553 + try {
  554 + adaptor.convertToPublish(deviceSessionCtx, rpcResponse).ifPresent(deviceSessionCtx.getChannel()::writeAndFlush);
  555 + } catch (Exception e) {
  556 + log.trace("[{}] Failed to convert device RPC commandto MQTT msg", sessionId, e);
  557 + }
  558 + }
558 559 }
... ...
1 1 /**
2 2 * Copyright © 2016-2018 The Thingsboard Authors
3   - * <p>
  3 + *
4 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 5 * you may not use this file except in compliance with the License.
6 6 * You may obtain a copy of the License at
7   - * <p>
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - * <p>
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
10 10 * Unless required by applicable law or agreed to in writing, software
11 11 * distributed under the License is distributed on an "AS IS" BASIS,
12 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
... ... @@ -17,7 +17,6 @@ package org.thingsboard.server.transport.mqtt.adaptors;
17 17
18 18 import com.google.gson.Gson;
19 19 import com.google.gson.JsonElement;
20   -import com.google.gson.JsonObject;
21 20 import com.google.gson.JsonParser;
22 21 import com.google.gson.JsonSyntaxException;
23 22 import io.netty.buffer.ByteBuf;
... ... @@ -99,6 +98,31 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor {
99 98 }
100 99
101 100 @Override
  101 + public TransportProtos.ToDeviceRpcResponseMsg convertToDeviceRpcResponse(DeviceSessionCtx ctx, MqttPublishMessage inbound) throws AdaptorException {
  102 + String topicName = inbound.variableHeader().topicName();
  103 + try {
  104 + Integer requestId = Integer.valueOf(topicName.substring(MqttTopics.DEVICE_RPC_RESPONSE_TOPIC.length()));
  105 + String payload = inbound.payload().toString(UTF8);
  106 + return TransportProtos.ToDeviceRpcResponseMsg.newBuilder().setRequestId(requestId).setPayload(payload).build();
  107 + } catch (RuntimeException e) {
  108 + log.warn("Failed to decode get attributes request", e);
  109 + throw new AdaptorException(e);
  110 + }
  111 + }
  112 +
  113 + @Override
  114 + public TransportProtos.ToServerRpcRequestMsg convertToServerRpcRequest(DeviceSessionCtx ctx, MqttPublishMessage inbound) throws AdaptorException {
  115 + String topicName = inbound.variableHeader().topicName();
  116 + String payload = validatePayload(ctx.getSessionId(), inbound.payload());
  117 + try {
  118 + Integer requestId = Integer.valueOf(topicName.substring(MqttTopics.DEVICE_RPC_REQUESTS_TOPIC.length()));
  119 + return JsonConverter.convertToServerRpcRequest(new JsonParser().parse(payload), requestId);
  120 + } catch (IllegalStateException | JsonSyntaxException ex) {
  121 + throw new AdaptorException(ex);
  122 + }
  123 + }
  124 +
  125 + @Override
102 126 public Optional<MqttMessage> convertToPublish(DeviceSessionCtx ctx, TransportProtos.GetAttributeResponseMsg responseMsg) throws AdaptorException {
103 127 if (!StringUtils.isEmpty(responseMsg.getError())) {
104 128 throw new AdaptorException(responseMsg.getError());
... ... @@ -115,9 +139,17 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor {
115 139
116 140 @Override
117 141 public Optional<MqttMessage> convertToPublish(DeviceSessionCtx ctx, TransportProtos.AttributeUpdateNotificationMsg notificationMsg) throws AdaptorException {
118   - return Optional.of(createMqttPublishMsg(ctx,
119   - MqttTopics.DEVICE_ATTRIBUTES_TOPIC,
120   - JsonConverter.toJson(notificationMsg)));
  142 + return Optional.of(createMqttPublishMsg(ctx, MqttTopics.DEVICE_ATTRIBUTES_TOPIC, JsonConverter.toJson(notificationMsg)));
  143 + }
  144 +
  145 + @Override
  146 + public Optional<MqttMessage> convertToPublish(DeviceSessionCtx ctx, TransportProtos.ToDeviceRpcRequestMsg rpcRequest) throws AdaptorException {
  147 + return Optional.of(createMqttPublishMsg(ctx, MqttTopics.DEVICE_RPC_REQUESTS_TOPIC + rpcRequest.getRequestId(), JsonConverter.toJson(rpcRequest, false)));
  148 + }
  149 +
  150 + @Override
  151 + public Optional<MqttMessage> convertToPublish(DeviceSessionCtx ctx, TransportProtos.ToServerRpcResponseMsg rpcResponse) {
  152 + return Optional.of(createMqttPublishMsg(ctx, MqttTopics.DEVICE_RPC_RESPONSE_TOPIC + rpcResponse.getRequestId(), JsonConverter.toJson(rpcResponse)));
121 153 }
122 154
123 155 @Override
... ... @@ -149,7 +181,7 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor {
149 181 msg = convertToRpcCommandResponse(ctx, (MqttPublishMessage) inbound);
150 182 break;
151 183 case TO_SERVER_RPC_REQUEST:
152   - msg = convertToServerRpcRequest(ctx, (MqttPublishMessage) inbound);
  184 + msg = null;//convertToServerRpcRequest(ctx, (MqttPublishMessage) inbound);
153 185 break;
154 186 default:
155 187 log.warn("[{}] Unsupported msg type: {}!", ctx.getSessionId(), type);
... ... @@ -181,13 +213,12 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor {
181 213 break;
182 214 case TO_DEVICE_RPC_REQUEST:
183 215 ToDeviceRpcRequestMsg rpcRequest = (ToDeviceRpcRequestMsg) msg;
184   - result = createMqttPublishMsg(ctx, MqttTopics.DEVICE_RPC_REQUESTS_TOPIC + rpcRequest.getRequestId(),
185   - rpcRequest);
  216 + result = createMqttPublishMsg(ctx, MqttTopics.DEVICE_RPC_REQUESTS_TOPIC + rpcRequest.getRequestId(), rpcRequest);
186 217 break;
187 218 case TO_SERVER_RPC_RESPONSE:
188   - ToServerRpcResponseMsg rpcResponse = (ToServerRpcResponseMsg) msg;
189   - result = createMqttPublishMsg(ctx, MqttTopics.DEVICE_RPC_RESPONSE_TOPIC + rpcResponse.getRequestId(),
190   - rpcResponse);
  219 +// ToServerRpcResponseMsg rpcResponse = (ToServerRpcResponseMsg) msg;
  220 +// result = createMqttPublishMsg(ctx, MqttTopics.DEVICE_RPC_RESPONSE_TOPIC + rpcResponse.getRequestId(),
  221 +// rpcResponse);
191 222 break;
192 223 case RULE_ENGINE_ERROR:
193 224 RuleEngineErrorMsg errorMsg = (RuleEngineErrorMsg) msg;
... ... @@ -232,7 +263,7 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor {
232 263 return createMqttPublishMsg(ctx, topic, JsonConverter.toJson(msg, false));
233 264 }
234 265
235   - private MqttPublishMessage createMqttPublishMsg(DeviceSessionCtx ctx, String topic, ToServerRpcResponseMsg msg) {
  266 + private MqttPublishMessage createMqttPublishMsg(DeviceSessionCtx ctx, String topic, TransportProtos.ToServerRpcResponseMsg msg) {
236 267 return createMqttPublishMsg(ctx, topic, JsonConverter.toJson(msg));
237 268 }
238 269
... ... @@ -290,7 +321,7 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor {
290 321 private AttributesUpdateRequest convertToUpdateAttributesRequest(SessionContext ctx, MqttPublishMessage inbound) throws AdaptorException {
291 322 String payload = validatePayload(ctx.getSessionId(), inbound.payload());
292 323 try {
293   - return JsonConverter.convertToAttributes(new JsonParser().parse(payload), inbound.variableHeader().messageId());
  324 + return JsonConverter.convertToAttributes(new JsonParser().parse(payload), inbound.variableHeader().packetId());
294 325 } catch (IllegalStateException | JsonSyntaxException ex) {
295 326 throw new AdaptorException(ex);
296 327 }
... ... @@ -299,18 +330,7 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor {
299 330 private TelemetryUploadRequest convertToTelemetryUploadRequest(SessionContext ctx, MqttPublishMessage inbound) throws AdaptorException {
300 331 String payload = validatePayload(ctx.getSessionId(), inbound.payload());
301 332 try {
302   - return JsonConverter.convertToTelemetry(new JsonParser().parse(payload), inbound.variableHeader().messageId());
303   - } catch (IllegalStateException | JsonSyntaxException ex) {
304   - throw new AdaptorException(ex);
305   - }
306   - }
307   -
308   - private FromDeviceMsg convertToServerRpcRequest(DeviceSessionCtx ctx, MqttPublishMessage inbound) throws AdaptorException {
309   - String topicName = inbound.variableHeader().topicName();
310   - String payload = validatePayload(ctx.getSessionId(), inbound.payload());
311   - try {
312   - Integer requestId = Integer.valueOf(topicName.substring(MqttTopics.DEVICE_RPC_REQUESTS_TOPIC.length()));
313   - return JsonConverter.convertToServerRpcRequest(new JsonParser().parse(payload), requestId);
  333 + return JsonConverter.convertToTelemetry(new JsonParser().parse(payload), inbound.variableHeader().packetId());
314 334 } catch (IllegalStateException | JsonSyntaxException ex) {
315 335 throw new AdaptorException(ex);
316 336 }
... ...
... ... @@ -19,7 +19,15 @@ import io.netty.handler.codec.mqtt.MqttMessage;
19 19 import io.netty.handler.codec.mqtt.MqttPublishMessage;
20 20 import org.thingsboard.server.common.transport.TransportAdaptor;
21 21 import org.thingsboard.server.common.transport.adaptor.AdaptorException;
22   -import org.thingsboard.server.gen.transport.TransportProtos;
  22 +import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcResponseMsg;
  23 +import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcRequestMsg;
  24 +import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcResponseMsg;
  25 +import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg;
  26 +import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg;
  27 +import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg;
  28 +import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg;
  29 +import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg;
  30 +import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcRequestMsg;
23 31 import org.thingsboard.server.transport.mqtt.session.DeviceSessionCtx;
24 32
25 33 import java.util.Optional;
... ... @@ -29,15 +37,21 @@ import java.util.Optional;
29 37 */
30 38 public interface MqttTransportAdaptor extends TransportAdaptor<DeviceSessionCtx, MqttMessage, MqttMessage> {
31 39
32   - TransportProtos.PostTelemetryMsg convertToPostTelemetry(DeviceSessionCtx ctx, MqttPublishMessage inbound) throws AdaptorException;
  40 + PostTelemetryMsg convertToPostTelemetry(DeviceSessionCtx ctx, MqttPublishMessage inbound) throws AdaptorException;
33 41
34   - TransportProtos.PostAttributeMsg convertToPostAttributes(DeviceSessionCtx ctx, MqttPublishMessage inbound) throws AdaptorException;
  42 + PostAttributeMsg convertToPostAttributes(DeviceSessionCtx ctx, MqttPublishMessage inbound) throws AdaptorException;
35 43
36   - TransportProtos.GetAttributeRequestMsg convertToGetAttributes(DeviceSessionCtx ctx, MqttPublishMessage inbound) throws AdaptorException;
  44 + GetAttributeRequestMsg convertToGetAttributes(DeviceSessionCtx ctx, MqttPublishMessage inbound) throws AdaptorException;
37 45
38   - Optional<MqttMessage> convertToPublish(DeviceSessionCtx ctx, TransportProtos.GetAttributeResponseMsg responseMsg) throws AdaptorException;
  46 + ToDeviceRpcResponseMsg convertToDeviceRpcResponse(DeviceSessionCtx ctx, MqttPublishMessage mqttMsg) throws AdaptorException;
39 47
40   - Optional<MqttMessage> convertToPublish(DeviceSessionCtx ctx, TransportProtos.AttributeUpdateNotificationMsg notificationMsg) throws AdaptorException;
  48 + ToServerRpcRequestMsg convertToServerRpcRequest(DeviceSessionCtx ctx, MqttPublishMessage mqttMsg) throws AdaptorException;
41 49
  50 + Optional<MqttMessage> convertToPublish(DeviceSessionCtx ctx, GetAttributeResponseMsg responseMsg) throws AdaptorException;
42 51
  52 + Optional<MqttMessage> convertToPublish(DeviceSessionCtx ctx, AttributeUpdateNotificationMsg notificationMsg) throws AdaptorException;
  53 +
  54 + Optional<MqttMessage> convertToPublish(DeviceSessionCtx ctx, ToDeviceRpcRequestMsg rpcRequest) throws AdaptorException;
  55 +
  56 + Optional<MqttMessage> convertToPublish(DeviceSessionCtx ctx, ToServerRpcResponseMsg rpcResponse);
43 57 }
... ...
1 1 /**
2 2 * Copyright © 2016-2018 The Thingsboard Authors
3   - * <p>
  3 + *
4 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 5 * you may not use this file except in compliance with the License.
6 6 * You may obtain a copy of the License at
7   - * <p>
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - * <p>
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
10 10 * Unless required by applicable law or agreed to in writing, software
11 11 * distributed under the License is distributed on an "AS IS" BASIS,
12 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
... ... @@ -164,6 +164,15 @@ public class MqttTransportService implements TransportService {
164 164 if (toSessionMsg.hasAttributeUpdateNotification()) {
165 165 listener.onAttributeUpdate(toSessionMsg.getAttributeUpdateNotification());
166 166 }
  167 + if (toSessionMsg.hasSessionCloseNotification()) {
  168 + listener.onRemoteSessionCloseCommand(toSessionMsg.getSessionCloseNotification());
  169 + }
  170 + if (toSessionMsg.hasToDeviceRequest()) {
  171 + listener.onToDeviceRpcRequest(toSessionMsg.getToDeviceRequest());
  172 + }
  173 + if (toSessionMsg.hasToServerResponse()) {
  174 + listener.onToServerRpcResponse(toSessionMsg.getToServerResponse());
  175 + }
167 176 });
168 177 } else {
169 178 //TODO: should we notify the device actor about missed session?
... ... @@ -273,6 +282,24 @@ public class MqttTransportService implements TransportService {
273 282 }
274 283
275 284 @Override
  285 + public void process(SessionInfoProto sessionInfo, TransportProtos.ToDeviceRpcResponseMsg msg, TransportServiceCallback<Void> callback) {
  286 + ToRuleEngineMsg toRuleEngineMsg = ToRuleEngineMsg.newBuilder().setToDeviceActorMsg(
  287 + TransportProtos.TransportToDeviceActorMsg.newBuilder().setSessionInfo(sessionInfo)
  288 + .setToDeviceRPCCallResponse(msg).build()
  289 + ).build();
  290 + send(sessionInfo, toRuleEngineMsg, callback);
  291 + }
  292 +
  293 + @Override
  294 + public void process(SessionInfoProto sessionInfo, TransportProtos.ToServerRpcRequestMsg msg, TransportServiceCallback<Void> callback) {
  295 + ToRuleEngineMsg toRuleEngineMsg = ToRuleEngineMsg.newBuilder().setToDeviceActorMsg(
  296 + TransportProtos.TransportToDeviceActorMsg.newBuilder().setSessionInfo(sessionInfo)
  297 + .setToServerRPCCallRequest(msg).build()
  298 + ).build();
  299 + send(sessionInfo, toRuleEngineMsg, callback);
  300 + }
  301 +
  302 + @Override
276 303 public void registerSession(SessionInfoProto sessionInfo, SessionMsgListener listener) {
277 304 sessions.putIfAbsent(toId(sessionInfo), listener);
278 305 //TODO: monitor sessions periodically: PING REQ/RESP, etc.
... ...