package redis.netty4; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.socket.SocketChannel; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; import spullara.util.concurrent.Promise; import java.net.InetSocketAddress; import java.util.LinkedList; import java.util.Queue; /** * Uses netty4 to talk to redis. */ public class RedisClientBase { private final static NioEventLoopGroup group = new NioEventLoopGroup(Runtime.getRuntime().availableProcessors()); private final SocketChannel socketChannel; private final Queue<Promise<Reply>> queue; protected RedisClientBase(SocketChannel socketChannel, Queue<Promise<Reply>> queue) { this.socketChannel = socketChannel; this.queue = queue; group.register(socketChannel); } public static Promise<RedisClientBase> connect(String host, int port) { final Queue<Promise<Reply>> queue = new LinkedList<>(); SocketChannel socketChannel = new NioSocketChannel(); final RedisClientBase client = new RedisClientBase(socketChannel, queue); socketChannel.pipeline().addLast(new RedisCommandEncoder(), new RedisReplyDecoder(), new SimpleChannelInboundHandler<Reply<?>>() { @Override protected void channelRead0(ChannelHandlerContext channelHandlerContext, Reply<?> reply) throws Exception { Promise<Reply> poll; synchronized (client) { poll = queue.poll(); if (poll == null) { throw new IllegalStateException("Promise queue is empty, received reply"); } } poll.set(reply); } }); final Promise<RedisClientBase> promise = new Promise<>(); socketChannel.connect(new InetSocketAddress(host, port)).addListener(new ChannelFutureListenerPromiseAdapter<>(promise, client)); return promise; } public Promise<Reply> send(Command command) { Promise<Reply> reply = new Promise<>(); synchronized (this) { queue.add(reply); socketChannel.write(command); } return reply; } }