Skip to content

Commit

Permalink
Add restapi module (code from dao-node)
Browse files Browse the repository at this point in the history
  • Loading branch information
HenrikJannsen committed Jun 6, 2024
1 parent e1913dc commit 0ce2a74
Show file tree
Hide file tree
Showing 34 changed files with 13,262 additions and 18 deletions.
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,10 @@ deploy
/apitest/src/main/resources/dao-setup*
/.run
/regtest/data_dirs
/build-logic/app-start-plugin/out/*
/build-logic/docker-image-builder/out/*
/build-logic/gradle-tasks/out/*
/build-logic/packaging/out/*
/build-logic/regtest/out/*
/build-logic/toolchain-resolver/out/*
/build-logic/tor-binary/out/*
13 changes: 13 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ fontawesomefx-materialdesign-font = { strictly = '2.0.26-9.1.2' }

fxmisc-easybind = { strictly = '1.0.3' }

glassfish-jaxb-lib = { strictly = '3.0.2' }
google-findbugs = { strictly = '3.0.2' }
google-gson = { strictly = '2.8.6' }
google-guava = { strictly = '30.1.1-jre' }
Expand All @@ -28,6 +29,7 @@ hamcrest = { strictly = '2.2' }
jackson = { strictly = '2.17.1' }
javax-annotation = { strictly = '1.2' }
jcsv = { strictly = '1.4.0' }
jersey-lib = { strictly = '3.0.4' }
jetbrains-annotations = { strictly = '13.0' }
jfoenix = { strictly = '9.0.10' }
jopt = { strictly = '5.0.4' }
Expand All @@ -46,6 +48,7 @@ protobuf = { strictly = '3.19.1' }
qrgen = { strictly = '1.3' }
javacv = { strictly = '1.5.10' }
slf4j = { strictly = '1.7.30' }
swagger-lib = { strictly = '2.2.0' }

[libraries]
apache-httpclient = { module = "org.apache.httpcomponents:httpclient", version.ref = "apache-httpclient" }
Expand All @@ -66,6 +69,7 @@ fontawesomefx-materialdesign-font = { module = "de.jensd:fontawesomefx-materiald

fxmisc-easybind = { module = "org.fxmisc.easybind:easybind", version.ref = "fxmisc-easybind" }

glassfish-jaxb = { module = 'org.glassfish.jaxb:jaxb-runtime', version.ref = 'glassfish-jaxb-lib' }
google-findbugs = { module = "com.google.code.findbugs:jsr305", version.ref = "google-findbugs" }
google-gson = { module = "com.google.code.gson:gson", version.ref = "google-gson" }
google-guava = { module = "com.google.guava:guava", version.ref = "google-guava" }
Expand All @@ -84,6 +88,9 @@ jackson-databind = { module = "com.fasterxml.jackson.core:jackson-databind", ver

javax-annotation = { module = "javax.annotation:javax.annotation-api", version.ref = "javax-annotation" }
jcsv = { module = "com.googlecode.jcsv:jcsv", version.ref = "jcsv" }
jersey-container-jdk-http = { module = 'org.glassfish.jersey.containers:jersey-container-jdk-http', version.ref = 'jersey-lib' }
jersey-media-json-jackson = { module = 'org.glassfish.jersey.media:jersey-media-json-jackson', version.ref = 'jersey-lib' }
jersey-inject-jersey-hk2 = { module = 'org.glassfish.jersey.inject:jersey-hk2', version.ref = 'jersey-lib' }
jetbrains-annotations = { module = "org.jetbrains:annotations", version.ref = "jetbrains-annotations" }
jfoenix = { module = "com.jfoenix:jfoenix", version.ref = "jfoenix" }
jopt = { module = "net.sf.jopt-simple:jopt-simple", version.ref = "jopt" }
Expand Down Expand Up @@ -111,3 +118,9 @@ protobuf-java = { module = "com.google.protobuf:protobuf-java", version.ref = "p
qrgen = { module = "net.glxn:qrgen", version.ref = "qrgen" }
javacv = { module = "org.bytedeco:javacv-platform", version.ref = "javacv" }
slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" }
swagger = { module = 'io.swagger.core.v3:swagger-jaxrs2-jakarta', version.ref = 'swagger-lib' }

[bundles]
jersey-libs = ['jersey-container-jdk-http', 'jersey-media-json-jackson', 'jersey-inject-jersey-hk2']


709 changes: 691 additions & 18 deletions gradle/verification-metadata.xml

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions restapi/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Rest API application

The Rest API application provides access to Bisq network data as well as Bisq DAO data.
It is used for Bisq 2 to request data about the DAO state as well as account age and account witness data for reputation use cases.


Program arguments to run 'RestApiMain' with Bitcoin Regtest and localhost mode:
```
--baseCurrencyNetwork=BTC_REGTEST
--useDevPrivilegeKeys=true
--useLocalhostForP2P=true
--appName=[your app name]
--fullDaoNode=true
--rpcUser=[Bitcoin rpc username]
--rpcPassword=[Bitcoin rpc password]
--rpcPort=18443
--rpcBlockNotificationPort=[port used in blocknotify]
```

To run 'RestApiMain' you need to have Bitcoin node running and have 'blocknotify' in the `bitcoin.conf` set up.


34 changes: 34 additions & 0 deletions restapi/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
plugins {
id 'bisq.application'
id 'bisq.gradle.app_start_plugin.AppStartPlugin'
}

mainClassName = 'bisq.restapi.RestApiMain'

dependencies {
implementation project(':common')
implementation project(':p2p')
implementation project(':core')
annotationProcessor libs.lombok
compileOnly libs.lombok
implementation libs.slf4j.api
implementation(libs.google.guice) {
exclude(module: 'guava')
}

implementation libs.google.guava
implementation libs.google.guice

implementation libs.glassfish.jaxb
implementation libs.bundles.jersey.libs
implementation libs.swagger

implementation libs.logback.core
implementation libs.logback.classic
compileOnly libs.lombok
annotationProcessor libs.lombok
implementation libs.slf4j.api

testAnnotationProcessor libs.lombok
testCompileOnly libs.lombok
}
218 changes: 218 additions & 0 deletions restapi/src/main/java/bisq/daonode/RestApi.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
/*
* 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.daonode;


import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.app.TorSetup;
import bisq.core.app.misc.AppSetupWithP2PAndDAO;
import bisq.core.app.misc.ExecutableForAppWithP2p;
import bisq.core.app.misc.ModuleForAppWithP2p;
import bisq.core.dao.SignVerifyService;
import bisq.core.dao.governance.bond.reputation.BondedReputationRepository;
import bisq.core.dao.governance.bond.role.BondedRolesRepository;
import bisq.core.dao.state.DaoStateService;
import bisq.core.dao.state.DaoStateSnapshotService;
import bisq.core.user.Cookie;
import bisq.core.user.CookieKey;
import bisq.core.user.Preferences;
import bisq.core.user.User;

import bisq.network.p2p.P2PService;
import bisq.network.p2p.P2PServiceListener;
import bisq.network.p2p.peers.PeerManager;

import bisq.common.Timer;
import bisq.common.UserThread;
import bisq.common.app.AppModule;
import bisq.common.app.Version;
import bisq.common.config.BaseCurrencyNetwork;
import bisq.common.config.Config;
import bisq.common.handlers.ResultHandler;

import com.google.inject.Key;
import com.google.inject.name.Names;

import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
//todo not sure if the restart handling from seed nodes is required

@Slf4j
public class RestApi extends ExecutableForAppWithP2p {
private static final long CHECK_CONNECTION_LOSS_SEC = 30;

private Timer checkConnectionLossTime;
@Getter
private DaoStateService daoStateService;
@Getter
private BondedReputationRepository bondedReputationRepository;
@Getter
private AccountAgeWitnessService accountAgeWitnessService;
@Getter
private BondedRolesRepository bondedRolesRepository;
@Getter
private SignVerifyService signVerifyService;

public RestApi() {
super("Bisq Data Node", "bisq-data-node", "bisq_data_node", Version.VERSION);
}

public Config getConfig() {
return config;
}

@Override
protected void doExecute() {
super.doExecute();

checkMemory(config, this);
}

@Override
protected void launchApplication() {
UserThread.execute(() -> {
try {
onApplicationLaunched();
} catch (Exception e) {
e.printStackTrace();
}
});
}


///////////////////////////////////////////////////////////////////////////////////////////
// We continue with a series of synchronous execution tasks
///////////////////////////////////////////////////////////////////////////////////////////

@Override
protected AppModule getModule() {
return new ModuleForAppWithP2p(config);
}

@Override
protected void applyInjector() {
super.applyInjector();

injector.getInstance(DaoStateSnapshotService.class).setDaoRequiresRestartHandler(this::gracefulShutDown);
}

@Override
protected void startApplication() {
super.startApplication();

Cookie cookie = injector.getInstance(User.class).getCookie();
cookie.getAsOptionalBoolean(CookieKey.CLEAN_TOR_DIR_AT_RESTART).ifPresent(wasCleanTorDirSet -> {
if (wasCleanTorDirSet) {
injector.getInstance(TorSetup.class).cleanupTorFiles(() -> {
log.info("Tor directory reset");
cookie.remove(CookieKey.CLEAN_TOR_DIR_AT_RESTART);
}, log::error);
}
});

injector.getInstance(Preferences.class).setUseFullModeDaoMonitor(false);
injector.getInstance(AppSetupWithP2PAndDAO.class).start();

daoStateService = injector.getInstance(DaoStateService.class);
accountAgeWitnessService = injector.getInstance(AccountAgeWitnessService.class);
bondedReputationRepository = injector.getInstance(BondedReputationRepository.class);
bondedRolesRepository = injector.getInstance(BondedRolesRepository.class);
signVerifyService = injector.getInstance(SignVerifyService.class);

injector.getInstance(P2PService.class).addP2PServiceListener(new P2PServiceListener() {
@Override
public void onDataReceived() {
// Do nothing
}

@Override
public void onNoSeedNodeAvailable() {
// Do nothing
}

@Override
public void onNoPeersAvailable() {
// Do nothing
}

@Override
public void onUpdatedDataReceived() {
// Do nothing
}

@Override
public void onTorNodeReady() {
// Do nothing
}

@Override
public void onHiddenServicePublished() {
boolean preventPeriodicShutdownAtSeedNode = injector.getInstance(Key.get(boolean.class,
Names.named(Config.PREVENT_PERIODIC_SHUTDOWN_AT_SEED_NODE)));
if (!preventPeriodicShutdownAtSeedNode) {
startShutDownInterval(RestApi.this);
}
UserThread.runAfter(() -> setupConnectionLossCheck(), 60);

accountAgeWitnessService.onAllServicesInitialized();
}

@Override
public void onSetupFailed(Throwable throwable) {
// Do nothing
}

@Override
public void onRequestCustomBridges() {
// Do nothing
}
});
}

private void setupConnectionLossCheck() {
// For dev testing (usually on BTC_REGTEST) we don't want to get the seed shut
// down as it is normal that the seed is the only actively running node.
if (Config.baseCurrencyNetwork() == BaseCurrencyNetwork.BTC_REGTEST) {
return;
}

if (checkConnectionLossTime != null) {
return;
}

checkConnectionLossTime = UserThread.runPeriodically(() -> {
if (injector.getInstance(PeerManager.class).getNumAllConnectionsLostEvents() > 1) {
// We set a flag to clear tor cache files at re-start. We cannot clear it now as Tor is used and
// that can cause problems.
injector.getInstance(User.class).getCookie().putAsBoolean(CookieKey.CLEAN_TOR_DIR_AT_RESTART, true);
shutDown(this);
}
}, CHECK_CONNECTION_LOSS_SEC);

}

public void gracefulShutDown() {
gracefulShutDown(() -> {
});
}

@Override
public void gracefulShutDown(ResultHandler resultHandler) {
super.gracefulShutDown(resultHandler);
}
}
Loading

0 comments on commit 0ce2a74

Please sign in to comment.