package org.greencheek.elasticacheconfig.client;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;
import org.greencheek.elasticacheconfig.confighandler.AsyncConfigInfoMessageHandler;
import org.greencheek.elasticacheconfig.decoder.ConfigInfoDecoder;
import org.greencheek.elasticacheconfig.handler.ClientInfoClientHandler;
import org.greencheek.elasticacheconfig.handler.RequestConfigInfoScheduler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.TimeUnit;
/**
* Created by dominictootell on 20/07/2014.
*/
public class PeriodicConfigRetrievalClient
{
private static final Logger log = LoggerFactory.getLogger(PeriodicConfigRetrievalClient.class);
private final TimeUnit idleTimeoutTimeUnit;
private final long readTimeout;
private final ClientInfoClientHandler handler;
private final int connectionTimeoutInMillis;
private final ElastiCacheConfigServerChooser configServerChooser;
private NioEventLoopGroup nioEventLoopGroup = new NioEventLoopGroup();
public PeriodicConfigRetrievalClient(ConfigRetrievalSettings settings)
{
ElastiCacheServerConnectionDetails[] configServers = settings.getElasticacheConfigHosts();
if(configServers.length==1) {
this.configServerChooser = new SingleElastiCacheConfigServerChooser(configServers[0]);
} else {
this.configServerChooser = new RoundRobinElastiCacheConfigServerChooser(configServers);
}
this.idleTimeoutTimeUnit = settings.getIdleTimeoutTimeUnit();
this.readTimeout = settings.getIdleReadTimeout();
this.connectionTimeoutInMillis = settings.getConnectionTimeoutInMillis();
this.handler = createHandler(settings.getScheduledConfigRetrieval(),settings.getConfigInfoMessageHandler(),
settings.getReconnectDelayTimeUnit(),settings.getReconnectDelay(),idleTimeoutTimeUnit,readTimeout,
settings.getNumberOfConsecutiveInvalidConfigsBeforeReconnect(),
connectionTimeoutInMillis);
}
public ClientInfoClientHandler createHandler(RequestConfigInfoScheduler scheduledRequester,
AsyncConfigInfoMessageHandler configReadHandler,
TimeUnit reconnectTimeUnit,
long reconnectionDelay,
TimeUnit idleTimeoutTimeUnit,
long idleReadTimeout,
int noConsecutiveInvalidConfigsBeforeReconnect,
int connectionTimeoutInMillis) {
return new ClientInfoClientHandler(scheduledRequester,configReadHandler,reconnectTimeUnit,reconnectionDelay,
idleTimeoutTimeUnit,idleReadTimeout,this.configServerChooser,noConsecutiveInvalidConfigsBeforeReconnect,
connectionTimeoutInMillis);
}
public void start() {
configureBootstrap(this.configServerChooser,handler,new Bootstrap(),nioEventLoopGroup,idleTimeoutTimeUnit,readTimeout,connectionTimeoutInMillis);
}
public void stop() {
nioEventLoopGroup.shutdownGracefully();
handler.shutdown();
}
public static ChannelFuture configureBootstrap(ElastiCacheConfigServerChooser configServerService,final ClientInfoClientHandler handler,
Bootstrap b, EventLoopGroup g, final TimeUnit idleTimeoutTimeUnit, final long idleTimeout,
final int connectionTimeoutInMillis) {
final ElastiCacheServerConnectionDetails configServer = configServerService.getServer();
b.group(g)
.channel(NioSocketChannel.class)
.remoteAddress(configServer.getHost(),configServer.getPort())
.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.config().setConnectTimeoutMillis(connectionTimeoutInMillis);
ch.pipeline().addLast(new ConfigInfoDecoder());
ch.pipeline().addLast(new IdleStateHandler(idleTimeout, 0, 0,idleTimeoutTimeUnit));
ch.pipeline().addLast(handler);
}
});
return b.connect().addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (future.cause() != null) {
log.warn("Failed to connect: {}:{}",configServer.getHost(),configServer.getPort(), future.cause());
}
}
});
}
}