-
Notifications
You must be signed in to change notification settings - Fork 1.1k
[reactor-optional] Credentials as adapter 8x #3842
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
a-TODO-rov
wants to merge
3
commits into
feature/reactor-optional-1
Choose a base branch
from
creds-adapter-8x
base: feature/reactor-optional-1
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
65 changes: 65 additions & 0 deletions
65
src/main/java/io/lettuce/core/AsyncCredentialsProviderAdapter.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| /* | ||
| * Copyright (c) 2026-Present, Redis Ltd. All rights reserved. | ||
| * SPDX-License-Identifier: MIT | ||
| */ | ||
| package io.lettuce.core; | ||
|
|
||
| import java.util.concurrent.CompletionStage; | ||
| import java.util.function.Consumer; | ||
|
|
||
| import reactor.core.publisher.Mono; | ||
|
|
||
| /** | ||
| * Adapts a reactor-free {@link CredentialsProvider} to the deprecated reactive {@link RedisCredentialsProvider}, so | ||
| * {@link RedisURI#getCredentialsProvider()} can keep returning a {@link RedisCredentialsProvider} while credentials are stored | ||
| * internally as a {@link CredentialsProvider}. Only {@link #resolveCredentials()} materialises a {@link Mono}; the async and | ||
| * streaming paths delegate directly and stay reactor-free. | ||
| * | ||
| * @author Aleksandar Todorov | ||
| * @since 7.7 | ||
| */ | ||
| class AsyncCredentialsProviderAdapter implements RedisCredentialsProvider { | ||
|
|
||
| private final CredentialsProvider delegate; | ||
|
|
||
| AsyncCredentialsProviderAdapter(CredentialsProvider delegate) { | ||
| this.delegate = delegate; | ||
| } | ||
|
|
||
| @Override | ||
| public Mono<RedisCredentials> resolveCredentials() { | ||
| return Mono.fromCompletionStage(delegate.resolveCredentialsAsync()); | ||
| } | ||
|
|
||
| @Override | ||
| public CompletionStage<RedisCredentials> resolveCredentialsAsync() { | ||
| return delegate.resolveCredentialsAsync(); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean supportsStreaming() { | ||
| return delegate.supportsStreaming(); | ||
| } | ||
|
|
||
| @Override | ||
| public Subscription subscribeToCredentials(Consumer<RedisCredentials> onNext, Consumer<Throwable> onError) { | ||
| return delegate.subscribeToCredentials(onNext, onError); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean equals(Object o) { | ||
| if (this == o) { | ||
| return true; | ||
| } | ||
| if (!(o instanceof AsyncCredentialsProviderAdapter)) { | ||
| return false; | ||
| } | ||
| return delegate.equals(((AsyncCredentialsProviderAdapter) o).delegate); | ||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() { | ||
| return delegate.hashCode(); | ||
| } | ||
|
|
||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,128 @@ | ||
| /* | ||
| * Copyright (c) 2026-Present, Redis Ltd. All rights reserved. | ||
| * SPDX-License-Identifier: MIT | ||
| */ | ||
| package io.lettuce.core; | ||
|
|
||
| import java.util.concurrent.CompletableFuture; | ||
| import java.util.concurrent.CompletionStage; | ||
| import java.util.function.Consumer; | ||
| import java.util.function.Supplier; | ||
|
|
||
| import io.lettuce.core.internal.Futures; | ||
| import io.lettuce.core.internal.LettuceAssert; | ||
|
|
||
| /** | ||
| * Interface for loading {@link RedisCredentials} used to authenticate a Redis connection, resolving credentials asynchronously | ||
| * as a {@link CompletionStage}. Replaces {@link RedisCredentialsProvider}. | ||
| * <p> | ||
| * Credentials are requested by the driver after connecting to the server. Therefore, credential retrieval is subject to | ||
| * complete within the connection creation timeout to avoid connection failures. | ||
| * | ||
| * @author Aleksandar Todorov | ||
| * @since 7.7 | ||
| */ | ||
| @FunctionalInterface | ||
| public interface CredentialsProvider { | ||
|
|
||
| /** | ||
| * Returns {@link RedisCredentials} that can be used to authorize a Redis connection. Each implementation of | ||
| * {@code CredentialsProvider} can choose its own strategy for loading credentials. For example, an implementation might | ||
| * load credentials from an existing key management system, or load new credentials when credentials are rotated. If an | ||
| * error occurs during the loading of credentials or credentials could not be found, the returned {@link CompletionStage} | ||
| * completes exceptionally. | ||
| * | ||
| * @return a {@link CompletionStage} that completes with the {@link RedisCredentials} used to authorize a Redis connection. | ||
| */ | ||
| CompletionStage<RedisCredentials> resolveCredentialsAsync(); | ||
|
|
||
| /** | ||
| * Creates a new {@link CredentialsProvider} from a given {@link Supplier}. | ||
| * | ||
| * @param supplier must not be {@code null}. | ||
| * @return a {@link CredentialsProvider} resolving the {@link RedisCredentials} produced by the {@link Supplier}. | ||
| */ | ||
| static CredentialsProvider from(Supplier<RedisCredentials> supplier) { | ||
|
|
||
| LettuceAssert.notNull(supplier, "Supplier must not be null"); | ||
|
|
||
| return () -> { | ||
| try { | ||
| RedisCredentials credentials = supplier.get(); | ||
| if (credentials == null) { | ||
| return Futures.failed(new IllegalStateException("Provided RedisCredentials supplier returned null")); | ||
| } | ||
| return CompletableFuture.completedFuture(credentials); | ||
| } catch (Exception e) { | ||
| return Futures.failed(e); | ||
| } | ||
| }; | ||
| } | ||
|
|
||
| /** | ||
| * Some implementations of the {@link CredentialsProvider} may support streaming new credentials, based on some event that | ||
| * originates outside the driver. In this case they should indicate that so the {@link RedisAuthenticationHandler} is able | ||
| * to process these new credentials. | ||
| * | ||
| * @return whether the {@link CredentialsProvider} supports streaming credentials. | ||
| */ | ||
| default boolean supportsStreaming() { | ||
| return false; | ||
| } | ||
|
|
||
| /** | ||
| * Subscribe to credential updates produced by this provider. | ||
| * <p> | ||
| * For implementations that support streaming credentials (as indicated by {@link #supportsStreaming()} returning | ||
| * {@code true}), the {@code onNext} consumer is invoked whenever new credentials become available, typically as a result of | ||
| * external events such as token renewal or rotation. The {@code onError} consumer is invoked when the provider observes a | ||
| * failure while obtaining new credentials. | ||
| * <p> | ||
| * Replay semantics on subscription are defined by the implementation and callers should consult the concrete provider's | ||
| * documentation. Subscribers must not assume any specific replay behaviour from this interface alone. | ||
| * <p> | ||
| * Implementations that do not support streaming credentials (where {@link #supportsStreaming()} returns {@code false}) | ||
| * throw an {@link UnsupportedOperationException} by default. | ||
| * | ||
| * @param onNext consumer invoked with each new {@link RedisCredentials} value, must not be {@code null}. | ||
| * @param onError consumer invoked with errors observed while producing credentials, must not be {@code null}. | ||
| * @return a {@link Subscription} that can be used to stop receiving updates. | ||
| * @throws UnsupportedOperationException if the provider does not support streaming credentials. | ||
| */ | ||
| default Subscription subscribeToCredentials(Consumer<RedisCredentials> onNext, Consumer<Throwable> onError) { | ||
| throw new UnsupportedOperationException("Streaming credentials are not supported by this provider."); | ||
| } | ||
|
|
||
| /** | ||
| * Extension to {@link CredentialsProvider} that resolves credentials immediately without the need to defer the credential | ||
| * resolution. | ||
| */ | ||
| @FunctionalInterface | ||
| interface ImmediateCredentialsProvider extends CredentialsProvider { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. might need to move it back into |
||
|
|
||
| @Override | ||
| default CompletionStage<RedisCredentials> resolveCredentialsAsync() { | ||
| try { | ||
| RedisCredentials credentials = resolveCredentialsNow(); | ||
| if (credentials == null) { | ||
| return Futures.failed(new IllegalStateException("RedisCredentials resolved to null")); | ||
| } | ||
| return CompletableFuture.completedFuture(credentials); | ||
| } catch (Exception e) { | ||
| return Futures.failed(e); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Returns {@link RedisCredentials} that can be used to authorize a Redis connection. Each implementation of | ||
| * {@code CredentialsProvider} can choose its own strategy for loading credentials. For example, an implementation might | ||
| * load credentials from an existing key management system, or load new credentials when credentials are rotated. If an | ||
| * error occurs during the loading of credentials or credentials could not be found, a runtime exception will be raised. | ||
| * | ||
| * @return the resolved {@link RedisCredentials} that can be used to authorize a Redis connection. | ||
| */ | ||
| RedisCredentials resolveCredentialsNow(); | ||
|
|
||
| } | ||
|
|
||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this simply means breaking binary compatibility. if there are other spots we already broke it, then lets never mind.