|
|
@@ -2,8 +2,8 @@ package org.jetlinks.community.network.mqtt.server.vertx;
|
|
|
|
|
|
import io.netty.buffer.ByteBuf;
|
|
|
import io.netty.buffer.Unpooled;
|
|
|
-import io.netty.handler.codec.mqtt.MqttConnectReturnCode;
|
|
|
-import io.netty.handler.codec.mqtt.MqttQoS;
|
|
|
+import io.netty.channel.nio.NioEventLoopGroup;
|
|
|
+import io.netty.handler.codec.mqtt.*;
|
|
|
import io.vertx.core.buffer.Buffer;
|
|
|
import io.vertx.core.net.SocketAddress;
|
|
|
import io.vertx.mqtt.MqttEndpoint;
|
|
|
@@ -30,6 +30,8 @@ import javax.annotation.Nonnull;
|
|
|
import java.net.InetSocketAddress;
|
|
|
import java.time.Duration;
|
|
|
import java.util.Optional;
|
|
|
+import java.util.concurrent.ScheduledFuture;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
import java.util.function.Consumer;
|
|
|
import java.util.function.Function;
|
|
|
import java.util.stream.Collectors;
|
|
|
@@ -45,11 +47,19 @@ class VertxMqttConnection implements MqttConnection {
|
|
|
|
|
|
private final EmitterProcessor<MqttPublishing> messageProcessor = EmitterProcessor.create(false);
|
|
|
|
|
|
+
|
|
|
+ private ScheduledFuture<?> pingRespTimeout;
|
|
|
+
|
|
|
private final FluxSink<MqttPublishing> publishingFluxSink = messageProcessor.sink(FluxSink.OverflowStrategy.BUFFER);
|
|
|
|
|
|
- private final EmitterProcessor<MqttSubscription> subscription = EmitterProcessor.create(false);
|
|
|
+ private final EmitterProcessor<MqttSubscription> subscriptionProcessor = EmitterProcessor.create(false);
|
|
|
private final EmitterProcessor<MqttUnSubscription> unsubscription = EmitterProcessor.create(false);
|
|
|
|
|
|
+ private final VertxMqttPublishing publishing = new VertxMqttPublishing(false);
|
|
|
+ private final VertxMqttSubscription subscription = new VertxMqttSubscription( false);
|
|
|
+ private final VertxMqttMqttUnSubscription unSubscription = new VertxMqttMqttUnSubscription(false);
|
|
|
+ private Optional<MqttMessage> willMessage=null;
|
|
|
+
|
|
|
private static final MqttAuth emptyAuth = new MqttAuth() {
|
|
|
@Override
|
|
|
public String getUsername() {
|
|
|
@@ -69,10 +79,9 @@ class VertxMqttConnection implements MqttConnection {
|
|
|
|
|
|
private final Consumer<MqttConnection> defaultListener = mqttConnection -> {
|
|
|
log.debug("mqtt client [{}] disconnected", getClientId());
|
|
|
- subscription.onComplete();
|
|
|
+ subscriptionProcessor.onComplete();
|
|
|
unsubscription.onComplete();
|
|
|
messageProcessor.onComplete();
|
|
|
-
|
|
|
};
|
|
|
|
|
|
private Consumer<MqttConnection> disconnectConsumer = defaultListener;
|
|
|
@@ -113,10 +122,18 @@ class VertxMqttConnection implements MqttConnection {
|
|
|
if (accepted) {
|
|
|
return this;
|
|
|
}
|
|
|
+ //todo 需要验证密码
|
|
|
+ String protocolName = endpoint.protocolName();
|
|
|
+ int protocolVersion = endpoint.protocolVersion();
|
|
|
log.debug("mqtt client [{}] connected", getClientId());
|
|
|
accepted = true;
|
|
|
+ ping();
|
|
|
try {
|
|
|
if (!endpoint.isConnected()) {
|
|
|
+ //心跳检测 todo 改为配置文件配置
|
|
|
+ heartIdleHandler(endpoint,5,TimeUnit.SECONDS);
|
|
|
+ //放置遗言
|
|
|
+ this.willMessage = this.getWillMessage();
|
|
|
endpoint.accept();
|
|
|
}
|
|
|
} catch (Exception e) {
|
|
|
@@ -128,6 +145,14 @@ class VertxMqttConnection implements MqttConnection {
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
+ @Override
|
|
|
+ public void heartIdleHandler(MqttEndpoint endpoint, long delay, TimeUnit unit) {
|
|
|
+ this.pingRespTimeout= new NioEventLoopGroup(1).schedule(()->{
|
|
|
+ log.error("通道关闭了:{}",endpoint.remoteAddress());
|
|
|
+ endpoint.close();
|
|
|
+ },delay,unit);
|
|
|
+ }
|
|
|
+
|
|
|
@Override
|
|
|
public void keepAlive() {
|
|
|
ping();
|
|
|
@@ -135,24 +160,33 @@ class VertxMqttConnection implements MqttConnection {
|
|
|
|
|
|
void ping() {
|
|
|
lastPingTime = System.currentTimeMillis();
|
|
|
+ if (this.pingRespTimeout != null && !this.pingRespTimeout.isCancelled() && !this.pingRespTimeout.isDone()) {
|
|
|
+ this.pingRespTimeout.cancel(true);
|
|
|
+ this.pingRespTimeout = null;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
void init() {
|
|
|
this.endpoint
|
|
|
+ .exceptionHandler(event -> {
|
|
|
+
|
|
|
+ })
|
|
|
.disconnectHandler(ignore -> this.complete())
|
|
|
.closeHandler(ignore -> this.complete())
|
|
|
.pingHandler(ignore -> {
|
|
|
this.ping();
|
|
|
- if (!endpoint.isAutoKeepAlive()) {
|
|
|
+ if (endpoint.isAutoKeepAlive()) {
|
|
|
endpoint.pong();
|
|
|
}
|
|
|
})
|
|
|
.publishHandler(msg -> {
|
|
|
ping();
|
|
|
- VertxMqttPublishing publishing = new VertxMqttPublishing(msg, false);
|
|
|
+ publishing.setMessage(msg);
|
|
|
+ publishing.handlerMessage(messageProcessor);
|
|
|
boolean hasDownstream = this.messageProcessor.hasDownstreams();
|
|
|
if (autoAckMsg || !hasDownstream) {
|
|
|
publishing.acknowledge();
|
|
|
+ this.publishingFluxSink.next(publishing);
|
|
|
}
|
|
|
if (hasDownstream) {
|
|
|
this.publishingFluxSink.next(publishing);
|
|
|
@@ -182,18 +216,20 @@ class VertxMqttConnection implements MqttConnection {
|
|
|
})
|
|
|
.subscribeHandler(msg -> {
|
|
|
ping();
|
|
|
- VertxMqttSubscription subscription = new VertxMqttSubscription(msg, false);
|
|
|
- boolean hasDownstream = this.subscription.hasDownstreams();
|
|
|
+ subscription.setMessage(msg);
|
|
|
+ subscription.handlerSubscription(this.subscriptionProcessor);
|
|
|
+ boolean hasDownstream = this.subscriptionProcessor.hasDownstreams();
|
|
|
if (autoAckSub || !hasDownstream) {
|
|
|
subscription.acknowledge();
|
|
|
}
|
|
|
if (hasDownstream) {
|
|
|
- this.subscription.onNext(subscription);
|
|
|
+ this.subscriptionProcessor.onNext(subscription);
|
|
|
}
|
|
|
})
|
|
|
.unsubscribeHandler(msg -> {
|
|
|
ping();
|
|
|
- VertxMqttMqttUnSubscription unSubscription = new VertxMqttMqttUnSubscription(msg, false);
|
|
|
+ unSubscription.setMessage(msg);
|
|
|
+ unSubscription.handlerUnSubscription(this.unsubscription);
|
|
|
boolean hasDownstream = this.unsubscription.hasDownstreams();
|
|
|
if (autoAckUnSub || !hasDownstream) {
|
|
|
unSubscription.acknowledge();
|
|
|
@@ -260,9 +296,8 @@ class VertxMqttConnection implements MqttConnection {
|
|
|
|
|
|
@Override
|
|
|
public Flux<MqttSubscription> handleSubscribe(boolean autoAck) {
|
|
|
-
|
|
|
autoAckSub = autoAck;
|
|
|
- return subscription.map(Function.identity());
|
|
|
+ return subscriptionProcessor.map(Function.identity());
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@@ -350,10 +385,22 @@ class VertxMqttConnection implements MqttConnection {
|
|
|
@AllArgsConstructor
|
|
|
class VertxMqttPublishing implements MqttPublishing {
|
|
|
|
|
|
- private final MqttPublishMessage message;
|
|
|
+ private MqttPublishMessage message;
|
|
|
|
|
|
private volatile boolean acknowledged;
|
|
|
|
|
|
+ public VertxMqttPublishing(boolean acknowledged) {
|
|
|
+ this.acknowledged = acknowledged;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setMessage(MqttPublishMessage message) {
|
|
|
+ this.message = message;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setAcknowledged(boolean acknowledged) {
|
|
|
+ this.acknowledged = acknowledged;
|
|
|
+ }
|
|
|
+
|
|
|
@Override
|
|
|
public MqttMessage getMessage() {
|
|
|
return new VertxMqttMessage(message);
|
|
|
@@ -373,15 +420,31 @@ class VertxMqttConnection implements MqttConnection {
|
|
|
endpoint.publishReceived(message.messageId());
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void handlerMessage(Flux publishFlux) {
|
|
|
+ publishFlux.subscribe(publish->{
|
|
|
+ //todo 发布消息
|
|
|
+ });
|
|
|
+
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
@AllArgsConstructor
|
|
|
class VertxMqttSubscription implements MqttSubscription {
|
|
|
|
|
|
- private final MqttSubscribeMessage message;
|
|
|
+ private MqttSubscribeMessage message;
|
|
|
+
|
|
|
|
|
|
private volatile boolean acknowledged;
|
|
|
|
|
|
+ public VertxMqttSubscription(boolean acknowledged) {
|
|
|
+ this.acknowledged = acknowledged;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setMessage(MqttSubscribeMessage message) {
|
|
|
+ this.message = message;
|
|
|
+ }
|
|
|
@Override
|
|
|
public MqttSubscribeMessage getMessage() {
|
|
|
return message;
|
|
|
@@ -396,15 +459,29 @@ class VertxMqttConnection implements MqttConnection {
|
|
|
endpoint.subscribeAcknowledge(message.messageId(), message.topicSubscriptions().stream()
|
|
|
.map(MqttTopicSubscription::qualityOfService).collect(Collectors.toList()));
|
|
|
}
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void handlerSubscription(Flux subscriptionFlux) {
|
|
|
+ subscriptionFlux.subscribe(result->{
|
|
|
+ //todo 订阅主题
|
|
|
+ });
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
@AllArgsConstructor
|
|
|
class VertxMqttMqttUnSubscription implements MqttUnSubscription {
|
|
|
|
|
|
- private final MqttUnsubscribeMessage message;
|
|
|
+ private MqttUnsubscribeMessage message;
|
|
|
|
|
|
private volatile boolean acknowledged;
|
|
|
|
|
|
+ public VertxMqttMqttUnSubscription(boolean acknowledged) {
|
|
|
+ this.acknowledged = acknowledged;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setMessage(MqttUnsubscribeMessage message) {
|
|
|
+ this.message = message;
|
|
|
+ }
|
|
|
@Override
|
|
|
public MqttUnsubscribeMessage getMessage() {
|
|
|
return message;
|
|
|
@@ -419,6 +496,13 @@ class VertxMqttConnection implements MqttConnection {
|
|
|
acknowledged = true;
|
|
|
endpoint.unsubscribeAcknowledge(message.messageId());
|
|
|
}
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void handlerUnSubscription(Flux unSubscriptionFlux) {
|
|
|
+ unSubscriptionFlux.subscribe(result->{
|
|
|
+ //取消订阅主题
|
|
|
+ });
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
|