Skip to content

Commit

Permalink
feat: introduce VertxTcpClientFactory
Browse files Browse the repository at this point in the history
  • Loading branch information
ytvnr committed Mar 7, 2024
1 parent f0b8c40 commit ce299db
Show file tree
Hide file tree
Showing 6 changed files with 624 additions and 0 deletions.
@@ -0,0 +1,112 @@
package io.gravitee.node.vertx.client.tcp;

import io.gravitee.node.api.configuration.Configuration;
import io.gravitee.node.vertx.client.ssl.KeyStore;
import io.gravitee.node.vertx.client.ssl.SslOptions;
import io.gravitee.node.vertx.client.ssl.TrustStore;
import io.gravitee.node.vertx.proxy.VertxProxyOptionsUtils;
import io.vertx.core.net.NetClientOptions;
import io.vertx.core.net.OpenSSLEngineOptions;
import io.vertx.core.net.ProxyOptions;
import io.vertx.core.net.ProxyType;
import io.vertx.rxjava3.core.Vertx;
import io.vertx.rxjava3.core.net.NetClient;
import java.util.concurrent.TimeUnit;
import lombok.Builder;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Builder
public class VertxTcpClientFactory {

protected static final String TCP_SSL_OPENSSL_CONFIGURATION = "tcp.ssl.openssl";

@NonNull
private final Vertx vertx;

@NonNull
private final Configuration nodeConfiguration;

private final VertxTcpTarget tcpTarget;
private VertxTcpClientOptions tcpOptions;
private SslOptions sslOptions;
private VertxTcpProxyOptions proxyOptions;

public NetClient createTcpClient() {
if (tcpOptions == null) {
tcpOptions = new VertxTcpClientOptions();
}

return vertx.createNetClient(createNetClientOptions());
}

private NetClientOptions createNetClientOptions() {
var clientOptions = new NetClientOptions().setMetricsName("tcp-client");
clientOptions
.setConnectTimeout(tcpOptions.getConnectTimeout())
.setReconnectAttempts(tcpOptions.getReconnectAttempts())
.setReconnectInterval(tcpOptions.getReconnectInterval())
.setIdleTimeout(tcpOptions.getIdleTimeout())
.setIdleTimeoutUnit(TimeUnit.MILLISECONDS)
.setReadIdleTimeout(tcpOptions.getIdleTimeout())
.setWriteIdleTimeout(tcpOptions.getIdleTimeout());

configureSsl(clientOptions);
configureTcpProxy(clientOptions);

return clientOptions;
}

private void configureTcpProxy(NetClientOptions clientOptions) {
if (proxyOptions != null && proxyOptions.isEnabled()) {
if (proxyOptions.isUseSystemProxy()) {
setSystemProxy(clientOptions);
} else {
ProxyOptions newProxyOptions = new ProxyOptions();
newProxyOptions.setHost(proxyOptions.getHost());
newProxyOptions.setPort(proxyOptions.getPort());
newProxyOptions.setUsername(proxyOptions.getUsername());
newProxyOptions.setPassword(proxyOptions.getPassword());
newProxyOptions.setType(ProxyType.valueOf(this.proxyOptions.getType().name()));
clientOptions.setProxyOptions(newProxyOptions);
}
}
}

private void setSystemProxy(NetClientOptions clientOptions) {
try {
clientOptions.setProxyOptions(VertxProxyOptionsUtils.buildProxyOptions(nodeConfiguration));
} catch (Exception e) {
log.warn(
"TcpClient (target[{}]) requires a system proxy to be defined but some configurations are missing or not well defined: {}",
tcpTarget,
e.getMessage()
);
log.warn("Ignoring system proxy");
}
}

private void configureSsl(final NetClientOptions clientOptions) {
clientOptions.setSsl(tcpTarget.isSecured());
if (sslOptions != null) {
if (Boolean.TRUE.equals(nodeConfiguration.getProperty(TCP_SSL_OPENSSL_CONFIGURATION, Boolean.class, false))) {
clientOptions.setSslEngineOptions(new OpenSSLEngineOptions());
}

clientOptions.setTrustAll(sslOptions.isTrustAll());

try {
if (!sslOptions.isTrustAll()) {
// Client truststore configuration (trust server certificate).
sslOptions.trustStore().flatMap(TrustStore::trustOptions).ifPresent(clientOptions::setTrustOptions);
}

// Client keystore configuration (client certificate for mtls).
sslOptions.keyStore().flatMap(KeyStore::keyCertOptions).ifPresent(clientOptions::setKeyCertOptions);
} catch (KeyStore.KeyStoreCertOptionsException | TrustStore.TrustOptionsException e) {
throw new IllegalArgumentException(e.getMessage() + " for " + tcpTarget);
}
}
}
}
@@ -0,0 +1,25 @@
package io.gravitee.node.vertx.client.tcp;

import lombok.Data;

/**
* @author Yann TAVERNIER (yann.tavernier at graviteesource.com)
* @author GraviteeSource Team
*/
@Data
public class VertxTcpClientOptions {

public static final int DEFAULT_IDLE_TIMEOUT = 0;
public static final int DEFAULT_READ_IDLE_TIMEOUT = 0;
public static final int DEFAULT_WRITE_IDLE_TIMEOUT = 0;
public static final int DEFAULT_CONNECT_TIMEOUT = 3000;
public static final int DEFAULT_RECONNECT_ATTEMPTS = 5;
public static final int DEFAULT_RECONNECT_INTERVAL = 1000;

int connectTimeout = DEFAULT_CONNECT_TIMEOUT;
private int reconnectAttempts = DEFAULT_RECONNECT_ATTEMPTS;
private int reconnectInterval = DEFAULT_RECONNECT_INTERVAL;
private int idleTimeout = DEFAULT_IDLE_TIMEOUT;
private int readIdleTimeout = DEFAULT_READ_IDLE_TIMEOUT;
private int writeIdleTimeout = DEFAULT_WRITE_IDLE_TIMEOUT;
}
@@ -0,0 +1,38 @@
package io.gravitee.node.vertx.client.tcp;

import java.io.Serial;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

/**
* @author Yann TAVERNIER (yann.tavernier at graviteesource.com)
* @author GraviteeSource Team
*/
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class VertxTcpProxyOptions implements Serializable {

@Serial
private static final long serialVersionUID = 6710746676968205250L;

private boolean enabled;

private boolean useSystemProxy;

private String host;

private int port;

private String username;

private String password;

private VertxTcpProxyType type = VertxTcpProxyType.SOCKS5;
}
@@ -0,0 +1,10 @@
package io.gravitee.node.vertx.client.tcp;

/**
* @author Yann TAVERNIER (yann.tavernier at graviteesource.com)
* @author GraviteeSource Team
*/
public enum VertxTcpProxyType {
SOCKS4,
SOCKS5,
}
@@ -0,0 +1,24 @@
package io.gravitee.node.vertx.client.tcp;

import lombok.Builder;
import lombok.Data;

/**
* @author Benoit BORDIGONI (benoit.bordigoni at graviteesource.com)
* @author GraviteeSource Team
*/
@Data
@Builder
public class VertxTcpTarget {

private String host;
private int port;

@Builder.Default
private boolean secured = false;

@Override
public String toString() {
return host + ":" + port;
}
}

0 comments on commit ce299db

Please sign in to comment.