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

feat: initialize the OpenGeminiReactorClient #12

Merged
merged 1 commit into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -22,4 +22,10 @@ public class TlsConfig {
public String trustStorePassword;

public boolean tlsVerificationDisabled;

public boolean tlsHostnameVerificationDisabled;

public String[] tlsVersions;

public String[] tlsCipherSuites;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,48 @@
package io.opengemini.client.reactor;

import io.netty.handler.ssl.SslContext;
import io.opengemini.client.api.Address;
import io.opengemini.client.api.TlsConfig;
import reactor.netty.http.client.HttpClient;
import reactor.netty.http.client.HttpClientSecurityUtils;

import java.util.ArrayList;
import java.util.List;

public class OpenGeminiReactorClient {
private final HttpClient client;

private final List<String> serverUrls = new ArrayList<>();

public OpenGeminiReactorClient(Configuration conf) {
HttpClient client = HttpClient.create();

String httpPrefix;
if (conf.isTlsEnabled()) {
TlsConfig tlsConfig = conf.getTlsConfig();
client = client.secure(spec -> {
SslContext context = SslContextUtil.buildFromJks(
tlsConfig.getKeyStorePath(),
tlsConfig.getKeyStorePassword(),
tlsConfig.getTrustStorePath(),
tlsConfig.getTrustStorePassword(),
tlsConfig.isTlsVerificationDisabled(),
tlsConfig.getTlsVersions(),
tlsConfig.getTlsCipherSuites());
if (tlsConfig.isTlsHostnameVerificationDisabled()) {
spec.sslContext(context)
.handlerConfigurator(HttpClientSecurityUtils.HOSTNAME_VERIFICATION_CONFIGURER);
} else {
spec.sslContext(context);
}
});
httpPrefix = "https://";
} else {
httpPrefix = "http://";
}
for (Address address : conf.getAddresses()) {
this.serverUrls.add(httpPrefix + address.getHost() + ":" + address.getPort());
}
this.client = client;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package io.opengemini.client.reactor;

import io.opengemini.client.api.AuthConfig;
import io.opengemini.client.api.AuthType;
import io.opengemini.client.api.BatchConfig;
import io.opengemini.client.api.OpenGeminiException;
import io.opengemini.client.api.OpengeminiConst;

public class OpenGeminiReactorClientFactory {
public static OpenGeminiReactorClient create(Configuration configuration) throws OpenGeminiException {
if (configuration.getAddresses() == null || configuration.getAddresses().isEmpty()) {
throw new OpenGeminiException("at least one address is required");
}
AuthConfig authConfig = configuration.getAuthConfig();
if (authConfig != null) {
if (authConfig.getAuthType() == AuthType.TOKEN && (authConfig.getToken() == null
|| authConfig.getToken().isEmpty())) {
throw new OpenGeminiException("invalid auth config due to empty token");
}
if (authConfig.getAuthType() == AuthType.PASSWORD) {
if (authConfig.getUsername() == null || authConfig.getUsername().isEmpty()) {
throw new OpenGeminiException("invalid auth config due to empty username");
}
if (authConfig.getPassword() == null || authConfig.getPassword().isEmpty()) {
throw new OpenGeminiException("invalid auth config due to empty password");
}
}
}
BatchConfig batchConfig = configuration.getBatchConfig();
if (batchConfig != null) {
if (batchConfig.getBatchInterval() <= 0) {
throw new OpenGeminiException("batch enabled, batch interval must be great than 0");
}
if (batchConfig.getBatchSize() <= 0) {
throw new OpenGeminiException("batch enabled, batch size must be great than 0");
}
}
if (configuration.getTimeout() == null || configuration.getTimeout().isNegative()) {
configuration.setTimeout(OpengeminiConst.DEFAULT_TIMEOUT);
}
if (configuration.getConnectTimeout() == null || configuration.getConnectTimeout().isNegative()) {
configuration.setConnectTimeout(OpengeminiConst.DEFAULT_CONNECT_TIMEOUT);
}
return new OpenGeminiReactorClient(configuration);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package io.opengemini.client.reactor;

import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManagerFactory;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.util.Arrays;

public class SslContextUtil {
public static SslContext buildFromJks(
String keyStorePath, String keyStorePassword,
String trustStorePath, String trustStorePassword,
boolean disableSslVerify, String[] tlsProtocols, String[] tlsCiphers) {

try {
SslContextBuilder sslContextBuilder = SslContextBuilder.forClient();

if (keyStorePath != null && keyStorePassword != null) {
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
try (FileInputStream keyStoreInputStream = new FileInputStream(keyStorePath)) {
keyStore.load(keyStoreInputStream, keyStorePassword.toCharArray());
}
String defaultKeyAlgorithm = KeyManagerFactory.getDefaultAlgorithm();
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(defaultKeyAlgorithm);
keyManagerFactory.init(keyStore, keyStorePassword.toCharArray());
sslContextBuilder.keyManager(keyManagerFactory);
}

if (disableSslVerify) {
sslContextBuilder.trustManager(InsecureTrustManagerFactory.INSTANCE);
} else if (trustStorePath != null && trustStorePassword != null) {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
try (FileInputStream trustStoreInputStream = new FileInputStream(trustStorePath)) {
trustStore.load(trustStoreInputStream, trustStorePassword.toCharArray());
}
String defaultTrustAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(defaultTrustAlgorithm);
trustManagerFactory.init(trustStore);
sslContextBuilder.trustManager(trustManagerFactory);
}

if (tlsProtocols != null) {
sslContextBuilder.protocols(tlsProtocols);
}

if (tlsCiphers != null) {
sslContextBuilder.ciphers(Arrays.asList(tlsCiphers));
}

return sslContextBuilder.build();
} catch (Exception e) {
throw new RuntimeException("Error setting up SSL configuration", e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package io.opengemini.client.reactor;

import io.opengemini.client.api.Address;
import io.opengemini.client.api.AuthConfig;
import io.opengemini.client.api.AuthType;
import io.opengemini.client.api.BatchConfig;
import io.opengemini.client.api.OpenGeminiException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.List;

class OpenGeminiReactorClientFactoryTest {

private static Configuration configuration;
private static AuthConfig authConfig;
private static BatchConfig batchConfig;

@BeforeAll
public static void setUp() {
configuration = new Configuration();
authConfig = new AuthConfig();
batchConfig = new BatchConfig();
}

@Test
public void testGetClientWithNullAddresses() {
configuration.setAddresses(null);
Throwable actualException = Assertions.assertThrows(OpenGeminiException.class, () -> {
OpenGeminiReactorClientFactory.create(configuration);
});
Assertions.assertEquals("at least one address is required", actualException.getMessage());
}

@Test
public void testGetClientWithEmptyAddresses() {
configuration.setAddresses(new ArrayList<>());

Throwable actualException = Assertions.assertThrows(OpenGeminiException.class, () -> {
OpenGeminiReactorClientFactory.create(configuration);
});
Assertions.assertEquals("at least one address is required", actualException.getMessage());
}

@Test
public void testGetClientWithEmptyToken() {
configuration.setAddresses(List.of(new Address()));
authConfig.setAuthType(AuthType.TOKEN);
authConfig.setToken("");
configuration.setAuthConfig(authConfig);

Throwable actualException = Assertions.assertThrows(OpenGeminiException.class, () -> {
OpenGeminiReactorClientFactory.create(configuration);
});
Assertions.assertEquals("invalid auth config due to empty token", actualException.getMessage());
}

@Test
public void testGetClientWithEmptyUserName() {
configuration.setAddresses(List.of(new Address()));
authConfig.setAuthType(AuthType.PASSWORD);
authConfig.setPassword("pass");
authConfig.setUsername("");
configuration.setAuthConfig(authConfig);

Throwable actualException = Assertions.assertThrows(OpenGeminiException.class, () -> {
OpenGeminiReactorClientFactory.create(configuration);
});
Assertions.assertEquals("invalid auth config due to empty username", actualException.getMessage());
}

@Test
public void testGetClientWithNullPassword() {
configuration.setAddresses(List.of(new Address()));
authConfig.setAuthType(AuthType.PASSWORD);
authConfig.setPassword(null);
authConfig.setUsername("user");
configuration.setAuthConfig(authConfig);

Throwable actualException = Assertions.assertThrows(OpenGeminiException.class, () -> {
OpenGeminiReactorClientFactory.create(configuration);
});
Assertions.assertEquals("invalid auth config due to empty password", actualException.getMessage());
}

@Test
public void testGetClientWithInvalidBatchInterval() {
configuration.setAddresses(List.of(new Address()));
authConfig.setAuthType(null);
batchConfig.setBatchInterval(-1);
configuration.setBatchConfig(batchConfig);

Throwable actualException = Assertions.assertThrows(OpenGeminiException.class, () -> {
OpenGeminiReactorClientFactory.create(configuration);
});
Assertions.assertEquals("batch enabled, batch interval must be great than 0", actualException.getMessage());
}

@Test
public void testGetClientWithInvalidBatchSize() {
configuration.setAddresses(List.of(new Address()));
authConfig.setAuthType(null);
batchConfig.setBatchInterval(1);
batchConfig.setBatchSize(-1);
configuration.setBatchConfig(batchConfig);

Throwable actualException = Assertions.assertThrows(OpenGeminiException.class, () -> {
OpenGeminiReactorClientFactory.create(configuration);
});
Assertions.assertEquals("batch enabled, batch size must be great than 0", actualException.getMessage());
}
}
Loading