package com.lambdaworks.redis.sentinel;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.atomic.AtomicReference;
import com.lambdaworks.redis.RedisFuture;
import com.lambdaworks.redis.RedisSentinelAsyncConnection;
import com.lambdaworks.redis.api.StatefulConnection;
import com.lambdaworks.redis.codec.RedisCodec;
import com.lambdaworks.redis.internal.LettuceAssert;
import com.lambdaworks.redis.protocol.AsyncCommand;
import com.lambdaworks.redis.protocol.Command;
import com.lambdaworks.redis.protocol.RedisCommand;
import com.lambdaworks.redis.sentinel.api.StatefulRedisSentinelConnection;
import com.lambdaworks.redis.sentinel.api.async.RedisSentinelAsyncCommands;
/**
* An asynchronous and thread-safe API for a Redis Sentinel connection.
*
* @param <K> Key type.
* @param <V> Value type.
* @author Mark Paluch
* @since 3.0
*/
public class RedisSentinelAsyncCommandsImpl<K, V> implements RedisSentinelAsyncCommands<K, V>,
RedisSentinelAsyncConnection<K, V> {
private final SentinelCommandBuilder<K, V> commandBuilder;
private final StatefulConnection<K, V> connection;
public RedisSentinelAsyncCommandsImpl(StatefulConnection<K, V> connection, RedisCodec<K, V> codec) {
this.connection = connection;
commandBuilder = new SentinelCommandBuilder<K, V>(codec);
}
@Override
public RedisFuture<SocketAddress> getMasterAddrByName(K key) {
Command<K, V, List<V>> cmd = commandBuilder.getMasterAddrByKey(key);
CompletionStage<List<V>> future = dispatch(cmd);
AtomicReference<SocketAddress> ref = new AtomicReference<>();
AsyncCommand<K, V, SocketAddress> convert = new AsyncCommand<K, V, SocketAddress>((RedisCommand) cmd) {
@Override
protected void completeResult() {
complete(ref.get());
}
};
future.whenComplete((list, t) -> {
if (t != null) {
convert.completeExceptionally(t);
return;
}
if (!list.isEmpty()) {
LettuceAssert.isTrue(list.size() == 2, "List must contain exact 2 entries (Hostname, Port)");
String hostname = (String) list.get(0);
String port = (String) list.get(1);
ref.set(new InetSocketAddress(hostname, Integer.parseInt(port)));
}
convert.complete();
});
return convert;
}
@Override
public RedisFuture<List<Map<K, V>>> masters() {
return dispatch(commandBuilder.masters());
}
@Override
public RedisFuture<Map<K, V>> master(K key) {
return dispatch(commandBuilder.master(key));
}
@Override
public RedisFuture<List<Map<K, V>>> slaves(K key) {
return dispatch(commandBuilder.slaves(key));
}
@Override
public RedisFuture<Long> reset(K key) {
return dispatch(commandBuilder.reset(key));
}
@Override
public RedisFuture<String> failover(K key) {
return dispatch(commandBuilder.failover(key));
}
@Override
public RedisFuture<String> monitor(K key, String ip, int port, int quorum) {
return dispatch(commandBuilder.monitor(key, ip, port, quorum));
}
@Override
public RedisFuture<String> set(K key, String option, V value) {
return dispatch(commandBuilder.set(key, option, value));
}
@Override
public RedisFuture<String> remove(K key) {
return dispatch(commandBuilder.remove(key));
}
@Override
public RedisFuture<String> ping() {
return dispatch(commandBuilder.ping());
}
public <T> AsyncCommand<K, V, T> dispatch(RedisCommand<K, V, T> cmd) {
return connection.dispatch(new AsyncCommand<>(cmd));
}
@Override
public void close() {
connection.close();
}
@Override
public boolean isOpen() {
return connection.isOpen();
}
@Override
public StatefulRedisSentinelConnection<K, V> getStatefulConnection() {
return (StatefulRedisSentinelConnection<K, V>) connection;
}
}