Interrupted trade process working for both variants

This commit is contained in:
Manfred Karrer 2015-04-03 17:53:43 +02:00
parent a2aa0b40b4
commit d09fb97f8d
13 changed files with 161 additions and 50 deletions

View file

@ -54,6 +54,8 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
SELLER_WAIT_TX_CONF, SELLER_WAIT_TX_CONF,
SELLER_WAIT_PAYMENT_STARTED, SELLER_WAIT_PAYMENT_STARTED,
SELLER_CONFIRM_RECEIVE_PAYMENT, SELLER_CONFIRM_RECEIVE_PAYMENT,
SELLER_PUBLISH_PAYOUT_TX,
SELLER_SEND_PUBLISHED_MSG,
SELLER_COMPLETED, SELLER_COMPLETED,
BUYER_WAIT_TX_CONF, BUYER_WAIT_TX_CONF,
@ -287,7 +289,12 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
break; break;
case FIAT_PAYMENT_RECEIVED: case FIAT_PAYMENT_RECEIVED:
viewState.set(ViewState.SELLER_PUBLISH_PAYOUT_TX);
break;
case PAYOUT_PUBLISHED: case PAYOUT_PUBLISHED:
viewState.set(ViewState.SELLER_SEND_PUBLISHED_MSG);
break;
case PAYOUT_PUBLISHED_MSG_SENT:
viewState.set(ViewState.SELLER_COMPLETED); viewState.set(ViewState.SELLER_COMPLETED);
break; break;
@ -324,7 +331,12 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
break; break;
case FIAT_PAYMENT_RECEIVED: case FIAT_PAYMENT_RECEIVED:
viewState.set(ViewState.SELLER_PUBLISH_PAYOUT_TX);
break;
case PAYOUT_PUBLISHED: case PAYOUT_PUBLISHED:
viewState.set(ViewState.SELLER_SEND_PUBLISHED_MSG);
break;
case PAYOUT_PUBLISHED_MSG_SENT:
viewState.set(ViewState.SELLER_COMPLETED); viewState.set(ViewState.SELLER_COMPLETED);
break; break;

View file

@ -123,6 +123,12 @@ public class SellerSubView extends TradeSubView {
"your security deposit and the Bitcoin buyer receive the Bitcoin amount you sold.", "your security deposit and the Bitcoin buyer receive the Bitcoin amount you sold.",
model.getCurrencyCode())); model.getCurrencyCode()));
break;
case SELLER_PUBLISH_PAYOUT_TX:
((ConfirmFiatReceivedView) tradeStepDetailsView).setStatusText("Publishing transaction...");
break;
case SELLER_SEND_PUBLISHED_MSG:
((ConfirmFiatReceivedView) tradeStepDetailsView).setStatusText("Sending message to trading partner...");
break; break;
case SELLER_COMPLETED: case SELLER_COMPLETED:
waitTxInBlockchain.done(); waitTxInBlockchain.done();

View file

@ -38,6 +38,9 @@ public class ConfirmFiatReceivedView extends TradeStepDetailsView {
private Label infoLabel; private Label infoLabel;
private InfoDisplay infoDisplay; private InfoDisplay infoDisplay;
private final ChangeListener<String> txIdChangeListener; private final ChangeListener<String> txIdChangeListener;
private Button confirmFiatReceivedButton;
private Label statusLabel;
private ProgressIndicator statusProgressIndicator;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -74,6 +77,10 @@ public class ConfirmFiatReceivedView extends TradeStepDetailsView {
private void onPaymentReceived(ActionEvent actionEvent) { private void onPaymentReceived(ActionEvent actionEvent) {
log.debug("onPaymentReceived"); log.debug("onPaymentReceived");
model.fiatPaymentReceived(); model.fiatPaymentReceived();
confirmFiatReceivedButton.setDisable(true);
statusProgressIndicator.setVisible(true);
statusProgressIndicator.setProgress(-1);
} }
@ -91,6 +98,10 @@ public class ConfirmFiatReceivedView extends TradeStepDetailsView {
infoDisplay.setText(text); infoDisplay.setText(text);
} }
public void setStatusText(String text) {
statusLabel.setText(text);
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Build view // Build view
@ -104,8 +115,14 @@ public class ConfirmFiatReceivedView extends TradeStepDetailsView {
getAndAddTitledGroupBg(gridPane, gridRow, 1, "Information", Layout.GROUP_DISTANCE); getAndAddTitledGroupBg(gridPane, gridRow, 1, "Information", Layout.GROUP_DISTANCE);
infoLabel = getAndAddInfoLabel(gridPane, gridRow++, Layout.FIRST_ROW_AND_GROUP_DISTANCE); infoLabel = getAndAddInfoLabel(gridPane, gridRow++, Layout.FIRST_ROW_AND_GROUP_DISTANCE);
getAndAddButton(gridPane, gridRow++, "Confirm payment receipt", this::onPaymentReceived); ButtonWithProgressIndicatorAndLabelBucket bucket = getAndAddButtonWithStatus(gridPane, gridRow++, "Confirm payment receipt", this::onPaymentReceived);
confirmFiatReceivedButton = bucket.button;
statusProgressIndicator = bucket.progressIndicator;
statusLabel = bucket.label;
} }
} }

View file

@ -44,8 +44,10 @@ public class StartFiatView extends TradeStepDetailsView {
private TextFieldWithCopyIcon secondaryIdTextField; private TextFieldWithCopyIcon secondaryIdTextField;
private InfoDisplay paymentsInfoDisplay; private InfoDisplay paymentsInfoDisplay;
private Button paymentStartedButton; private Button paymentStartedButton;
private Label statusLabel;
private final ChangeListener<String> txIdChangeListener; private final ChangeListener<String> txIdChangeListener;
private ProgressIndicator statusProgressIndicator;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -102,6 +104,9 @@ public class StartFiatView extends TradeStepDetailsView {
log.debug("onPaymentStarted"); log.debug("onPaymentStarted");
model.fiatPaymentStarted(); model.fiatPaymentStarted();
paymentStartedButton.setDisable(true); paymentStartedButton.setDisable(true);
statusProgressIndicator.setVisible(true);
statusProgressIndicator.setProgress(-1);
statusLabel.setText("Sending message to trading partner...");
} }
@ -122,6 +127,9 @@ public class StartFiatView extends TradeStepDetailsView {
primaryIdTextField = getAndAddLabelTextFieldWithCopyIconPair(gridPane, gridRow++, "IBAN:").textFieldWithCopyIcon; primaryIdTextField = getAndAddLabelTextFieldWithCopyIconPair(gridPane, gridRow++, "IBAN:").textFieldWithCopyIcon;
secondaryIdTextField = getAndAddLabelTextFieldWithCopyIconPair(gridPane, gridRow++, "BIC:").textFieldWithCopyIcon; secondaryIdTextField = getAndAddLabelTextFieldWithCopyIconPair(gridPane, gridRow++, "BIC:").textFieldWithCopyIcon;
paymentsInfoDisplay = getAndAddInfoDisplay(gridPane, gridRow++, "infoDisplay", this::onOpenHelp); paymentsInfoDisplay = getAndAddInfoDisplay(gridPane, gridRow++, "infoDisplay", this::onOpenHelp);
paymentStartedButton = getAndAddButton(gridPane, gridRow++, "Payment started", this::onPaymentStarted); ButtonWithProgressIndicatorAndLabelBucket bucket = getAndAddButtonWithStatus(gridPane, gridRow++, "Payment started", this::onPaymentStarted);
paymentStartedButton = bucket.button;
statusProgressIndicator = bucket.progressIndicator;
statusLabel = bucket.label;
} }
} }

View file

@ -195,6 +195,34 @@ public class ComponentBuilder {
return button; return button;
} }
public static ButtonWithProgressIndicatorAndLabelBucket getAndAddButtonWithStatus(GridPane gridPane,
int rowIndex,
String ButtonTitle,
EventHandler<ActionEvent> onActionHandler) {
HBox hBox = new HBox();
hBox.setSpacing(10);
Button button = new Button(ButtonTitle);
button.setDefaultButton(true);
button.setOnAction(onActionHandler);
ProgressIndicator progressIndicator = new ProgressIndicator(0);
progressIndicator.setPrefHeight(24);
progressIndicator.setPrefWidth(24);
progressIndicator.setVisible(false);
Label label = new Label();
label.setPadding(new Insets(5, 0, 0, 0));
hBox.getChildren().addAll(button, progressIndicator, label);
GridPane.setRowIndex(hBox, rowIndex);
GridPane.setColumnIndex(hBox, 1);
GridPane.setMargin(hBox, new Insets(15, 0, 40, 0));
gridPane.getChildren().add(hBox);
return new ButtonWithProgressIndicatorAndLabelBucket(button, progressIndicator, label);
}
public static class LabelTextFieldPair { public static class LabelTextFieldPair {
public Label label; public Label label;
public TextField textField; public TextField textField;
@ -235,4 +263,16 @@ public class ComponentBuilder {
} }
} }
public static class ButtonWithProgressIndicatorAndLabelBucket {
public Button button;
public ProgressIndicator progressIndicator;
public Label label;
public ButtonWithProgressIndicatorAndLabelBucket(Button button, ProgressIndicator progressIndicator, Label label) {
this.button = button;
this.progressIndicator = progressIndicator;
this.label = label;
}
}
} }

View file

@ -175,19 +175,25 @@ public class FileManager<T> {
} }
public void removeFile(String fileName) { public void removeFile(String fileName) {
log.debug("removeFile" + fileName);
File file = new File(dir, fileName); File file = new File(dir, fileName);
boolean result = file.delete(); lock.lock();
if (!result) try {
log.warn("Could not delete file: " + file.toString()); boolean result = file.delete();
if (!result)
log.warn("Could not delete file: " + file.toString());
File backupDir = new File(Paths.get(dir.getAbsolutePath(), "backup").toString()); File backupDir = new File(Paths.get(dir.getAbsolutePath(), "backup").toString());
if (backupDir.exists()) { if (backupDir.exists()) {
File backupFile = new File(Paths.get(dir.getAbsolutePath(), "backup", fileName).toString()); File backupFile = new File(Paths.get(dir.getAbsolutePath(), "backup", fileName).toString());
if (backupFile.exists()) { if (backupFile.exists()) {
result = backupFile.delete(); result = backupFile.delete();
if (!result) if (!result)
log.warn("Could not delete backupFile: " + file.toString()); log.warn("Could not delete backupFile: " + file.toString());
}
} }
} finally {
lock.unlock();
} }
} }
@ -210,23 +216,33 @@ public class FileManager<T> {
} }
public void removeAndBackupFile(String fileName) throws IOException { public void removeAndBackupFile(String fileName) throws IOException {
File corruptedBackupDir = new File(Paths.get(dir.getAbsolutePath(), "corrupted").toString()); lock.lock();
if (!corruptedBackupDir.exists()) try {
if (!corruptedBackupDir.mkdir()) File corruptedBackupDir = new File(Paths.get(dir.getAbsolutePath(), "corrupted").toString());
log.warn("make dir failed"); if (!corruptedBackupDir.exists())
if (!corruptedBackupDir.mkdir())
log.warn("make dir failed");
File corruptedFile = new File(Paths.get(dir.getAbsolutePath(), "corrupted", fileName).toString()); File corruptedFile = new File(Paths.get(dir.getAbsolutePath(), "corrupted", fileName).toString());
renameTempFileToFile(storageFile, corruptedFile); renameTempFileToFile(storageFile, corruptedFile);
} finally {
lock.unlock();
}
} }
public void backupFile(String fileName) throws IOException { public void backupFile(String fileName) throws IOException {
File backupDir = new File(Paths.get(dir.getAbsolutePath(), "backup").toString()); lock.lock();
if (!backupDir.exists()) try {
if (!backupDir.mkdir()) File backupDir = new File(Paths.get(dir.getAbsolutePath(), "backup").toString());
log.warn("make dir failed"); if (!backupDir.exists())
if (!backupDir.mkdir())
log.warn("make dir failed");
File backupFile = new File(Paths.get(dir.getAbsolutePath(), "backup", fileName).toString()); File backupFile = new File(Paths.get(dir.getAbsolutePath(), "backup", fileName).toString());
Files.copy(storageFile, backupFile); Files.copy(storageFile, backupFile);
} finally {
lock.unlock();
}
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -258,8 +274,6 @@ public class FileManager<T> {
objectOutputStream = new ObjectOutputStream(fileOutputStream); objectOutputStream = new ObjectOutputStream(fileOutputStream);
// TODO ConcurrentModificationException happens sometimes at that line // TODO ConcurrentModificationException happens sometimes at that line
//log.debug("serializable " + serializable.toString());
log.debug("storageFile " + storageFile.toString());
objectOutputStream.writeObject(serializable); objectOutputStream.writeObject(serializable);
// Attempt to force the bits to hit the disk. In reality the OS or hard disk itself may still decide // Attempt to force the bits to hit the disk. In reality the OS or hard disk itself may still decide
@ -274,6 +288,8 @@ public class FileManager<T> {
renameTempFileToFile(tempFile, storageFile); renameTempFileToFile(tempFile, storageFile);
} catch (Throwable t) { } catch (Throwable t) {
log.debug("storageFile " + storageFile.toString());
log.debug("currentThread " + Thread.currentThread());
t.printStackTrace(); t.printStackTrace();
log.error("Error at saveToFile: " + t.getMessage()); log.error("Error at saveToFile: " + t.getMessage());
} finally { } finally {

View file

@ -73,23 +73,15 @@ public class BuyerAsTakerProtocol implements TradeProtocol {
// Public methods // Public methods
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public void cleanup() {
log.debug("cleanup " + this);
processModel.getMessageService().removeMessageHandler(messageHandler);
}
public void setMailboxMessage(MailboxMessage mailboxMessage) { public void setMailboxMessage(MailboxMessage mailboxMessage) {
log.debug("setMailboxMessage " + mailboxMessage); log.debug("setMailboxMessage " + mailboxMessage);
// Might be called twice, so check that its only processed once // Might be called twice, so check that its only processed once
/* if (takerTradeProcessModel.getMailboxMessage() == null) { if (processModel.getMailboxMessage() == null) {
takerTradeProcessModel.setMailboxMessage(mailboxMessage); processModel.setMailboxMessage(mailboxMessage);
if (mailboxMessage instanceof FiatTransferStartedMessage) { if (mailboxMessage instanceof PayoutTxPublishedMessage) {
handleFiatTransferStartedMessage((FiatTransferStartedMessage) mailboxMessage); handle((PayoutTxPublishedMessage) mailboxMessage);
} }
else if (mailboxMessage instanceof DepositTxPublishedMessage) { }
handleDepositTxPublishedMessage((DepositTxPublishedMessage) mailboxMessage);
}
}*/
} }
public void takeAvailableOffer() { public void takeAvailableOffer() {
@ -106,6 +98,10 @@ public class BuyerAsTakerProtocol implements TradeProtocol {
taskRunner.run(); taskRunner.run();
} }
public void cleanup() {
log.debug("cleanup " + this);
processModel.getMessageService().removeMessageHandler(messageHandler);
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message handling // Incoming message handling

View file

@ -77,12 +77,15 @@ public class SellerAsOffererProtocol implements TradeProtocol {
public void setMailboxMessage(MailboxMessage mailboxMessage) { public void setMailboxMessage(MailboxMessage mailboxMessage) {
log.debug("setMailboxMessage " + mailboxMessage); log.debug("setMailboxMessage " + mailboxMessage);
// Might be called twice, so check that its only processed once // Might be called twice, so check that its only processed once
/* if (offererTradeProcessModel.getMailboxMessage() == null) { if (processModel.getMailboxMessage() == null) {
offererTradeProcessModel.setMailboxMessage(mailboxMessage); processModel.setMailboxMessage(mailboxMessage);
if (mailboxMessage instanceof PayoutTxPublishedMessage) { if (mailboxMessage instanceof FiatTransferStartedMessage) {
handlePayoutTxPublishedMessage((PayoutTxPublishedMessage) mailboxMessage); handle((FiatTransferStartedMessage) mailboxMessage);
} }
}*/ else if (mailboxMessage instanceof DepositTxPublishedMessage) {
handle((DepositTxPublishedMessage) mailboxMessage);
}
}
} }
public void cleanup() { public void cleanup() {

View file

@ -75,11 +75,6 @@ public class SellerAsTakerProtocol implements TradeProtocol {
// Public methods // Public methods
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public void cleanup() {
log.debug("cleanup " + this);
processModel.getMessageService().removeMessageHandler(messageHandler);
}
public void setMailboxMessage(MailboxMessage mailboxMessage) { public void setMailboxMessage(MailboxMessage mailboxMessage) {
log.debug("setMailboxMessage " + mailboxMessage); log.debug("setMailboxMessage " + mailboxMessage);
// Might be called twice, so check that its only processed once // Might be called twice, so check that its only processed once
@ -107,6 +102,11 @@ public class SellerAsTakerProtocol implements TradeProtocol {
taskRunner.run(); taskRunner.run();
} }
public void cleanup() {
log.debug("cleanup " + this);
processModel.getMessageService().removeMessageHandler(messageHandler);
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message handling // Incoming message handling

View file

@ -43,6 +43,7 @@ public class SendDepositTxPublishedMessage extends TradeTask {
@Override @Override
public void handleResult() { public void handleResult() {
log.trace("DepositTxPublishedMessage successfully arrived at peer"); log.trace("DepositTxPublishedMessage successfully arrived at peer");
complete(); complete();
} }

View file

@ -19,10 +19,14 @@ package io.bitsquare.trade.protocol.trade.tasks.seller;
import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.p2p.listener.SendMessageListener; import io.bitsquare.p2p.listener.SendMessageListener;
import io.bitsquare.trade.OffererTrade;
import io.bitsquare.trade.TakerTrade;
import io.bitsquare.trade.Trade; import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.TradeTask; import io.bitsquare.trade.protocol.trade.TradeTask;
import io.bitsquare.trade.protocol.trade.messages.PayoutTxPublishedMessage; import io.bitsquare.trade.protocol.trade.messages.PayoutTxPublishedMessage;
import io.bitsquare.trade.states.OffererTradeState;
import io.bitsquare.trade.states.StateUtil; import io.bitsquare.trade.states.StateUtil;
import io.bitsquare.trade.states.TakerTradeState;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -46,6 +50,12 @@ public class SendPayoutTxPublishedMessage extends TradeTask {
@Override @Override
public void handleResult() { public void handleResult() {
log.trace("PayoutTxPublishedMessage successfully arrived at peer"); log.trace("PayoutTxPublishedMessage successfully arrived at peer");
if (trade instanceof TakerTrade)
trade.setProcessState(TakerTradeState.ProcessState.PAYOUT_PUBLISHED_MSG_SENT);
else if (trade instanceof OffererTrade)
trade.setProcessState(OffererTradeState.ProcessState.PAYOUT_PUBLISHED_MSG_SENT);
complete(); complete();
} }

View file

@ -41,6 +41,7 @@ public class OffererTradeState {
FIAT_PAYMENT_RECEIVED, FIAT_PAYMENT_RECEIVED,
PAYOUT_PUBLISHED, PAYOUT_PUBLISHED,
PAYOUT_PUBLISHED_MSG_SENT,
MESSAGE_SENDING_FAILED, MESSAGE_SENDING_FAILED,
EXCEPTION EXCEPTION

View file

@ -42,6 +42,7 @@ public class TakerTradeState {
FIAT_PAYMENT_RECEIVED, FIAT_PAYMENT_RECEIVED,
PAYOUT_PUBLISHED, PAYOUT_PUBLISHED,
PAYOUT_PUBLISHED_MSG_SENT,
MESSAGE_SENDING_FAILED, MESSAGE_SENDING_FAILED,
EXCEPTION EXCEPTION