package com.intrbiz.bergamot.notification.engine.slack.io;
import java.nio.charset.Charset;
import java.util.Timer;
import java.util.TimerTask;
import javax.net.ssl.SSLEngine;
import org.apache.log4j.Logger;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.ssl.SslHandshakeCompletionEvent;
public class SlackClientHandler extends ChannelInboundHandlerAdapter
{
private final Logger logger = Logger.getLogger(SlackClientHandler.class);
private volatile long start;
private final FullHttpRequest request;
private final Timer timer;
private final SSLEngine sslEngine;
private volatile TimerTask timeoutTask;
private volatile boolean timedOut = false;
public SlackClientHandler(Timer timer, SSLEngine sslEngine, FullHttpRequest request)
{
super();
this.request = request;
this.timer = timer;
this.sslEngine = sslEngine;
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
{
if (! this.timedOut)
{
FullHttpResponse response = (FullHttpResponse) msg;
long runtime = System.currentTimeMillis() - this.start;
logger.info("Slack WebHook: Got HTTP response: " + response.getStatus() + " in: " + runtime + "ms");
if (logger.isTraceEnabled())
{
logger.trace("Response:\n" + response);
logger.trace("Content:\n" + response.content().toString(Charset.defaultCharset()));
}
// cancel the timeout
if (this.timeoutTask != null) this.timeoutTask.cancel();
// Note: we don't currently care what the response it, simply fire and move on
}
// close
if (ctx.channel().isActive()) ctx.close();
}
@Override
public void channelActive(ChannelHandlerContext ctx)
{
logger.debug("Connection opened: " + ctx.channel().remoteAddress());
if (this.sslEngine == null)
{
// plain request
this.sendRequest(ctx);
}
}
public void userEventTriggered(ChannelHandlerContext ctx, Object event)
{
if (this.sslEngine != null && event instanceof SslHandshakeCompletionEvent)
{
SslHandshakeCompletionEvent ev = (SslHandshakeCompletionEvent) event;
logger.debug("SSL handshake complete: " + ev.isSuccess());
if (ev.isSuccess())
{
this.sendRequest(ctx);
}
}
}
protected void sendRequest(ChannelHandlerContext ctx)
{
logger.debug("Sending HTTP request");
this.start = System.currentTimeMillis();
// schedule timeout for 60 seconds
this.timeoutTask = new TimeoutTask(this);
this.timer.schedule(this.timeoutTask, this.start + 60_000L);
// send the request
if (logger.isTraceEnabled()) logger.trace("Request:\n" + this.request);
ctx.writeAndFlush(this.request);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception
{
logger.debug("Connection closed: " + ctx.channel().remoteAddress());
if (this.timeoutTask != null) this.timeoutTask.cancel();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception
{
logger.error("Error processing HTTP request: " + cause);
}
protected void onTimeout()
{
// invoke the error timeout
this.timedOut = true;
}
/**
* Timeout timer task which will nullify the HTTPClientHandler immediately
*/
protected static class TimeoutTask extends TimerTask
{
private volatile SlackClientHandler handler;
public TimeoutTask(SlackClientHandler handler)
{
this.handler = handler;
}
@Override
public void run()
{
if (this.handler != null) this.handler.onTimeout();
this.handler = null;
}
@Override
public boolean cancel()
{
this.handler = null;
return super.cancel();
}
};
}