All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.feingto.iot.server.handler.mqtt.ConnectHandler Maven / Gradle / Ivy

There is a newer version: 1.2.5.RELEASE
Show newest version
package com.feingto.iot.server.handler.mqtt;

import com.feingto.iot.common.Constants;
import com.feingto.iot.common.model.mqtt.SessionStore;
import com.feingto.iot.common.service.IAuth;
import com.feingto.iot.common.service.mqtt.MessageRequest;
import com.feingto.iot.common.service.mqtt.MessageResponse;
import com.feingto.iot.server.cache.MessageCache;
import com.feingto.iot.server.cache.SessionCache;
import com.feingto.iot.server.handler.BaseMessageHandler;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.handler.codec.mqtt.*;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.util.Optional;

/**
 * 请求连接处理器
 *
 * @author longfei
 */
@Slf4j
public class ConnectHandler extends BaseMessageHandler {
    private final IAuth authService;

    public ConnectHandler(IAuth authService) {
        super(MqttMessageType.CONNECT);
        this.authService = authService;
    }

    @Override
    public void handle(Channel channel, Object object) {
        MqttConnectMessage msg = (MqttConnectMessage) object;
        MqttConnectPayload payload = msg.payload();
        String clientId = payload.clientIdentifier();
        if (StringUtils.isEmpty(clientId)) {
            MessageResponse.connack(channel, MqttConnectReturnCode.CONNECTION_REFUSED_IDENTIFIER_REJECTED);
            channel.close();
            return;
        }

        // 认证
        MqttConnectVariableHeader variableHeader = msg.variableHeader();
        if (variableHeader.hasUserName() && variableHeader.hasPassword()
                && !authService.authorized(payload.userName(), payload.passwordInBytes())) {
            MessageResponse.connack(channel, MqttConnectReturnCode.CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD);
            channel.close();
            return;
        }

        // 关闭同一clientId之前的连接, cleanSession为true时清除会话
        Optional.ofNullable(SessionCache.getInstance().get(clientId))
                .ifPresent(sess -> {
                    if (sess.cleanSession()) {
                        log.debug(">>> clean the previous session of the {}", clientId);
                        this.cleanSession(clientId);
                    }
                    sess.channel().close();
                });

        // 保存遗嘱消息, 网络连接关闭时发布这个遗嘱消息, 除非服务端收到DISCONNECT
        SessionStore session = new SessionStore().cleanSession(variableHeader.isCleanSession());
        if (variableHeader.isWillFlag()) {
            log.debug(">>> save will message of the {}", clientId);
            session.willMessage(new MqttPublishMessage(
                    new MqttFixedHeader(MqttMessageType.PUBLISH, false,
                            MqttQoS.valueOf(variableHeader.willQos()), variableHeader.isWillRetain(), 0),
                    new MqttPublishVariableHeader(payload.willTopic(), 0),
                    Unpooled.buffer().writeBytes(payload.willMessageInBytes())));
        }

        // 服务端在一点五倍的保持连接时间内没有收到客户端的控制报文则断开客户端的网络连接
        if (variableHeader.keepAliveTimeSeconds() > 0) {
            channel.pipeline().addFirst(new IdleStateHandler(0, 0,
                    Math.round(variableHeader.keepAliveTimeSeconds() * 1.5f)));
        }

        // 添加通道属性 clientId
        channel.attr(Constants.KEY_CLIENT_ID).set(clientId);
        // 存储会话信息
        SessionCache.getInstance().put(clientId, session.channel(channel));

        // 返回connack消息
        MessageResponse.connack(channel, MqttConnectReturnCode.CONNECTION_ACCEPTED);

        // cleanSession为false时返回未完成的QoS1和QoS2消息
        if (!variableHeader.isCleanSession()) {
            MessageCache.getInstance(igniteMessage).findBylientId(clientId).stream()
                    .filter(cacheMessage -> MqttMessageType.PUBLISH.equals(cacheMessage.type()) ||
                            MqttMessageType.PUBREL.equals(cacheMessage.type()))
                    .forEach(cacheMessage -> MessageRequest.publish(channel, cacheMessage));
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy