提交 ef0ce7e3 编写于 作者: 如梦技术's avatar 如梦技术 🐛

添加 mqtt 5 所有 ReasonCode。

上级 24a7958b
......@@ -22,24 +22,24 @@ package net.dreamlu.iot.mqtt.codec;
* @author netty
*/
public final class MqttConnAckVariableHeader {
private final MqttConnectReturnCode connectReturnCode;
private final MqttConnectReasonCode connectReturnCode;
private final boolean sessionPresent;
private final MqttProperties properties;
public MqttConnAckVariableHeader(MqttConnectReturnCode connectReturnCode, boolean sessionPresent) {
public MqttConnAckVariableHeader(MqttConnectReasonCode connectReturnCode, boolean sessionPresent) {
this(connectReturnCode, sessionPresent, MqttProperties.NO_PROPERTIES);
}
public MqttConnAckVariableHeader(MqttConnectReturnCode connectReturnCode, boolean sessionPresent,
MqttProperties properties) {
public MqttConnAckVariableHeader(MqttConnectReasonCode connectReturnCode, boolean sessionPresent,
MqttProperties properties) {
this.connectReturnCode = connectReturnCode;
this.sessionPresent = sessionPresent;
this.properties = MqttProperties.withEmptyDefaults(properties);
}
public MqttConnectReturnCode connectReturnCode() {
public MqttConnectReasonCode connectReturnCode() {
return connectReturnCode;
}
......
......@@ -21,7 +21,7 @@ package net.dreamlu.iot.mqtt.codec;
*
* @author netty
*/
public enum MqttConnectReturnCode {
public enum MqttConnectReasonCode implements MqttReasonCode {
/**
* ReturnCode
*/
......@@ -55,39 +55,25 @@ public enum MqttConnectReturnCode {
CONNECTION_REFUSED_SERVER_MOVED((byte) 0x9D),
CONNECTION_REFUSED_CONNECTION_RATE_EXCEEDED((byte) 0x9F);
private static final MqttConnectReturnCode[] VALUES;
private static final MqttConnectReasonCode[] VALUES = new MqttConnectReasonCode[160];
static {
MqttConnectReturnCode[] values = values();
VALUES = new MqttConnectReturnCode[160];
for (MqttConnectReturnCode code : values) {
final int unsignedByte = code.byteValue & 0xFF;
// Suppress a warning about out of bounds access since the enum contains only correct values
VALUES[unsignedByte] = code; // lgtm [java/index-out-of-bounds]
}
ReasonCodeUtils.fillValuesByCode(VALUES, values());
}
private final byte byteValue;
MqttConnectReturnCode(byte byteValue) {
MqttConnectReasonCode(byte byteValue) {
this.byteValue = byteValue;
}
public byte byteValue() {
return byteValue;
public static MqttConnectReasonCode valueOf(byte b) {
return ReasonCodeUtils.codeLoopUp(VALUES, b, "Connect");
}
public static MqttConnectReturnCode valueOf(byte b) {
final int unsignedByte = b & 0xFF;
MqttConnectReturnCode mqttConnectReturnCode = null;
try {
mqttConnectReturnCode = VALUES[unsignedByte];
} catch (ArrayIndexOutOfBoundsException ignored) {
// no op
}
if (mqttConnectReturnCode == null) {
throw new IllegalArgumentException("unknown connect return code: " + unsignedByte);
}
return mqttConnectReturnCode;
@Override
public byte value() {
return byteValue;
}
}
......@@ -261,7 +261,7 @@ public final class MqttDecoder {
}
final MqttConnAckVariableHeader mqttConnAckVariableHeader =
new MqttConnAckVariableHeader(MqttConnectReturnCode.valueOf(returnCode), sessionPresent, properties);
new MqttConnAckVariableHeader(MqttConnectReasonCode.valueOf(returnCode), sessionPresent, properties);
return new Result<>(mqttConnAckVariableHeader, numberOfBytesConsumed);
}
......
/*
* Copyright 2021 The vertx Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://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, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package net.dreamlu.iot.mqtt.codec;
/**
* Reason codes for DISCONNECT MQTT message
*
* @author vertx-mqtt
*/
public enum MqttDisconnectReasonCode implements MqttReasonCode {
/**
* Disconnect ReasonCode
*/
NORMAL((byte) 0x0),
WITH_WILL_MESSAGE((byte) 0x04),
UNSPECIFIED_ERROR((byte) 0x80),
MALFORMED_PACKET((byte) 0x81),
PROTOCOL_ERROR((byte) 0x82),
IMPLEMENTATION_SPECIFIC_ERROR((byte) 0x83),
NOT_AUTHORIZED((byte) 0x87),
SERVER_BUSY((byte) 0x89),
SERVER_SHUTTING_DOWN((byte) 0x8B),
KEEP_ALIVE_TIMEOUT((byte) 0x8D),
SESSION_TAKEN_OVER((byte) 0x8E),
TOPIC_FILTER_INVALID((byte) 0x8F),
TOPIC_NAME_INVALID((byte) 0x90),
RECEIVE_MAXIMUM_EXCEEDED((byte) 0x93),
TOPIC_ALIAS_INVALID((byte) 0x94),
PACKET_TOO_LARGE((byte) 0x95),
MESSAGE_RATE_TOO_HIGH((byte) 0x96),
QUOTA_EXCEEDED((byte) 0x97),
ADMINISTRATIVE_ACTION((byte) 0x98),
PAYLOAD_FORMAT_INVALID((byte) 0x99),
RETAIN_NOT_SUPPORTED((byte) 0x9A),
QOS_NOT_SUPPORTED((byte) 0x9B),
USE_ANOTHER_SERVER((byte) 0x9C),
SERVER_MOVED((byte) 0x9D),
SHARED_SUBSCRIPTIONS_NOT_SUPPORTED((byte) 0x9E),
CONNECTION_RATE_EXCEEDED((byte) 0x9F),
MAXIMUM_CONNECT_TIME((byte) 0xA0),
SUBSCRIPTION_IDENTIFIERS_NOT_SUPPORTED((byte) 0xA1),
WILDCARD_SUBSCRIPTIONS_NOT_SUPPORTED((byte) 0xA2);
MqttDisconnectReasonCode(byte byteValue) {
this.byteValue = byteValue;
}
private final byte byteValue;
@Override
public byte value() {
return byteValue;
}
private static final MqttDisconnectReasonCode[] VALUES = new MqttDisconnectReasonCode[0xA3];
static {
ReasonCodeUtils.fillValuesByCode(VALUES, values());
}
public static MqttDisconnectReasonCode valueOf(byte b) {
return ReasonCodeUtils.codeLoopUp(VALUES, b, "DISCONNECT");
}
}
......@@ -208,7 +208,7 @@ public final class MqttEncoder {
buf.put((byte) getFixedHeaderByte1(message.fixedHeader()));
writeVariableLengthInt(buf, 2 + propertiesBytes.length);
buf.put((byte) (message.variableHeader().isSessionPresent() ? 0x01 : 0x00));
buf.put(message.variableHeader().connectReturnCode().byteValue());
buf.put(message.variableHeader().connectReturnCode().value());
buf.put(propertiesBytes);
return buf;
}
......
......@@ -288,7 +288,7 @@ public final class MqttMessageBuilders {
public static final class ConnAckBuilder {
private MqttConnectReturnCode returnCode;
private MqttConnectReasonCode returnCode;
private boolean sessionPresent;
private MqttProperties properties = MqttProperties.NO_PROPERTIES;
private ConnAckPropertiesBuilder propsBuilder;
......@@ -296,7 +296,7 @@ public final class MqttMessageBuilders {
private ConnAckBuilder() {
}
public ConnAckBuilder returnCode(MqttConnectReturnCode returnCode) {
public ConnAckBuilder returnCode(MqttConnectReasonCode returnCode) {
this.returnCode = returnCode;
return this;
}
......
/*
* Copyright 2021 The vertx Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://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, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package net.dreamlu.iot.mqtt.codec;
/**
* Reason codes for PUBACK MQTT message
*
* @author vertx-mqtt
*/
public enum MqttPubAckReasonCode implements MqttReasonCode {
/**
* PubAck ReasonCode
*/
SUCCESS((byte) 0x0),
NO_MATCHING_SUBSCRIBERS((byte) 0x10),
UNSPECIFIED_ERROR((byte) 0x80),
IMPLEMENTATION_SPECIFIC_ERROR((byte) 0x83),
NOT_AUTHORIZED((byte) 0x87),
TOPIC_NAME_INVALID((byte) 0x90),
PACKET_IDENTIFIER_IN_USE((byte) 0x91),
QUOTA_EXCEEDED((byte) 0x97),
PAYLOAD_FORMAT_INVALID((byte) 0x99);
MqttPubAckReasonCode(byte byteValue) {
this.byteValue = byteValue;
}
private final byte byteValue;
private static final MqttPubAckReasonCode[] VALUES = new MqttPubAckReasonCode[0x9A];
static {
ReasonCodeUtils.fillValuesByCode(VALUES, values());
}
public static MqttPubAckReasonCode valueOf(byte b) {
return ReasonCodeUtils.codeLoopUp(VALUES, b, "PUBACK");
}
@Override
public byte value() {
return byteValue;
}
}
/*
* Copyright 2021 The vertx Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://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, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package net.dreamlu.iot.mqtt.codec;
/**
* Reason codes for PUBCOMP MQTT message
*
* @author vertx-mqtt
*/
public enum MqttPubCompReasonCode implements MqttReasonCode {
/**
* PubComp ReasonCode
*/
SUCCESS((byte) 0x0),
PACKET_IDENTIFIER_NOT_FOUND((byte) 0x92);
MqttPubCompReasonCode(byte byteValue) {
this.byteValue = byteValue;
}
private final byte byteValue;
@Override
public byte value() {
return byteValue;
}
public static MqttPubCompReasonCode valueOf(byte b) {
if (b == SUCCESS.byteValue) {
return SUCCESS;
} else if (b == PACKET_IDENTIFIER_NOT_FOUND.byteValue) {
return PACKET_IDENTIFIER_NOT_FOUND;
} else {
throw new IllegalArgumentException("unknown PUBCOMP reason code: " + b);
}
}
}
/*
* Copyright 2021 The vertx Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://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, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package net.dreamlu.iot.mqtt.codec;
/**
* Reason codes for PUBREC MQTT message
*
* @author vertx-mqtt
*/
public enum MqttPubRecReasonCode implements MqttReasonCode {
/**
* PubRec ReasonCode
*/
SUCCESS((byte) 0x0),
NO_MATCHING_SUBSCRIBERS((byte) 0x10),
UNSPECIFIED_ERROR((byte) 0x80),
IMPLEMENTATION_SPECIFIC_ERROR((byte) 0x83),
NOT_AUTHORIZED((byte) 0x87),
TOPIC_NAME_INVALID((byte) 0x90),
PACKET_IDENTIFIER_IN_USE((byte) 0x91),
QUOTA_EXCEEDED((byte) 0x97),
PAYLOAD_FORMAT_INVALID((byte) 0x99);
MqttPubRecReasonCode(byte byteValue) {
this.byteValue = byteValue;
}
private final byte byteValue;
@Override
public byte value() {
return byteValue;
}
@Override
public boolean isError() {
return Byte.toUnsignedInt(byteValue) >= Byte.toUnsignedInt(UNSPECIFIED_ERROR.byteValue);
}
private static final MqttPubRecReasonCode[] VALUES = new MqttPubRecReasonCode[0x9A];
static {
ReasonCodeUtils.fillValuesByCode(VALUES, values());
}
public static MqttPubRecReasonCode valueOf(byte b) {
return ReasonCodeUtils.codeLoopUp(VALUES, b, "PUBREC");
}
}
/*
* Copyright 2021 The vertx Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://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, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package net.dreamlu.iot.mqtt.codec;
/**
* Reason codes for PUBREL MQTT message
*
* @author vertx-mqtt
*/
public enum MqttPubRelReasonCode implements MqttReasonCode {
/**
* PubRel ReasonCode
*/
SUCCESS((byte) 0x0),
PACKET_IDENTIFIER_NOT_FOUND((byte) 0x92);
MqttPubRelReasonCode(byte byteValue) {
this.byteValue = byteValue;
}
private final byte byteValue;
@Override
public byte value() {
return byteValue;
}
public static MqttPubRelReasonCode valueOf(byte b) {
if (b == SUCCESS.byteValue) {
return SUCCESS;
} else if (b == PACKET_IDENTIFIER_NOT_FOUND.byteValue) {
return PACKET_IDENTIFIER_NOT_FOUND;
} else {
throw new IllegalArgumentException("unknown PUBREL reason code: " + b);
}
}
}
/*
* Copyright 2021 The vertx Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://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, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package net.dreamlu.iot.mqtt.codec;
/**
* Common interface for MQTT messages reason codes enums
*
* @author vertx-mqtt
*/
public interface MqttReasonCode {
/**
* byteValue
*
* @return byteValue
*/
byte value();
/**
* isError
*
* @return boolean
*/
default boolean isError() {
return (value() & 0x80) != 0;
}
}
/*
* Copyright 2021 The vertx Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://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, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package net.dreamlu.iot.mqtt.codec;
/**
* Reason codes for SUBACK MQTT message
*
* @author vertx-mqtt
*/
public enum MqttSubAckReasonCode implements MqttReasonCode {
//All MQTT versions
GRANTED_QOS0((byte) 0x0),
GRANTED_QOS1((byte) 0x1),
GRANTED_QOS2((byte) 0x2),
UNSPECIFIED_ERROR((byte) 0x80),
//MQTT5 or higher
IMPLEMENTATION_SPECIFIC_ERROR((byte) 0x83),
NOT_AUTHORIZED((byte) 0x87),
TOPIC_FILTER_INVALID((byte) 0x8F),
PACKET_IDENTIFIER_IN_USE((byte) 0x91),
QUOTA_EXCEEDED((byte) 0x97),
SHARED_SUBSCRIPTIONS_NOT_SUPPORTED((byte) 0x9E),
SUBSCRIPTION_IDENTIFIERS_NOT_SUPPORTED((byte) 0xA1),
WILDCARD_SUBSCRIPTIONS_NOT_SUPPORTED((byte) 0xA2);
MqttSubAckReasonCode(byte byteValue) {
this.byteValue = byteValue;
}
private final byte byteValue;
@Override
public byte value() {
return byteValue;
}
public static MqttSubAckReasonCode qosGranted(MqttQoS qos) {
switch (qos) {
case AT_MOST_ONCE:
return MqttSubAckReasonCode.GRANTED_QOS0;
case AT_LEAST_ONCE:
return MqttSubAckReasonCode.GRANTED_QOS1;
case EXACTLY_ONCE:
return MqttSubAckReasonCode.GRANTED_QOS2;
case FAILURE:
return MqttSubAckReasonCode.UNSPECIFIED_ERROR;
default:
return MqttSubAckReasonCode.UNSPECIFIED_ERROR;
}
}
public MqttSubAckReasonCode limitForMqttVersion(MqttVersion version) {
if (version != MqttVersion.MQTT_5 && byteValue > UNSPECIFIED_ERROR.byteValue) {
return UNSPECIFIED_ERROR;
} else {
return this;
}
}
}
/*
* Copyright 2021 The vertx Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://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, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package net.dreamlu.iot.mqtt.codec;
/**
* Reason codes for UNSUBACK MQTT message
*
* @author vertx-mqtt
*/
public enum MqttUnsubAckReasonCode implements MqttReasonCode {
/**
* UnsubAck ReasonCode
*/
SUCCESS((byte) 0x0),
NO_SUBSCRIPTION_EXISTED((byte) 0x11),
UNSPECIFIED_ERROR((byte) 0x80),
IMPLEMENTATION_SPECIFIC_ERROR((byte) 0x83),
NOT_AUTHORIZED((byte) 0x87),
TOPIC_FILTER_INVALID((byte) 0x8F),
PACKET_IDENTIFIER_IN_USE((byte) 0x91);
MqttUnsubAckReasonCode(byte byteValue) {
this.byteValue = byteValue;
}
private final byte byteValue;
@Override
public byte value() {
return byteValue;
}
}
/*
* Copyright 2021 The vertx Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://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, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package net.dreamlu.iot.mqtt.codec;
/**
* Utilities for MQTT message codes enums
*
* @author vertx-mqtt
*/
public class ReasonCodeUtils {
protected static <C extends MqttReasonCode> void fillValuesByCode(C[] valuesByCode, C[] values) {
for (C code : values) {
final int unsignedByte = code.value() & 0xFF;
valuesByCode[unsignedByte] = code;
}
}
protected static <C> C codeLoopUp(C[] valuesByCode, byte b, String codeType) {
final int unsignedByte = b & 0xFF;
C reasonCode = null;
try {
reasonCode = valuesByCode[unsignedByte];
} catch (ArrayIndexOutOfBoundsException ignored) {
// no op
}
if (reasonCode == null) {
throw new IllegalArgumentException("unknown " + codeType + " reason code: " + unsignedByte);
}
return reasonCode;
}
}
......@@ -57,7 +57,7 @@ public class DefaultMqttClientProcessor implements IMqttClientProcessor {
@Override
public void processConAck(ChannelContext context, MqttConnAckMessage message) {
MqttConnAckVariableHeader connAckVariableHeader = message.variableHeader();
MqttConnectReturnCode returnCode = connAckVariableHeader.connectReturnCode();
MqttConnectReasonCode returnCode = connAckVariableHeader.connectReturnCode();
switch (returnCode) {
case CONNECTION_ACCEPTED:
// 1. 连接成功的日志
......
......@@ -150,7 +150,7 @@ public class MqttServerAioHandler implements ServerAioHandler {
if (cause instanceof MqttUnacceptableProtocolVersionException) {
// 不支持的协议版本
MqttConnAckMessage message = MqttMessageBuilders.connAck()
.returnCode(MqttConnectReturnCode.CONNECTION_REFUSED_UNACCEPTABLE_PROTOCOL_VERSION)
.returnCode(MqttConnectReasonCode.CONNECTION_REFUSED_UNACCEPTABLE_PROTOCOL_VERSION)
.sessionPresent(false)
.build();
Tio.send(context, message);
......@@ -158,7 +158,7 @@ public class MqttServerAioHandler implements ServerAioHandler {
} else if (cause instanceof MqttIdentifierRejectedException) {
// 不合格的 clientId
MqttConnAckMessage message = MqttMessageBuilders.connAck()
.returnCode(MqttConnectReturnCode.CONNECTION_REFUSED_IDENTIFIER_REJECTED)
.returnCode(MqttConnectReasonCode.CONNECTION_REFUSED_IDENTIFIER_REJECTED)
.sessionPresent(false)
.build();
Tio.send(context, message);
......
......@@ -77,14 +77,14 @@ public class DefaultMqttServerProcessor implements MqttServerProcessor {
String clientId = payload.clientIdentifier();
// 1. 客户端必须提供 clientId, 不管 cleanSession 是否为1, 此处没有参考标准协议实现
if (StrUtil.isBlank(clientId)) {
connAckByReturnCode(clientId, context, MqttConnectReturnCode.CONNECTION_REFUSED_IDENTIFIER_REJECTED);
connAckByReturnCode(clientId, context, MqttConnectReasonCode.CONNECTION_REFUSED_IDENTIFIER_REJECTED);
return;
}
// 2. 认证
String userName = payload.userName();
String password = payload.password();
if (!authHandler.authenticate(clientId, userName, password)) {
connAckByReturnCode(clientId, context, MqttConnectReturnCode.CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD);
connAckByReturnCode(clientId, context, MqttConnectReasonCode.CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD);
return;
}
// 3. 判断 clientId 是否在多个地方使用,如果在其他地方有使用,先解绑
......@@ -122,12 +122,12 @@ public class DefaultMqttServerProcessor implements MqttServerProcessor {
messageStore.addWillMessage(clientId, willMessage);
}
// 8. 返回 ack
connAckByReturnCode(clientId, context, MqttConnectReturnCode.CONNECTION_ACCEPTED);
connAckByReturnCode(clientId, context, MqttConnectReasonCode.CONNECTION_ACCEPTED);
// 9. 在线状态
connectStatusListener.online(clientId);
}
private void connAckByReturnCode(String clientId, ChannelContext context, MqttConnectReturnCode returnCode) {
private void connAckByReturnCode(String clientId, ChannelContext context, MqttConnectReasonCode returnCode) {
MqttConnAckMessage message = MqttMessageBuilders.connAck()
.returnCode(returnCode)
.sessionPresent(false)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册