Showing
13 changed files
with
333 additions
and
212 deletions
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()) { | ... | ... |
application/src/main/java/org/thingsboard/server/actors/device/PendingSessionMsgData.java
deleted
100644 → 0
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 | } | ... | ... |
transport/mqtt-transport/src/main/java/org/thingsboard/server/mqtt/service/MqttTransportService.java
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. | ... | ... |