package ch.loway.oss.ari4java.tools.http;
import ch.loway.oss.ari4java.tools.HttpResponseHandler;
import ch.loway.oss.ari4java.tools.WsClientAutoReconnect;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.util.CharsetUtil;
/**
* NettyWSClientHandler handles the transactions with the remote
* WebSocket, forwarding to the client HttpResponseHandler interface.
*
* @author mwalton
*
*/
@ChannelHandler.Sharable
public class NettyWSClientHandler extends NettyHttpClientHandler {
final WebSocketClientHandshaker handshaker;
private ChannelPromise handshakeFuture;
final HttpResponseHandler wsCallback;
private WsClientAutoReconnect wsClient = null;
private boolean shuttingDown = false;
public NettyWSClientHandler(WebSocketClientHandshaker handshaker, HttpResponseHandler wsCallback, WsClientAutoReconnect wsClient) {
this(handshaker, wsCallback);
this.wsClient = wsClient;
}
public NettyWSClientHandler(WebSocketClientHandshaker handshaker, HttpResponseHandler wsCallback) {
this.handshaker = handshaker;
this.wsCallback = wsCallback;
}
public ChannelFuture handshakeFuture() {
return handshakeFuture;
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
handshakeFuture = ctx.newPromise();
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
handshaker.handshake(ctx.channel());
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
if (!shuttingDown) {
if (this.wsClient != null) {
wsClient.reconnectWs();
} else {
wsCallback.onDisconnect();
}
}
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
Channel ch = ctx.channel();
if (!handshaker.isHandshakeComplete()) {
handshaker.finishHandshake(ch, (FullHttpResponse) msg);
handshakeFuture.setSuccess();
wsCallback.onChReadyToWrite();
return;
}
if (msg instanceof FullHttpResponse) {
FullHttpResponse response = (FullHttpResponse) msg;
String error = "Unexpected FullHttpResponse (getStatus=" + response.getStatus() + ", content=" + response.content().toString(CharsetUtil.UTF_8) + ')';
System.err.println(error);
throw new Exception(error);
}
// call this so we can set the last received time
wsCallback.onResponseReceived();
WebSocketFrame frame = (WebSocketFrame) msg;
if (frame instanceof TextWebSocketFrame) {
TextWebSocketFrame textFrame = (TextWebSocketFrame) frame;
responseText = textFrame.text();
wsCallback.onSuccess(textFrame.text());
} else if (frame instanceof CloseWebSocketFrame) {
ch.close();
if (!shuttingDown) {
if (this.wsClient != null) {
wsClient.reconnectWs();
} else {
wsCallback.onDisconnect();
}
}
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (!shuttingDown)
return;
cause.printStackTrace();
if (!handshakeFuture.isDone()) {
handshakeFuture.setFailure(cause);
}
ctx.close();
wsCallback.onFailure(cause);
}
public boolean isShuttingDown() {
return shuttingDown;
}
public void setShuttingDown(boolean shuttingDown) {
this.shuttingDown = shuttingDown;
}
}