Add callback for broadcaster when sending mailbox msg

This commit is contained in:
Manfred Karrer 2016-01-27 00:04:03 +01:00
parent 9bb4683379
commit 602c503cea
22 changed files with 231 additions and 112 deletions

View file

@ -87,8 +87,7 @@ public class TaskRunner<T extends Model> {
} }
void handleErrorMessage(String errorMessage) { void handleErrorMessage(String errorMessage) {
log.error("Task failed: " + currentTask.getSimpleName()); log.error("Task failed: " + currentTask.getSimpleName() + " / errorMessage: " + errorMessage);
log.error("errorMessage: " + errorMessage);
failed = true; failed = true;
errorMessageHandler.handleErrorMessage(errorMessage); errorMessageHandler.handleErrorMessage(errorMessage);
} }

View file

@ -196,7 +196,7 @@ public class DisputeManager {
} }
@Override @Override
public void onFault() { public void onFault(String errorMessage) {
log.error("sendEncryptedMessage failed"); log.error("sendEncryptedMessage failed");
} }
} }
@ -263,7 +263,7 @@ public class DisputeManager {
} }
@Override @Override
public void onFault() { public void onFault(String errorMessage) {
log.error("sendEncryptedMessage failed"); log.error("sendEncryptedMessage failed");
} }
} }
@ -313,7 +313,7 @@ public class DisputeManager {
} }
@Override @Override
public void onFault() { public void onFault(String errorMessage) {
log.error("sendEncryptedMessage failed"); log.error("sendEncryptedMessage failed");
} }
} }
@ -354,7 +354,7 @@ public class DisputeManager {
} }
@Override @Override
public void onFault() { public void onFault(String errorMessage) {
log.error("sendEncryptedMessage failed"); log.error("sendEncryptedMessage failed");
} }
} }
@ -381,7 +381,7 @@ public class DisputeManager {
} }
@Override @Override
public void onFault() { public void onFault(String errorMessage) {
log.error("sendEncryptedMessage failed"); log.error("sendEncryptedMessage failed");
} }
} }

View file

@ -61,7 +61,7 @@ public class PaymentMethod implements Serializable, Comparable {
public static final List<PaymentMethod> ALL_VALUES = new ArrayList<>(Arrays.asList( public static final List<PaymentMethod> ALL_VALUES = new ArrayList<>(Arrays.asList(
OK_PAY = new PaymentMethod(OK_PAY_ID, 0, DAY), // tx instant so min. wait time OK_PAY = new PaymentMethod(OK_PAY_ID, 0, DAY), // tx instant so min. wait time
PERFECT_MONEY = new PaymentMethod(PERFECT_MONEY_ID, 0, DAY), PERFECT_MONEY = new PaymentMethod(PERFECT_MONEY_ID, 0, DAY),
SEPA = new PaymentMethod(SEPA_ID, 0, 8 * DAY), // sepa takes 1-3 business days. We use 8 days to include safety for holidays SEPA = new PaymentMethod(SEPA_ID, 0, 7 * DAY), // sepa takes 1-3 business days. We use 7 days to include safety for holidays
SWISH = new PaymentMethod(SWISH_ID, 0, DAY), SWISH = new PaymentMethod(SWISH_ID, 0, DAY),
ALI_PAY = new PaymentMethod(ALI_PAY_ID, 0, DAY), ALI_PAY = new PaymentMethod(ALI_PAY_ID, 0, DAY),
/* FED_WIRE = new PaymentMethod(FED_WIRE_ID, 0, DAY),*/ /* FED_WIRE = new PaymentMethod(FED_WIRE_ID, 0, DAY),*/

View file

@ -18,6 +18,8 @@
package io.bitsquare.trade; package io.bitsquare.trade;
import io.bitsquare.app.Version; import io.bitsquare.app.Version;
import io.bitsquare.common.handlers.ErrorMessageHandler;
import io.bitsquare.common.handlers.ResultHandler;
import io.bitsquare.p2p.NodeAddress; import io.bitsquare.p2p.NodeAddress;
import io.bitsquare.storage.Storage; import io.bitsquare.storage.Storage;
import io.bitsquare.trade.offer.Offer; import io.bitsquare.trade.offer.Offer;
@ -50,9 +52,9 @@ public abstract class BuyerTrade extends Trade implements Serializable {
state = State.PREPARATION; state = State.PREPARATION;
} }
public void onFiatPaymentStarted() { public void onFiatPaymentStarted(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
checkArgument(tradeProtocol instanceof BuyerProtocol, "tradeProtocol NOT instanceof BuyerProtocol"); checkArgument(tradeProtocol instanceof BuyerProtocol, "Check failed: tradeProtocol instanceof BuyerProtocol");
((BuyerProtocol) tradeProtocol).onFiatPaymentStarted(); ((BuyerProtocol) tradeProtocol).onFiatPaymentStarted(resultHandler, errorMessageHandler);
} }

View file

@ -17,6 +17,8 @@
package io.bitsquare.trade.protocol.trade; package io.bitsquare.trade.protocol.trade;
import io.bitsquare.common.handlers.ErrorMessageHandler;
import io.bitsquare.common.handlers.ResultHandler;
import io.bitsquare.p2p.Message; import io.bitsquare.p2p.Message;
import io.bitsquare.p2p.NodeAddress; import io.bitsquare.p2p.NodeAddress;
import io.bitsquare.p2p.messaging.MailboxMessage; import io.bitsquare.p2p.messaging.MailboxMessage;
@ -145,12 +147,18 @@ public class BuyerAsOffererProtocol extends TradeProtocol implements BuyerProtoc
// User clicked the "bank transfer started" button // User clicked the "bank transfer started" button
@Override @Override
public void onFiatPaymentStarted() { public void onFiatPaymentStarted(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
buyerAsOffererTrade.setState(Trade.State.FIAT_PAYMENT_STARTED); buyerAsOffererTrade.setState(Trade.State.FIAT_PAYMENT_STARTED);
TradeTaskRunner taskRunner = new TradeTaskRunner(buyerAsOffererTrade, TradeTaskRunner taskRunner = new TradeTaskRunner(buyerAsOffererTrade,
() -> handleTaskRunnerSuccess("onFiatPaymentStarted"), () -> {
this::handleTaskRunnerFault); resultHandler.handleResult();
handleTaskRunnerSuccess("onFiatPaymentStarted");
},
(errorMessage) -> {
errorMessageHandler.handleErrorMessage(errorMessage);
handleTaskRunnerFault(errorMessage);
});
taskRunner.addTasks( taskRunner.addTasks(
VerifyTakeOfferFeePayment.class, VerifyTakeOfferFeePayment.class,
SendFiatTransferStartedMessage.class SendFiatTransferStartedMessage.class

View file

@ -18,6 +18,8 @@
package io.bitsquare.trade.protocol.trade; package io.bitsquare.trade.protocol.trade;
import io.bitsquare.common.handlers.ErrorMessageHandler;
import io.bitsquare.common.handlers.ResultHandler;
import io.bitsquare.p2p.Message; import io.bitsquare.p2p.Message;
import io.bitsquare.p2p.NodeAddress; import io.bitsquare.p2p.NodeAddress;
import io.bitsquare.p2p.messaging.MailboxMessage; import io.bitsquare.p2p.messaging.MailboxMessage;
@ -131,12 +133,18 @@ public class BuyerAsTakerProtocol extends TradeProtocol implements BuyerProtocol
// User clicked the "bank transfer started" button // User clicked the "bank transfer started" button
@Override @Override
public void onFiatPaymentStarted() { public void onFiatPaymentStarted(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
buyerAsTakerTrade.setState(Trade.State.FIAT_PAYMENT_STARTED); buyerAsTakerTrade.setState(Trade.State.FIAT_PAYMENT_STARTED);
TradeTaskRunner taskRunner = new TradeTaskRunner(buyerAsTakerTrade, TradeTaskRunner taskRunner = new TradeTaskRunner(buyerAsTakerTrade,
() -> handleTaskRunnerSuccess("onFiatPaymentStarted"), () -> {
this::handleTaskRunnerFault); resultHandler.handleResult();
handleTaskRunnerSuccess("onFiatPaymentStarted");
},
(errorMessage) -> {
errorMessageHandler.handleErrorMessage(errorMessage);
handleTaskRunnerFault(errorMessage);
});
taskRunner.addTasks( taskRunner.addTasks(
VerifyOfferFeePayment.class, VerifyOfferFeePayment.class,
SendFiatTransferStartedMessage.class SendFiatTransferStartedMessage.class

View file

@ -17,6 +17,9 @@
package io.bitsquare.trade.protocol.trade; package io.bitsquare.trade.protocol.trade;
import io.bitsquare.common.handlers.ErrorMessageHandler;
import io.bitsquare.common.handlers.ResultHandler;
public interface BuyerProtocol { public interface BuyerProtocol {
void onFiatPaymentStarted(); void onFiatPaymentStarted(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler);
} }

View file

@ -36,7 +36,6 @@ public class SendFiatTransferStartedMessage extends TradeTask {
protected void run() { protected void run() {
try { try {
runInterceptHook(); runInterceptHook();
processModel.getP2PService().sendEncryptedMailboxMessage( processModel.getP2PService().sendEncryptedMailboxMessage(
trade.getTradingPeerNodeAddress(), trade.getTradingPeerNodeAddress(),
processModel.tradingPeer.getPubKeyRing(), processModel.tradingPeer.getPubKeyRing(),
@ -48,22 +47,22 @@ public class SendFiatTransferStartedMessage extends TradeTask {
new SendMailboxMessageListener() { new SendMailboxMessageListener() {
@Override @Override
public void onArrived() { public void onArrived() {
log.trace("Message arrived at peer."); log.info("Message arrived at peer.");
trade.setState(Trade.State.FIAT_PAYMENT_STARTED_MSG_SENT); trade.setState(Trade.State.FIAT_PAYMENT_STARTED_MSG_SENT);
complete(); complete();
} }
@Override @Override
public void onStoredInMailbox() { public void onStoredInMailbox() {
log.trace("Message stored in mailbox."); log.info("Message stored in mailbox.");
trade.setState(Trade.State.FIAT_PAYMENT_STARTED_MSG_SENT); trade.setState(Trade.State.FIAT_PAYMENT_STARTED_MSG_SENT);
complete(); complete();
} }
@Override @Override
public void onFault() { public void onFault(String errorMessage) {
appendToErrorMessage("FiatTransferStartedMessage sending failed"); appendToErrorMessage("FiatTransferStartedMessage sending failed");
failed(); failed(errorMessage);
} }
} }
); );

View file

@ -61,7 +61,7 @@ public class SendPayoutTxFinalizedMessage extends TradeTask {
} }
@Override @Override
public void onFault() { public void onFault(String errorMessage) {
appendToErrorMessage("PayoutTxFinalizedMessage sending failed"); appendToErrorMessage("PayoutTxFinalizedMessage sending failed");
failed(); failed();
} }

View file

@ -65,7 +65,7 @@ public class SendFinalizePayoutTxRequest extends TradeTask {
} }
@Override @Override
public void onFault() { public void onFault(String errorMessage) {
appendToErrorMessage("FinalizePayoutTxRequest sending failed"); appendToErrorMessage("FinalizePayoutTxRequest sending failed");
failed(); failed();
} }

View file

@ -61,7 +61,7 @@ public class SendDepositTxPublishedMessage extends TradeTask {
} }
@Override @Override
public void onFault() { public void onFault(String errorMessage) {
appendToErrorMessage("DepositTxPublishedMessage sending failed"); appendToErrorMessage("DepositTxPublishedMessage sending failed");
failed(); failed();
} }

View file

@ -72,7 +72,7 @@ public class SendPayDepositRequest extends TradeTask {
} }
@Override @Override
public void onFault() { public void onFault(String errorMessage) {
appendToErrorMessage("PayDepositRequest sending failed"); appendToErrorMessage("PayDepositRequest sending failed");
failed(); failed();
} }

View file

@ -39,8 +39,11 @@ import io.bitsquare.gui.popups.DisplayAlertMessagePopup;
import io.bitsquare.gui.popups.Popup; import io.bitsquare.gui.popups.Popup;
import io.bitsquare.gui.popups.WalletPasswordPopup; import io.bitsquare.gui.popups.WalletPasswordPopup;
import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.locale.CountryUtil;
import io.bitsquare.locale.CurrencyUtil;
import io.bitsquare.p2p.P2PService; import io.bitsquare.p2p.P2PService;
import io.bitsquare.p2p.P2PServiceListener; import io.bitsquare.p2p.P2PServiceListener;
import io.bitsquare.payment.OKPayAccount;
import io.bitsquare.trade.Trade; import io.bitsquare.trade.Trade;
import io.bitsquare.trade.TradeManager; import io.bitsquare.trade.TradeManager;
import io.bitsquare.trade.offer.OpenOffer; import io.bitsquare.trade.offer.OpenOffer;
@ -411,6 +414,15 @@ public class MainViewModel implements ViewModel {
// now show app // now show app
showAppScreen.set(true); showAppScreen.set(true);
if (BitsquareApp.DEV_MODE && user.getPaymentAccounts().isEmpty()) {
OKPayAccount okPayAccount = new OKPayAccount();
okPayAccount.setAccountNr("dummy");
okPayAccount.setAccountName("OKPay dummy");
okPayAccount.setSelectedTradeCurrency(CurrencyUtil.getDefaultTradeCurrency());
okPayAccount.setCountry(CountryUtil.getDefaultCountry());
user.addPaymentAccount(okPayAccount);
}
} }
private void checkPeriodicallyForBtcSyncState() { private void checkPeriodicallyForBtcSyncState() {

View file

@ -26,6 +26,8 @@ import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.btc.WalletService; import io.bitsquare.btc.WalletService;
import io.bitsquare.common.UserThread; import io.bitsquare.common.UserThread;
import io.bitsquare.common.crypto.KeyRing; import io.bitsquare.common.crypto.KeyRing;
import io.bitsquare.common.handlers.ErrorMessageHandler;
import io.bitsquare.common.handlers.ResultHandler;
import io.bitsquare.gui.Navigation; import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.common.model.ActivatableDataModel; import io.bitsquare.gui.common.model.ActivatableDataModel;
import io.bitsquare.gui.main.MainView; import io.bitsquare.gui.main.MainView;
@ -54,6 +56,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
public class PendingTradesDataModel extends ActivatableDataModel { public class PendingTradesDataModel extends ActivatableDataModel {
@ -152,10 +155,11 @@ public class PendingTradesDataModel extends ActivatableDataModel {
} }
} }
void onFiatPaymentStarted() { void onFiatPaymentStarted(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
checkNotNull(trade, "trade must not be null"); checkNotNull(trade, "trade must not be null");
if (trade instanceof BuyerTrade && trade.getDisputeState() == Trade.DisputeState.NONE) checkArgument(trade instanceof BuyerTrade, "Check failed: trade instanceof BuyerTrade");
((BuyerTrade) trade).onFiatPaymentStarted(); checkArgument(trade.getDisputeState() == Trade.DisputeState.NONE, "Check failed: trade.getDisputeState() == Trade.DisputeState.NONE");
((BuyerTrade) trade).onFiatPaymentStarted(resultHandler, errorMessageHandler);
} }
void onFiatPaymentReceived() { void onFiatPaymentReceived() {

View file

@ -131,7 +131,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
appFocusProperty = scene.getWindow().focusedProperty(); appFocusProperty = scene.getWindow().focusedProperty();
appFocusProperty.addListener(appFocusChangeListener); appFocusProperty.addListener(appFocusChangeListener);
model.currentTrade().addListener(currentTradeChangeListener); model.currentTrade().addListener(currentTradeChangeListener);
setNewSubView(model.currentTrade().get()); //setNewSubView(model.currentTrade().get());
table.setItems(model.getList()); table.setItems(model.getList());
table.getSelectionModel().selectedItemProperty().addListener(selectedItemChangeListener); table.getSelectionModel().selectedItemProperty().addListener(selectedItemChangeListener);
PendingTradesListItem selectedItem = model.getSelectedItem(); PendingTradesListItem selectedItem = model.getSelectedItem();

View file

@ -19,6 +19,8 @@ package io.bitsquare.gui.main.portfolio.pendingtrades;
import com.google.inject.Inject; import com.google.inject.Inject;
import io.bitsquare.btc.FeePolicy; import io.bitsquare.btc.FeePolicy;
import io.bitsquare.common.handlers.ErrorMessageHandler;
import io.bitsquare.common.handlers.ResultHandler;
import io.bitsquare.gui.common.model.ActivatableWithDataModel; import io.bitsquare.gui.common.model.ActivatableWithDataModel;
import io.bitsquare.gui.common.model.ViewModel; import io.bitsquare.gui.common.model.ViewModel;
import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.gui.util.BSFormatter;
@ -179,8 +181,8 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
return dataModel.getTradeProperty(); return dataModel.getTradeProperty();
} }
public void fiatPaymentStarted() { public void fiatPaymentStarted(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
dataModel.onFiatPaymentStarted(); dataModel.onFiatPaymentStarted(resultHandler, errorMessageHandler);
} }
public void fiatPaymentReceived() { public void fiatPaymentReceived() {
@ -362,13 +364,10 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
break; break;
case DEPOSIT_CONFIRMED: case DEPOSIT_CONFIRMED:
case FIAT_PAYMENT_STARTED:
sellerState.set(WAIT_FOR_FIAT_PAYMENT_STARTED); sellerState.set(WAIT_FOR_FIAT_PAYMENT_STARTED);
buyerState.set(PendingTradesViewModel.BuyerState.REQUEST_START_FIAT_PAYMENT); buyerState.set(PendingTradesViewModel.BuyerState.REQUEST_START_FIAT_PAYMENT);
break; break;
case FIAT_PAYMENT_STARTED:
break;
case FIAT_PAYMENT_STARTED_MSG_SENT: case FIAT_PAYMENT_STARTED_MSG_SENT:
buyerState.set(PendingTradesViewModel.BuyerState.WAIT_FOR_FIAT_PAYMENT_RECEIPT); buyerState.set(PendingTradesViewModel.BuyerState.WAIT_FOR_FIAT_PAYMENT_RECEIPT);
break; break;

View file

@ -86,7 +86,7 @@ public class StartPaymentView extends TradeStepDetailsView {
model.getTxId().removeListener(txIdChangeListener); model.getTxId().removeListener(txIdChangeListener);
txIdTextField.cleanup(); txIdTextField.cleanup();
statusProgressIndicator.setProgress(0); removeStatusProgressIndicator();
} }
@ -161,12 +161,40 @@ public class StartPaymentView extends TradeStepDetailsView {
private void confirmPaymentStarted() { private void confirmPaymentStarted() {
paymentStartedButton.setDisable(true); paymentStartedButton.setDisable(true);
paymentStartedButton.setMinWidth(130);
statusProgressIndicator.setVisible(true); statusProgressIndicator.setVisible(true);
statusProgressIndicator.setManaged(true);
statusProgressIndicator.setProgress(-1); statusProgressIndicator.setProgress(-1);
statusLabel.setText("Sending message to trading partner...");
model.fiatPaymentStarted(); statusLabel.setWrapText(true);
statusLabel.setPrefWidth(220);
statusLabel.setText("Sending message to your trading partner.\n" +
"Please wait until you get the confirmation that the message has arrived.");
model.fiatPaymentStarted(() -> {
// We would not really need an update as the success triggers a screen change
removeStatusProgressIndicator();
statusLabel.setText("");
// In case the first send failed we got the support button displayed.
// If it succeeds at a second try we remove the support button again.
if (openSupportTicketButton != null) {
gridPane.getChildren().remove(openSupportTicketButton);
openSupportTicketButton = null;
}
}, errorMessage -> {
removeStatusProgressIndicator();
statusLabel.setText("Sending message to your trading partner failed.\n" +
"Please try again and if it continue to fail report a bug.");
paymentStartedButton.setDisable(false);
});
}
private void removeStatusProgressIndicator() {
statusProgressIndicator.setVisible(false);
statusProgressIndicator.setProgress(0);
statusProgressIndicator.setManaged(false);
} }

View file

@ -22,6 +22,7 @@ import io.bitsquare.gui.components.TitledGroupBg;
import io.bitsquare.gui.main.help.Help; import io.bitsquare.gui.main.help.Help;
import io.bitsquare.gui.main.help.HelpId; import io.bitsquare.gui.main.help.HelpId;
import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesViewModel; import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesViewModel;
import io.bitsquare.gui.popups.Popup;
import io.bitsquare.gui.util.Layout; import io.bitsquare.gui.util.Layout;
import io.bitsquare.trade.Trade; import io.bitsquare.trade.Trade;
import javafx.geometry.HPos; import javafx.geometry.HPos;
@ -52,7 +53,7 @@ public abstract class TradeStepDetailsView extends AnchorPane {
protected Label infoLabel; protected Label infoLabel;
protected TitledGroupBg infoTitledGroupBg; protected TitledGroupBg infoTitledGroupBg;
protected Button openDisputeButton; protected Button openDisputeButton;
private Button openSupportTicketButton; protected Button openSupportTicketButton;
private Trade trade; private Trade trade;
private Subscription errorMessageSubscription; private Subscription errorMessageSubscription;
@ -181,7 +182,12 @@ public abstract class TradeStepDetailsView extends AnchorPane {
} }
private void addErrorLabel() { private void addErrorLabel() {
if (infoLabel == null) { new Popup().warning(trade.errorMessageProperty().getValue()
+ "\n\nPlease report the problem to your arbitrator. He will forward it to the developers to investigate the problem.\n" +
"After the problem has be analysed you will get back all the funds you paid in.\n" +
"There will be no arbitration fee charged if it was a technical error.").show();
/*if (infoLabel == null) {
infoTitledGroupBg = addTitledGroupBg(gridPane, ++gridRow, 1, "Error", Layout.GROUP_DISTANCE); infoTitledGroupBg = addTitledGroupBg(gridPane, ++gridRow, 1, "Error", Layout.GROUP_DISTANCE);
infoLabel = addMultilineLabel(gridPane, gridRow, Layout.FIRST_ROW_AND_GROUP_DISTANCE); infoLabel = addMultilineLabel(gridPane, gridRow, Layout.FIRST_ROW_AND_GROUP_DISTANCE);
} }
@ -190,11 +196,10 @@ public abstract class TradeStepDetailsView extends AnchorPane {
+ "\n\nPlease report the problem to your arbitrator. He will forward it to the developers to investigate the problem.\n" + + "\n\nPlease report the problem to your arbitrator. He will forward it to the developers to investigate the problem.\n" +
"After the problem has be analysed you will get back all the funds you paid in.\n" + "After the problem has be analysed you will get back all the funds you paid in.\n" +
"There will be no arbitration fee charged if it was a technical error."); "There will be no arbitration fee charged if it was a technical error.");
infoLabel.setStyle(" -fx-text-fill: -bs-error-red;"); infoLabel.setStyle(" -fx-text-fill: -bs-error-red;");*/
if (openSupportTicketButton == null) { if (openSupportTicketButton == null) {
openSupportTicketButton = addButtonAfterGroup(gridPane, ++gridRow, "Request support"); openSupportTicketButton = addButton(gridPane, ++gridRow, "Request support");
GridPane.setColumnIndex(openSupportTicketButton, 0);
GridPane.setHalignment(openSupportTicketButton, HPos.LEFT); GridPane.setHalignment(openSupportTicketButton, HPos.LEFT);
openSupportTicketButton.setOnAction(e -> model.dataModel.onOpenSupportTicket()); openSupportTicketButton.setOnAction(e -> model.dataModel.onOpenSupportTicket());
} }

View file

@ -27,6 +27,7 @@ import io.bitsquare.p2p.storage.data.ExpirableMailboxPayload;
import io.bitsquare.p2p.storage.data.ExpirablePayload; import io.bitsquare.p2p.storage.data.ExpirablePayload;
import io.bitsquare.p2p.storage.data.ProtectedData; import io.bitsquare.p2p.storage.data.ProtectedData;
import io.bitsquare.p2p.storage.data.ProtectedMailboxData; import io.bitsquare.p2p.storage.data.ProtectedMailboxData;
import io.bitsquare.p2p.storage.messages.AddDataMessage;
import javafx.beans.property.*; import javafx.beans.property.*;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import org.fxmisc.easybind.EasyBind; import org.fxmisc.easybind.EasyBind;
@ -45,7 +46,8 @@ import java.util.concurrent.CopyOnWriteArraySet;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
public class P2PService implements SetupListener, MessageListener, ConnectionListener, RequestDataManager.Listener, HashMapChangedListener { public class P2PService implements SetupListener, MessageListener, ConnectionListener, RequestDataManager.Listener,
HashMapChangedListener {
private static final Logger log = LoggerFactory.getLogger(P2PService.class); private static final Logger log = LoggerFactory.getLogger(P2PService.class);
private final SeedNodesRepository seedNodesRepository; private final SeedNodesRepository seedNodesRepository;
@ -56,6 +58,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
// set in init // set in init
private NetworkNode networkNode; private NetworkNode networkNode;
private Broadcaster broadcaster;
private P2PDataStorage p2PDataStorage; private P2PDataStorage p2PDataStorage;
private PeerManager peerManager; private PeerManager peerManager;
private RequestDataManager requestDataManager; private RequestDataManager requestDataManager;
@ -118,7 +121,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
networkNode.addConnectionListener(this); networkNode.addConnectionListener(this);
networkNode.addMessageListener(this); networkNode.addMessageListener(this);
Broadcaster broadcaster = new Broadcaster(networkNode); broadcaster = new Broadcaster(networkNode);
p2PDataStorage = new P2PDataStorage(broadcaster, networkNode, storageDir); p2PDataStorage = new P2PDataStorage(broadcaster, networkNode, storageDir);
p2PDataStorage.addHashMapChangedListener(this); p2PDataStorage.addHashMapChangedListener(this);
@ -455,28 +458,23 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
} }
} }
public void sendEncryptedMailboxMessage(NodeAddress peerNodeAddress, PubKeyRing peersPubKeyRing, public void sendEncryptedMailboxMessage(NodeAddress peersNodeAddress, PubKeyRing peersPubKeyRing,
MailboxMessage message, SendMailboxMessageListener sendMailboxMessageListener) { MailboxMessage message,
SendMailboxMessageListener sendMailboxMessageListener) {
Log.traceCall("message " + message); Log.traceCall("message " + message);
checkNotNull(peerNodeAddress, "PeerAddress must not be null (sendEncryptedMailboxMessage)"); checkNotNull(peersNodeAddress,
checkArgument(optionalKeyRing.isPresent(), "keyRing not set. Seems that is called on a seed node which must not happen."); "PeerAddress must not be null (sendEncryptedMailboxMessage)");
checkArgument(!optionalKeyRing.get().getPubKeyRing().equals(peersPubKeyRing), "We got own keyring instead of that from peer"); checkNotNull(networkNode.getNodeAddress(),
"My node address must not be null at sendEncryptedMailboxMessage");
checkArgument(optionalKeyRing.isPresent(),
"keyRing not set. Seems that is called on a seed node which must not happen.");
checkArgument(!optionalKeyRing.get().getPubKeyRing().equals(peersPubKeyRing),
"We got own keyring instead of that from peer");
checkArgument(optionalEncryptionService.isPresent(),
"EncryptionService not set. Seems that is called on a seed node which must not happen.");
if (isNetworkReady()) { if (isNetworkReady()) {
trySendEncryptedMailboxMessage(peerNodeAddress, peersPubKeyRing, message, sendMailboxMessageListener); if (!networkNode.getAllConnections().isEmpty()) {
} else {
throw new NetworkNotReadyException();
}
}
// send message and if it fails (peer offline) we store the data to the network
private void trySendEncryptedMailboxMessage(NodeAddress peersNodeAddress, PubKeyRing peersPubKeyRing,
MailboxMessage message, SendMailboxMessageListener sendMailboxMessageListener) {
Log.traceCall();
checkNotNull(networkNode.getNodeAddress(), "My node address must not be null at trySendEncryptedMailboxMessage");
checkArgument(optionalKeyRing.isPresent(), "keyRing not set. Seems that is called on a seed node which must not happen.");
checkArgument(optionalEncryptionService.isPresent(), "EncryptionService not set. Seems that is called on a seed node which must not happen.");
checkNotNull(networkNode.getNodeAddress(), "networkNode.getNodeAddress() must not be null.");
try { try {
log.info("\n\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" + log.info("\n\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" +
"Encrypt message:\nmessage={}" "Encrypt message:\nmessage={}"
@ -503,30 +501,68 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
addMailboxData(new ExpirableMailboxPayload(directMessage, addMailboxData(new ExpirableMailboxPayload(directMessage,
optionalKeyRing.get().getSignatureKeyPair().getPublic(), optionalKeyRing.get().getSignatureKeyPair().getPublic(),
receiverStoragePublicKey), receiverStoragePublicKey),
receiverStoragePublicKey); receiverStoragePublicKey,
sendMailboxMessageListener.onStoredInMailbox(); sendMailboxMessageListener);
} }
}); });
} catch (CryptoException e) { } catch (CryptoException e) {
log.error("sendEncryptedMessage failed"); log.error("sendEncryptedMessage failed");
e.printStackTrace(); e.printStackTrace();
sendMailboxMessageListener.onFault(); sendMailboxMessageListener.onFault("Data already exist in our local database");
}
} else {
sendMailboxMessageListener.onFault("There are no P2P network nodes connected. " +
"Please check your internet connection.");
}
} else {
throw new NetworkNotReadyException();
} }
} }
private void addMailboxData(ExpirableMailboxPayload expirableMailboxPayload, PublicKey receiversPublicKey) {
private void addMailboxData(ExpirableMailboxPayload expirableMailboxPayload,
PublicKey receiversPublicKey,
SendMailboxMessageListener sendMailboxMessageListener) {
Log.traceCall(); Log.traceCall();
checkArgument(optionalKeyRing.isPresent(), "keyRing not set. Seems that is called on a seed node which must not happen."); checkArgument(optionalKeyRing.isPresent(),
"keyRing not set. Seems that is called on a seed node which must not happen.");
if (isNetworkReady()) { if (isNetworkReady()) {
if (!networkNode.getAllConnections().isEmpty()) {
try { try {
ProtectedMailboxData protectedMailboxData = p2PDataStorage.getMailboxDataWithSignedSeqNr( ProtectedMailboxData protectedMailboxData = p2PDataStorage.getMailboxDataWithSignedSeqNr(
expirableMailboxPayload, expirableMailboxPayload,
optionalKeyRing.get().getSignatureKeyPair(), optionalKeyRing.get().getSignatureKeyPair(),
receiversPublicKey); receiversPublicKey);
p2PDataStorage.add(protectedMailboxData, networkNode.getNodeAddress());
Timer sendMailboxMessageTimeoutTimer = UserThread.runAfter(() -> {
boolean result = p2PDataStorage.remove(protectedMailboxData, networkNode.getNodeAddress());
log.debug("remove result=" + result);
sendMailboxMessageListener.onFault("A timeout occurred when trying to broadcast mailbox data.");
}, 30);
broadcaster.addOneTimeListener(message -> {
if (message instanceof AddDataMessage &&
((AddDataMessage) message).data.equals(protectedMailboxData)) {
sendMailboxMessageListener.onStoredInMailbox();
sendMailboxMessageTimeoutTimer.cancel();
}
});
boolean result = p2PDataStorage.add(protectedMailboxData, networkNode.getNodeAddress());
if (!result) {
sendMailboxMessageTimeoutTimer.cancel();
sendMailboxMessageListener.onFault("Data already exists in our local database");
boolean result2 = p2PDataStorage.remove(protectedMailboxData, networkNode.getNodeAddress());
log.debug("remove result=" + result2);
}
} catch (CryptoException e) { } catch (CryptoException e) {
log.error("Signing at getDataWithSignedSeqNr failed. That should never happen."); log.error("Signing at getDataWithSignedSeqNr failed. That should never happen.");
} }
} else {
sendMailboxMessageListener.onFault("There are no P2P network nodes connected. " +
"Please check your internet connection.");
}
} else { } else {
throw new NetworkNotReadyException(); throw new NetworkNotReadyException();
} }
@ -651,8 +687,6 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public boolean isNetworkReady() { public boolean isNetworkReady() {
log.debug("###### isNetworkReady networkReadyBinding " + networkReadyBinding.get());
log.debug("###### isNetworkReady hiddenServicePublished.get() && preliminaryDataReceived.get() " + (hiddenServicePublished.get() && preliminaryDataReceived.get()));
return hiddenServicePublished.get() && preliminaryDataReceived.get(); return hiddenServicePublished.get() && preliminaryDataReceived.get();
} }

View file

@ -5,5 +5,5 @@ public interface SendMailboxMessageListener {
void onStoredInMailbox(); void onStoredInMailbox();
void onFault(); void onFault(String errorMessage);
} }

View file

@ -14,10 +14,18 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.Set; import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
public class Broadcaster { public class Broadcaster {
private static final Logger log = LoggerFactory.getLogger(Broadcaster.class); private static final Logger log = LoggerFactory.getLogger(Broadcaster.class);
public interface Listener {
void onBroadcasted(DataBroadcastMessage message);
}
private final NetworkNode networkNode; private final NetworkNode networkNode;
private final Set<Listener> listeners = new CopyOnWriteArraySet<>();
public Broadcaster(NetworkNode networkNode) { public Broadcaster(NetworkNode networkNode) {
this.networkNode = networkNode; this.networkNode = networkNode;
@ -38,6 +46,10 @@ public class Broadcaster {
@Override @Override
public void onSuccess(Connection connection) { public void onSuccess(Connection connection) {
log.trace("Broadcast from " + networkNode.getNodeAddress() + " to " + connection + " succeeded."); log.trace("Broadcast from " + networkNode.getNodeAddress() + " to " + connection + " succeeded.");
listeners.stream().forEach(listener -> {
listener.onBroadcasted(message);
listeners.remove(listener);
});
} }
@Override @Override
@ -51,4 +63,10 @@ public class Broadcaster {
"message = {}", message); "message = {}", message);
} }
} }
// That listener gets immediately removed after the handler is called
public void addOneTimeListener(Listener listener) {
listeners.add(listener);
}
} }

View file

@ -317,7 +317,7 @@ public class P2PServiceTest {
} }
@Override @Override
public void onFault() { public void onFault(String errorMessage) {
log.error("onFault"); log.error("onFault");
} }
} }
@ -353,7 +353,7 @@ public class P2PServiceTest {
} }
@Override @Override
public void onFault() { public void onFault(String errorMessage) {
log.error("onFault"); log.error("onFault");
} }
} }