Skip to content
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

Poc/xds filter v2 #36

Draft
wants to merge 34 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
05a7ca1
poc
jrhee17 Dec 18, 2024
daf6898
EndpointGroup is not nullable
jrhee17 Dec 19, 2024
3bed526
lint
jrhee17 Dec 19, 2024
27386f0
updated api
jrhee17 Dec 19, 2024
78044de
cleanup
jrhee17 Dec 19, 2024
812d517
add clientOption
jrhee17 Dec 19, 2024
a6f616b
add public APIs
jrhee17 Dec 19, 2024
cd7b2ba
rename tail
jrhee17 Dec 19, 2024
970a83e
add factory validation
jrhee17 Dec 19, 2024
ef24cc1
version where tests pass
jrhee17 Dec 20, 2024
54736e1
working version
jrhee17 Dec 20, 2024
7014db8
add factory methods
jrhee17 Dec 20, 2024
396e4da
add undefined uri handling
jrhee17 Dec 23, 2024
87464b2
support for websocket
jrhee17 Dec 23, 2024
264266d
save progress
jrhee17 Dec 23, 2024
23bb1da
default values are overridden
jrhee17 Dec 24, 2024
aedc2ad
fix build failure
jrhee17 Dec 24, 2024
4c1d21e
add tests for rest
jrhee17 Dec 24, 2024
a4cda11
adde exception to signature
jrhee17 Dec 24, 2024
ee04280
revert websocket changes
jrhee17 Dec 24, 2024
b308b01
cleanup
jrhee17 Dec 24, 2024
6d3f920
limit visibility of reqTarget
jrhee17 Dec 24, 2024
3784ae9
working version
jrhee17 Dec 24, 2024
9718904
use uri
jrhee17 Dec 26, 2024
2aad561
add tests for grpc
jrhee17 Dec 26, 2024
8851e0a
grpc tests
jrhee17 Dec 26, 2024
009d3db
add test for retrofit
jrhee17 Dec 26, 2024
2ea7a17
add params builder
jrhee17 Dec 26, 2024
2d30639
more consistent uris
jrhee17 Dec 27, 2024
933063e
revert undefined uri change
jrhee17 Dec 27, 2024
fab5156
use builder
jrhee17 Dec 27, 2024
4f5d916
rename
jrhee17 Dec 27, 2024
b7bc7ef
add thrift tests
jrhee17 Dec 27, 2024
450f843
add test for undefined protocol
jrhee17 Dec 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public class AbstractClientOptionsBuilder {

private final Map<ClientOption<?>, ClientOptionValue<?>> options = new LinkedHashMap<>();
private final ClientDecorationBuilder decoration = ClientDecoration.builder();
private final ClientPreprocessorsBuilder clientPreprocessorsBuilder = new ClientPreprocessorsBuilder();
private final HttpHeadersBuilder headers = HttpHeaders.builder();

@Nullable
Expand Down Expand Up @@ -127,6 +128,8 @@ public <T> AbstractClientOptionsBuilder option(ClientOptionValue<T> optionValue)
} else if (opt == ClientOptions.HEADERS) {
final HttpHeaders h = (HttpHeaders) optionValue.value();
setHeaders(h);
} else if (opt == ClientOptions.PREPROCESSORS) {
clientPreprocessorsBuilder.add((ClientPreprocessors) optionValue.value());
} else {
options.put(opt, optionValue);
}
Expand Down Expand Up @@ -520,6 +523,26 @@ public AbstractClientOptionsBuilder responseTimeoutMode(ResponseTimeoutMode resp
requireNonNull(responseTimeoutMode, "responseTimeoutMode"));
}

/**
* Adds the specified HTTP-level {@code preprocessor}.
*
* @param preprocessor the {@link HttpPreprocessor} that preprocesses an invocation
*/
public AbstractClientOptionsBuilder preprocessor(HttpPreprocessor preprocessor) {
clientPreprocessorsBuilder.add(preprocessor);
return this;
}

/**
* Adds the specified RPC-level {@code rpcPreprocessor}.
*
* @param rpcPreprocessor the {@link RpcPreprocessor} that preprocesses an invocation
*/
public AbstractClientOptionsBuilder rpcPreprocessor(RpcPreprocessor rpcPreprocessor) {
clientPreprocessorsBuilder.addRpc(rpcPreprocessor);
return this;
}

/**
* Builds {@link ClientOptions} with the given options and the
* {@linkplain ClientOptions#of() default options}.
Expand All @@ -538,6 +561,7 @@ protected final ClientOptions buildOptions(@Nullable ClientOptions baseOptions)
ImmutableList.builder();
additionalValues.addAll(optVals);
additionalValues.add(ClientOptions.DECORATION.newValue(decoration.build()));
additionalValues.add(ClientOptions.PREPROCESSORS.newValue(clientPreprocessorsBuilder.build()));
additionalValues.add(ClientOptions.HEADERS.newValue(headers.build()));
additionalValues.add(ClientOptions.CONTEXT_HOOK.newValue(contextHook));
if (contextCustomizer != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import static com.google.common.base.Preconditions.checkArgument;
import static com.linecorp.armeria.common.SessionProtocol.httpAndHttpsValues;
import static com.linecorp.armeria.internal.client.ClientBuilderParamsUtil.preprocessorToUri;
import static com.linecorp.armeria.internal.client.ClientUtil.UNDEFINED_URI;
import static java.util.Objects.requireNonNull;

Expand All @@ -28,6 +29,7 @@
import com.linecorp.armeria.common.SerializationFormat;
import com.linecorp.armeria.common.SessionProtocol;
import com.linecorp.armeria.common.annotation.Nullable;
import com.linecorp.armeria.internal.client.ClientBuilderParamsUtil;

/**
* A skeletal builder implementation for {@link WebClient}.
Expand All @@ -47,7 +49,7 @@ public abstract class AbstractWebClientBuilder extends AbstractClientOptionsBuil
* Creates a new instance.
*/
protected AbstractWebClientBuilder() {
this(UNDEFINED_URI, null, null, null);
this(UNDEFINED_URI, null, null, null, DefaultWebClientPreprocessor.INSTANCE);
}

/**
Expand All @@ -69,25 +71,42 @@ protected AbstractWebClientBuilder(URI uri) {
protected AbstractWebClientBuilder(SessionProtocol sessionProtocol, EndpointGroup endpointGroup,
@Nullable String path) {
this(null, validateSessionProtocol(sessionProtocol),
requireNonNull(endpointGroup, "endpointGroup"), path);
requireNonNull(endpointGroup, "endpointGroup"), path, null);
}

/**
* TBU.
*/
protected AbstractWebClientBuilder(HttpPreprocessor httpPreprocessor, @Nullable String path) {
this(preprocessorToUri(httpPreprocessor, path), null, null, null, httpPreprocessor);
}

/**
* Creates a new instance.
*/
protected AbstractWebClientBuilder(@Nullable URI uri, @Nullable Scheme scheme,
@Nullable EndpointGroup endpointGroup, @Nullable String path) {
this(uri, scheme, endpointGroup, path, maybeDefaultPreprocessor(uri));
}

private AbstractWebClientBuilder(@Nullable URI uri, @Nullable Scheme scheme,
@Nullable EndpointGroup endpointGroup, @Nullable String path,
@Nullable HttpPreprocessor httpPreprocessor) {
assert uri != null || (scheme != null && endpointGroup != null);
assert path == null || uri == null;
this.uri = uri;
this.scheme = scheme;
this.endpointGroup = endpointGroup;
this.path = validatePath(path);

if (httpPreprocessor != null) {
preprocessor(httpPreprocessor);
}
}

private static URI validateUri(URI uri) {
requireNonNull(uri, "uri");
if (Clients.isUndefinedUri(uri)) {
if (ClientBuilderParamsUtil.isInternalUri(uri)) {
return uri;
}
final String givenScheme = requireNonNull(uri, "uri").getScheme();
Expand Down Expand Up @@ -129,6 +148,21 @@ private static String validatePath(@Nullable String path) {
return path;
}

@Nullable
private static HttpPreprocessor maybeDefaultPreprocessor(@Nullable URI uri) {
if (uri != null && Clients.isUndefinedUri(uri)) {
return DefaultWebClientPreprocessor.INSTANCE;
}
return null;
}

private static URI maybeResolvePath(@Nullable String path) {
if (path == null) {
return UNDEFINED_URI;
}
return UNDEFINED_URI.resolve(path);
}

/**
* Returns a newly-created web client based on the properties of this builder.
*
Expand Down Expand Up @@ -184,4 +218,10 @@ public AbstractWebClientBuilder rpcDecorator(Function<? super RpcClient, ? exten
public AbstractWebClientBuilder rpcDecorator(DecoratingRpcClientFunction decorator) {
throw new UnsupportedOperationException("RPC decorator cannot be added to the web client builder.");
}

@Deprecated
@Override
public AbstractClientOptionsBuilder rpcPreprocessor(RpcPreprocessor rpcPreprocessor) {
throw new UnsupportedOperationException("RPC preprocessor cannot be added to the web client builder.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,16 @@
import com.linecorp.armeria.client.redirect.RedirectConfig;
import com.linecorp.armeria.common.RequestId;
import com.linecorp.armeria.common.Scheme;
import com.linecorp.armeria.common.SerializationFormat;
import com.linecorp.armeria.common.SessionProtocol;
import com.linecorp.armeria.common.SuccessFunction;
import com.linecorp.armeria.common.annotation.Nullable;
import com.linecorp.armeria.common.annotation.UnstableApi;
import com.linecorp.armeria.common.auth.AuthToken;
import com.linecorp.armeria.common.auth.BasicToken;
import com.linecorp.armeria.common.auth.OAuth1aToken;
import com.linecorp.armeria.common.auth.OAuth2Token;
import com.linecorp.armeria.internal.client.ClientBuilderParamsUtil;

/**
* Creates a new client that connects to the specified {@link URI} using the builder pattern. Use the factory
Expand Down Expand Up @@ -95,6 +98,18 @@ public final class ClientBuilder extends AbstractClientOptionsBuilder {
this.scheme = scheme;
}

ClientBuilder(SerializationFormat serializationFormat,
ClientPreprocessors preprocessors, @Nullable String path) {
checkArgument(!preprocessors.isEmpty(),
"At least one preprocessor must be set in ClientPreprocessors.");
endpointGroup = null;
this.path = path;
scheme = Scheme.of(serializationFormat, SessionProtocol.UNDEFINED);
uri = ClientBuilderParamsUtil.preprocessorToUri(scheme, preprocessors, path);
preprocessors.preprocessors().forEach(this::preprocessor);
preprocessors.rpcPreprocessors().forEach(this::rpcPreprocessor);
}

/**
* Returns a newly-created client which implements the specified {@code clientType}, based on the
* properties of this builder.
Expand Down Expand Up @@ -300,4 +315,14 @@ public ClientBuilder contextHook(Supplier<? extends AutoCloseable> contextHook)
public ClientBuilder responseTimeoutMode(ResponseTimeoutMode responseTimeoutMode) {
return (ClientBuilder) super.responseTimeoutMode(responseTimeoutMode);
}

@Override
public ClientBuilder preprocessor(HttpPreprocessor decorator) {
return (ClientBuilder) super.preprocessor(decorator);
}

@Override
public ClientBuilder rpcPreprocessor(RpcPreprocessor decorator) {
return (ClientBuilder) super.rpcPreprocessor(decorator);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,11 @@ static ClientBuilderParams of(Scheme scheme, EndpointGroup endpointGroup,
* Returns the options of the client.
*/
ClientOptions options();

/**
* TBU.
*/
default ClientBuilderParamsBuilder paramsBuilder() {
return new ClientBuilderParamsBuilder(this);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
* Copyright 2024 LINE Corporation
*
* LINE Corporation licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/

package com.linecorp.armeria.client;

import static com.google.common.base.MoreObjects.firstNonNull;
import static com.linecorp.armeria.internal.client.ClientBuilderParamsUtil.nullOrEmptyToSlash;

import java.net.URI;
import java.net.URISyntaxException;

import com.linecorp.armeria.common.Scheme;
import com.linecorp.armeria.common.SerializationFormat;
import com.linecorp.armeria.common.annotation.Nullable;

/**
* TBU.
*/
public final class ClientBuilderParamsBuilder {

private final ClientBuilderParams params;

@Nullable
private SerializationFormat serializationFormat;
@Nullable
private String absolutePathRef;
@Nullable
private Class<?> type;
@Nullable
private ClientOptions options;

ClientBuilderParamsBuilder(ClientBuilderParams params) {
this.params = params;
}

/**
* TBU.
*/
public ClientBuilderParamsBuilder serializationFormat(SerializationFormat serializationFormat) {
this.serializationFormat = serializationFormat;
return this;
}

/**
* TBU.
*/
public ClientBuilderParamsBuilder absolutePathRef(String absolutePathRef) {
this.absolutePathRef = absolutePathRef;
return this;
}

/**
* TBU.
*/
public ClientBuilderParamsBuilder clientType(Class<?> type) {
this.type = type;
return this;
}

/**
* TBU.
*/
public ClientBuilderParamsBuilder options(ClientOptions options) {
this.options = options;
return this;
}

/**
* TBU.
*/
public ClientBuilderParams build() {
final Scheme scheme;
final String schemeStr;
if (serializationFormat != null) {
scheme = Scheme.of(serializationFormat, params.scheme().sessionProtocol());
if (scheme.serializationFormat() == SerializationFormat.NONE) {
schemeStr = scheme.sessionProtocol().uriText();
} else {
schemeStr = scheme.uriText();
}
} else {
scheme = params.scheme();
schemeStr = params.uri().getScheme();
}

final String path;
if (absolutePathRef != null) {
path = nullOrEmptyToSlash(absolutePathRef);
} else {
path = params.absolutePathRef();
}

final URI prevUri = params.uri();
final URI uri;
try {
uri = new URI(schemeStr, prevUri.getRawAuthority(), path,
prevUri.getRawQuery(), prevUri.getRawFragment());
} catch (URISyntaxException e) {
throw new IllegalArgumentException(e);
}
return new DefaultClientBuilderParams(scheme, params.endpointGroup(), uri.getRawPath(),
uri, firstNonNull(type, params.clientType()),
firstNonNull(options, params.options()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright 2024 LINE Corporation
*
* LINE Corporation licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/

package com.linecorp.armeria.client;

import com.linecorp.armeria.common.Request;
import com.linecorp.armeria.common.Response;

/**
* TBU.
*/
@FunctionalInterface
public interface ClientExecution<I extends Request, O extends Response> {

/**
* TBU.
*/
O execute(PartialClientRequestContext ctx, I req) throws Exception;
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import com.linecorp.armeria.common.util.ReleasableHolder;
import com.linecorp.armeria.common.util.ShutdownHooks;
import com.linecorp.armeria.common.util.Unwrappable;
import com.linecorp.armeria.internal.client.ClientBuilderParamsUtil;

import io.micrometer.core.instrument.MeterRegistry;
import io.netty.channel.EventLoop;
Expand Down Expand Up @@ -291,7 +292,7 @@ default ClientFactory unwrap() {
default URI validateUri(URI uri) {
requireNonNull(uri, "uri");

if (Clients.isUndefinedUri(uri)) {
if (ClientBuilderParamsUtil.isInternalUri(uri)) {
// We use a special singleton marker URI for clients that do not explicitly define a
// host or scheme at construction time.
// As this isn't created by users, we don't need to normalize it.
Expand Down
Loading