com.github.lontime.exthttp.configuration.OptionResolver Maven / Gradle / Ivy
package com.github.lontime.exthttp.configuration;
import java.nio.charset.Charset;
import java.nio.file.Paths;
import java.time.Duration;
import java.util.List;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import com.github.lontime.base.commonj.utils.CollectionHelper;
import com.github.lontime.base.commonj.utils.StringHelper;
import com.github.lontime.extconfig.ConfigHelper;
import com.github.lontime.exthttp.common.ClientCookieDecoderEnum;
import com.github.lontime.exthttp.common.ClientCookieEncoderEnum;
import com.github.lontime.exthttp.common.ConfigKeys;
import com.github.lontime.shaded.com.google.common.base.Splitter;
import com.github.lontime.shaded.com.google.common.base.Suppliers;
import com.github.lontime.shaded.io.helidon.config.Config;
import io.netty.handler.codec.http.cookie.Cookie;
import io.netty.handler.codec.http.cookie.CookieHeaderNames;
import io.netty.handler.codec.http.cookie.DefaultCookie;
import io.netty.handler.logging.LogLevel;
import reactor.netty.http.HttpProtocol;
import reactor.netty.http.server.ProxyProtocolSupportType;
import reactor.netty.transport.ProxyProvider;
import reactor.netty.transport.logging.AdvancedByteBufFormat;
/**
* OptionResolver.
*
* @author lontime
* @since 1.0
*/
public class OptionResolver {
public static final String FILE_NAME = "http";
//------------------singleton------------------
private static Supplier supplier = Suppliers.memoize(OptionResolver::new);
public static OptionResolver getInstance() {
return supplier.get();
}
//------------------singleton------------------
private final Options options;
public OptionResolver() {
this.options = ConfigHelper.resolve(FILE_NAME)
.as(new Mapper()).orElse(new Options());
}
public ClientOption getClientOption(String name) {
return options.getClients().stream().filter(s -> s.getName().equals(name)).findFirst()
.orElse(ClientOption.DEFAULT);
}
public List getServerOptions() {
return options.getServers();
}
public ConnectionOption getConnectionOption(String name) {
return options.getConnections().stream().filter(s -> s.getName().equals(name))
.findFirst().orElse(new ConnectionOption(name));
}
static class Mapper implements Function {
@Override
public Options apply(Config config) {
final Options opts = new Options();
config.get("connections").asList(new ConnectionMapper()).ifPresent(opts::setConnections);
config.get("clients").asList(new ClientMapper()).ifPresent(opts::setClients);
config.get("servers").asList(new ServerMapper()).ifPresent(opts::setServers);
return opts;
}
}
static class ServerMapper implements Function {
@Override
public ServerOption apply(Config config) {
final ServerOption opts = new ServerOption();
opts.setName(config.name());
config.get("protocols").asString().map(s -> Splitter.on(",").trimResults().omitEmptyStrings()
.splitToStream(s).map(s1 -> HttpProtocol.valueOf(s1)).collect(Collectors.toList()))
.filter(CollectionHelper::isNotEmpty).ifPresent(opts::setProtocols);
config.get("host").asString().ifPresent(opts::setHost);
config.get("port").asInt().ifPresent(opts::setPort);
config.get("bindTimeout").asString().as(String::toUpperCase).as(Duration::parse)
.ifPresent(opts::setBindTimeout);
config.get("disposeTimeout").asString().as(String::toUpperCase).as(Duration::parse)
.ifPresent(opts::setDisposeTimeout);
config.get("enableCompress").asBoolean().ifPresent(opts::setEnableCompress);
config.get("compressSize").asInt().ifPresent(opts::setCompressSize);
config.get("idleTimeout").asString().as(String::toUpperCase).as(Duration::parse)
.ifPresent(opts::setIdleTimeout);
config.get("maxKeepAliveRequests").asInt().ifPresent(opts::setMaxKeepAliveRequests);
config.get("noSSL").asBoolean().ifPresent(opts::setNoSSL);
config.get("warmup").asBoolean().ifPresent(opts::setWarmup);
config.get("wiretapEnabled").asBoolean().ifPresent(opts::setWiretapEnabled);
config.get("wiretapSpec").as(new WiretapSpecMapper()).ifPresent(opts::setWiretapSpec);
config.get("requestDecoder").as(s -> requestDecoder(s)).ifPresent(opts::setRequestDecoder);
config.get("http11Certificate").as(s -> certificateSpec(s)).ifPresent(opts::setHttp11Certificate);
config.get("http2Certificate").as(s -> certificateSpec(s)).ifPresent(opts::setHttp2Certificate);
config.get("accessLog").asBoolean().ifPresent(opts::setAccessLog);
config.get("channelOptions").detach().asMap().ifPresent(m -> opts.setChannelOptions(ConfigKeys.resolve(m)));
config.get("epollChannelOptions").detach().asMap().ifPresent(m -> opts.setEpollChannelOptions(ConfigKeys.resolve(m)));
config.get("nioChannelOptions").detach().asMap().ifPresent(m -> opts.setNioChannelOptions(ConfigKeys.resolve(m)));
config.get("proxyType").asString().as(String::toUpperCase).as(ProxyProtocolSupportType::valueOf)
.ifPresent(opts::setProxyType);
config.get("attrs").detach().asMap().ifPresent(m -> opts.setAttrs(ConfigKeys.resolve(m, false)));
config.get("autoStart").asBoolean().ifPresent(opts::setAutoStart);
return opts;
}
private ServerOption.RequestDecoder requestDecoder(Config config) {
final ServerOption.RequestDecoder opts = new ServerOption.RequestDecoder();
config.get("initialBufferSize").asInt().ifPresent(opts::setInitialBufferSize);
config.get("maxChunkSize").asInt().ifPresent(opts::setMaxChunkSize);
config.get("maxHeaderSize").asInt().ifPresent(opts::setMaxHeaderSize);
config.get("maxInitialLineLength").asInt().ifPresent(opts::setMaxInitialLineLength);
config.get("allowDuplicateContentLengths").asBoolean().ifPresent(opts::setAllowDuplicateContentLengths);
config.get("validateHeaders").asBoolean().ifPresent(opts::setValidateHeaders);
config.get("h2cMaxContentLength").asInt().ifPresent(opts::setH2cMaxContentLength);
return opts;
}
private CertificateSpec certificateSpec(Config config) {
final CertificateSpec spec = new CertificateSpec();
config.get("keyCertChainFile").asString().map(s -> Paths.get(s).toFile()).ifPresent(spec::setKeyCertChainFile);
config.get("keyFile").asString().map(s -> Paths.get(s).toFile()).ifPresent(spec::setKeyFile);
config.get("keyPassword").asString().ifPresent(spec::setKeyPassword);
config.get("testing").asBoolean().ifPresent(spec::setTesting);
return spec;
}
}
static class ConnectionMapper implements Function {
@Override
public ConnectionOption apply(Config config) {
final ConnectionOption opts = new ConnectionOption();
opts.setName(config.name());
config.get("pool").as(c -> pool(c)).ifPresent(opts::setPool);
return opts;
}
private ConnectionOption.Pool pool(Config config) {
final ConnectionOption.Pool opts = new ConnectionOption.Pool();
config.get("name").asString().ifPresent(opts::setName);
config.get("maxConnections").asInt().ifPresent(opts::setMaxConnections);
config.get("pendingAcquireMaxCount").asInt().ifPresent(opts::setPendingAcquireMaxCount);
config.get("pendingAcquireTimeout").asString().as(String::toUpperCase).as(Duration::parse)
.ifPresent(opts::setPendingAcquireTimeout);
config.get("maxIdleTime").asString().as(String::toUpperCase).as(Duration::parse)
.ifPresent(opts::setMaxIdleTime);
config.get("maxLifeTime").asString().as(String::toUpperCase).as(Duration::parse)
.ifPresent(opts::setMaxLifeTime);
config.get("leasingStrategy").asString().ifPresent(opts::setLeasingStrategy);
config.get("permitsSamplingRate").asDouble().ifPresent(opts::setPermitsSamplingRate);
config.get("evictionInterval").asString().as(String::toUpperCase).as(Duration::parse)
.ifPresent(opts::setEvictionInterval);
config.get("disposeTimeout").asString().as(String::toUpperCase).as(Duration::parse)
.ifPresent(opts::setDisposeTimeout);
config.get("inactivePoolDisposeInterval").asString().as(String::toUpperCase).as(Duration::parse)
.ifPresent(opts::setInactivePoolDisposeInterval);
config.get("poolInactivity").asString().as(String::toUpperCase).as(Duration::parse)
.ifPresent(opts::setPoolInactivity);
return opts;
}
}
static class ClientMapper implements Function {
@Override
public ClientOption apply(Config config) {
final ClientOption opts = new ClientOption();
config.get("name").asString().ifPresent(opts::setName);
config.get("connectionName").asString().ifPresent(opts::setConnectionName);
config.get("protocols").asString().map(s -> Splitter.on(",").trimResults().omitEmptyStrings()
.splitToStream(s).map(s1 -> HttpProtocol.valueOf(s1)).collect(Collectors.toList()))
.filter(CollectionHelper::isNotEmpty).ifPresent(opts::setProtocols);
config.get("host").asString().ifPresent(opts::setHost);
config.get("port").asInt().ifPresent(opts::setPort);
config.get("baseUrl").asString().ifPresent(opts::setBaseUrl);
config.get("keepAlive").asBoolean().ifPresent(opts::setKeepAlive);
config.get("headers").detach().asMap().ifPresent(m -> opts.setHeaders(ConfigKeys.resolve(m, false)));
// config.get("headers").detach().asMap().ifPresent(opts::setHeaders);
config.get("cookies").asList(s -> cookie(s)).ifPresent(opts::setCookies);
config.get("cookieEncoder").asString().as(String::toUpperCase).as(ClientCookieEncoderEnum::valueOf)
.ifPresent(opts::setCookieEncoder);
config.get("cookieDecoder").asString().as(String::toUpperCase).as(ClientCookieDecoderEnum::valueOf)
.ifPresent(opts::setCookieDecoder);
config.get("compress").asBoolean().ifPresent(opts::setCompress);
config.get("disableRetry").asBoolean().ifPresent(opts::setDisableRetry);
config.get("responseDecoder").as(s -> responseDecoder(s)).ifPresent(opts::setResponseDecoder);
config.get("wiretapEnabled").asBoolean().ifPresent(opts::setWiretapEnabled);
config.get("wiretapSpec").as(new WiretapSpecMapper()).ifPresent(opts::setWiretapSpec);
config.get("secure").asBoolean().ifPresent(opts::setSecure);
config.get("http11Secure").asBoolean().ifPresent(opts::setHttp11Secure);
config.get("http2Secure").asBoolean().ifPresent(opts::setHttp2Secure);
config.get("noSSL").asBoolean().ifPresent(opts::setNoSSL);
config.get("noProxy").asBoolean().ifPresent(opts::setNoProxy);
config.get("warmup").asBoolean().ifPresent(opts::setWarmup);
config.get("followRedirect").asBoolean().ifPresent(opts::setFollowRedirect);
config.get("redirect").as(s -> redirect(s)).ifPresent(opts::setRedirect);
config.get("channelOptions").detach().asMap().ifPresent(m -> opts.setChannelOptions(ConfigKeys.resolve(m)));
config.get("epollChannelOptions").detach().asMap().ifPresent(m -> opts.setEpollChannelOptions(ConfigKeys.resolve(m)));
config.get("nioChannelOptions").detach().asMap().ifPresent(m -> opts.setNioChannelOptions(ConfigKeys.resolve(m)));
config.get("proxy").as(s -> proxy(s)).ifPresent(opts::setProxy);
config.get("attrs").detach().asMap().ifPresent(m -> opts.setAttrs(ConfigKeys.resolve(m, false)));
return opts;
}
private ClientOption.Proxy proxy(Config config) {
final ClientOption.Proxy opts = new ClientOption.Proxy();
config.get("type").asString().as(String::toUpperCase).as(ProxyProvider.Proxy::valueOf)
.ifPresent(opts::setType);
config.get("host").asString().ifPresent(opts::setHost);
config.get("port").asInt().ifPresent(opts::setPort);
return opts;
}
private ClientOption.Redirect redirect(Config config) {
final ClientOption.Redirect opts = new ClientOption.Redirect();
config.get("isFollowRedirect").asBoolean().ifPresent(opts::setIsFollowRedirect);
config.get("headers").detach().asMap().ifPresent(opts::setHeaders);
config.get("responseTimeout").asString().as(String::toUpperCase).as(Duration::parse)
.ifPresent(opts::setResponseTimeout);
config.get("cookie").as(s -> cookie(s)).ifPresent(opts::setCookie);
return opts;
}
private ClientOption.ResponseDecoder responseDecoder(Config config) {
final ClientOption.ResponseDecoder opts = new ClientOption.ResponseDecoder();
config.get("parseHttpAfterConnectRequest").asBoolean().ifPresent(opts::setParseHttpAfterConnectRequest);
config.get("initialBufferSize").asInt().ifPresent(opts::setInitialBufferSize);
config.get("maxChunkSize").asInt().ifPresent(opts::setMaxChunkSize);
config.get("maxHeaderSize").asInt().ifPresent(opts::setMaxHeaderSize);
config.get("maxInitialLineLength").asInt().ifPresent(opts::setMaxInitialLineLength);
config.get("failOnMissingResponse").asBoolean().ifPresent(opts::setFailOnMissingResponse);
config.get("allowDuplicateContentLengths").asBoolean().ifPresent(opts::setAllowDuplicateContentLengths);
config.get("validateHeaders").asBoolean().ifPresent(opts::setValidateHeaders);
config.get("h2cMaxContentLength").asInt().ifPresent(opts::setH2cMaxContentLength);
return opts;
}
private Cookie cookie(Config config) {
final String name = config.get("name").asString().orElse(null);
final String value = config.get("value").asString().orElse(null);
if (StringHelper.isEmpty(name) || StringHelper.isEmpty(value)) {
return null;
}
final DefaultCookie cookie = new DefaultCookie(name, value);
config.get("wrap").asBoolean().ifPresent(cookie::setWrap);
config.get("domain").asString().ifPresent(cookie::setDomain);
config.get("path").asString().ifPresent(cookie::setPath);
config.get("maxAge").asLong().ifPresent(cookie::setMaxAge);
config.get("secure").asBoolean().ifPresent(cookie::setSecure);
config.get("httpOnly").asBoolean().ifPresent(cookie::setHttpOnly);
config.get("sameSite").asString().as(String::toLowerCase).as(s -> StringHelper.capitalize(s))
.as(s -> CookieHeaderNames.SameSite.valueOf(s)).ifPresent(cookie::setSameSite);
return cookie;
}
}
static class WiretapSpecMapper implements Function {
@Override
public WiretapSpec apply(Config config) {
final WiretapSpec opts = new WiretapSpec();
config.get("category").asString().ifPresent(opts::setCategory);
config.get("level").asString().as(String::toUpperCase).as(LogLevel::valueOf).ifPresent(opts::setLevel);
config.get("format").asString().as(String::toUpperCase).as(s -> s.replace('-', '_'))
.as(AdvancedByteBufFormat::valueOf).ifPresent(opts::setFormat);
config.get("charset").asString().map(s -> Charset.forName(s)).ifPresent(opts::setCharset);
return opts;
}
}
}