WindChat/windchat-connector/src/main/java/com/windchat/im/connector/ws/handler/WsServerHandler.java

184 lines
6.7 KiB
Java
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.windchat.im.connector.ws.handler;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.windchat.common.channel.ChannelSession;
import com.windchat.common.channel.WebChannelManager;
import com.windchat.common.command.Command;
import com.windchat.common.command.CommandResponse;
import com.windchat.common.constant.CharsetCoding;
import com.windchat.common.executor.AbstracteExecutor;
import com.windchat.im.business.cache.WebSessionCache;
import com.windchat.im.connector.codec.parser.ChannelConst;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.QueryStringDecoder;
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;
/**
* 接受客户端发送的消息客户端发送的消息组装成TextWebSocketFrame格式
*
* @author Sam{@link an.guoyue254@gmail.com}
* @since 2018-05-02 15:01:08
*/
public class WsServerHandler extends SimpleChannelInboundHandler<Object> {
private static Logger logger = LoggerFactory.getLogger(WsServerHandler.class);
private static final String AKAXIN_WS_PATH = "/akaxin/ws";
// ws 握手
private WebSocketServerHandshaker wsHandshaker;
private AbstracteExecutor<Command, CommandResponse> executor;
public WsServerHandler(AbstracteExecutor<Command, CommandResponse> executor) {
this.executor = executor;
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
System.out.println("ChannelId" + ctx.channel().id().asLongText());
}
// 客户端连接上服务端
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channel active clientIp" + ctx.channel().remoteAddress().toString());
ctx.channel().attr(ChannelConst.CHANNELSESSION).set(new ChannelSession(ctx.channel()));
}
// 从客户端读取消息
@Override
protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof FullHttpRequest) {
// http 请求握手
doHttpRequest(ctx, (FullHttpRequest) msg);
} else if (msg instanceof WebSocketFrame) {
// websocket 请求
doWSRequest(ctx, (WebSocketFrame) msg);
} else {
// 错误请求,关闭连接
ctx.close();
}
}
// 处理http请求ws握手使用http请求
private void doHttpRequest(ChannelHandlerContext ctx, FullHttpRequest request) {
if (request.decoderResult().isFailure()) {
ctx.close();
return;
}
// 握手使用get方法所以我们控制只接受get方法
if (HttpMethod.GET != request.method()) {
ctx.close();
return;
}
String wsUrl = "ws://" + request.headers().get(HttpHeaderNames.HOST) + AKAXIN_WS_PATH;
WebSocketServerHandshakerFactory webSocketFactory = new WebSocketServerHandshakerFactory(wsUrl, null, true);
wsHandshaker = webSocketFactory.newHandshaker(request);
if (wsHandshaker != null) {
//
ChannelFuture channelFuture = wsHandshaker.handshake(ctx.channel(), request);
if (channelFuture.isSuccess()) {
// 握手并且验证用户webSessionId
QueryStringDecoder queryDecoder = new QueryStringDecoder(request.uri());
List<String> sessionIds = queryDecoder.parameters().get("sessionId");
if (sessionIds != null && sessionIds.size() > 0) {
String sessionId = sessionIds.get(0);
String siteUserId = WebSessionCache.getSiteUserId(sessionId);
// test siteUserId
siteUserId = "77151873-0fc7-4cf1-8bd6-67d00190fcf6";
if (StringUtils.isNotBlank(siteUserId)) {
ChannelSession channelSession = ctx.channel().attr(ChannelConst.CHANNELSESSION).get();
// siteUserId && sessionId 放入Channel缓存中
channelSession.setUserId(siteUserId);
WebChannelManager.addChannelSession(siteUserId, channelSession);
} else {
// cant get authed message ,so close the channel
// ctx.close();
}
} else {
ctx.close();
}
System.out.println("client handshaker success parm=" + queryDecoder.parameters());
}
} else {
WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
}
}
// 处理ws请求
private void doWSRequest(ChannelHandlerContext ctx, WebSocketFrame wsFrame) {
InetSocketAddress socketAddress = (InetSocketAddress) ctx.channel().remoteAddress();
String clientIp = socketAddress.getAddress().getHostAddress();
ChannelSession channelSession = ctx.channel().attr(ChannelConst.CHANNELSESSION).get();
Command command = new Command();
command.setSiteUserId(channelSession.getUserId());
command.setClientIp(clientIp);
command.setStartTime(System.currentTimeMillis());
if (wsFrame instanceof TextWebSocketFrame) {
TextWebSocketFrame textWsFrame = (TextWebSocketFrame) wsFrame;
String webText = textWsFrame.text();
try {
command.setParams(webText.getBytes(CharsetCoding.UTF_8));
} catch (UnsupportedEncodingException e) {
logger.error("web message text=" + webText + " Charset code error");
}
TextWebSocketFrame resFrame = new TextWebSocketFrame(textWsFrame.text());
ctx.channel().writeAndFlush(resFrame);
executor.execute("WS-ACTION", command);
} else if (wsFrame instanceof PingWebSocketFrame) {
// ping/pong
ctx.channel().writeAndFlush(new PongWebSocketFrame(wsFrame.content().retain()));
logger.info("ws client siteUserId={} ping to server", command.getSiteUserId());
} else if (wsFrame instanceof CloseWebSocketFrame) {
// close channel
wsHandshaker.close(ctx.channel(), (CloseWebSocketFrame) wsFrame.retain());
WebChannelManager.delChannelSession(command.getSiteUserId());
}
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
ChannelSession channelSession = ctx.channel().attr(ChannelConst.CHANNELSESSION).get();
WebChannelManager.delChannelSession(channelSession.getUserId());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
// ctx.close();
logger.error("ws channel exception happen", cause);
}
}