package com.lambdaworks.redis.sentinel; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.Map; import java.util.function.Supplier; import rx.Observable; import com.lambdaworks.redis.ReactiveCommandDispatcher; import com.lambdaworks.redis.api.StatefulConnection; import com.lambdaworks.redis.codec.RedisCodec; import com.lambdaworks.redis.internal.LettuceAssert; import com.lambdaworks.redis.protocol.RedisCommand; import com.lambdaworks.redis.sentinel.api.StatefulRedisSentinelConnection; import com.lambdaworks.redis.sentinel.api.rx.RedisSentinelReactiveCommands; /** * A reactive 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 RedisSentinelReactiveCommandsImpl<K, V> implements RedisSentinelReactiveCommands<K, V> { private final SentinelCommandBuilder<K, V> commandBuilder; private final StatefulConnection<K, V> connection; public RedisSentinelReactiveCommandsImpl(StatefulConnection<K, V> connection, RedisCodec<K, V> codec) { this.connection = connection; commandBuilder = new SentinelCommandBuilder<K, V>(codec); } @Override public Observable<SocketAddress> getMasterAddrByName(K key) { Observable<V> observable = createDissolvingObservable(() -> commandBuilder.getMasterAddrByKey(key)); return observable.buffer(2).map(list -> { if (list.isEmpty()) { return null; } 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); return new InetSocketAddress(hostname, Integer.parseInt(port)); }); } @Override public Observable<Map<K, V>> masters() { return createDissolvingObservable(() -> commandBuilder.masters()); } @Override public Observable<Map<K, V>> master(K key) { return createObservable(() -> commandBuilder.master(key)); } @Override public Observable<Map<K, V>> slaves(K key) { return createDissolvingObservable(() -> commandBuilder.slaves(key)); } @Override public Observable<Long> reset(K key) { return createObservable(() -> commandBuilder.reset(key)); } @Override public Observable<String> failover(K key) { return createObservable(() -> commandBuilder.failover(key)); } @Override public Observable<String> monitor(K key, String ip, int port, int quorum) { return createObservable(() -> commandBuilder.monitor(key, ip, port, quorum)); } @Override public Observable<String> set(K key, String option, V value) { return createObservable(() -> commandBuilder.set(key, option, value)); } @Override public Observable<String> remove(K key) { return createObservable(() -> commandBuilder.remove(key)); } @Override public Observable<String> ping() { return createObservable(() -> commandBuilder.ping()); } @Override public void close() { connection.close(); } @Override public boolean isOpen() { return connection.isOpen(); } @Override public StatefulRedisSentinelConnection<K, V> getStatefulConnection() { return (StatefulRedisSentinelConnection<K, V>) connection; } public <T> Observable<T> createObservable(Supplier<RedisCommand<K, V, T>> commandSupplier) { return Observable.create(new ReactiveCommandDispatcher<K, V, T>(commandSupplier, connection, false)); } @SuppressWarnings("unchecked") public <T, R> R createDissolvingObservable(Supplier<RedisCommand<K, V, T>> commandSupplier) { return (R) Observable.create(new ReactiveCommandDispatcher<>(commandSupplier, connection, true)); } }