WindChat/windchat-connector/src/main/java/com/windchat/im/connector/netty/handler/NettyServerHandler.java

175 lines
7.4 KiB
Java
Raw Normal View History

2019-07-29 23:42:16 +08:00
/**
* Copyright 2018-2028 Akaxin Group
*
* Licensed 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
*
* 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,
* 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.
*/
2019-11-27 23:33:33 +08:00
package com.windchat.im.connector.netty.handler;
2019-07-29 23:42:16 +08:00
import java.net.InetSocketAddress;
import java.util.Map;
2019-11-27 23:33:33 +08:00
import com.windchat.im.connector.codec.parser.ChannelConst;
2019-07-29 23:42:16 +08:00
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
2019-11-27 23:36:54 +08:00
import com.windchat.common.channel.ChannelManager;
import com.windchat.common.channel.ChannelSession;
import com.windchat.common.command.Command;
import com.windchat.common.command.CommandResponse;
import com.windchat.common.command.RedisCommand;
import com.windchat.common.constant.RequestAction;
import com.windchat.common.executor.AbstracteExecutor;
import com.windchat.common.logs.LogUtils;
import com.windchat.common.utils.StringHelper;
2019-07-29 23:42:16 +08:00
import com.akaxin.proto.core.CoreProto;
2019-11-27 23:33:33 +08:00
import com.windchat.im.connector.constant.AkxProject;
import com.windchat.im.connector.session.SessionManager;
2019-07-29 23:42:16 +08:00
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
/**
* Netty处理TCP链接中接受客户端传入的消息
*
* @author Sam{@link an.guoyue254@gmail.com}
* @since 2017.11.07 16:56:36
*/
public class NettyServerHandler extends SimpleChannelInboundHandler<RedisCommand> {
private static final Logger logger = LoggerFactory.getLogger(NettyServerHandler.class);
private AbstracteExecutor<Command, CommandResponse> executor;
public NettyServerHandler(AbstracteExecutor<Command, CommandResponse> executor) {
this.executor = executor;
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
InetSocketAddress socketAddress = (InetSocketAddress) ctx.channel().remoteAddress();
String clientIp = socketAddress.getAddress().getHostAddress();
ctx.channel().attr(ChannelConst.CHANNELSESSION).set(new ChannelSession(ctx.channel()));
logger.debug("{} client={} connect to Netty Server...", AkxProject.PLN, clientIp);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
InetSocketAddress socketAddress = (InetSocketAddress) ctx.channel().remoteAddress();
String clientIp = socketAddress.getAddress().getHostAddress();
logger.debug("{} client={} close connection... ChannelSize={}", AkxProject.PLN, clientIp,
ChannelManager.getChannelSessionSize());
ChannelSession channelSession = ctx.channel().attr(ChannelConst.CHANNELSESSION).get();
if (channelSession.getCtype() == 1 && StringUtils.isNotEmpty(channelSession.getUserId())) {
ChannelManager.delChannelSession(channelSession.getDeviceId());
String siteUserId = channelSession.getUserId();
String deviceId = channelSession.getDeviceId();
boolean offRes = SessionManager.getInstance().setUserOffline(siteUserId, deviceId);
logger.debug("{} set client={} siteUserId={} deviceId={} offline-status:{} ChannelSize={}", AkxProject.PLN,
clientIp, siteUserId, deviceId, offRes, ChannelManager.getChannelSessionSize());
}
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, RedisCommand redisCmd) throws Exception {
InetSocketAddress socketAddress = (InetSocketAddress) ctx.channel().remoteAddress();
String clientIp = socketAddress.getAddress().getHostAddress();
ChannelSession channelSession = ctx.channel().attr(ChannelConst.CHANNELSESSION).get();
// Channel不可用情况下关闭连接事件
// disconnect tcp connection as channel is unavailable
if (channelSession.getChannel() == null || !channelSession.getChannel().isActive()) {
ctx.disconnect();// 断开连接事件(与对方的连接断开)
logger.warn("{} close client={} as its channel is not active ", AkxProject.PLN, clientIp);
}
String version = redisCmd.getParameterByIndex(0);// 网络协议版本1.0
String action = redisCmd.getParameterByIndex(1);
byte[] params = redisCmd.getBytesParamByIndex(2);
CoreProto.TransportPackageData packageData = CoreProto.TransportPackageData.parseFrom(params);
Map<Integer, String> header = packageData.getHeaderMap();
Command command = new Command();
command.setClientIp(clientIp);
command.setSiteUserId(channelSession.getUserId());
command.setDeviceId(channelSession.getDeviceId());
command.setAction(action);
command.setHeader(header);
if (header != null) {
command.setClientVersion(header.get(CoreProto.HeaderKey.CLIENT_SOCKET_VERSION_VALUE));
}
command.setParams(packageData.getData().toByteArray());
command.setChannelSession(channelSession);
command.setStartTime(System.currentTimeMillis());
if (!RequestAction.IM_CTS_PING.getName().equalsIgnoreCase(command.getAction())) {
logger.debug("{} client={} -> site version={} action={} params-length={}", AkxProject.PLN, clientIp,
version, action, params.length);
}
if (RequestAction.IM.getName().equals(command.getRety())) {
// 如果是syncFinish则这里需要修改channel中的syncFinTime
channelSession.setActionForPsn(action);
// 单独处理im.site.hello && im.site.auth
if (RequestAction.SITE.getName().equalsIgnoreCase(command.getService())) {
String anoRequest = command.getRety() + "." + command.getService();
command.setRety(anoRequest);
}
CommandResponse response = this.executor.execute(command.getRety(), command);
if (!RequestAction.IM_CTS_PING.getName().equals(command.getAction())) {
// 输出IM请求结果
LogUtils.requestResultLog(logger, command, response);
}
} else if (RequestAction.API.getName().equalsIgnoreCase(command.getRety())) {
CommandResponse response = this.executor.execute(command.getRety(), command);
// 输出API请求结果
LogUtils.requestResultLog(logger, command, response);
} else {
/**
* <pre>
*
* pipeline.addLast("A", new AHandler());
* pipeline.addLast("B", new BHandler());
* pipeline.addLast("C", new CHandler());
*
* ctx.close() && channel().close();
* ctx.close(): close the channel in current handler,will start from the tail of the ChannelPipeline
* do A.close() ,B.close(),C.close();
* channel().close():close channel in all handler from pointer
* do C.close() , B.close(), A.close();
* </pre>
*/
ctx.channel().close();// 关闭channel事件(关闭自己的连接)
logger.error("{} client={} siteUserId={} action={} unknow request method", AkxProject.PLN,
command.getClientIp(), command.getSiteUserId(), command.getAction());
return;
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
InetSocketAddress socketAddress = (InetSocketAddress) ctx.channel().remoteAddress();
String clientIp = socketAddress.getAddress().getHostAddress();
ctx.close();
logger.error(StringHelper.format("{} client{} channel exeception happen.", AkxProject.PLN, clientIp), cause);
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
// 设置idle触发此方法
// logger.info("user event triggered evt={}", evt.toString());
}
}