Showing
32 changed files
with
877 additions
and
1140 deletions
@@ -31,6 +31,7 @@ import lombok.Setter; | @@ -31,6 +31,7 @@ import lombok.Setter; | ||
31 | import lombok.extern.slf4j.Slf4j; | 31 | import lombok.extern.slf4j.Slf4j; |
32 | import org.springframework.beans.factory.annotation.Autowired; | 32 | import org.springframework.beans.factory.annotation.Autowired; |
33 | import org.springframework.beans.factory.annotation.Value; | 33 | import org.springframework.beans.factory.annotation.Value; |
34 | +import org.springframework.context.annotation.Lazy; | ||
34 | import org.springframework.stereotype.Component; | 35 | import org.springframework.stereotype.Component; |
35 | import org.thingsboard.rule.engine.api.MailService; | 36 | import org.thingsboard.rule.engine.api.MailService; |
36 | import org.thingsboard.server.actors.service.ActorService; | 37 | import org.thingsboard.server.actors.service.ActorService; |
@@ -69,6 +70,7 @@ import org.thingsboard.server.service.script.JsExecutorService; | @@ -69,6 +70,7 @@ import org.thingsboard.server.service.script.JsExecutorService; | ||
69 | import org.thingsboard.server.service.script.JsInvokeService; | 70 | import org.thingsboard.server.service.script.JsInvokeService; |
70 | import org.thingsboard.server.service.state.DeviceStateService; | 71 | import org.thingsboard.server.service.state.DeviceStateService; |
71 | import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; | 72 | import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; |
73 | +import org.thingsboard.server.service.transport.RuleEngineTransportService; | ||
72 | 74 | ||
73 | import javax.annotation.Nullable; | 75 | import javax.annotation.Nullable; |
74 | import java.io.IOException; | 76 | import java.io.IOException; |
@@ -204,6 +206,11 @@ public class ActorSystemContext { | @@ -204,6 +206,11 @@ public class ActorSystemContext { | ||
204 | @Getter | 206 | @Getter |
205 | private DeviceStateService deviceStateService; | 207 | private DeviceStateService deviceStateService; |
206 | 208 | ||
209 | + @Lazy | ||
210 | + @Autowired | ||
211 | + @Getter | ||
212 | + private RuleEngineTransportService ruleEngineTransportService; | ||
213 | + | ||
207 | @Value("${cluster.partition_id}") | 214 | @Value("${cluster.partition_id}") |
208 | @Getter | 215 | @Getter |
209 | private long queuePartitionId; | 216 | private long queuePartitionId; |
@@ -39,7 +39,6 @@ import org.thingsboard.server.common.msg.aware.TenantAwareMsg; | @@ -39,7 +39,6 @@ import org.thingsboard.server.common.msg.aware.TenantAwareMsg; | ||
39 | import org.thingsboard.server.common.msg.cluster.SendToClusterMsg; | 39 | import org.thingsboard.server.common.msg.cluster.SendToClusterMsg; |
40 | import org.thingsboard.server.common.msg.cluster.ServerAddress; | 40 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
41 | import org.thingsboard.server.common.msg.core.BasicActorSystemToDeviceSessionActorMsg; | 41 | import org.thingsboard.server.common.msg.core.BasicActorSystemToDeviceSessionActorMsg; |
42 | -import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; | ||
43 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; | 42 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; |
44 | import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; | 43 | import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; |
45 | import org.thingsboard.server.dao.model.ModelConstants; | 44 | import org.thingsboard.server.dao.model.ModelConstants; |
@@ -105,7 +104,7 @@ public class AppActor extends RuleChainManagerActor { | @@ -105,7 +104,7 @@ public class AppActor extends RuleChainManagerActor { | ||
105 | case SERVICE_TO_RULE_ENGINE_MSG: | 104 | case SERVICE_TO_RULE_ENGINE_MSG: |
106 | onServiceToRuleEngineMsg((ServiceToRuleEngineMsg) msg); | 105 | onServiceToRuleEngineMsg((ServiceToRuleEngineMsg) msg); |
107 | break; | 106 | break; |
108 | - case DEVICE_SESSION_TO_DEVICE_ACTOR_MSG: | 107 | + case TRANSPORT_TO_DEVICE_ACTOR_MSG: |
109 | case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: | 108 | case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: |
110 | case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG: | 109 | case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG: |
111 | case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG: | 110 | case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG: |
@@ -169,16 +168,6 @@ public class AppActor extends RuleChainManagerActor { | @@ -169,16 +168,6 @@ public class AppActor extends RuleChainManagerActor { | ||
169 | getOrCreateTenantActor(msg.getTenantId()).tell(msg, ActorRef.noSender()); | 168 | getOrCreateTenantActor(msg.getTenantId()).tell(msg, ActorRef.noSender()); |
170 | } | 169 | } |
171 | 170 | ||
172 | - private void processDeviceMsg(DeviceToDeviceActorMsg deviceToDeviceActorMsg) { | ||
173 | - TenantId tenantId = deviceToDeviceActorMsg.getTenantId(); | ||
174 | - ActorRef tenantActor = getOrCreateTenantActor(tenantId); | ||
175 | - if (deviceToDeviceActorMsg.getPayload().getMsgType().requiresRulesProcessing()) { | ||
176 | -// tenantActor.tell(new RuleChainDeviceMsg(deviceToDeviceActorMsg, ruleManager.getRuleChain(this.context())), context().self()); | ||
177 | - } else { | ||
178 | - tenantActor.tell(deviceToDeviceActorMsg, context().self()); | ||
179 | - } | ||
180 | - } | ||
181 | - | ||
182 | private ActorRef getOrCreateTenantActor(TenantId tenantId) { | 171 | private ActorRef getOrCreateTenantActor(TenantId tenantId) { |
183 | return tenantActors.computeIfAbsent(tenantId, k -> context().actorOf(Props.create(new TenantActor.ActorCreator(systemContext, tenantId)) | 172 | return tenantActors.computeIfAbsent(tenantId, k -> context().actorOf(Props.create(new TenantActor.ActorCreator(systemContext, tenantId)) |
184 | .withDispatcher(DefaultActorService.CORE_DISPATCHER_NAME), tenantId.toString())); | 173 | .withDispatcher(DefaultActorService.CORE_DISPATCHER_NAME), tenantId.toString())); |
@@ -26,12 +26,12 @@ import org.thingsboard.server.common.data.id.DeviceId; | @@ -26,12 +26,12 @@ import org.thingsboard.server.common.data.id.DeviceId; | ||
26 | import org.thingsboard.server.common.data.id.TenantId; | 26 | import org.thingsboard.server.common.data.id.TenantId; |
27 | import org.thingsboard.server.common.msg.TbActorMsg; | 27 | import org.thingsboard.server.common.msg.TbActorMsg; |
28 | import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | 28 | import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
29 | -import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; | ||
30 | import org.thingsboard.server.common.msg.timeout.DeviceActorClientSideRpcTimeoutMsg; | 29 | import org.thingsboard.server.common.msg.timeout.DeviceActorClientSideRpcTimeoutMsg; |
31 | import org.thingsboard.server.common.msg.timeout.DeviceActorQueueTimeoutMsg; | 30 | import org.thingsboard.server.common.msg.timeout.DeviceActorQueueTimeoutMsg; |
32 | import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg; | 31 | import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg; |
33 | import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg; | 32 | import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg; |
34 | import org.thingsboard.server.service.rpc.ToServerRpcResponseActorMsg; | 33 | import org.thingsboard.server.service.rpc.ToServerRpcResponseActorMsg; |
34 | +import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; | ||
35 | 35 | ||
36 | public class DeviceActor extends ContextAwareActor { | 36 | public class DeviceActor extends ContextAwareActor { |
37 | 37 | ||
@@ -50,8 +50,8 @@ public class DeviceActor extends ContextAwareActor { | @@ -50,8 +50,8 @@ public class DeviceActor extends ContextAwareActor { | ||
50 | case CLUSTER_EVENT_MSG: | 50 | case CLUSTER_EVENT_MSG: |
51 | processor.processClusterEventMsg((ClusterEventMsg) msg); | 51 | processor.processClusterEventMsg((ClusterEventMsg) msg); |
52 | break; | 52 | break; |
53 | - case DEVICE_SESSION_TO_DEVICE_ACTOR_MSG: | ||
54 | - processor.process(context(), (DeviceToDeviceActorMsg) msg); | 53 | + case TRANSPORT_TO_DEVICE_ACTOR_MSG: |
54 | + processor.process(context(), (TransportToDeviceActorMsgWrapper) msg); | ||
55 | break; | 55 | break; |
56 | case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: | 56 | case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: |
57 | processor.processAttributesUpdate(context(), (DeviceAttributesEventNotificationMsg) msg); | 57 | processor.processAttributesUpdate(context(), (DeviceAttributesEventNotificationMsg) msg); |
1 | /** | 1 | /** |
2 | * Copyright © 2016-2018 The Thingsboard Authors | 2 | * Copyright © 2016-2018 The Thingsboard Authors |
3 | - * | 3 | + * <p> |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. | 5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at | 6 | * You may obtain a copy of the License at |
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | 7 | + * <p> |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * <p> | ||
10 | * Unless required by applicable law or agreed to in writing, software | 10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
@@ -61,7 +61,6 @@ import org.thingsboard.server.common.msg.core.TelemetryUploadRequest; | @@ -61,7 +61,6 @@ import org.thingsboard.server.common.msg.core.TelemetryUploadRequest; | ||
61 | import org.thingsboard.server.common.msg.core.ToDeviceRpcRequestMsg; | 61 | import org.thingsboard.server.common.msg.core.ToDeviceRpcRequestMsg; |
62 | import org.thingsboard.server.common.msg.core.ToDeviceRpcResponseMsg; | 62 | import org.thingsboard.server.common.msg.core.ToDeviceRpcResponseMsg; |
63 | import org.thingsboard.server.common.msg.core.ToServerRpcRequestMsg; | 63 | import org.thingsboard.server.common.msg.core.ToServerRpcRequestMsg; |
64 | -import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; | ||
65 | import org.thingsboard.server.common.msg.kv.BasicAttributeKVMsg; | 64 | import org.thingsboard.server.common.msg.kv.BasicAttributeKVMsg; |
66 | import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; | 65 | import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; |
67 | import org.thingsboard.server.common.msg.session.FromDeviceMsg; | 66 | import org.thingsboard.server.common.msg.session.FromDeviceMsg; |
@@ -71,9 +70,11 @@ import org.thingsboard.server.common.msg.session.ToDeviceMsg; | @@ -71,9 +70,11 @@ import org.thingsboard.server.common.msg.session.ToDeviceMsg; | ||
71 | import org.thingsboard.server.common.msg.timeout.DeviceActorClientSideRpcTimeoutMsg; | 70 | import org.thingsboard.server.common.msg.timeout.DeviceActorClientSideRpcTimeoutMsg; |
72 | import org.thingsboard.server.common.msg.timeout.DeviceActorQueueTimeoutMsg; | 71 | import org.thingsboard.server.common.msg.timeout.DeviceActorQueueTimeoutMsg; |
73 | import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg; | 72 | import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg; |
73 | +import org.thingsboard.server.gen.transport.TransportProtos; | ||
74 | import org.thingsboard.server.service.rpc.FromDeviceRpcResponse; | 74 | import org.thingsboard.server.service.rpc.FromDeviceRpcResponse; |
75 | import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg; | 75 | import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg; |
76 | import org.thingsboard.server.service.rpc.ToServerRpcResponseActorMsg; | 76 | import org.thingsboard.server.service.rpc.ToServerRpcResponseActorMsg; |
77 | +import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; | ||
77 | 78 | ||
78 | import javax.annotation.Nullable; | 79 | import javax.annotation.Nullable; |
79 | import java.util.ArrayList; | 80 | import java.util.ArrayList; |
@@ -92,6 +93,8 @@ import java.util.function.Consumer; | @@ -92,6 +93,8 @@ import java.util.function.Consumer; | ||
92 | import java.util.function.Predicate; | 93 | import java.util.function.Predicate; |
93 | import java.util.stream.Collectors; | 94 | import java.util.stream.Collectors; |
94 | 95 | ||
96 | +import org.thingsboard.server.gen.transport.TransportProtos.*; | ||
97 | + | ||
95 | /** | 98 | /** |
96 | * @author Andrew Shvayka | 99 | * @author Andrew Shvayka |
97 | */ | 100 | */ |
@@ -99,12 +102,11 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | @@ -99,12 +102,11 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | ||
99 | 102 | ||
100 | private final TenantId tenantId; | 103 | private final TenantId tenantId; |
101 | private final DeviceId deviceId; | 104 | private final DeviceId deviceId; |
102 | - private final Map<SessionId, SessionInfo> sessions; | ||
103 | - private final Map<SessionId, SessionInfo> attributeSubscriptions; | ||
104 | - private final Map<SessionId, SessionInfo> rpcSubscriptions; | 105 | + private final Map<UUID, SessionInfo> sessions; |
106 | + private final Map<UUID, SessionInfo> attributeSubscriptions; | ||
107 | + private final Map<UUID, SessionInfo> rpcSubscriptions; | ||
105 | private final Map<Integer, ToDeviceRpcRequestMetadata> toDeviceRpcPendingMap; | 108 | private final Map<Integer, ToDeviceRpcRequestMetadata> toDeviceRpcPendingMap; |
106 | private final Map<Integer, ToServerRpcRequestMetadata> toServerRpcPendingMap; | 109 | private final Map<Integer, ToServerRpcRequestMetadata> toServerRpcPendingMap; |
107 | - private final Map<UUID, PendingSessionMsgData> pendingMsgs; | ||
108 | 110 | ||
109 | private final Gson gson = new Gson(); | 111 | private final Gson gson = new Gson(); |
110 | private final JsonParser jsonParser = new JsonParser(); | 112 | private final JsonParser jsonParser = new JsonParser(); |
@@ -123,7 +125,6 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | @@ -123,7 +125,6 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | ||
123 | this.rpcSubscriptions = new HashMap<>(); | 125 | this.rpcSubscriptions = new HashMap<>(); |
124 | this.toDeviceRpcPendingMap = new HashMap<>(); | 126 | this.toDeviceRpcPendingMap = new HashMap<>(); |
125 | this.toServerRpcPendingMap = new HashMap<>(); | 127 | this.toServerRpcPendingMap = new HashMap<>(); |
126 | - this.pendingMsgs = new HashMap<>(); | ||
127 | initAttributes(); | 128 | initAttributes(); |
128 | } | 129 | } |
129 | 130 | ||
@@ -154,11 +155,11 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | @@ -154,11 +155,11 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | ||
154 | boolean sent = rpcSubscriptions.size() > 0; | 155 | boolean sent = rpcSubscriptions.size() > 0; |
155 | Set<SessionId> syncSessionSet = new HashSet<>(); | 156 | Set<SessionId> syncSessionSet = new HashSet<>(); |
156 | rpcSubscriptions.entrySet().forEach(sub -> { | 157 | rpcSubscriptions.entrySet().forEach(sub -> { |
157 | - ActorSystemToDeviceSessionActorMsg response = new BasicActorSystemToDeviceSessionActorMsg(rpcRequest, sub.getKey()); | ||
158 | - sendMsgToSessionActor(response, sub.getValue().getServer()); | ||
159 | - if (SessionType.SYNC == sub.getValue().getType()) { | ||
160 | - syncSessionSet.add(sub.getKey()); | ||
161 | - } | 158 | +// ActorSystemToDeviceSessionActorMsg response = new BasicActorSystemToDeviceSessionActorMsg(rpcRequest, sub.getKey()); |
159 | +// sendMsgToSessionActor(response, sub.getValue().getServer()); | ||
160 | +// if (SessionType.SYNC == sub.getValue().getType()) { | ||
161 | +// syncSessionSet.add(sub.getKey()); | ||
162 | +// } | ||
162 | }); | 163 | }); |
163 | syncSessionSet.forEach(rpcSubscriptions::remove); | 164 | syncSessionSet.forEach(rpcSubscriptions::remove); |
164 | 165 | ||
@@ -191,15 +192,6 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | @@ -191,15 +192,6 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | ||
191 | } | 192 | } |
192 | } | 193 | } |
193 | 194 | ||
194 | - void processQueueTimeout(ActorContext context, DeviceActorQueueTimeoutMsg msg) { | ||
195 | - PendingSessionMsgData data = pendingMsgs.remove(msg.getId()); | ||
196 | - if (data != null) { | ||
197 | - logger.debug("[{}] Queue put [{}] timeout detected!", deviceId, msg.getId()); | ||
198 | - ToDeviceMsg toDeviceMsg = new RuleEngineErrorMsg(data.getSessionMsgType(), RuleEngineError.QUEUE_PUT_TIMEOUT); | ||
199 | - sendMsgToSessionActor(new BasicActorSystemToDeviceSessionActorMsg(toDeviceMsg, data.getSessionId()), data.getServerAddress()); | ||
200 | - } | ||
201 | - } | ||
202 | - | ||
203 | void processQueueAck(ActorContext context, RuleEngineQueuePutAckMsg msg) { | 195 | void processQueueAck(ActorContext context, RuleEngineQueuePutAckMsg msg) { |
204 | PendingSessionMsgData data = pendingMsgs.remove(msg.getId()); | 196 | PendingSessionMsgData data = pendingMsgs.remove(msg.getId()); |
205 | if (data != null && data.isReplyOnQueueAck()) { | 197 | if (data != null && data.isReplyOnQueueAck()) { |
@@ -252,31 +244,37 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | @@ -252,31 +244,37 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | ||
252 | }; | 244 | }; |
253 | } | 245 | } |
254 | 246 | ||
255 | - void process(ActorContext context, DeviceToDeviceActorMsg msg) { | ||
256 | - processSubscriptionCommands(context, msg); | ||
257 | - processRpcResponses(context, msg); | ||
258 | - processSessionStateMsgs(msg); | 247 | + void process(ActorContext context, TransportToDeviceActorMsgWrapper wrapper) { |
248 | + TransportToDeviceActorMsg msg = wrapper.getMsg(); | ||
249 | +// processSubscriptionCommands(context, msg); | ||
250 | +// processRpcResponses(context, msg); | ||
251 | + if (msg.hasSessionEvent()) { | ||
252 | + processSessionStateMsgs(msg.getSessionInfo(), msg.getSessionEvent()); | ||
253 | + } | ||
259 | 254 | ||
260 | - SessionMsgType sessionMsgType = msg.getPayload().getMsgType(); | ||
261 | - if (sessionMsgType.requiresRulesProcessing()) { | ||
262 | - switch (sessionMsgType) { | ||
263 | - case GET_ATTRIBUTES_REQUEST: | ||
264 | - handleGetAttributesRequest(msg); | ||
265 | - break; | ||
266 | - case POST_ATTRIBUTES_REQUEST: | ||
267 | - handlePostAttributesRequest(context, msg); | ||
268 | - reportActivity(); | ||
269 | - break; | ||
270 | - case POST_TELEMETRY_REQUEST: | ||
271 | - handlePostTelemetryRequest(context, msg); | ||
272 | - reportActivity(); | ||
273 | - break; | ||
274 | - case TO_SERVER_RPC_REQUEST: | ||
275 | - handleClientSideRPCRequest(context, msg); | ||
276 | - reportActivity(); | ||
277 | - break; | ||
278 | - } | 255 | + if (msg.hasPostAttributes()) { |
256 | + handlePostAttributesRequest(context, msg.getSessionInfo(), msg.getPostAttributes()); | ||
257 | + reportActivity(); | ||
279 | } | 258 | } |
259 | + if (msg.hasPostTelemetry()) { | ||
260 | + handlePostTelemetryRequest(context, msg.getSessionInfo(), msg.getPostTelemetry()); | ||
261 | + reportActivity(); | ||
262 | + } | ||
263 | + if (msg.hasGetAttributes()) { | ||
264 | + handleGetAttributesRequest(context, msg.getSessionInfo(), msg.getGetAttributes()); | ||
265 | + } | ||
266 | +// SessionMsgType sessionMsgType = msg.getPayload().getMsgType(); | ||
267 | +// if (sessionMsgType.requiresRulesProcessing()) { | ||
268 | +// switch (sessionMsgType) { | ||
269 | +// case GET_ATTRIBUTES_REQUEST: | ||
270 | +// handleGetAttributesRequest(msg); | ||
271 | +// break; | ||
272 | +// case TO_SERVER_RPC_REQUEST: | ||
273 | +// handleClientSideRPCRequest(context, msg); | ||
274 | +// reportActivity(); | ||
275 | +// break; | ||
276 | +// } | ||
277 | +// } | ||
280 | } | 278 | } |
281 | 279 | ||
282 | private void reportActivity() { | 280 | private void reportActivity() { |
@@ -291,6 +289,39 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | @@ -291,6 +289,39 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | ||
291 | systemContext.getDeviceStateService().onDeviceDisconnect(deviceId); | 289 | systemContext.getDeviceStateService().onDeviceDisconnect(deviceId); |
292 | } | 290 | } |
293 | 291 | ||
292 | + private void handleGetAttributesRequest(ActorContext context, SessionInfoProto sessionInfo, GetAttributeRequestMsg request) { | ||
293 | + ListenableFuture<List<AttributeKvEntry>> clientAttributesFuture = getAttributeKvEntries(deviceId, DataConstants.CLIENT_SCOPE, toOptionalSet(request.getClientAttributeNamesList())); | ||
294 | + ListenableFuture<List<AttributeKvEntry>> sharedAttributesFuture = getAttributeKvEntries(deviceId, DataConstants.SHARED_SCOPE, toOptionalSet(request.getSharedAttributeNamesList())); | ||
295 | + | ||
296 | + Futures.addCallback(Futures.allAsList(Arrays.asList(clientAttributesFuture, sharedAttributesFuture)), new FutureCallback<List<List<AttributeKvEntry>>>() { | ||
297 | + @Override | ||
298 | + public void onSuccess(@Nullable List<List<AttributeKvEntry>> result) { | ||
299 | + systemContext.getRuleEngineTransportService().process(); | ||
300 | + BasicGetAttributesResponse response = BasicGetAttributesResponse.onSuccess(request.getMsgType(), | ||
301 | + request.getRequestId(), BasicAttributeKVMsg.from(result.get(0), result.get(1))); | ||
302 | + sendMsgToSessionActor(new BasicActorSystemToDeviceSessionActorMsg(response, src.getSessionId()), src.getServerAddress()); | ||
303 | + } | ||
304 | + | ||
305 | + @Override | ||
306 | + public void onFailure(Throwable t) { | ||
307 | + if (t instanceof Exception) { | ||
308 | + ToDeviceMsg toDeviceMsg = BasicStatusCodeResponse.onError(SessionMsgType.GET_ATTRIBUTES_REQUEST, request.getRequestId(), (Exception) t); | ||
309 | + sendMsgToSessionActor(new BasicActorSystemToDeviceSessionActorMsg(toDeviceMsg, src.getSessionId()), src.getServerAddress()); | ||
310 | + } else { | ||
311 | + logger.error("[{}] Failed to process attributes request", deviceId, t); | ||
312 | + } | ||
313 | + } | ||
314 | + }); | ||
315 | + } | ||
316 | + | ||
317 | + private Optional<Set<String>> toOptionalSet(List<String> strings) { | ||
318 | + if (strings == null || strings.isEmpty()) { | ||
319 | + return Optional.empty(); | ||
320 | + } else { | ||
321 | + return Optional.of(new HashSet<>(strings)); | ||
322 | + } | ||
323 | + } | ||
324 | + | ||
294 | private void handleGetAttributesRequest(DeviceToDeviceActorMsg src) { | 325 | private void handleGetAttributesRequest(DeviceToDeviceActorMsg src) { |
295 | GetAttributesRequest request = (GetAttributesRequest) src.getPayload(); | 326 | GetAttributesRequest request = (GetAttributesRequest) src.getPayload(); |
296 | ListenableFuture<List<AttributeKvEntry>> clientAttributesFuture = getAttributeKvEntries(deviceId, DataConstants.CLIENT_SCOPE, request.getClientAttributeNames()); | 327 | ListenableFuture<List<AttributeKvEntry>> clientAttributesFuture = getAttributeKvEntries(deviceId, DataConstants.CLIENT_SCOPE, request.getClientAttributeNames()); |
@@ -328,43 +359,20 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | @@ -328,43 +359,20 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | ||
328 | } | 359 | } |
329 | } | 360 | } |
330 | 361 | ||
331 | - private void handlePostAttributesRequest(ActorContext context, DeviceToDeviceActorMsg src) { | ||
332 | - AttributesUpdateRequest request = (AttributesUpdateRequest) src.getPayload(); | ||
333 | - | ||
334 | - JsonObject json = new JsonObject(); | ||
335 | - for (AttributeKvEntry kv : request.getAttributes()) { | ||
336 | - kv.getBooleanValue().ifPresent(v -> json.addProperty(kv.getKey(), v)); | ||
337 | - kv.getLongValue().ifPresent(v -> json.addProperty(kv.getKey(), v)); | ||
338 | - kv.getDoubleValue().ifPresent(v -> json.addProperty(kv.getKey(), v)); | ||
339 | - kv.getStrValue().ifPresent(v -> json.addProperty(kv.getKey(), v)); | ||
340 | - } | ||
341 | - | ||
342 | - TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), deviceId, defaultMetaData.copy(), TbMsgDataType.JSON, gson.toJson(json), null, null, 0L); | ||
343 | - PendingSessionMsgData msgData = new PendingSessionMsgData(src.getSessionId(), src.getServerAddress(), | ||
344 | - SessionMsgType.POST_ATTRIBUTES_REQUEST, request.getRequestId(), true, 1); | ||
345 | - pushToRuleEngineWithTimeout(context, tbMsg, msgData); | 362 | + private void handlePostAttributesRequest(ActorContext context, SessionInfoProto sessionInfo, PostAttributeMsg postAttributes) { |
363 | + JsonObject json = getJsonObject(postAttributes.getKvList()); | ||
364 | + TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), deviceId, defaultMetaData.copy(), | ||
365 | + TbMsgDataType.JSON, gson.toJson(json), null, null, 0L); | ||
366 | + pushToRuleEngine(context, tbMsg); | ||
346 | } | 367 | } |
347 | 368 | ||
348 | - private void handlePostTelemetryRequest(ActorContext context, DeviceToDeviceActorMsg src) { | ||
349 | - TelemetryUploadRequest request = (TelemetryUploadRequest) src.getPayload(); | ||
350 | - | ||
351 | - Map<Long, List<KvEntry>> tsData = request.getData(); | ||
352 | - | ||
353 | - PendingSessionMsgData msgData = new PendingSessionMsgData(src.getSessionId(), src.getServerAddress(), | ||
354 | - SessionMsgType.POST_TELEMETRY_REQUEST, request.getRequestId(), true, tsData.size()); | ||
355 | - | ||
356 | - for (Map.Entry<Long, List<KvEntry>> entry : tsData.entrySet()) { | ||
357 | - JsonObject json = new JsonObject(); | ||
358 | - for (KvEntry kv : entry.getValue()) { | ||
359 | - kv.getBooleanValue().ifPresent(v -> json.addProperty(kv.getKey(), v)); | ||
360 | - kv.getLongValue().ifPresent(v -> json.addProperty(kv.getKey(), v)); | ||
361 | - kv.getDoubleValue().ifPresent(v -> json.addProperty(kv.getKey(), v)); | ||
362 | - kv.getStrValue().ifPresent(v -> json.addProperty(kv.getKey(), v)); | ||
363 | - } | 369 | + private void handlePostTelemetryRequest(ActorContext context, SessionInfoProto sessionInfo, PostTelemetryMsg postTelemetry) { |
370 | + for (TsKvListProto tsKv : postTelemetry.getTsKvListList()) { | ||
371 | + JsonObject json = getJsonObject(tsKv.getKvList()); | ||
364 | TbMsgMetaData metaData = defaultMetaData.copy(); | 372 | TbMsgMetaData metaData = defaultMetaData.copy(); |
365 | - metaData.putValue("ts", entry.getKey() + ""); | 373 | + metaData.putValue("ts", tsKv.getTs() + ""); |
366 | TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.POST_TELEMETRY_REQUEST.name(), deviceId, metaData, TbMsgDataType.JSON, gson.toJson(json), null, null, 0L); | 374 | TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.POST_TELEMETRY_REQUEST.name(), deviceId, metaData, TbMsgDataType.JSON, gson.toJson(json), null, null, 0L); |
367 | - pushToRuleEngineWithTimeout(context, tbMsg, msgData); | 375 | + pushToRuleEngine(context, tbMsg); |
368 | } | 376 | } |
369 | } | 377 | } |
370 | 378 | ||
@@ -401,16 +409,7 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | @@ -401,16 +409,7 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | ||
401 | } | 409 | } |
402 | } | 410 | } |
403 | 411 | ||
404 | - private void pushToRuleEngineWithTimeout(ActorContext context, TbMsg tbMsg, PendingSessionMsgData pendingMsgData) { | ||
405 | - SessionMsgType sessionMsgType = pendingMsgData.getSessionMsgType(); | ||
406 | - int requestId = pendingMsgData.getRequestId(); | ||
407 | - if (systemContext.isQueuePersistenceEnabled()) { | ||
408 | - pendingMsgs.put(tbMsg.getId(), pendingMsgData); | ||
409 | - scheduleMsgWithDelay(context, new DeviceActorQueueTimeoutMsg(tbMsg.getId(), systemContext.getQueuePersistenceTimeout()), systemContext.getQueuePersistenceTimeout()); | ||
410 | - } else { | ||
411 | - ActorSystemToDeviceSessionActorMsg response = new BasicActorSystemToDeviceSessionActorMsg(BasicStatusCodeResponse.onSuccess(sessionMsgType, requestId), pendingMsgData.getSessionId()); | ||
412 | - sendMsgToSessionActor(response, pendingMsgData.getServerAddress()); | ||
413 | - } | 412 | + private void pushToRuleEngine(ActorContext context, TbMsg tbMsg) { |
414 | context.parent().tell(new DeviceActorToRuleEngineMsg(context.self(), tbMsg), context.self()); | 413 | context.parent().tell(new DeviceActorToRuleEngineMsg(context.self(), tbMsg), context.self()); |
415 | } | 414 | } |
416 | 415 | ||
@@ -497,13 +496,12 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | @@ -497,13 +496,12 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | ||
497 | } | 496 | } |
498 | } | 497 | } |
499 | 498 | ||
500 | - private void processSessionStateMsgs(DeviceToDeviceActorMsg msg) { | ||
501 | - SessionId sessionId = msg.getSessionId(); | ||
502 | - FromDeviceMsg inMsg = msg.getPayload(); | ||
503 | - if (inMsg instanceof SessionOpenMsg) { | 499 | + private void processSessionStateMsgs(SessionInfoProto sessionInfo, SessionEventMsg msg) { |
500 | + UUID sessionId = new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()); | ||
501 | + if (msg.getEvent() == SessionEvent.OPEN) { | ||
504 | logger.debug("[{}] Processing new session [{}]", deviceId, sessionId); | 502 | logger.debug("[{}] Processing new session [{}]", deviceId, sessionId); |
505 | if (sessions.size() >= systemContext.getMaxConcurrentSessionsPerDevice()) { | 503 | if (sessions.size() >= systemContext.getMaxConcurrentSessionsPerDevice()) { |
506 | - SessionId sessionIdToRemove = sessions.keySet().stream().findFirst().orElse(null); | 504 | + UUID sessionIdToRemove = sessions.keySet().stream().findFirst().orElse(null); |
507 | if (sessionIdToRemove != null) { | 505 | if (sessionIdToRemove != null) { |
508 | closeSession(sessionIdToRemove, sessions.remove(sessionIdToRemove)); | 506 | closeSession(sessionIdToRemove, sessions.remove(sessionIdToRemove)); |
509 | } | 507 | } |
@@ -512,6 +510,10 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | @@ -512,6 +510,10 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | ||
512 | if (sessions.size() == 1) { | 510 | if (sessions.size() == 1) { |
513 | reportSessionOpen(); | 511 | reportSessionOpen(); |
514 | } | 512 | } |
513 | + } | ||
514 | + FromDeviceMsg inMsg = msg.getPayload(); | ||
515 | + if (inMsg instanceof SessionOpenMsg) { | ||
516 | + logger.debug("[{}] Processing new session [{}]", deviceId, sessionId); | ||
515 | } else if (inMsg instanceof SessionCloseMsg) { | 517 | } else if (inMsg instanceof SessionCloseMsg) { |
516 | logger.debug("[{}] Canceling subscriptions for closed session [{}]", deviceId, sessionId); | 518 | logger.debug("[{}] Canceling subscriptions for closed session [{}]", deviceId, sessionId); |
517 | sessions.remove(sessionId); | 519 | sessions.remove(sessionId); |
@@ -540,8 +542,12 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | @@ -540,8 +542,12 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | ||
540 | rpcSubscriptions.clear(); | 542 | rpcSubscriptions.clear(); |
541 | } | 543 | } |
542 | 544 | ||
543 | - private void closeSession(SessionId sessionId, SessionInfo sessionInfo) { | ||
544 | - sendMsgToSessionActor(new BasicActorSystemToDeviceSessionActorMsg(new SessionCloseNotification(), sessionId), sessionInfo.getServer()); | 545 | + private void closeSession(UUID sessionId, SessionInfo sessionInfo) { |
546 | + DeviceActorToTransportMsg msg = DeviceActorToTransportMsg.newBuilder() | ||
547 | + .setSessionIdMSB(sessionId.getMostSignificantBits()) | ||
548 | + .setSessionIdLSB(sessionId.getLeastSignificantBits()) | ||
549 | + .setSessionCloseNotification(SessionCloseNotificationProto.getDefaultInstance()).build(); | ||
550 | + systemContext.getRuleEngineTransportService().process(sessionInfo.getNodeId(), msg); | ||
545 | } | 551 | } |
546 | 552 | ||
547 | void processNameOrTypeUpdate(DeviceNameOrTypeUpdateMsg msg) { | 553 | void processNameOrTypeUpdate(DeviceNameOrTypeUpdateMsg msg) { |
@@ -552,4 +558,24 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | @@ -552,4 +558,24 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | ||
552 | this.defaultMetaData.putValue("deviceType", deviceType); | 558 | this.defaultMetaData.putValue("deviceType", deviceType); |
553 | } | 559 | } |
554 | 560 | ||
561 | + private JsonObject getJsonObject(List<KeyValueProto> tsKv) { | ||
562 | + JsonObject json = new JsonObject(); | ||
563 | + for (KeyValueProto kv : tsKv) { | ||
564 | + switch (kv.getType()) { | ||
565 | + case BOOLEAN_V: | ||
566 | + json.addProperty(kv.getKey(), kv.getBoolV()); | ||
567 | + break; | ||
568 | + case LONG_V: | ||
569 | + json.addProperty(kv.getKey(), kv.getLongV()); | ||
570 | + break; | ||
571 | + case DOUBLE_V: | ||
572 | + json.addProperty(kv.getKey(), kv.getDoubleV()); | ||
573 | + break; | ||
574 | + case STRING_V: | ||
575 | + json.addProperty(kv.getKey(), kv.getStringV()); | ||
576 | + break; | ||
577 | + } | ||
578 | + } | ||
579 | + return json; | ||
580 | + } | ||
555 | } | 581 | } |
@@ -22,6 +22,7 @@ import org.thingsboard.server.common.msg.cluster.ServerAddress; | @@ -22,6 +22,7 @@ import org.thingsboard.server.common.msg.cluster.ServerAddress; | ||
22 | import org.thingsboard.server.common.msg.session.SessionMsgType; | 22 | import org.thingsboard.server.common.msg.session.SessionMsgType; |
23 | 23 | ||
24 | import java.util.Optional; | 24 | import java.util.Optional; |
25 | +import java.util.UUID; | ||
25 | 26 | ||
26 | /** | 27 | /** |
27 | * Created by ashvayka on 17.04.18. | 28 | * Created by ashvayka on 17.04.18. |
@@ -30,7 +31,7 @@ import java.util.Optional; | @@ -30,7 +31,7 @@ import java.util.Optional; | ||
30 | @AllArgsConstructor | 31 | @AllArgsConstructor |
31 | public final class PendingSessionMsgData { | 32 | public final class PendingSessionMsgData { |
32 | 33 | ||
33 | - private final SessionId sessionId; | 34 | + private final UUID sessionId; |
34 | private final Optional<ServerAddress> serverAddress; | 35 | private final Optional<ServerAddress> serverAddress; |
35 | private final SessionMsgType sessionMsgType; | 36 | private final SessionMsgType sessionMsgType; |
36 | private final int requestId; | 37 | private final int requestId; |
1 | /** | 1 | /** |
2 | * Copyright © 2016-2018 The Thingsboard Authors | 2 | * Copyright © 2016-2018 The Thingsboard Authors |
3 | - * | 3 | + * <p> |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. | 5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at | 6 | * You may obtain a copy of the License at |
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | 7 | + * <p> |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * <p> | ||
10 | * Unless required by applicable law or agreed to in writing, software | 10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
@@ -16,10 +16,7 @@ | @@ -16,10 +16,7 @@ | ||
16 | package org.thingsboard.server.actors.device; | 16 | package org.thingsboard.server.actors.device; |
17 | 17 | ||
18 | import lombok.Data; | 18 | import lombok.Data; |
19 | -import org.thingsboard.server.common.msg.cluster.ServerAddress; | ||
20 | -import org.thingsboard.server.common.msg.session.SessionType; | ||
21 | - | ||
22 | -import java.util.Optional; | 19 | +import org.thingsboard.server.gen.transport.TransportProtos.SessionType; |
23 | 20 | ||
24 | /** | 21 | /** |
25 | * @author Andrew Shvayka | 22 | * @author Andrew Shvayka |
@@ -27,5 +24,6 @@ import java.util.Optional; | @@ -27,5 +24,6 @@ import java.util.Optional; | ||
27 | @Data | 24 | @Data |
28 | public class SessionInfo { | 25 | public class SessionInfo { |
29 | private final SessionType type; | 26 | private final SessionType type; |
30 | - private final Optional<ServerAddress> server; | 27 | + private final String nodeId; |
28 | + | ||
31 | } | 29 | } |
application/src/main/java/org/thingsboard/server/actors/session/ASyncMsgProcessor.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.session; | ||
17 | - | ||
18 | -import akka.actor.ActorContext; | ||
19 | -import akka.event.LoggingAdapter; | ||
20 | -import org.thingsboard.server.actors.ActorSystemContext; | ||
21 | -import org.thingsboard.server.actors.shared.SessionTimeoutMsg; | ||
22 | -import org.thingsboard.server.common.data.id.SessionId; | ||
23 | -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | ||
24 | -import org.thingsboard.server.common.msg.cluster.ServerAddress; | ||
25 | -import org.thingsboard.server.common.msg.core.AttributesSubscribeMsg; | ||
26 | -import org.thingsboard.server.common.msg.core.ResponseMsg; | ||
27 | -import org.thingsboard.server.common.msg.core.RpcSubscribeMsg; | ||
28 | -import org.thingsboard.server.common.msg.core.SessionCloseMsg; | ||
29 | -import org.thingsboard.server.common.msg.core.SessionOpenMsg; | ||
30 | -import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; | ||
31 | -import org.thingsboard.server.common.msg.session.BasicSessionActorToAdaptorMsg; | ||
32 | -import org.thingsboard.server.common.msg.session.FromDeviceMsg; | ||
33 | -import org.thingsboard.server.common.msg.session.FromDeviceRequestMsg; | ||
34 | -import org.thingsboard.server.common.msg.session.SessionMsgType; | ||
35 | -import org.thingsboard.server.common.msg.session.SessionType; | ||
36 | -import org.thingsboard.server.common.msg.session.ToDeviceMsg; | ||
37 | -import org.thingsboard.server.common.msg.session.TransportToDeviceSessionActorMsg; | ||
38 | -import org.thingsboard.server.common.msg.session.ex.SessionException; | ||
39 | - | ||
40 | -import java.util.HashMap; | ||
41 | -import java.util.Map; | ||
42 | -import java.util.Optional; | ||
43 | - | ||
44 | -class ASyncMsgProcessor extends AbstractSessionActorMsgProcessor { | ||
45 | - | ||
46 | - private boolean firstMsg = true; | ||
47 | - private Map<Integer, DeviceToDeviceActorMsg> pendingMap = new HashMap<>(); | ||
48 | - private Optional<ServerAddress> currentTargetServer; | ||
49 | - private boolean subscribedToAttributeUpdates; | ||
50 | - private boolean subscribedToRpcCommands; | ||
51 | - | ||
52 | - public ASyncMsgProcessor(ActorSystemContext ctx, LoggingAdapter logger, SessionId sessionId) { | ||
53 | - super(ctx, logger, sessionId); | ||
54 | - } | ||
55 | - | ||
56 | - @Override | ||
57 | - protected void processToDeviceActorMsg(ActorContext ctx, TransportToDeviceSessionActorMsg msg) { | ||
58 | - updateSessionCtx(msg, SessionType.ASYNC); | ||
59 | - DeviceToDeviceActorMsg pendingMsg = toDeviceMsg(msg); | ||
60 | - FromDeviceMsg fromDeviceMsg = pendingMsg.getPayload(); | ||
61 | - if (firstMsg) { | ||
62 | - if (fromDeviceMsg.getMsgType() != SessionMsgType.SESSION_OPEN) { | ||
63 | - toDeviceMsg(new SessionOpenMsg()).ifPresent(m -> forwardToAppActor(ctx, m)); | ||
64 | - } | ||
65 | - firstMsg = false; | ||
66 | - } | ||
67 | - switch (fromDeviceMsg.getMsgType()) { | ||
68 | - case POST_TELEMETRY_REQUEST: | ||
69 | - case POST_ATTRIBUTES_REQUEST: | ||
70 | - FromDeviceRequestMsg requestMsg = (FromDeviceRequestMsg) fromDeviceMsg; | ||
71 | - if (requestMsg.getRequestId() >= 0) { | ||
72 | - logger.debug("[{}] Pending request {} registered", requestMsg.getRequestId(), requestMsg.getMsgType()); | ||
73 | - //TODO: handle duplicates. | ||
74 | - pendingMap.put(requestMsg.getRequestId(), pendingMsg); | ||
75 | - } | ||
76 | - break; | ||
77 | - case SUBSCRIBE_ATTRIBUTES_REQUEST: | ||
78 | - subscribedToAttributeUpdates = true; | ||
79 | - break; | ||
80 | - case UNSUBSCRIBE_ATTRIBUTES_REQUEST: | ||
81 | - subscribedToAttributeUpdates = false; | ||
82 | - break; | ||
83 | - case SUBSCRIBE_RPC_COMMANDS_REQUEST: | ||
84 | - subscribedToRpcCommands = true; | ||
85 | - break; | ||
86 | - case UNSUBSCRIBE_RPC_COMMANDS_REQUEST: | ||
87 | - subscribedToRpcCommands = false; | ||
88 | - break; | ||
89 | - default: | ||
90 | - break; | ||
91 | - } | ||
92 | - currentTargetServer = forwardToAppActor(ctx, pendingMsg); | ||
93 | - } | ||
94 | - | ||
95 | - @Override | ||
96 | - public void processToDeviceMsg(ActorContext context, ToDeviceMsg msg) { | ||
97 | - try { | ||
98 | - if (msg.getSessionMsgType() != SessionMsgType.SESSION_CLOSE) { | ||
99 | - switch (msg.getSessionMsgType()) { | ||
100 | - case STATUS_CODE_RESPONSE: | ||
101 | - case GET_ATTRIBUTES_RESPONSE: | ||
102 | - ResponseMsg responseMsg = (ResponseMsg) msg; | ||
103 | - if (responseMsg.getRequestId() >= 0) { | ||
104 | - logger.debug("[{}] Pending request processed: {}", responseMsg.getRequestId(), responseMsg); | ||
105 | - pendingMap.remove(responseMsg.getRequestId()); | ||
106 | - } | ||
107 | - break; | ||
108 | - default: | ||
109 | - break; | ||
110 | - } | ||
111 | - sessionCtx.onMsg(new BasicSessionActorToAdaptorMsg(this.sessionCtx, msg)); | ||
112 | - } else { | ||
113 | - sessionCtx.onMsg(org.thingsboard.server.common.msg.session.ctrl.SessionCloseMsg.onCredentialsRevoked(sessionCtx.getSessionId())); | ||
114 | - } | ||
115 | - } catch (SessionException e) { | ||
116 | - logger.warning("Failed to push session response msg", e); | ||
117 | - } | ||
118 | - } | ||
119 | - | ||
120 | - @Override | ||
121 | - public void processTimeoutMsg(ActorContext context, SessionTimeoutMsg msg) { | ||
122 | - // TODO Auto-generated method stub | ||
123 | - } | ||
124 | - | ||
125 | - @Override | ||
126 | - protected void cleanupSession(ActorContext ctx) { | ||
127 | - toDeviceMsg(new SessionCloseMsg()).ifPresent(m -> forwardToAppActor(ctx, m)); | ||
128 | - } | ||
129 | - | ||
130 | - @Override | ||
131 | - public void processClusterEvent(ActorContext context, ClusterEventMsg msg) { | ||
132 | - if (pendingMap.size() > 0 || subscribedToAttributeUpdates || subscribedToRpcCommands) { | ||
133 | - Optional<ServerAddress> newTargetServer = systemContext.getRoutingService().resolveById(getDeviceId()); | ||
134 | - if (!newTargetServer.equals(currentTargetServer)) { | ||
135 | - firstMsg = true; | ||
136 | - currentTargetServer = newTargetServer; | ||
137 | - pendingMap.values().forEach(v -> { | ||
138 | - forwardToAppActor(context, v, currentTargetServer); | ||
139 | - if (currentTargetServer.isPresent()) { | ||
140 | - logger.debug("[{}] Forwarded msg to new server: {}", sessionId, currentTargetServer.get()); | ||
141 | - } else { | ||
142 | - logger.debug("[{}] Forwarded msg to local server.", sessionId); | ||
143 | - } | ||
144 | - }); | ||
145 | - if (subscribedToAttributeUpdates) { | ||
146 | - toDeviceMsg(new AttributesSubscribeMsg()).ifPresent(m -> forwardToAppActor(context, m, currentTargetServer)); | ||
147 | - logger.debug("[{}] Forwarded attributes subscription.", sessionId); | ||
148 | - } | ||
149 | - if (subscribedToRpcCommands) { | ||
150 | - toDeviceMsg(new RpcSubscribeMsg()).ifPresent(m -> forwardToAppActor(context, m, currentTargetServer)); | ||
151 | - logger.debug("[{}] Forwarded rpc commands subscription.", sessionId); | ||
152 | - } | ||
153 | - } | ||
154 | - } | ||
155 | - } | ||
156 | -} |
application/src/main/java/org/thingsboard/server/actors/session/AbstractSessionActorMsgProcessor.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.session; | ||
17 | - | ||
18 | -import akka.actor.ActorContext; | ||
19 | -import akka.actor.ActorRef; | ||
20 | -import akka.event.LoggingAdapter; | ||
21 | -import org.thingsboard.server.actors.ActorSystemContext; | ||
22 | -import org.thingsboard.server.actors.shared.AbstractContextAwareMsgProcessor; | ||
23 | -import org.thingsboard.server.actors.shared.SessionTimeoutMsg; | ||
24 | -import org.thingsboard.server.common.data.id.DeviceId; | ||
25 | -import org.thingsboard.server.common.data.id.SessionId; | ||
26 | -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | ||
27 | -import org.thingsboard.server.common.msg.cluster.SendToClusterMsg; | ||
28 | -import org.thingsboard.server.common.msg.cluster.ServerAddress; | ||
29 | -import org.thingsboard.server.common.msg.device.BasicDeviceToDeviceActorMsg; | ||
30 | -import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; | ||
31 | -import org.thingsboard.server.common.msg.session.AdaptorToSessionActorMsg; | ||
32 | -import org.thingsboard.server.common.msg.session.FromDeviceMsg; | ||
33 | -import org.thingsboard.server.common.msg.session.SessionContext; | ||
34 | -import org.thingsboard.server.common.msg.session.SessionCtrlMsg; | ||
35 | -import org.thingsboard.server.common.msg.session.SessionType; | ||
36 | -import org.thingsboard.server.common.msg.session.ToDeviceMsg; | ||
37 | -import org.thingsboard.server.common.msg.session.TransportToDeviceSessionActorMsg; | ||
38 | -import org.thingsboard.server.common.msg.session.ctrl.SessionCloseMsg; | ||
39 | - | ||
40 | -import java.util.Optional; | ||
41 | - | ||
42 | -abstract class AbstractSessionActorMsgProcessor extends AbstractContextAwareMsgProcessor { | ||
43 | - | ||
44 | - protected final SessionId sessionId; | ||
45 | - protected SessionContext sessionCtx; | ||
46 | - protected DeviceToDeviceActorMsg deviceToDeviceActorMsgPrototype; | ||
47 | - | ||
48 | - protected AbstractSessionActorMsgProcessor(ActorSystemContext ctx, LoggingAdapter logger, SessionId sessionId) { | ||
49 | - super(ctx, logger); | ||
50 | - this.sessionId = sessionId; | ||
51 | - } | ||
52 | - | ||
53 | - protected abstract void processToDeviceActorMsg(ActorContext ctx, TransportToDeviceSessionActorMsg msg); | ||
54 | - | ||
55 | - protected abstract void processTimeoutMsg(ActorContext context, SessionTimeoutMsg msg); | ||
56 | - | ||
57 | - protected abstract void processToDeviceMsg(ActorContext context, ToDeviceMsg msg); | ||
58 | - | ||
59 | - public abstract void processClusterEvent(ActorContext context, ClusterEventMsg msg); | ||
60 | - | ||
61 | - protected void processSessionCtrlMsg(ActorContext ctx, SessionCtrlMsg msg) { | ||
62 | - if (msg instanceof SessionCloseMsg) { | ||
63 | - cleanupSession(ctx); | ||
64 | - terminateSession(ctx, sessionId); | ||
65 | - } | ||
66 | - } | ||
67 | - | ||
68 | - protected void cleanupSession(ActorContext ctx) { | ||
69 | - } | ||
70 | - | ||
71 | - protected void updateSessionCtx(TransportToDeviceSessionActorMsg msg, SessionType type) { | ||
72 | - sessionCtx = msg.getSessionMsg().getSessionContext(); | ||
73 | - deviceToDeviceActorMsgPrototype = new BasicDeviceToDeviceActorMsg(msg, type); | ||
74 | - } | ||
75 | - | ||
76 | - protected DeviceToDeviceActorMsg toDeviceMsg(TransportToDeviceSessionActorMsg msg) { | ||
77 | - AdaptorToSessionActorMsg adaptorMsg = msg.getSessionMsg(); | ||
78 | - return new BasicDeviceToDeviceActorMsg(deviceToDeviceActorMsgPrototype, adaptorMsg.getMsg()); | ||
79 | - } | ||
80 | - | ||
81 | - protected Optional<DeviceToDeviceActorMsg> toDeviceMsg(FromDeviceMsg msg) { | ||
82 | - if (deviceToDeviceActorMsgPrototype != null) { | ||
83 | - return Optional.of(new BasicDeviceToDeviceActorMsg(deviceToDeviceActorMsgPrototype, msg)); | ||
84 | - } else { | ||
85 | - return Optional.empty(); | ||
86 | - } | ||
87 | - } | ||
88 | - | ||
89 | - protected Optional<ServerAddress> forwardToAppActor(ActorContext ctx, DeviceToDeviceActorMsg toForward) { | ||
90 | - Optional<ServerAddress> address = systemContext.getRoutingService().resolveById(toForward.getDeviceId()); | ||
91 | - forwardToAppActor(ctx, toForward, address); | ||
92 | - return address; | ||
93 | - } | ||
94 | - | ||
95 | - protected Optional<ServerAddress> forwardToAppActorIfAddressChanged(ActorContext ctx, DeviceToDeviceActorMsg toForward, Optional<ServerAddress> oldAddress) { | ||
96 | - | ||
97 | - Optional<ServerAddress> newAddress = systemContext.getRoutingService().resolveById(toForward.getDeviceId()); | ||
98 | - if (!newAddress.equals(oldAddress)) { | ||
99 | - getAppActor().tell(new SendToClusterMsg(toForward.getDeviceId(), toForward | ||
100 | - .toOtherAddress(systemContext.getRoutingService().getCurrentServer())), ctx.self()); | ||
101 | - } | ||
102 | - return newAddress; | ||
103 | - } | ||
104 | - | ||
105 | - protected void forwardToAppActor(ActorContext ctx, DeviceToDeviceActorMsg toForward, Optional<ServerAddress> address) { | ||
106 | - if (address.isPresent()) { | ||
107 | - systemContext.getRpcService().tell(systemContext.getEncodingService().convertToProtoDataMessage(address.get(), | ||
108 | - toForward.toOtherAddress(systemContext.getRoutingService().getCurrentServer()))); | ||
109 | - } else { | ||
110 | - getAppActor().tell(toForward, ctx.self()); | ||
111 | - } | ||
112 | - } | ||
113 | - | ||
114 | - public static void terminateSession(ActorContext ctx, SessionId sessionId) { | ||
115 | - ctx.parent().tell(new SessionTerminationMsg(sessionId), ActorRef.noSender()); | ||
116 | - ctx.stop(ctx.self()); | ||
117 | - } | ||
118 | - | ||
119 | - public DeviceId getDeviceId() { | ||
120 | - return deviceToDeviceActorMsgPrototype.getDeviceId(); | ||
121 | - } | ||
122 | -} |
application/src/main/java/org/thingsboard/server/actors/session/SessionActor.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.session; | ||
17 | - | ||
18 | -import akka.actor.OneForOneStrategy; | ||
19 | -import akka.actor.SupervisorStrategy; | ||
20 | -import akka.event.Logging; | ||
21 | -import akka.event.LoggingAdapter; | ||
22 | -import org.thingsboard.server.actors.ActorSystemContext; | ||
23 | -import org.thingsboard.server.actors.service.ContextAwareActor; | ||
24 | -import org.thingsboard.server.actors.service.ContextBasedCreator; | ||
25 | -import org.thingsboard.server.actors.shared.SessionTimeoutMsg; | ||
26 | -import org.thingsboard.server.common.data.id.SessionId; | ||
27 | -import org.thingsboard.server.common.msg.TbActorMsg; | ||
28 | -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | ||
29 | -import org.thingsboard.server.common.msg.core.ActorSystemToDeviceSessionActorMsg; | ||
30 | -import org.thingsboard.server.common.msg.session.SessionCtrlMsg; | ||
31 | -import org.thingsboard.server.common.msg.session.SessionMsg; | ||
32 | -import org.thingsboard.server.common.msg.session.SessionType; | ||
33 | -import org.thingsboard.server.common.msg.session.TransportToDeviceSessionActorMsg; | ||
34 | -import org.thingsboard.server.common.msg.session.ctrl.SessionCloseMsg; | ||
35 | -import scala.concurrent.duration.Duration; | ||
36 | - | ||
37 | -public class SessionActor extends ContextAwareActor { | ||
38 | - | ||
39 | - private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); | ||
40 | - | ||
41 | - private final SessionId sessionId; | ||
42 | - private AbstractSessionActorMsgProcessor processor; | ||
43 | - | ||
44 | - private SessionActor(ActorSystemContext systemContext, SessionId sessionId) { | ||
45 | - super(systemContext); | ||
46 | - this.sessionId = sessionId; | ||
47 | - } | ||
48 | - | ||
49 | - @Override | ||
50 | - public SupervisorStrategy supervisorStrategy() { | ||
51 | - return new OneForOneStrategy(-1, Duration.Inf(), | ||
52 | - throwable -> { | ||
53 | - logger.error(throwable, "Unknown session error"); | ||
54 | - if (throwable instanceof Error) { | ||
55 | - return OneForOneStrategy.escalate(); | ||
56 | - } else { | ||
57 | - return OneForOneStrategy.resume(); | ||
58 | - } | ||
59 | - }); | ||
60 | - } | ||
61 | - | ||
62 | - @Override | ||
63 | - protected boolean process(TbActorMsg msg) { | ||
64 | - switch (msg.getMsgType()) { | ||
65 | - case TRANSPORT_TO_DEVICE_SESSION_ACTOR_MSG: | ||
66 | - processTransportToSessionMsg((TransportToDeviceSessionActorMsg) msg); | ||
67 | - break; | ||
68 | - case ACTOR_SYSTEM_TO_DEVICE_SESSION_ACTOR_MSG: | ||
69 | - processActorsToSessionMsg((ActorSystemToDeviceSessionActorMsg) msg); | ||
70 | - break; | ||
71 | - case SESSION_TIMEOUT_MSG: | ||
72 | - processTimeoutMsg((SessionTimeoutMsg) msg); | ||
73 | - break; | ||
74 | - case SESSION_CTRL_MSG: | ||
75 | - processSessionCloseMsg((SessionCtrlMsg) msg); | ||
76 | - break; | ||
77 | - case CLUSTER_EVENT_MSG: | ||
78 | - processClusterEvent((ClusterEventMsg) msg); | ||
79 | - break; | ||
80 | - default: return false; | ||
81 | - } | ||
82 | - return true; | ||
83 | - } | ||
84 | - | ||
85 | - private void processClusterEvent(ClusterEventMsg msg) { | ||
86 | - processor.processClusterEvent(context(), msg); | ||
87 | - } | ||
88 | - | ||
89 | - private void processTransportToSessionMsg(TransportToDeviceSessionActorMsg msg) { | ||
90 | - initProcessor(msg); | ||
91 | - processor.processToDeviceActorMsg(context(), msg); | ||
92 | - } | ||
93 | - | ||
94 | - private void processActorsToSessionMsg(ActorSystemToDeviceSessionActorMsg msg) { | ||
95 | - processor.processToDeviceMsg(context(), msg.getMsg()); | ||
96 | - } | ||
97 | - | ||
98 | - private void processTimeoutMsg(SessionTimeoutMsg msg) { | ||
99 | - if (processor != null) { | ||
100 | - processor.processTimeoutMsg(context(), msg); | ||
101 | - } else { | ||
102 | - logger.warning("[{}] Can't process timeout msg: {} without processor", sessionId, msg); | ||
103 | - } | ||
104 | - } | ||
105 | - | ||
106 | - private void processSessionCloseMsg(SessionCtrlMsg msg) { | ||
107 | - if (processor != null) { | ||
108 | - processor.processSessionCtrlMsg(context(), msg); | ||
109 | - } else if (msg instanceof SessionCloseMsg) { | ||
110 | - AbstractSessionActorMsgProcessor.terminateSession(context(), sessionId); | ||
111 | - } else { | ||
112 | - logger.warning("[{}] Can't process session ctrl msg: {} without processor", sessionId, msg); | ||
113 | - } | ||
114 | - } | ||
115 | - | ||
116 | - private void initProcessor(TransportToDeviceSessionActorMsg msg) { | ||
117 | - if (processor == null) { | ||
118 | - SessionMsg sessionMsg = (SessionMsg) msg.getSessionMsg(); | ||
119 | - if (sessionMsg.getSessionContext().getSessionType() == SessionType.SYNC) { | ||
120 | - processor = new SyncMsgProcessor(systemContext, logger, sessionId); | ||
121 | - } else { | ||
122 | - processor = new ASyncMsgProcessor(systemContext, logger, sessionId); | ||
123 | - } | ||
124 | - } | ||
125 | - } | ||
126 | - | ||
127 | - public static class ActorCreator extends ContextBasedCreator<SessionActor> { | ||
128 | - private static final long serialVersionUID = 1L; | ||
129 | - | ||
130 | - private final SessionId sessionId; | ||
131 | - | ||
132 | - public ActorCreator(ActorSystemContext context, SessionId sessionId) { | ||
133 | - super(context); | ||
134 | - this.sessionId = sessionId; | ||
135 | - } | ||
136 | - | ||
137 | - @Override | ||
138 | - public SessionActor create() throws Exception { | ||
139 | - return new SessionActor(context, sessionId); | ||
140 | - } | ||
141 | - } | ||
142 | - | ||
143 | -} |
application/src/main/java/org/thingsboard/server/actors/session/SessionManagerActor.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.session; | ||
17 | - | ||
18 | -import akka.actor.ActorInitializationException; | ||
19 | -import akka.actor.ActorRef; | ||
20 | -import akka.actor.InvalidActorNameException; | ||
21 | -import akka.actor.LocalActorRef; | ||
22 | -import akka.actor.OneForOneStrategy; | ||
23 | -import akka.actor.Props; | ||
24 | -import akka.actor.SupervisorStrategy; | ||
25 | -import akka.actor.Terminated; | ||
26 | -import akka.event.Logging; | ||
27 | -import akka.event.LoggingAdapter; | ||
28 | -import akka.japi.Function; | ||
29 | -import org.thingsboard.server.actors.ActorSystemContext; | ||
30 | -import org.thingsboard.server.actors.service.ContextAwareActor; | ||
31 | -import org.thingsboard.server.actors.service.ContextBasedCreator; | ||
32 | -import org.thingsboard.server.actors.service.DefaultActorService; | ||
33 | -import org.thingsboard.server.actors.shared.SessionTimeoutMsg; | ||
34 | -import org.thingsboard.server.common.data.id.SessionId; | ||
35 | -import org.thingsboard.server.common.msg.TbActorMsg; | ||
36 | -import org.thingsboard.server.common.msg.aware.SessionAwareMsg; | ||
37 | -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | ||
38 | -import org.thingsboard.server.common.msg.core.ActorSystemToDeviceSessionActorMsg; | ||
39 | -import org.thingsboard.server.common.msg.core.SessionCloseMsg; | ||
40 | -import org.thingsboard.server.common.msg.session.SessionCtrlMsg; | ||
41 | -import scala.concurrent.duration.Duration; | ||
42 | - | ||
43 | -import java.util.HashMap; | ||
44 | -import java.util.Map; | ||
45 | - | ||
46 | -public class SessionManagerActor extends ContextAwareActor { | ||
47 | - | ||
48 | - private static final int INITIAL_SESSION_MAP_SIZE = 1024; | ||
49 | - | ||
50 | - private final LoggingAdapter log = Logging.getLogger(getContext().system(), this); | ||
51 | - | ||
52 | - private final Map<String, ActorRef> sessionActors; | ||
53 | - | ||
54 | - SessionManagerActor(ActorSystemContext systemContext) { | ||
55 | - super(systemContext); | ||
56 | - this.sessionActors = new HashMap<>(INITIAL_SESSION_MAP_SIZE); | ||
57 | - } | ||
58 | - | ||
59 | - @Override | ||
60 | - public SupervisorStrategy supervisorStrategy() { | ||
61 | - return strategy; | ||
62 | - } | ||
63 | - | ||
64 | - @Override | ||
65 | - protected boolean process(TbActorMsg msg) { | ||
66 | - //TODO Move everything here, to work with TbActorMsg | ||
67 | - return false; | ||
68 | - } | ||
69 | - | ||
70 | - @Override | ||
71 | - public void onReceive(Object msg) throws Exception { | ||
72 | - if (msg instanceof SessionCtrlMsg) { | ||
73 | - onSessionCtrlMsg((SessionCtrlMsg) msg); | ||
74 | - } else if (msg instanceof SessionAwareMsg) { | ||
75 | - forwardToSessionActor((SessionAwareMsg) msg); | ||
76 | - } else if (msg instanceof SessionTerminationMsg) { | ||
77 | - onSessionTermination((SessionTerminationMsg) msg); | ||
78 | - } else if (msg instanceof Terminated) { | ||
79 | - onTermination((Terminated) msg); | ||
80 | - } else if (msg instanceof SessionTimeoutMsg) { | ||
81 | - onSessionTimeout((SessionTimeoutMsg) msg); | ||
82 | - } else if (msg instanceof ClusterEventMsg) { | ||
83 | - broadcast(msg); | ||
84 | - } | ||
85 | - } | ||
86 | - | ||
87 | - private void broadcast(Object msg) { | ||
88 | - sessionActors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender())); | ||
89 | - } | ||
90 | - | ||
91 | - private void onSessionTimeout(SessionTimeoutMsg msg) { | ||
92 | - String sessionIdStr = msg.getSessionId().toUidStr(); | ||
93 | - ActorRef sessionActor = sessionActors.get(sessionIdStr); | ||
94 | - if (sessionActor != null) { | ||
95 | - sessionActor.tell(msg, ActorRef.noSender()); | ||
96 | - } | ||
97 | - } | ||
98 | - | ||
99 | - private void onSessionCtrlMsg(SessionCtrlMsg msg) { | ||
100 | - String sessionIdStr = msg.getSessionId().toUidStr(); | ||
101 | - ActorRef sessionActor = sessionActors.get(sessionIdStr); | ||
102 | - if (sessionActor != null) { | ||
103 | - sessionActor.tell(msg, ActorRef.noSender()); | ||
104 | - } | ||
105 | - } | ||
106 | - | ||
107 | - private void onSessionTermination(SessionTerminationMsg msg) { | ||
108 | - String sessionIdStr = msg.getId().toUidStr(); | ||
109 | - ActorRef sessionActor = sessionActors.remove(sessionIdStr); | ||
110 | - if (sessionActor != null) { | ||
111 | - log.debug("[{}] Removed session actor.", sessionIdStr); | ||
112 | - //TODO: onSubscriptionUpdate device actor about session close; | ||
113 | - } else { | ||
114 | - log.debug("[{}] Session actor was already removed.", sessionIdStr); | ||
115 | - } | ||
116 | - } | ||
117 | - | ||
118 | - private void forwardToSessionActor(SessionAwareMsg msg) { | ||
119 | - if (msg instanceof ActorSystemToDeviceSessionActorMsg || msg instanceof SessionCloseMsg) { | ||
120 | - String sessionIdStr = msg.getSessionId().toUidStr(); | ||
121 | - ActorRef sessionActor = sessionActors.get(sessionIdStr); | ||
122 | - if (sessionActor != null) { | ||
123 | - sessionActor.tell(msg, ActorRef.noSender()); | ||
124 | - } else { | ||
125 | - log.debug("[{}] Session actor was already removed.", sessionIdStr); | ||
126 | - } | ||
127 | - } else { | ||
128 | - try { | ||
129 | - getOrCreateSessionActor(msg.getSessionId()).tell(msg, self()); | ||
130 | - } catch (InvalidActorNameException e) { | ||
131 | - log.info("Invalid msg : {}", msg); | ||
132 | - } | ||
133 | - } | ||
134 | - } | ||
135 | - | ||
136 | - private ActorRef getOrCreateSessionActor(SessionId sessionId) { | ||
137 | - String sessionIdStr = sessionId.toUidStr(); | ||
138 | - ActorRef sessionActor = sessionActors.get(sessionIdStr); | ||
139 | - if (sessionActor == null) { | ||
140 | - log.debug("[{}] Creating session actor.", sessionIdStr); | ||
141 | - sessionActor = context().actorOf( | ||
142 | - Props.create(new SessionActor.ActorCreator(systemContext, sessionId)).withDispatcher(DefaultActorService.SESSION_DISPATCHER_NAME), | ||
143 | - sessionIdStr); | ||
144 | - sessionActors.put(sessionIdStr, sessionActor); | ||
145 | - log.debug("[{}] Created session actor.", sessionIdStr); | ||
146 | - } | ||
147 | - return sessionActor; | ||
148 | - } | ||
149 | - | ||
150 | - private void onTermination(Terminated message) { | ||
151 | - ActorRef terminated = message.actor(); | ||
152 | - if (terminated instanceof LocalActorRef) { | ||
153 | - log.info("Removed actor: {}.", terminated); | ||
154 | - //TODO: cleanup session actors map | ||
155 | - } else { | ||
156 | - throw new IllegalStateException("Remote actors are not supported!"); | ||
157 | - } | ||
158 | - } | ||
159 | - | ||
160 | - public static class ActorCreator extends ContextBasedCreator<SessionManagerActor> { | ||
161 | - private static final long serialVersionUID = 1L; | ||
162 | - | ||
163 | - public ActorCreator(ActorSystemContext context) { | ||
164 | - super(context); | ||
165 | - } | ||
166 | - | ||
167 | - @Override | ||
168 | - public SessionManagerActor create() throws Exception { | ||
169 | - return new SessionManagerActor(context); | ||
170 | - } | ||
171 | - } | ||
172 | - | ||
173 | - private final SupervisorStrategy strategy = new OneForOneStrategy(3, Duration.create("1 minute"), new Function<Throwable, SupervisorStrategy.Directive>() { | ||
174 | - @Override | ||
175 | - public SupervisorStrategy.Directive apply(Throwable t) { | ||
176 | - logger.error(t, "Unknown failure"); | ||
177 | - return SupervisorStrategy.stop(); | ||
178 | - } | ||
179 | - }); | ||
180 | -} |
application/src/main/java/org/thingsboard/server/actors/session/SyncMsgProcessor.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.session; | ||
17 | - | ||
18 | -import akka.actor.ActorContext; | ||
19 | -import akka.event.LoggingAdapter; | ||
20 | -import org.thingsboard.server.actors.ActorSystemContext; | ||
21 | -import org.thingsboard.server.actors.shared.SessionTimeoutMsg; | ||
22 | -import org.thingsboard.server.common.data.id.SessionId; | ||
23 | -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | ||
24 | -import org.thingsboard.server.common.msg.cluster.ServerAddress; | ||
25 | -import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; | ||
26 | -import org.thingsboard.server.common.msg.session.BasicSessionActorToAdaptorMsg; | ||
27 | -import org.thingsboard.server.common.msg.session.SessionContext; | ||
28 | -import org.thingsboard.server.common.msg.session.SessionType; | ||
29 | -import org.thingsboard.server.common.msg.session.ToDeviceMsg; | ||
30 | -import org.thingsboard.server.common.msg.session.TransportToDeviceSessionActorMsg; | ||
31 | -import org.thingsboard.server.common.msg.session.ctrl.SessionCloseMsg; | ||
32 | -import org.thingsboard.server.common.msg.session.ex.SessionException; | ||
33 | - | ||
34 | -import java.util.Optional; | ||
35 | - | ||
36 | -class SyncMsgProcessor extends AbstractSessionActorMsgProcessor { | ||
37 | - private DeviceToDeviceActorMsg pendingMsg; | ||
38 | - private Optional<ServerAddress> currentTargetServer; | ||
39 | - private boolean pendingResponse; | ||
40 | - | ||
41 | - public SyncMsgProcessor(ActorSystemContext ctx, LoggingAdapter logger, SessionId sessionId) { | ||
42 | - super(ctx, logger, sessionId); | ||
43 | - } | ||
44 | - | ||
45 | - @Override | ||
46 | - protected void processToDeviceActorMsg(ActorContext ctx, TransportToDeviceSessionActorMsg msg) { | ||
47 | - updateSessionCtx(msg, SessionType.SYNC); | ||
48 | - pendingMsg = toDeviceMsg(msg); | ||
49 | - pendingResponse = true; | ||
50 | - currentTargetServer = forwardToAppActor(ctx, pendingMsg); | ||
51 | - scheduleMsgWithDelay(ctx, new SessionTimeoutMsg(sessionId), getTimeout(systemContext, msg.getSessionMsg().getSessionContext()), ctx.parent()); | ||
52 | - } | ||
53 | - | ||
54 | - public void processTimeoutMsg(ActorContext context, SessionTimeoutMsg msg) { | ||
55 | - if (pendingResponse) { | ||
56 | - try { | ||
57 | - sessionCtx.onMsg(SessionCloseMsg.onTimeout(sessionId)); | ||
58 | - } catch (SessionException e) { | ||
59 | - logger.warning("Failed to push session close msg", e); | ||
60 | - } | ||
61 | - terminateSession(context, this.sessionId); | ||
62 | - } | ||
63 | - } | ||
64 | - | ||
65 | - public void processToDeviceMsg(ActorContext context, ToDeviceMsg msg) { | ||
66 | - try { | ||
67 | - sessionCtx.onMsg(new BasicSessionActorToAdaptorMsg(this.sessionCtx, msg)); | ||
68 | - pendingResponse = false; | ||
69 | - } catch (SessionException e) { | ||
70 | - logger.warning("Failed to push session response msg", e); | ||
71 | - } | ||
72 | - terminateSession(context, this.sessionId); | ||
73 | - } | ||
74 | - | ||
75 | - @Override | ||
76 | - public void processClusterEvent(ActorContext context, ClusterEventMsg msg) { | ||
77 | - if (pendingResponse) { | ||
78 | - Optional<ServerAddress> newTargetServer = forwardToAppActorIfAddressChanged(context, pendingMsg, currentTargetServer); | ||
79 | - if (logger.isDebugEnabled()) { | ||
80 | - if (!newTargetServer.equals(currentTargetServer)) { | ||
81 | - if (newTargetServer.isPresent()) { | ||
82 | - logger.debug("[{}] Forwarded msg to new server: {}", sessionId, newTargetServer.get()); | ||
83 | - } else { | ||
84 | - logger.debug("[{}] Forwarded msg to local server.", sessionId); | ||
85 | - } | ||
86 | - } | ||
87 | - } | ||
88 | - currentTargetServer = newTargetServer; | ||
89 | - } | ||
90 | - } | ||
91 | - | ||
92 | - private long getTimeout(ActorSystemContext ctx, SessionContext sessionCtx) { | ||
93 | - return sessionCtx.getTimeout() > 0 ? sessionCtx.getTimeout() : ctx.getSyncSessionTimeout(); | ||
94 | - } | ||
95 | -} |
@@ -87,7 +87,7 @@ public class TenantActor extends RuleChainManagerActor { | @@ -87,7 +87,7 @@ public class TenantActor extends RuleChainManagerActor { | ||
87 | case DEVICE_ACTOR_TO_RULE_ENGINE_MSG: | 87 | case DEVICE_ACTOR_TO_RULE_ENGINE_MSG: |
88 | onDeviceActorToRuleEngineMsg((DeviceActorToRuleEngineMsg) msg); | 88 | onDeviceActorToRuleEngineMsg((DeviceActorToRuleEngineMsg) msg); |
89 | break; | 89 | break; |
90 | - case DEVICE_SESSION_TO_DEVICE_ACTOR_MSG: | 90 | + case TRANSPORT_TO_DEVICE_ACTOR_MSG: |
91 | case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: | 91 | case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: |
92 | case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG: | 92 | case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG: |
93 | case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG: | 93 | case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG: |
1 | +package org.thingsboard.server.service.transport; | ||
2 | + | ||
3 | +import akka.actor.ActorRef; | ||
4 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
5 | +import lombok.extern.slf4j.Slf4j; | ||
6 | +import org.apache.kafka.clients.consumer.ConsumerRecords; | ||
7 | +import org.apache.kafka.clients.producer.Callback; | ||
8 | +import org.apache.kafka.clients.producer.RecordMetadata; | ||
9 | +import org.springframework.beans.factory.annotation.Autowired; | ||
10 | +import org.springframework.beans.factory.annotation.Value; | ||
11 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | ||
12 | +import org.springframework.stereotype.Service; | ||
13 | +import org.thingsboard.server.actors.ActorSystemContext; | ||
14 | +import org.thingsboard.server.actors.service.ActorService; | ||
15 | +import org.thingsboard.server.common.msg.cluster.ServerAddress; | ||
16 | +import org.thingsboard.server.gen.transport.TransportProtos.DeviceActorToTransportMsg; | ||
17 | +import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; | ||
18 | +import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; | ||
19 | +import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg; | ||
20 | +import org.thingsboard.server.kafka.TBKafkaConsumerTemplate; | ||
21 | +import org.thingsboard.server.kafka.TBKafkaProducerTemplate; | ||
22 | +import org.thingsboard.server.kafka.TbKafkaSettings; | ||
23 | +import org.thingsboard.server.service.cluster.discovery.DiscoveryService; | ||
24 | +import org.thingsboard.server.service.cluster.routing.ClusterRoutingService; | ||
25 | +import org.thingsboard.server.service.cluster.rpc.ClusterRpcService; | ||
26 | +import org.thingsboard.server.service.encoding.DataDecodingEncodingService; | ||
27 | +import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; | ||
28 | + | ||
29 | +import javax.annotation.PostConstruct; | ||
30 | +import javax.annotation.PreDestroy; | ||
31 | +import java.time.Duration; | ||
32 | +import java.util.Optional; | ||
33 | +import java.util.concurrent.ExecutorService; | ||
34 | +import java.util.concurrent.Executors; | ||
35 | +import java.util.function.Consumer; | ||
36 | + | ||
37 | +/** | ||
38 | + * Created by ashvayka on 09.10.18. | ||
39 | + */ | ||
40 | +@Slf4j | ||
41 | +@Service | ||
42 | +@ConditionalOnProperty(prefix = "transport.remote", value = "enabled", havingValue = "true") | ||
43 | +public class RemoteRuleEngineTransportService implements RuleEngineTransportService { | ||
44 | + | ||
45 | + private static final ObjectMapper mapper = new ObjectMapper(); | ||
46 | + | ||
47 | + @Value("${transport.remote.rule_engine.topic}") | ||
48 | + private String ruleEngineTopic; | ||
49 | + @Value("${transport.remote.notifications.topic}") | ||
50 | + private String notificationsTopic; | ||
51 | + @Value("${transport.remote.rule_engine.poll_interval}") | ||
52 | + private int pollDuration; | ||
53 | + @Value("${transport.remote.rule_engine.auto_commit_interval}") | ||
54 | + private int autoCommitInterval; | ||
55 | + | ||
56 | + @Autowired | ||
57 | + private TbKafkaSettings kafkaSettings; | ||
58 | + | ||
59 | + @Autowired | ||
60 | + private DiscoveryService discoveryService; | ||
61 | + | ||
62 | + @Autowired | ||
63 | + private ActorSystemContext actorContext; | ||
64 | + | ||
65 | + @Autowired | ||
66 | + private ActorService actorService; | ||
67 | + | ||
68 | + //TODO: completely replace this routing with the Kafka routing by partition ids. | ||
69 | + @Autowired | ||
70 | + private ClusterRoutingService routingService; | ||
71 | + @Autowired | ||
72 | + private ClusterRpcService rpcService; | ||
73 | + @Autowired | ||
74 | + private DataDecodingEncodingService encodingService; | ||
75 | + | ||
76 | + private TBKafkaConsumerTemplate<ToRuleEngineMsg> ruleEngineConsumer; | ||
77 | + private TBKafkaProducerTemplate<ToTransportMsg> notificationsProducer; | ||
78 | + | ||
79 | + private ExecutorService mainConsumerExecutor = Executors.newSingleThreadExecutor(); | ||
80 | + | ||
81 | + private volatile boolean stopped = false; | ||
82 | + | ||
83 | + @PostConstruct | ||
84 | + public void init() { | ||
85 | + TBKafkaProducerTemplate.TBKafkaProducerTemplateBuilder<ToTransportMsg> notificationsProducerBuilder = TBKafkaProducerTemplate.builder(); | ||
86 | + notificationsProducerBuilder.settings(kafkaSettings); | ||
87 | + notificationsProducerBuilder.defaultTopic(notificationsTopic); | ||
88 | + notificationsProducerBuilder.encoder(new ToTransportMsgEncoder()); | ||
89 | + | ||
90 | + notificationsProducer = notificationsProducerBuilder.build(); | ||
91 | + notificationsProducer.init(); | ||
92 | + | ||
93 | + TBKafkaConsumerTemplate.TBKafkaConsumerTemplateBuilder<ToRuleEngineMsg> ruleEngineConsumerBuilder = TBKafkaConsumerTemplate.builder(); | ||
94 | + ruleEngineConsumerBuilder.settings(kafkaSettings); | ||
95 | + ruleEngineConsumerBuilder.topic(ruleEngineTopic); | ||
96 | + ruleEngineConsumerBuilder.clientId(discoveryService.getNodeId()); | ||
97 | + ruleEngineConsumerBuilder.groupId("tb-node"); | ||
98 | + ruleEngineConsumerBuilder.autoCommit(true); | ||
99 | + ruleEngineConsumerBuilder.autoCommitIntervalMs(autoCommitInterval); | ||
100 | + ruleEngineConsumerBuilder.decoder(new ToRuleEngineMsgDecoder()); | ||
101 | + | ||
102 | + ruleEngineConsumer = ruleEngineConsumerBuilder.build(); | ||
103 | + ruleEngineConsumer.subscribe(); | ||
104 | + | ||
105 | + mainConsumerExecutor.execute(() -> { | ||
106 | + while (!stopped) { | ||
107 | + try { | ||
108 | + ConsumerRecords<String, byte[]> records = ruleEngineConsumer.poll(Duration.ofMillis(pollDuration)); | ||
109 | + records.forEach(record -> { | ||
110 | + try { | ||
111 | + ToRuleEngineMsg toRuleEngineMsg = ruleEngineConsumer.decode(record); | ||
112 | + if (toRuleEngineMsg.hasToDeviceActorMsg()) { | ||
113 | + forwardToDeviceActor(toRuleEngineMsg.getToDeviceActorMsg()); | ||
114 | + } | ||
115 | + } catch (Throwable e) { | ||
116 | + log.warn("Failed to process the notification.", e); | ||
117 | + } | ||
118 | + }); | ||
119 | + } catch (Exception e) { | ||
120 | + log.warn("Failed to obtain messages from queue.", e); | ||
121 | + try { | ||
122 | + Thread.sleep(pollDuration); | ||
123 | + } catch (InterruptedException e2) { | ||
124 | + log.trace("Failed to wait until the server has capacity to handle new requests", e2); | ||
125 | + } | ||
126 | + } | ||
127 | + } | ||
128 | + }); | ||
129 | + } | ||
130 | + | ||
131 | + @Override | ||
132 | + public void process(String nodeId, DeviceActorToTransportMsg msg) { | ||
133 | + process(nodeId, msg, null, null); | ||
134 | + } | ||
135 | + | ||
136 | + @Override | ||
137 | + public void process(String nodeId, DeviceActorToTransportMsg msg, Runnable onSuccess, Consumer<Throwable> onFailure) { | ||
138 | + notificationsProducer.send(notificationsTopic + "." + nodeId, | ||
139 | + ToTransportMsg.newBuilder().setToDeviceSessionMsg(msg).build() | ||
140 | + , new QueueCallbackAdaptor(onSuccess, onFailure)); | ||
141 | + } | ||
142 | + | ||
143 | + private void forwardToDeviceActor(TransportToDeviceActorMsg toDeviceActorMsg) { | ||
144 | + TransportToDeviceActorMsgWrapper wrapper = new TransportToDeviceActorMsgWrapper(toDeviceActorMsg); | ||
145 | + Optional<ServerAddress> address = routingService.resolveById(wrapper.getDeviceId()); | ||
146 | + if (address.isPresent()) { | ||
147 | + rpcService.tell(encodingService.convertToProtoDataMessage(address.get(), wrapper)); | ||
148 | + } else { | ||
149 | + actorContext.getAppActor().tell(wrapper, ActorRef.noSender()); | ||
150 | + } | ||
151 | + } | ||
152 | + | ||
153 | + @PreDestroy | ||
154 | + public void destroy() { | ||
155 | + stopped = true; | ||
156 | + if (ruleEngineConsumer != null) { | ||
157 | + ruleEngineConsumer.unsubscribe(); | ||
158 | + } | ||
159 | + if (mainConsumerExecutor != null) { | ||
160 | + mainConsumerExecutor.shutdownNow(); | ||
161 | + } | ||
162 | + } | ||
163 | + | ||
164 | + private static class QueueCallbackAdaptor implements Callback { | ||
165 | + private final Runnable onSuccess; | ||
166 | + private final Consumer<Throwable> onFailure; | ||
167 | + | ||
168 | + QueueCallbackAdaptor(Runnable onSuccess, Consumer<Throwable> onFailure) { | ||
169 | + this.onSuccess = onSuccess; | ||
170 | + this.onFailure = onFailure; | ||
171 | + } | ||
172 | + | ||
173 | + @Override | ||
174 | + public void onCompletion(RecordMetadata metadata, Exception exception) { | ||
175 | + if (exception == null) { | ||
176 | + if (onSuccess != null) { | ||
177 | + onSuccess.run(); | ||
178 | + } | ||
179 | + } else { | ||
180 | + if (onFailure != null) { | ||
181 | + onFailure.accept(exception); | ||
182 | + } | ||
183 | + } | ||
184 | + } | ||
185 | + } | ||
186 | + | ||
187 | +} |
application/src/main/java/org/thingsboard/server/service/transport/RuleEngineTransportService.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | + * <p> | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * <p> | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * <p> | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.service.transport; | ||
17 | + | ||
18 | +import org.thingsboard.server.gen.transport.TransportProtos.DeviceActorToTransportMsg; | ||
19 | +import org.thingsboard.server.gen.transport.TransportProtos.; | ||
20 | + | ||
21 | +import java.util.function.Consumer; | ||
22 | + | ||
23 | +/** | ||
24 | + * Created by ashvayka on 05.10.18. | ||
25 | + */ | ||
26 | +public interface RuleEngineTransportService { | ||
27 | + | ||
28 | + void process(String nodeId, DeviceActorToTransportMsg msg); | ||
29 | + | ||
30 | + void process(String nodeId, DeviceActorToTransportMsg msg, Runnable onSuccess, Consumer<Throwable> onFailure); | ||
31 | + | ||
32 | +} |
application/src/main/java/org/thingsboard/server/service/transport/ToRuleEngineMsgDecoder.java
renamed from
application/src/main/java/org/thingsboard/server/actors/session/SessionTerminationMsg.java
@@ -13,14 +13,19 @@ | @@ -13,14 +13,19 @@ | ||
13 | * See the License for the specific language governing permissions and | 13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | -package org.thingsboard.server.actors.session; | 16 | +package org.thingsboard.server.service.transport; |
17 | 17 | ||
18 | -import org.thingsboard.server.actors.shared.ActorTerminationMsg; | ||
19 | -import org.thingsboard.server.common.data.id.SessionId; | 18 | +import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
19 | +import org.thingsboard.server.kafka.TbKafkaDecoder; | ||
20 | 20 | ||
21 | -public class SessionTerminationMsg extends ActorTerminationMsg<SessionId> { | 21 | +import java.io.IOException; |
22 | 22 | ||
23 | - public SessionTerminationMsg(SessionId id) { | ||
24 | - super(id); | 23 | +/** |
24 | + * Created by ashvayka on 05.10.18. | ||
25 | + */ | ||
26 | +public class ToRuleEngineMsgDecoder implements TbKafkaDecoder<ToRuleEngineMsg> { | ||
27 | + @Override | ||
28 | + public ToRuleEngineMsg decode(byte[] data) throws IOException { | ||
29 | + return ToRuleEngineMsg.parseFrom(data); | ||
25 | } | 30 | } |
26 | } | 31 | } |
application/src/main/java/org/thingsboard/server/service/transport/ToTransportMsgEncoder.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | + * <p> | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * <p> | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * <p> | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.service.transport; | ||
17 | + | ||
18 | +import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; | ||
19 | +import org.thingsboard.server.kafka.TbKafkaEncoder; | ||
20 | + | ||
21 | +/** | ||
22 | + * Created by ashvayka on 05.10.18. | ||
23 | + */ | ||
24 | +public class ToTransportMsgEncoder implements TbKafkaEncoder<ToTransportMsg> { | ||
25 | + @Override | ||
26 | + public byte[] encode(ToTransportMsg value) { | ||
27 | + return value.toByteArray(); | ||
28 | + } | ||
29 | +} |
1 | +package org.thingsboard.server.service.transport.msg; | ||
2 | + | ||
3 | +import lombok.Data; | ||
4 | +import org.thingsboard.server.common.data.id.DeviceId; | ||
5 | +import org.thingsboard.server.common.data.id.TenantId; | ||
6 | +import org.thingsboard.server.common.msg.MsgType; | ||
7 | +import org.thingsboard.server.common.msg.TbActorMsg; | ||
8 | +import org.thingsboard.server.common.msg.aware.DeviceAwareMsg; | ||
9 | +import org.thingsboard.server.common.msg.aware.TenantAwareMsg; | ||
10 | +import org.thingsboard.server.common.msg.cluster.ServerAddress; | ||
11 | +import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg; | ||
12 | + | ||
13 | +import java.io.Serializable; | ||
14 | +import java.util.UUID; | ||
15 | + | ||
16 | +/** | ||
17 | + * Created by ashvayka on 09.10.18. | ||
18 | + */ | ||
19 | +@Data | ||
20 | +public class TransportToDeviceActorMsgWrapper implements TbActorMsg, DeviceAwareMsg, TenantAwareMsg, Serializable { | ||
21 | + | ||
22 | + private final TenantId tenantId; | ||
23 | + private final DeviceId deviceId; | ||
24 | + private final TransportToDeviceActorMsg msg; | ||
25 | + | ||
26 | + public TransportToDeviceActorMsgWrapper(TransportToDeviceActorMsg msg) { | ||
27 | + this.msg = msg; | ||
28 | + this.tenantId = new TenantId(new UUID(msg.getSessionInfo().getTenantIdMSB(), msg.getSessionInfo().getTenantIdLSB())); | ||
29 | + this.deviceId = new DeviceId(new UUID(msg.getSessionInfo().getDeviceIdMSB(), msg.getSessionInfo().getDeviceIdLSB())); | ||
30 | + } | ||
31 | + | ||
32 | + @Override | ||
33 | + public MsgType getMsgType() { | ||
34 | + return MsgType.TRANSPORT_TO_DEVICE_ACTOR_MSG; | ||
35 | + } | ||
36 | +} |
@@ -462,4 +462,8 @@ transport: | @@ -462,4 +462,8 @@ transport: | ||
462 | request_poll_interval: "${TB_TRANSPORT_RESPONSE_POLL_INTERVAL_MS:25}" | 462 | request_poll_interval: "${TB_TRANSPORT_RESPONSE_POLL_INTERVAL_MS:25}" |
463 | request_auto_commit_interval: "${TB_TRANSPORT_RESPONSE_AUTO_COMMIT_INTERVAL_MS:1000}" | 463 | request_auto_commit_interval: "${TB_TRANSPORT_RESPONSE_AUTO_COMMIT_INTERVAL_MS:1000}" |
464 | rule_engine: | 464 | rule_engine: |
465 | - topic: "${TB_RULE_ENGINE_TOPIC:tb.rule-engine}" | ||
465 | + topic: "${TB_RULE_ENGINE_TOPIC:tb.rule-engine}" | ||
466 | + poll_interval: "${TB_RULE_ENGINE_POLL_INTERVAL_MS:25}" | ||
467 | + auto_commit_interval: "${TB_RULE_ENGINE_AUTO_COMMIT_INTERVAL_MS:100}" | ||
468 | + notifications: | ||
469 | + topic: "${TB_TRANSPORT_NOTIFICATIONS_TOPIC:tb.transport.notifications}" |
@@ -77,11 +77,6 @@ public enum MsgType { | @@ -77,11 +77,6 @@ public enum MsgType { | ||
77 | */ | 77 | */ |
78 | RULE_TO_SELF_MSG, | 78 | RULE_TO_SELF_MSG, |
79 | 79 | ||
80 | - /** | ||
81 | - * Message that is sent by Session Actor to Device Actor. Represents messages from the device itself. | ||
82 | - */ | ||
83 | - DEVICE_SESSION_TO_DEVICE_ACTOR_MSG, | ||
84 | - | ||
85 | DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG, | 80 | DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG, |
86 | 81 | ||
87 | DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG, | 82 | DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG, |
@@ -111,6 +106,12 @@ public enum MsgType { | @@ -111,6 +106,12 @@ public enum MsgType { | ||
111 | TRANSPORT_TO_DEVICE_SESSION_ACTOR_MSG, | 106 | TRANSPORT_TO_DEVICE_SESSION_ACTOR_MSG, |
112 | SESSION_TIMEOUT_MSG, | 107 | SESSION_TIMEOUT_MSG, |
113 | SESSION_CTRL_MSG, | 108 | SESSION_CTRL_MSG, |
114 | - STATS_PERSIST_TICK_MSG; | 109 | + STATS_PERSIST_TICK_MSG, |
110 | + | ||
111 | + | ||
112 | + /** | ||
113 | + * Message that is sent by TransportRuleEngineService to Device Actor. Represents messages from the device itself. | ||
114 | + */ | ||
115 | + TRANSPORT_TO_DEVICE_ACTOR_MSG; | ||
115 | 116 | ||
116 | } | 117 | } |
common/message/src/main/java/org/thingsboard/server/common/msg/device/BasicDeviceToDeviceActorMsg.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.common.msg.device; | ||
17 | - | ||
18 | -import lombok.ToString; | ||
19 | -import org.thingsboard.server.common.data.id.CustomerId; | ||
20 | -import org.thingsboard.server.common.data.id.DeviceId; | ||
21 | -import org.thingsboard.server.common.data.id.SessionId; | ||
22 | -import org.thingsboard.server.common.data.id.TenantId; | ||
23 | -import org.thingsboard.server.common.msg.MsgType; | ||
24 | -import org.thingsboard.server.common.msg.cluster.ServerAddress; | ||
25 | -import org.thingsboard.server.common.msg.session.FromDeviceMsg; | ||
26 | -import org.thingsboard.server.common.msg.session.SessionType; | ||
27 | -import org.thingsboard.server.common.msg.session.TransportToDeviceSessionActorMsg; | ||
28 | - | ||
29 | -import java.util.Optional; | ||
30 | - | ||
31 | -@ToString | ||
32 | -public class BasicDeviceToDeviceActorMsg implements DeviceToDeviceActorMsg { | ||
33 | - | ||
34 | - private static final long serialVersionUID = -1866795134993115408L; | ||
35 | - | ||
36 | - private final TenantId tenantId; | ||
37 | - private final CustomerId customerId; | ||
38 | - private final DeviceId deviceId; | ||
39 | - private final SessionId sessionId; | ||
40 | - private final SessionType sessionType; | ||
41 | - private final ServerAddress serverAddress; | ||
42 | - private final FromDeviceMsg msg; | ||
43 | - | ||
44 | - public BasicDeviceToDeviceActorMsg(DeviceToDeviceActorMsg other, FromDeviceMsg msg) { | ||
45 | - this(null, other.getTenantId(), other.getCustomerId(), other.getDeviceId(), other.getSessionId(), other.getSessionType(), msg); | ||
46 | - } | ||
47 | - | ||
48 | - public BasicDeviceToDeviceActorMsg(TransportToDeviceSessionActorMsg msg, SessionType sessionType) { | ||
49 | - this(null, msg.getTenantId(), msg.getCustomerId(), msg.getDeviceId(), msg.getSessionId(), sessionType, msg.getSessionMsg().getMsg()); | ||
50 | - } | ||
51 | - | ||
52 | - private BasicDeviceToDeviceActorMsg(ServerAddress serverAddress, TenantId tenantId, CustomerId customerId, DeviceId deviceId, SessionId sessionId, SessionType sessionType, | ||
53 | - FromDeviceMsg msg) { | ||
54 | - super(); | ||
55 | - this.serverAddress = serverAddress; | ||
56 | - this.tenantId = tenantId; | ||
57 | - this.customerId = customerId; | ||
58 | - this.deviceId = deviceId; | ||
59 | - this.sessionId = sessionId; | ||
60 | - this.sessionType = sessionType; | ||
61 | - this.msg = msg; | ||
62 | - } | ||
63 | - | ||
64 | - @Override | ||
65 | - public DeviceId getDeviceId() { | ||
66 | - return deviceId; | ||
67 | - } | ||
68 | - | ||
69 | - @Override | ||
70 | - public CustomerId getCustomerId() { | ||
71 | - return customerId; | ||
72 | - } | ||
73 | - | ||
74 | - public TenantId getTenantId() { | ||
75 | - return tenantId; | ||
76 | - } | ||
77 | - | ||
78 | - @Override | ||
79 | - public SessionId getSessionId() { | ||
80 | - return sessionId; | ||
81 | - } | ||
82 | - | ||
83 | - @Override | ||
84 | - public SessionType getSessionType() { | ||
85 | - return sessionType; | ||
86 | - } | ||
87 | - | ||
88 | - @Override | ||
89 | - public Optional<ServerAddress> getServerAddress() { | ||
90 | - return Optional.ofNullable(serverAddress); | ||
91 | - } | ||
92 | - | ||
93 | - @Override | ||
94 | - public FromDeviceMsg getPayload() { | ||
95 | - return msg; | ||
96 | - } | ||
97 | - | ||
98 | - @Override | ||
99 | - public DeviceToDeviceActorMsg toOtherAddress(ServerAddress otherAddress) { | ||
100 | - return new BasicDeviceToDeviceActorMsg(otherAddress, tenantId, customerId, deviceId, sessionId, sessionType, msg); | ||
101 | - } | ||
102 | - | ||
103 | - @Override | ||
104 | - public MsgType getMsgType() { | ||
105 | - return MsgType.DEVICE_SESSION_TO_DEVICE_ACTOR_MSG; | ||
106 | - } | ||
107 | -} |
1 | /** | 1 | /** |
2 | * Copyright © 2016-2018 The Thingsboard Authors | 2 | * Copyright © 2016-2018 The Thingsboard Authors |
3 | - * | 3 | + * <p> |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. | 5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at | 6 | * You may obtain a copy of the License at |
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | 7 | + * <p> |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * <p> | ||
10 | * Unless required by applicable law or agreed to in writing, software | 10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
@@ -49,7 +49,9 @@ public class TBKafkaConsumerTemplate<T> { | @@ -49,7 +49,9 @@ public class TBKafkaConsumerTemplate<T> { | ||
49 | boolean autoCommit, int autoCommitIntervalMs) { | 49 | boolean autoCommit, int autoCommitIntervalMs) { |
50 | Properties props = settings.toProps(); | 50 | Properties props = settings.toProps(); |
51 | props.put(ConsumerConfig.CLIENT_ID_CONFIG, clientId); | 51 | props.put(ConsumerConfig.CLIENT_ID_CONFIG, clientId); |
52 | - props.put(ConsumerConfig.GROUP_ID_CONFIG, groupId); | 52 | + if (groupId != null) { |
53 | + props.put(ConsumerConfig.GROUP_ID_CONFIG, groupId); | ||
54 | + } | ||
53 | props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, autoCommit); | 55 | props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, autoCommit); |
54 | props.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, autoCommitIntervalMs); | 56 | props.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, autoCommitIntervalMs); |
55 | props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer"); | 57 | props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer"); |
1 | /** | 1 | /** |
2 | * Copyright © 2016-2018 The Thingsboard Authors | 2 | * Copyright © 2016-2018 The Thingsboard Authors |
3 | - * | 3 | + * <p> |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. | 5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at | 6 | * You may obtain a copy of the License at |
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | 7 | + * <p> |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * <p> | ||
10 | * Unless required by applicable law or agreed to in writing, software | 10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
@@ -20,6 +20,7 @@ import lombok.Getter; | @@ -20,6 +20,7 @@ import lombok.Getter; | ||
20 | import lombok.extern.slf4j.Slf4j; | 20 | import lombok.extern.slf4j.Slf4j; |
21 | import org.apache.kafka.clients.admin.CreateTopicsResult; | 21 | import org.apache.kafka.clients.admin.CreateTopicsResult; |
22 | import org.apache.kafka.clients.admin.NewTopic; | 22 | import org.apache.kafka.clients.admin.NewTopic; |
23 | +import org.apache.kafka.clients.producer.Callback; | ||
23 | import org.apache.kafka.clients.producer.KafkaProducer; | 24 | import org.apache.kafka.clients.producer.KafkaProducer; |
24 | import org.apache.kafka.clients.producer.ProducerConfig; | 25 | import org.apache.kafka.clients.producer.ProducerConfig; |
25 | import org.apache.kafka.clients.producer.ProducerRecord; | 26 | import org.apache.kafka.clients.producer.ProducerRecord; |
@@ -89,28 +90,28 @@ public class TBKafkaProducerTemplate<T> { | @@ -89,28 +90,28 @@ public class TBKafkaProducerTemplate<T> { | ||
89 | } | 90 | } |
90 | } | 91 | } |
91 | 92 | ||
92 | - public Future<RecordMetadata> send(String key, T value) { | ||
93 | - return send(key, value, null, null); | 93 | + public Future<RecordMetadata> send(String key, T value, Callback callback) { |
94 | + return send(key, value, null, callback); | ||
94 | } | 95 | } |
95 | 96 | ||
96 | - public Future<RecordMetadata> send(String key, T value, Iterable<Header> headers) { | ||
97 | - return send(key, value, null, headers); | 97 | + public Future<RecordMetadata> send(String key, T value, Iterable<Header> headers, Callback callback) { |
98 | + return send(key, value, null, headers, callback); | ||
98 | } | 99 | } |
99 | 100 | ||
100 | - public Future<RecordMetadata> send(String key, T value, Long timestamp, Iterable<Header> headers) { | ||
101 | - return send(this.defaultTopic, key, value, timestamp, headers); | 101 | + public Future<RecordMetadata> send(String key, T value, Long timestamp, Iterable<Header> headers, Callback callback) { |
102 | + return send(this.defaultTopic, key, value, timestamp, headers, callback); | ||
102 | } | 103 | } |
103 | 104 | ||
104 | - public Future<RecordMetadata> send(String topic, String key, T value, Iterable<Header> headers) { | ||
105 | - return send(topic, key, value, null, headers); | 105 | + public Future<RecordMetadata> send(String topic, String key, T value, Iterable<Header> headers, Callback callback) { |
106 | + return send(topic, key, value, null, headers, callback); | ||
106 | } | 107 | } |
107 | 108 | ||
108 | - public Future<RecordMetadata> send(String topic, String key, T value, Long timestamp, Iterable<Header> headers) { | 109 | + public Future<RecordMetadata> send(String topic, String key, T value, Long timestamp, Iterable<Header> headers, Callback callback) { |
109 | byte[] data = encoder.encode(value); | 110 | byte[] data = encoder.encode(value); |
110 | ProducerRecord<String, byte[]> record; | 111 | ProducerRecord<String, byte[]> record; |
111 | Integer partition = getPartition(topic, key, value, data); | 112 | Integer partition = getPartition(topic, key, value, data); |
112 | record = new ProducerRecord<>(topic, partition, timestamp, key, data, headers); | 113 | record = new ProducerRecord<>(topic, partition, timestamp, key, data, headers); |
113 | - return producer.send(record); | 114 | + return producer.send(record, callback); |
114 | } | 115 | } |
115 | 116 | ||
116 | private Integer getPartition(String topic, String key, T value, byte[] data) { | 117 | private Integer getPartition(String topic, String key, T value, byte[] data) { |
1 | /** | 1 | /** |
2 | * Copyright © 2016-2018 The Thingsboard Authors | 2 | * Copyright © 2016-2018 The Thingsboard Authors |
3 | - * | 3 | + * <p> |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. | 5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at | 6 | * You may obtain a copy of the License at |
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | 7 | + * <p> |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * <p> | ||
10 | * Unless required by applicable law or agreed to in writing, software | 10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
@@ -77,55 +77,64 @@ public class TbKafkaResponseTemplate<Request, Response> extends AbstractTbKafkaT | @@ -77,55 +77,64 @@ public class TbKafkaResponseTemplate<Request, Response> extends AbstractTbKafkaT | ||
77 | requestTemplate.subscribe(); | 77 | requestTemplate.subscribe(); |
78 | loopExecutor.submit(() -> { | 78 | loopExecutor.submit(() -> { |
79 | while (!stopped) { | 79 | while (!stopped) { |
80 | - while (pendingRequestCount.get() >= maxPendingRequests) { | 80 | + try { |
81 | + while (pendingRequestCount.get() >= maxPendingRequests) { | ||
82 | + try { | ||
83 | + Thread.sleep(pollInterval); | ||
84 | + } catch (InterruptedException e) { | ||
85 | + log.trace("Failed to wait until the server has capacity to handle new requests", e); | ||
86 | + } | ||
87 | + } | ||
88 | + ConsumerRecords<String, byte[]> requests = requestTemplate.poll(Duration.ofMillis(pollInterval)); | ||
89 | + requests.forEach(request -> { | ||
90 | + Header requestIdHeader = request.headers().lastHeader(TbKafkaSettings.REQUEST_ID_HEADER); | ||
91 | + if (requestIdHeader == null) { | ||
92 | + log.error("[{}] Missing requestId in header", request); | ||
93 | + return; | ||
94 | + } | ||
95 | + UUID requestId = bytesToUuid(requestIdHeader.value()); | ||
96 | + if (requestId == null) { | ||
97 | + log.error("[{}] Missing requestId in header and body", request); | ||
98 | + return; | ||
99 | + } | ||
100 | + Header responseTopicHeader = request.headers().lastHeader(TbKafkaSettings.RESPONSE_TOPIC_HEADER); | ||
101 | + if (responseTopicHeader == null) { | ||
102 | + log.error("[{}] Missing response topic in header", request); | ||
103 | + return; | ||
104 | + } | ||
105 | + String responseTopic = bytesToString(responseTopicHeader.value()); | ||
106 | + try { | ||
107 | + pendingRequestCount.getAndIncrement(); | ||
108 | + Request decodedRequest = requestTemplate.decode(request); | ||
109 | + AsyncCallbackTemplate.withCallbackAndTimeout(handler.handle(decodedRequest), | ||
110 | + response -> { | ||
111 | + pendingRequestCount.decrementAndGet(); | ||
112 | + reply(requestId, responseTopic, response); | ||
113 | + }, | ||
114 | + e -> { | ||
115 | + pendingRequestCount.decrementAndGet(); | ||
116 | + if (e.getCause() != null && e.getCause() instanceof TimeoutException) { | ||
117 | + log.warn("[{}] Timedout to process the request: {}", requestId, request, e); | ||
118 | + } else { | ||
119 | + log.trace("[{}] Failed to process the request: {}", requestId, request, e); | ||
120 | + } | ||
121 | + }, | ||
122 | + requestTimeout, | ||
123 | + timeoutExecutor, | ||
124 | + callbackExecutor); | ||
125 | + } catch (Throwable e) { | ||
126 | + pendingRequestCount.decrementAndGet(); | ||
127 | + log.warn("[{}] Failed to process the request: {}", requestId, request, e); | ||
128 | + } | ||
129 | + }); | ||
130 | + } catch (Throwable e) { | ||
131 | + log.warn("Failed to obtain messages from queue.", e); | ||
81 | try { | 132 | try { |
82 | Thread.sleep(pollInterval); | 133 | Thread.sleep(pollInterval); |
83 | - } catch (InterruptedException e) { | ||
84 | - log.trace("Failed to wait until the server has capacity to handle new requests", e); | 134 | + } catch (InterruptedException e2) { |
135 | + log.trace("Failed to wait until the server has capacity to handle new requests", e2); | ||
85 | } | 136 | } |
86 | } | 137 | } |
87 | - ConsumerRecords<String, byte[]> requests = requestTemplate.poll(Duration.ofMillis(pollInterval)); | ||
88 | - requests.forEach(request -> { | ||
89 | - Header requestIdHeader = request.headers().lastHeader(TbKafkaSettings.REQUEST_ID_HEADER); | ||
90 | - if (requestIdHeader == null) { | ||
91 | - log.error("[{}] Missing requestId in header", request); | ||
92 | - return; | ||
93 | - } | ||
94 | - UUID requestId = bytesToUuid(requestIdHeader.value()); | ||
95 | - if (requestId == null) { | ||
96 | - log.error("[{}] Missing requestId in header and body", request); | ||
97 | - return; | ||
98 | - } | ||
99 | - Header responseTopicHeader = request.headers().lastHeader(TbKafkaSettings.RESPONSE_TOPIC_HEADER); | ||
100 | - if (responseTopicHeader == null) { | ||
101 | - log.error("[{}] Missing response topic in header", request); | ||
102 | - return; | ||
103 | - } | ||
104 | - String responseTopic = bytesToString(responseTopicHeader.value()); | ||
105 | - try { | ||
106 | - pendingRequestCount.getAndIncrement(); | ||
107 | - Request decodedRequest = requestTemplate.decode(request); | ||
108 | - AsyncCallbackTemplate.withCallbackAndTimeout(handler.handle(decodedRequest), | ||
109 | - response -> { | ||
110 | - pendingRequestCount.decrementAndGet(); | ||
111 | - reply(requestId, responseTopic, response); | ||
112 | - }, | ||
113 | - e -> { | ||
114 | - pendingRequestCount.decrementAndGet(); | ||
115 | - if (e.getCause() != null && e.getCause() instanceof TimeoutException) { | ||
116 | - log.warn("[{}] Timedout to process the request: {}", requestId, request, e); | ||
117 | - } else { | ||
118 | - log.trace("[{}] Failed to process the request: {}", requestId, request, e); | ||
119 | - } | ||
120 | - }, | ||
121 | - requestTimeout, | ||
122 | - timeoutExecutor, | ||
123 | - callbackExecutor); | ||
124 | - } catch (Throwable e) { | ||
125 | - pendingRequestCount.decrementAndGet(); | ||
126 | - log.warn("[{}] Failed to process the request: {}", requestId, request, e); | ||
127 | - } | ||
128 | - }); | ||
129 | } | 138 | } |
130 | }); | 139 | }); |
131 | } | 140 | } |
@@ -141,7 +150,7 @@ public class TbKafkaResponseTemplate<Request, Response> extends AbstractTbKafkaT | @@ -141,7 +150,7 @@ public class TbKafkaResponseTemplate<Request, Response> extends AbstractTbKafkaT | ||
141 | } | 150 | } |
142 | 151 | ||
143 | private void reply(UUID requestId, String topic, Response response) { | 152 | private void reply(UUID requestId, String topic, Response response) { |
144 | - responseTemplate.send(topic, requestId.toString(), response, Collections.singletonList(new RecordHeader(TbKafkaSettings.REQUEST_ID_HEADER, uuidToBytes(requestId)))); | 153 | + responseTemplate.send(topic, requestId.toString(), response, Collections.singletonList(new RecordHeader(TbKafkaSettings.REQUEST_ID_HEADER, uuidToBytes(requestId))), null); |
145 | } | 154 | } |
146 | 155 | ||
147 | } | 156 | } |
common/transport/src/main/java/org/thingsboard/server/common/transport/SessionMsgListener.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | + * <p> | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * <p> | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * <p> | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.common.transport; | ||
17 | + | ||
18 | +import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg; | ||
19 | + | ||
20 | +/** | ||
21 | + * Created by ashvayka on 04.10.18. | ||
22 | + */ | ||
23 | +public interface SessionMsgListener { | ||
24 | + | ||
25 | + void onGetAttributesResponse(GetAttributeResponseMsg getAttributesResponse); | ||
26 | +} |
1 | /** | 1 | /** |
2 | * Copyright © 2016-2018 The Thingsboard Authors | 2 | * Copyright © 2016-2018 The Thingsboard Authors |
3 | - * | 3 | + * <p> |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. | 5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at | 6 | * You may obtain a copy of the License at |
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | 7 | + * <p> |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * <p> | ||
10 | * Unless required by applicable law or agreed to in writing, software | 10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
@@ -15,23 +15,33 @@ | @@ -15,23 +15,33 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.common.transport; | 16 | package org.thingsboard.server.common.transport; |
17 | 17 | ||
18 | -import org.thingsboard.server.gen.transport.TransportProtos; | 18 | +import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; |
19 | +import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg; | ||
20 | +import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg; | ||
21 | +import org.thingsboard.server.gen.transport.TransportProtos.SessionEventMsg; | ||
22 | +import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; | ||
23 | +import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceTokenRequestMsg; | ||
24 | +import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509CertRequestMsg; | ||
19 | 25 | ||
20 | /** | 26 | /** |
21 | * Created by ashvayka on 04.10.18. | 27 | * Created by ashvayka on 04.10.18. |
22 | */ | 28 | */ |
23 | public interface TransportService { | 29 | public interface TransportService { |
24 | 30 | ||
25 | - void process(TransportProtos.ValidateDeviceTokenRequestMsg msg, | ||
26 | - TransportServiceCallback<TransportProtos.ValidateDeviceCredentialsResponseMsg> callback); | 31 | + void process(ValidateDeviceTokenRequestMsg msg, |
32 | + TransportServiceCallback<ValidateDeviceCredentialsResponseMsg> callback); | ||
27 | 33 | ||
28 | - void process(TransportProtos.ValidateDeviceX509CertRequestMsg msg, | ||
29 | - TransportServiceCallback<TransportProtos.ValidateDeviceCredentialsResponseMsg> callback); | 34 | + void process(ValidateDeviceX509CertRequestMsg msg, |
35 | + TransportServiceCallback<ValidateDeviceCredentialsResponseMsg> callback); | ||
30 | 36 | ||
31 | - void process(TransportProtos.SessionEventMsg msg, TransportServiceCallback<Void> callback); | 37 | + void process(SessionInfoProto sessionInfo, SessionEventMsg msg, TransportServiceCallback<Void> callback); |
32 | 38 | ||
33 | - void process(TransportProtos.PostTelemetryMsg msg, TransportServiceCallback<Void> callback); | 39 | + void process(SessionInfoProto sessionInfo, PostTelemetryMsg msg, TransportServiceCallback<Void> callback); |
34 | 40 | ||
35 | - void process(TransportProtos.PostAttributeMsg msg, TransportServiceCallback<Void> callback); | 41 | + void process(SessionInfoProto sessionInfo, PostAttributeMsg msg, TransportServiceCallback<Void> callback); |
42 | + | ||
43 | + void registerSession(SessionInfoProto sessionInfo, SessionMsgListener listener); | ||
44 | + | ||
45 | + void deregisterSession(SessionInfoProto sessionInfo); | ||
36 | 46 | ||
37 | } | 47 | } |
1 | /** | 1 | /** |
2 | * Copyright © 2016-2018 The Thingsboard Authors | 2 | * Copyright © 2016-2018 The Thingsboard Authors |
3 | - * | 3 | + * <p> |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. | 5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at | 6 | * You may obtain a copy of the License at |
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | 7 | + * <p> |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * <p> | ||
10 | * Unless required by applicable law or agreed to in writing, software | 10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
@@ -16,17 +16,12 @@ | @@ -16,17 +16,12 @@ | ||
16 | package org.thingsboard.server.common.transport.session; | 16 | package org.thingsboard.server.common.transport.session; |
17 | 17 | ||
18 | import lombok.Data; | 18 | import lombok.Data; |
19 | -import lombok.extern.slf4j.Slf4j; | ||
20 | -import org.thingsboard.server.common.data.Device; | ||
21 | -import org.thingsboard.server.common.data.security.DeviceCredentialsFilter; | ||
22 | -import org.thingsboard.server.common.data.security.DeviceTokenCredentials; | 19 | +import lombok.Getter; |
20 | +import org.thingsboard.server.common.data.id.DeviceId; | ||
23 | import org.thingsboard.server.common.msg.session.SessionContext; | 21 | import org.thingsboard.server.common.msg.session.SessionContext; |
24 | -import org.thingsboard.server.common.transport.SessionMsgProcessor; | ||
25 | -import org.thingsboard.server.common.transport.auth.DeviceAuthResult; | ||
26 | -import org.thingsboard.server.common.transport.auth.DeviceAuthService; | ||
27 | -import org.thingsboard.server.gen.transport.TransportProtos; | 22 | +import org.thingsboard.server.gen.transport.TransportProtos.DeviceInfoProto; |
28 | 23 | ||
29 | -import java.util.Optional; | 24 | +import java.util.UUID; |
30 | 25 | ||
31 | /** | 26 | /** |
32 | * @author Andrew Shvayka | 27 | * @author Andrew Shvayka |
@@ -34,7 +29,9 @@ import java.util.Optional; | @@ -34,7 +29,9 @@ import java.util.Optional; | ||
34 | @Data | 29 | @Data |
35 | public abstract class DeviceAwareSessionContext implements SessionContext { | 30 | public abstract class DeviceAwareSessionContext implements SessionContext { |
36 | 31 | ||
37 | - private volatile TransportProtos.DeviceInfoProto deviceInfo; | 32 | + @Getter |
33 | + private volatile DeviceId deviceId; | ||
34 | + private volatile DeviceInfoProto deviceInfo; | ||
38 | 35 | ||
39 | public long getDeviceIdMSB() { | 36 | public long getDeviceIdMSB() { |
40 | return deviceInfo.getDeviceIdMSB(); | 37 | return deviceInfo.getDeviceIdMSB(); |
@@ -44,6 +41,16 @@ public abstract class DeviceAwareSessionContext implements SessionContext { | @@ -44,6 +41,16 @@ public abstract class DeviceAwareSessionContext implements SessionContext { | ||
44 | return deviceInfo.getDeviceIdLSB(); | 41 | return deviceInfo.getDeviceIdLSB(); |
45 | } | 42 | } |
46 | 43 | ||
44 | + public DeviceId getDeviceId() { | ||
45 | + return deviceId; | ||
46 | + } | ||
47 | + | ||
48 | + public void setDeviceInfo(DeviceInfoProto deviceInfo) { | ||
49 | + this.deviceInfo = deviceInfo; | ||
50 | + this.deviceId = new DeviceId(new UUID(deviceInfo.getDeviceIdMSB(), deviceInfo.getDeviceIdLSB())); | ||
51 | + } | ||
52 | + | ||
53 | + | ||
47 | public boolean isConnected() { | 54 | public boolean isConnected() { |
48 | return deviceInfo != null; | 55 | return deviceInfo != null; |
49 | } | 56 | } |
@@ -23,9 +23,12 @@ option java_outer_classname = "TransportProtos"; | @@ -23,9 +23,12 @@ option java_outer_classname = "TransportProtos"; | ||
23 | * Data Structures; | 23 | * Data Structures; |
24 | */ | 24 | */ |
25 | message SessionInfoProto { | 25 | message SessionInfoProto { |
26 | - string nodeId = 1; | ||
27 | - int64 sessionIdMSB = 2; | ||
28 | - int64 sessionIdLSB = 3; | 26 | + int64 sessionIdMSB = 1; |
27 | + int64 sessionIdLSB = 2; | ||
28 | + int64 tenantIdMSB = 3; | ||
29 | + int64 tenantIdLSB = 4; | ||
30 | + int64 deviceIdMSB = 5; | ||
31 | + int64 deviceIdLSB = 6; | ||
29 | } | 32 | } |
30 | 33 | ||
31 | enum SessionEvent { | 34 | enum SessionEvent { |
@@ -33,12 +36,25 @@ enum SessionEvent { | @@ -33,12 +36,25 @@ enum SessionEvent { | ||
33 | CLOSED = 1; | 36 | CLOSED = 1; |
34 | } | 37 | } |
35 | 38 | ||
39 | +enum SessionType { | ||
40 | + SYNC = 0; | ||
41 | + ASYNC = 1; | ||
42 | +} | ||
43 | + | ||
44 | +enum KeyValueType { | ||
45 | + BOOLEAN_V = 0; | ||
46 | + LONG_V = 1; | ||
47 | + DOUBLE_V = 2; | ||
48 | + STRING_V = 3; | ||
49 | +} | ||
50 | + | ||
36 | message KeyValueProto { | 51 | message KeyValueProto { |
37 | string key = 1; | 52 | string key = 1; |
38 | - bool bool_v = 2; | ||
39 | - int64 long_v = 3; | ||
40 | - double double_v = 4; | ||
41 | - string string_v = 5; | 53 | + KeyValueType type = 2; |
54 | + bool bool_v = 3; | ||
55 | + int64 long_v = 4; | ||
56 | + double double_v = 5; | ||
57 | + string string_v = 6; | ||
42 | } | 58 | } |
43 | 59 | ||
44 | message TsKvListProto { | 60 | message TsKvListProto { |
@@ -60,33 +76,28 @@ message DeviceInfoProto { | @@ -60,33 +76,28 @@ message DeviceInfoProto { | ||
60 | * Messages that use Data Structures; | 76 | * Messages that use Data Structures; |
61 | */ | 77 | */ |
62 | message SessionEventMsg { | 78 | message SessionEventMsg { |
63 | - SessionInfoProto sessionInfo = 1; | ||
64 | - int64 deviceIdMSB = 2; | ||
65 | - int64 deviceIdLSB = 3; | ||
66 | - SessionEvent event = 4; | 79 | + string nodeId = 1; |
80 | + SessionType sessionType = 2; | ||
81 | + SessionEvent event = 3; | ||
67 | } | 82 | } |
68 | 83 | ||
69 | message PostTelemetryMsg { | 84 | message PostTelemetryMsg { |
70 | - SessionInfoProto sessionInfo = 1; | ||
71 | - repeated TsKvListProto tsKvList = 2; | 85 | + repeated TsKvListProto tsKvList = 1; |
72 | } | 86 | } |
73 | 87 | ||
74 | message PostAttributeMsg { | 88 | message PostAttributeMsg { |
75 | - SessionInfoProto sessionInfo = 1; | ||
76 | - repeated TsKvListProto tsKvList = 2; | 89 | + repeated KeyValueProto kv = 1; |
77 | } | 90 | } |
78 | 91 | ||
79 | message GetAttributeRequestMsg { | 92 | message GetAttributeRequestMsg { |
80 | - SessionInfoProto sessionInfo = 1; | ||
81 | - repeated string clientAttributeNames = 2; | ||
82 | - repeated string sharedAttributeNames = 3; | 93 | + repeated string clientAttributeNames = 1; |
94 | + repeated string sharedAttributeNames = 2; | ||
83 | } | 95 | } |
84 | 96 | ||
85 | message GetAttributeResponseMsg { | 97 | message GetAttributeResponseMsg { |
86 | - SessionInfoProto sessionInfo = 1; | ||
87 | - repeated TsKvListProto clientAttributeList = 2; | ||
88 | - repeated TsKvListProto sharedAttributeList = 3; | ||
89 | - repeated string deletedAttributeKeys = 4; | 98 | + repeated TsKvListProto clientAttributeList = 1; |
99 | + repeated TsKvListProto sharedAttributeList = 2; | ||
100 | + repeated string deletedAttributeKeys = 3; | ||
90 | } | 101 | } |
91 | 102 | ||
92 | message ValidateDeviceTokenRequestMsg { | 103 | message ValidateDeviceTokenRequestMsg { |
@@ -101,11 +112,34 @@ message ValidateDeviceCredentialsResponseMsg { | @@ -101,11 +112,34 @@ message ValidateDeviceCredentialsResponseMsg { | ||
101 | DeviceInfoProto deviceInfo = 1; | 112 | DeviceInfoProto deviceInfo = 1; |
102 | } | 113 | } |
103 | 114 | ||
115 | +message SessionCloseNotificationProto { | ||
116 | + string message = 1; | ||
117 | +} | ||
118 | + | ||
119 | +message TransportToDeviceActorMsg { | ||
120 | + SessionInfoProto sessionInfo = 1; | ||
121 | + SessionEventMsg sessionEvent = 2; | ||
122 | + PostTelemetryMsg postTelemetry = 3; | ||
123 | + PostAttributeMsg postAttributes = 4; | ||
124 | + GetAttributeRequestMsg getAttributes = 5; | ||
125 | +} | ||
126 | + | ||
127 | +message DeviceActorToTransportMsg { | ||
128 | + int64 sessionIdMSB = 1; | ||
129 | + int64 sessionIdLSB = 2; | ||
130 | + SessionCloseNotificationProto sessionCloseNotification = 3; | ||
131 | + GetAttributeResponseMsg getAttributesResponse = 4; | ||
132 | +} | ||
133 | + | ||
104 | /** | 134 | /** |
105 | * Main messages; | 135 | * Main messages; |
106 | */ | 136 | */ |
107 | -message TransportToRuleEngineMsg { | 137 | +message ToRuleEngineMsg { |
138 | + TransportToDeviceActorMsg toDeviceActorMsg = 1; | ||
139 | +} | ||
108 | 140 | ||
141 | +message ToTransportMsg { | ||
142 | + DeviceActorToTransportMsg toDeviceSessionMsg = 1; | ||
109 | } | 143 | } |
110 | 144 | ||
111 | message TransportApiRequestMsg { | 145 | message TransportApiRequestMsg { |
1 | /** | 1 | /** |
2 | * Copyright © 2016-2018 The Thingsboard Authors | 2 | * Copyright © 2016-2018 The Thingsboard Authors |
3 | - * | 3 | + * <p> |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. | 5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at | 6 | * You may obtain a copy of the License at |
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | 7 | + * <p> |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * <p> | ||
10 | * Unless required by applicable law or agreed to in writing, software | 10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
@@ -26,32 +26,25 @@ import io.netty.handler.codec.mqtt.MqttFixedHeader; | @@ -26,32 +26,25 @@ import io.netty.handler.codec.mqtt.MqttFixedHeader; | ||
26 | import io.netty.handler.codec.mqtt.MqttMessage; | 26 | import io.netty.handler.codec.mqtt.MqttMessage; |
27 | import io.netty.handler.codec.mqtt.MqttMessageIdVariableHeader; | 27 | import io.netty.handler.codec.mqtt.MqttMessageIdVariableHeader; |
28 | import io.netty.handler.codec.mqtt.MqttPubAckMessage; | 28 | import io.netty.handler.codec.mqtt.MqttPubAckMessage; |
29 | -import io.netty.handler.codec.mqtt.MqttPublishMessage; | ||
30 | import io.netty.handler.codec.mqtt.MqttQoS; | 29 | import io.netty.handler.codec.mqtt.MqttQoS; |
31 | import io.netty.handler.codec.mqtt.MqttSubAckMessage; | 30 | import io.netty.handler.codec.mqtt.MqttSubAckMessage; |
32 | import io.netty.handler.codec.mqtt.MqttSubAckPayload; | 31 | import io.netty.handler.codec.mqtt.MqttSubAckPayload; |
33 | -import io.netty.handler.codec.mqtt.MqttSubscribeMessage; | ||
34 | -import io.netty.handler.codec.mqtt.MqttTopicSubscription; | ||
35 | -import io.netty.handler.codec.mqtt.MqttUnsubscribeMessage; | ||
36 | import io.netty.handler.ssl.SslHandler; | 32 | import io.netty.handler.ssl.SslHandler; |
37 | import io.netty.util.concurrent.Future; | 33 | import io.netty.util.concurrent.Future; |
38 | import io.netty.util.concurrent.GenericFutureListener; | 34 | import io.netty.util.concurrent.GenericFutureListener; |
39 | import lombok.extern.slf4j.Slf4j; | 35 | import lombok.extern.slf4j.Slf4j; |
40 | import org.springframework.util.StringUtils; | 36 | import org.springframework.util.StringUtils; |
41 | -import org.thingsboard.server.common.data.Device; | ||
42 | -import org.thingsboard.server.common.data.security.DeviceTokenCredentials; | ||
43 | -import org.thingsboard.server.common.data.security.DeviceX509Credentials; | ||
44 | -import org.thingsboard.server.common.msg.core.SessionOpenMsg; | ||
45 | -import org.thingsboard.server.common.msg.session.AdaptorToSessionActorMsg; | ||
46 | -import org.thingsboard.server.common.msg.session.BasicAdaptorToSessionActorMsg; | ||
47 | -import org.thingsboard.server.common.msg.session.BasicTransportToDeviceSessionActorMsg; | ||
48 | -import org.thingsboard.server.common.msg.session.ctrl.SessionCloseMsg; | ||
49 | import org.thingsboard.server.common.transport.TransportService; | 37 | import org.thingsboard.server.common.transport.TransportService; |
50 | import org.thingsboard.server.common.transport.TransportServiceCallback; | 38 | import org.thingsboard.server.common.transport.TransportServiceCallback; |
51 | -import org.thingsboard.server.common.transport.adaptor.AdaptorException; | ||
52 | import org.thingsboard.server.common.transport.quota.QuotaService; | 39 | import org.thingsboard.server.common.transport.quota.QuotaService; |
53 | import org.thingsboard.server.dao.EncryptionUtil; | 40 | import org.thingsboard.server.dao.EncryptionUtil; |
54 | -import org.thingsboard.server.gen.transport.TransportProtos; | 41 | +import org.thingsboard.server.gen.transport.TransportProtos.DeviceInfoProto; |
42 | +import org.thingsboard.server.gen.transport.TransportProtos.SessionEvent; | ||
43 | +import org.thingsboard.server.gen.transport.TransportProtos.SessionEventMsg; | ||
44 | +import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; | ||
45 | +import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; | ||
46 | +import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceTokenRequestMsg; | ||
47 | +import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509CertRequestMsg; | ||
55 | import org.thingsboard.server.transport.mqtt.adaptors.MqttTransportAdaptor; | 48 | import org.thingsboard.server.transport.mqtt.adaptors.MqttTransportAdaptor; |
56 | import org.thingsboard.server.transport.mqtt.session.DeviceSessionCtx; | 49 | import org.thingsboard.server.transport.mqtt.session.DeviceSessionCtx; |
57 | import org.thingsboard.server.transport.mqtt.session.GatewaySessionCtx; | 50 | import org.thingsboard.server.transport.mqtt.session.GatewaySessionCtx; |
@@ -61,49 +54,19 @@ import javax.net.ssl.SSLPeerUnverifiedException; | @@ -61,49 +54,19 @@ import javax.net.ssl.SSLPeerUnverifiedException; | ||
61 | import javax.security.cert.X509Certificate; | 54 | import javax.security.cert.X509Certificate; |
62 | import java.io.IOException; | 55 | import java.io.IOException; |
63 | import java.net.InetSocketAddress; | 56 | import java.net.InetSocketAddress; |
64 | -import java.util.ArrayList; | ||
65 | import java.util.List; | 57 | import java.util.List; |
66 | import java.util.UUID; | 58 | import java.util.UUID; |
67 | import java.util.concurrent.ConcurrentHashMap; | 59 | import java.util.concurrent.ConcurrentHashMap; |
68 | import java.util.concurrent.ConcurrentMap; | 60 | import java.util.concurrent.ConcurrentMap; |
69 | 61 | ||
70 | -import org.thingsboard.server.gen.transport.TransportProtos.*; | ||
71 | - | ||
72 | import static io.netty.handler.codec.mqtt.MqttConnectReturnCode.CONNECTION_ACCEPTED; | 62 | import static io.netty.handler.codec.mqtt.MqttConnectReturnCode.CONNECTION_ACCEPTED; |
73 | import static io.netty.handler.codec.mqtt.MqttConnectReturnCode.CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD; | 63 | import static io.netty.handler.codec.mqtt.MqttConnectReturnCode.CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD; |
74 | import static io.netty.handler.codec.mqtt.MqttConnectReturnCode.CONNECTION_REFUSED_NOT_AUTHORIZED; | 64 | import static io.netty.handler.codec.mqtt.MqttConnectReturnCode.CONNECTION_REFUSED_NOT_AUTHORIZED; |
75 | import static io.netty.handler.codec.mqtt.MqttMessageType.CONNACK; | 65 | import static io.netty.handler.codec.mqtt.MqttMessageType.CONNACK; |
76 | -import static io.netty.handler.codec.mqtt.MqttMessageType.PINGRESP; | ||
77 | import static io.netty.handler.codec.mqtt.MqttMessageType.PUBACK; | 66 | import static io.netty.handler.codec.mqtt.MqttMessageType.PUBACK; |
78 | import static io.netty.handler.codec.mqtt.MqttMessageType.SUBACK; | 67 | import static io.netty.handler.codec.mqtt.MqttMessageType.SUBACK; |
79 | -import static io.netty.handler.codec.mqtt.MqttMessageType.UNSUBACK; | ||
80 | import static io.netty.handler.codec.mqtt.MqttQoS.AT_LEAST_ONCE; | 68 | import static io.netty.handler.codec.mqtt.MqttQoS.AT_LEAST_ONCE; |
81 | import static io.netty.handler.codec.mqtt.MqttQoS.AT_MOST_ONCE; | 69 | import static io.netty.handler.codec.mqtt.MqttQoS.AT_MOST_ONCE; |
82 | -import static io.netty.handler.codec.mqtt.MqttQoS.FAILURE; | ||
83 | -import static org.thingsboard.server.common.msg.session.SessionMsgType.GET_ATTRIBUTES_REQUEST; | ||
84 | -import static org.thingsboard.server.common.msg.session.SessionMsgType.POST_ATTRIBUTES_REQUEST; | ||
85 | -import static org.thingsboard.server.common.msg.session.SessionMsgType.POST_TELEMETRY_REQUEST; | ||
86 | -import static org.thingsboard.server.common.msg.session.SessionMsgType.SUBSCRIBE_ATTRIBUTES_REQUEST; | ||
87 | -import static org.thingsboard.server.common.msg.session.SessionMsgType.SUBSCRIBE_RPC_COMMANDS_REQUEST; | ||
88 | -import static org.thingsboard.server.common.msg.session.SessionMsgType.TO_DEVICE_RPC_RESPONSE; | ||
89 | -import static org.thingsboard.server.common.msg.session.SessionMsgType.TO_SERVER_RPC_REQUEST; | ||
90 | -import static org.thingsboard.server.common.msg.session.SessionMsgType.UNSUBSCRIBE_ATTRIBUTES_REQUEST; | ||
91 | -import static org.thingsboard.server.common.msg.session.SessionMsgType.UNSUBSCRIBE_RPC_COMMANDS_REQUEST; | ||
92 | -import static org.thingsboard.server.transport.mqtt.MqttTopics.BASE_GATEWAY_API_TOPIC; | ||
93 | -import static org.thingsboard.server.transport.mqtt.MqttTopics.DEVICE_ATTRIBUTES_REQUEST_TOPIC_PREFIX; | ||
94 | -import static org.thingsboard.server.transport.mqtt.MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_TOPIC; | ||
95 | -import static org.thingsboard.server.transport.mqtt.MqttTopics.DEVICE_ATTRIBUTES_TOPIC; | ||
96 | -import static org.thingsboard.server.transport.mqtt.MqttTopics.DEVICE_RPC_REQUESTS_SUB_TOPIC; | ||
97 | -import static org.thingsboard.server.transport.mqtt.MqttTopics.DEVICE_RPC_REQUESTS_TOPIC; | ||
98 | -import static org.thingsboard.server.transport.mqtt.MqttTopics.DEVICE_RPC_RESPONSE_SUB_TOPIC; | ||
99 | -import static org.thingsboard.server.transport.mqtt.MqttTopics.DEVICE_RPC_RESPONSE_TOPIC; | ||
100 | -import static org.thingsboard.server.transport.mqtt.MqttTopics.DEVICE_TELEMETRY_TOPIC; | ||
101 | -import static org.thingsboard.server.transport.mqtt.MqttTopics.GATEWAY_ATTRIBUTES_REQUEST_TOPIC; | ||
102 | -import static org.thingsboard.server.transport.mqtt.MqttTopics.GATEWAY_ATTRIBUTES_TOPIC; | ||
103 | -import static org.thingsboard.server.transport.mqtt.MqttTopics.GATEWAY_CONNECT_TOPIC; | ||
104 | -import static org.thingsboard.server.transport.mqtt.MqttTopics.GATEWAY_DISCONNECT_TOPIC; | ||
105 | -import static org.thingsboard.server.transport.mqtt.MqttTopics.GATEWAY_RPC_TOPIC; | ||
106 | -import static org.thingsboard.server.transport.mqtt.MqttTopics.GATEWAY_TELEMETRY_TOPIC; | ||
107 | 70 | ||
108 | /** | 71 | /** |
109 | * @author Andrew Shvayka | 72 | * @author Andrew Shvayka |
@@ -389,7 +352,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement | @@ -389,7 +352,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement | ||
389 | } else { | 352 | } else { |
390 | ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_ACCEPTED)); | 353 | ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_ACCEPTED)); |
391 | deviceSessionCtx.setDeviceInfo(msg.getDeviceInfo()); | 354 | deviceSessionCtx.setDeviceInfo(msg.getDeviceInfo()); |
392 | - transportService.process(getSessionEventMsg(SessionEvent.OPEN), null); | 355 | + transportService.process(deviceSessionCtx, getSessionEventMsg(SessionEvent.OPEN), null); |
393 | checkGatewaySession(); | 356 | checkGatewaySession(); |
394 | } | 357 | } |
395 | } | 358 | } |
@@ -418,7 +381,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement | @@ -418,7 +381,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement | ||
418 | } else { | 381 | } else { |
419 | ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_ACCEPTED)); | 382 | ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_ACCEPTED)); |
420 | deviceSessionCtx.setDeviceInfo(msg.getDeviceInfo()); | 383 | deviceSessionCtx.setDeviceInfo(msg.getDeviceInfo()); |
421 | - transportService.process(getSessionEventMsg(SessionEvent.OPEN), null); | 384 | + transportService.process(deviceSessionCtx, getSessionEventMsg(SessionEvent.OPEN), null); |
422 | checkGatewaySession(); | 385 | checkGatewaySession(); |
423 | } | 386 | } |
424 | } | 387 | } |
@@ -452,7 +415,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement | @@ -452,7 +415,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement | ||
452 | private void processDisconnect(ChannelHandlerContext ctx) { | 415 | private void processDisconnect(ChannelHandlerContext ctx) { |
453 | ctx.close(); | 416 | ctx.close(); |
454 | if (deviceSessionCtx.isConnected()) { | 417 | if (deviceSessionCtx.isConnected()) { |
455 | - transportService.process(getSessionEventMsg(SessionEvent.CLOSED), null); | 418 | + transportService.process(deviceSessionCtx, getSessionEventMsg(SessionEvent.CLOSED), null); |
456 | if (gatewaySessionCtx != null) { | 419 | if (gatewaySessionCtx != null) { |
457 | gatewaySessionCtx.onGatewayDisconnect(); | 420 | gatewaySessionCtx.onGatewayDisconnect(); |
458 | } | 421 | } |
@@ -534,7 +497,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement | @@ -534,7 +497,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement | ||
534 | @Override | 497 | @Override |
535 | public void operationComplete(Future<? super Void> future) throws Exception { | 498 | public void operationComplete(Future<? super Void> future) throws Exception { |
536 | if (deviceSessionCtx.isConnected()) { | 499 | if (deviceSessionCtx.isConnected()) { |
537 | - transportService.process(getSessionEventMsg(SessionEvent.CLOSED), null); | 500 | + transportService.process(deviceSessionCtx, getSessionEventMsg(SessionEvent.CLOSED), null); |
538 | } | 501 | } |
539 | } | 502 | } |
540 | } | 503 | } |
transport/mqtt-transport/src/main/java/org/thingsboard/server/mqtt/service/MqttTransportService.java
1 | /** | 1 | /** |
2 | * Copyright © 2016-2018 The Thingsboard Authors | 2 | * Copyright © 2016-2018 The Thingsboard Authors |
3 | - * | 3 | + * <p> |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. | 5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at | 6 | * You may obtain a copy of the License at |
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | 7 | + * <p> |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * <p> | ||
10 | * Unless required by applicable law or agreed to in writing, software | 10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
@@ -15,21 +15,41 @@ | @@ -15,21 +15,41 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.mqtt.service; | 16 | package org.thingsboard.server.mqtt.service; |
17 | 17 | ||
18 | +import lombok.extern.slf4j.Slf4j; | ||
19 | +import org.apache.kafka.clients.consumer.ConsumerRecords; | ||
20 | +import org.apache.kafka.clients.producer.Callback; | ||
21 | +import org.apache.kafka.clients.producer.RecordMetadata; | ||
18 | import org.springframework.beans.factory.annotation.Autowired; | 22 | import org.springframework.beans.factory.annotation.Autowired; |
19 | import org.springframework.beans.factory.annotation.Value; | 23 | import org.springframework.beans.factory.annotation.Value; |
20 | import org.springframework.stereotype.Service; | 24 | import org.springframework.stereotype.Service; |
25 | +import org.thingsboard.server.common.transport.SessionMsgListener; | ||
21 | import org.thingsboard.server.common.transport.TransportService; | 26 | import org.thingsboard.server.common.transport.TransportService; |
22 | import org.thingsboard.server.common.transport.TransportServiceCallback; | 27 | import org.thingsboard.server.common.transport.TransportServiceCallback; |
28 | +import org.thingsboard.server.gen.transport.TransportProtos; | ||
29 | +import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg; | ||
30 | +import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg; | ||
31 | +import org.thingsboard.server.gen.transport.TransportProtos.SessionEventMsg; | ||
32 | +import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; | ||
33 | +import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; | ||
34 | +import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; | ||
35 | +import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; | ||
36 | +import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; | ||
37 | +import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; | ||
38 | +import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceTokenRequestMsg; | ||
39 | +import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509CertRequestMsg; | ||
23 | import org.thingsboard.server.kafka.AsyncCallbackTemplate; | 40 | import org.thingsboard.server.kafka.AsyncCallbackTemplate; |
24 | import org.thingsboard.server.kafka.TBKafkaConsumerTemplate; | 41 | import org.thingsboard.server.kafka.TBKafkaConsumerTemplate; |
25 | import org.thingsboard.server.kafka.TBKafkaProducerTemplate; | 42 | import org.thingsboard.server.kafka.TBKafkaProducerTemplate; |
26 | import org.thingsboard.server.kafka.TbKafkaRequestTemplate; | 43 | import org.thingsboard.server.kafka.TbKafkaRequestTemplate; |
27 | -import org.thingsboard.server.gen.transport.TransportProtos.*; | ||
28 | import org.thingsboard.server.kafka.TbKafkaSettings; | 44 | import org.thingsboard.server.kafka.TbKafkaSettings; |
29 | import org.thingsboard.server.transport.mqtt.MqttTransportContext; | 45 | import org.thingsboard.server.transport.mqtt.MqttTransportContext; |
30 | 46 | ||
31 | import javax.annotation.PostConstruct; | 47 | import javax.annotation.PostConstruct; |
32 | import javax.annotation.PreDestroy; | 48 | import javax.annotation.PreDestroy; |
49 | +import java.time.Duration; | ||
50 | +import java.util.UUID; | ||
51 | +import java.util.concurrent.ConcurrentHashMap; | ||
52 | +import java.util.concurrent.ConcurrentMap; | ||
33 | import java.util.concurrent.ExecutorService; | 53 | import java.util.concurrent.ExecutorService; |
34 | import java.util.concurrent.Executors; | 54 | import java.util.concurrent.Executors; |
35 | 55 | ||
@@ -37,10 +57,17 @@ import java.util.concurrent.Executors; | @@ -37,10 +57,17 @@ import java.util.concurrent.Executors; | ||
37 | * Created by ashvayka on 05.10.18. | 57 | * Created by ashvayka on 05.10.18. |
38 | */ | 58 | */ |
39 | @Service | 59 | @Service |
60 | +@Slf4j | ||
40 | public class MqttTransportService implements TransportService { | 61 | public class MqttTransportService implements TransportService { |
41 | 62 | ||
42 | @Value("${kafka.rule_engine.topic}") | 63 | @Value("${kafka.rule_engine.topic}") |
43 | private String ruleEngineTopic; | 64 | private String ruleEngineTopic; |
65 | + @Value("${kafka.notifications.topic}") | ||
66 | + private String notificationsTopic; | ||
67 | + @Value("${kafka.notifications.poll_interval}") | ||
68 | + private int notificationsPollDuration; | ||
69 | + @Value("${kafka.notifications.auto_commit_interval}") | ||
70 | + private int notificationsAutoCommitInterval; | ||
44 | @Value("${kafka.transport_api.requests_topic}") | 71 | @Value("${kafka.transport_api.requests_topic}") |
45 | private String transportApiRequestsTopic; | 72 | private String transportApiRequestsTopic; |
46 | @Value("${kafka.transport_api.responses_topic}") | 73 | @Value("${kafka.transport_api.responses_topic}") |
@@ -54,6 +81,8 @@ public class MqttTransportService implements TransportService { | @@ -54,6 +81,8 @@ public class MqttTransportService implements TransportService { | ||
54 | @Value("${kafka.transport_api.response_auto_commit_interval}") | 81 | @Value("${kafka.transport_api.response_auto_commit_interval}") |
55 | private int autoCommitInterval; | 82 | private int autoCommitInterval; |
56 | 83 | ||
84 | + private ConcurrentMap<UUID, SessionMsgListener> sessions = new ConcurrentHashMap<>(); | ||
85 | + | ||
57 | @Autowired | 86 | @Autowired |
58 | private TbKafkaSettings kafkaSettings; | 87 | private TbKafkaSettings kafkaSettings; |
59 | //We use this to get the node id. We should replace this with a component that provides the node id. | 88 | //We use this to get the node id. We should replace this with a component that provides the node id. |
@@ -63,6 +92,12 @@ public class MqttTransportService implements TransportService { | @@ -63,6 +92,12 @@ public class MqttTransportService implements TransportService { | ||
63 | private ExecutorService transportCallbackExecutor; | 92 | private ExecutorService transportCallbackExecutor; |
64 | 93 | ||
65 | private TbKafkaRequestTemplate<TransportApiRequestMsg, TransportApiResponseMsg> transportApiTemplate; | 94 | private TbKafkaRequestTemplate<TransportApiRequestMsg, TransportApiResponseMsg> transportApiTemplate; |
95 | + private TBKafkaProducerTemplate<ToRuleEngineMsg> ruleEngineProducer; | ||
96 | + private TBKafkaConsumerTemplate<ToTransportMsg> mainConsumer; | ||
97 | + | ||
98 | + private ExecutorService mainConsumerExecutor = Executors.newSingleThreadExecutor(); | ||
99 | + | ||
100 | + private volatile boolean stopped = false; | ||
66 | 101 | ||
67 | @PostConstruct | 102 | @PostConstruct |
68 | public void init() { | 103 | public void init() { |
@@ -77,7 +112,7 @@ public class MqttTransportService implements TransportService { | @@ -77,7 +112,7 @@ public class MqttTransportService implements TransportService { | ||
77 | responseBuilder.settings(kafkaSettings); | 112 | responseBuilder.settings(kafkaSettings); |
78 | responseBuilder.topic(transportApiResponsesTopic + "." + transportContext.getNodeId()); | 113 | responseBuilder.topic(transportApiResponsesTopic + "." + transportContext.getNodeId()); |
79 | responseBuilder.clientId(transportContext.getNodeId()); | 114 | responseBuilder.clientId(transportContext.getNodeId()); |
80 | - responseBuilder.groupId("transport-node"); | 115 | + responseBuilder.groupId(null); |
81 | responseBuilder.autoCommit(true); | 116 | responseBuilder.autoCommit(true); |
82 | responseBuilder.autoCommitIntervalMs(autoCommitInterval); | 117 | responseBuilder.autoCommitIntervalMs(autoCommitInterval); |
83 | responseBuilder.decoder(new TransportApiResponseDecoder()); | 118 | responseBuilder.decoder(new TransportApiResponseDecoder()); |
@@ -91,16 +126,79 @@ public class MqttTransportService implements TransportService { | @@ -91,16 +126,79 @@ public class MqttTransportService implements TransportService { | ||
91 | builder.pollInterval(responsePollDuration); | 126 | builder.pollInterval(responsePollDuration); |
92 | transportApiTemplate = builder.build(); | 127 | transportApiTemplate = builder.build(); |
93 | transportApiTemplate.init(); | 128 | transportApiTemplate.init(); |
129 | + | ||
130 | + TBKafkaProducerTemplate.TBKafkaProducerTemplateBuilder<ToRuleEngineMsg> ruleEngineProducerBuilder = TBKafkaProducerTemplate.builder(); | ||
131 | + ruleEngineProducerBuilder.settings(kafkaSettings); | ||
132 | + ruleEngineProducerBuilder.defaultTopic(ruleEngineTopic); | ||
133 | + ruleEngineProducerBuilder.encoder(new ToRuleEngineMsgEncoder()); | ||
134 | + ruleEngineProducer = ruleEngineProducerBuilder.build(); | ||
135 | + ruleEngineProducer.init(); | ||
136 | + | ||
137 | + TBKafkaConsumerTemplate.TBKafkaConsumerTemplateBuilder<ToTransportMsg> mainConsumerBuilder = TBKafkaConsumerTemplate.builder(); | ||
138 | + mainConsumerBuilder.settings(kafkaSettings); | ||
139 | + mainConsumerBuilder.topic(notificationsTopic + "." + transportContext.getNodeId()); | ||
140 | + mainConsumerBuilder.clientId(transportContext.getNodeId()); | ||
141 | + mainConsumerBuilder.groupId(null); | ||
142 | + mainConsumerBuilder.autoCommit(true); | ||
143 | + mainConsumerBuilder.autoCommitIntervalMs(notificationsAutoCommitInterval); | ||
144 | + mainConsumerBuilder.decoder(new ToTransportMsgResponseDecoder()); | ||
145 | + mainConsumer = mainConsumerBuilder.build(); | ||
146 | + mainConsumer.subscribe(); | ||
147 | + | ||
148 | + mainConsumerExecutor.execute(() -> { | ||
149 | + while (!stopped) { | ||
150 | + try { | ||
151 | + ConsumerRecords<String, byte[]> records = mainConsumer.poll(Duration.ofMillis(notificationsPollDuration)); | ||
152 | + records.forEach(record -> { | ||
153 | + try { | ||
154 | + ToTransportMsg toTransportMsg = mainConsumer.decode(record); | ||
155 | + if (toTransportMsg.hasToDeviceSessionMsg()) { | ||
156 | + TransportProtos.DeviceActorToTransportMsg toSessionMsg = toTransportMsg.getToDeviceSessionMsg(); | ||
157 | + UUID sessionId = new UUID(toSessionMsg.getSessionIdMSB(), toSessionMsg.getSessionIdLSB()); | ||
158 | + SessionMsgListener listener = sessions.get(sessionId); | ||
159 | + if (listener != null) { | ||
160 | + transportCallbackExecutor.submit(() -> { | ||
161 | + if (toSessionMsg.hasGetAttributesResponse()) { | ||
162 | + listener.onGetAttributesResponse(toSessionMsg.getGetAttributesResponse()); | ||
163 | + } | ||
164 | + }); | ||
165 | + } else { | ||
166 | + //TODO: should we notify the device actor about missed session? | ||
167 | + log.debug("[{}] Missing session.", sessionId); | ||
168 | + } | ||
169 | + | ||
170 | + } | ||
171 | + } catch (Throwable e) { | ||
172 | + log.warn("Failed to process the notification.", e); | ||
173 | + } | ||
174 | + }); | ||
175 | + } catch (Exception e) { | ||
176 | + log.warn("Failed to obtain messages from queue.", e); | ||
177 | + try { | ||
178 | + Thread.sleep(notificationsPollDuration); | ||
179 | + } catch (InterruptedException e2) { | ||
180 | + log.trace("Failed to wait until the server has capacity to handle new requests", e2); | ||
181 | + } | ||
182 | + } | ||
183 | + } | ||
184 | + }); | ||
94 | } | 185 | } |
95 | 186 | ||
96 | @PreDestroy | 187 | @PreDestroy |
97 | public void destroy() { | 188 | public void destroy() { |
189 | + stopped = true; | ||
98 | if (transportApiTemplate != null) { | 190 | if (transportApiTemplate != null) { |
99 | transportApiTemplate.stop(); | 191 | transportApiTemplate.stop(); |
100 | } | 192 | } |
101 | if (transportCallbackExecutor != null) { | 193 | if (transportCallbackExecutor != null) { |
102 | transportCallbackExecutor.shutdownNow(); | 194 | transportCallbackExecutor.shutdownNow(); |
103 | } | 195 | } |
196 | + if (mainConsumer != null) { | ||
197 | + mainConsumer.unsubscribe(); | ||
198 | + } | ||
199 | + if (mainConsumerExecutor != null) { | ||
200 | + mainConsumerExecutor.shutdownNow(); | ||
201 | + } | ||
104 | } | 202 | } |
105 | 203 | ||
106 | @Override | 204 | @Override |
@@ -118,17 +216,69 @@ public class MqttTransportService implements TransportService { | @@ -118,17 +216,69 @@ public class MqttTransportService implements TransportService { | ||
118 | } | 216 | } |
119 | 217 | ||
120 | @Override | 218 | @Override |
121 | - public void process(SessionEventMsg msg, TransportServiceCallback<Void> callback) { | 219 | + public void process(SessionInfoProto sessionInfo, SessionEventMsg msg, TransportServiceCallback<Void> callback) { |
220 | + ToRuleEngineMsg toRuleEngineMsg = ToRuleEngineMsg.newBuilder().setToDeviceActorMsg( | ||
221 | + TransportProtos.TransportToDeviceActorMsg.newBuilder().setSessionInfo(sessionInfo) | ||
222 | + .setSessionEvent(msg).build() | ||
223 | + ).build(); | ||
224 | + send(sessionInfo, toRuleEngineMsg, callback); | ||
225 | + } | ||
122 | 226 | ||
227 | + @Override | ||
228 | + public void process(SessionInfoProto sessionInfo, PostTelemetryMsg msg, TransportServiceCallback<Void> callback) { | ||
229 | + ToRuleEngineMsg toRuleEngineMsg = ToRuleEngineMsg.newBuilder().setToDeviceActorMsg( | ||
230 | + TransportProtos.TransportToDeviceActorMsg.newBuilder().setSessionInfo(sessionInfo) | ||
231 | + .setPostTelemetry(msg).build() | ||
232 | + ).build(); | ||
233 | + send(sessionInfo, toRuleEngineMsg, callback); | ||
123 | } | 234 | } |
124 | 235 | ||
125 | @Override | 236 | @Override |
126 | - public void process(PostTelemetryMsg msg, TransportServiceCallback<Void> callback) { | 237 | + public void process(SessionInfoProto sessionInfo, PostAttributeMsg msg, TransportServiceCallback<Void> callback) { |
238 | + ToRuleEngineMsg toRuleEngineMsg = ToRuleEngineMsg.newBuilder().setToDeviceActorMsg( | ||
239 | + TransportProtos.TransportToDeviceActorMsg.newBuilder().setSessionInfo(sessionInfo) | ||
240 | + .setPostAttributes(msg).build() | ||
241 | + ).build(); | ||
242 | + send(sessionInfo, toRuleEngineMsg, callback); | ||
243 | + } | ||
127 | 244 | ||
245 | + @Override | ||
246 | + public void registerSession(SessionInfoProto sessionInfo, SessionMsgListener listener) { | ||
247 | + sessions.putIfAbsent(toId(sessionInfo), listener); | ||
248 | + //TODO: monitor sessions periodically: PING REQ/RESP, etc. | ||
128 | } | 249 | } |
129 | 250 | ||
130 | @Override | 251 | @Override |
131 | - public void process(PostAttributeMsg msg, TransportServiceCallback<Void> callback) { | 252 | + public void deregisterSession(SessionInfoProto sessionInfo) { |
253 | + sessions.remove(toId(sessionInfo)); | ||
254 | + } | ||
255 | + | ||
256 | + private UUID toId(SessionInfoProto sessionInfo) { | ||
257 | + return new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()); | ||
258 | + } | ||
259 | + | ||
260 | + private String getRoutingKey(SessionInfoProto sessionInfo) { | ||
261 | + return new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB()).toString(); | ||
262 | + } | ||
263 | + | ||
264 | + private static class TransportCallbackAdaptor implements Callback { | ||
265 | + private final TransportServiceCallback<Void> callback; | ||
266 | + | ||
267 | + TransportCallbackAdaptor(TransportServiceCallback<Void> callback) { | ||
268 | + this.callback = callback; | ||
269 | + } | ||
270 | + | ||
271 | + @Override | ||
272 | + public void onCompletion(RecordMetadata metadata, Exception exception) { | ||
273 | + if (exception == null) { | ||
274 | + callback.onSuccess(null); | ||
275 | + } else { | ||
276 | + callback.onError(exception); | ||
277 | + } | ||
278 | + } | ||
279 | + } | ||
132 | 280 | ||
281 | + private void send(SessionInfoProto sessionInfo, ToRuleEngineMsg toRuleEngineMsg, TransportServiceCallback<Void> callback) { | ||
282 | + ruleEngineProducer.send(getRoutingKey(sessionInfo), toRuleEngineMsg, new TransportCallbackAdaptor(callback)); | ||
133 | } | 283 | } |
134 | } | 284 | } |
1 | +/** | ||
2 | + * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | + * <p> | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * <p> | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * <p> | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.mqtt.service; | ||
17 | + | ||
18 | +import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; | ||
19 | +import org.thingsboard.server.kafka.TbKafkaEncoder; | ||
20 | + | ||
21 | +/** | ||
22 | + * Created by ashvayka on 05.10.18. | ||
23 | + */ | ||
24 | +public class ToRuleEngineMsgEncoder implements TbKafkaEncoder<ToRuleEngineMsg> { | ||
25 | + @Override | ||
26 | + public byte[] encode(ToRuleEngineMsg value) { | ||
27 | + return value.toByteArray(); | ||
28 | + } | ||
29 | +} |
transport/mqtt-transport/src/main/java/org/thingsboard/server/mqtt/service/ToTransportMsgResponseDecoder.java
renamed from
common/message/src/main/java/org/thingsboard/server/common/msg/device/DeviceToDeviceActorMsg.java
@@ -13,29 +13,19 @@ | @@ -13,29 +13,19 @@ | ||
13 | * See the License for the specific language governing permissions and | 13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | -package org.thingsboard.server.common.msg.device; | 16 | +package org.thingsboard.server.mqtt.service; |
17 | 17 | ||
18 | -import java.io.Serializable; | ||
19 | -import java.util.Optional; | 18 | +import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; |
19 | +import org.thingsboard.server.kafka.TbKafkaDecoder; | ||
20 | 20 | ||
21 | -import org.thingsboard.server.common.data.id.SessionId; | ||
22 | -import org.thingsboard.server.common.msg.TbActorMsg; | ||
23 | -import org.thingsboard.server.common.msg.aware.CustomerAwareMsg; | ||
24 | -import org.thingsboard.server.common.msg.aware.DeviceAwareMsg; | ||
25 | -import org.thingsboard.server.common.msg.aware.TenantAwareMsg; | ||
26 | -import org.thingsboard.server.common.msg.cluster.ServerAddress; | ||
27 | -import org.thingsboard.server.common.msg.session.FromDeviceMsg; | ||
28 | -import org.thingsboard.server.common.msg.session.SessionType; | 21 | +import java.io.IOException; |
29 | 22 | ||
30 | -public interface DeviceToDeviceActorMsg extends TbActorMsg, DeviceAwareMsg, CustomerAwareMsg, TenantAwareMsg, Serializable { | ||
31 | - | ||
32 | - SessionId getSessionId(); | ||
33 | - | ||
34 | - SessionType getSessionType(); | ||
35 | - | ||
36 | - Optional<ServerAddress> getServerAddress(); | ||
37 | - | ||
38 | - FromDeviceMsg getPayload(); | ||
39 | - | ||
40 | - DeviceToDeviceActorMsg toOtherAddress(ServerAddress otherAddress); | 23 | +/** |
24 | + * Created by ashvayka on 05.10.18. | ||
25 | + */ | ||
26 | +public class ToTransportMsgResponseDecoder implements TbKafkaDecoder<ToTransportMsg> { | ||
27 | + @Override | ||
28 | + public ToTransportMsg decode(byte[] data) throws IOException { | ||
29 | + return ToTransportMsg.parseFrom(data); | ||
30 | + } | ||
41 | } | 31 | } |
@@ -82,3 +82,7 @@ kafka: | @@ -82,3 +82,7 @@ kafka: | ||
82 | response_auto_commit_interval: "${TB_TRANSPORT_RESPONSE_AUTO_COMMIT_INTERVAL_MS:100}" | 82 | response_auto_commit_interval: "${TB_TRANSPORT_RESPONSE_AUTO_COMMIT_INTERVAL_MS:100}" |
83 | rule_engine: | 83 | rule_engine: |
84 | topic: "${TB_RULE_ENGINE_TOPIC:tb.rule-engine}" | 84 | topic: "${TB_RULE_ENGINE_TOPIC:tb.rule-engine}" |
85 | + notifications: | ||
86 | + topic: "${TB_TRANSPORT_NOTIFICATIONS_TOPIC:tb.transport.notifications}" | ||
87 | + poll_interval: "${TB_TRANSPORT_NOTIFICATIONS_POLL_INTERVAL_MS:25}" | ||
88 | + auto_commit_interval: "${TB_TRANSPORT_NOTIFICATIONS_AUTO_COMMIT_INTERVAL_MS:100}" |