package com.outbrain.gruffalo.netty;
import com.google.common.base.Preconditions;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelOption;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
class GruffaloProxy {
private static final Logger log = LoggerFactory.getLogger(GruffaloProxy.class);
private final ChannelFuture tcpChannelFuture;
private final ChannelFuture udpChannelFuture;
private final EventLoopGroup eventLoopGroup;
private final Throttler throttler;
public GruffaloProxy(final EventLoopGroup eventLoopGroup, final TcpServerPipelineFactory tcpServerPipelineFactory,
final UdpServerPipelineFactory udpServerPipelineFactory, final int tcpPort, final int udpPort, final Throttler throttler) throws InterruptedException {
this.throttler = Preconditions.checkNotNull(throttler, "throttler must not be null");
this.eventLoopGroup = Preconditions.checkNotNull(eventLoopGroup, "eventLoopGroup must not be null");
tcpChannelFuture = createTcpBootstrap(tcpServerPipelineFactory, tcpPort);
udpChannelFuture = createUdpBootstrap(udpServerPipelineFactory, udpPort);
log.info("Initialization completed");
}
public static void main(final String[] args) {
new ClassPathXmlApplicationContext("classpath:applicationContext-GruffaloLib-all.xml");
}
private ChannelFuture createUdpBootstrap(final UdpServerPipelineFactory udpServerPipelineFactory, final int udpPort) throws InterruptedException {
log.info("Initializing UDP...");
Bootstrap udpBootstrap = new Bootstrap();
udpBootstrap.group(eventLoopGroup).channel(NioDatagramChannel.class).handler(udpServerPipelineFactory);
final ChannelFuture channelFuture = udpBootstrap.bind(udpPort);
log.info("Binding to UDP port {}", udpPort);
return channelFuture;
}
private ChannelFuture createTcpBootstrap(final TcpServerPipelineFactory tcpServerPipelineFactory, final int tcpPort) throws InterruptedException {
log.info("Initializing TCP...");
ServerBootstrap tcpBootstrap = new ServerBootstrap();
tcpBootstrap.group(eventLoopGroup);
tcpBootstrap.channel(NioServerSocketChannel.class);
tcpBootstrap.childHandler(tcpServerPipelineFactory);
tcpBootstrap.option(ChannelOption.ALLOCATOR, UnpooledByteBufAllocator.DEFAULT);
final ChannelFuture channelFuture = tcpBootstrap.bind(tcpPort).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(final ChannelFuture future) throws Exception {
throttler.setServerChannel(future.channel());
}
});
log.info("Binding to TCP port {}", tcpPort);
return channelFuture;
}
public void shutdown() throws InterruptedException {
log.info("Shutting down inbound channels...");
tcpChannelFuture.sync().channel().closeFuture().await(200);
udpChannelFuture.sync().channel().closeFuture().await(200);
log.info("Shutting down server...");
eventLoopGroup.shutdownGracefully();
}
}