|
|
|
@ -5,7 +5,7 @@ |
|
|
|
* you may not use this file except in compliance with the License. |
|
|
|
* You may obtain a copy of the License at |
|
|
|
* |
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
* |
|
|
|
* Unless required by applicable law or agreed to in writing, software |
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
|
|
@ -16,16 +16,14 @@ |
|
|
|
package org.thingsboard.server.common.transport.service; |
|
|
|
|
|
|
|
import lombok.extern.slf4j.Slf4j; |
|
|
|
import org.apache.kafka.clients.admin.CreateTopicsResult; |
|
|
|
import org.apache.kafka.clients.admin.NewTopic; |
|
|
|
import org.apache.kafka.clients.consumer.ConsumerRecords; |
|
|
|
import org.apache.kafka.clients.producer.Callback; |
|
|
|
import org.apache.kafka.clients.producer.RecordMetadata; |
|
|
|
import org.springframework.beans.factory.annotation.Autowired; |
|
|
|
import org.springframework.beans.factory.annotation.Value; |
|
|
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
|
|
|
import org.springframework.stereotype.Service; |
|
|
|
import org.thingsboard.common.util.ThingsBoardThreadFactory; |
|
|
|
import org.thingsboard.server.TbQueueCallback; |
|
|
|
import org.thingsboard.server.TbQueueMsgMetadata; |
|
|
|
import org.thingsboard.server.common.TbProtoQueueMsg; |
|
|
|
import org.thingsboard.server.common.transport.TransportServiceCallback; |
|
|
|
import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg; |
|
|
|
import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg; |
|
|
|
@ -43,22 +41,18 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
|
|
|
import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcRequestMsg; |
|
|
|
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; |
|
|
|
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; |
|
|
|
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; |
|
|
|
import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg; |
|
|
|
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; |
|
|
|
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceTokenRequestMsg; |
|
|
|
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509CertRequestMsg; |
|
|
|
import org.thingsboard.server.kafka.AsyncCallbackTemplate; |
|
|
|
import org.thingsboard.server.kafka.TBKafkaAdmin; |
|
|
|
import org.thingsboard.server.kafka.TBKafkaConsumerTemplate; |
|
|
|
import org.thingsboard.server.kafka.TBKafkaProducerTemplate; |
|
|
|
import org.thingsboard.server.kafka.TbKafkaRequestTemplate; |
|
|
|
import org.thingsboard.server.kafka.TbKafkaSettings; |
|
|
|
import org.thingsboard.server.kafka.TbNodeIdProvider; |
|
|
|
|
|
|
|
import javax.annotation.PostConstruct; |
|
|
|
import javax.annotation.PreDestroy; |
|
|
|
import java.time.Duration; |
|
|
|
import java.util.List; |
|
|
|
import java.util.UUID; |
|
|
|
import java.util.concurrent.ExecutorService; |
|
|
|
import java.util.concurrent.Executors; |
|
|
|
|
|
|
|
@ -97,10 +91,6 @@ public class RemoteTransportService extends AbstractTransportService { |
|
|
|
@Autowired |
|
|
|
private TbNodeIdProvider nodeIdProvider; |
|
|
|
|
|
|
|
private TbKafkaRequestTemplate<TransportApiRequestMsg, TransportApiResponseMsg> transportApiTemplate; |
|
|
|
private TBKafkaProducerTemplate<ToRuleEngineMsg> ruleEngineProducer; |
|
|
|
private TBKafkaConsumerTemplate<ToTransportMsg> mainConsumer; |
|
|
|
|
|
|
|
private ExecutorService mainConsumerExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("remote-transport-consumer")); |
|
|
|
|
|
|
|
private volatile boolean stopped = false; |
|
|
|
@ -109,67 +99,67 @@ public class RemoteTransportService extends AbstractTransportService { |
|
|
|
public void init() { |
|
|
|
super.init(); |
|
|
|
|
|
|
|
TBKafkaProducerTemplate.TBKafkaProducerTemplateBuilder<TransportApiRequestMsg> requestBuilder = TBKafkaProducerTemplate.builder(); |
|
|
|
requestBuilder.settings(kafkaSettings); |
|
|
|
requestBuilder.clientId("producer-transport-api-request-" + nodeIdProvider.getNodeId()); |
|
|
|
requestBuilder.defaultTopic(transportApiRequestsTopic); |
|
|
|
requestBuilder.encoder(new TransportApiRequestEncoder()); |
|
|
|
|
|
|
|
TBKafkaConsumerTemplate.TBKafkaConsumerTemplateBuilder<TransportApiResponseMsg> responseBuilder = TBKafkaConsumerTemplate.builder(); |
|
|
|
responseBuilder.settings(kafkaSettings); |
|
|
|
responseBuilder.topic(transportApiResponsesTopic + "." + nodeIdProvider.getNodeId()); |
|
|
|
responseBuilder.clientId("transport-api-client-" + nodeIdProvider.getNodeId()); |
|
|
|
responseBuilder.groupId("transport-api-client"); |
|
|
|
responseBuilder.autoCommit(true); |
|
|
|
responseBuilder.autoCommitIntervalMs(autoCommitInterval); |
|
|
|
responseBuilder.decoder(new TransportApiResponseDecoder()); |
|
|
|
|
|
|
|
TbKafkaRequestTemplate.TbKafkaRequestTemplateBuilder |
|
|
|
<TransportApiRequestMsg, TransportApiResponseMsg> builder = TbKafkaRequestTemplate.builder(); |
|
|
|
builder.requestTemplate(requestBuilder.build()); |
|
|
|
builder.responseTemplate(responseBuilder.build()); |
|
|
|
builder.maxPendingRequests(maxPendingRequests); |
|
|
|
builder.maxRequestTimeout(maxRequestsTimeout); |
|
|
|
builder.pollInterval(responsePollDuration); |
|
|
|
transportApiTemplate = builder.build(); |
|
|
|
transportApiTemplate.init(); |
|
|
|
|
|
|
|
TBKafkaProducerTemplate.TBKafkaProducerTemplateBuilder<ToRuleEngineMsg> ruleEngineProducerBuilder = TBKafkaProducerTemplate.builder(); |
|
|
|
ruleEngineProducerBuilder.settings(kafkaSettings); |
|
|
|
ruleEngineProducerBuilder.clientId("producer-rule-engine-request-" + nodeIdProvider.getNodeId()); |
|
|
|
ruleEngineProducerBuilder.defaultTopic(ruleEngineTopic); |
|
|
|
ruleEngineProducerBuilder.encoder(new ToRuleEngineMsgEncoder()); |
|
|
|
ruleEngineProducer = ruleEngineProducerBuilder.build(); |
|
|
|
ruleEngineProducer.init(); |
|
|
|
|
|
|
|
String notificationsTopicName = notificationsTopic + "." + nodeIdProvider.getNodeId(); |
|
|
|
|
|
|
|
try { |
|
|
|
TBKafkaAdmin admin = new TBKafkaAdmin(kafkaSettings); |
|
|
|
CreateTopicsResult result = admin.createTopic(new NewTopic(notificationsTopicName, 1, (short) 1)); |
|
|
|
result.all().get(); |
|
|
|
} catch (Exception e) { |
|
|
|
log.trace("Failed to create topic: {}", e.getMessage(), e); |
|
|
|
} |
|
|
|
|
|
|
|
TBKafkaConsumerTemplate.TBKafkaConsumerTemplateBuilder<ToTransportMsg> mainConsumerBuilder = TBKafkaConsumerTemplate.builder(); |
|
|
|
mainConsumerBuilder.settings(kafkaSettings); |
|
|
|
mainConsumerBuilder.topic(notificationsTopicName); |
|
|
|
mainConsumerBuilder.clientId("transport-" + nodeIdProvider.getNodeId()); |
|
|
|
mainConsumerBuilder.groupId("transport"); |
|
|
|
mainConsumerBuilder.autoCommit(true); |
|
|
|
mainConsumerBuilder.autoCommitIntervalMs(notificationsAutoCommitInterval); |
|
|
|
mainConsumerBuilder.decoder(new ToTransportMsgResponseDecoder()); |
|
|
|
mainConsumer = mainConsumerBuilder.build(); |
|
|
|
mainConsumer.subscribe(); |
|
|
|
// TBKafkaProducerTemplate.TBKafkaProducerTemplateBuilder<TransportApiRequestMsg> requestBuilder = TBKafkaProducerTemplate.builder();
|
|
|
|
// requestBuilder.settings(kafkaSettings);
|
|
|
|
// requestBuilder.clientId("producer-transport-api-request-" + nodeIdProvider.getNodeId());
|
|
|
|
// requestBuilder.defaultTopic(transportApiRequestsTopic);
|
|
|
|
// requestBuilder.encoder(new TransportApiRequestEncoder());
|
|
|
|
//
|
|
|
|
// TBKafkaConsumerTemplate.TBKafkaConsumerTemplateBuilder<TransportApiResponseMsg> responseBuilder = TBKafkaConsumerTemplate.builder();
|
|
|
|
// responseBuilder.settings(kafkaSettings);
|
|
|
|
// responseBuilder.topic(transportApiResponsesTopic + "." + nodeIdProvider.getNodeId());
|
|
|
|
// responseBuilder.clientId("transport-api-client-" + nodeIdProvider.getNodeId());
|
|
|
|
// responseBuilder.groupId("transport-api-client");
|
|
|
|
// responseBuilder.autoCommit(true);
|
|
|
|
// responseBuilder.autoCommitIntervalMs(autoCommitInterval);
|
|
|
|
// responseBuilder.decoder(new TransportApiResponseDecoder());
|
|
|
|
//
|
|
|
|
// TbKafkaRequestTemplate.TbKafkaRequestTemplateBuilder
|
|
|
|
// <TransportApiRequestMsg, TransportApiResponseMsg> builder = TbKafkaRequestTemplate.builder();
|
|
|
|
// builder.requestTemplate(requestBuilder.build());
|
|
|
|
// builder.responseTemplate(responseBuilder.build());
|
|
|
|
// builder.maxPendingRequests(maxPendingRequests);
|
|
|
|
// builder.maxRequestTimeout(maxRequestsTimeout);
|
|
|
|
// builder.pollInterval(responsePollDuration);
|
|
|
|
// transportApiTemplate = builder.build();
|
|
|
|
// transportApiTemplate.init();
|
|
|
|
//
|
|
|
|
// TBKafkaProducerTemplate.TBKafkaProducerTemplateBuilder<ToRuleEngineMsg> ruleEngineProducerBuilder = TBKafkaProducerTemplate.builder();
|
|
|
|
// ruleEngineProducerBuilder.settings(kafkaSettings);
|
|
|
|
// ruleEngineProducerBuilder.clientId("producer-rule-engine-request-" + nodeIdProvider.getNodeId());
|
|
|
|
// ruleEngineProducerBuilder.defaultTopic(ruleEngineTopic);
|
|
|
|
// ruleEngineProducerBuilder.encoder(new ToRuleEngineMsgEncoder());
|
|
|
|
// ruleEngineProducer = ruleEngineProducerBuilder.build();
|
|
|
|
// ruleEngineProducer.init();
|
|
|
|
//
|
|
|
|
// String notificationsTopicName = notificationsTopic + "." + nodeIdProvider.getNodeId();
|
|
|
|
//
|
|
|
|
// try {
|
|
|
|
// TBKafkaAdmin admin = new TBKafkaAdmin(kafkaSettings);
|
|
|
|
// CreateTopicsResult result = admin.createTopic(new NewTopic(notificationsTopicName, 1, (short) 1));
|
|
|
|
// result.all().get();
|
|
|
|
// } catch (Exception e) {
|
|
|
|
// log.trace("Failed to create topic: {}", e.getMessage(), e);
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// TBKafkaConsumerTemplate.TBKafkaConsumerTemplateBuilder<ToTransportMsg> mainConsumerBuilder = TBKafkaConsumerTemplate.builder();
|
|
|
|
// mainConsumerBuilder.settings(kafkaSettings);
|
|
|
|
// mainConsumerBuilder.topic(notificationsTopicName);
|
|
|
|
// mainConsumerBuilder.clientId("transport-" + nodeIdProvider.getNodeId());
|
|
|
|
// mainConsumerBuilder.groupId("transport");
|
|
|
|
// mainConsumerBuilder.autoCommit(true);
|
|
|
|
// mainConsumerBuilder.autoCommitIntervalMs(notificationsAutoCommitInterval);
|
|
|
|
// mainConsumerBuilder.decoder(new ToTransportMsgResponseDecoder());
|
|
|
|
// mainConsumer = mainConsumerBuilder.build();
|
|
|
|
// mainConsumer.subscribe();
|
|
|
|
|
|
|
|
mainConsumerExecutor.execute(() -> { |
|
|
|
while (!stopped) { |
|
|
|
try { |
|
|
|
ConsumerRecords<String, byte[]> records = mainConsumer.poll(Duration.ofMillis(notificationsPollDuration)); |
|
|
|
List<TbProtoQueueMsg<ToTransportMsg>> records = transportNotificationsConsumer.poll(notificationsPollDuration); |
|
|
|
records.forEach(record -> { |
|
|
|
try { |
|
|
|
ToTransportMsg toTransportMsg = mainConsumer.decode(record); |
|
|
|
ToTransportMsg toTransportMsg = record.getValue(); |
|
|
|
if (toTransportMsg.hasToDeviceSessionMsg()) { |
|
|
|
processToTransportMsg(toTransportMsg.getToDeviceSessionMsg()); |
|
|
|
} |
|
|
|
@ -193,12 +183,12 @@ public class RemoteTransportService extends AbstractTransportService { |
|
|
|
public void destroy() { |
|
|
|
super.destroy(); |
|
|
|
stopped = true; |
|
|
|
if (transportApiTemplate != null) { |
|
|
|
transportApiTemplate.stop(); |
|
|
|
} |
|
|
|
if (mainConsumer != null) { |
|
|
|
mainConsumer.unsubscribe(); |
|
|
|
} |
|
|
|
// if (transportApiTemplate != null) {
|
|
|
|
// transportApiTemplate.stop();
|
|
|
|
// }
|
|
|
|
// if (mainConsumer != null) {
|
|
|
|
// mainConsumer.unsubscribe();
|
|
|
|
// }
|
|
|
|
if (mainConsumerExecutor != null) { |
|
|
|
mainConsumerExecutor.shutdownNow(); |
|
|
|
} |
|
|
|
@ -207,25 +197,25 @@ public class RemoteTransportService extends AbstractTransportService { |
|
|
|
@Override |
|
|
|
public void process(ValidateDeviceTokenRequestMsg msg, TransportServiceCallback<ValidateDeviceCredentialsResponseMsg> callback) { |
|
|
|
log.trace("Processing msg: {}", msg); |
|
|
|
AsyncCallbackTemplate.withCallback(transportApiTemplate.post(msg.getToken(), |
|
|
|
TransportApiRequestMsg.newBuilder().setValidateTokenRequestMsg(msg).build()), |
|
|
|
response -> callback.onSuccess(response.getValidateTokenResponseMsg()), callback::onError, transportCallbackExecutor); |
|
|
|
TbProtoQueueMsg<TransportApiRequestMsg> protoMsg = new TbProtoQueueMsg<>(UUID.randomUUID(), TransportApiRequestMsg.newBuilder().setValidateTokenRequestMsg(msg).build()); |
|
|
|
AsyncCallbackTemplate.withCallback(transportApiRequestTemplate.send(protoMsg), |
|
|
|
response -> callback.onSuccess(response.getValue().getValidateTokenResponseMsg()), callback::onError, transportCallbackExecutor); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public void process(ValidateDeviceX509CertRequestMsg msg, TransportServiceCallback<ValidateDeviceCredentialsResponseMsg> callback) { |
|
|
|
log.trace("Processing msg: {}", msg); |
|
|
|
AsyncCallbackTemplate.withCallback(transportApiTemplate.post(msg.getHash(), |
|
|
|
TransportApiRequestMsg.newBuilder().setValidateX509CertRequestMsg(msg).build()), |
|
|
|
response -> callback.onSuccess(response.getValidateTokenResponseMsg()), callback::onError, transportCallbackExecutor); |
|
|
|
TbProtoQueueMsg<TransportApiRequestMsg> protoMsg = new TbProtoQueueMsg<>(UUID.randomUUID(), TransportApiRequestMsg.newBuilder().setValidateX509CertRequestMsg(msg).build()); |
|
|
|
AsyncCallbackTemplate.withCallback(transportApiRequestTemplate.send(protoMsg), |
|
|
|
response -> callback.onSuccess(response.getValue().getValidateTokenResponseMsg()), callback::onError, transportCallbackExecutor); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public void process(GetOrCreateDeviceFromGatewayRequestMsg msg, TransportServiceCallback<GetOrCreateDeviceFromGatewayResponseMsg> callback) { |
|
|
|
log.trace("Processing msg: {}", msg); |
|
|
|
AsyncCallbackTemplate.withCallback(transportApiTemplate.post(msg.getDeviceName(), |
|
|
|
TransportApiRequestMsg.newBuilder().setGetOrCreateDeviceRequestMsg(msg).build()), |
|
|
|
response -> callback.onSuccess(response.getGetOrCreateDeviceResponseMsg()), callback::onError, transportCallbackExecutor); |
|
|
|
TbProtoQueueMsg<TransportApiRequestMsg> protoMsg = new TbProtoQueueMsg<>(UUID.randomUUID(), TransportApiRequestMsg.newBuilder().setGetOrCreateDeviceRequestMsg(msg).build()); |
|
|
|
AsyncCallbackTemplate.withCallback(transportApiRequestTemplate.send(protoMsg), |
|
|
|
response -> callback.onSuccess(response.getValue().getGetOrCreateDeviceResponseMsg()), callback::onError, transportCallbackExecutor); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
@ -322,18 +312,30 @@ public class RemoteTransportService extends AbstractTransportService { |
|
|
|
} |
|
|
|
|
|
|
|
private void send(SessionInfoProto sessionInfo, ToRuleEngineMsg toRuleEngineMsg, TransportServiceCallback<Void> callback) { |
|
|
|
ruleEngineProducer.send(getRoutingKey(sessionInfo), toRuleEngineMsg, (metadata, exception) -> { |
|
|
|
if (callback != null) { |
|
|
|
if (exception == null) { |
|
|
|
this.transportCallbackExecutor.submit(() -> { |
|
|
|
callback.onSuccess(null); |
|
|
|
}); |
|
|
|
} else { |
|
|
|
this.transportCallbackExecutor.submit(() -> { |
|
|
|
callback.onError(exception); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
ruleEngineMsgProducer.send(new TbProtoQueueMsg<>(getRoutingKey(sessionInfo), toRuleEngineMsg), callback != null ? |
|
|
|
new TransportTbQueueCallback(callback) : null); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
private class TransportTbQueueCallback implements TbQueueCallback { |
|
|
|
private final TransportServiceCallback<Void> callback; |
|
|
|
|
|
|
|
private TransportTbQueueCallback(TransportServiceCallback<Void> callback) { |
|
|
|
this.callback = callback; |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public void onSuccess(TbQueueMsgMetadata metadata) { |
|
|
|
RemoteTransportService.this.transportCallbackExecutor.submit(() -> { |
|
|
|
callback.onSuccess(null); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public void onFailure(Throwable t) { |
|
|
|
RemoteTransportService.this.transportCallbackExecutor.submit(() -> { |
|
|
|
callback.onError(t); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|