diff --git a/network/tor-local-network/build.gradle b/network/tor-local-network/build.gradle
index ab1b6acfc3..7f3b1cf47e 100644
--- a/network/tor-local-network/build.gradle
+++ b/network/tor-local-network/build.gradle
@@ -1,6 +1,11 @@
plugins {
id 'bisq.java-library'
id 'bisq.java-integration-tests'
+ id 'application'
+}
+
+application {
+ mainClass = 'bisq.tor.local_network.Main'
}
dependencies {
diff --git a/network/tor-local-network/src/main/java/bisq/tor/local_network/Main.java b/network/tor-local-network/src/main/java/bisq/tor/local_network/Main.java
new file mode 100644
index 0000000000..2d524cad4f
--- /dev/null
+++ b/network/tor-local-network/src/main/java/bisq/tor/local_network/Main.java
@@ -0,0 +1,74 @@
+/*
+ * 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 .
+ */
+
+package bisq.tor.local_network;
+
+import bisq.common.data.Pair;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Optional;
+
+public class Main {
+ private static final String PASSPHRASE = "my_passphrase";
+
+ public static void main(String[] args) throws IOException, InterruptedException {
+ Pair dataDirAndStartArg = parseArgs(args);
+ if (!dataDirAndStartArg.getSecond()) {
+ System.out.println("--start argument is missing.");
+ }
+
+ Path dataDir = dataDirAndStartArg.getFirst();
+ new TorNetwork(dataDir)
+ .addDirAuth(PASSPHRASE)
+ .addDirAuth(PASSPHRASE)
+ .addDirAuth(PASSPHRASE)
+
+ .addRelay()
+ .addRelay()
+ .addRelay()
+ .addRelay()
+ .addRelay()
+
+ .addClient()
+ .addClient()
+
+ .start();
+ }
+
+ private static Pair parseArgs(String[] allArgs) {
+ Optional dataDirPath = Optional.empty();
+ boolean isStartCommand = false;
+
+ for (int i = 0; i < allArgs.length; i++) {
+ switch (allArgs[i]) {
+ case "--dataDir":
+ dataDirPath = Optional.of(
+ Path.of(allArgs[i + 1])
+ );
+ break;
+
+ case "--start":
+ isStartCommand = true;
+ break;
+
+ }
+ }
+
+ return new Pair<>(dataDirPath.orElseThrow(), isStartCommand);
+ }
+}
diff --git a/network/tor-local-network/src/main/java/bisq/tor/local_network/TorNetwork.java b/network/tor-local-network/src/main/java/bisq/tor/local_network/TorNetwork.java
index 5085aac577..1f0ad69181 100644
--- a/network/tor-local-network/src/main/java/bisq/tor/local_network/TorNetwork.java
+++ b/network/tor-local-network/src/main/java/bisq/tor/local_network/TorNetwork.java
@@ -24,6 +24,7 @@
import bisq.tor.local_network.torrc.RelayTorrcGenerator;
import bisq.tor.local_network.torrc.TorrcFileGenerator;
+import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.HashSet;
@@ -51,10 +52,7 @@ public TorNetwork addDirAuth(String passphrase) throws IOException, InterruptedE
String nickname = "da" + dirAuthIndex++;
Path nodeDataDir = rootDataDir.resolve(nickname);
- boolean isSuccess = nodeDataDir.toFile().mkdir();
- if (!isSuccess) {
- throw new IllegalStateException("Couldn't create data directory for " + nickname);
- }
+ createDataDirIfNotPresent(nodeDataDir);
var dirAuth = TorNode.builder()
.type(TorNode.Type.DIRECTORY_AUTHORITY)
@@ -74,10 +72,7 @@ public TorNetwork addRelay() {
String nickname = "relay" + relayIndex++;
Path nodeDataDir = rootDataDir.resolve(nickname);
- boolean isSuccess = nodeDataDir.toFile().mkdir();
- if (!isSuccess) {
- throw new IllegalStateException("Couldn't create data directory for " + nickname);
- }
+ createDataDirIfNotPresent(nodeDataDir);
TorNode firstRelay = TorNode.builder()
.type(TorNode.Type.RELAY)
@@ -97,10 +92,7 @@ public TorNetwork addClient() {
String nickname = "client" + clientIndex++;
Path nodeDataDir = rootDataDir.resolve(nickname);
- boolean isSuccess = nodeDataDir.toFile().mkdir();
- if (!isSuccess) {
- throw new IllegalStateException("Couldn't create data directory for " + nickname);
- }
+ createDataDirIfNotPresent(nodeDataDir);
TorNode firstClient = TorNode.builder()
.type(TorNode.Type.CLIENT)
@@ -121,24 +113,36 @@ public void start() throws IOException {
startProcesses();
}
+ private void createDataDirIfNotPresent(Path nodeDataDirPath) {
+ File nodeDataDirFile = nodeDataDirPath.toFile();
+ if (nodeDataDirFile.exists()) {
+ return;
+ }
+
+ boolean isSuccess = nodeDataDirPath.toFile().mkdir();
+ if (!isSuccess) {
+ throw new IllegalStateException("Couldn't create data directory: " + nodeDataDirPath.toAbsolutePath());
+ }
+ }
+
private void generateTorrcFiles() throws IOException {
Set allDAs = dirAuthFactory.getAllDirectoryAuthorities();
for (TorNode da : allDAs) {
var torDaTorrcGenerator = new DirectoryAuthorityTorrcGenerator(da);
var torrcFileGenerator = new TorrcFileGenerator(torDaTorrcGenerator, allDAs);
- torrcFileGenerator.generate();
+ generateTorrc(da, torrcFileGenerator);
}
for (TorNode relay : relays) {
var relayTorrcGenerator = new RelayTorrcGenerator(relay);
var torrcFileGenerator = new TorrcFileGenerator(relayTorrcGenerator, allDAs);
- torrcFileGenerator.generate();
+ generateTorrc(relay, torrcFileGenerator);
}
for (TorNode client : clients) {
var clientTorrcGenerator = new ClientTorrcGenerator(client);
var torrcFileGenerator = new TorrcFileGenerator(clientTorrcGenerator, allDAs);
- torrcFileGenerator.generate();
+ generateTorrc(client, torrcFileGenerator);
}
}
@@ -168,4 +172,11 @@ private Process createAndStartTorProcess(TorNode torNode) throws IOException {
processBuilder.redirectOutput(ProcessBuilder.Redirect.DISCARD);
return processBuilder.start();
}
+
+ private void generateTorrc(TorNode torNode, TorrcFileGenerator torrcFileGenerator) throws IOException {
+ if (torNode.getTorrcPath().toFile().exists()) {
+ return;
+ }
+ torrcFileGenerator.generate();
+ }
}
diff --git a/network/tor-local-network/src/main/java/bisq/tor/local_network/da/DirectoryAuthorityFactory.java b/network/tor-local-network/src/main/java/bisq/tor/local_network/da/DirectoryAuthorityFactory.java
index d1ac3ada98..e1253d329e 100644
--- a/network/tor-local-network/src/main/java/bisq/tor/local_network/da/DirectoryAuthorityFactory.java
+++ b/network/tor-local-network/src/main/java/bisq/tor/local_network/da/DirectoryAuthorityFactory.java
@@ -38,13 +38,15 @@ public void createDirectoryAuthority(TorNode directoryAuthority,
createDataDirIfNotPresent(dataDir);
Path keysPath = dataDir.resolve("keys");
- boolean isSuccess = keysPath.toFile().mkdirs();
- if (!isSuccess) {
- throw new IllegalStateException("Couldn't create keys folder in data directory for directory authority.");
+ File keysDirFile = keysPath.toFile();
+ if (!keysDirFile.exists()) {
+ boolean isSuccess = keysDirFile.mkdirs();
+ if (!isSuccess) {
+ throw new IllegalStateException("Couldn't create keys folder in data directory for directory authority.");
+ }
+ DirectoryAuthorityKeyGenerator.generate(directoryAuthority, passphrase);
}
- DirectoryAuthorityKeyGenerator.generate(directoryAuthority, passphrase);
-
allDirectoryAuthorities.add(directoryAuthority);
}