mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-05-28 19:22:14 -04:00
Merge branch 'wip-cbeams'
Additional changes during the process of isolating TomP2P. High-level changes include: - Beginning to break up the monolithic MessageFacade into modular repository classes, starting with the OfferRepository interface and its TomP2P implementation - Major refactoring of the CreateOfferCoordinator class, eliminating the never-completely-implemented resume logic. This class still needs quite a bit of work, but it's now considerably simpler than it was - Refactoring the Node and BootstrapNode types for greater clarity and ease of use - Most classes that use the net.tomp2p API have been moved into tomp2p subpackages, e.g. io.bitsquare.offer.tomp2p. Classes within have been made package private wherever possible. - The Guice module structure has evolved. For example, note the relationship between offer.OfferModule and offer.tomp2p.TomP2POfferModule, and note how the latter is consumed by app.AppModule. This arrangement provides for clear contracts as to what is required to assemble a functioning Bitsquare application, while allowing implementation-specific modules to be swapped in and out with ease and still allowing implementation-specific classes to remain package-private. See extended commit comments for further details. * wip-cbeams: Rename io.bitsquare.{Abstract=>}BitsquareModule Move io.bitsquare.{network=>util}.tomp2p.BaseFutureUtil Introduce app.gui.MainModule Optimize imports Introduce io.bitsquare.msg.tomp2p package Introduce io.bitsquare.offer.tomp2p package Extract isSuccess(BaseFuture) method into util class Remove offer creation recovery from CreateOfferCoordinator Remove unused MessageFacade from CreateOfferCoordinator Inline BroadCastOfferFeeTx#run into CreateOfferCoordinator Inline CreateOfferFeeTx#run into CreateOfferCoordinator Replace VerifyOffer class with Offer#validate method Inline CreateOfferCoordinator#onFailed Rename methods used to implement *Handler lambdas Rename *Handler methods Move generic *Handler types to new util.task package Replace AddOfferListener Result/Fault handlers Introduce OfferRepository interface and TomP2P impl
This commit is contained in:
commit
5d56dc62c9
57 changed files with 1084 additions and 1196 deletions
|
@ -25,24 +25,24 @@ import com.google.inject.Injector;
|
|||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
public abstract class AbstractBitsquareModule extends AbstractModule {
|
||||
public abstract class BitsquareModule extends AbstractModule {
|
||||
|
||||
protected final Properties properties;
|
||||
|
||||
private final Set<AbstractBitsquareModule> modules = Sets.newHashSet();
|
||||
private final Set<BitsquareModule> modules = Sets.newHashSet();
|
||||
|
||||
protected AbstractBitsquareModule(Properties properties) {
|
||||
protected BitsquareModule(Properties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
protected void install(AbstractBitsquareModule module) {
|
||||
protected void install(BitsquareModule module) {
|
||||
super.install(module);
|
||||
modules.add(module);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close any instances this module is responsible for and recursively close any
|
||||
* sub-modules installed via {@link #install(AbstractBitsquareModule)}. This method
|
||||
* sub-modules installed via {@link #install(BitsquareModule)}. This method
|
||||
* must be called manually, e.g. at the end of a main() method or in the stop() method
|
||||
* of a JavaFX Application; alternatively it may be registered as a JVM shutdown hook.
|
||||
*
|
|
@ -17,25 +17,23 @@
|
|||
|
||||
package io.bitsquare.app;
|
||||
|
||||
import io.bitsquare.AbstractBitsquareModule;
|
||||
import io.bitsquare.BitsquareModule;
|
||||
import io.bitsquare.btc.BitcoinModule;
|
||||
import io.bitsquare.crypto.CryptoModule;
|
||||
import io.bitsquare.gui.GuiModule;
|
||||
import io.bitsquare.msg.DefaultMessageModule;
|
||||
import io.bitsquare.msg.MessageModule;
|
||||
import io.bitsquare.msg.tomp2p.TomP2PMessageModule;
|
||||
import io.bitsquare.offer.OfferModule;
|
||||
import io.bitsquare.offer.tomp2p.TomP2POfferModule;
|
||||
import io.bitsquare.persistence.Persistence;
|
||||
import io.bitsquare.settings.Settings;
|
||||
import io.bitsquare.trade.TradeModule;
|
||||
import io.bitsquare.user.User;
|
||||
import io.bitsquare.util.ConfigLoader;
|
||||
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.name.Names;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import net.tomp2p.connection.Ports;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
@ -44,19 +42,16 @@ import org.slf4j.LoggerFactory;
|
|||
import akka.actor.ActorSystem;
|
||||
import scala.concurrent.duration.Duration;
|
||||
|
||||
public class BitsquareModule extends AbstractBitsquareModule {
|
||||
/**
|
||||
* Configures all non-UI modules necessary to run a Bitsquare application.
|
||||
*/
|
||||
public class AppModule extends BitsquareModule {
|
||||
private static final Logger log = LoggerFactory.getLogger(AppModule.class);
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(BitsquareModule.class);
|
||||
private final Stage primaryStage;
|
||||
private final String appName;
|
||||
|
||||
public BitsquareModule(Stage primaryStage, String appName) {
|
||||
this(primaryStage, appName, ConfigLoader.loadConfig());
|
||||
}
|
||||
|
||||
public BitsquareModule(Stage primaryStage, String appName, Properties properties) {
|
||||
public AppModule(Properties properties, String appName) {
|
||||
super(properties);
|
||||
this.primaryStage = primaryStage;
|
||||
this.appName = appName;
|
||||
}
|
||||
|
||||
|
@ -70,7 +65,7 @@ public class BitsquareModule extends AbstractBitsquareModule {
|
|||
install(bitcoinModule());
|
||||
install(cryptoModule());
|
||||
install(tradeModule());
|
||||
install(guiModule());
|
||||
install(offerModule());
|
||||
|
||||
bindConstant().annotatedWith(Names.named("appName")).to(appName);
|
||||
bind(ActorSystem.class).toInstance(ActorSystem.create(appName));
|
||||
|
@ -80,7 +75,7 @@ public class BitsquareModule extends AbstractBitsquareModule {
|
|||
}
|
||||
|
||||
protected MessageModule messageModule() {
|
||||
return new DefaultMessageModule(properties);
|
||||
return new TomP2PMessageModule(properties);
|
||||
}
|
||||
|
||||
protected BitcoinModule bitcoinModule() {
|
||||
|
@ -95,9 +90,7 @@ public class BitsquareModule extends AbstractBitsquareModule {
|
|||
return new TradeModule(properties);
|
||||
}
|
||||
|
||||
protected GuiModule guiModule() {
|
||||
return new GuiModule(properties, primaryStage);
|
||||
}
|
||||
protected OfferModule offerModule() { return new TomP2POfferModule(properties); }
|
||||
|
||||
@Override
|
||||
protected void doClose(Injector injector) {
|
|
@ -18,7 +18,6 @@
|
|||
package io.bitsquare.app.gui;
|
||||
|
||||
import io.bitsquare.app.ArgumentParser;
|
||||
import io.bitsquare.app.BitsquareModule;
|
||||
import io.bitsquare.gui.Navigation;
|
||||
import io.bitsquare.gui.SystemTray;
|
||||
import io.bitsquare.gui.ViewLoader;
|
||||
|
@ -51,7 +50,7 @@ public class Main extends Application {
|
|||
private static final Logger log = LoggerFactory.getLogger(Main.class);
|
||||
private static String appName = "Bitsquare";
|
||||
|
||||
private BitsquareModule bitsquareModule;
|
||||
private MainModule mainModule;
|
||||
private Injector injector;
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
@ -67,8 +66,8 @@ public class Main extends Application {
|
|||
|
||||
@Override
|
||||
public void start(Stage primaryStage) {
|
||||
bitsquareModule = new BitsquareModule(primaryStage, appName);
|
||||
injector = Guice.createInjector(bitsquareModule);
|
||||
mainModule = new MainModule(appName, primaryStage);
|
||||
injector = Guice.createInjector(mainModule);
|
||||
|
||||
|
||||
// route uncaught exceptions to a user-facing dialog
|
||||
|
@ -138,7 +137,7 @@ public class Main extends Application {
|
|||
|
||||
@Override
|
||||
public void stop() {
|
||||
bitsquareModule.close(injector);
|
||||
mainModule.close(injector);
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
|
43
src/main/java/io/bitsquare/app/gui/MainModule.java
Normal file
43
src/main/java/io/bitsquare/app/gui/MainModule.java
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* This file is part of Bitsquare.
|
||||
*
|
||||
* Bitsquare 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.
|
||||
*
|
||||
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.app.gui;
|
||||
|
||||
import io.bitsquare.BitsquareModule;
|
||||
import io.bitsquare.app.AppModule;
|
||||
import io.bitsquare.gui.GuiModule;
|
||||
import io.bitsquare.util.ConfigLoader;
|
||||
|
||||
import javafx.stage.Stage;
|
||||
|
||||
class MainModule extends BitsquareModule {
|
||||
|
||||
private final String appName;
|
||||
private final Stage primaryStage;
|
||||
|
||||
public MainModule(String appName, Stage primaryStage) {
|
||||
super(ConfigLoader.loadConfig());
|
||||
this.appName = appName;
|
||||
this.primaryStage = primaryStage;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
install(new AppModule(properties, appName));
|
||||
install(new GuiModule(properties, primaryStage));
|
||||
}
|
||||
}
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
package io.bitsquare.btc;
|
||||
|
||||
import io.bitsquare.AbstractBitsquareModule;
|
||||
import io.bitsquare.BitsquareModule;
|
||||
|
||||
import org.bitcoinj.core.NetworkParameters;
|
||||
import org.bitcoinj.params.MainNetParams;
|
||||
|
@ -28,7 +28,7 @@ import com.google.inject.Injector;
|
|||
|
||||
import java.util.Properties;
|
||||
|
||||
public class BitcoinModule extends AbstractBitsquareModule {
|
||||
public class BitcoinModule extends BitsquareModule {
|
||||
|
||||
private static final BitcoinNetwork DEFAULT_NETWORK = BitcoinNetwork.REGTEST;
|
||||
|
||||
|
|
|
@ -17,11 +17,11 @@
|
|||
|
||||
package io.bitsquare.crypto;
|
||||
|
||||
import io.bitsquare.AbstractBitsquareModule;
|
||||
import io.bitsquare.BitsquareModule;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
public class CryptoModule extends AbstractBitsquareModule {
|
||||
public class CryptoModule extends BitsquareModule {
|
||||
|
||||
public CryptoModule(Properties properties) {
|
||||
super(properties);
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
package io.bitsquare.gui;
|
||||
|
||||
import io.bitsquare.AbstractBitsquareModule;
|
||||
import io.bitsquare.BitsquareModule;
|
||||
import io.bitsquare.gui.components.Popups;
|
||||
import io.bitsquare.gui.main.help.Help;
|
||||
import io.bitsquare.gui.main.trade.offerbook.OfferBook;
|
||||
|
@ -32,7 +32,7 @@ import java.util.Properties;
|
|||
|
||||
import javafx.stage.Stage;
|
||||
|
||||
public class GuiModule extends AbstractBitsquareModule {
|
||||
public class GuiModule extends BitsquareModule {
|
||||
|
||||
private final Stage primaryStage;
|
||||
|
||||
|
|
|
@ -20,9 +20,8 @@ package io.bitsquare.gui.main.trade.offerbook;
|
|||
import io.bitsquare.bank.BankAccount;
|
||||
import io.bitsquare.locale.Country;
|
||||
import io.bitsquare.locale.CurrencyUtil;
|
||||
import io.bitsquare.msg.MessageFacade;
|
||||
import io.bitsquare.msg.listeners.OfferBookListener;
|
||||
import io.bitsquare.offer.Offer;
|
||||
import io.bitsquare.offer.OfferRepository;
|
||||
import io.bitsquare.user.User;
|
||||
import io.bitsquare.util.Utilities;
|
||||
|
||||
|
@ -44,18 +43,18 @@ import static com.google.common.base.Preconditions.checkArgument;
|
|||
* Holds and manages the unsorted and unfiltered offerbook list of both buy and sell offers.
|
||||
* It is handled as singleton by Guice and is used by 2 instances of OfferBookModel (one for Buy one for Sell).
|
||||
* As it is used only by the Buy and Sell UIs we treat it as local UI model.
|
||||
* It also use OfferBookListener as the lists items class and we don't want to get any dependency out of the package
|
||||
* for that.
|
||||
* It also use OfferRepository.Listener as the lists items class and we don't want to get any dependency out of the
|
||||
* package for that.
|
||||
*/
|
||||
public class OfferBook {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(OfferBook.class);
|
||||
|
||||
private final MessageFacade messageFacade;
|
||||
private final OfferRepository offerRepository;
|
||||
private final User user;
|
||||
|
||||
private final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
||||
private final OfferBookListener offerBookListener;
|
||||
private final OfferRepository.Listener offerRepositoryListener;
|
||||
private final ChangeListener<BankAccount> bankAccountChangeListener;
|
||||
private final ChangeListener<Number> invalidationListener;
|
||||
private String fiatCode;
|
||||
|
@ -69,14 +68,14 @@ public class OfferBook {
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
OfferBook(MessageFacade messageFacade, User user) {
|
||||
this.messageFacade = messageFacade;
|
||||
OfferBook(OfferRepository offerRepository, User user) {
|
||||
this.offerRepository = offerRepository;
|
||||
this.user = user;
|
||||
|
||||
bankAccountChangeListener = (observableValue, oldValue, newValue) -> setBankAccount(newValue);
|
||||
invalidationListener = (ov, oldValue, newValue) -> requestOffers();
|
||||
|
||||
offerBookListener = new OfferBookListener() {
|
||||
offerRepositoryListener = new OfferRepository.Listener() {
|
||||
@Override
|
||||
public void onOfferAdded(Offer offer) {
|
||||
addOfferToOfferBookListItems(offer);
|
||||
|
@ -143,15 +142,15 @@ public class OfferBook {
|
|||
private void addListeners() {
|
||||
log.debug("addListeners ");
|
||||
user.currentBankAccountProperty().addListener(bankAccountChangeListener);
|
||||
messageFacade.addOfferBookListener(offerBookListener);
|
||||
messageFacade.invalidationTimestampProperty().addListener(invalidationListener);
|
||||
offerRepository.addListener(offerRepositoryListener);
|
||||
offerRepository.invalidationTimestampProperty().addListener(invalidationListener);
|
||||
}
|
||||
|
||||
private void removeListeners() {
|
||||
log.debug("removeListeners ");
|
||||
user.currentBankAccountProperty().removeListener(bankAccountChangeListener);
|
||||
messageFacade.removeOfferBookListener(offerBookListener);
|
||||
messageFacade.invalidationTimestampProperty().removeListener(invalidationListener);
|
||||
offerRepository.removeListener(offerRepositoryListener);
|
||||
offerRepository.invalidationTimestampProperty().removeListener(invalidationListener);
|
||||
}
|
||||
|
||||
private void addOfferToOfferBookListItems(Offer offer) {
|
||||
|
@ -161,7 +160,7 @@ public class OfferBook {
|
|||
}
|
||||
|
||||
private void requestOffers() {
|
||||
messageFacade.getOffers(fiatCode);
|
||||
offerRepository.getOffers(fiatCode);
|
||||
}
|
||||
|
||||
|
||||
|
@ -174,11 +173,11 @@ public class OfferBook {
|
|||
addListeners();
|
||||
setBankAccount(user.getCurrentBankAccount());
|
||||
pollingTimer = Utilities.setInterval(3000, (animationTimer) -> {
|
||||
messageFacade.requestInvalidationTimeStampFromDHT(fiatCode);
|
||||
offerRepository.requestInvalidationTimeStampFromDHT(fiatCode);
|
||||
return null;
|
||||
});
|
||||
|
||||
messageFacade.getOffers(fiatCode);
|
||||
offerRepository.getOffers(fiatCode);
|
||||
}
|
||||
|
||||
private void stopPolling() {
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* This file is part of Bitsquare.
|
||||
*
|
||||
* Bitsquare 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.
|
||||
*
|
||||
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.msg;
|
||||
|
||||
import io.bitsquare.AbstractBitsquareModule;
|
||||
import io.bitsquare.network.BootstrapNodes;
|
||||
import io.bitsquare.network.Node;
|
||||
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.name.Names;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
public class DefaultMessageModule extends AbstractBitsquareModule implements MessageModule {
|
||||
|
||||
public DefaultMessageModule(Properties properties) {
|
||||
super(properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(MessageFacade.class).to(TomP2PMessageFacade.class).asEagerSingleton();
|
||||
bind(P2PNode.class).asEagerSingleton();
|
||||
bind(BootstrappedPeerFactory.class).asEagerSingleton();
|
||||
bind(DHTSeedService.class);
|
||||
|
||||
// we will probably later use disk storage instead of memory storage for TomP2P
|
||||
bind(Boolean.class).annotatedWith(Names.named("useDiskStorage")).toInstance(false);
|
||||
|
||||
bind(Node.class)
|
||||
.annotatedWith(Names.named("bootstrapNode"))
|
||||
.toInstance(BootstrapNodes.LOCALHOST);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doClose(Injector injector) {
|
||||
injector.getInstance(MessageFacade.class).shutDown();
|
||||
}
|
||||
}
|
|
@ -18,22 +18,17 @@
|
|||
package io.bitsquare.msg;
|
||||
|
||||
import io.bitsquare.arbitrator.Arbitrator;
|
||||
import io.bitsquare.msg.listeners.AddOfferListener;
|
||||
import io.bitsquare.msg.listeners.ArbitratorListener;
|
||||
import io.bitsquare.msg.listeners.BootstrapListener;
|
||||
import io.bitsquare.msg.listeners.GetPeerAddressListener;
|
||||
import io.bitsquare.msg.listeners.IncomingMessageListener;
|
||||
import io.bitsquare.msg.listeners.OfferBookListener;
|
||||
import io.bitsquare.msg.listeners.OutgoingMessageListener;
|
||||
import io.bitsquare.network.Peer;
|
||||
import io.bitsquare.offer.Offer;
|
||||
|
||||
import java.security.PublicKey;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import javafx.beans.property.LongProperty;
|
||||
|
||||
public interface MessageFacade extends MessageBroker {
|
||||
|
||||
void sendMessage(Peer peer, Message message, OutgoingMessageListener listener);
|
||||
|
@ -46,25 +41,11 @@ public interface MessageFacade extends MessageBroker {
|
|||
|
||||
void removeIncomingMessageListener(IncomingMessageListener listener);
|
||||
|
||||
void addOffer(Offer offer, AddOfferListener addOfferListener);
|
||||
|
||||
void addArbitratorListener(ArbitratorListener listener);
|
||||
|
||||
void getArbitrators(Locale defaultLanguageLocale);
|
||||
|
||||
LongProperty invalidationTimestampProperty();
|
||||
|
||||
void addOfferBookListener(OfferBookListener offerBookListener);
|
||||
|
||||
void requestInvalidationTimeStampFromDHT(String fiatCode);
|
||||
|
||||
void getOffers(String fiatCode);
|
||||
|
||||
void removeOffer(Offer offer);
|
||||
|
||||
void init(int clientPort, BootstrapListener bootstrapListener);
|
||||
|
||||
void getPeerAddress(PublicKey messagePublicKey, GetPeerAddressListener getPeerAddressListener);
|
||||
|
||||
void removeOfferBookListener(OfferBookListener offerBookListener);
|
||||
}
|
||||
|
|
|
@ -17,7 +17,43 @@
|
|||
|
||||
package io.bitsquare.msg;
|
||||
|
||||
import com.google.inject.Module;
|
||||
import io.bitsquare.BitsquareModule;
|
||||
import io.bitsquare.network.BootstrapNodes;
|
||||
import io.bitsquare.network.Node;
|
||||
|
||||
public interface MessageModule extends Module {
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.name.Names;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
public abstract class MessageModule extends BitsquareModule {
|
||||
|
||||
protected MessageModule(Properties properties) {
|
||||
super(properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void configure() {
|
||||
bind(MessageFacade.class).to(messageFacade()).asEagerSingleton();
|
||||
bind(DHTSeedService.class);
|
||||
|
||||
// we will probably later use disk storage instead of memory storage for TomP2P
|
||||
bind(Boolean.class).annotatedWith(Names.named("useDiskStorage")).toInstance(false);
|
||||
|
||||
bind(Node.class)
|
||||
.annotatedWith(Names.named("bootstrapNode"))
|
||||
.toInstance(BootstrapNodes.DIGITAL_OCEAN_1);
|
||||
|
||||
doConfigure();
|
||||
}
|
||||
|
||||
protected void doConfigure() {
|
||||
}
|
||||
|
||||
protected abstract Class<? extends MessageFacade> messageFacade();
|
||||
|
||||
@Override
|
||||
protected void doClose(Injector injector) {
|
||||
injector.getInstance(MessageFacade.class).shutDown();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,564 +0,0 @@
|
|||
/*
|
||||
* This file is part of Bitsquare.
|
||||
*
|
||||
* Bitsquare 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.
|
||||
*
|
||||
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.msg;
|
||||
|
||||
import io.bitsquare.arbitrator.Arbitrator;
|
||||
import io.bitsquare.msg.listeners.AddOfferListener;
|
||||
import io.bitsquare.msg.listeners.ArbitratorListener;
|
||||
import io.bitsquare.msg.listeners.BootstrapListener;
|
||||
import io.bitsquare.msg.listeners.GetPeerAddressListener;
|
||||
import io.bitsquare.msg.listeners.IncomingMessageListener;
|
||||
import io.bitsquare.msg.listeners.OfferBookListener;
|
||||
import io.bitsquare.msg.listeners.OutgoingMessageListener;
|
||||
import io.bitsquare.network.Peer;
|
||||
import io.bitsquare.network.tomp2p.TomP2PPeer;
|
||||
import io.bitsquare.offer.Offer;
|
||||
import io.bitsquare.user.User;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import java.security.PublicKey;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.LongProperty;
|
||||
import javafx.beans.property.SimpleLongProperty;
|
||||
|
||||
import net.tomp2p.dht.FutureGet;
|
||||
import net.tomp2p.dht.FuturePut;
|
||||
import net.tomp2p.dht.FutureRemove;
|
||||
import net.tomp2p.futures.BaseFuture;
|
||||
import net.tomp2p.futures.BaseFutureAdapter;
|
||||
import net.tomp2p.futures.BaseFutureListener;
|
||||
import net.tomp2p.futures.FutureDirect;
|
||||
import net.tomp2p.peers.Number160;
|
||||
import net.tomp2p.peers.Number640;
|
||||
import net.tomp2p.storage.Data;
|
||||
import net.tomp2p.utils.Utils;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
/**
|
||||
* That facade delivers direct messaging and DHT functionality from the TomP2P library
|
||||
* It is the translating domain specific functionality to the messaging layer.
|
||||
* The TomP2P library codebase shall not be used outside that facade.
|
||||
* That way we limit the dependency of the TomP2P library only to that class (and it's sub components).
|
||||
* <p>
|
||||
* TODO: improve callbacks that Platform.runLater is not necessary. We call usually that methods form teh UI thread.
|
||||
*/
|
||||
class TomP2PMessageFacade implements MessageFacade {
|
||||
private static final Logger log = LoggerFactory.getLogger(TomP2PMessageFacade.class);
|
||||
private static final String ARBITRATORS_ROOT = "ArbitratorsRoot";
|
||||
|
||||
private final P2PNode p2pNode;
|
||||
private final User user;
|
||||
|
||||
private final List<OfferBookListener> offerBookListeners = new ArrayList<>();
|
||||
private final List<ArbitratorListener> arbitratorListeners = new ArrayList<>();
|
||||
private final List<IncomingMessageListener> incomingMessageListeners = new ArrayList<>();
|
||||
private final LongProperty invalidationTimestamp = new SimpleLongProperty(0);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
public TomP2PMessageFacade(User user, P2PNode p2pNode) {
|
||||
this.user = user;
|
||||
this.p2pNode = p2pNode;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Public Methods
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void init(int port, BootstrapListener bootstrapListener) {
|
||||
p2pNode.setMessageBroker(this);
|
||||
p2pNode.setKeyPair(user.getMessageKeyPair());
|
||||
|
||||
p2pNode.start(port, bootstrapListener);
|
||||
}
|
||||
|
||||
public void shutDown() {
|
||||
if (p2pNode != null)
|
||||
p2pNode.shutDown();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Find peer address by publicKey
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
public void getPeerAddress(PublicKey publicKey, GetPeerAddressListener listener) {
|
||||
final Number160 locationKey = Utils.makeSHAHash(publicKey.getEncoded());
|
||||
FutureGet futureGet = p2pNode.getDomainProtectedData(locationKey, publicKey);
|
||||
|
||||
futureGet.addListener(new BaseFutureAdapter<BaseFuture>() {
|
||||
@Override
|
||||
public void operationComplete(BaseFuture baseFuture) throws Exception {
|
||||
if (isSuccess(baseFuture) && futureGet.data() != null) {
|
||||
final Peer peer = (Peer) futureGet.data().object();
|
||||
Platform.runLater(() -> listener.onResult(peer));
|
||||
}
|
||||
else {
|
||||
Platform.runLater(listener::onFailed);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Offer
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void addOffer(Offer offer, AddOfferListener addOfferListener) {
|
||||
Number160 locationKey = Number160.createHash(offer.getCurrency().getCurrencyCode());
|
||||
try {
|
||||
final Data offerData = new Data(offer);
|
||||
|
||||
// the offer is default 30 days valid
|
||||
int defaultOfferTTL = 30 * 24 * 60 * 60;
|
||||
offerData.ttlSeconds(defaultOfferTTL);
|
||||
log.trace("Add offer to DHT requested. Added data: [locationKey: " + locationKey +
|
||||
", hash: " + offerData.hash().toString() + "]");
|
||||
FuturePut futurePut = p2pNode.addProtectedData(locationKey, offerData);
|
||||
futurePut.addListener(new BaseFutureListener<BaseFuture>() {
|
||||
@Override
|
||||
public void operationComplete(BaseFuture future) throws Exception {
|
||||
if (isSuccess(future)) {
|
||||
Platform.runLater(() -> {
|
||||
addOfferListener.onComplete();
|
||||
offerBookListeners.stream().forEach(listener -> {
|
||||
try {
|
||||
Object offerDataObject = offerData.object();
|
||||
if (offerDataObject instanceof Offer) {
|
||||
log.error("Added offer to DHT with ID: " + ((Offer)
|
||||
offerDataObject).getId());
|
||||
listener.onOfferAdded((Offer) offerDataObject);
|
||||
}
|
||||
} catch (ClassNotFoundException | IOException e) {
|
||||
e.printStackTrace();
|
||||
log.error("Add offer to DHT failed: " + e.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
// TODO will be removed when we don't use polling anymore
|
||||
writeInvalidationTimestampToDHT(locationKey);
|
||||
log.trace("Add offer to DHT was successful. Added data: " +
|
||||
"[locationKey: " + locationKey +
|
||||
", value: " + offerData + "]");
|
||||
});
|
||||
}
|
||||
else {
|
||||
Platform.runLater(() -> {
|
||||
addOfferListener.onFailed("Add offer to DHT failed.",
|
||||
new Exception("Add offer to DHT failed. Reason: " + future
|
||||
.failedReason()));
|
||||
log.error("Add offer to DHT failed. Reason: " + future.failedReason
|
||||
());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(Throwable t) throws Exception {
|
||||
Platform.runLater(() -> {
|
||||
addOfferListener.onFailed("Add offer to DHT failed with an exception.",
|
||||
t);
|
||||
log.error("Add offer to DHT failed with an exception: " + t.getMessage());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
} catch (IOException e) {
|
||||
Platform.runLater(() -> {
|
||||
addOfferListener.onFailed("Add offer to DHT failed with an exception.", e);
|
||||
log.error("Add offer to DHT failed with an exception: " + e.getMessage());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//TODO remove is failing, probably due Coin or Fiat class (was working before)
|
||||
// objects are identical but returned object form network might have some problem with serialisation?
|
||||
|
||||
public void removeOffer(Offer offer) {
|
||||
Number160 locationKey = Number160.createHash(offer.getCurrency().getCurrencyCode());
|
||||
try {
|
||||
final Data offerData = new Data(offer);
|
||||
log.trace("Remove offer from DHT requested. Removed data: [locationKey: " + locationKey +
|
||||
", hash: " + offerData.hash().toString() + "]");
|
||||
FutureRemove futureRemove = p2pNode.removeFromDataMap(locationKey, offerData);
|
||||
futureRemove.addListener(new BaseFutureListener<BaseFuture>() {
|
||||
@Override
|
||||
public void operationComplete(BaseFuture future) throws Exception {
|
||||
if (isSuccess(future)) {
|
||||
Platform.runLater(() -> {
|
||||
offerBookListeners.stream().forEach(offerBookListener -> {
|
||||
try {
|
||||
Object offerDataObject = offerData.object();
|
||||
if (offerDataObject instanceof Offer) {
|
||||
log.trace("Remove offer from DHT was successful. Removed data: [key: " +
|
||||
locationKey + ", " +
|
||||
"offer: " + offerDataObject + "]");
|
||||
offerBookListener.onOfferRemoved((Offer) offerDataObject);
|
||||
}
|
||||
} catch (ClassNotFoundException | IOException e) {
|
||||
e.printStackTrace();
|
||||
log.error("Remove offer from DHT failed. Error: " + e.getMessage());
|
||||
}
|
||||
});
|
||||
writeInvalidationTimestampToDHT(locationKey);
|
||||
});
|
||||
}
|
||||
else {
|
||||
log.error("Remove offer from DHT failed. Cause: future.isSuccess() = false, locationKey: " +
|
||||
locationKey + ", Reason: " + future.failedReason());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(Throwable t) throws Exception {
|
||||
log.error("Remove offer from DHT failed. Error: " + t.getMessage());
|
||||
}
|
||||
});
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
log.error("Remove offer from DHT failed. Error: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void getOffers(String currencyCode) {
|
||||
Number160 locationKey = Number160.createHash(currencyCode);
|
||||
log.trace("Get offers from DHT requested for locationKey: " + locationKey);
|
||||
FutureGet futureGet = p2pNode.getDataMap(locationKey);
|
||||
futureGet.addListener(new BaseFutureAdapter<BaseFuture>() {
|
||||
@Override
|
||||
public void operationComplete(BaseFuture baseFuture) throws Exception {
|
||||
if (isSuccess(baseFuture)) {
|
||||
final Map<Number640, Data> dataMap = futureGet.dataMap();
|
||||
final List<Offer> offers = new ArrayList<>();
|
||||
if (dataMap != null) {
|
||||
for (Data offerData : dataMap.values()) {
|
||||
try {
|
||||
Object offerDataObject = offerData.object();
|
||||
if (offerDataObject instanceof Offer) {
|
||||
offers.add((Offer) offerDataObject);
|
||||
}
|
||||
} catch (ClassNotFoundException | IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
Platform.runLater(() -> offerBookListeners.stream().forEach(listener ->
|
||||
listener.onOffersReceived(offers)));
|
||||
}
|
||||
|
||||
log.trace("Get offers from DHT was successful. Stored data: [key: " + locationKey
|
||||
+ ", values: " + futureGet.dataMap() + "]");
|
||||
}
|
||||
else {
|
||||
final Map<Number640, Data> dataMap = futureGet.dataMap();
|
||||
if (dataMap == null || dataMap.size() == 0) {
|
||||
log.trace("Get offers from DHT delivered empty dataMap.");
|
||||
Platform.runLater(() -> offerBookListeners.stream().forEach(listener ->
|
||||
listener.onOffersReceived(new ArrayList<>())));
|
||||
}
|
||||
else {
|
||||
log.error("Get offers from DHT was not successful with reason:" + baseFuture.failedReason());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Trade process
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void sendMessage(Peer peer, Message message,
|
||||
OutgoingMessageListener listener) {
|
||||
if (!(peer instanceof TomP2PPeer)) {
|
||||
throw new IllegalArgumentException("peer must be of type TomP2PPeer");
|
||||
}
|
||||
FutureDirect futureDirect = p2pNode.sendData(((TomP2PPeer) peer).getPeerAddress(), message);
|
||||
futureDirect.addListener(new BaseFutureListener<BaseFuture>() {
|
||||
@Override
|
||||
public void operationComplete(BaseFuture future) throws Exception {
|
||||
if (isSuccess(futureDirect)) {
|
||||
Platform.runLater(listener::onResult);
|
||||
}
|
||||
else {
|
||||
Platform.runLater(listener::onFailed);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(Throwable t) throws Exception {
|
||||
Platform.runLater(listener::onFailed);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Arbitrators
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void addArbitrator(Arbitrator arbitrator) {
|
||||
Number160 locationKey = Number160.createHash(ARBITRATORS_ROOT);
|
||||
try {
|
||||
final Data arbitratorData = new Data(arbitrator);
|
||||
|
||||
FuturePut addFuture = p2pNode.addProtectedData(locationKey, arbitratorData);
|
||||
addFuture.addListener(new BaseFutureAdapter<BaseFuture>() {
|
||||
@Override
|
||||
public void operationComplete(BaseFuture future) throws Exception {
|
||||
Platform.runLater(() -> arbitratorListeners.stream().forEach(listener ->
|
||||
{
|
||||
try {
|
||||
Object arbitratorDataObject = arbitratorData.object();
|
||||
if (arbitratorDataObject instanceof Arbitrator) {
|
||||
listener.onArbitratorAdded((Arbitrator) arbitratorDataObject);
|
||||
}
|
||||
} catch (ClassNotFoundException | IOException e) {
|
||||
e.printStackTrace();
|
||||
log.error(e.toString());
|
||||
}
|
||||
}));
|
||||
|
||||
if (isSuccess(addFuture)) {
|
||||
log.trace("Add arbitrator to DHT was successful. Stored data: [key: " + locationKey + ", " +
|
||||
"values: " + arbitratorData + "]");
|
||||
}
|
||||
else {
|
||||
log.error("Add arbitrator to DHT failed with reason:" + addFuture.failedReason());
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeArbitrator(Arbitrator arbitrator) throws IOException {
|
||||
Number160 locationKey = Number160.createHash(ARBITRATORS_ROOT);
|
||||
final Data arbitratorData = new Data(arbitrator);
|
||||
FutureRemove removeFuture = p2pNode.removeFromDataMap(locationKey, arbitratorData);
|
||||
removeFuture.addListener(new BaseFutureAdapter<BaseFuture>() {
|
||||
@Override
|
||||
public void operationComplete(BaseFuture future) throws Exception {
|
||||
Platform.runLater(() -> arbitratorListeners.stream().forEach(listener ->
|
||||
{
|
||||
for (Data arbitratorData : removeFuture.dataMap().values()) {
|
||||
try {
|
||||
Object arbitratorDataObject = arbitratorData.object();
|
||||
if (arbitratorDataObject instanceof Arbitrator) {
|
||||
Arbitrator arbitrator = (Arbitrator) arbitratorDataObject;
|
||||
listener.onArbitratorRemoved(arbitrator);
|
||||
}
|
||||
} catch (ClassNotFoundException | IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}));
|
||||
if (isSuccess(removeFuture)) {
|
||||
log.trace("Remove arbitrator from DHT was successful. Stored data: [key: " + locationKey + ", " +
|
||||
"values: " + arbitratorData + "]");
|
||||
}
|
||||
else {
|
||||
log.error("Remove arbitrators from DHT failed with reason:" + removeFuture.failedReason());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void getArbitrators(Locale languageLocale) {
|
||||
Number160 locationKey = Number160.createHash(ARBITRATORS_ROOT);
|
||||
FutureGet futureGet = p2pNode.getDataMap(locationKey);
|
||||
futureGet.addListener(new BaseFutureAdapter<BaseFuture>() {
|
||||
@Override
|
||||
public void operationComplete(BaseFuture baseFuture) throws Exception {
|
||||
Platform.runLater(() -> arbitratorListeners.stream().forEach(listener ->
|
||||
{
|
||||
List<Arbitrator> arbitrators = new ArrayList<>();
|
||||
for (Data arbitratorData : futureGet.dataMap().values()) {
|
||||
try {
|
||||
Object arbitratorDataObject = arbitratorData.object();
|
||||
if (arbitratorDataObject instanceof Arbitrator) {
|
||||
arbitrators.add((Arbitrator) arbitratorDataObject);
|
||||
}
|
||||
} catch (ClassNotFoundException | IOException e) {
|
||||
e.printStackTrace();
|
||||
log.error("Get arbitrators from DHT failed with exception:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
listener.onArbitratorsReceived(arbitrators);
|
||||
}));
|
||||
if (isSuccess(baseFuture)) {
|
||||
log.trace("Get arbitrators from DHT was successful. Stored data: [key: " + locationKey + ", " +
|
||||
"values: " + futureGet.dataMap() + "]");
|
||||
}
|
||||
else {
|
||||
log.error("Get arbitrators from DHT failed with reason:" + baseFuture.failedReason());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Event Listeners
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void addOfferBookListener(OfferBookListener listener) {
|
||||
offerBookListeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeOfferBookListener(OfferBookListener listener) {
|
||||
offerBookListeners.remove(listener);
|
||||
}
|
||||
|
||||
public void addArbitratorListener(ArbitratorListener listener) {
|
||||
arbitratorListeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeArbitratorListener(ArbitratorListener listener) {
|
||||
arbitratorListeners.remove(listener);
|
||||
}
|
||||
|
||||
public void addIncomingMessageListener(IncomingMessageListener listener) {
|
||||
incomingMessageListeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeIncomingMessageListener(IncomingMessageListener listener) {
|
||||
incomingMessageListeners.remove(listener);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* We store the timestamp of any change of the offer list (add, remove offer) and we poll in intervals for changes.
|
||||
* If we detect a change we request the offer list from the DHT.
|
||||
* Polling should be replaced by a push based solution later.
|
||||
*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Polling
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void writeInvalidationTimestampToDHT(Number160 locationKey) {
|
||||
invalidationTimestamp.set(System.currentTimeMillis());
|
||||
try {
|
||||
FuturePut putFuture = p2pNode.putData(getInvalidatedLocationKey(locationKey),
|
||||
new Data(invalidationTimestamp.get()));
|
||||
putFuture.addListener(new BaseFutureListener<BaseFuture>() {
|
||||
@Override
|
||||
public void operationComplete(BaseFuture future) throws Exception {
|
||||
if (isSuccess(putFuture))
|
||||
log.trace("Update invalidationTimestamp to DHT was successful. TimeStamp=" +
|
||||
invalidationTimestamp.get());
|
||||
else
|
||||
log.error("Update invalidationTimestamp to DHT failed with reason:" + putFuture.failedReason());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(Throwable t) throws Exception {
|
||||
log.error("Update invalidationTimestamp to DHT failed with exception:" + t.getMessage());
|
||||
}
|
||||
});
|
||||
} catch (IOException e) {
|
||||
log.error("Update invalidationTimestamp to DHT failed with exception:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public LongProperty invalidationTimestampProperty() {
|
||||
return invalidationTimestamp;
|
||||
}
|
||||
|
||||
public void requestInvalidationTimeStampFromDHT(String currencyCode) {
|
||||
Number160 locationKey = Number160.createHash(currencyCode);
|
||||
FutureGet getFuture = p2pNode.getData(getInvalidatedLocationKey(locationKey));
|
||||
getFuture.addListener(new BaseFutureListener<BaseFuture>() {
|
||||
@Override
|
||||
public void operationComplete(BaseFuture future) throws Exception {
|
||||
if (isSuccess(getFuture)) {
|
||||
Data data = getFuture.data();
|
||||
if (data != null && data.object() instanceof Long) {
|
||||
final Object object = data.object();
|
||||
Platform.runLater(() -> {
|
||||
Long timeStamp = (Long) object;
|
||||
//log.trace("Get invalidationTimestamp from DHT was successful. TimeStamp=" + timeStamp);
|
||||
invalidationTimestamp.set(timeStamp);
|
||||
});
|
||||
}
|
||||
else if (data != null) {
|
||||
log.error("Get invalidationTimestamp from DHT failed. Data = " + data);
|
||||
}
|
||||
}
|
||||
else if (getFuture.data() == null) {
|
||||
// OK as nothing is set at the moment
|
||||
log.trace("Get invalidationTimestamp from DHT returns null. That is ok for the startup.");
|
||||
}
|
||||
else {
|
||||
log.error("Get invalidationTimestamp from DHT failed with reason:" + getFuture.failedReason());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(Throwable t) throws Exception {
|
||||
log.error("Get invalidationTimestamp from DHT failed with exception:" + t.getMessage());
|
||||
t.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Number160 getInvalidatedLocationKey(Number160 locationKey) {
|
||||
return Number160.createHash(locationKey + "invalidated");
|
||||
}
|
||||
|
||||
// Isolate the success handling as there is bug in port forwarding mode
|
||||
private boolean isSuccess(BaseFuture baseFuture) {
|
||||
// return baseFuture.isSuccess();
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Incoming message handler
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void handleMessage(Object message, Peer sender) {
|
||||
if (message instanceof Message) {
|
||||
Platform.runLater(() -> incomingMessageListeners.stream().forEach(e ->
|
||||
e.onMessage((Message) message, sender)));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@
|
|||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.msg;
|
||||
package io.bitsquare.msg.tomp2p;
|
||||
|
||||
import io.bitsquare.network.BootstrapState;
|
||||
import io.bitsquare.network.Node;
|
||||
|
@ -65,7 +65,7 @@ import org.slf4j.LoggerFactory;
|
|||
/**
|
||||
* Creates a DHT peer and bootstrap to the network via a seed node
|
||||
*/
|
||||
public class BootstrappedPeerFactory {
|
||||
class BootstrappedPeerFactory {
|
||||
private static final Logger log = LoggerFactory.getLogger(BootstrappedPeerFactory.class);
|
||||
|
||||
private KeyPair keyPair;
|
298
src/main/java/io/bitsquare/msg/tomp2p/TomP2PMessageFacade.java
Normal file
298
src/main/java/io/bitsquare/msg/tomp2p/TomP2PMessageFacade.java
Normal file
|
@ -0,0 +1,298 @@
|
|||
/*
|
||||
* This file is part of Bitsquare.
|
||||
*
|
||||
* Bitsquare 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.
|
||||
*
|
||||
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.msg.tomp2p;
|
||||
|
||||
import io.bitsquare.arbitrator.Arbitrator;
|
||||
import io.bitsquare.msg.Message;
|
||||
import io.bitsquare.msg.MessageFacade;
|
||||
import io.bitsquare.msg.listeners.ArbitratorListener;
|
||||
import io.bitsquare.msg.listeners.BootstrapListener;
|
||||
import io.bitsquare.msg.listeners.GetPeerAddressListener;
|
||||
import io.bitsquare.msg.listeners.IncomingMessageListener;
|
||||
import io.bitsquare.msg.listeners.OutgoingMessageListener;
|
||||
import io.bitsquare.network.Peer;
|
||||
import io.bitsquare.network.tomp2p.TomP2PPeer;
|
||||
import io.bitsquare.user.User;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import java.security.PublicKey;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import javafx.application.Platform;
|
||||
|
||||
import net.tomp2p.dht.FutureGet;
|
||||
import net.tomp2p.dht.FuturePut;
|
||||
import net.tomp2p.dht.FutureRemove;
|
||||
import net.tomp2p.futures.BaseFuture;
|
||||
import net.tomp2p.futures.BaseFutureAdapter;
|
||||
import net.tomp2p.futures.BaseFutureListener;
|
||||
import net.tomp2p.futures.FutureDirect;
|
||||
import net.tomp2p.peers.Number160;
|
||||
import net.tomp2p.storage.Data;
|
||||
import net.tomp2p.utils.Utils;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static io.bitsquare.util.tomp2p.BaseFutureUtil.isSuccess;
|
||||
|
||||
|
||||
/**
|
||||
* That facade delivers direct messaging and DHT functionality from the TomP2P library
|
||||
* It is the translating domain specific functionality to the messaging layer.
|
||||
* The TomP2P library codebase shall not be used outside that facade.
|
||||
* That way we limit the dependency of the TomP2P library only to that class (and it's sub components).
|
||||
* <p>
|
||||
* TODO: improve callbacks that Platform.runLater is not necessary. We call usually that methods form teh UI thread.
|
||||
*/
|
||||
class TomP2PMessageFacade implements MessageFacade {
|
||||
private static final Logger log = LoggerFactory.getLogger(TomP2PMessageFacade.class);
|
||||
private static final String ARBITRATORS_ROOT = "ArbitratorsRoot";
|
||||
|
||||
private final TomP2PNode p2pNode;
|
||||
private final User user;
|
||||
|
||||
private final List<ArbitratorListener> arbitratorListeners = new ArrayList<>();
|
||||
private final List<IncomingMessageListener> incomingMessageListeners = new ArrayList<>();
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
public TomP2PMessageFacade(User user, TomP2PNode p2pNode) {
|
||||
this.user = user;
|
||||
this.p2pNode = p2pNode;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Public Methods
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void init(int port, BootstrapListener bootstrapListener) {
|
||||
p2pNode.setMessageBroker(this);
|
||||
p2pNode.setKeyPair(user.getMessageKeyPair());
|
||||
|
||||
p2pNode.start(port, bootstrapListener);
|
||||
}
|
||||
|
||||
public void shutDown() {
|
||||
if (p2pNode != null)
|
||||
p2pNode.shutDown();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Find peer address by publicKey
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
public void getPeerAddress(PublicKey publicKey, GetPeerAddressListener listener) {
|
||||
final Number160 locationKey = Utils.makeSHAHash(publicKey.getEncoded());
|
||||
FutureGet futureGet = p2pNode.getDomainProtectedData(locationKey, publicKey);
|
||||
|
||||
futureGet.addListener(new BaseFutureAdapter<BaseFuture>() {
|
||||
@Override
|
||||
public void operationComplete(BaseFuture baseFuture) throws Exception {
|
||||
if (isSuccess(baseFuture) && futureGet.data() != null) {
|
||||
final Peer peer = (Peer) futureGet.data().object();
|
||||
Platform.runLater(() -> listener.onResult(peer));
|
||||
}
|
||||
else {
|
||||
Platform.runLater(listener::onFailed);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Trade process
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void sendMessage(Peer peer, Message message,
|
||||
OutgoingMessageListener listener) {
|
||||
if (!(peer instanceof TomP2PPeer)) {
|
||||
throw new IllegalArgumentException("peer must be of type TomP2PPeer");
|
||||
}
|
||||
FutureDirect futureDirect = p2pNode.sendData(((TomP2PPeer) peer).getPeerAddress(), message);
|
||||
futureDirect.addListener(new BaseFutureListener<BaseFuture>() {
|
||||
@Override
|
||||
public void operationComplete(BaseFuture future) throws Exception {
|
||||
if (isSuccess(futureDirect)) {
|
||||
Platform.runLater(listener::onResult);
|
||||
}
|
||||
else {
|
||||
Platform.runLater(listener::onFailed);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(Throwable t) throws Exception {
|
||||
Platform.runLater(listener::onFailed);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Arbitrators
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void addArbitrator(Arbitrator arbitrator) {
|
||||
Number160 locationKey = Number160.createHash(ARBITRATORS_ROOT);
|
||||
try {
|
||||
final Data arbitratorData = new Data(arbitrator);
|
||||
|
||||
FuturePut addFuture = p2pNode.addProtectedData(locationKey, arbitratorData);
|
||||
addFuture.addListener(new BaseFutureAdapter<BaseFuture>() {
|
||||
@Override
|
||||
public void operationComplete(BaseFuture future) throws Exception {
|
||||
Platform.runLater(() -> arbitratorListeners.stream().forEach(listener ->
|
||||
{
|
||||
try {
|
||||
Object arbitratorDataObject = arbitratorData.object();
|
||||
if (arbitratorDataObject instanceof Arbitrator) {
|
||||
listener.onArbitratorAdded((Arbitrator) arbitratorDataObject);
|
||||
}
|
||||
} catch (ClassNotFoundException | IOException e) {
|
||||
e.printStackTrace();
|
||||
log.error(e.toString());
|
||||
}
|
||||
}));
|
||||
|
||||
if (isSuccess(addFuture)) {
|
||||
log.trace("Add arbitrator to DHT was successful. Stored data: [key: " + locationKey + ", " +
|
||||
"values: " + arbitratorData + "]");
|
||||
}
|
||||
else {
|
||||
log.error("Add arbitrator to DHT failed with reason:" + addFuture.failedReason());
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeArbitrator(Arbitrator arbitrator) throws IOException {
|
||||
Number160 locationKey = Number160.createHash(ARBITRATORS_ROOT);
|
||||
final Data arbitratorData = new Data(arbitrator);
|
||||
FutureRemove removeFuture = p2pNode.removeFromDataMap(locationKey, arbitratorData);
|
||||
removeFuture.addListener(new BaseFutureAdapter<BaseFuture>() {
|
||||
@Override
|
||||
public void operationComplete(BaseFuture future) throws Exception {
|
||||
Platform.runLater(() -> arbitratorListeners.stream().forEach(listener ->
|
||||
{
|
||||
for (Data arbitratorData : removeFuture.dataMap().values()) {
|
||||
try {
|
||||
Object arbitratorDataObject = arbitratorData.object();
|
||||
if (arbitratorDataObject instanceof Arbitrator) {
|
||||
Arbitrator arbitrator = (Arbitrator) arbitratorDataObject;
|
||||
listener.onArbitratorRemoved(arbitrator);
|
||||
}
|
||||
} catch (ClassNotFoundException | IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}));
|
||||
if (isSuccess(removeFuture)) {
|
||||
log.trace("Remove arbitrator from DHT was successful. Stored data: [key: " + locationKey + ", " +
|
||||
"values: " + arbitratorData + "]");
|
||||
}
|
||||
else {
|
||||
log.error("Remove arbitrators from DHT failed with reason:" + removeFuture.failedReason());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void getArbitrators(Locale languageLocale) {
|
||||
Number160 locationKey = Number160.createHash(ARBITRATORS_ROOT);
|
||||
FutureGet futureGet = p2pNode.getDataMap(locationKey);
|
||||
futureGet.addListener(new BaseFutureAdapter<BaseFuture>() {
|
||||
@Override
|
||||
public void operationComplete(BaseFuture baseFuture) throws Exception {
|
||||
Platform.runLater(() -> arbitratorListeners.stream().forEach(listener ->
|
||||
{
|
||||
List<Arbitrator> arbitrators = new ArrayList<>();
|
||||
for (Data arbitratorData : futureGet.dataMap().values()) {
|
||||
try {
|
||||
Object arbitratorDataObject = arbitratorData.object();
|
||||
if (arbitratorDataObject instanceof Arbitrator) {
|
||||
arbitrators.add((Arbitrator) arbitratorDataObject);
|
||||
}
|
||||
} catch (ClassNotFoundException | IOException e) {
|
||||
e.printStackTrace();
|
||||
log.error("Get arbitrators from DHT failed with exception:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
listener.onArbitratorsReceived(arbitrators);
|
||||
}));
|
||||
if (isSuccess(baseFuture)) {
|
||||
log.trace("Get arbitrators from DHT was successful. Stored data: [key: " + locationKey + ", " +
|
||||
"values: " + futureGet.dataMap() + "]");
|
||||
}
|
||||
else {
|
||||
log.error("Get arbitrators from DHT failed with reason:" + baseFuture.failedReason());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Event Listeners
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void addArbitratorListener(ArbitratorListener listener) {
|
||||
arbitratorListeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeArbitratorListener(ArbitratorListener listener) {
|
||||
arbitratorListeners.remove(listener);
|
||||
}
|
||||
|
||||
public void addIncomingMessageListener(IncomingMessageListener listener) {
|
||||
incomingMessageListeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeIncomingMessageListener(IncomingMessageListener listener) {
|
||||
incomingMessageListeners.remove(listener);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Incoming message handler
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void handleMessage(Object message, Peer sender) {
|
||||
if (message instanceof Message) {
|
||||
Platform.runLater(() -> incomingMessageListeners.stream().forEach(e ->
|
||||
e.onMessage((Message) message, sender)));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* This file is part of Bitsquare.
|
||||
*
|
||||
* Bitsquare 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.
|
||||
*
|
||||
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.msg.tomp2p;
|
||||
|
||||
import io.bitsquare.msg.MessageFacade;
|
||||
import io.bitsquare.msg.MessageModule;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
public class TomP2PMessageModule extends MessageModule {
|
||||
|
||||
public TomP2PMessageModule(Properties properties) {
|
||||
super(properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doConfigure() {
|
||||
bind(TomP2PNode.class).asEagerSingleton();
|
||||
bind(BootstrappedPeerFactory.class).asEagerSingleton();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<? extends MessageFacade> messageFacade() {
|
||||
return TomP2PMessageFacade.class;
|
||||
}
|
||||
}
|
|
@ -15,8 +15,9 @@
|
|||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.msg;
|
||||
package io.bitsquare.msg.tomp2p;
|
||||
|
||||
import io.bitsquare.msg.MessageBroker;
|
||||
import io.bitsquare.msg.listeners.BootstrapListener;
|
||||
import io.bitsquare.network.tomp2p.TomP2PPeer;
|
||||
|
||||
|
@ -66,14 +67,16 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import lighthouse.files.AppDirectory;
|
||||
|
||||
import static io.bitsquare.util.tomp2p.BaseFutureUtil.isSuccess;
|
||||
|
||||
/**
|
||||
* The fully bootstrapped P2PNode which is responsible himself for his availability in the messaging system. It saves
|
||||
* for instance the IP address periodically.
|
||||
* This class is offering generic functionality of TomP2P needed for Bitsquare, like data and domain protection.
|
||||
* It does not handle any domain aspects of Bitsquare.
|
||||
*/
|
||||
public class P2PNode {
|
||||
private static final Logger log = LoggerFactory.getLogger(P2PNode.class);
|
||||
public class TomP2PNode {
|
||||
private static final Logger log = LoggerFactory.getLogger(TomP2PNode.class);
|
||||
|
||||
private KeyPair keyPair;
|
||||
private final Boolean useDiskStorage;
|
||||
|
@ -90,14 +93,14 @@ public class P2PNode {
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
public P2PNode(BootstrappedPeerFactory bootstrappedPeerFactory,
|
||||
@Named("useDiskStorage") Boolean useDiskStorage) {
|
||||
public TomP2PNode(BootstrappedPeerFactory bootstrappedPeerFactory,
|
||||
@Named("useDiskStorage") Boolean useDiskStorage) {
|
||||
this.bootstrappedPeerFactory = bootstrappedPeerFactory;
|
||||
this.useDiskStorage = useDiskStorage;
|
||||
}
|
||||
|
||||
// for unit testing
|
||||
P2PNode(KeyPair keyPair, PeerDHT peerDHT) {
|
||||
TomP2PNode(KeyPair keyPair, PeerDHT peerDHT) {
|
||||
this.keyPair = keyPair;
|
||||
this.peerDHT = peerDHT;
|
||||
peerDHT.peerBean().keyPair(keyPair);
|
||||
|
@ -309,7 +312,7 @@ public class P2PNode {
|
|||
public void onSuccess(@Nullable PeerDHT peerDHT) {
|
||||
try {
|
||||
if (peerDHT != null) {
|
||||
P2PNode.this.peerDHT = peerDHT;
|
||||
TomP2PNode.this.peerDHT = peerDHT;
|
||||
setupReplyHandler();
|
||||
FuturePut futurePut = storePeerAddress();
|
||||
futurePut.addListener(new BaseFutureListener<BaseFuture>() {
|
||||
|
@ -400,10 +403,4 @@ public class P2PNode {
|
|||
storage = new StorageMemory();
|
||||
}
|
||||
}
|
||||
|
||||
// Isolate the success handling as there is bug in port forwarding mode
|
||||
private boolean isSuccess(BaseFuture baseFuture) {
|
||||
// return baseFuture.isSuccess();
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -34,6 +34,9 @@ import java.util.Date;
|
|||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import static com.google.common.base.Preconditions.*;
|
||||
import static io.bitsquare.btc.Restrictions.MIN_TRADE_AMOUNT;
|
||||
|
||||
//TODO flatten down?
|
||||
|
||||
public class Offer implements Serializable {
|
||||
|
@ -194,6 +197,37 @@ public class Offer implements Serializable {
|
|||
return bankAccountUID;
|
||||
}
|
||||
|
||||
public Date getCreationDate() {
|
||||
return creationDate;
|
||||
}
|
||||
|
||||
public void validate() throws Exception {
|
||||
checkNotNull(getAcceptedCountries(), "AcceptedCountries is null");
|
||||
checkNotNull(getAcceptedLanguageLocales(), "AcceptedLanguageLocales is null");
|
||||
checkNotNull(getAmount(), "Amount is null");
|
||||
checkNotNull(getArbitrators(), "Arbitrator is null");
|
||||
checkNotNull(getBankAccountId(), "BankAccountId is null");
|
||||
checkNotNull(getSecurityDeposit(), "SecurityDeposit is null");
|
||||
checkNotNull(getCreationDate(), "CreationDate is null");
|
||||
checkNotNull(getCurrency(), "Currency is null");
|
||||
checkNotNull(getDirection(), "Direction is null");
|
||||
checkNotNull(getId(), "Id is null");
|
||||
checkNotNull(getMessagePublicKey(), "MessagePublicKey is null");
|
||||
checkNotNull(getMinAmount(), "MinAmount is null");
|
||||
checkNotNull(getPrice(), "Price is null");
|
||||
|
||||
checkArgument(getMinAmount().compareTo(MIN_TRADE_AMOUNT) >= 0, "MinAmount is less then " + MIN_TRADE_AMOUNT);
|
||||
checkArgument(getAmount().compareTo(MIN_TRADE_AMOUNT) >= 0, "Amount is less then " + MIN_TRADE_AMOUNT);
|
||||
checkArgument(getAmount().compareTo(getMinAmount()) >= 0, "MinAmount is larger then Amount");
|
||||
checkArgument(getSecurityDeposit().isPositive(), "SecurityDeposit is not positive");
|
||||
checkArgument(getPrice().isPositive(), "Price is 0 or negative");
|
||||
|
||||
// TODO check balance
|
||||
// securityDeposit
|
||||
// Coin totalsToFund
|
||||
// getAddressInfoByTradeID(offerId)
|
||||
// TODO when offer is flattened continue here...
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
@ -215,9 +249,4 @@ public class Offer implements Serializable {
|
|||
", arbitrator=" + arbitrators +
|
||||
'}';
|
||||
}
|
||||
|
||||
|
||||
public Date getCreationDate() {
|
||||
return creationDate;
|
||||
}
|
||||
}
|
||||
|
|
36
src/main/java/io/bitsquare/offer/OfferModule.java
Normal file
36
src/main/java/io/bitsquare/offer/OfferModule.java
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* This file is part of Bitsquare.
|
||||
*
|
||||
* Bitsquare 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.
|
||||
*
|
||||
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.offer;
|
||||
|
||||
import io.bitsquare.BitsquareModule;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
public abstract class OfferModule extends BitsquareModule {
|
||||
|
||||
protected OfferModule(Properties properties) {
|
||||
super(properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(OfferRepository.class).to(offerRepository()).asEagerSingleton();
|
||||
}
|
||||
|
||||
protected abstract Class<? extends OfferRepository> offerRepository();
|
||||
}
|
50
src/main/java/io/bitsquare/offer/OfferRepository.java
Normal file
50
src/main/java/io/bitsquare/offer/OfferRepository.java
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* This file is part of Bitsquare.
|
||||
*
|
||||
* Bitsquare 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.
|
||||
*
|
||||
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.offer;
|
||||
|
||||
import io.bitsquare.util.task.FaultHandler;
|
||||
import io.bitsquare.util.task.ResultHandler;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javafx.beans.property.LongProperty;
|
||||
|
||||
public interface OfferRepository {
|
||||
|
||||
void getOffers(String fiatCode);
|
||||
|
||||
void addOffer(Offer offer, ResultHandler resultHandler, FaultHandler faultHandler);
|
||||
|
||||
void removeOffer(Offer offer);
|
||||
|
||||
void addListener(Listener listener);
|
||||
|
||||
void removeListener(Listener listener);
|
||||
|
||||
LongProperty invalidationTimestampProperty();
|
||||
|
||||
void requestInvalidationTimeStampFromDHT(String fiatCode);
|
||||
|
||||
interface Listener {
|
||||
void onOfferAdded(Offer offer);
|
||||
|
||||
void onOffersReceived(List<Offer> offers);
|
||||
|
||||
void onOfferRemoved(Offer offer);
|
||||
}
|
||||
}
|
|
@ -15,16 +15,21 @@
|
|||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.msg.listeners;
|
||||
package io.bitsquare.offer.tomp2p;
|
||||
|
||||
import io.bitsquare.offer.Offer;
|
||||
import io.bitsquare.offer.OfferModule;
|
||||
import io.bitsquare.offer.OfferRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
public interface OfferBookListener {
|
||||
void onOfferAdded(Offer offer);
|
||||
public class TomP2POfferModule extends OfferModule {
|
||||
|
||||
void onOffersReceived(List<Offer> offers);
|
||||
public TomP2POfferModule(Properties properties) {
|
||||
super(properties);
|
||||
}
|
||||
|
||||
void onOfferRemoved(Offer offer);
|
||||
}
|
||||
@Override
|
||||
public Class<? extends OfferRepository> offerRepository() {
|
||||
return TomP2POfferRepository.class;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,296 @@
|
|||
/*
|
||||
* This file is part of Bitsquare.
|
||||
*
|
||||
* Bitsquare 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.
|
||||
*
|
||||
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.offer.tomp2p;
|
||||
|
||||
import io.bitsquare.msg.tomp2p.TomP2PNode;
|
||||
import io.bitsquare.offer.Offer;
|
||||
import io.bitsquare.offer.OfferRepository;
|
||||
import io.bitsquare.util.task.FaultHandler;
|
||||
import io.bitsquare.util.task.ResultHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.LongProperty;
|
||||
import javafx.beans.property.SimpleLongProperty;
|
||||
|
||||
import net.tomp2p.dht.FutureGet;
|
||||
import net.tomp2p.dht.FuturePut;
|
||||
import net.tomp2p.dht.FutureRemove;
|
||||
import net.tomp2p.futures.BaseFuture;
|
||||
import net.tomp2p.futures.BaseFutureAdapter;
|
||||
import net.tomp2p.futures.BaseFutureListener;
|
||||
import net.tomp2p.peers.Number160;
|
||||
import net.tomp2p.peers.Number640;
|
||||
import net.tomp2p.storage.Data;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static io.bitsquare.util.tomp2p.BaseFutureUtil.isSuccess;
|
||||
|
||||
class TomP2POfferRepository implements OfferRepository {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(TomP2POfferRepository.class);
|
||||
|
||||
private final List<Listener> offerRepositoryListeners = new ArrayList<>();
|
||||
private final LongProperty invalidationTimestamp = new SimpleLongProperty(0);
|
||||
|
||||
private final TomP2PNode p2pNode;
|
||||
|
||||
@Inject
|
||||
public TomP2POfferRepository(TomP2PNode p2pNode) {
|
||||
this.p2pNode = p2pNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addOffer(Offer offer, ResultHandler resultHandler, FaultHandler faultHandler) {
|
||||
Number160 locationKey = Number160.createHash(offer.getCurrency().getCurrencyCode());
|
||||
try {
|
||||
final Data offerData = new Data(offer);
|
||||
|
||||
// the offer is default 30 days valid
|
||||
int defaultOfferTTL = 30 * 24 * 60 * 60;
|
||||
offerData.ttlSeconds(defaultOfferTTL);
|
||||
log.trace("Add offer to DHT requested. Added data: [locationKey: " + locationKey +
|
||||
", hash: " + offerData.hash().toString() + "]");
|
||||
FuturePut futurePut = p2pNode.addProtectedData(locationKey, offerData);
|
||||
futurePut.addListener(new BaseFutureListener<BaseFuture>() {
|
||||
@Override
|
||||
public void operationComplete(BaseFuture future) throws Exception {
|
||||
if (isSuccess(future)) {
|
||||
Platform.runLater(() -> {
|
||||
resultHandler.handleResult();
|
||||
offerRepositoryListeners.stream().forEach(listener -> {
|
||||
try {
|
||||
Object offerDataObject = offerData.object();
|
||||
if (offerDataObject instanceof Offer) {
|
||||
log.error("Added offer to DHT with ID: " + offerDataObject);
|
||||
listener.onOfferAdded((Offer) offerDataObject);
|
||||
}
|
||||
} catch (ClassNotFoundException | IOException e) {
|
||||
e.printStackTrace();
|
||||
log.error("Add offer to DHT failed: " + e.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
writeInvalidationTimestampToDHT(locationKey);
|
||||
log.trace("Add offer to DHT was successful. Added data: [locationKey: " + locationKey +
|
||||
", value: " + offerData + "]");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(Throwable ex) throws Exception {
|
||||
Platform.runLater(() -> {
|
||||
faultHandler.handleFault("Failed to add offer to DHT", ex);
|
||||
});
|
||||
}
|
||||
});
|
||||
} catch (IOException ex) {
|
||||
Platform.runLater(() -> {
|
||||
faultHandler.handleFault("Failed to add offer to DHT", ex);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//TODO remove is failing, probably due Coin or Fiat class (was working before)
|
||||
// objects are identical but returned object form network might have some problem with serialisation?
|
||||
public void removeOffer(Offer offer) {
|
||||
Number160 locationKey = Number160.createHash(offer.getCurrency().getCurrencyCode());
|
||||
try {
|
||||
final Data offerData = new Data(offer);
|
||||
log.trace("Remove offer from DHT requested. Removed data: [locationKey: " + locationKey +
|
||||
", hash: " + offerData.hash().toString() + "]");
|
||||
FutureRemove futureRemove = p2pNode.removeFromDataMap(locationKey, offerData);
|
||||
futureRemove.addListener(new BaseFutureListener<BaseFuture>() {
|
||||
@Override
|
||||
public void operationComplete(BaseFuture future) throws Exception {
|
||||
if (isSuccess(future)) {
|
||||
Platform.runLater(() -> {
|
||||
offerRepositoryListeners.stream().forEach(listener -> {
|
||||
try {
|
||||
Object offerDataObject = offerData.object();
|
||||
if (offerDataObject instanceof Offer) {
|
||||
log.trace("Remove offer from DHT was successful. Removed data: [key: " +
|
||||
locationKey + ", " +
|
||||
"offer: " + (Offer) offerDataObject + "]");
|
||||
listener.onOfferRemoved((Offer) offerDataObject);
|
||||
}
|
||||
} catch (ClassNotFoundException | IOException e) {
|
||||
e.printStackTrace();
|
||||
log.error("Remove offer from DHT failed. Error: " + e.getMessage());
|
||||
}
|
||||
});
|
||||
writeInvalidationTimestampToDHT(locationKey);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(Throwable t) throws Exception {
|
||||
log.error("Remove offer from DHT failed. Error: " + t.getMessage());
|
||||
}
|
||||
});
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
log.error("Remove offer from DHT failed. Error: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void getOffers(String currencyCode) {
|
||||
Number160 locationKey = Number160.createHash(currencyCode);
|
||||
log.trace("Get offers from DHT requested for locationKey: " + locationKey);
|
||||
FutureGet futureGet = p2pNode.getDataMap(locationKey);
|
||||
futureGet.addListener(new BaseFutureAdapter<BaseFuture>() {
|
||||
@Override
|
||||
public void operationComplete(BaseFuture baseFuture) throws Exception {
|
||||
if (isSuccess(baseFuture)) {
|
||||
final Map<Number640, Data> dataMap = futureGet.dataMap();
|
||||
final List<Offer> offers = new ArrayList<>();
|
||||
if (dataMap != null) {
|
||||
for (Data offerData : dataMap.values()) {
|
||||
try {
|
||||
Object offerDataObject = offerData.object();
|
||||
if (offerDataObject instanceof Offer) {
|
||||
offers.add((Offer) offerDataObject);
|
||||
}
|
||||
} catch (ClassNotFoundException | IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
Platform.runLater(() -> offerRepositoryListeners.stream().forEach(listener ->
|
||||
listener.onOffersReceived(offers)));
|
||||
}
|
||||
|
||||
log.trace("Get offers from DHT was successful. Stored data: [key: " + locationKey
|
||||
+ ", values: " + futureGet.dataMap() + "]");
|
||||
}
|
||||
else {
|
||||
final Map<Number640, Data> dataMap = futureGet.dataMap();
|
||||
if (dataMap == null || dataMap.size() == 0) {
|
||||
log.trace("Get offers from DHT delivered empty dataMap.");
|
||||
Platform.runLater(() -> offerRepositoryListeners.stream().forEach(listener ->
|
||||
listener.onOffersReceived(new ArrayList<>())));
|
||||
}
|
||||
else {
|
||||
log.error("Get offers from DHT was not successful with reason:" + baseFuture.failedReason());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(Listener listener) {
|
||||
offerRepositoryListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(Listener listener) {
|
||||
offerRepositoryListeners.remove(listener);
|
||||
}
|
||||
|
||||
/*
|
||||
* We store the timestamp of any change of the offer list (add, remove offer) and we poll
|
||||
* in intervals for changes. If we detect a change we request the offer list from the DHT.
|
||||
* Polling should be replaced by a push based solution later.
|
||||
*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Polling
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void writeInvalidationTimestampToDHT(Number160 locationKey) {
|
||||
invalidationTimestamp.set(System.currentTimeMillis());
|
||||
try {
|
||||
FuturePut putFuture = p2pNode.putData(getInvalidatedLocationKey(locationKey),
|
||||
new Data(invalidationTimestamp.get()));
|
||||
putFuture.addListener(new BaseFutureListener<BaseFuture>() {
|
||||
@Override
|
||||
public void operationComplete(BaseFuture future) throws Exception {
|
||||
if (isSuccess(putFuture))
|
||||
log.trace("Update invalidationTimestamp to DHT was successful. TimeStamp=" +
|
||||
invalidationTimestamp.get());
|
||||
else
|
||||
log.error("Update invalidationTimestamp to DHT failed with reason:" + putFuture.failedReason());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(Throwable t) throws Exception {
|
||||
log.error("Update invalidationTimestamp to DHT failed with exception:" + t.getMessage());
|
||||
}
|
||||
});
|
||||
} catch (IOException e) {
|
||||
log.error("Update invalidationTimestamp to DHT failed with exception:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public LongProperty invalidationTimestampProperty() {
|
||||
return invalidationTimestamp;
|
||||
}
|
||||
|
||||
public void requestInvalidationTimeStampFromDHT(String currencyCode) {
|
||||
Number160 locationKey = Number160.createHash(currencyCode);
|
||||
FutureGet getFuture = p2pNode.getData(getInvalidatedLocationKey(locationKey));
|
||||
getFuture.addListener(new BaseFutureListener<BaseFuture>() {
|
||||
@Override
|
||||
public void operationComplete(BaseFuture future) throws Exception {
|
||||
if (isSuccess(getFuture)) {
|
||||
Data data = getFuture.data();
|
||||
if (data != null && data.object() instanceof Long) {
|
||||
final Object object = data.object();
|
||||
Platform.runLater(() -> {
|
||||
Long timeStamp = (Long) object;
|
||||
//log.trace("Get invalidationTimestamp from DHT was successful. TimeStamp=" + timeStamp);
|
||||
invalidationTimestamp.set(timeStamp);
|
||||
});
|
||||
}
|
||||
else if (data != null) {
|
||||
log.error("Get invalidationTimestamp from DHT failed. Data = " + data);
|
||||
}
|
||||
}
|
||||
else if (getFuture.data() == null) {
|
||||
// OK as nothing is set at the moment
|
||||
// log.trace("Get invalidationTimestamp from DHT returns null. That is ok for the startup.");
|
||||
}
|
||||
else {
|
||||
log.error("Get invalidationTimestamp from DHT failed with reason:" + getFuture.failedReason());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(Throwable t) throws Exception {
|
||||
log.error("Get invalidationTimestamp from DHT failed with exception:" + t.getMessage());
|
||||
t.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Number160 getInvalidatedLocationKey(Number160 locationKey) {
|
||||
return Number160.createHash(locationKey + "invalidated");
|
||||
}
|
||||
}
|
|
@ -25,9 +25,9 @@ import io.bitsquare.msg.MessageFacade;
|
|||
import io.bitsquare.network.Peer;
|
||||
import io.bitsquare.offer.Direction;
|
||||
import io.bitsquare.offer.Offer;
|
||||
import io.bitsquare.offer.OfferRepository;
|
||||
import io.bitsquare.persistence.Persistence;
|
||||
import io.bitsquare.settings.Settings;
|
||||
import io.bitsquare.trade.handlers.ErrorMessageHandler;
|
||||
import io.bitsquare.trade.handlers.TransactionResultHandler;
|
||||
import io.bitsquare.trade.protocol.createoffer.CreateOfferCoordinator;
|
||||
import io.bitsquare.trade.protocol.trade.TradeMessage;
|
||||
|
@ -44,6 +44,7 @@ import io.bitsquare.trade.protocol.trade.taker.messages.RequestOffererPublishDep
|
|||
import io.bitsquare.trade.protocol.trade.taker.messages.RequestTakeOfferMessage;
|
||||
import io.bitsquare.trade.protocol.trade.taker.messages.TakeOfferFeePayedMessage;
|
||||
import io.bitsquare.user.User;
|
||||
import io.bitsquare.util.task.ErrorMessageHandler;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
|
@ -78,11 +79,11 @@ public class TradeManager {
|
|||
private final BlockChainFacade blockChainFacade;
|
||||
private final WalletFacade walletFacade;
|
||||
private final CryptoFacade cryptoFacade;
|
||||
private final OfferRepository offerRepository;
|
||||
|
||||
//TODO store TakerAsSellerProtocol in trade
|
||||
private final Map<String, SellerTakesOfferProtocol> takerAsSellerProtocolMap = new HashMap<>();
|
||||
private final Map<String, BuyerAcceptsOfferProtocol> offererAsBuyerProtocolMap = new HashMap<>();
|
||||
private final Map<String, CreateOfferCoordinator> createOfferCoordinatorMap = new HashMap<>();
|
||||
|
||||
private final ObservableMap<String, Offer> offers = FXCollections.observableHashMap();
|
||||
private final ObservableMap<String, Trade> pendingTrades = FXCollections.observableHashMap();
|
||||
|
@ -99,7 +100,8 @@ public class TradeManager {
|
|||
|
||||
@Inject
|
||||
public TradeManager(User user, Settings settings, Persistence persistence, MessageFacade messageFacade,
|
||||
BlockChainFacade blockChainFacade, WalletFacade walletFacade, CryptoFacade cryptoFacade) {
|
||||
BlockChainFacade blockChainFacade, WalletFacade walletFacade, CryptoFacade cryptoFacade,
|
||||
OfferRepository offerRepository) {
|
||||
this.user = user;
|
||||
this.settings = settings;
|
||||
this.persistence = persistence;
|
||||
|
@ -107,6 +109,7 @@ public class TradeManager {
|
|||
this.blockChainFacade = blockChainFacade;
|
||||
this.walletFacade = walletFacade;
|
||||
this.cryptoFacade = cryptoFacade;
|
||||
this.offerRepository = offerRepository;
|
||||
|
||||
Object offersObject = persistence.read(this, "offers");
|
||||
if (offersObject instanceof Map) {
|
||||
|
@ -163,36 +166,23 @@ public class TradeManager {
|
|||
settings.getAcceptedCountries(),
|
||||
settings.getAcceptedLanguageLocales());
|
||||
|
||||
if (createOfferCoordinatorMap.containsKey(offer.getId())) {
|
||||
errorMessageHandler.onFault("A createOfferCoordinator for the offer with the id " + offer.getId() + " " +
|
||||
"already exists.");
|
||||
}
|
||||
else {
|
||||
CreateOfferCoordinator createOfferCoordinator = new CreateOfferCoordinator(persistence,
|
||||
offer,
|
||||
walletFacade,
|
||||
messageFacade,
|
||||
(transactionId) -> {
|
||||
try {
|
||||
offer.setOfferFeePaymentTxID(transactionId.getHashAsString());
|
||||
addOffer(offer);
|
||||
createOfferCoordinatorMap.remove(offer.getId());
|
||||
CreateOfferCoordinator createOfferCoordinator = new CreateOfferCoordinator(
|
||||
offer,
|
||||
walletFacade,
|
||||
(transactionId) -> {
|
||||
try {
|
||||
offer.setOfferFeePaymentTxID(transactionId.getHashAsString());
|
||||
addOffer(offer);
|
||||
resultHandler.onResult(transactionId);
|
||||
} catch (Exception e) {
|
||||
errorMessageHandler.handleErrorMessage("Could not save offer. Reason: " +
|
||||
(e.getCause() != null ? e.getCause().getMessage() : e.toString()));
|
||||
}
|
||||
},
|
||||
(message, throwable) -> errorMessageHandler.handleErrorMessage(message),
|
||||
offerRepository);
|
||||
|
||||
resultHandler.onResult(transactionId);
|
||||
} catch (Exception e) {
|
||||
//TODO retry policy
|
||||
errorMessageHandler.onFault("Could not save offer. Reason: " +
|
||||
(e.getCause() != null ? e.getCause().getMessage() : e.toString()));
|
||||
createOfferCoordinatorMap.remove(offer.getId());
|
||||
}
|
||||
},
|
||||
(message, throwable) -> {
|
||||
errorMessageHandler.onFault(message);
|
||||
createOfferCoordinatorMap.remove(offer.getId());
|
||||
});
|
||||
createOfferCoordinatorMap.put(offer.getId(), createOfferCoordinator);
|
||||
createOfferCoordinator.start();
|
||||
}
|
||||
createOfferCoordinator.start();
|
||||
}
|
||||
|
||||
private void addOffer(Offer offer) {
|
||||
|
@ -210,7 +200,7 @@ public class TradeManager {
|
|||
offers.remove(offer.getId());
|
||||
persistOffers();
|
||||
|
||||
messageFacade.removeOffer(offer);
|
||||
offerRepository.removeOffer(offer);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -17,11 +17,11 @@
|
|||
|
||||
package io.bitsquare.trade;
|
||||
|
||||
import io.bitsquare.AbstractBitsquareModule;
|
||||
import io.bitsquare.BitsquareModule;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
public class TradeModule extends AbstractBitsquareModule {
|
||||
public class TradeModule extends BitsquareModule {
|
||||
|
||||
public TradeModule(Properties properties) {
|
||||
super(properties);
|
||||
|
|
|
@ -18,157 +18,89 @@
|
|||
package io.bitsquare.trade.protocol.createoffer;
|
||||
|
||||
import io.bitsquare.btc.WalletFacade;
|
||||
import io.bitsquare.msg.MessageFacade;
|
||||
import io.bitsquare.offer.Offer;
|
||||
import io.bitsquare.persistence.Persistence;
|
||||
import io.bitsquare.trade.handlers.FaultHandler;
|
||||
import io.bitsquare.offer.OfferRepository;
|
||||
import io.bitsquare.trade.handlers.TransactionResultHandler;
|
||||
import io.bitsquare.trade.protocol.createoffer.tasks.BroadCastOfferFeeTx;
|
||||
import io.bitsquare.trade.protocol.createoffer.tasks.CreateOfferFeeTx;
|
||||
import io.bitsquare.trade.protocol.createoffer.tasks.PublishOfferToDHT;
|
||||
import io.bitsquare.trade.protocol.createoffer.tasks.VerifyOffer;
|
||||
import io.bitsquare.util.task.FaultHandler;
|
||||
|
||||
import org.bitcoinj.core.InsufficientMoneyException;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Responsible for coordinating tasks involved in the create offer process.
|
||||
* It holds the model.state of the current process and support recovery if possible.
|
||||
*/
|
||||
//TODO recover policy, timer
|
||||
|
||||
@Immutable
|
||||
public class CreateOfferCoordinator {
|
||||
public enum State {
|
||||
INITED,
|
||||
STARTED,
|
||||
VALIDATED,
|
||||
OFFER_FEE_TX_CREATED,
|
||||
OFFER_FEE_BROAD_CASTED,
|
||||
OFFER_PUBLISHED_TO_DHT
|
||||
}
|
||||
|
||||
/**
|
||||
* The model is not immutable but only exposed to the CreateOfferCoordinator
|
||||
*/
|
||||
static class Model implements Serializable {
|
||||
private static final long serialVersionUID = 3027720554200858916L;
|
||||
|
||||
private final Persistence persistence;
|
||||
private State state;
|
||||
//TODO use tx id
|
||||
Transaction transaction;
|
||||
|
||||
Model(Persistence persistence) {
|
||||
this.persistence = persistence;
|
||||
}
|
||||
|
||||
public State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(State state) {
|
||||
this.state = state;
|
||||
|
||||
//TODO will have performance issues, but could be handled inside the persistence solution (queue up save
|
||||
// requests and exec. them on dedicated thread)
|
||||
persistence.write(this, "state", state);
|
||||
}
|
||||
}
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(CreateOfferCoordinator.class);
|
||||
|
||||
private final Offer offer;
|
||||
private final WalletFacade walletFacade;
|
||||
private final MessageFacade messageFacade;
|
||||
private final TransactionResultHandler resultHandler;
|
||||
private final FaultHandler faultHandler;
|
||||
private final Model model;
|
||||
private final OfferRepository offerRepository;
|
||||
|
||||
public CreateOfferCoordinator(Persistence persistence, Offer offer, WalletFacade walletFacade,
|
||||
MessageFacade messageFacade, TransactionResultHandler resultHandler,
|
||||
FaultHandler faultHandler) {
|
||||
this(offer, walletFacade, messageFacade, resultHandler, faultHandler, new Model(persistence));
|
||||
}
|
||||
|
||||
// for recovery from model
|
||||
public CreateOfferCoordinator(Offer offer, WalletFacade walletFacade, MessageFacade messageFacade,
|
||||
TransactionResultHandler resultHandler, FaultHandler faultHandler, Model model) {
|
||||
public CreateOfferCoordinator(Offer offer, WalletFacade walletFacade, TransactionResultHandler resultHandler,
|
||||
FaultHandler faultHandler, OfferRepository offerRepository) {
|
||||
this.offer = offer;
|
||||
this.walletFacade = walletFacade;
|
||||
this.messageFacade = messageFacade;
|
||||
this.resultHandler = resultHandler;
|
||||
this.faultHandler = faultHandler;
|
||||
this.model = model;
|
||||
|
||||
model.setState(State.INITED);
|
||||
this.offerRepository = offerRepository;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
model.setState(State.STARTED);
|
||||
VerifyOffer.run(this::onOfferValidated, this::onFailed, offer);
|
||||
}
|
||||
try {
|
||||
offer.validate();
|
||||
} catch (Exception ex) {
|
||||
faultHandler.handleFault("Offer validation failed", ex);
|
||||
return;
|
||||
}
|
||||
|
||||
private void onOfferValidated() {
|
||||
model.setState(State.VALIDATED);
|
||||
CreateOfferFeeTx.run(this::onOfferFeeTxCreated, this::onFailed, walletFacade, offer.getId());
|
||||
}
|
||||
Transaction transaction;
|
||||
|
||||
private void onOfferFeeTxCreated(Transaction transaction) {
|
||||
model.transaction = transaction;
|
||||
model.setState(State.OFFER_FEE_TX_CREATED);
|
||||
offer.setOfferFeePaymentTxID(transaction.getHashAsString());
|
||||
BroadCastOfferFeeTx.run(this::onOfferFeeTxBroadCasted, this::onFailed, walletFacade, transaction);
|
||||
}
|
||||
try {
|
||||
transaction = walletFacade.createOfferFeeTx(offer.getId());
|
||||
offer.setOfferFeePaymentTxID(transaction.getHashAsString());
|
||||
} catch (InsufficientMoneyException ex) {
|
||||
faultHandler.handleFault(
|
||||
"Offer fee payment failed because there is insufficient money in the trade wallet", ex);
|
||||
return;
|
||||
} catch (Throwable ex) {
|
||||
faultHandler.handleFault("Offer fee payment failed because of an exception occurred", ex);
|
||||
return;
|
||||
}
|
||||
|
||||
private void onOfferFeeTxBroadCasted() {
|
||||
model.setState(State.OFFER_FEE_BROAD_CASTED);
|
||||
PublishOfferToDHT.run(this::onOfferPublishedToDHT, this::onFailed, messageFacade, offer);
|
||||
}
|
||||
try {
|
||||
walletFacade.broadcastCreateOfferFeeTx(transaction, new FutureCallback<Transaction>() {
|
||||
@Override
|
||||
public void onSuccess(Transaction transaction) {
|
||||
log.info("sendResult onSuccess:" + transaction);
|
||||
if (transaction == null) {
|
||||
faultHandler.handleFault("Offer fee payment failed.",
|
||||
new Exception("Offer fee payment failed. Transaction = null."));
|
||||
return;
|
||||
}
|
||||
|
||||
private void onOfferPublishedToDHT() {
|
||||
model.setState(State.OFFER_PUBLISHED_TO_DHT);
|
||||
resultHandler.onResult(model.transaction);
|
||||
}
|
||||
try {
|
||||
offerRepository.addOffer(offer, () -> resultHandler.onResult(transaction), faultHandler);
|
||||
} catch (Exception e) {
|
||||
faultHandler.handleFault("Offer fee payment failed.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void onFailed(String message, Throwable throwable) {
|
||||
//TODO recover policy, timer
|
||||
faultHandler.onFault(message, throwable);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Recovery
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void recover() {
|
||||
switch (model.getState()) {
|
||||
case INITED:
|
||||
case STARTED:
|
||||
case VALIDATED:
|
||||
case OFFER_FEE_TX_CREATED:
|
||||
// we start over again, no critical and expensive work done yet
|
||||
start();
|
||||
break;
|
||||
case OFFER_FEE_BROAD_CASTED:
|
||||
// actually the only replay case here, tx publish was successful but storage to dht failed.
|
||||
// Republish the offer to DHT
|
||||
PublishOfferToDHT.run(this::onOfferPublishedToDHT, this::onFailed, messageFacade, offer);
|
||||
break;
|
||||
case OFFER_PUBLISHED_TO_DHT:
|
||||
// should be impossible
|
||||
log.warn("That case must not happen.");
|
||||
break;
|
||||
default:
|
||||
log.error("Illegal state passes. That must not happen");
|
||||
break;
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
faultHandler.handleFault("Offer fee payment failed with an exception.", t);
|
||||
}
|
||||
});
|
||||
} catch (Throwable t) {
|
||||
faultHandler.handleFault("Offer fee payment failed because an exception occurred.", t);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
* This file is part of Bitsquare.
|
||||
*
|
||||
* Bitsquare 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.
|
||||
*
|
||||
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.trade.protocol.createoffer.tasks;
|
||||
|
||||
import io.bitsquare.btc.WalletFacade;
|
||||
import io.bitsquare.trade.handlers.FaultHandler;
|
||||
import io.bitsquare.trade.handlers.ResultHandler;
|
||||
|
||||
import org.bitcoinj.core.Transaction;
|
||||
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class BroadCastOfferFeeTx {
|
||||
private static final Logger log = LoggerFactory.getLogger(BroadCastOfferFeeTx.class);
|
||||
|
||||
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, WalletFacade walletFacade,
|
||||
Transaction tx) {
|
||||
try {
|
||||
walletFacade.broadcastCreateOfferFeeTx(tx, new FutureCallback<Transaction>() {
|
||||
@Override
|
||||
public void onSuccess(@javax.annotation.Nullable Transaction transaction) {
|
||||
log.info("sendResult onSuccess:" + transaction);
|
||||
if (transaction != null) {
|
||||
try {
|
||||
resultHandler.onResult();
|
||||
} catch (Exception e) {
|
||||
faultHandler.onFault("Offer fee payment failed.", e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
faultHandler.onFault("Offer fee payment failed.",
|
||||
new Exception("Offer fee payment failed. Transaction = null."));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NotNull Throwable t) {
|
||||
faultHandler.onFault("Offer fee payment failed with an exception.", t);
|
||||
}
|
||||
});
|
||||
} catch (Throwable t) {
|
||||
faultHandler.onFault("Offer fee payment failed because an exception occurred.", t);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
* This file is part of Bitsquare.
|
||||
*
|
||||
* Bitsquare 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.
|
||||
*
|
||||
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.trade.protocol.createoffer.tasks;
|
||||
|
||||
import io.bitsquare.btc.WalletFacade;
|
||||
import io.bitsquare.trade.handlers.FaultHandler;
|
||||
import io.bitsquare.trade.handlers.TransactionResultHandler;
|
||||
|
||||
import org.bitcoinj.core.InsufficientMoneyException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class CreateOfferFeeTx {
|
||||
private static final Logger log = LoggerFactory.getLogger(CreateOfferFeeTx.class);
|
||||
|
||||
public static void run(TransactionResultHandler resultHandler, FaultHandler faultHandler,
|
||||
WalletFacade walletFacade, String offerId) {
|
||||
try {
|
||||
resultHandler.onResult(walletFacade.createOfferFeeTx(offerId));
|
||||
} catch (InsufficientMoneyException e) {
|
||||
faultHandler.onFault("Offer fee payment failed because there is insufficient money in the trade wallet. " +
|
||||
"", e);
|
||||
} catch (Throwable t) {
|
||||
faultHandler.onFault("Offer fee payment failed because of an exception occurred. ", t);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* This file is part of Bitsquare.
|
||||
*
|
||||
* Bitsquare 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.
|
||||
*
|
||||
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.trade.protocol.createoffer.tasks;
|
||||
|
||||
import io.bitsquare.msg.MessageFacade;
|
||||
import io.bitsquare.msg.listeners.AddOfferListener;
|
||||
import io.bitsquare.offer.Offer;
|
||||
import io.bitsquare.trade.handlers.FaultHandler;
|
||||
import io.bitsquare.trade.handlers.ResultHandler;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class PublishOfferToDHT {
|
||||
private static final Logger log = LoggerFactory.getLogger(PublishOfferToDHT.class);
|
||||
|
||||
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, MessageFacade messageFacade,
|
||||
Offer offer) {
|
||||
messageFacade.addOffer(offer, new AddOfferListener() {
|
||||
@Override
|
||||
public void onComplete() {
|
||||
resultHandler.onResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailed(String reason, Throwable throwable) {
|
||||
faultHandler.onFault("Publish offer to DHT failed.", throwable);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
/*
|
||||
* This file is part of Bitsquare.
|
||||
*
|
||||
* Bitsquare 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.
|
||||
*
|
||||
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.trade.protocol.createoffer.tasks;
|
||||
|
||||
import io.bitsquare.btc.Restrictions;
|
||||
import io.bitsquare.offer.Offer;
|
||||
import io.bitsquare.trade.handlers.FaultHandler;
|
||||
import io.bitsquare.trade.handlers.ResultHandler;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static com.google.common.base.Preconditions.*;
|
||||
|
||||
@Immutable
|
||||
public class VerifyOffer {
|
||||
private static final Logger log = LoggerFactory.getLogger(VerifyOffer.class);
|
||||
|
||||
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, Offer offer) {
|
||||
try {
|
||||
checkNotNull(offer.getAcceptedCountries(), "AcceptedCountries is null");
|
||||
checkNotNull(offer.getAcceptedLanguageLocales(), "AcceptedLanguageLocales is null");
|
||||
checkNotNull(offer.getAmount(), "Amount is null");
|
||||
checkNotNull(offer.getArbitrators(), "Arbitrator is null");
|
||||
//checkNotNull(offer.getBankAccountCountry(), "BankAccountCountry is null");
|
||||
checkNotNull(offer.getBankAccountId(), "BankAccountId is null");
|
||||
checkNotNull(offer.getSecurityDeposit(), "SecurityDeposit is null");
|
||||
checkNotNull(offer.getCreationDate(), "CreationDate is null");
|
||||
checkNotNull(offer.getCurrency(), "Currency is null");
|
||||
checkNotNull(offer.getDirection(), "Direction is null");
|
||||
checkNotNull(offer.getId(), "Id is null");
|
||||
checkNotNull(offer.getMessagePublicKey(), "MessagePublicKey is null");
|
||||
checkNotNull(offer.getMinAmount(), "MinAmount is null");
|
||||
checkNotNull(offer.getPrice(), "Price is null");
|
||||
|
||||
//checkArgument(!offer.getAcceptedCountries().isEmpty(), "AcceptedCountries is empty");
|
||||
//checkArgument(!offer.getAcceptedLanguageLocales().isEmpty(), "AcceptedLanguageLocales is empty");
|
||||
checkArgument(offer.getMinAmount().compareTo(Restrictions.MIN_TRADE_AMOUNT) >= 0,
|
||||
"MinAmount is less then " + Restrictions.MIN_TRADE_AMOUNT);
|
||||
checkArgument(offer.getAmount().compareTo(Restrictions.MIN_TRADE_AMOUNT) >= 0,
|
||||
"Amount is less then " + Restrictions.MIN_TRADE_AMOUNT);
|
||||
checkArgument(offer.getAmount().compareTo(offer.getMinAmount()) >= 0, "MinAmount is larger then Amount");
|
||||
checkArgument(offer.getSecurityDeposit().isPositive(), "SecurityDeposit is not positive");
|
||||
checkArgument(offer.getPrice().isPositive(), "Price is 0 or negative");
|
||||
|
||||
// TODO check balance
|
||||
// securityDeposit
|
||||
// Coin totalsToFund
|
||||
// getAddressInfoByTradeID(offerId)
|
||||
// TODO when offer is flattened continue here...
|
||||
|
||||
resultHandler.onResult();
|
||||
} catch (Throwable t) {
|
||||
faultHandler.onFault("Offer validation failed.", t);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@
|
|||
package io.bitsquare.trade.protocol.trade.offerer.tasks;
|
||||
|
||||
import io.bitsquare.btc.WalletFacade;
|
||||
import io.bitsquare.trade.handlers.ExceptionHandler;
|
||||
import io.bitsquare.util.task.ExceptionHandler;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.InsufficientMoneyException;
|
||||
|
@ -50,7 +50,7 @@ public class CreateDepositTx {
|
|||
resultHandler.onResult(offererPubKey, preparedOffererDepositTxAsHex, offererTxOutIndex);
|
||||
} catch (InsufficientMoneyException e) {
|
||||
log.error("Create deposit tx faultHandler.onFault due InsufficientMoneyException " + e);
|
||||
exceptionHandler.onError(
|
||||
exceptionHandler.handleException(
|
||||
new Exception("Create deposit tx faultHandler.onFault due InsufficientMoneyException " + e));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,8 +21,8 @@ import io.bitsquare.msg.MessageFacade;
|
|||
import io.bitsquare.msg.listeners.OutgoingMessageListener;
|
||||
import io.bitsquare.network.Peer;
|
||||
import io.bitsquare.trade.Trade;
|
||||
import io.bitsquare.trade.handlers.ExceptionHandler;
|
||||
import io.bitsquare.trade.protocol.trade.offerer.messages.RespondToTakeOfferRequestMessage;
|
||||
import io.bitsquare.util.task.ExceptionHandler;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -49,7 +49,7 @@ public class HandleTakeOfferRequest {
|
|||
@Override
|
||||
public void onFailed() {
|
||||
log.error("AcceptTakeOfferRequestMessage did not arrive at peer");
|
||||
exceptionHandler.onError(new Exception("AcceptTakeOfferRequestMessage did not arrive at peer"));
|
||||
exceptionHandler.handleException(new Exception("AcceptTakeOfferRequestMessage did not arrive at peer"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -21,9 +21,9 @@ import io.bitsquare.bank.BankAccount;
|
|||
import io.bitsquare.msg.MessageFacade;
|
||||
import io.bitsquare.msg.listeners.OutgoingMessageListener;
|
||||
import io.bitsquare.network.Peer;
|
||||
import io.bitsquare.trade.handlers.ExceptionHandler;
|
||||
import io.bitsquare.trade.handlers.ResultHandler;
|
||||
import io.bitsquare.trade.protocol.trade.offerer.messages.RequestTakerDepositPaymentMessage;
|
||||
import io.bitsquare.util.task.ExceptionHandler;
|
||||
import io.bitsquare.util.task.ResultHandler;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -48,13 +48,14 @@ public class RequestTakerDepositPayment {
|
|||
@Override
|
||||
public void onResult() {
|
||||
log.trace("RequestTakerDepositPaymentMessage successfully arrived at peer");
|
||||
resultHandler.onResult();
|
||||
resultHandler.handleResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailed() {
|
||||
log.error("RequestTakerDepositPaymentMessage did not arrive at peer");
|
||||
exceptionHandler.onError(new Exception("RequestTakerDepositPaymentMessage did not arrive at peer"));
|
||||
exceptionHandler.handleException(new Exception("RequestTakerDepositPaymentMessage did not arrive at " +
|
||||
"peer"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -20,9 +20,9 @@ package io.bitsquare.trade.protocol.trade.offerer.tasks;
|
|||
import io.bitsquare.msg.MessageFacade;
|
||||
import io.bitsquare.msg.listeners.OutgoingMessageListener;
|
||||
import io.bitsquare.network.Peer;
|
||||
import io.bitsquare.trade.handlers.ExceptionHandler;
|
||||
import io.bitsquare.trade.handlers.ResultHandler;
|
||||
import io.bitsquare.trade.protocol.trade.offerer.messages.DepositTxPublishedMessage;
|
||||
import io.bitsquare.util.task.ExceptionHandler;
|
||||
import io.bitsquare.util.task.ResultHandler;
|
||||
|
||||
import org.bitcoinj.core.Transaction;
|
||||
import org.bitcoinj.core.Utils;
|
||||
|
@ -43,13 +43,13 @@ public class SendDepositTxIdToTaker {
|
|||
@Override
|
||||
public void onResult() {
|
||||
log.trace("DepositTxPublishedMessage successfully arrived at peer");
|
||||
resultHandler.onResult();
|
||||
resultHandler.handleResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailed() {
|
||||
log.error("DepositTxPublishedMessage did not arrive at peer");
|
||||
exceptionHandler.onError(new Exception("DepositTxPublishedMessage did not arrive at peer"));
|
||||
exceptionHandler.handleException(new Exception("DepositTxPublishedMessage did not arrive at peer"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -21,9 +21,9 @@ import io.bitsquare.btc.WalletFacade;
|
|||
import io.bitsquare.msg.MessageFacade;
|
||||
import io.bitsquare.msg.listeners.OutgoingMessageListener;
|
||||
import io.bitsquare.network.Peer;
|
||||
import io.bitsquare.trade.handlers.ExceptionHandler;
|
||||
import io.bitsquare.trade.handlers.ResultHandler;
|
||||
import io.bitsquare.trade.protocol.trade.offerer.messages.BankTransferInitedMessage;
|
||||
import io.bitsquare.util.task.ExceptionHandler;
|
||||
import io.bitsquare.util.task.ResultHandler;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.ECKey;
|
||||
|
@ -72,19 +72,19 @@ public class SendSignedPayoutTx {
|
|||
@Override
|
||||
public void onResult() {
|
||||
log.trace("BankTransferInitedMessage successfully arrived at peer");
|
||||
resultHandler.onResult();
|
||||
resultHandler.handleResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailed() {
|
||||
log.error("BankTransferInitedMessage did not arrive at peer");
|
||||
exceptionHandler.onError(new Exception("BankTransferInitedMessage did not arrive at peer"));
|
||||
exceptionHandler.handleException(new Exception("BankTransferInitedMessage did not arrive at peer"));
|
||||
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
log.error("Exception at OffererCreatesAndSignsPayoutTx " + e);
|
||||
exceptionHandler.onError(e);
|
||||
exceptionHandler.handleException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
|
||||
package io.bitsquare.trade.protocol.trade.offerer.tasks;
|
||||
|
||||
import io.bitsquare.trade.handlers.ResultHandler;
|
||||
import io.bitsquare.trade.protocol.trade.offerer.BuyerAcceptsOfferProtocolListener;
|
||||
import io.bitsquare.util.task.ResultHandler;
|
||||
|
||||
import org.bitcoinj.core.Transaction;
|
||||
import org.bitcoinj.core.TransactionConfidence;
|
||||
|
@ -44,7 +44,7 @@ public class SetupListenerForBlockChainConfirmation {
|
|||
listener.onDepositTxConfirmedInBlockchain();
|
||||
depositTransaction.getConfidence().removeEventListener(this);
|
||||
log.trace("Tx is in blockchain");
|
||||
resultHandler.onResult();
|
||||
resultHandler.handleResult();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
package io.bitsquare.trade.protocol.trade.offerer.tasks;
|
||||
|
||||
import io.bitsquare.btc.WalletFacade;
|
||||
import io.bitsquare.trade.handlers.ExceptionHandler;
|
||||
import io.bitsquare.util.task.ExceptionHandler;
|
||||
|
||||
import org.bitcoinj.core.Transaction;
|
||||
|
||||
|
@ -59,12 +59,12 @@ public class SignAndPublishDepositTx {
|
|||
@Override
|
||||
public void onFailure(@NotNull Throwable t) {
|
||||
log.error("offererSignAndPublishTx faultHandler.onFault:" + t);
|
||||
exceptionHandler.onError(t);
|
||||
exceptionHandler.handleException(t);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
log.error("offererSignAndPublishTx faultHandler.onFault:" + e);
|
||||
exceptionHandler.onError(e);
|
||||
exceptionHandler.handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,8 +21,8 @@ import io.bitsquare.bank.BankAccount;
|
|||
import io.bitsquare.crypto.CryptoFacade;
|
||||
import io.bitsquare.offer.Offer;
|
||||
import io.bitsquare.trade.Contract;
|
||||
import io.bitsquare.trade.handlers.ExceptionHandler;
|
||||
import io.bitsquare.util.Utilities;
|
||||
import io.bitsquare.util.task.ExceptionHandler;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.ECKey;
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
package io.bitsquare.trade.protocol.trade.offerer.tasks;
|
||||
|
||||
import io.bitsquare.btc.WalletFacade;
|
||||
import io.bitsquare.trade.handlers.ExceptionHandler;
|
||||
import io.bitsquare.trade.handlers.ResultHandler;
|
||||
import io.bitsquare.util.task.ExceptionHandler;
|
||||
import io.bitsquare.util.task.ResultHandler;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -33,7 +33,7 @@ public class VerifyTakeOfferFeePayment {
|
|||
//TODO mocked yet, need a confidence listeners
|
||||
int numOfPeersSeenTx = walletFacade.getNumOfPeersSeenTx(takeOfferFeeTxId);
|
||||
if (numOfPeersSeenTx > 2) {
|
||||
resultHandler.onResult();
|
||||
resultHandler.handleResult();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,9 +19,9 @@ package io.bitsquare.trade.protocol.trade.offerer.tasks;
|
|||
|
||||
import io.bitsquare.bank.BankAccount;
|
||||
import io.bitsquare.btc.BlockChainFacade;
|
||||
import io.bitsquare.trade.handlers.ExceptionHandler;
|
||||
import io.bitsquare.trade.handlers.ResultHandler;
|
||||
import io.bitsquare.trade.protocol.trade.shared.tasks.VerifyPeerAccount;
|
||||
import io.bitsquare.util.task.ExceptionHandler;
|
||||
import io.bitsquare.util.task.ResultHandler;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
|
|
@ -19,8 +19,8 @@ package io.bitsquare.trade.protocol.trade.shared.tasks;
|
|||
|
||||
import io.bitsquare.bank.BankAccount;
|
||||
import io.bitsquare.btc.BlockChainFacade;
|
||||
import io.bitsquare.trade.handlers.ExceptionHandler;
|
||||
import io.bitsquare.trade.handlers.ResultHandler;
|
||||
import io.bitsquare.util.task.ExceptionHandler;
|
||||
import io.bitsquare.util.task.ResultHandler;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -34,15 +34,16 @@ public class VerifyPeerAccount {
|
|||
if (blockChainFacade.verifyAccountRegistration()) {
|
||||
if (blockChainFacade.isAccountBlackListed(peersAccountId, peersBankAccount)) {
|
||||
log.error("Taker is blacklisted");
|
||||
exceptionHandler.onError(new Exception("Taker is blacklisted"));
|
||||
exceptionHandler.handleException(new Exception("Taker is blacklisted"));
|
||||
}
|
||||
else {
|
||||
resultHandler.onResult();
|
||||
resultHandler.handleResult();
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.error("Account registration validation for peer faultHandler.onFault.");
|
||||
exceptionHandler.onError(new Exception("Account registration validation for peer faultHandler.onFault."));
|
||||
exceptionHandler.handleException(new Exception("Account registration validation for peer faultHandler" +
|
||||
".onFault."));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,8 +21,8 @@ import io.bitsquare.bank.BankAccount;
|
|||
import io.bitsquare.crypto.CryptoFacade;
|
||||
import io.bitsquare.offer.Offer;
|
||||
import io.bitsquare.trade.Contract;
|
||||
import io.bitsquare.trade.handlers.ExceptionHandler;
|
||||
import io.bitsquare.util.Utilities;
|
||||
import io.bitsquare.util.task.ExceptionHandler;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.ECKey;
|
||||
|
@ -58,7 +58,7 @@ public class CreateAndSignContract {
|
|||
resultHandler.onResult(contract, contractAsJson, signature);
|
||||
} catch (Throwable t) {
|
||||
log.error("Exception at sign contract " + t);
|
||||
exceptionHandler.onError(t);
|
||||
exceptionHandler.handleException(t);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ package io.bitsquare.trade.protocol.trade.taker.tasks;
|
|||
import io.bitsquare.msg.MessageFacade;
|
||||
import io.bitsquare.msg.listeners.GetPeerAddressListener;
|
||||
import io.bitsquare.network.Peer;
|
||||
import io.bitsquare.trade.handlers.ExceptionHandler;
|
||||
import io.bitsquare.util.task.ExceptionHandler;
|
||||
|
||||
import java.security.PublicKey;
|
||||
|
||||
|
@ -43,7 +43,7 @@ public class GetPeerAddress {
|
|||
@Override
|
||||
public void onFailed() {
|
||||
log.error("Lookup for peer address faultHandler.onFault.");
|
||||
exceptionHandler.onError(new Exception("Lookup for peer address faultHandler.onFault."));
|
||||
exceptionHandler.handleException(new Exception("Lookup for peer address faultHandler.onFault."));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
package io.bitsquare.trade.protocol.trade.taker.tasks;
|
||||
|
||||
import io.bitsquare.btc.WalletFacade;
|
||||
import io.bitsquare.trade.handlers.ExceptionHandler;
|
||||
import io.bitsquare.util.task.ExceptionHandler;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.InsufficientMoneyException;
|
||||
|
@ -57,7 +57,7 @@ public class PayDeposit {
|
|||
resultHandler.onResult(signedTakerDepositTx);
|
||||
} catch (InsufficientMoneyException e) {
|
||||
log.error("Pay deposit faultHandler.onFault due InsufficientMoneyException " + e);
|
||||
exceptionHandler.onError(
|
||||
exceptionHandler.handleException(
|
||||
new Exception("Pay deposit faultHandler.onFault due InsufficientMoneyException " + e));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
package io.bitsquare.trade.protocol.trade.taker.tasks;
|
||||
|
||||
import io.bitsquare.btc.WalletFacade;
|
||||
import io.bitsquare.trade.handlers.ExceptionHandler;
|
||||
import io.bitsquare.util.task.ExceptionHandler;
|
||||
|
||||
import org.bitcoinj.core.InsufficientMoneyException;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
|
@ -47,13 +47,13 @@ public class PayTakeOfferFee {
|
|||
@Override
|
||||
public void onFailure(@NotNull Throwable t) {
|
||||
log.error("Take offer fee paid faultHandler.onFault with exception: " + t);
|
||||
exceptionHandler.onError(
|
||||
exceptionHandler.handleException(
|
||||
new Exception("Take offer fee paid faultHandler.onFault with exception: " + t));
|
||||
}
|
||||
});
|
||||
} catch (InsufficientMoneyException e) {
|
||||
log.error("Take offer fee paid faultHandler.onFault due InsufficientMoneyException " + e);
|
||||
exceptionHandler.onError(
|
||||
exceptionHandler.handleException(
|
||||
new Exception("Take offer fee paid faultHandler.onFault due to InsufficientMoneyException " + e));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,9 +20,9 @@ package io.bitsquare.trade.protocol.trade.taker.tasks;
|
|||
import io.bitsquare.msg.MessageFacade;
|
||||
import io.bitsquare.msg.listeners.OutgoingMessageListener;
|
||||
import io.bitsquare.network.Peer;
|
||||
import io.bitsquare.trade.handlers.ExceptionHandler;
|
||||
import io.bitsquare.trade.handlers.ResultHandler;
|
||||
import io.bitsquare.trade.protocol.trade.taker.messages.RequestTakeOfferMessage;
|
||||
import io.bitsquare.util.task.ExceptionHandler;
|
||||
import io.bitsquare.util.task.ResultHandler;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -38,13 +38,14 @@ public class RequestTakeOffer {
|
|||
@Override
|
||||
public void onResult() {
|
||||
log.trace("RequestTakeOfferMessage successfully arrived at peer");
|
||||
resultHandler.onResult();
|
||||
resultHandler.handleResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailed() {
|
||||
log.error("RequestTakeOfferMessage did not arrive at peer");
|
||||
exceptionHandler.onError(new Exception("RequestTakeOfferMessage did not arrive at peer"));
|
||||
exceptionHandler.handleException(new Exception("RequestTakeOfferMessage did not arrive at " +
|
||||
"peer"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -20,9 +20,9 @@ package io.bitsquare.trade.protocol.trade.taker.tasks;
|
|||
import io.bitsquare.msg.MessageFacade;
|
||||
import io.bitsquare.msg.listeners.OutgoingMessageListener;
|
||||
import io.bitsquare.network.Peer;
|
||||
import io.bitsquare.trade.handlers.ExceptionHandler;
|
||||
import io.bitsquare.trade.handlers.ResultHandler;
|
||||
import io.bitsquare.trade.protocol.trade.taker.messages.PayoutTxPublishedMessage;
|
||||
import io.bitsquare.util.task.ExceptionHandler;
|
||||
import io.bitsquare.util.task.ResultHandler;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -38,13 +38,13 @@ public class SendPayoutTxToOfferer {
|
|||
@Override
|
||||
public void onResult() {
|
||||
log.trace("PayoutTxPublishedMessage successfully arrived at peer");
|
||||
resultHandler.onResult();
|
||||
resultHandler.handleResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailed() {
|
||||
log.error("PayoutTxPublishedMessage did not arrive at peer");
|
||||
exceptionHandler.onError(new Exception("PayoutTxPublishedMessage did not arrive at peer"));
|
||||
exceptionHandler.handleException(new Exception("PayoutTxPublishedMessage did not arrive at peer"));
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -22,9 +22,9 @@ import io.bitsquare.btc.WalletFacade;
|
|||
import io.bitsquare.msg.MessageFacade;
|
||||
import io.bitsquare.msg.listeners.OutgoingMessageListener;
|
||||
import io.bitsquare.network.Peer;
|
||||
import io.bitsquare.trade.handlers.ExceptionHandler;
|
||||
import io.bitsquare.trade.handlers.ResultHandler;
|
||||
import io.bitsquare.trade.protocol.trade.taker.messages.RequestOffererPublishDepositTxMessage;
|
||||
import io.bitsquare.util.task.ExceptionHandler;
|
||||
import io.bitsquare.util.task.ResultHandler;
|
||||
|
||||
import org.bitcoinj.core.Transaction;
|
||||
import org.bitcoinj.core.Utils;
|
||||
|
@ -72,13 +72,13 @@ public class SendSignedTakerDepositTxAsHex {
|
|||
@Override
|
||||
public void onResult() {
|
||||
log.trace("RequestOffererDepositPublicationMessage successfully arrived at peer");
|
||||
resultHandler.onResult();
|
||||
resultHandler.handleResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailed() {
|
||||
log.error("RequestOffererDepositPublicationMessage did not arrive at peer");
|
||||
exceptionHandler.onError(
|
||||
exceptionHandler.handleException(
|
||||
new Exception("RequestOffererDepositPublicationMessage did not arrive at peer"));
|
||||
}
|
||||
});
|
||||
|
|
|
@ -20,9 +20,9 @@ package io.bitsquare.trade.protocol.trade.taker.tasks;
|
|||
import io.bitsquare.msg.MessageFacade;
|
||||
import io.bitsquare.msg.listeners.OutgoingMessageListener;
|
||||
import io.bitsquare.network.Peer;
|
||||
import io.bitsquare.trade.handlers.ExceptionHandler;
|
||||
import io.bitsquare.trade.handlers.ResultHandler;
|
||||
import io.bitsquare.trade.protocol.trade.taker.messages.TakeOfferFeePayedMessage;
|
||||
import io.bitsquare.util.task.ExceptionHandler;
|
||||
import io.bitsquare.util.task.ResultHandler;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
|
@ -48,13 +48,13 @@ public class SendTakeOfferFeePayedTxId {
|
|||
@Override
|
||||
public void onResult() {
|
||||
log.trace("TakeOfferFeePayedMessage successfully arrived at peer");
|
||||
resultHandler.onResult();
|
||||
resultHandler.handleResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailed() {
|
||||
log.error("TakeOfferFeePayedMessage did not arrive at peer");
|
||||
exceptionHandler.onError(new Exception("TakeOfferFeePayedMessage did not arrive at peer"));
|
||||
exceptionHandler.handleException(new Exception("TakeOfferFeePayedMessage did not arrive at peer"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
package io.bitsquare.trade.protocol.trade.taker.tasks;
|
||||
|
||||
import io.bitsquare.btc.WalletFacade;
|
||||
import io.bitsquare.trade.handlers.ExceptionHandler;
|
||||
import io.bitsquare.util.task.ExceptionHandler;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
|
@ -65,12 +65,12 @@ public class SignAndPublishPayoutTx {
|
|||
@Override
|
||||
public void onFailure(@NotNull Throwable t) {
|
||||
log.error("Exception at takerSignsAndSendsTx " + t);
|
||||
exceptionHandler.onError(t);
|
||||
exceptionHandler.handleException(t);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
log.error("Exception at takerSignsAndSendsTx " + e);
|
||||
exceptionHandler.onError(e);
|
||||
exceptionHandler.handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,9 +19,9 @@ package io.bitsquare.trade.protocol.trade.taker.tasks;
|
|||
|
||||
import io.bitsquare.bank.BankAccount;
|
||||
import io.bitsquare.btc.BlockChainFacade;
|
||||
import io.bitsquare.trade.handlers.ExceptionHandler;
|
||||
import io.bitsquare.trade.handlers.ResultHandler;
|
||||
import io.bitsquare.trade.protocol.trade.shared.tasks.VerifyPeerAccount;
|
||||
import io.bitsquare.util.task.ExceptionHandler;
|
||||
import io.bitsquare.util.task.ResultHandler;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
|
|
@ -15,11 +15,11 @@
|
|||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.trade.handlers;
|
||||
package io.bitsquare.util.task;
|
||||
|
||||
/**
|
||||
* For reporting error message only (UI)
|
||||
*/
|
||||
public interface ErrorMessageHandler {
|
||||
void onFault(String errorMessage);
|
||||
void handleErrorMessage(String errorMessage);
|
||||
}
|
|
@ -15,11 +15,11 @@
|
|||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.trade.handlers;
|
||||
package io.bitsquare.util.task;
|
||||
|
||||
/**
|
||||
* For reporting throwables only
|
||||
*/
|
||||
public interface ExceptionHandler {
|
||||
void onError(Throwable throwable);
|
||||
void handleException(Throwable throwable);
|
||||
}
|
|
@ -15,11 +15,11 @@
|
|||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.trade.handlers;
|
||||
package io.bitsquare.util.task;
|
||||
|
||||
/**
|
||||
* For reporting a description message and throwable
|
||||
*/
|
||||
public interface FaultHandler {
|
||||
void onFault(String message, Throwable throwable);
|
||||
void handleFault(String message, Throwable throwable);
|
||||
}
|
|
@ -15,8 +15,8 @@
|
|||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.trade.handlers;
|
||||
package io.bitsquare.util.task;
|
||||
|
||||
public interface ResultHandler {
|
||||
void onResult();
|
||||
void handleResult();
|
||||
}
|
|
@ -15,10 +15,15 @@
|
|||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.msg.listeners;
|
||||
package io.bitsquare.util.tomp2p;
|
||||
|
||||
public interface AddOfferListener {
|
||||
void onComplete();
|
||||
import net.tomp2p.futures.BaseFuture;
|
||||
|
||||
void onFailed(String reason, Throwable throwable);
|
||||
public class BaseFutureUtil {
|
||||
|
||||
// Isolate the success handling as there is bug in port forwarding mode
|
||||
public static boolean isSuccess(BaseFuture baseFuture) {
|
||||
// return baseFuture.isSuccess();
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -15,9 +15,11 @@
|
|||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.gui;
|
||||
package io.bitsquare.app.gui;
|
||||
|
||||
import io.bitsquare.app.BitsquareModule;
|
||||
import io.bitsquare.gui.FatalException;
|
||||
import io.bitsquare.gui.Navigation;
|
||||
import io.bitsquare.gui.ViewLoader;
|
||||
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
|
@ -30,7 +32,7 @@ import org.junit.Before;
|
|||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ViewLoaderTest {
|
||||
public class ViewLoaderTests {
|
||||
|
||||
public static class TestApp extends Application {
|
||||
static Stage primaryStage;
|
||||
|
@ -56,7 +58,7 @@ public class ViewLoaderTest {
|
|||
|
||||
@Before
|
||||
public void setUp() {
|
||||
Injector injector = Guice.createInjector(new BitsquareModule(TestApp.primaryStage, "testApp"));
|
||||
Injector injector = Guice.createInjector(new MainModule("testApp", TestApp.primaryStage));
|
||||
ViewLoader.setInjector(injector);
|
||||
}
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.msg;
|
||||
package io.bitsquare.msg.tomp2p;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
@ -48,12 +48,12 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
// TODO Reactivate tests when P2PNode is using original code again. we deactivated the security features atm.
|
||||
// TODO Reactivate tests when TomP2PNode is using original code again. we deactivated the security features atm.
|
||||
// cause IOException: Not listening to anything. Maybe your binding information is wrong.
|
||||
// investigate what has broken it, probably from update to latest head
|
||||
@Ignore
|
||||
public class P2PNodeTest {
|
||||
private static final Logger log = LoggerFactory.getLogger(P2PNodeTest.class);
|
||||
public class TomP2PNodeTest {
|
||||
private static final Logger log = LoggerFactory.getLogger(TomP2PNodeTest.class);
|
||||
|
||||
final private static Random rnd = new Random(42L);
|
||||
|
||||
|
@ -80,12 +80,12 @@ public class P2PNodeTest {
|
|||
KeyPair keyPairClient = keyGen.genKeyPair();
|
||||
KeyPair keyPairOtherPeer = keyGen.genKeyPair();
|
||||
|
||||
P2PNode node;
|
||||
TomP2PNode node;
|
||||
Number160 locationKey;
|
||||
Object object;
|
||||
FutureDirect futureDirect;
|
||||
|
||||
node = new P2PNode(keyPairClient, client);
|
||||
node = new TomP2PNode(keyPairClient, client);
|
||||
object = "clients data";
|
||||
futureDirect = node.sendData(otherPeer.peerAddress(), object);
|
||||
futureDirect.awaitUninterruptibly();
|
||||
|
@ -110,7 +110,7 @@ public class P2PNodeTest {
|
|||
KeyPair keyPairClient = keyGen.genKeyPair();
|
||||
KeyPair keyPairOtherPeer = keyGen.genKeyPair();
|
||||
|
||||
P2PNode node;
|
||||
TomP2PNode node;
|
||||
Number160 locationKey;
|
||||
Data data;
|
||||
FuturePut futurePut;
|
||||
|
@ -119,7 +119,7 @@ public class P2PNodeTest {
|
|||
// otherPeer tries to squat clients location store
|
||||
// he can do it but as he has not the domain key of the client he cannot do any harm
|
||||
// he only can store und that path: locationKey.otherPeerDomainKey.data
|
||||
node = new P2PNode(keyPairOtherPeer, otherPeer);
|
||||
node = new TomP2PNode(keyPairOtherPeer, otherPeer);
|
||||
locationKey = Number160.createHash("clients location");
|
||||
data = new Data("otherPeer data");
|
||||
futurePut = node.putDomainProtectedData(locationKey, data);
|
||||
|
@ -133,7 +133,7 @@ public class P2PNodeTest {
|
|||
|
||||
// client store his data und his domainkey, no problem with previous occupied
|
||||
// he only can store und that path: locationKey.clientDomainKey.data
|
||||
node = new P2PNode(keyPairClient, client);
|
||||
node = new TomP2PNode(keyPairClient, client);
|
||||
locationKey = Number160.createHash("clients location");
|
||||
data = new Data("client data");
|
||||
futurePut = node.putDomainProtectedData(locationKey, data);
|
||||
|
@ -146,7 +146,7 @@ public class P2PNodeTest {
|
|||
assertEquals("client data", futureGet.data().object());
|
||||
|
||||
// also other peers can read that data if they know the public key of the client
|
||||
node = new P2PNode(keyPairOtherPeer, otherPeer);
|
||||
node = new TomP2PNode(keyPairOtherPeer, otherPeer);
|
||||
futureGet = node.getDomainProtectedData(locationKey, keyPairClient.getPublic());
|
||||
futureGet.awaitUninterruptibly();
|
||||
assertTrue(futureGet.isSuccess());
|
||||
|
@ -168,7 +168,7 @@ public class P2PNodeTest {
|
|||
assertFalse(futurePut.isSuccess());
|
||||
|
||||
// he can read his prev. stored data
|
||||
node = new P2PNode(keyPairOtherPeer, otherPeer);
|
||||
node = new TomP2PNode(keyPairOtherPeer, otherPeer);
|
||||
futureGet = node.getDomainProtectedData(locationKey, keyPairOtherPeer.getPublic());
|
||||
futureGet.awaitUninterruptibly();
|
||||
assertTrue(futureGet.isSuccess());
|
||||
|
@ -226,7 +226,7 @@ public class P2PNodeTest {
|
|||
PeerDHT otherPeer = peers[2];
|
||||
UtilsDHT2.perfectRouting(peers);
|
||||
|
||||
P2PNode node;
|
||||
TomP2PNode node;
|
||||
final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
|
||||
keyGen.initialize(1024);
|
||||
KeyPair keyPairClient = keyGen.genKeyPair();
|
||||
|
@ -243,7 +243,7 @@ public class P2PNodeTest {
|
|||
KeyPair keyPair1 = gen.generateKeyPair();
|
||||
keyPairClient = keyPair1;
|
||||
|
||||
node = new P2PNode(keyPairClient, client);
|
||||
node = new TomP2PNode(keyPairClient, client);
|
||||
locationKey = Number160.createHash("add to list clients location");
|
||||
data = new Data("add to list client data1");
|
||||
Data data_1 = data;
|
||||
|
@ -298,7 +298,7 @@ public class P2PNodeTest {
|
|||
futurePut.awaitUninterruptibly();
|
||||
assertTrue(futurePut.isSuccess());
|
||||
|
||||
node = new P2PNode(keyPairOtherPeer, otherPeer);
|
||||
node = new TomP2PNode(keyPairOtherPeer, otherPeer);
|
||||
futureGet = node.getDataMap(locationKey);
|
||||
futureGet.awaitUninterruptibly();
|
||||
assertTrue(futureGet.isSuccess());
|
||||
|
@ -334,7 +334,7 @@ public class P2PNodeTest {
|
|||
|
||||
|
||||
// client removes his entry -> OK
|
||||
node = new P2PNode(keyPairClient, client);
|
||||
node = new TomP2PNode(keyPairClient, client);
|
||||
FutureRemove futureRemove = node.removeFromDataMap(locationKey, data_1);
|
||||
futureRemove.awaitUninterruptibly();
|
||||
assertTrue(futureRemove.isSuccess());
|
||||
|
@ -375,7 +375,7 @@ public class P2PNodeTest {
|
|||
|
||||
|
||||
// otherPeer tries to removes client entry -> FAIL
|
||||
node = new P2PNode(keyPairOtherPeer, otherPeer);
|
||||
node = new TomP2PNode(keyPairOtherPeer, otherPeer);
|
||||
futureRemove = node.removeFromDataMap(locationKey, data_2);
|
||||
futureRemove.awaitUninterruptibly();
|
||||
assertFalse(futureRemove.isSuccess());
|
|
@ -18,7 +18,6 @@
|
|||
package io.bitsquare.util;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue