package com.lld.im.tcp.handler;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.lld.im.codec.pack.LoginPack;
import com.lld.im.codec.pack.message.ChatMessageAck;
import com.lld.im.codec.pack.user.LoginAckPack;
import com.lld.im.codec.pack.user.UserStatusChangeNotifyPack;
import com.lld.im.codec.proto.Message;
import com.lld.im.codec.proto.MessagePack;
import com.lld.im.common.ResponseVO;
import com.lld.im.common.constant.Constants;
import com.lld.im.common.enums.ImConnectStatusEnum;
import com.lld.im.common.enums.command.GroupEventCommand;
import com.lld.im.common.enums.command.MessageCommand;
import com.lld.im.common.enums.command.SystemCommand;
import com.lld.im.common.enums.command.UserEventCommand;
import com.lld.im.common.model.UserClientDto;
import com.lld.im.common.model.UserSession;
import com.lld.im.common.model.message.CheckSendMessageReq;
import com.lld.im.tcp.feign.FeignMessageService;
import com.lld.im.tcp.publish.MqMessageProducer;
import com.lld.im.tcp.redis.RedisManager;
import com.lld.im.tcp.utils.SessionSocketHolder;
import feign.Feign;
import feign.Request;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.AttributeKey;
import org.redisson.api.RMap;
import org.redisson.api.RTopic;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import java.net.InetAddress;
public class NettyServerHandler extends SimpleChannelInboundHandler<Message> {
private final static Logger logger = LoggerFactory.getLogger(NettyServerHandler.class);
private final Integer brokerId;
private final FeignMessageService feignMessageService;
public NettyServerHandler(Integer brokerId, String logicUrl) {
logger.info("brokerId-{},logicUrl-{}",brokerId, logicUrl);
this.brokerId = brokerId;
feignMessageService = Feign.builder()
.encoder(new JacksonEncoder())
.decoder(new JacksonDecoder())
.options(new Request.Options(1000, 3500))
.target(FeignMessageService.class, logicUrl);
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, Message msg) {
logger.info("NettyServerHandler-channelRead0-msg = {}",msg);
Integer command = msg.getMessageHeader().getCommand();
logger.info("command-{}",command);
logger.info("command == MessageCommand.MSG_P2P.getCommand()-->{}",command == MessageCommand.MSG_P2P.getCommand());
if (command == SystemCommand.LOGIN.getCommand()) {
LoginPack loginPack = JSON.parseObject(JSONObject.toJSONString(msg.getMessagePack()), new TypeReference<LoginPack>() {}.getType());
String userId = loginPack.getUserId();
ctx.channel().attr(AttributeKey.valueOf(Constants.USER_ID)).set(userId);
String clientImei = msg.getMessageHeader().getClientType() + ":" + msg.getMessageHeader().getImei();
ctx.channel().attr(AttributeKey.valueOf(Constants.CLIENT_IMEI)).set(clientImei);
ctx.channel().attr(AttributeKey.valueOf(Constants.APP_ID)).set(msg.getMessageHeader().getAppId());
ctx.channel().attr(AttributeKey.valueOf(Constants.CLIENT_TYPE)).set(msg.getMessageHeader().getClientType());
ctx.channel().attr(AttributeKey.valueOf(Constants.IMEI)).set(msg.getMessageHeader().getImei());
logger.info("userId-{},clientImei-{},appId-{},clientType-{},imei-{}",
userId,
clientImei,
msg.getMessageHeader().getAppId(),
msg.getMessageHeader().getClientType(),
msg.getMessageHeader().getImei());
UserSession userSession = new UserSession();
userSession.setAppId(msg.getMessageHeader().getAppId());
userSession.setClientType(msg.getMessageHeader().getClientType());
userSession.setUserId(loginPack.getUserId());
userSession.setConnectState(ImConnectStatusEnum.ONLINE_STATUS.getCode());
userSession.setBrokerId(brokerId);
logger.info("brokerId-{}",brokerId);
userSession.setImei(msg.getMessageHeader().getImei());
try {
InetAddress localHost = InetAddress.getLocalHost();
userSession.setBrokerHost(localHost.getHostAddress());
} catch (Exception e) {
e.printStackTrace();
}
RedissonClient redissonClient = RedisManager.getRedissonClient();
RMap<String, String> map = redissonClient.getMap(msg.getMessageHeader().getAppId() + Constants.RedisConstants.USER_SESSION_CONSTANTS + loginPack.getUserId());
map.put(msg.getMessageHeader().getClientType() + ":" + msg.getMessageHeader().getImei(), JSONObject.toJSONString(userSession));
SessionSocketHolder
.put(msg.getMessageHeader().getAppId(), loginPack.getUserId(),
msg.getMessageHeader().getClientType(), msg.getMessageHeader().getImei(), (NioSocketChannel) ctx.channel());
UserClientDto dto = new UserClientDto();
dto.setImei(msg.getMessageHeader().getImei());
dto.setUserId(loginPack.getUserId());
dto.setClientType(msg.getMessageHeader().getClientType());
dto.setAppId(msg.getMessageHeader().getAppId());
RTopic topic = redissonClient.getTopic(Constants.RedisConstants.USER_LOGIN_CHANNEL);
topic.publish(JSONObject.toJSONString(dto));
UserStatusChangeNotifyPack userStatusChangeNotifyPack = new UserStatusChangeNotifyPack();
userStatusChangeNotifyPack.setAppId(msg.getMessageHeader().getAppId());
userStatusChangeNotifyPack.setUserId(loginPack.getUserId());
userStatusChangeNotifyPack.setStatus(ImConnectStatusEnum.ONLINE_STATUS.getCode());
MqMessageProducer.sendMessage(userStatusChangeNotifyPack,
msg.getMessageHeader(),
UserEventCommand.USER_ONLINE_STATUS_CHANGE.getCommand());
MessagePack<LoginAckPack> loginSuccess = new MessagePack<>();
LoginAckPack loginAckPack = new LoginAckPack();
loginAckPack.setUserId(loginPack.getUserId());
loginSuccess.setCommand(SystemCommand.LOGIN_ACK.getCommand());
loginSuccess.setData(loginAckPack);
loginSuccess.setImei(msg.getMessageHeader().getImei());
loginSuccess.setAppId(msg.getMessageHeader().getAppId());
ctx.channel().writeAndFlush(loginSuccess);
} else if (command == SystemCommand.LOGOUT.getCommand()) {
SessionSocketHolder.removeUserSession((NioSocketChannel) ctx.channel());
} else if (command == SystemCommand.PING.getCommand()) {
logger.info("PING-{}",System.currentTimeMillis());
ctx.channel().attr(AttributeKey.valueOf(Constants.READ_TIME)).set(System.currentTimeMillis());
} else if (command == MessageCommand.MSG_P2P.getCommand() || command == GroupEventCommand.MSG_GROUP.getCommand()) {
try {
String toId;
CheckSendMessageReq req = new CheckSendMessageReq();
req.setAppId(msg.getMessageHeader().getAppId());
req.setCommand(msg.getMessageHeader().getCommand());
JSONObject jsonObject = JSON.parseObject(JSONObject.toJSONString(msg.getMessagePack()));
String fromId = jsonObject.getString("fromId");
if (command == MessageCommand.MSG_P2P.getCommand()) {
toId = jsonObject.getString("toId");
} else {
toId = jsonObject.getString("groupId");
}
req.setToId(toId);
req.setFromId(fromId);
logger.info("appId-{}-toId-{}-fromId-{}",msg.getMessageHeader().getAppId(),toId,fromId);
ResponseVO responseVO = feignMessageService.checkSendMessage(req);
if (responseVO.isOk()) {
MqMessageProducer.sendMessage(msg, command);
} else {
int ackCommand;
if (command == MessageCommand.MSG_P2P.getCommand()) {
ackCommand = MessageCommand.MSG_ACK.getCommand();
} else {
ackCommand = GroupEventCommand.GROUP_MSG_ACK.getCommand();
}
MessagePack<ResponseVO> ack = new MessagePack<>();
ChatMessageAck chatMessageAck = new ChatMessageAck(jsonObject.getString("messageId"));
responseVO.setData(chatMessageAck);
ack.setData(responseVO);
ack.setCommand(ackCommand);
ctx.channel().writeAndFlush(ack);
}
} catch (Exception e) {
e.printStackTrace();
}
} else {
logger.info("*******************NettyServerHandler--没有匹配上的都发送到mq中**************");
MqMessageProducer.sendMessage(msg, command);
}
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
super.exceptionCaught(ctx, cause);
}
}