From 900bbff5a7bb1f3fd3cbea3378c3e8ae56f21666 Mon Sep 17 00:00:00 2001
From: ghubstan <36207203+ghubstan@users.noreply.github.com>
Date: Sat, 25 Dec 2021 11:40:18 -0300
Subject: [PATCH 1/2] Upgrade to gradle 7.3.3
Upgrade checks to Log4j 2.17.0
See https://github.com/gradle/gradle/issues/19360
---
gradle/wrapper/gradle-wrapper.properties | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 234b6472e1..59250647c4 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionSha256Sum=2debee19271e1b82c6e41137d78e44e6e841035230a1a169ca47fd3fb09ed87b
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip
+distributionSha256Sum=b586e04868a22fd817c8971330fec37e298f3242eb85c374181b12d637f80302
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
From aba58748458bbe8acb09f28bc8df987f2ca9b02f Mon Sep 17 00:00:00 2001
From: ghubstan <36207203+ghubstan@users.noreply.github.com>
Date: Sat, 25 Dec 2021 13:24:52 -0300
Subject: [PATCH 2/2] Demo typesafe configuration library
This is a simple example of how Misq might use the typesafe library (~295Kb)
to load all global and sub-module configurations from a single misq.conf file.
- Dependency constraint added to common-platform's build.gradle.
- Dependency (implemention) declared in common and network build files.
- Global misq.conf file added to common module's resource folder (might need to move it).
This sample configuration contains a network service sub config, but only the
"networkIOPool {}" block has real values.
- Added new MisqConfig class to load misq.conf, and provide a getConfig(String path)
method to give any object a typesafe Config instance of any scope: from global,
to library, down to smallest grouping of scalar configuration values.
- Added test to check "networkIOPool" config is loaded with correct values.
- Replaced hard-coded NETWORK_IO_POOL parameters with values loaded from
misq.conf
TODO
The typesafe library can probably support everying Misq will need in terms of
configuration, including the ability to merge distinct dev and/or production configs
(sub-module level), as well as property files and json files into a global config.
---
common/build.gradle | 3 +-
.../misq/common/configuration/MisqConfig.java | 87 +++++++++++++++++++
common/src/main/resources/misq.conf | 63 ++++++++++++++
network/build.gradle | 1 +
.../network/misq/network/NetworkService.java | 12 ++-
.../misq/network/TypesafeConfigTest.java | 23 +++++
platforms/common-platform/build.gradle | 7 ++
7 files changed, 191 insertions(+), 5 deletions(-)
create mode 100644 common/src/main/java/network/misq/common/configuration/MisqConfig.java
create mode 100644 common/src/main/resources/misq.conf
create mode 100644 network/src/test/java/network/misq/network/TypesafeConfigTest.java
diff --git a/common/build.gradle b/common/build.gradle
index 0c6e919406..dda9046270 100644
--- a/common/build.gradle
+++ b/common/build.gradle
@@ -13,8 +13,9 @@ apply from: '../buildSrc/lombok-dependencies.gradle'
dependencies {
api platform(project(':platforms:common-platform'))
-
+
implementation 'com.google.guava:guava'
+ implementation 'com.typesafe:config'
}
test {
diff --git a/common/src/main/java/network/misq/common/configuration/MisqConfig.java b/common/src/main/java/network/misq/common/configuration/MisqConfig.java
new file mode 100644
index 0000000000..e0ccf46ab3
--- /dev/null
+++ b/common/src/main/java/network/misq/common/configuration/MisqConfig.java
@@ -0,0 +1,87 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see
+ * Set the Java system property -Dconfig.trace=loads to get output on stderr describing each file that is loaded. + * (The output will show the library attempting to load misq.json, misq.properties, and reference.conf, but not fail.) + *
+ * Use myConfig.root().render() to get a Config as a string with comments showing where each value came from. + * This string can be printed out on console or logged to a file etc. + *
+ * If you see errors like com.typesafe.config.ConfigException$Missing: No configuration setting found for key foo, + * and you're sure that key is defined in your config file, they might appear e.g. when you're loading configuration + * from a thread that's not the JVM's main thread. Try passing the ClassLoader in manually - e.g. with + * ConfigFactory.load(getClass().getClassLoader()) or setting the context class loader. If you don't pass one, + * Lightbend Config uses the calling thread's contextClassLoader, and in some cases, it may not have your configuration + * files in its classpath, so loading the config on that thread can yield unexpected, erroneous results. + *
+ * REFERENCES + *
+ * https://github.com/lightbend/config + * https://www.stubbornjava.com/posts/typesafe-config-features-and-example-usage + * https://florentfo.rest/2019/01/07/configuring-spark-applications-with-typesafe-config.html + */ +@Slf4j +public class MisqConfig { + + public static final String NETWORK_CONFIG_PATH = "misq.networkConfig"; + public static final String NETWORK_IO_POOL_CONFIG_PATH = NETWORK_CONFIG_PATH + ".networkIOPool"; + + private static final Config MISQ_CONFIG = ConfigFactory.load("misq"); + + static { + try { + MISQ_CONFIG.checkValid(ConfigFactory.defaultReference(), "misq"); + } catch (Exception ex) { + throw new IllegalStateException("misq.conf validation failed", ex); + } + } + + /** + * Return the global Config object. + * + * @return Config + */ + public static Config getGlobalConfig() { + return MISQ_CONFIG; + } + + /** + * Return a Config for a given configuration path, e.g., + * "misq.networkConfig.torPeerGroupServiceConfig.peerExchangeConfig". + * + * @param path String representing a valid path in misq.conf + * @return Config + */ + public static Config getConfig(String path) { + MISQ_CONFIG.checkValid(ConfigFactory.defaultReference(), path); + return MISQ_CONFIG.getConfig(path); + } + + public static void main(String[] args) { + log.info("MISQ_CONFIG = {}", MISQ_CONFIG); + log.info("misq.networkConfig.torPeerGroupServiceConfig = {}", getConfig("misq.networkConfig.torPeerGroupServiceConfig")); + log.info("misq.networkConfig.i2pPeerGroupServiceConfig = {}", getConfig("misq.networkConfig.i2pPeerGroupServiceConfig")); + } +} diff --git a/common/src/main/resources/misq.conf b/common/src/main/resources/misq.conf new file mode 100644 index 0000000000..434303783e --- /dev/null +++ b/common/src/main/resources/misq.conf @@ -0,0 +1,63 @@ +// A comment +# Another comment +misq { + + networkConfig = { + + networkIOPool { + name = "NETWORK_IO_POOL" + corePoolSize = 1 + maximumPoolSize = 5000 + keepAliveTimeInSec = 10 + } + + baseDirPath = "some/path" + supportedTransportTypes = "TOR,I2P" + + transportConfig { + baseDirPath = "some/transport-config/path" + } + + serviceNodeConfig { + p2pServiceNodeConfig="PEER_GROUP,DATA,CONFIDENTIAL,RELAY,MONITOR" + } + + i2pPeerGroupServiceConfig { + peerGroupConfig { + minNumConnectedPeers=8 + maxNumConnectedPeers=12 + minNumReportedPeers=30 + } + + peerExchangeConfig { + numSeeNodesAtBoostrap=2 + numPersistedPeersAtBoostrap=100 + numReportedPeersAtBoostrap=50 + } + + keepAliveServiceConfig { + bootstrapTime=1111 + interval=2222 + } + } + + torPeerGroupServiceConfig { + peerGroupConfig { + minNumConnectedPeers=8 + maxNumConnectedPeers=12 + minNumReportedPeers=30 + } + + peerExchangeConfig { + numSeeNodesAtBoostrap=2 + numPersistedPeersAtBoostrap=100 + numReportedPeersAtBoostrap=50 + } + + keepAliveServiceConfig { + bootstrapTime=1111 + interval=2222 + } + } + } +} diff --git a/network/build.gradle b/network/build.gradle index db6ecbf7af..e8ff00aa9b 100644 --- a/network/build.gradle +++ b/network/build.gradle @@ -24,6 +24,7 @@ dependencies { implementation project(':security') implementation project(':persistence') + implementation 'com.typesafe:config' implementation 'com.google.guava:guava' implementation 'io.reactivex.rxjava2:rxjava' implementation 'com.google.protobuf:protobuf-gradle-plugin' diff --git a/network/src/main/java/network/misq/network/NetworkService.java b/network/src/main/java/network/misq/network/NetworkService.java index e5c5e3be06..f686d7825c 100644 --- a/network/src/main/java/network/misq/network/NetworkService.java +++ b/network/src/main/java/network/misq/network/NetworkService.java @@ -20,6 +20,7 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; +import network.misq.common.configuration.MisqConfig; import network.misq.common.threading.ExecutorFactory; import network.misq.common.util.NetworkUtils; import network.misq.network.http.HttpService; @@ -47,6 +48,7 @@ import java.util.function.BiConsumer; import static com.google.common.base.Preconditions.checkArgument; +import static network.misq.common.configuration.MisqConfig.NETWORK_IO_POOL_CONFIG_PATH; /** * High level API for network access to p2p network as well to http services (over Tor). If user has only I2P selected @@ -65,10 +67,12 @@ public class NetworkService { // If a user has 10 offers with dedicated nodes and 5 connections open, its another 100 threads + 50 at sending // messages. 100-200 threads might be a usual scenario, but it could also peak much higher, so we will give // maximumPoolSize sufficient headroom and use a rather short keepAliveTimeInSec. - public static final ThreadPoolExecutor NETWORK_IO_POOL = ExecutorFactory.getThreadPoolExecutor("NETWORK_IO_POOL", - 1, - 5000, - 10, + public static final com.typesafe.config.Config NETWORK_IO_POOL_CONFIG = MisqConfig.getConfig(NETWORK_IO_POOL_CONFIG_PATH); + public static final ThreadPoolExecutor NETWORK_IO_POOL = ExecutorFactory.getThreadPoolExecutor( + NETWORK_IO_POOL_CONFIG.getString("name"), + NETWORK_IO_POOL_CONFIG.getInt("corePoolSize"), + NETWORK_IO_POOL_CONFIG.getInt("maximumPoolSize"), + NETWORK_IO_POOL_CONFIG.getLong("keepAliveTimeInSec"), new SynchronousQueue<>()); public static record Config(String baseDirPath, diff --git a/network/src/test/java/network/misq/network/TypesafeConfigTest.java b/network/src/test/java/network/misq/network/TypesafeConfigTest.java new file mode 100644 index 0000000000..904202c56f --- /dev/null +++ b/network/src/test/java/network/misq/network/TypesafeConfigTest.java @@ -0,0 +1,23 @@ +package network.misq.network; + +import com.typesafe.config.Config; +import network.misq.common.configuration.MisqConfig; +import org.junit.jupiter.api.Test; + +import static network.misq.common.configuration.MisqConfig.NETWORK_IO_POOL_CONFIG_PATH; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class TypesafeConfigTest { + + @Test + public void testNetworkPoolConfig() { + Config config = MisqConfig.getConfig(NETWORK_IO_POOL_CONFIG_PATH); + assertNotNull(config); + + assertEquals("NETWORK_IO_POOL", config.getString("name")); + assertEquals(1, config.getInt("corePoolSize")); + assertEquals(5000, config.getInt("maximumPoolSize")); + assertEquals(10, config.getLong("keepAliveTimeInSec")); + } +} diff --git a/platforms/common-platform/build.gradle b/platforms/common-platform/build.gradle index 168c4ae794..711c7ef1e7 100644 --- a/platforms/common-platform/build.gradle +++ b/platforms/common-platform/build.gradle @@ -12,6 +12,13 @@ dependencies { version { require '1.3.2' } } + ///////////////////////////////////////////////////////////////////////////////// + // Typesafe configuration dependency constraints + ///////////////////////////////////////////////////////////////////////////////// + api('com.typesafe:config') { + version { require '1.4.1' } + } + ///////////////////////////////////////////////////////////////////////////////// // Protobuf dependency constraints /////////////////////////////////////////////////////////////////////////////////