184 lines
6.7 KiB
Java
Executable File
184 lines
6.7 KiB
Java
Executable File
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);
|
||
}
|
||
|
||
}
|