Skip to content

Commit

Permalink
Add inventory module
Browse files Browse the repository at this point in the history
Simple monitor dumping json files with data result and request/response time to disk. Can be used by a simple web server to show state of seed nodes.
  • Loading branch information
chimp1984 committed Oct 23, 2020
1 parent 55b693e commit 3521619
Show file tree
Hide file tree
Showing 5 changed files with 322 additions and 0 deletions.
13 changes: 13 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ configure([project(':cli'),
project(':seednode'),
project(':statsnode'),
project(':pricenode'),
project(':inventory'),
project(':apitest')]) {

apply plugin: 'application'
Expand Down Expand Up @@ -594,6 +595,18 @@ configure(project(':daemon')) {
}
}

configure(project(':inventory')) {
mainClassName = 'bisq.inventory.InventoryMonitorMain'

dependencies {
compile project(':core')
compile "com.google.guava:guava:$guavaVersion"

compileOnly "org.projectlombok:lombok:$lombokVersion"
annotationProcessor "org.projectlombok:lombok:$lombokVersion"
}
}

configure(project(':apitest')) {
mainClassName = 'bisq.apitest.ApiTestMain'

Expand Down
186 changes: 186 additions & 0 deletions inventory/src/main/java/bisq/inventory/InventoryMonitor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
/*
* 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 bisq.inventory;


import bisq.core.network.p2p.seed.DefaultSeedNodeRepository;
import bisq.core.proto.network.CoreNetworkProtoResolver;

import bisq.network.p2p.NetworkNodeProvider;
import bisq.network.p2p.NodeAddress;
import bisq.network.p2p.inventory.GetInventoryRequestManager;
import bisq.network.p2p.network.NetworkNode;
import bisq.network.p2p.network.SetupListener;

import bisq.common.UserThread;
import bisq.common.app.Capabilities;
import bisq.common.app.Capability;
import bisq.common.config.BaseCurrencyNetwork;
import bisq.common.file.JsonFileManager;
import bisq.common.util.Utilities;

import java.time.Clock;

import java.io.File;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import org.jetbrains.annotations.NotNull;

@Slf4j
public class InventoryMonitor {

private final NetworkNode networkNode;
private final GetInventoryRequestManager getInventoryRequestManager;
private final List<NodeAddress> seedNodes = new ArrayList<>();
private final Map<NodeAddress, JsonFileManager> jsonFileManagerByNodeAddress = new HashMap<>();
private final boolean useLocalhostForP2P;
private final int intervalSec;

public InventoryMonitor(File appDir,
boolean useLocalhostForP2P,
BaseCurrencyNetwork network,
int intervalSec) {
this.useLocalhostForP2P = useLocalhostForP2P;
this.intervalSec = intervalSec;
Capabilities.app.addAll(
Capability.TRADE_STATISTICS,
Capability.TRADE_STATISTICS_2,
Capability.ACCOUNT_AGE_WITNESS,
Capability.ACK_MSG,
Capability.PROPOSAL,
Capability.BLIND_VOTE,
Capability.DAO_STATE,
Capability.BUNDLE_OF_ENVELOPES,
Capability.MEDIATION,
Capability.SIGNED_ACCOUNT_AGE_WITNESS,
Capability.REFUND_AGENT,
Capability.TRADE_STATISTICS_HASH_UPDATE,
Capability.NO_ADDRESS_PRE_FIX,
Capability.TRADE_STATISTICS_3,
Capability.RECEIVE_BSQ_BLOCK
);

networkNode = new NetworkNodeProvider(new CoreNetworkProtoResolver(Clock.systemDefaultZone()),
ArrayList::new,
useLocalhostForP2P,
9999,
new File(appDir, "tor"),
null,
"",
-1,
"",
null,
false,
false).get();
getInventoryRequestManager = new GetInventoryRequestManager(networkNode);

seedNodes.addAll(DefaultSeedNodeRepository.getSeedNodeAddressesFromPropertyFile(network));

File jsonDir = new File(appDir, "json");
if (!jsonDir.exists() && !jsonDir.mkdir()) {
log.warn("make jsonDir failed");
}
seedNodes.forEach(nodeAddress -> {
JsonFileManager jsonFileManager = new JsonFileManager(new File(jsonDir, getShortAddress(nodeAddress, useLocalhostForP2P)));
jsonFileManagerByNodeAddress.put(nodeAddress, jsonFileManager);
});

networkNode.start(new SetupListener() {
@Override
public void onTorNodeReady() {
startRequests();
}

@Override
public void onHiddenServicePublished() {
}

@Override
public void onSetupFailed(Throwable throwable) {
}

@Override
public void onRequestCustomBridges() {
}
});
}

@NotNull
private String getShortAddress(NodeAddress nodeAddress, boolean useLocalhostForP2P) {
return useLocalhostForP2P ?
nodeAddress.getFullAddress().replace(":", "_") :
nodeAddress.getFullAddress().substring(0, 10);
}

private void startRequests() {
UserThread.runPeriodically(this::requestAllSeeds, intervalSec);
requestAllSeeds();
}

private void requestAllSeeds() {
seedNodes.forEach(nodeAddress -> {
RequestInfo requestInfo = new RequestInfo(System.currentTimeMillis());
new Thread(() -> {
Thread.currentThread().setName("request @ " + getShortAddress(nodeAddress, useLocalhostForP2P));
getInventoryRequestManager.request(nodeAddress,
result -> {
log.info("nodeAddress={}, result={}", nodeAddress, result.toString());
long responseTime = System.currentTimeMillis();
requestInfo.setResponseTime(responseTime);
requestInfo.setResult(result);
String json = Utilities.objectToJson(requestInfo);
jsonFileManagerByNodeAddress.get(nodeAddress).writeToDisc(json, String.valueOf(responseTime));
},
errorMessage -> {
log.warn(errorMessage);
requestInfo.setErrorMessage(errorMessage);
});
}).start();

});


}

public void shutDown() {
jsonFileManagerByNodeAddress.values().forEach(JsonFileManager::shutDown);
}

@Getter
static class RequestInfo {
private final long requestStartTime;
@Setter
private long responseTime;
@Setter
private Map<String, Integer> result;
@Setter
private String errorMessage;

public RequestInfo(long requestStartTime) {
this.requestStartTime = requestStartTime;
}
}
}
106 changes: 106 additions & 0 deletions inventory/src/main/java/bisq/inventory/InventoryMonitorMain.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
* 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 bisq.inventory;


import bisq.common.UserThread;
import bisq.common.app.Log;
import bisq.common.app.Version;
import bisq.common.config.BaseCurrencyNetwork;
import bisq.common.util.Utilities;

import com.google.common.util.concurrent.ThreadFactoryBuilder;

import java.nio.file.Paths;

import java.io.File;

import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

import ch.qos.logback.classic.Level;

import lombok.extern.slf4j.Slf4j;



import sun.misc.Signal;

@Slf4j
public class InventoryMonitorMain {

private static InventoryMonitor inventoryMonitor;
private static boolean stopped;

// prog args for regtest: 10 1 BTC_REGTEST
public static void main(String[] args) {
int intervalSec = 600;
boolean useLocalhostForP2P = false;
BaseCurrencyNetwork network = BaseCurrencyNetwork.BTC_MAINNET;

if (args.length > 0) {
intervalSec = Integer.parseInt(args[0]);
}
if (args.length > 1) {
useLocalhostForP2P = args[1].equals("1");
}
if (args.length > 2) {
network = BaseCurrencyNetwork.valueOf(args[2]);
}

String appName = "bisq-InventoryMonitor-" + network;

File appDir = new File(Utilities.getUserDataDir(), appName);
String logPath = Paths.get(appDir.getPath(), "bisq").toString();
Log.setup(logPath);
Log.setLevel(Level.INFO);
Version.setBaseCryptoNetworkId(network.ordinal());

inventoryMonitor = new InventoryMonitor(appDir, useLocalhostForP2P, network, intervalSec);

ThreadFactory threadFactory = new ThreadFactoryBuilder()
.setNameFormat(inventoryMonitor.getClass().getSimpleName())
.setDaemon(true)
.build();
UserThread.setExecutor(Executors.newSingleThreadExecutor(threadFactory));

Signal.handle(new Signal("INT"), signal -> {
shutDown();
});

Signal.handle(new Signal("TERM"), signal -> {
shutDown();
});
keepRunning();
}

private static void shutDown() {
inventoryMonitor.shutDown();
stopped = true;
System.exit(0);
}

private static void keepRunning() {
while (!stopped) {
try {
Thread.sleep(Long.MAX_VALUE);
} catch (InterruptedException ignore) {
}
}
}
}
16 changes: 16 additions & 0 deletions inventory/src/main/resources/logback.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="CONSOLE_APPENDER" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%highlight(%d{MMM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{30}: %msg %xEx%n)</pattern>
</encoder>
</appender>

<root level="TRACE">
<appender-ref ref="CONSOLE_APPENDER"/>
</root>

<logger name="com.neemre.btcdcli4j" level="WARN"/>
<logger name="com.neemre.btcdcli4j.core.client.ClientConfigurator" level="ERROR"/>

</configuration>
1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ include 'pricenode'
include 'relay'
include 'seednode'
include 'statsnode'
include 'inventory'
include 'apitest'

rootProject.name = 'bisq'

0 comments on commit 3521619

Please sign in to comment.