Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Demo lightbend / typesafe configuration library #18

Merged
merged 2 commits into from
Dec 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion common/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
*/
package network.misq.common.configuration;

import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import lombok.extern.slf4j.Slf4j;

/**
* TIPS
* <p>
* 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.)
* <p>
* 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.
* <p>
* 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.
* <p>
* REFERENCES
* <p>
* 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"));
}
}
63 changes: 63 additions & 0 deletions common/src/main/resources/misq.conf
Original file line number Diff line number Diff line change
@@ -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
}
}
}
}
4 changes: 2 additions & 2 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions network/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
12 changes: 8 additions & 4 deletions network/src/main/java/network/misq/network/NetworkService.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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,
Expand Down
23 changes: 23 additions & 0 deletions network/src/test/java/network/misq/network/TypesafeConfigTest.java
Original file line number Diff line number Diff line change
@@ -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"));
}
}
7 changes: 7 additions & 0 deletions platforms/common-platform/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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
/////////////////////////////////////////////////////////////////////////////////
Expand Down