Compare commits
8 Commits
c7d2b89d82
...
0.2.0-beta
Author | SHA1 | Date | |
---|---|---|---|
8ef2d9c64e
|
|||
1510956989
|
|||
ac4f0fdd19
|
|||
37da03c719
|
|||
60bc4375cf
|
|||
725fe22b80
|
|||
ca18b63f27
|
|||
23f2a351a6
|
@@ -39,9 +39,9 @@ jobs:
|
||||
push: true
|
||||
pull: true
|
||||
tags: |
|
||||
gitea.woggioni.net/woggioni/rbcs:latest
|
||||
gitea.woggioni.net/woggioni/rbcs:${{ steps.retrieve-version.outputs.VERSION }}
|
||||
target: release
|
||||
gitea.woggioni.net/woggioni/rbcs:vanilla
|
||||
gitea.woggioni.net/woggioni/rbcs:vanilla-${{ steps.retrieve-version.outputs.VERSION }}
|
||||
target: release-vanilla
|
||||
cache-from: type=registry,ref=gitea.woggioni.net/woggioni/rbcs:buildx
|
||||
-
|
||||
name: Build rbcs memcache Docker image
|
||||
@@ -57,6 +57,20 @@ jobs:
|
||||
target: release-memcache
|
||||
cache-from: type=registry,ref=gitea.woggioni.net/woggioni/rbcs:buildx
|
||||
cache-to: type=registry,mode=max,compression=zstd,image-manifest=true,oci-mediatypes=true,ref=gitea.woggioni.net/woggioni/rbcs:buildx
|
||||
-
|
||||
name: Build rbcs memcache Docker image
|
||||
uses: docker/build-push-action@v5.3.0
|
||||
with:
|
||||
context: "docker/build/docker"
|
||||
platforms: linux/amd64
|
||||
push: true
|
||||
pull: true
|
||||
tags: |
|
||||
gitea.woggioni.net/woggioni/rbcs:latest
|
||||
gitea.woggioni.net/woggioni/rbcs:${{ steps.retrieve-version.outputs.VERSION }}
|
||||
gitea.woggioni.net/woggioni/rbcs:native
|
||||
gitea.woggioni.net/woggioni/rbcs:native-${{ steps.retrieve-version.outputs.VERSION }}
|
||||
target: release-native
|
||||
- name: Publish artifacts
|
||||
env:
|
||||
PUBLISHER_TOKEN: ${{ secrets.PUBLISHER_TOKEN }}
|
||||
|
46
README.md
46
README.md
@@ -66,11 +66,18 @@ buildCache {
|
||||
url = 'https://rbcs.example.com/'
|
||||
push = true
|
||||
allowInsecureProtocol = false
|
||||
// The credentials block is only required if you enable
|
||||
// HTTP basic authentication on RBCS
|
||||
credentials {
|
||||
username = 'build-cache-user'
|
||||
password = 'some-complicated-password'
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
alternatively you can add this to `${GRADLE_HOME}/init.gradle`
|
||||
alternatively you can add this to `${GRADLE_HOME}/init.gradle` to configure the remote cache
|
||||
at the system level
|
||||
|
||||
```groovy
|
||||
gradle.settingsEvaluated { settings ->
|
||||
@@ -79,14 +86,51 @@ gradle.settingsEvaluated { settings ->
|
||||
url = 'https://rbcs.example.com/'
|
||||
push = true
|
||||
allowInsecureProtocol = false
|
||||
// The credentials block is only required if you enable
|
||||
// HTTP basic authentication on RBCS
|
||||
credentials {
|
||||
username = 'build-cache-user'
|
||||
password = 'some-complicated-password'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
add `org.gradle.caching=true` to your `<project>/gradle.properties` or run gradle with `--build-cache`.
|
||||
|
||||
Read [Gradle documentation](https://docs.gradle.org/current/userguide/build_cache.html) for more detailed information.
|
||||
|
||||
### Using RBCS with Maven
|
||||
|
||||
1. Create an `extensions.xml` in `<project>/.mvn/extensions.xml` with the following content
|
||||
```xml
|
||||
<extensions xmlns="http://maven.apache.org/EXTENSIONS/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/EXTENSIONS/1.1.0 https://maven.apache.org/xsd/core-extensions-1.0.0.xsd">
|
||||
<extension>
|
||||
<groupId>org.apache.maven.extensions</groupId>
|
||||
<artifactId>maven-build-cache-extension</artifactId>
|
||||
<version>1.2.0</version>
|
||||
</extension>
|
||||
</extensions>
|
||||
```
|
||||
2. Copy [maven-build-cache-config.xml](https://maven.apache.org/extensions/maven-build-cache-extension/maven-build-cache-config.xml) into `<project>/.mvn/` folder
|
||||
3. Edit the `cache/configuration/remote` element
|
||||
```xml
|
||||
<remote enabled="true" id="rbcs">
|
||||
<url>https://rbcs.example.com/</url>
|
||||
</remote>
|
||||
```
|
||||
4. Run maven with
|
||||
```bash
|
||||
mvn -Dmaven.build.cache.enabled=true -Dmaven.build.cache.debugOutput=true -Dmaven.build.cache.remote.save.enabled=true package
|
||||
```
|
||||
|
||||
Alternatively you can set those properties in your `<project>/pom.xml`
|
||||
|
||||
|
||||
Read [here](https://maven.apache.org/extensions/maven-build-cache-extension/remote-cache.html)
|
||||
for more informations
|
||||
|
||||
## FAQ
|
||||
### Why should I use a build cache?
|
||||
|
@@ -14,9 +14,7 @@ allprojects { subproject ->
|
||||
if(project.currentTag.isPresent()) {
|
||||
version = project.currentTag.map { it[0] }.get()
|
||||
} else {
|
||||
version = project.gitRevision.map { gitRevision ->
|
||||
"${getProperty('rbcs.version')}.${gitRevision[0..10]}"
|
||||
}.get()
|
||||
version = "${getProperty('rbcs.version')}-SNAPSHOT"
|
||||
}
|
||||
|
||||
repositories {
|
||||
@@ -24,7 +22,6 @@ allprojects { subproject ->
|
||||
url = getProperty('gitea.maven.url')
|
||||
content {
|
||||
includeModule 'net.woggioni', 'jwo'
|
||||
includeModule 'net.woggioni', 'xmemcached'
|
||||
includeGroup 'com.lys'
|
||||
}
|
||||
}
|
||||
@@ -41,7 +38,7 @@ allprojects { subproject ->
|
||||
withSourcesJar()
|
||||
modularity.inferModulePath = true
|
||||
toolchain {
|
||||
languageVersion = JavaLanguageVersion.of(21)
|
||||
languageVersion = JavaLanguageVersion.of(23)
|
||||
vendor = JvmVendorSpec.ORACLE
|
||||
}
|
||||
}
|
||||
|
178
doc/server_configuration.md
Normal file
178
doc/server_configuration.md
Normal file
@@ -0,0 +1,178 @@
|
||||
|
||||
### RBCS server configuration file elements and attributes
|
||||
|
||||
#### Root Element: `server`
|
||||
The root element that contains all server configuration.
|
||||
|
||||
**Attributes:**
|
||||
- `path` (optional): URI path prefix for cache requests. Example: if set to "cache", requests would be made to "http://www.example.com/cache/KEY"
|
||||
|
||||
#### Child Elements
|
||||
|
||||
#### `<bind>`
|
||||
Configures server socket settings.
|
||||
|
||||
**Attributes:**
|
||||
- `host` (required): Server bind address
|
||||
- `port` (required): Server port number
|
||||
- `incoming-connections-backlog-size` (optional, default: 1024): Maximum queue length for incoming connection indications
|
||||
|
||||
#### `<connection>`
|
||||
Configures connection handling parameters.
|
||||
|
||||
**Attributes:**
|
||||
- `idle-timeout` (optional, default: PT30S): Connection timeout when no activity
|
||||
- `read-idle-timeout` (optional, default: PT60S): Connection timeout when no reads
|
||||
- `write-idle-timeout` (optional, default: PT60S): Connection timeout when no writes
|
||||
- `max-request-size` (optional, default: 0x4000000): Maximum allowed request body size
|
||||
|
||||
#### `<event-executor>`
|
||||
Configures event execution settings.
|
||||
|
||||
**Attributes:**
|
||||
- `use-virtual-threads` (optional, default: true): Whether to use virtual threads for the server handler
|
||||
|
||||
#### `<cache>`
|
||||
Defines cache storage implementation. Two types are available:
|
||||
|
||||
##### InMemory Cache
|
||||
|
||||
A simple storage backend that uses an hash map to store data in memory
|
||||
|
||||
**Attributes:**
|
||||
- `max-age` (default: P1D): Cache entry lifetime
|
||||
- `max-size` (default: 0x1000000): Maximum cache size in bytes
|
||||
- `digest` (default: MD5): Key hashing algorithm
|
||||
- `enable-compression` (default: true): Enable deflate compression
|
||||
- `compression-level` (default: -1): Compression level (-1 to 9)
|
||||
- `chunk-size` (default: 0x10000): Maximum socket write size
|
||||
|
||||
##### FileSystem Cache
|
||||
|
||||
A storage backend that stores data in a folder on the disk
|
||||
|
||||
**Attributes:**
|
||||
- `path`: Storage directory path
|
||||
- `max-age` (default: P1D): Cache entry lifetime
|
||||
- `digest` (default: MD5): Key hashing algorithm
|
||||
- `enable-compression` (default: true): Enable deflate compression
|
||||
- `compression-level` (default: -1): Compression level
|
||||
- `chunk-size` (default: 0x10000): Maximum in-memory cache value size
|
||||
|
||||
#### `<authorization>`
|
||||
Configures user and group-based access control.
|
||||
|
||||
##### `<users>`
|
||||
List of registered users.
|
||||
- Contains `<user>` elements:
|
||||
|
||||
**Attributes:**
|
||||
- `name` (required): Username
|
||||
- `password` (optional): For basic authentication
|
||||
- Can contain an `anonymous` element to allow for unauthenticated access
|
||||
|
||||
##### `<groups>`
|
||||
List of user groups.
|
||||
- Contains `<group>` elements:
|
||||
|
||||
**Attributes:**
|
||||
- `name`: Group name
|
||||
- Can contain:
|
||||
- `users`: List of user references
|
||||
- `roles`: List of roles (READER/WRITER)
|
||||
- `user-quota`: Per-user quota
|
||||
- `group-quota`: Group-wide quota
|
||||
|
||||
#### `<authentication>`
|
||||
Configures authentication mechanism. Options:
|
||||
- `<basic>`: HTTP basic authentication
|
||||
- `<client-certificate>`: TLS certificate authentication, it uses attributes of the subject's X.500 name
|
||||
to extract the username and group of the client.
|
||||
|
||||
Example:
|
||||
```xml
|
||||
<client-certificate>
|
||||
<user-extractor attribute-name="CN" pattern="(.*)"/>
|
||||
<group-extractor attribute-name="O" pattern="(.*)"/>
|
||||
</client-certificate>
|
||||
```
|
||||
- `<none>`: No authentication
|
||||
|
||||
#### `<tls>`
|
||||
Configures TLS encryption.
|
||||
|
||||
**Child Elements:**
|
||||
- `<keystore>`: Server certificate configuration
|
||||
|
||||
**Attributes:**
|
||||
- `file` (required): Keystore file path
|
||||
- `password`: Keystore password
|
||||
- `key-alias` (required): Private key alias
|
||||
- `key-password`: Private key password
|
||||
- `<truststore>`: Client certificate verification
|
||||
|
||||
**Attributes:**
|
||||
- `file` (required): Truststore file path
|
||||
- `password`: Truststore password
|
||||
- `check-certificate-status`: Enable CRL/OCSP checking
|
||||
- `require-client-certificate` (default: false): Require client certificates
|
||||
|
||||
|
||||
----------------------------
|
||||
|
||||
# Complete configuration example
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<rbcs:server xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:rbcs="urn:net.woggioni.rbcs.server"
|
||||
xs:schemaLocation="urn:net.woggioni.rbcs.server jpms://net.woggioni.rbcs.server/net/woggioni/rbcs/server/schema/rbcs.xsd"
|
||||
>
|
||||
<bind host="0.0.0.0" port="8080" incoming-connections-backlog-size="1024"/>
|
||||
<connection
|
||||
max-request-size="67108864"
|
||||
idle-timeout="PT10S"
|
||||
read-idle-timeout="PT20S"
|
||||
write-idle-timeout="PT20S"
|
||||
read-timeout="PT5S"
|
||||
write-timeout="PT5S"/>
|
||||
<event-executor use-virtual-threads="true"/>
|
||||
<cache xs:type="rbcs:inMemoryCacheType" max-age="P7D" enable-compression="false" max-size="0x10000000" />
|
||||
<!--cache xs:type="rbcs:fileSystemCacheType" max-age="P7D" enable-compression="false" path="${sys:java.io.tmpdir}/rbcs"/-->
|
||||
<authorization>
|
||||
<users>
|
||||
<user name="user1" password="II+qeNLft2pZ/JVNo9F7jpjM/BqEcfsJW27NZ6dPVs8tAwHbxrJppKYsbL7J/SMl">
|
||||
<quota calls="100" period="PT1S"/>
|
||||
</user>
|
||||
<user name="user2" password="v6T9+q6/VNpvLknji3ixPiyz2YZCQMXj2FN7hvzbfc2Ig+IzAHO0iiBCH9oWuBDq"/>
|
||||
<anonymous>
|
||||
<quota calls="10" period="PT60S" initial-available-calls="10" max-available-calls="10"/>
|
||||
</anonymous>
|
||||
</users>
|
||||
<groups>
|
||||
<group name="readers">
|
||||
<users>
|
||||
<anonymous/>
|
||||
</users>
|
||||
<roles>
|
||||
<reader/>
|
||||
</roles>
|
||||
</group>
|
||||
<group name="writers">
|
||||
<users>
|
||||
<user ref="user1"/>
|
||||
<user ref="user2"/>
|
||||
</users>
|
||||
<roles>
|
||||
<reader/>
|
||||
<writer/>
|
||||
</roles>
|
||||
</group>
|
||||
</groups>
|
||||
</authorization>
|
||||
<authentication>
|
||||
<basic/>
|
||||
</authentication>
|
||||
</rbcs:server>
|
||||
|
||||
```
|
@@ -3,7 +3,7 @@ RUN adduser -D luser
|
||||
USER luser
|
||||
WORKDIR /home/luser
|
||||
|
||||
FROM base-release AS release
|
||||
FROM base-release AS release-vanilla
|
||||
ADD rbcs-cli-envelope-*.jar rbcs.jar
|
||||
ENTRYPOINT ["java", "-XX:+UseSerialGC", "-XX:GCTimeRatio=24", "-jar", "/home/luser/rbcs.jar", "server"]
|
||||
|
||||
@@ -15,3 +15,9 @@ RUN --mount=type=bind,source=.,target=/build/distributions tar -xf /build/distri
|
||||
WORKDIR /home/luser
|
||||
ADD logback.xml .
|
||||
ENTRYPOINT ["java", "-Dlogback.configurationFile=logback.xml", "-XX:+UseSerialGC", "-XX:GCTimeRatio=24", "-jar", "/home/luser/rbcs.jar", "server"]
|
||||
|
||||
FROM scratch AS release-native
|
||||
ADD rbcs-cli.upx /rbcs/rbcs-cli
|
||||
ENV RBCS_CONFIGURATION_DIR="/rbcs"
|
||||
WORKDIR /rbcs
|
||||
ENTRYPOINT ["./rbcs/rbcs-cli"]
|
||||
|
24
docker/README.md
Normal file
24
docker/README.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# RBCS Docker images
|
||||
There are 3 image flavours:
|
||||
- vanilla
|
||||
- memcache
|
||||
- native
|
||||
|
||||
The `vanilla` image only contains the envelope
|
||||
jar file with no plugins and is based on `eclipse-temurin:21-jre-alpine`
|
||||
|
||||
The `memcache` image is similar to the `vanilla` image, except that it also contains
|
||||
the `rbcs-server-memcache` plugin in the `plugins` folder, use this image if you don't want to use the `native`
|
||||
image and want to use memcache as the cache backend
|
||||
|
||||
The `native` image contains a native, statically-linked executable created with GraalVM
|
||||
that has no userspace dependencies. It also embeds the memcache plugin inside the executable.
|
||||
Use this image for maximum efficiency and minimal memory footprint.
|
||||
|
||||
## Which image shoud I use?
|
||||
The `native` image uses Java's SerialGC, so it's ideal for constrained environment like containers or small servers,
|
||||
if you have a lot of resources and want to squeeze out the maximum throughput you should consider the
|
||||
`vanilla` or `memcache` image, then choose and fine tune the garbage collector.
|
||||
|
||||
Also the `native` image is only available for the `x86_64` architecture at the moment,
|
||||
while `vanilla` and `memcache` also ship a `aarch64` variant.
|
@@ -4,7 +4,7 @@ org.gradle.caching=true
|
||||
|
||||
rbcs.version = 0.2.0
|
||||
|
||||
lys.version = 2025.02.08
|
||||
lys.version = 2025.02.26
|
||||
|
||||
gitea.maven.url = https://gitea.woggioni.net/api/packages/woggioni/maven
|
||||
docker.registry.url=gitea.woggioni.net
|
||||
|
@@ -5,6 +5,7 @@ plugins {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api catalog.netty.common
|
||||
api catalog.netty.buffer
|
||||
api catalog.netty.handler
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ module net.woggioni.rbcs.api {
|
||||
requires io.netty.buffer;
|
||||
requires io.netty.handler;
|
||||
requires io.netty.transport;
|
||||
requires io.netty.common;
|
||||
exports net.woggioni.rbcs.api;
|
||||
exports net.woggioni.rbcs.api.exception;
|
||||
exports net.woggioni.rbcs.api.message;
|
||||
|
@@ -0,0 +1,13 @@
|
||||
package net.woggioni.rbcs.api;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public interface AsyncCloseable extends AutoCloseable {
|
||||
|
||||
CompletableFuture<Void> asyncClose();
|
||||
|
||||
@Override
|
||||
default void close() throws Exception {
|
||||
asyncClose().get();
|
||||
}
|
||||
}
|
@@ -1,7 +1,15 @@
|
||||
package net.woggioni.rbcs.api;
|
||||
|
||||
import io.netty.channel.ChannelFactory;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.socket.DatagramChannel;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
|
||||
public interface CacheHandlerFactory extends AutoCloseable {
|
||||
ChannelHandler newHandler();
|
||||
public interface CacheHandlerFactory extends AsyncCloseable {
|
||||
ChannelHandler newHandler(
|
||||
EventLoopGroup eventLoopGroup,
|
||||
ChannelFactory<SocketChannel> socketChannelFactory,
|
||||
ChannelFactory<DatagramChannel> datagramChannelFactory
|
||||
);
|
||||
}
|
||||
|
@@ -83,17 +83,6 @@ public class Configuration {
|
||||
Group extract(X509Certificate cert);
|
||||
}
|
||||
|
||||
@Value
|
||||
public static class Throttling {
|
||||
KeyStore keyStore;
|
||||
TrustStore trustStore;
|
||||
boolean verifyClients;
|
||||
}
|
||||
|
||||
public enum ClientCertificate {
|
||||
REQUIRED, OPTIONAL
|
||||
}
|
||||
|
||||
@Value
|
||||
public static class Tls {
|
||||
KeyStore keyStore;
|
||||
|
@@ -9,20 +9,22 @@ plugins {
|
||||
id 'maven-publish'
|
||||
}
|
||||
|
||||
import net.woggioni.gradle.envelope.EnvelopePlugin
|
||||
import net.woggioni.gradle.envelope.EnvelopeJarTask
|
||||
import net.woggioni.gradle.graalvm.NativeImageConfigurationTask
|
||||
import net.woggioni.gradle.graalvm.NativeImagePlugin
|
||||
import net.woggioni.gradle.graalvm.NativeImageTask
|
||||
import net.woggioni.gradle.graalvm.UpxTask
|
||||
import net.woggioni.gradle.graalvm.JlinkPlugin
|
||||
import net.woggioni.gradle.graalvm.JlinkTask
|
||||
|
||||
Property<String> mainModuleName = objects.property(String.class)
|
||||
mainModuleName.set('net.woggioni.rbcs.cli')
|
||||
Property<String> mainClassName = objects.property(String.class)
|
||||
mainClassName.set('net.woggioni.rbcs.cli.RemoteBuildCacheServerCli')
|
||||
sourceSets {
|
||||
configureNativeImage {
|
||||
java {
|
||||
}
|
||||
kotlin {
|
||||
|
||||
tasks.named(JavaPlugin.COMPILE_JAVA_TASK_NAME, JavaCompile) {
|
||||
options.javaModuleMainClass = mainClassName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configurations {
|
||||
@@ -32,16 +34,25 @@ configurations {
|
||||
canBeResolved = true
|
||||
visible = true
|
||||
}
|
||||
}
|
||||
|
||||
envelopeJar {
|
||||
mainModule = mainModuleName
|
||||
mainClass = mainClassName
|
||||
configureNativeImageImplementation {
|
||||
extendsFrom implementation
|
||||
}
|
||||
|
||||
configureNativeImageRuntimeOnly {
|
||||
extendsFrom runtimeOnly
|
||||
}
|
||||
|
||||
nativeImage {
|
||||
extendsFrom runtimeClasspath
|
||||
}
|
||||
|
||||
extraClasspath = ["plugins"]
|
||||
}
|
||||
|
||||
dependencies {
|
||||
configureNativeImageImplementation project
|
||||
configureNativeImageImplementation project(':rbcs-server-memcache')
|
||||
|
||||
implementation catalog.jwo
|
||||
implementation catalog.slf4j.api
|
||||
implementation catalog.picocli
|
||||
@@ -52,32 +63,55 @@ dependencies {
|
||||
// runtimeOnly catalog.slf4j.jdk14
|
||||
runtimeOnly catalog.logback.classic
|
||||
// runtimeOnly catalog.slf4j.simple
|
||||
nativeImage project(':rbcs-server-memcache')
|
||||
|
||||
}
|
||||
|
||||
Provider<EnvelopeJarTask> envelopeJarTaskProvider = tasks.named('envelopeJar', EnvelopeJarTask.class) {
|
||||
// systemProperties['java.util.logging.config.class'] = 'net.woggioni.rbcs.LoggingConfig'
|
||||
// systemProperties['log.config.source'] = 'net/woggioni/rbcs/cli/logging.properties'
|
||||
// systemProperties['java.util.logging.config.file'] = 'classpath:net/woggioni/rbcs/cli/logging.properties'
|
||||
|
||||
Property<String> mainModuleName = objects.property(String.class)
|
||||
mainModuleName.set('net.woggioni.rbcs.cli')
|
||||
Property<String> mainClassName = objects.property(String.class)
|
||||
mainClassName.set('net.woggioni.rbcs.cli.RemoteBuildCacheServerCli')
|
||||
|
||||
tasks.named(JavaPlugin.COMPILE_JAVA_TASK_NAME, JavaCompile) {
|
||||
options.javaModuleMainClass = mainClassName
|
||||
}
|
||||
|
||||
Provider<Jar> jarTaskProvider = tasks.named(JavaPlugin.JAR_TASK_NAME, Jar)
|
||||
|
||||
Provider<EnvelopeJarTask> envelopeJarTaskProvider = tasks.named(EnvelopePlugin.ENVELOPE_JAR_TASK_NAME, EnvelopeJarTask.class) {
|
||||
mainModule = mainModuleName
|
||||
mainClass = mainClassName
|
||||
|
||||
extraClasspath = ["plugins"]
|
||||
|
||||
systemProperties['logback.configurationFile'] = 'classpath:net/woggioni/rbcs/cli/logback.xml'
|
||||
systemProperties['io.netty.leakDetectionLevel'] = 'DISABLED'
|
||||
|
||||
// systemProperties['org.slf4j.simpleLogger.showDateTime'] = 'true'
|
||||
// systemProperties['org.slf4j.simpleLogger.defaultLogLevel'] = 'debug'
|
||||
// systemProperties['org.slf4j.simpleLogger.log.com.google.code.yanf4j'] = 'warn'
|
||||
// systemProperties['org.slf4j.simpleLogger.log.net.rubyeye.xmemcached'] = 'warn'
|
||||
// systemProperties['org.slf4j.simpleLogger.dateTimeFormat'] = 'yyyy-MM-dd\'T\'HH:mm:ss.SSSZ'
|
||||
}
|
||||
|
||||
tasks.named(NativeImagePlugin.CONFIGURE_NATIVE_IMAGE_TASK_NAME, NativeImageConfigurationTask) {
|
||||
mainClass = mainClassName
|
||||
mainModule = mainModuleName
|
||||
mainClass = "net.woggioni.rbcs.cli.graal.GraalNativeImageConfiguration"
|
||||
setClasspath(configurations.configureNativeImageRuntimeClasspath + sourceSets.graal.output.classesDirs)
|
||||
mergeConfiguration = false
|
||||
systemProperty('logback.configurationFile', 'classpath:net/woggioni/rbcs/cli/logback.xml')
|
||||
systemProperty('io.netty.leakDetectionLevel', 'DISABLED')
|
||||
modularity.inferModulePath = false
|
||||
enabled = false
|
||||
}
|
||||
|
||||
tasks.named(NativeImagePlugin.NATIVE_IMAGE_TASK_NAME, NativeImageTask) {
|
||||
nativeImage {
|
||||
mainClass = mainClassName
|
||||
mainModule = mainModuleName
|
||||
// mainModule = mainModuleName
|
||||
useMusl = true
|
||||
buildStaticImage = true
|
||||
linkAtBuildTime = false
|
||||
classpath = project.files(jarTaskProvider, configurations.nativeImage)
|
||||
compressExecutable = true
|
||||
compressionLevel = 10
|
||||
useLZMA = false
|
||||
}
|
||||
|
||||
Provider<UpxTask> upxTaskProvider = tasks.named(NativeImagePlugin.UPX_TASK_NAME, UpxTask) {
|
||||
}
|
||||
|
||||
tasks.named(JlinkPlugin.JLINK_TASK_NAME, JlinkTask) {
|
||||
@@ -95,14 +129,20 @@ tasks.named(JavaPlugin.PROCESS_RESOURCES_TASK_NAME, ProcessResources) {
|
||||
|
||||
artifacts {
|
||||
release(envelopeJarTaskProvider)
|
||||
release(upxTaskProvider)
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
maven(MavenPublication) {
|
||||
artifact envelopeJar
|
||||
artifact(upxTaskProvider) {
|
||||
classifier = "linux-x86_64"
|
||||
extension = "exe"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
6
rbcs-cli/native-image/jni-config.json
Normal file
6
rbcs-cli/native-image/jni-config.json
Normal file
@@ -0,0 +1,6 @@
|
||||
[
|
||||
{
|
||||
"name":"java.lang.Boolean",
|
||||
"methods":[{"name":"getBoolean","parameterTypes":["java.lang.String"] }]
|
||||
}
|
||||
]
|
@@ -1,2 +1,2 @@
|
||||
Args=-H:Optimize=3 --gc=serial --initialize-at-run-time=io.netty
|
||||
Args=-O3 --gc=serial --install-exit-handlers --initialize-at-run-time=io.netty --enable-url-protocols=jpms --initialize-at-build-time=net.woggioni.rbcs.common.RbcsUrlStreamHandlerFactory,net.woggioni.rbcs.common.RbcsUrlStreamHandlerFactory$JpmsHandler
|
||||
#-H:TraceClassInitialization=io.netty.handler.ssl.BouncyCastleAlpnSslUtils
|
8
rbcs-cli/native-image/predefined-classes-config.json
Normal file
8
rbcs-cli/native-image/predefined-classes-config.json
Normal file
@@ -0,0 +1,8 @@
|
||||
[
|
||||
{
|
||||
"type":"agent-extracted",
|
||||
"classes":[
|
||||
]
|
||||
}
|
||||
]
|
||||
|
2
rbcs-cli/native-image/proxy-config.json
Normal file
2
rbcs-cli/native-image/proxy-config.json
Normal file
@@ -0,0 +1,2 @@
|
||||
[
|
||||
]
|
756
rbcs-cli/native-image/reflect-config.json
Normal file
756
rbcs-cli/native-image/reflect-config.json
Normal file
@@ -0,0 +1,756 @@
|
||||
[
|
||||
{
|
||||
"name":"android.os.Build$VERSION"
|
||||
},
|
||||
{
|
||||
"name":"ch.qos.logback.classic.encoder.PatternLayoutEncoder",
|
||||
"queryAllPublicMethods":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"ch.qos.logback.classic.joran.SerializedModelConfigurator",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"ch.qos.logback.classic.util.DefaultJoranConfigurator",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"ch.qos.logback.core.ConsoleAppender",
|
||||
"queryAllPublicMethods":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }, {"name":"setTarget","parameterTypes":["java.lang.String"] }]
|
||||
},
|
||||
{
|
||||
"name":"ch.qos.logback.core.OutputStreamAppender",
|
||||
"methods":[{"name":"setEncoder","parameterTypes":["ch.qos.logback.core.encoder.Encoder"] }]
|
||||
},
|
||||
{
|
||||
"name":"ch.qos.logback.core.encoder.Encoder",
|
||||
"methods":[{"name":"valueOf","parameterTypes":["java.lang.String"] }]
|
||||
},
|
||||
{
|
||||
"name":"ch.qos.logback.core.encoder.LayoutWrappingEncoder",
|
||||
"methods":[{"name":"setParent","parameterTypes":["ch.qos.logback.core.spi.ContextAware"] }]
|
||||
},
|
||||
{
|
||||
"name":"ch.qos.logback.core.pattern.PatternLayoutEncoderBase",
|
||||
"methods":[{"name":"setPattern","parameterTypes":["java.lang.String"] }]
|
||||
},
|
||||
{
|
||||
"name":"ch.qos.logback.core.spi.ContextAware",
|
||||
"methods":[{"name":"valueOf","parameterTypes":["java.lang.String"] }]
|
||||
},
|
||||
{
|
||||
"name":"com.aayushatharva.brotli4j.Brotli4jLoader"
|
||||
},
|
||||
{
|
||||
"name":"com.github.luben.zstd.Zstd"
|
||||
},
|
||||
{
|
||||
"name":"com.sun.crypto.provider.AESCipher$General",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"com.sun.crypto.provider.ARCFOURCipher",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"com.sun.crypto.provider.ChaCha20Cipher$ChaCha20Poly1305",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"com.sun.crypto.provider.DESCipher",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"com.sun.crypto.provider.DESedeCipher",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"com.sun.crypto.provider.DHParameters",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"com.sun.crypto.provider.GaloisCounterMode$AESGCM",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"com.sun.crypto.provider.HmacCore$HmacSHA512",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"com.sun.crypto.provider.PBKDF2Core$HmacSHA512",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"com.sun.crypto.provider.TlsMasterSecretGenerator",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"com.sun.org.apache.xerces.internal.impl.dv.xs.ExtendedSchemaDVFactoryImpl",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"com.sun.org.apache.xerces.internal.impl.dv.xs.SchemaDVFactoryImpl",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"groovy.lang.Closure"
|
||||
},
|
||||
{
|
||||
"name":"io.netty.bootstrap.ServerBootstrap$1"
|
||||
},
|
||||
{
|
||||
"name":"io.netty.bootstrap.ServerBootstrap$ServerBootstrapAcceptor",
|
||||
"methods":[{"name":"channelRead","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }, {"name":"exceptionCaught","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Throwable"] }]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.buffer.AbstractByteBufAllocator",
|
||||
"queryAllDeclaredMethods":true
|
||||
},
|
||||
{
|
||||
"name":"io.netty.buffer.AbstractReferenceCountedByteBuf",
|
||||
"fields":[{"name":"refCnt"}]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.channel.AbstractChannelHandlerContext",
|
||||
"fields":[{"name":"handlerState"}]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.channel.ChannelDuplexHandler",
|
||||
"methods":[{"name":"bind","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.net.SocketAddress","io.netty.channel.ChannelPromise"] }, {"name":"close","parameterTypes":["io.netty.channel.ChannelHandlerContext","io.netty.channel.ChannelPromise"] }, {"name":"connect","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.net.SocketAddress","java.net.SocketAddress","io.netty.channel.ChannelPromise"] }, {"name":"deregister","parameterTypes":["io.netty.channel.ChannelHandlerContext","io.netty.channel.ChannelPromise"] }, {"name":"disconnect","parameterTypes":["io.netty.channel.ChannelHandlerContext","io.netty.channel.ChannelPromise"] }, {"name":"flush","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"read","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"write","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object","io.netty.channel.ChannelPromise"] }]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.channel.ChannelHandlerAdapter",
|
||||
"methods":[{"name":"exceptionCaught","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Throwable"] }]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.channel.ChannelInboundHandlerAdapter",
|
||||
"methods":[{"name":"channelActive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelInactive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelRead","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }, {"name":"channelReadComplete","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelRegistered","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelUnregistered","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelWritabilityChanged","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"exceptionCaught","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Throwable"] }, {"name":"userEventTriggered","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.channel.ChannelInitializer",
|
||||
"methods":[{"name":"channelRegistered","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"exceptionCaught","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Throwable"] }]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.channel.ChannelOutboundBuffer",
|
||||
"fields":[{"name":"totalPendingSize"}, {"name":"unwritable"}]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.channel.ChannelOutboundHandlerAdapter",
|
||||
"methods":[{"name":"bind","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.net.SocketAddress","io.netty.channel.ChannelPromise"] }, {"name":"connect","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.net.SocketAddress","java.net.SocketAddress","io.netty.channel.ChannelPromise"] }, {"name":"deregister","parameterTypes":["io.netty.channel.ChannelHandlerContext","io.netty.channel.ChannelPromise"] }, {"name":"disconnect","parameterTypes":["io.netty.channel.ChannelHandlerContext","io.netty.channel.ChannelPromise"] }, {"name":"flush","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"read","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.channel.CombinedChannelDuplexHandler",
|
||||
"methods":[{"name":"bind","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.net.SocketAddress","io.netty.channel.ChannelPromise"] }, {"name":"channelActive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelInactive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelRead","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }, {"name":"channelReadComplete","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelRegistered","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelUnregistered","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelWritabilityChanged","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"close","parameterTypes":["io.netty.channel.ChannelHandlerContext","io.netty.channel.ChannelPromise"] }, {"name":"connect","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.net.SocketAddress","java.net.SocketAddress","io.netty.channel.ChannelPromise"] }, {"name":"deregister","parameterTypes":["io.netty.channel.ChannelHandlerContext","io.netty.channel.ChannelPromise"] }, {"name":"disconnect","parameterTypes":["io.netty.channel.ChannelHandlerContext","io.netty.channel.ChannelPromise"] }, {"name":"exceptionCaught","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Throwable"] }, {"name":"flush","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"read","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"userEventTriggered","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }, {"name":"write","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object","io.netty.channel.ChannelPromise"] }]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.channel.DefaultChannelConfig",
|
||||
"fields":[{"name":"autoRead"}, {"name":"writeBufferWaterMark"}]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.channel.DefaultChannelPipeline",
|
||||
"fields":[{"name":"estimatorHandle"}]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.channel.DefaultChannelPipeline$HeadContext",
|
||||
"methods":[{"name":"bind","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.net.SocketAddress","io.netty.channel.ChannelPromise"] }, {"name":"channelActive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelInactive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelRead","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }, {"name":"channelReadComplete","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelRegistered","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelUnregistered","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelWritabilityChanged","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"close","parameterTypes":["io.netty.channel.ChannelHandlerContext","io.netty.channel.ChannelPromise"] }, {"name":"connect","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.net.SocketAddress","java.net.SocketAddress","io.netty.channel.ChannelPromise"] }, {"name":"deregister","parameterTypes":["io.netty.channel.ChannelHandlerContext","io.netty.channel.ChannelPromise"] }, {"name":"disconnect","parameterTypes":["io.netty.channel.ChannelHandlerContext","io.netty.channel.ChannelPromise"] }, {"name":"exceptionCaught","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Throwable"] }, {"name":"flush","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"read","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"userEventTriggered","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }, {"name":"write","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object","io.netty.channel.ChannelPromise"] }]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.channel.DefaultChannelPipeline$TailContext",
|
||||
"methods":[{"name":"channelActive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelInactive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelRead","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }, {"name":"channelReadComplete","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelRegistered","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelUnregistered","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelWritabilityChanged","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"exceptionCaught","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Throwable"] }, {"name":"userEventTriggered","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.channel.SimpleChannelInboundHandler",
|
||||
"methods":[{"name":"channelRead","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.channel.embedded.EmbeddedChannel$2"
|
||||
},
|
||||
{
|
||||
"name":"io.netty.channel.pool.SimpleChannelPool$1"
|
||||
},
|
||||
{
|
||||
"name":"io.netty.channel.socket.nio.NioSocketChannel",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.handler.codec.ByteToMessageDecoder",
|
||||
"methods":[{"name":"channelInactive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelRead","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }, {"name":"channelReadComplete","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"userEventTriggered","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.handler.codec.MessageAggregator",
|
||||
"methods":[{"name":"channelInactive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelReadComplete","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.handler.codec.MessageToByteEncoder",
|
||||
"methods":[{"name":"write","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object","io.netty.channel.ChannelPromise"] }]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.handler.codec.MessageToMessageCodec",
|
||||
"methods":[{"name":"channelRead","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }, {"name":"channelReadComplete","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.handler.codec.MessageToMessageDecoder",
|
||||
"methods":[{"name":"channelRead","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.handler.codec.compression.JdkZlibDecoder"
|
||||
},
|
||||
{
|
||||
"name":"io.netty.handler.codec.compression.JdkZlibEncoder",
|
||||
"methods":[{"name":"close","parameterTypes":["io.netty.channel.ChannelHandlerContext","io.netty.channel.ChannelPromise"] }]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.handler.codec.http.HttpClientCodec"
|
||||
},
|
||||
{
|
||||
"name":"io.netty.handler.codec.http.HttpContentDecoder",
|
||||
"methods":[{"name":"channelInactive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelReadComplete","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.handler.codec.http.HttpContentDecompressor"
|
||||
},
|
||||
{
|
||||
"name":"io.netty.handler.codec.http.HttpContentEncoder",
|
||||
"methods":[{"name":"channelInactive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.handler.codec.http.HttpObjectAggregator"
|
||||
},
|
||||
{
|
||||
"name":"io.netty.handler.codec.http.HttpServerCodec"
|
||||
},
|
||||
{
|
||||
"name":"io.netty.handler.codec.memcache.binary.BinaryMemcacheClientCodec"
|
||||
},
|
||||
{
|
||||
"name":"io.netty.handler.stream.ChunkedWriteHandler",
|
||||
"methods":[{"name":"channelInactive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelWritabilityChanged","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"flush","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"write","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object","io.netty.channel.ChannelPromise"] }]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.handler.timeout.IdleStateHandler",
|
||||
"methods":[{"name":"channelActive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelInactive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelRead","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }, {"name":"channelReadComplete","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelRegistered","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"write","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object","io.netty.channel.ChannelPromise"] }]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.internal.tcnative.SSLContext"
|
||||
},
|
||||
{
|
||||
"name":"io.netty.util.AbstractReferenceCounted",
|
||||
"fields":[{"name":"refCnt"}]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.util.DefaultAttributeMap",
|
||||
"fields":[{"name":"attributes"}]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.util.DefaultAttributeMap$DefaultAttribute",
|
||||
"fields":[{"name":"attributeMap"}]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.util.Recycler$DefaultHandle",
|
||||
"fields":[{"name":"state"}]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.util.ReferenceCountUtil",
|
||||
"queryAllDeclaredMethods":true
|
||||
},
|
||||
{
|
||||
"name":"io.netty.util.concurrent.DefaultPromise",
|
||||
"fields":[{"name":"result"}]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.util.concurrent.SingleThreadEventExecutor",
|
||||
"fields":[{"name":"state"}, {"name":"threadProperties"}]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.util.internal.shaded.org.jctools.queues.BaseMpscLinkedArrayQueueColdProducerFields",
|
||||
"fields":[{"name":"producerLimit"}]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.util.internal.shaded.org.jctools.queues.BaseMpscLinkedArrayQueueConsumerFields",
|
||||
"fields":[{"name":"consumerIndex"}]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.util.internal.shaded.org.jctools.queues.BaseMpscLinkedArrayQueueProducerFields",
|
||||
"fields":[{"name":"producerIndex"}]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.util.internal.shaded.org.jctools.queues.unpadded.MpscUnpaddedArrayQueueConsumerIndexField",
|
||||
"fields":[{"name":"consumerIndex"}]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.util.internal.shaded.org.jctools.queues.unpadded.MpscUnpaddedArrayQueueProducerIndexField",
|
||||
"fields":[{"name":"producerIndex"}]
|
||||
},
|
||||
{
|
||||
"name":"io.netty.util.internal.shaded.org.jctools.queues.unpadded.MpscUnpaddedArrayQueueProducerLimitField",
|
||||
"fields":[{"name":"producerLimit"}]
|
||||
},
|
||||
{
|
||||
"name":"java.io.FilePermission"
|
||||
},
|
||||
{
|
||||
"name":"java.lang.Object",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true
|
||||
},
|
||||
{
|
||||
"name":"java.lang.ProcessHandle",
|
||||
"methods":[{"name":"current","parameterTypes":[] }, {"name":"pid","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"java.lang.RuntimePermission"
|
||||
},
|
||||
{
|
||||
"name":"java.lang.System",
|
||||
"methods":[{"name":"console","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"java.lang.Thread",
|
||||
"fields":[{"name":"threadLocalRandomProbe"}]
|
||||
},
|
||||
{
|
||||
"name":"java.net.NetPermission"
|
||||
},
|
||||
{
|
||||
"name":"java.net.SocketPermission"
|
||||
},
|
||||
{
|
||||
"name":"java.net.URLPermission",
|
||||
"methods":[{"name":"<init>","parameterTypes":["java.lang.String","java.lang.String"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.nio.Bits",
|
||||
"fields":[{"name":"MAX_MEMORY"}, {"name":"UNALIGNED"}]
|
||||
},
|
||||
{
|
||||
"name":"java.nio.Buffer",
|
||||
"fields":[{"name":"address"}]
|
||||
},
|
||||
{
|
||||
"name":"java.nio.ByteBuffer",
|
||||
"methods":[{"name":"alignedSlice","parameterTypes":["int"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.nio.DirectByteBuffer",
|
||||
"methods":[{"name":"<init>","parameterTypes":["long","long"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.nio.channels.spi.SelectorProvider",
|
||||
"methods":[{"name":"openServerSocketChannel","parameterTypes":["java.net.ProtocolFamily"] }, {"name":"openSocketChannel","parameterTypes":["java.net.ProtocolFamily"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.nio.file.Path"
|
||||
},
|
||||
{
|
||||
"name":"java.nio.file.Paths",
|
||||
"methods":[{"name":"get","parameterTypes":["java.lang.String","java.lang.String[]"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.security.AlgorithmParametersSpi"
|
||||
},
|
||||
{
|
||||
"name":"java.security.AllPermission"
|
||||
},
|
||||
{
|
||||
"name":"java.security.KeyStoreSpi"
|
||||
},
|
||||
{
|
||||
"name":"java.security.SecureRandomParameters"
|
||||
},
|
||||
{
|
||||
"name":"java.security.SecurityPermission"
|
||||
},
|
||||
{
|
||||
"name":"java.sql.Connection"
|
||||
},
|
||||
{
|
||||
"name":"java.sql.Driver"
|
||||
},
|
||||
{
|
||||
"name":"java.sql.DriverManager",
|
||||
"methods":[{"name":"getConnection","parameterTypes":["java.lang.String"] }, {"name":"getDriver","parameterTypes":["java.lang.String"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.sql.Time",
|
||||
"methods":[{"name":"<init>","parameterTypes":["long"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.sql.Timestamp",
|
||||
"methods":[{"name":"valueOf","parameterTypes":["java.lang.String"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.time.Duration",
|
||||
"methods":[{"name":"parse","parameterTypes":["java.lang.CharSequence"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.time.Instant",
|
||||
"methods":[{"name":"parse","parameterTypes":["java.lang.CharSequence"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.time.LocalDate",
|
||||
"methods":[{"name":"parse","parameterTypes":["java.lang.CharSequence"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.time.LocalDateTime",
|
||||
"methods":[{"name":"parse","parameterTypes":["java.lang.CharSequence"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.time.LocalTime",
|
||||
"methods":[{"name":"parse","parameterTypes":["java.lang.CharSequence"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.time.MonthDay",
|
||||
"methods":[{"name":"parse","parameterTypes":["java.lang.CharSequence"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.time.OffsetDateTime",
|
||||
"methods":[{"name":"parse","parameterTypes":["java.lang.CharSequence"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.time.OffsetTime",
|
||||
"methods":[{"name":"parse","parameterTypes":["java.lang.CharSequence"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.time.Period",
|
||||
"methods":[{"name":"parse","parameterTypes":["java.lang.CharSequence"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.time.Year",
|
||||
"methods":[{"name":"parse","parameterTypes":["java.lang.CharSequence"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.time.YearMonth",
|
||||
"methods":[{"name":"parse","parameterTypes":["java.lang.CharSequence"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.time.ZoneId",
|
||||
"methods":[{"name":"of","parameterTypes":["java.lang.String"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.time.ZoneOffset",
|
||||
"methods":[{"name":"of","parameterTypes":["java.lang.String"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.time.ZonedDateTime",
|
||||
"methods":[{"name":"parse","parameterTypes":["java.lang.CharSequence"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.util.PropertyPermission"
|
||||
},
|
||||
{
|
||||
"name":"java.util.concurrent.ForkJoinTask",
|
||||
"fields":[{"name":"aux"}, {"name":"status"}]
|
||||
},
|
||||
{
|
||||
"name":"java.util.concurrent.atomic.AtomicBoolean",
|
||||
"fields":[{"name":"value"}]
|
||||
},
|
||||
{
|
||||
"name":"java.util.concurrent.atomic.AtomicReference",
|
||||
"fields":[{"name":"value"}]
|
||||
},
|
||||
{
|
||||
"name":"java.util.concurrent.atomic.Striped64",
|
||||
"fields":[{"name":"base"}, {"name":"cellsBusy"}]
|
||||
},
|
||||
{
|
||||
"name":"java.util.concurrent.atomic.Striped64$Cell",
|
||||
"fields":[{"name":"value"}]
|
||||
},
|
||||
{
|
||||
"name":"java.util.zip.Adler32",
|
||||
"methods":[{"name":"update","parameterTypes":["java.nio.ByteBuffer"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.util.zip.CRC32",
|
||||
"methods":[{"name":"update","parameterTypes":["java.nio.ByteBuffer"] }]
|
||||
},
|
||||
{
|
||||
"name":"javax.security.auth.x500.X500Principal",
|
||||
"fields":[{"name":"thisX500Name"}],
|
||||
"methods":[{"name":"<init>","parameterTypes":["sun.security.x509.X500Name"] }]
|
||||
},
|
||||
{
|
||||
"name":"javax.smartcardio.CardPermission"
|
||||
},
|
||||
{
|
||||
"name":"jdk.internal.misc.Unsafe",
|
||||
"methods":[{"name":"getUnsafe","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"net.woggioni.rbcs.cli.RemoteBuildCacheServerCli",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true
|
||||
},
|
||||
{
|
||||
"name":"net.woggioni.rbcs.cli.RemoteBuildCacheServerCli$VersionProvider",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"net.woggioni.rbcs.cli.impl.RbcsCommand",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true
|
||||
},
|
||||
{
|
||||
"name":"net.woggioni.rbcs.cli.impl.commands.BenchmarkCommand",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true
|
||||
},
|
||||
{
|
||||
"name":"net.woggioni.rbcs.cli.impl.commands.ClientCommand",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true
|
||||
},
|
||||
{
|
||||
"name":"net.woggioni.rbcs.cli.impl.commands.GetCommand",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true
|
||||
},
|
||||
{
|
||||
"name":"net.woggioni.rbcs.cli.impl.commands.HealthCheckCommand",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true
|
||||
},
|
||||
{
|
||||
"name":"net.woggioni.rbcs.cli.impl.commands.PasswordHashCommand",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true
|
||||
},
|
||||
{
|
||||
"name":"net.woggioni.rbcs.cli.impl.commands.PutCommand",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true
|
||||
},
|
||||
{
|
||||
"name":"net.woggioni.rbcs.cli.impl.commands.ServerCommand",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true
|
||||
},
|
||||
{
|
||||
"name":"net.woggioni.rbcs.cli.impl.converters.ByteSizeConverter",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"net.woggioni.rbcs.cli.impl.converters.DurationConverter",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"net.woggioni.rbcs.cli.impl.converters.OutputStreamConverter",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"net.woggioni.rbcs.client.RemoteBuildCacheClient$sendRequest$1$operationComplete$responseHandler$1",
|
||||
"methods":[{"name":"channelInactive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"exceptionCaught","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Throwable"] }]
|
||||
},
|
||||
{
|
||||
"name":"net.woggioni.rbcs.client.RemoteBuildCacheClient$sendRequest$1$operationComplete$timeoutHandler$1",
|
||||
"methods":[{"name":"userEventTriggered","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }]
|
||||
},
|
||||
{
|
||||
"name":"net.woggioni.rbcs.server.RemoteBuildCacheServer$HttpChunkContentCompressor",
|
||||
"methods":[{"name":"write","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object","io.netty.channel.ChannelPromise"] }]
|
||||
},
|
||||
{
|
||||
"name":"net.woggioni.rbcs.server.RemoteBuildCacheServer$NettyHttpBasicAuthenticator"
|
||||
},
|
||||
{
|
||||
"name":"net.woggioni.rbcs.server.RemoteBuildCacheServer$ServerInitializer"
|
||||
},
|
||||
{
|
||||
"name":"net.woggioni.rbcs.server.RemoteBuildCacheServer$ServerInitializer$initChannel$4",
|
||||
"methods":[{"name":"userEventTriggered","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }]
|
||||
},
|
||||
{
|
||||
"name":"net.woggioni.rbcs.server.auth.AbstractNettyHttpAuthenticator",
|
||||
"methods":[{"name":"channelRead","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }]
|
||||
},
|
||||
{
|
||||
"name":"net.woggioni.rbcs.server.cache.FileSystemCacheHandler",
|
||||
"methods":[{"name":"exceptionCaught","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Throwable"] }]
|
||||
},
|
||||
{
|
||||
"name":"net.woggioni.rbcs.server.cache.InMemoryCacheHandler",
|
||||
"methods":[{"name":"exceptionCaught","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Throwable"] }]
|
||||
},
|
||||
{
|
||||
"name":"net.woggioni.rbcs.server.exception.ExceptionHandler",
|
||||
"methods":[{"name":"exceptionCaught","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Throwable"] }]
|
||||
},
|
||||
{
|
||||
"name":"net.woggioni.rbcs.server.handler.CacheContentHandler",
|
||||
"methods":[{"name":"exceptionCaught","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Throwable"] }]
|
||||
},
|
||||
{
|
||||
"name":"net.woggioni.rbcs.server.handler.MaxRequestSizeHandler",
|
||||
"methods":[{"name":"channelRead","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }]
|
||||
},
|
||||
{
|
||||
"name":"net.woggioni.rbcs.server.handler.ServerHandler",
|
||||
"methods":[{"name":"channelRead","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }, {"name":"exceptionCaught","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Throwable"] }, {"name":"write","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object","io.netty.channel.ChannelPromise"] }]
|
||||
},
|
||||
{
|
||||
"name":"net.woggioni.rbcs.server.handler.TraceHandler",
|
||||
"methods":[{"name":"channelRead","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }, {"name":"exceptionCaught","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Throwable"] }]
|
||||
},
|
||||
{
|
||||
"name":"net.woggioni.rbcs.server.memcache.MemcacheCacheHandler",
|
||||
"methods":[{"name":"exceptionCaught","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Throwable"] }]
|
||||
},
|
||||
{
|
||||
"name":"net.woggioni.rbcs.server.memcache.client.MemcacheClient$sendRequest$1$operationComplete$handler$1",
|
||||
"methods":[{"name":"channelInactive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"exceptionCaught","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Throwable"] }]
|
||||
},
|
||||
{
|
||||
"name":"net.woggioni.rbcs.server.throttling.ThrottlingHandler",
|
||||
"methods":[{"name":"channelRead","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.misc.Unsafe",
|
||||
"fields":[{"name":"theUnsafe"}],
|
||||
"methods":[{"name":"copyMemory","parameterTypes":["java.lang.Object","long","java.lang.Object","long","long"] }, {"name":"getAndAddLong","parameterTypes":["java.lang.Object","long","long"] }, {"name":"getAndSetObject","parameterTypes":["java.lang.Object","long","java.lang.Object"] }, {"name":"invokeCleaner","parameterTypes":["java.nio.ByteBuffer"] }, {"name":"storeFence","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.nio.ch.SelectorImpl",
|
||||
"fields":[{"name":"publicSelectedKeys"}, {"name":"selectedKeys"}]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.pkcs12.PKCS12KeyStore",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.pkcs12.PKCS12KeyStore$DualFormatPKCS12",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.provider.DSA$SHA224withDSA",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.provider.DSA$SHA256withDSA",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.provider.JavaKeyStore$JKS",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.provider.MD5",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.provider.NativePRNG",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }, {"name":"<init>","parameterTypes":["java.security.SecureRandomParameters"] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.provider.NativePRNG$NonBlocking",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }, {"name":"<init>","parameterTypes":["java.security.SecureRandomParameters"] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.provider.SHA",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.provider.SHA2$SHA224",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.provider.SHA2$SHA256",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.provider.SHA5$SHA384",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.provider.SHA5$SHA512",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.provider.X509Factory",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.rsa.PSSParameters",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.rsa.RSAKeyFactory$Legacy",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.rsa.RSAPSSSignature",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.rsa.RSASignature$SHA224withRSA",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.ssl.KeyManagerFactoryImpl$SunX509",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.ssl.SSLContextImpl$DefaultSSLContext",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.ssl.SSLContextImpl$TLSContext",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.ssl.TrustManagerFactoryImpl$PKIXFactory",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.x509.AuthorityInfoAccessExtension",
|
||||
"methods":[{"name":"<init>","parameterTypes":["java.lang.Boolean","java.lang.Object"] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.x509.AuthorityKeyIdentifierExtension",
|
||||
"methods":[{"name":"<init>","parameterTypes":["java.lang.Boolean","java.lang.Object"] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.x509.BasicConstraintsExtension",
|
||||
"methods":[{"name":"<init>","parameterTypes":["java.lang.Boolean","java.lang.Object"] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.x509.CRLDistributionPointsExtension",
|
||||
"methods":[{"name":"<init>","parameterTypes":["java.lang.Boolean","java.lang.Object"] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.x509.CertificatePoliciesExtension",
|
||||
"methods":[{"name":"<init>","parameterTypes":["java.lang.Boolean","java.lang.Object"] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.x509.KeyUsageExtension",
|
||||
"methods":[{"name":"<init>","parameterTypes":["java.lang.Boolean","java.lang.Object"] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.x509.NetscapeCertTypeExtension",
|
||||
"methods":[{"name":"<init>","parameterTypes":["java.lang.Boolean","java.lang.Object"] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.x509.PrivateKeyUsageExtension",
|
||||
"methods":[{"name":"<init>","parameterTypes":["java.lang.Boolean","java.lang.Object"] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.x509.SubjectAlternativeNameExtension",
|
||||
"methods":[{"name":"<init>","parameterTypes":["java.lang.Boolean","java.lang.Object"] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.x509.SubjectKeyIdentifierExtension",
|
||||
"methods":[{"name":"<init>","parameterTypes":["java.lang.Boolean","java.lang.Object"] }]
|
||||
}
|
||||
]
|
74
rbcs-cli/native-image/resource-config.json
Normal file
74
rbcs-cli/native-image/resource-config.json
Normal file
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"resources": {
|
||||
"includes": [
|
||||
{
|
||||
"pattern": "\\QMETA-INF/MANIFEST.MF\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/services/ch.qos.logback.classic.spi.Configurator\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/services/java.lang.System$LoggerFinder\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/services/java.net.spi.InetAddressResolverProvider\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/services/java.net.spi.URLStreamHandlerProvider\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/services/java.nio.channels.spi.SelectorProvider\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/services/java.time.zone.ZoneRulesProvider\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/services/javax.xml.parsers.DocumentBuilderFactory\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/services/javax.xml.parsers.SAXParserFactory\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/services/net.woggioni.rbcs.api.CacheProvider\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/services/org.slf4j.spi.SLF4JServiceProvider\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\Qclasspath:net/woggioni/rbcs/cli/logback.xml\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\Qlogback-test.scmo\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\Qlogback.scmo\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\Qnet/woggioni/rbcs/cli/logback.xml\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\Qnet/woggioni/rbcs/server/rbcs-default.xml\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\Qnet/woggioni/rbcs/server/schema/rbcs.xsd\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\Qnet/woggioni/rbcs/client/schema/rbcs-client.xsd\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\Q/net/woggioni/rbcs/server/memcache/schema/rbcs-memcache.xsd\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "java.base:\\Qsun/text/resources/LineBreakIteratorData\\E"
|
||||
}
|
||||
]
|
||||
},
|
||||
"bundles": [
|
||||
{
|
||||
"name": "com.sun.org.apache.xerces.internal.impl.xpath.regex.message",
|
||||
"locales": [
|
||||
""
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
11
rbcs-cli/native-image/serialization-config.json
Normal file
11
rbcs-cli/native-image/serialization-config.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"types":[
|
||||
{
|
||||
"name":"net.woggioni.rbcs.api.CacheValueMetadata"
|
||||
}
|
||||
],
|
||||
"lambdaCapturingTypes":[
|
||||
],
|
||||
"proxies":[
|
||||
]
|
||||
}
|
@@ -0,0 +1,161 @@
|
||||
package net.woggioni.rbcs.cli.graal
|
||||
|
||||
import net.woggioni.rbcs.api.Configuration
|
||||
import net.woggioni.rbcs.api.Configuration.User
|
||||
import net.woggioni.rbcs.api.Role
|
||||
import net.woggioni.rbcs.cli.RemoteBuildCacheServerCli
|
||||
import net.woggioni.rbcs.cli.impl.commands.BenchmarkCommand
|
||||
import net.woggioni.rbcs.cli.impl.commands.HealthCheckCommand
|
||||
import net.woggioni.rbcs.client.RemoteBuildCacheClient
|
||||
import net.woggioni.rbcs.common.HostAndPort
|
||||
import net.woggioni.rbcs.common.PasswordSecurity.hashPassword
|
||||
import net.woggioni.rbcs.common.RBCS
|
||||
import net.woggioni.rbcs.common.Xml
|
||||
import net.woggioni.rbcs.server.RemoteBuildCacheServer
|
||||
import net.woggioni.rbcs.server.cache.FileSystemCacheConfiguration
|
||||
import net.woggioni.rbcs.server.cache.InMemoryCacheConfiguration
|
||||
import net.woggioni.rbcs.server.configuration.Parser
|
||||
import net.woggioni.rbcs.server.memcache.MemcacheCacheConfiguration
|
||||
import java.net.URI
|
||||
import java.nio.file.Path
|
||||
import java.time.Duration
|
||||
import java.time.temporal.ChronoUnit
|
||||
import java.util.concurrent.ExecutionException
|
||||
import java.util.zip.Deflater
|
||||
|
||||
object GraalNativeImageConfiguration {
|
||||
@JvmStatic
|
||||
fun main(vararg args : String) {
|
||||
|
||||
val serverDoc = RemoteBuildCacheServer.DEFAULT_CONFIGURATION_URL.openStream().use {
|
||||
Xml.parseXml(RemoteBuildCacheServer.DEFAULT_CONFIGURATION_URL, it)
|
||||
}
|
||||
Parser.parse(doc)
|
||||
|
||||
val clientDoc = RemoteBuildCacheClient.Configuration.openStream().use {
|
||||
Xml.parseXml(RemoteBuildCacheServer.DEFAULT_CONFIGURATION_URL, it)
|
||||
}
|
||||
Parser.parse(doc)
|
||||
|
||||
val PASSWORD = "password"
|
||||
val readersGroup = Configuration.Group("readers", setOf(Role.Reader), null, null)
|
||||
val writersGroup = Configuration.Group("writers", setOf(Role.Writer), null, null)
|
||||
|
||||
|
||||
val users = listOf(
|
||||
User("user1", hashPassword(PASSWORD), setOf(readersGroup), null),
|
||||
User("user2", hashPassword(PASSWORD), setOf(writersGroup), null),
|
||||
User("user3", hashPassword(PASSWORD), setOf(readersGroup, writersGroup), null),
|
||||
User("", null, setOf(readersGroup), null),
|
||||
User("user4", hashPassword(PASSWORD), setOf(readersGroup),
|
||||
Configuration.Quota(1, Duration.of(1, ChronoUnit.DAYS), 0, 1)
|
||||
),
|
||||
User("user5", hashPassword(PASSWORD), setOf(readersGroup),
|
||||
Configuration.Quota(1, Duration.of(5, ChronoUnit.SECONDS), 0, 1)
|
||||
)
|
||||
)
|
||||
|
||||
val serverPort = RBCS.getFreePort()
|
||||
|
||||
val caches = listOf<Configuration.Cache>(
|
||||
InMemoryCacheConfiguration(
|
||||
maxAge = Duration.ofSeconds(3600),
|
||||
digestAlgorithm = "MD5",
|
||||
compressionLevel = Deflater.DEFAULT_COMPRESSION,
|
||||
compressionEnabled = false,
|
||||
maxSize = 0x1000000,
|
||||
chunkSize = 0x1000
|
||||
),
|
||||
FileSystemCacheConfiguration(
|
||||
Path.of(System.getProperty("java.io.tmpdir")).resolve("rbcs"),
|
||||
maxAge = Duration.ofSeconds(3600),
|
||||
digestAlgorithm = "MD5",
|
||||
compressionLevel = Deflater.DEFAULT_COMPRESSION,
|
||||
compressionEnabled = false,
|
||||
chunkSize = 0x1000
|
||||
),
|
||||
MemcacheCacheConfiguration(
|
||||
listOf(MemcacheCacheConfiguration.Server(
|
||||
HostAndPort("127.0.0.1", 11211),
|
||||
1000,
|
||||
4)
|
||||
),
|
||||
Duration.ofSeconds(60),
|
||||
"MD5",
|
||||
null,
|
||||
1,
|
||||
0x1000
|
||||
)
|
||||
)
|
||||
|
||||
for (cache in caches) {
|
||||
val serverConfiguration = Configuration(
|
||||
"127.0.0.1",
|
||||
serverPort,
|
||||
100,
|
||||
null,
|
||||
Configuration.EventExecutor(true),
|
||||
Configuration.Connection(
|
||||
Duration.ofSeconds(10),
|
||||
Duration.ofSeconds(15),
|
||||
Duration.ofSeconds(15),
|
||||
0x10000,
|
||||
),
|
||||
users.asSequence().map { it.name to it }.toMap(),
|
||||
sequenceOf(writersGroup, readersGroup).map { it.name to it }.toMap(),
|
||||
cache,
|
||||
Configuration.BasicAuthentication(),
|
||||
null,
|
||||
)
|
||||
|
||||
MemcacheCacheConfiguration(
|
||||
listOf(
|
||||
MemcacheCacheConfiguration.Server(
|
||||
HostAndPort("127.0.0.1", 11211),
|
||||
1000,
|
||||
4
|
||||
)
|
||||
),
|
||||
Duration.ofSeconds(60),
|
||||
"MD5",
|
||||
null,
|
||||
1,
|
||||
0x1000
|
||||
)
|
||||
|
||||
val serverHandle = RemoteBuildCacheServer(serverConfiguration).run()
|
||||
|
||||
|
||||
val clientProfile = RemoteBuildCacheClient.Configuration.Profile(
|
||||
URI.create("http://127.0.0.1:$serverPort/"),
|
||||
null,
|
||||
RemoteBuildCacheClient.Configuration.Authentication.BasicAuthenticationCredentials("user3", PASSWORD),
|
||||
Duration.ofSeconds(3),
|
||||
10,
|
||||
true,
|
||||
RemoteBuildCacheClient.Configuration.RetryPolicy(
|
||||
3,
|
||||
1000,
|
||||
1.2
|
||||
),
|
||||
RemoteBuildCacheClient.Configuration.TrustStore(null, null, false, false)
|
||||
)
|
||||
|
||||
HealthCheckCommand.run(clientProfile)
|
||||
|
||||
BenchmarkCommand.run(
|
||||
clientProfile,
|
||||
1000,
|
||||
0x100,
|
||||
true
|
||||
)
|
||||
|
||||
serverHandle.sendShutdownSignal()
|
||||
try {
|
||||
serverHandle.get()
|
||||
} catch (ee : ExecutionException) {
|
||||
}
|
||||
}
|
||||
RemoteBuildCacheServerCli.main("--help")
|
||||
}
|
||||
}
|
@@ -23,8 +23,13 @@ class RemoteBuildCacheServerCli : RbcsCommand() {
|
||||
|
||||
class VersionProvider : AbstractVersionProvider()
|
||||
companion object {
|
||||
private fun setPropertyIfNotPresent(key: String, value: String) {
|
||||
System.getProperty(key) ?: System.setProperty(key, value)
|
||||
}
|
||||
@JvmStatic
|
||||
fun main(vararg args: String) {
|
||||
setPropertyIfNotPresent("logback.configurationFile", "net/woggioni/rbcs/cli/logback.xml")
|
||||
setPropertyIfNotPresent("io.netty.leakDetectionLevel", "DISABLED")
|
||||
val currentClassLoader = RemoteBuildCacheServerCli::class.java.classLoader
|
||||
Thread.currentThread().contextClassLoader = currentClassLoader
|
||||
if(currentClassLoader.javaClass.name == "net.woggioni.envelope.loader.ModuleClassLoader") {
|
||||
|
@@ -26,52 +26,25 @@ import kotlin.random.Random
|
||||
showDefaultValues = true
|
||||
)
|
||||
class BenchmarkCommand : RbcsCommand() {
|
||||
companion object{
|
||||
companion object {
|
||||
private val log = createLogger<BenchmarkCommand>()
|
||||
}
|
||||
|
||||
@CommandLine.Spec
|
||||
private lateinit var spec: CommandLine.Model.CommandSpec
|
||||
|
||||
@CommandLine.Option(
|
||||
names = ["-e", "--entries"],
|
||||
description = ["Total number of elements to be added to the cache"],
|
||||
paramLabel = "NUMBER_OF_ENTRIES"
|
||||
)
|
||||
private var numberOfEntries = 1000
|
||||
|
||||
@CommandLine.Option(
|
||||
names = ["-s", "--size"],
|
||||
description = ["Size of a cache value in bytes"],
|
||||
paramLabel = "SIZE",
|
||||
converter = [ByteSizeConverter::class]
|
||||
)
|
||||
private var size = 0x1000
|
||||
|
||||
@CommandLine.Option(
|
||||
names = ["-r", "--random"],
|
||||
description = ["Insert completely random byte values"]
|
||||
)
|
||||
private var randomValues = false
|
||||
|
||||
override fun run() {
|
||||
val clientCommand = spec.parent().userObject() as ClientCommand
|
||||
val profile = clientCommand.profileName.let { profileName ->
|
||||
clientCommand.configuration.profiles[profileName]
|
||||
?: throw IllegalArgumentException("Profile $profileName does not exist in configuration")
|
||||
}
|
||||
fun run(profile : RemoteBuildCacheClient.Configuration.Profile,
|
||||
numberOfEntries : Int,
|
||||
entrySize : Int,
|
||||
useRandomValue : Boolean,
|
||||
) {
|
||||
val progressThreshold = LongMath.ceilDiv(numberOfEntries.toLong(), 20)
|
||||
RemoteBuildCacheClient(profile).use { client ->
|
||||
|
||||
val entryGenerator = sequence {
|
||||
val random = Random(SecureRandom.getInstance("NativePRNGNonBlocking").nextLong())
|
||||
while (true) {
|
||||
val key = JWO.bytesToHex(random.nextBytes(16))
|
||||
val value = if(randomValues) {
|
||||
random.nextBytes(size)
|
||||
val value = if (useRandomValue) {
|
||||
random.nextBytes(entrySize)
|
||||
} else {
|
||||
val byteValue = random.nextInt().toByte()
|
||||
ByteArray(size) {_ -> byteValue}
|
||||
ByteArray(entrySize) { _ -> byteValue }
|
||||
}
|
||||
yield(key to value)
|
||||
}
|
||||
@@ -90,7 +63,8 @@ class BenchmarkCommand : RbcsCommand() {
|
||||
if (iterator.hasNext()) {
|
||||
val entry = iterator.next()
|
||||
semaphore.acquire()
|
||||
val future = client.put(entry.first, entry.second, CacheValueMetadata(null, null)).thenApply { entry }
|
||||
val future =
|
||||
client.put(entry.first, entry.second, CacheValueMetadata(null, null)).thenApply { entry }
|
||||
future.whenComplete { result, ex ->
|
||||
if (ex != null) {
|
||||
log.error(ex.message, ex)
|
||||
@@ -99,7 +73,7 @@ class BenchmarkCommand : RbcsCommand() {
|
||||
}
|
||||
semaphore.release()
|
||||
val completed = completionCounter.incrementAndGet()
|
||||
if(completed.mod(progressThreshold) == 0L) {
|
||||
if (completed.mod(progressThreshold) == 0L) {
|
||||
log.debug {
|
||||
"Inserted $completed / $numberOfEntries"
|
||||
}
|
||||
@@ -147,7 +121,7 @@ class BenchmarkCommand : RbcsCommand() {
|
||||
}
|
||||
future.whenComplete { _, _ ->
|
||||
val completed = completionCounter.incrementAndGet()
|
||||
if(completed.mod(progressThreshold) == 0L) {
|
||||
if (completed.mod(progressThreshold) == 0L) {
|
||||
log.debug {
|
||||
"Retrieved $completed / ${entries.size}"
|
||||
}
|
||||
@@ -169,4 +143,43 @@ class BenchmarkCommand : RbcsCommand() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@CommandLine.Spec
|
||||
private lateinit var spec: CommandLine.Model.CommandSpec
|
||||
|
||||
@CommandLine.Option(
|
||||
names = ["-e", "--entries"],
|
||||
description = ["Total number of elements to be added to the cache"],
|
||||
paramLabel = "NUMBER_OF_ENTRIES"
|
||||
)
|
||||
private var numberOfEntries = 1000
|
||||
|
||||
@CommandLine.Option(
|
||||
names = ["-s", "--size"],
|
||||
description = ["Size of a cache value in bytes"],
|
||||
paramLabel = "SIZE",
|
||||
converter = [ByteSizeConverter::class]
|
||||
)
|
||||
private var size = 0x1000
|
||||
|
||||
@CommandLine.Option(
|
||||
names = ["-r", "--random"],
|
||||
description = ["Insert completely random byte values"]
|
||||
)
|
||||
private var randomValues = false
|
||||
|
||||
override fun run() {
|
||||
val clientCommand = spec.parent().userObject() as ClientCommand
|
||||
val profile = clientCommand.profileName.let { profileName ->
|
||||
clientCommand.configuration.profiles[profileName]
|
||||
?: throw IllegalArgumentException("Profile $profileName does not exist in configuration")
|
||||
}
|
||||
run(
|
||||
profile,
|
||||
numberOfEntries,
|
||||
size,
|
||||
randomValues
|
||||
)
|
||||
}
|
||||
}
|
@@ -15,17 +15,8 @@ import kotlin.random.Random
|
||||
class HealthCheckCommand : RbcsCommand() {
|
||||
companion object{
|
||||
private val log = createLogger<HealthCheckCommand>()
|
||||
}
|
||||
|
||||
@CommandLine.Spec
|
||||
private lateinit var spec: CommandLine.Model.CommandSpec
|
||||
|
||||
override fun run() {
|
||||
val clientCommand = spec.parent().userObject() as ClientCommand
|
||||
val profile = clientCommand.profileName.let { profileName ->
|
||||
clientCommand.configuration.profiles[profileName]
|
||||
?: throw IllegalArgumentException("Profile $profileName does not exist in configuration")
|
||||
}
|
||||
fun run(profile : RemoteBuildCacheClient.Configuration.Profile) {
|
||||
RemoteBuildCacheClient(profile).use { client ->
|
||||
val random = Random(SecureRandom.getInstance("NativePRNGNonBlocking").nextLong())
|
||||
val nonce = ByteArray(0xa0)
|
||||
@@ -45,4 +36,17 @@ class HealthCheckCommand : RbcsCommand() {
|
||||
}.get()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@CommandLine.Spec
|
||||
private lateinit var spec: CommandLine.Model.CommandSpec
|
||||
|
||||
override fun run() {
|
||||
val clientCommand = spec.parent().userObject() as ClientCommand
|
||||
val profile = clientCommand.profileName.let { profileName ->
|
||||
clientCommand.configuration.profiles[profileName]
|
||||
?: throw IllegalArgumentException("Profile $profileName does not exist in configuration")
|
||||
}
|
||||
run(profile)
|
||||
}
|
||||
}
|
@@ -37,6 +37,7 @@ import io.netty.util.concurrent.Future
|
||||
import io.netty.util.concurrent.GenericFutureListener
|
||||
import net.woggioni.rbcs.api.CacheValueMetadata
|
||||
import net.woggioni.rbcs.client.impl.Parser
|
||||
import net.woggioni.rbcs.common.RBCS.loadKeystore
|
||||
import net.woggioni.rbcs.common.Xml
|
||||
import net.woggioni.rbcs.common.createLogger
|
||||
import net.woggioni.rbcs.common.debug
|
||||
@@ -54,6 +55,8 @@ import java.util.concurrent.CompletableFuture
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.TimeoutException
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import javax.net.ssl.TrustManagerFactory
|
||||
import javax.net.ssl.X509TrustManager
|
||||
import kotlin.random.Random
|
||||
import io.netty.util.concurrent.Future as NettyFuture
|
||||
|
||||
@@ -63,7 +66,7 @@ class RemoteBuildCacheClient(private val profile: Configuration.Profile) : AutoC
|
||||
}
|
||||
|
||||
private val group: NioEventLoopGroup
|
||||
private var sslContext: SslContext
|
||||
private val sslContext: SslContext
|
||||
private val pool: ChannelPool
|
||||
|
||||
data class Configuration(
|
||||
@@ -78,6 +81,13 @@ class RemoteBuildCacheClient(private val profile: Configuration.Profile) : AutoC
|
||||
data class BasicAuthenticationCredentials(val username: String, val password: String) : Authentication()
|
||||
}
|
||||
|
||||
class TrustStore (
|
||||
var file: Path?,
|
||||
var password: String?,
|
||||
var checkCertificateStatus: Boolean = false,
|
||||
var verifyServerCertificate: Boolean = true,
|
||||
)
|
||||
|
||||
class RetryPolicy(
|
||||
val maxAttempts: Int,
|
||||
val initialDelayMillis: Long,
|
||||
@@ -100,6 +110,7 @@ class RemoteBuildCacheClient(private val profile: Configuration.Profile) : AutoC
|
||||
val maxConnections: Int,
|
||||
val compressionEnabled: Boolean,
|
||||
val retryPolicy: RetryPolicy?,
|
||||
val tlsTruststore : TrustStore?
|
||||
)
|
||||
|
||||
companion object {
|
||||
@@ -115,10 +126,33 @@ class RemoteBuildCacheClient(private val profile: Configuration.Profile) : AutoC
|
||||
group = NioEventLoopGroup()
|
||||
sslContext = SslContextBuilder.forClient().also { builder ->
|
||||
(profile.authentication as? Configuration.Authentication.TlsClientAuthenticationCredentials)?.let { tlsClientAuthenticationCredentials ->
|
||||
builder.keyManager(
|
||||
builder.apply {
|
||||
keyManager(
|
||||
tlsClientAuthenticationCredentials.key,
|
||||
*tlsClientAuthenticationCredentials.certificateChain
|
||||
)
|
||||
profile.tlsTruststore?.let { trustStore ->
|
||||
if(!trustStore.verifyServerCertificate) {
|
||||
trustManager(object : X509TrustManager {
|
||||
override fun checkClientTrusted(certChain: Array<out X509Certificate>, p1: String?) {
|
||||
}
|
||||
|
||||
override fun checkServerTrusted(certChain: Array<out X509Certificate>, p1: String?) {
|
||||
}
|
||||
|
||||
override fun getAcceptedIssuers() = null
|
||||
})
|
||||
} else {
|
||||
trustStore.file?.let {
|
||||
val ts = loadKeystore(it, trustStore.password)
|
||||
val trustManagerFactory: TrustManagerFactory =
|
||||
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
|
||||
trustManagerFactory.init(ts)
|
||||
trustManager(trustManagerFactory)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.build()
|
||||
|
||||
|
@@ -31,6 +31,7 @@ object Parser {
|
||||
var authentication: RemoteBuildCacheClient.Configuration.Authentication? = null
|
||||
var retryPolicy: RemoteBuildCacheClient.Configuration.RetryPolicy? = null
|
||||
var connection : RemoteBuildCacheClient.Configuration.Connection? = null
|
||||
var trustStore : RemoteBuildCacheClient.Configuration.TrustStore? = null
|
||||
for (gchild in child.asIterable()) {
|
||||
when (gchild.localName) {
|
||||
"tls-client-auth" -> {
|
||||
@@ -108,6 +109,17 @@ object Parser {
|
||||
writeIdleTimeout,
|
||||
)
|
||||
}
|
||||
|
||||
"tls-trust-store" -> {
|
||||
val file = gchild.renderAttribute("file")
|
||||
?.let(Path::of)
|
||||
val password = gchild.renderAttribute("password")
|
||||
val checkCertificateStatus = gchild.renderAttribute("check-certificate-status")
|
||||
?.let(String::toBoolean) ?: false
|
||||
val verifyServerCertificate = gchild.renderAttribute("verify-server-certificate")
|
||||
?.let(String::toBoolean) ?: true
|
||||
trustStore = RemoteBuildCacheClient.Configuration.TrustStore(file, password, checkCertificateStatus, verifyServerCertificate)
|
||||
}
|
||||
}
|
||||
}
|
||||
val maxConnections = child.renderAttribute("max-connections")
|
||||
@@ -126,7 +138,8 @@ object Parser {
|
||||
connectionTimeout,
|
||||
maxConnections,
|
||||
compressionEnabled,
|
||||
retryPolicy
|
||||
retryPolicy,
|
||||
trustStore
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@@ -21,6 +21,7 @@
|
||||
</xs:choice>
|
||||
<xs:element name="connection" type="rbcs-client:connectionType" minOccurs="0" />
|
||||
<xs:element name="retry-policy" type="rbcs-client:retryType" minOccurs="0"/>
|
||||
<xs:element name="tls-trust-store" type="rbcs-client:trustStoreType" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="name" type="xs:token" use="required"/>
|
||||
<xs:attribute name="base-url" type="xs:anyURI" use="required"/>
|
||||
@@ -57,4 +58,34 @@
|
||||
<xs:attribute name="exp" type="xs:double" default="2.0"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="trustStoreType">
|
||||
<xs:attribute name="file" type="xs:string" use="required">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
Path to the trustore file
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="password" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
Trustore file password
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="check-certificate-status" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
Whether or not check the certificate validity using CRL/OCSP
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="verify-server-certificate" type="xs:boolean" use="optional" default="true">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
If false, the client will blindly trust the provided server certificate
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
||||
|
@@ -129,7 +129,7 @@ class RetryTest {
|
||||
previousAttempt.first + testArgs.initialDelay * Math.pow(testArgs.exp, index.toDouble()) * 1e6
|
||||
val actualTimestamp = timestamp
|
||||
val err = Math.abs(expectedTimestamp - actualTimestamp) / expectedTimestamp
|
||||
Assertions.assertTrue(err < 1e-2)
|
||||
Assertions.assertTrue(err < 0.1)
|
||||
}
|
||||
if (index == attempts.size - 1 && index < testArgs.maxAttempt - 1) {
|
||||
/*
|
||||
|
@@ -9,6 +9,8 @@
|
||||
key-store-password="password"
|
||||
key-alias="woggioni@c962475fa38"
|
||||
key-password="key-password"/>
|
||||
<connection write-idle-timeout="PT60S" read-idle-timeout="PT60S" write-timeout="PT0S" read-timeout="PT0S" idle-timeout="PT30S" />
|
||||
<tls-trust-store file="file.pfx" password="password" check-certificate-status="false" verify-server-certificate="true"/>
|
||||
</profile>
|
||||
<profile name="profile2" base-url="https://rbcs2.example.com/">
|
||||
<basic-auth user="user" password="password"/>
|
||||
|
@@ -1,9 +1,26 @@
|
||||
package net.woggioni.rbcs.common
|
||||
|
||||
import net.woggioni.jwo.JWO
|
||||
import net.woggioni.jwo.Tuple2
|
||||
import java.io.IOException
|
||||
import java.net.InetAddress
|
||||
import java.net.ServerSocket
|
||||
import java.net.URI
|
||||
import java.net.URL
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.security.KeyStore
|
||||
import java.security.MessageDigest
|
||||
import java.security.cert.CertPathValidator
|
||||
import java.security.cert.CertPathValidatorException
|
||||
import java.security.cert.CertificateException
|
||||
import java.security.cert.CertificateFactory
|
||||
import java.security.cert.PKIXParameters
|
||||
import java.security.cert.PKIXRevocationChecker
|
||||
import java.security.cert.X509Certificate
|
||||
import java.util.EnumSet
|
||||
import javax.net.ssl.TrustManagerFactory
|
||||
import javax.net.ssl.X509TrustManager
|
||||
|
||||
object RBCS {
|
||||
fun String.toUrl() : URL = URL.of(URI(this), null)
|
||||
@@ -32,7 +49,7 @@ object RBCS {
|
||||
|
||||
fun digest(
|
||||
data: ByteArray,
|
||||
md: MessageDigest = MessageDigest.getInstance("MD5")
|
||||
md: MessageDigest
|
||||
): ByteArray {
|
||||
md.update(data)
|
||||
return md.digest()
|
||||
@@ -40,7 +57,7 @@ object RBCS {
|
||||
|
||||
fun digestString(
|
||||
data: ByteArray,
|
||||
md: MessageDigest = MessageDigest.getInstance("MD5")
|
||||
md: MessageDigest
|
||||
): String {
|
||||
return JWO.bytesToHex(digest(data, md))
|
||||
}
|
||||
@@ -58,4 +75,86 @@ object RBCS {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun getFreePort(): Int {
|
||||
var count = 0
|
||||
while (count < 50) {
|
||||
try {
|
||||
ServerSocket(0, 50, InetAddress.getLocalHost()).use { serverSocket ->
|
||||
val candidate = serverSocket.localPort
|
||||
if (candidate > 0) {
|
||||
return candidate
|
||||
} else {
|
||||
throw RuntimeException("Got invalid port number: $candidate")
|
||||
}
|
||||
}
|
||||
} catch (ignored: IOException) {
|
||||
++count
|
||||
}
|
||||
}
|
||||
throw RuntimeException("Error trying to find an open port")
|
||||
}
|
||||
|
||||
fun loadKeystore(file: Path, password: String?): KeyStore {
|
||||
val ext = JWO.splitExtension(file)
|
||||
.map(Tuple2<String, String>::get_2)
|
||||
.orElseThrow {
|
||||
IllegalArgumentException(
|
||||
"Keystore file '${file}' must have .jks, .p12, .pfx extension"
|
||||
)
|
||||
}
|
||||
val keystore = when (ext.substring(1).lowercase()) {
|
||||
"jks" -> KeyStore.getInstance("JKS")
|
||||
"p12", "pfx" -> KeyStore.getInstance("PKCS12")
|
||||
else -> throw IllegalArgumentException(
|
||||
"Keystore file '${file}' must have .jks, .p12, .pfx extension"
|
||||
)
|
||||
}
|
||||
Files.newInputStream(file).use {
|
||||
keystore.load(it, password?.let(String::toCharArray))
|
||||
}
|
||||
return keystore
|
||||
}
|
||||
|
||||
fun getTrustManager(trustStore: KeyStore?, certificateRevocationEnabled: Boolean): X509TrustManager {
|
||||
return if (trustStore != null) {
|
||||
val certificateFactory = CertificateFactory.getInstance("X.509")
|
||||
val validator = CertPathValidator.getInstance("PKIX").apply {
|
||||
val rc = revocationChecker as PKIXRevocationChecker
|
||||
rc.options = EnumSet.of(
|
||||
PKIXRevocationChecker.Option.NO_FALLBACK
|
||||
)
|
||||
}
|
||||
val params = PKIXParameters(trustStore).apply {
|
||||
isRevocationEnabled = certificateRevocationEnabled
|
||||
}
|
||||
object : X509TrustManager {
|
||||
override fun checkClientTrusted(chain: Array<out X509Certificate>, authType: String) {
|
||||
val clientCertificateChain = certificateFactory.generateCertPath(chain.toList())
|
||||
try {
|
||||
validator.validate(clientCertificateChain, params)
|
||||
} catch (ex: CertPathValidatorException) {
|
||||
throw CertificateException(ex)
|
||||
}
|
||||
}
|
||||
|
||||
override fun checkServerTrusted(chain: Array<out X509Certificate>, authType: String) {
|
||||
throw NotImplementedError()
|
||||
}
|
||||
|
||||
private val acceptedIssuers = trustStore.aliases().asSequence()
|
||||
.filter(trustStore::isCertificateEntry)
|
||||
.map(trustStore::getCertificate)
|
||||
.map { it as X509Certificate }
|
||||
.toList()
|
||||
.toTypedArray()
|
||||
|
||||
override fun getAcceptedIssuers() = acceptedIssuers
|
||||
}
|
||||
} else {
|
||||
val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
|
||||
trustManagerFactory.trustManagers.asSequence().filter { it is X509TrustManager }
|
||||
.single() as X509TrustManager
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,10 +1,20 @@
|
||||
package net.woggioni.rbcs.server.memcache
|
||||
|
||||
import io.netty.channel.ChannelFactory
|
||||
import io.netty.channel.ChannelHandler
|
||||
import io.netty.channel.EventLoopGroup
|
||||
import io.netty.channel.pool.FixedChannelPool
|
||||
import io.netty.channel.socket.DatagramChannel
|
||||
import io.netty.channel.socket.SocketChannel
|
||||
import net.woggioni.rbcs.api.CacheHandlerFactory
|
||||
import net.woggioni.rbcs.api.Configuration
|
||||
import net.woggioni.rbcs.common.HostAndPort
|
||||
import net.woggioni.rbcs.server.memcache.client.MemcacheClient
|
||||
import java.time.Duration
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
data class MemcacheCacheConfiguration(
|
||||
val servers: List<Server>,
|
||||
@@ -12,7 +22,7 @@ data class MemcacheCacheConfiguration(
|
||||
val digestAlgorithm: String? = null,
|
||||
val compressionMode: CompressionMode? = null,
|
||||
val compressionLevel: Int,
|
||||
val chunkSize : Int
|
||||
val chunkSize: Int
|
||||
) : Configuration.Cache {
|
||||
|
||||
enum class CompressionMode {
|
||||
@@ -23,19 +33,58 @@ data class MemcacheCacheConfiguration(
|
||||
}
|
||||
|
||||
data class Server(
|
||||
val endpoint : HostAndPort,
|
||||
val connectionTimeoutMillis : Int?,
|
||||
val maxConnections : Int
|
||||
val endpoint: HostAndPort,
|
||||
val connectionTimeoutMillis: Int?,
|
||||
val maxConnections: Int
|
||||
)
|
||||
|
||||
|
||||
override fun materialize() = object : CacheHandlerFactory {
|
||||
private val client = MemcacheClient(this@MemcacheCacheConfiguration.servers, chunkSize)
|
||||
override fun close() {
|
||||
client.close()
|
||||
|
||||
private val connectionPoolMap = ConcurrentHashMap<HostAndPort, FixedChannelPool>()
|
||||
|
||||
override fun newHandler(
|
||||
eventLoop: EventLoopGroup,
|
||||
socketChannelFactory: ChannelFactory<SocketChannel>,
|
||||
datagramChannelFactory: ChannelFactory<DatagramChannel>
|
||||
): ChannelHandler {
|
||||
return MemcacheCacheHandler(
|
||||
MemcacheClient(
|
||||
this@MemcacheCacheConfiguration.servers,
|
||||
chunkSize,
|
||||
eventLoop,
|
||||
socketChannelFactory,
|
||||
connectionPoolMap
|
||||
),
|
||||
digestAlgorithm,
|
||||
compressionMode != null,
|
||||
compressionLevel,
|
||||
chunkSize,
|
||||
maxAge
|
||||
)
|
||||
}
|
||||
|
||||
override fun asyncClose() = object : CompletableFuture<Void>() {
|
||||
init {
|
||||
val failure = AtomicReference<Throwable>(null)
|
||||
val pools = connectionPoolMap.values.toList()
|
||||
val npools = pools.size
|
||||
val finished = AtomicInteger(0)
|
||||
pools.forEach { pool ->
|
||||
pool.closeAsync().addListener {
|
||||
if (!it.isSuccess) {
|
||||
failure.compareAndSet(null, it.cause())
|
||||
}
|
||||
if(finished.incrementAndGet() == npools) {
|
||||
when(val ex = failure.get()) {
|
||||
null -> complete(null)
|
||||
else -> completeExceptionally(ex)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun newHandler() = MemcacheCacheHandler(client, digestAlgorithm, compressionMode != null, compressionLevel, chunkSize, maxAge)
|
||||
}
|
||||
|
||||
override fun getNamespaceURI() = "urn:net.woggioni.rbcs.server.memcache"
|
||||
|
@@ -4,16 +4,17 @@ package net.woggioni.rbcs.server.memcache.client
|
||||
import io.netty.bootstrap.Bootstrap
|
||||
import io.netty.buffer.ByteBuf
|
||||
import io.netty.channel.Channel
|
||||
import io.netty.channel.ChannelFactory
|
||||
import io.netty.channel.ChannelFutureListener
|
||||
import io.netty.channel.ChannelHandlerContext
|
||||
import io.netty.channel.ChannelOption
|
||||
import io.netty.channel.ChannelPipeline
|
||||
import io.netty.channel.EventLoopGroup
|
||||
import io.netty.channel.SimpleChannelInboundHandler
|
||||
import io.netty.channel.nio.NioEventLoopGroup
|
||||
import io.netty.channel.pool.AbstractChannelPoolHandler
|
||||
import io.netty.channel.pool.ChannelPool
|
||||
import io.netty.channel.pool.FixedChannelPool
|
||||
import io.netty.channel.socket.nio.NioSocketChannel
|
||||
import io.netty.channel.socket.SocketChannel
|
||||
import io.netty.handler.codec.memcache.LastMemcacheContent
|
||||
import io.netty.handler.codec.memcache.MemcacheContent
|
||||
import io.netty.handler.codec.memcache.MemcacheObject
|
||||
@@ -33,23 +34,22 @@ import java.util.concurrent.ConcurrentHashMap
|
||||
import io.netty.util.concurrent.Future as NettyFuture
|
||||
|
||||
|
||||
class MemcacheClient(private val servers: List<MemcacheCacheConfiguration.Server>, private val chunkSize : Int) : AutoCloseable {
|
||||
class MemcacheClient(
|
||||
private val servers: List<MemcacheCacheConfiguration.Server>,
|
||||
private val chunkSize : Int,
|
||||
private val group: EventLoopGroup,
|
||||
private val channelFactory: ChannelFactory<SocketChannel>,
|
||||
private val connectionPool: ConcurrentHashMap<HostAndPort, FixedChannelPool>
|
||||
) : AutoCloseable {
|
||||
|
||||
private companion object {
|
||||
private val log = createLogger<MemcacheCacheHandler>()
|
||||
}
|
||||
|
||||
private val group: NioEventLoopGroup
|
||||
private val connectionPool: MutableMap<HostAndPort, ChannelPool> = ConcurrentHashMap()
|
||||
|
||||
init {
|
||||
group = NioEventLoopGroup()
|
||||
}
|
||||
|
||||
private fun newConnectionPool(server: MemcacheCacheConfiguration.Server): FixedChannelPool {
|
||||
val bootstrap = Bootstrap().apply {
|
||||
group(group)
|
||||
channel(NioSocketChannel::class.java)
|
||||
channelFactory(channelFactory)
|
||||
option(ChannelOption.SO_KEEPALIVE, true)
|
||||
remoteAddress(InetSocketAddress(server.endpoint.host, server.endpoint.port))
|
||||
server.connectionTimeoutMillis?.let {
|
||||
|
@@ -21,7 +21,7 @@
|
||||
</xs:sequence>
|
||||
<xs:attribute name="max-age" type="xs:duration" default="P1D"/>
|
||||
<xs:attribute name="chunk-size" type="rbcs:byteSizeType" default="0x10000"/>
|
||||
<xs:attribute name="digest" type="xs:token" />
|
||||
<xs:attribute name="digest" type="xs:token"/>
|
||||
<xs:attribute name="compression-mode" type="rbcs-memcache:compressionType"/>
|
||||
<xs:attribute name="compression-level" type="rbcs:compressionLevelType" default="-1"/>
|
||||
</xs:extension>
|
||||
|
@@ -3,6 +3,7 @@ package net.woggioni.rbcs.server
|
||||
import io.netty.bootstrap.ServerBootstrap
|
||||
import io.netty.buffer.ByteBuf
|
||||
import io.netty.channel.Channel
|
||||
import io.netty.channel.ChannelFactory
|
||||
import io.netty.channel.ChannelFuture
|
||||
import io.netty.channel.ChannelHandler.Sharable
|
||||
import io.netty.channel.ChannelHandlerContext
|
||||
@@ -11,7 +12,12 @@ import io.netty.channel.ChannelInitializer
|
||||
import io.netty.channel.ChannelOption
|
||||
import io.netty.channel.ChannelPromise
|
||||
import io.netty.channel.nio.NioEventLoopGroup
|
||||
import io.netty.channel.socket.DatagramChannel
|
||||
import io.netty.channel.socket.ServerSocketChannel
|
||||
import io.netty.channel.socket.SocketChannel
|
||||
import io.netty.channel.socket.nio.NioDatagramChannel
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel
|
||||
import io.netty.channel.socket.nio.NioSocketChannel
|
||||
import io.netty.handler.codec.compression.CompressionOptions
|
||||
import io.netty.handler.codec.http.DefaultHttpContent
|
||||
import io.netty.handler.codec.http.HttpContentCompressor
|
||||
@@ -29,12 +35,13 @@ import io.netty.handler.timeout.IdleStateHandler
|
||||
import io.netty.util.AttributeKey
|
||||
import io.netty.util.concurrent.DefaultEventExecutorGroup
|
||||
import io.netty.util.concurrent.EventExecutorGroup
|
||||
import net.woggioni.jwo.JWO
|
||||
import net.woggioni.jwo.Tuple2
|
||||
import net.woggioni.rbcs.api.AsyncCloseable
|
||||
import net.woggioni.rbcs.api.Configuration
|
||||
import net.woggioni.rbcs.api.exception.ConfigurationException
|
||||
import net.woggioni.rbcs.common.PasswordSecurity.decodePasswordHash
|
||||
import net.woggioni.rbcs.common.PasswordSecurity.hashPassword
|
||||
import net.woggioni.rbcs.common.RBCS.getTrustManager
|
||||
import net.woggioni.rbcs.common.RBCS.loadKeystore
|
||||
import net.woggioni.rbcs.common.RBCS.toUrl
|
||||
import net.woggioni.rbcs.common.Xml
|
||||
import net.woggioni.rbcs.common.createLogger
|
||||
@@ -42,7 +49,6 @@ import net.woggioni.rbcs.common.debug
|
||||
import net.woggioni.rbcs.common.info
|
||||
import net.woggioni.rbcs.server.auth.AbstractNettyHttpAuthenticator
|
||||
import net.woggioni.rbcs.server.auth.Authorizer
|
||||
import net.woggioni.rbcs.server.auth.ClientCertificateValidator
|
||||
import net.woggioni.rbcs.server.auth.RoleAuthorizer
|
||||
import net.woggioni.rbcs.server.configuration.Parser
|
||||
import net.woggioni.rbcs.server.configuration.Serializer
|
||||
@@ -56,7 +62,6 @@ import java.io.OutputStream
|
||||
import java.net.InetSocketAddress
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.security.KeyStore
|
||||
import java.security.PrivateKey
|
||||
import java.security.cert.X509Certificate
|
||||
import java.time.Duration
|
||||
@@ -80,7 +85,7 @@ class RemoteBuildCacheServer(private val cfg: Configuration) {
|
||||
val userAttribute: AttributeKey<Configuration.User> = AttributeKey.valueOf("user")
|
||||
val groupAttribute: AttributeKey<Set<Configuration.Group>> = AttributeKey.valueOf("group")
|
||||
|
||||
val DEFAULT_CONFIGURATION_URL by lazy { "classpath:net/woggioni/rbcs/server/rbcs-default.xml".toUrl() }
|
||||
val DEFAULT_CONFIGURATION_URL by lazy { "jpms://net.woggioni.rbcs.server/net/woggioni/rbcs/server/rbcs-default.xml".toUrl() }
|
||||
private const val SSL_HANDLER_NAME = "sslHandler"
|
||||
|
||||
fun loadConfiguration(configurationFile: Path): Configuration {
|
||||
@@ -200,8 +205,10 @@ class RemoteBuildCacheServer(private val cfg: Configuration) {
|
||||
|
||||
private class ServerInitializer(
|
||||
private val cfg: Configuration,
|
||||
private val channelFactory : ChannelFactory<SocketChannel>,
|
||||
private val datagramChannelFactory : ChannelFactory<DatagramChannel>,
|
||||
private val eventExecutorGroup: EventExecutorGroup
|
||||
) : ChannelInitializer<Channel>(), AutoCloseable {
|
||||
) : ChannelInitializer<Channel>(), AsyncCloseable {
|
||||
|
||||
companion object {
|
||||
private fun createSslCtx(tls: Configuration.Tls): SslContext {
|
||||
@@ -221,7 +228,7 @@ class RemoteBuildCacheServer(private val cfg: Configuration) {
|
||||
val clientAuth = tls.trustStore?.let { trustStore ->
|
||||
val ts = loadKeystore(trustStore.file, trustStore.password)
|
||||
trustManager(
|
||||
ClientCertificateValidator.getTrustManager(ts, trustStore.isCheckCertificateStatus)
|
||||
getTrustManager(ts, trustStore.isCheckCertificateStatus)
|
||||
)
|
||||
if (trustStore.isRequireClientCertificate) ClientAuth.REQUIRE
|
||||
else ClientAuth.OPTIONAL
|
||||
@@ -231,27 +238,6 @@ class RemoteBuildCacheServer(private val cfg: Configuration) {
|
||||
}
|
||||
}
|
||||
|
||||
fun loadKeystore(file: Path, password: String?): KeyStore {
|
||||
val ext = JWO.splitExtension(file)
|
||||
.map(Tuple2<String, String>::get_2)
|
||||
.orElseThrow {
|
||||
IllegalArgumentException(
|
||||
"Keystore file '${file}' must have .jks, .p12, .pfx extension"
|
||||
)
|
||||
}
|
||||
val keystore = when (ext.substring(1).lowercase()) {
|
||||
"jks" -> KeyStore.getInstance("JKS")
|
||||
"p12", "pfx" -> KeyStore.getInstance("PKCS12")
|
||||
else -> throw IllegalArgumentException(
|
||||
"Keystore file '${file}' must have .jks, .p12, .pfx extension"
|
||||
)
|
||||
}
|
||||
Files.newInputStream(file).use {
|
||||
keystore.load(it, password?.let(String::toCharArray))
|
||||
}
|
||||
return keystore
|
||||
}
|
||||
|
||||
private val log = createLogger<ServerInitializer>()
|
||||
}
|
||||
|
||||
@@ -368,21 +354,20 @@ class RemoteBuildCacheServer(private val cfg: Configuration) {
|
||||
ServerHandler(prefix)
|
||||
}
|
||||
pipeline.addLast(eventExecutorGroup, ServerHandler.NAME, serverHandler)
|
||||
pipeline.addLast(cacheHandlerFactory.newHandler())
|
||||
|
||||
pipeline.addLast(cacheHandlerFactory.newHandler(ch.eventLoop(), channelFactory, datagramChannelFactory))
|
||||
pipeline.addLast(TraceHandler)
|
||||
pipeline.addLast(ExceptionHandler)
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
cacheHandlerFactory.close()
|
||||
}
|
||||
override fun asyncClose() = cacheHandlerFactory.asyncClose()
|
||||
}
|
||||
|
||||
class ServerHandle(
|
||||
closeFuture: ChannelFuture,
|
||||
private val bossGroup: EventExecutorGroup,
|
||||
private val executorGroups: Iterable<EventExecutorGroup>,
|
||||
private val serverInitializer: AutoCloseable,
|
||||
private val serverInitializer: AsyncCloseable,
|
||||
) : Future<Void> by from(closeFuture, executorGroups, serverInitializer) {
|
||||
|
||||
companion object {
|
||||
@@ -391,13 +376,28 @@ class RemoteBuildCacheServer(private val cfg: Configuration) {
|
||||
private fun from(
|
||||
closeFuture: ChannelFuture,
|
||||
executorGroups: Iterable<EventExecutorGroup>,
|
||||
serverInitializer: AutoCloseable
|
||||
serverInitializer: AsyncCloseable
|
||||
): CompletableFuture<Void> {
|
||||
val result = CompletableFuture<Void>()
|
||||
closeFuture.addListener {
|
||||
val errors = mutableListOf<Throwable>()
|
||||
val deadline = Instant.now().plusSeconds(20)
|
||||
try {
|
||||
serverInitializer.close()
|
||||
} catch (ex: Throwable) {
|
||||
log.error(ex.message, ex)
|
||||
errors.addLast(ex)
|
||||
}
|
||||
|
||||
serverInitializer.asyncClose().whenComplete { _, ex ->
|
||||
if(ex != null) {
|
||||
log.error(ex.message, ex)
|
||||
errors.addLast(ex)
|
||||
}
|
||||
|
||||
executorGroups.map {
|
||||
it.shutdownGracefully()
|
||||
}
|
||||
|
||||
for (executorGroup in executorGroups) {
|
||||
val future = executorGroup.terminationFuture()
|
||||
@@ -417,18 +417,14 @@ class RemoteBuildCacheServer(private val cfg: Configuration) {
|
||||
errors.addLast(ex)
|
||||
}
|
||||
}
|
||||
try {
|
||||
serverInitializer.close()
|
||||
} catch (ex: Throwable) {
|
||||
log.error(ex.message, ex)
|
||||
errors.addLast(ex)
|
||||
}
|
||||
|
||||
if(errors.isEmpty()) {
|
||||
result.complete(null)
|
||||
} else {
|
||||
result.completeExceptionally(errors.first())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result.thenAccept {
|
||||
log.info {
|
||||
@@ -441,16 +437,15 @@ class RemoteBuildCacheServer(private val cfg: Configuration) {
|
||||
|
||||
fun sendShutdownSignal() {
|
||||
bossGroup.shutdownGracefully()
|
||||
executorGroups.map {
|
||||
it.shutdownGracefully()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun run(): ServerHandle {
|
||||
// Create the multithreaded event loops for the server
|
||||
val bossGroup = NioEventLoopGroup(1)
|
||||
val serverSocketChannel = NioServerSocketChannel::class.java
|
||||
val channelFactory = ChannelFactory<SocketChannel> { NioSocketChannel() }
|
||||
val datagramChannelFactory = ChannelFactory<DatagramChannel> { NioDatagramChannel() }
|
||||
val serverChannelFactory = ChannelFactory<ServerSocketChannel> { NioServerSocketChannel() }
|
||||
val workerGroup = NioEventLoopGroup(0)
|
||||
val eventExecutorGroup = run {
|
||||
val threadFactory = if (cfg.eventExecutor.isUseVirtualThreads) {
|
||||
@@ -460,11 +455,11 @@ class RemoteBuildCacheServer(private val cfg: Configuration) {
|
||||
}
|
||||
DefaultEventExecutorGroup(Runtime.getRuntime().availableProcessors(), threadFactory)
|
||||
}
|
||||
val serverInitializer = ServerInitializer(cfg, eventExecutorGroup)
|
||||
val serverInitializer = ServerInitializer(cfg, channelFactory, datagramChannelFactory, workerGroup)
|
||||
val bootstrap = ServerBootstrap().apply {
|
||||
// Configure the server
|
||||
group(bossGroup, workerGroup)
|
||||
channel(serverSocketChannel)
|
||||
channelFactory(serverChannelFactory)
|
||||
childHandler(serverInitializer)
|
||||
option(ChannelOption.SO_BACKLOG, cfg.incomingConnectionsBacklogSize)
|
||||
childOption(ChannelOption.SO_KEEPALIVE, true)
|
||||
|
@@ -1,90 +0,0 @@
|
||||
package net.woggioni.rbcs.server.auth
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter
|
||||
import io.netty.handler.ssl.SslHandler
|
||||
import io.netty.handler.ssl.SslHandshakeCompletionEvent
|
||||
import java.security.KeyStore
|
||||
import java.security.cert.CertPathValidator
|
||||
import java.security.cert.CertPathValidatorException
|
||||
import java.security.cert.CertificateException
|
||||
import java.security.cert.CertificateFactory
|
||||
import java.security.cert.PKIXParameters
|
||||
import java.security.cert.PKIXRevocationChecker
|
||||
import java.security.cert.X509Certificate
|
||||
import java.util.EnumSet
|
||||
import javax.net.ssl.SSLSession
|
||||
import javax.net.ssl.TrustManagerFactory
|
||||
import javax.net.ssl.X509TrustManager
|
||||
|
||||
|
||||
class ClientCertificateValidator private constructor(
|
||||
private val sslHandler: SslHandler,
|
||||
private val x509TrustManager: X509TrustManager
|
||||
) : ChannelInboundHandlerAdapter() {
|
||||
override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
|
||||
if (evt is SslHandshakeCompletionEvent) {
|
||||
if (evt.isSuccess) {
|
||||
val session: SSLSession = sslHandler.engine().session
|
||||
val clientCertificateChain = session.peerCertificates as Array<X509Certificate>
|
||||
val authType: String = clientCertificateChain[0].publicKey.algorithm
|
||||
x509TrustManager.checkClientTrusted(clientCertificateChain, authType)
|
||||
} else {
|
||||
// Handle the failure, for example by closing the channel.
|
||||
}
|
||||
}
|
||||
super.userEventTriggered(ctx, evt)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getTrustManager(trustStore: KeyStore?, certificateRevocationEnabled: Boolean): X509TrustManager {
|
||||
return if (trustStore != null) {
|
||||
val certificateFactory = CertificateFactory.getInstance("X.509")
|
||||
val validator = CertPathValidator.getInstance("PKIX").apply {
|
||||
val rc = revocationChecker as PKIXRevocationChecker
|
||||
rc.options = EnumSet.of(
|
||||
PKIXRevocationChecker.Option.NO_FALLBACK
|
||||
)
|
||||
}
|
||||
val params = PKIXParameters(trustStore).apply {
|
||||
isRevocationEnabled = certificateRevocationEnabled
|
||||
}
|
||||
object : X509TrustManager {
|
||||
override fun checkClientTrusted(chain: Array<out X509Certificate>, authType: String) {
|
||||
val clientCertificateChain = certificateFactory.generateCertPath(chain.toList())
|
||||
try {
|
||||
validator.validate(clientCertificateChain, params)
|
||||
} catch (ex: CertPathValidatorException) {
|
||||
throw CertificateException(ex)
|
||||
}
|
||||
}
|
||||
|
||||
override fun checkServerTrusted(chain: Array<out X509Certificate>, authType: String) {
|
||||
throw NotImplementedError()
|
||||
}
|
||||
|
||||
private val acceptedIssuers = trustStore.aliases().asSequence()
|
||||
.filter(trustStore::isCertificateEntry)
|
||||
.map(trustStore::getCertificate)
|
||||
.map { it as X509Certificate }
|
||||
.toList()
|
||||
.toTypedArray()
|
||||
|
||||
override fun getAcceptedIssuers() = acceptedIssuers
|
||||
}
|
||||
} else {
|
||||
val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
|
||||
trustManagerFactory.trustManagers.asSequence().filter { it is X509TrustManager }
|
||||
.single() as X509TrustManager
|
||||
}
|
||||
}
|
||||
|
||||
fun of(
|
||||
sslHandler: SslHandler,
|
||||
trustStore: KeyStore?,
|
||||
certificateRevocationEnabled: Boolean
|
||||
): ClientCertificateValidator {
|
||||
return ClientCertificateValidator(sslHandler, getTrustManager(trustStore, certificateRevocationEnabled))
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
package net.woggioni.rbcs.server.cache
|
||||
|
||||
import net.woggioni.jwo.JWO
|
||||
import net.woggioni.rbcs.api.AsyncCloseable
|
||||
import net.woggioni.rbcs.api.CacheValueMetadata
|
||||
import net.woggioni.rbcs.common.createLogger
|
||||
import java.io.ByteArrayOutputStream
|
||||
@@ -18,11 +19,12 @@ import java.nio.file.StandardOpenOption
|
||||
import java.nio.file.attribute.BasicFileAttributes
|
||||
import java.time.Duration
|
||||
import java.time.Instant
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
class FileSystemCache(
|
||||
val root: Path,
|
||||
val maxAge: Duration
|
||||
) : AutoCloseable {
|
||||
) : AsyncCloseable {
|
||||
|
||||
class EntryValue(val metadata: CacheValueMetadata, val channel : FileChannel, val offset : Long, val size : Long) : Serializable
|
||||
|
||||
@@ -112,10 +114,19 @@ class FileSystemCache(
|
||||
return FileSink(metadata, file, tmpFile)
|
||||
}
|
||||
|
||||
private val garbageCollector = Thread.ofVirtual().name("file-system-cache-gc").start {
|
||||
private val closeFuture = object : CompletableFuture<Void>() {
|
||||
init {
|
||||
Thread.ofVirtual().name("file-system-cache-gc").start {
|
||||
try {
|
||||
while (running) {
|
||||
gc()
|
||||
}
|
||||
complete(null)
|
||||
} catch (ex : Throwable) {
|
||||
completeExceptionally(ex)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun gc() {
|
||||
@@ -151,8 +162,8 @@ class FileSystemCache(
|
||||
return result
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
override fun asyncClose() : CompletableFuture<Void> {
|
||||
running = false
|
||||
garbageCollector.join()
|
||||
return closeFuture
|
||||
}
|
||||
}
|
@@ -1,5 +1,9 @@
|
||||
package net.woggioni.rbcs.server.cache
|
||||
|
||||
import io.netty.channel.ChannelFactory
|
||||
import io.netty.channel.EventLoopGroup
|
||||
import io.netty.channel.socket.DatagramChannel
|
||||
import io.netty.channel.socket.SocketChannel
|
||||
import net.woggioni.jwo.Application
|
||||
import net.woggioni.rbcs.api.CacheHandlerFactory
|
||||
import net.woggioni.rbcs.api.Configuration
|
||||
@@ -19,11 +23,13 @@ data class FileSystemCacheConfiguration(
|
||||
override fun materialize() = object : CacheHandlerFactory {
|
||||
private val cache = FileSystemCache(root ?: Application.builder("rbcs").build().computeCacheDirectory(), maxAge)
|
||||
|
||||
override fun close() {
|
||||
cache.close()
|
||||
}
|
||||
override fun asyncClose() = cache.asyncClose()
|
||||
|
||||
override fun newHandler() = FileSystemCacheHandler(cache, digestAlgorithm, compressionEnabled, compressionLevel, chunkSize)
|
||||
override fun newHandler(
|
||||
eventLoop: EventLoopGroup,
|
||||
socketChannelFactory: ChannelFactory<SocketChannel>,
|
||||
datagramChannelFactory: ChannelFactory<DatagramChannel>
|
||||
) = FileSystemCacheHandler(cache, digestAlgorithm, compressionEnabled, compressionLevel, chunkSize)
|
||||
}
|
||||
|
||||
override fun getNamespaceURI() = RBCS.RBCS_NAMESPACE_URI
|
||||
|
@@ -30,7 +30,7 @@ class FileSystemCacheProvider : CacheProvider<FileSystemCacheConfiguration> {
|
||||
val compressionLevel = el.renderAttribute("compression-level")
|
||||
?.let(String::toInt)
|
||||
?: Deflater.DEFAULT_COMPRESSION
|
||||
val digestAlgorithm = el.renderAttribute("digest") ?: "MD5"
|
||||
val digestAlgorithm = el.renderAttribute("digest")
|
||||
val chunkSize = el.renderAttribute("chunk-size")
|
||||
?.let(Integer::decode)
|
||||
?: 0x10000
|
||||
|
@@ -1,10 +1,12 @@
|
||||
package net.woggioni.rbcs.server.cache
|
||||
|
||||
import io.netty.buffer.ByteBuf
|
||||
import net.woggioni.rbcs.api.AsyncCloseable
|
||||
import net.woggioni.rbcs.api.CacheValueMetadata
|
||||
import net.woggioni.rbcs.common.createLogger
|
||||
import java.time.Duration
|
||||
import java.time.Instant
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.PriorityBlockingQueue
|
||||
import java.util.concurrent.TimeUnit
|
||||
@@ -26,7 +28,7 @@ class CacheEntry(
|
||||
class InMemoryCache(
|
||||
private val maxAge: Duration,
|
||||
private val maxSize: Long
|
||||
) : AutoCloseable {
|
||||
) : AsyncCloseable {
|
||||
|
||||
companion object {
|
||||
private val log = createLogger<InMemoryCache>()
|
||||
@@ -45,7 +47,10 @@ class InMemoryCache(
|
||||
@Volatile
|
||||
private var running = true
|
||||
|
||||
private val garbageCollector = Thread.ofVirtual().name("in-memory-cache-gc").start {
|
||||
private val closeFuture = object : CompletableFuture<Void>() {
|
||||
init {
|
||||
Thread.ofVirtual().name("in-memory-cache-gc").start {
|
||||
try {
|
||||
while (running) {
|
||||
val el = removalQueue.poll(1, TimeUnit.SECONDS) ?: continue
|
||||
val value = el.value
|
||||
@@ -62,9 +67,15 @@ class InMemoryCache(
|
||||
Thread.sleep(minOf(Duration.between(now, el.expiry), Duration.ofSeconds(1)))
|
||||
}
|
||||
}
|
||||
complete(null)
|
||||
} catch (ex: Throwable) {
|
||||
completeExceptionally(ex)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeEldest(): Long {
|
||||
fun removeEldest(): Long {
|
||||
while (true) {
|
||||
val el = removalQueue.take()
|
||||
val value = el.value
|
||||
@@ -84,9 +95,9 @@ class InMemoryCache(
|
||||
}
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
override fun asyncClose() : CompletableFuture<Void> {
|
||||
running = false
|
||||
garbageCollector.join()
|
||||
return closeFuture
|
||||
}
|
||||
|
||||
fun get(key: ByteArray) = map[CacheKey(key)]?.run {
|
||||
|
@@ -1,5 +1,10 @@
|
||||
package net.woggioni.rbcs.server.cache
|
||||
|
||||
import io.netty.channel.ChannelFactory
|
||||
import io.netty.channel.EventLoopGroup
|
||||
import io.netty.channel.socket.DatagramChannel
|
||||
import io.netty.channel.socket.SocketChannel
|
||||
import io.netty.util.concurrent.Future
|
||||
import net.woggioni.rbcs.api.CacheHandlerFactory
|
||||
import net.woggioni.rbcs.api.Configuration
|
||||
import net.woggioni.rbcs.common.RBCS
|
||||
@@ -16,11 +21,13 @@ data class InMemoryCacheConfiguration(
|
||||
override fun materialize() = object : CacheHandlerFactory {
|
||||
private val cache = InMemoryCache(maxAge, maxSize)
|
||||
|
||||
override fun close() {
|
||||
cache.close()
|
||||
}
|
||||
override fun asyncClose() = cache.asyncClose()
|
||||
|
||||
override fun newHandler() = InMemoryCacheHandler(cache, digestAlgorithm, compressionEnabled, compressionLevel)
|
||||
override fun newHandler(
|
||||
eventLoop: EventLoopGroup,
|
||||
socketChannelFactory: ChannelFactory<SocketChannel>,
|
||||
datagramChannelFactory: ChannelFactory<DatagramChannel>
|
||||
) = InMemoryCacheHandler(cache, digestAlgorithm, compressionEnabled, compressionLevel)
|
||||
}
|
||||
|
||||
override fun getNamespaceURI() = RBCS.RBCS_NAMESPACE_URI
|
||||
|
@@ -30,7 +30,7 @@ class InMemoryCacheProvider : CacheProvider<InMemoryCacheConfiguration> {
|
||||
val compressionLevel = el.renderAttribute("compression-level")
|
||||
?.let(String::toInt)
|
||||
?: Deflater.DEFAULT_COMPRESSION
|
||||
val digestAlgorithm = el.renderAttribute("digest") ?: "MD5"
|
||||
val digestAlgorithm = el.renderAttribute("digest")
|
||||
val chunkSize = el.renderAttribute("chunk-size")
|
||||
?.let(Integer::decode)
|
||||
?: 0x10000
|
||||
|
@@ -153,7 +153,7 @@
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="digest" type="xs:token" default="MD5">
|
||||
<xs:attribute name="digest" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
Hashing algorithm to apply to the key. If omitted, no hashing is performed.
|
||||
@@ -209,7 +209,7 @@
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="digest" type="xs:token" default="MD5">
|
||||
<xs:attribute name="digest" type="xs:token" default="SHA3-224">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
Hashing algorithm to apply to the key. If omitted, no hashing is performed.
|
||||
|
@@ -1,30 +0,0 @@
|
||||
package net.woggioni.rbcs.server.test.utils;
|
||||
|
||||
import net.woggioni.jwo.JWO;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
|
||||
public class NetworkUtils {
|
||||
|
||||
private static final int MAX_ATTEMPTS = 50;
|
||||
|
||||
public static int getFreePort() {
|
||||
int count = 0;
|
||||
while(count < MAX_ATTEMPTS) {
|
||||
try (ServerSocket serverSocket = new ServerSocket(0, 50, InetAddress.getLocalHost())) {
|
||||
final var candidate = serverSocket.getLocalPort();
|
||||
if (candidate > 0) {
|
||||
return candidate;
|
||||
} else {
|
||||
JWO.newThrowable(RuntimeException.class, "Got invalid port number: %d", candidate);
|
||||
throw new RuntimeException("Error trying to find an open port");
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("Error trying to find an open port");
|
||||
}
|
||||
}
|
@@ -2,10 +2,10 @@ package net.woggioni.rbcs.server.test
|
||||
|
||||
import net.woggioni.rbcs.api.Configuration
|
||||
import net.woggioni.rbcs.api.Role
|
||||
import net.woggioni.rbcs.common.RBCS.getFreePort
|
||||
import net.woggioni.rbcs.common.Xml
|
||||
import net.woggioni.rbcs.server.cache.FileSystemCacheConfiguration
|
||||
import net.woggioni.rbcs.server.configuration.Serializer
|
||||
import net.woggioni.rbcs.server.test.utils.NetworkUtils
|
||||
import java.net.URI
|
||||
import java.net.http.HttpRequest
|
||||
import java.nio.charset.StandardCharsets
|
||||
@@ -33,7 +33,7 @@ abstract class AbstractBasicAuthServerTest : AbstractServerTest() {
|
||||
this.cacheDir = testDir.resolve("cache")
|
||||
cfg = Configuration.of(
|
||||
"127.0.0.1",
|
||||
NetworkUtils.getFreePort(),
|
||||
getFreePort(),
|
||||
50,
|
||||
serverPath,
|
||||
Configuration.EventExecutor(false),
|
||||
|
@@ -2,12 +2,12 @@ package net.woggioni.rbcs.server.test
|
||||
|
||||
import net.woggioni.rbcs.api.Configuration
|
||||
import net.woggioni.rbcs.api.Role
|
||||
import net.woggioni.rbcs.common.RBCS.getFreePort
|
||||
import net.woggioni.rbcs.common.Xml
|
||||
import net.woggioni.rbcs.server.cache.FileSystemCacheConfiguration
|
||||
import net.woggioni.rbcs.server.configuration.Serializer
|
||||
import net.woggioni.rbcs.server.test.utils.CertificateUtils
|
||||
import net.woggioni.rbcs.server.test.utils.CertificateUtils.X509Credentials
|
||||
import net.woggioni.rbcs.server.test.utils.NetworkUtils
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import java.net.URI
|
||||
import java.net.http.HttpClient
|
||||
@@ -138,7 +138,7 @@ abstract class AbstractTlsServerTest : AbstractServerTest() {
|
||||
createKeyStoreAndTrustStore()
|
||||
cfg = Configuration(
|
||||
"127.0.0.1",
|
||||
NetworkUtils.getFreePort(),
|
||||
getFreePort(),
|
||||
100,
|
||||
serverPath,
|
||||
Configuration.EventExecutor(false),
|
||||
|
@@ -2,10 +2,10 @@ package net.woggioni.rbcs.server.test
|
||||
|
||||
import io.netty.handler.codec.http.HttpResponseStatus
|
||||
import net.woggioni.rbcs.api.Configuration
|
||||
import net.woggioni.rbcs.common.RBCS.getFreePort
|
||||
import net.woggioni.rbcs.common.Xml
|
||||
import net.woggioni.rbcs.server.cache.InMemoryCacheConfiguration
|
||||
import net.woggioni.rbcs.server.configuration.Serializer
|
||||
import net.woggioni.rbcs.server.test.utils.NetworkUtils
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.Order
|
||||
import org.junit.jupiter.api.Test
|
||||
@@ -33,7 +33,7 @@ class NoAuthServerTest : AbstractServerTest() {
|
||||
this.cacheDir = testDir.resolve("cache")
|
||||
cfg = Configuration(
|
||||
"127.0.0.1",
|
||||
NetworkUtils.getFreePort(),
|
||||
getFreePort(),
|
||||
100,
|
||||
serverPath,
|
||||
Configuration.EventExecutor(false),
|
||||
|
Reference in New Issue
Block a user