Remove OpenOffer, remove offerIsAvailable handling form trade protocol

This commit is contained in:
Manfred Karrer 2015-03-17 19:11:10 +01:00
parent 831c001fb4
commit b10b6ff203
34 changed files with 327 additions and 895 deletions

View File

@ -51,7 +51,8 @@ public abstract class Task<T extends SharedModel> {
abstract protected void doRun() throws WalletException, TransactionVerificationException, SigningException; abstract protected void doRun() throws WalletException, TransactionVerificationException, SigningException;
abstract protected void updateStateOnFault(); protected void updateStateOnFault() {
}
private void interceptBeforeRun() { private void interceptBeforeRun() {
if (getClass() == taskToInterceptBeforeRun) if (getClass() == taskToInterceptBeforeRun)

View File

@ -17,6 +17,9 @@
package io.bitsquare.gui.main.debug; package io.bitsquare.gui.main.debug;
import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.viewfx.view.FxmlView;
import io.bitsquare.common.viewfx.view.InitializableView;
import io.bitsquare.trade.protocol.availability.CheckOfferAvailabilityProtocol; import io.bitsquare.trade.protocol.availability.CheckOfferAvailabilityProtocol;
import io.bitsquare.trade.protocol.availability.tasks.ProcessReportOfferAvailabilityMessage; import io.bitsquare.trade.protocol.availability.tasks.ProcessReportOfferAvailabilityMessage;
import io.bitsquare.trade.protocol.availability.tasks.RequestIsOfferAvailable; import io.bitsquare.trade.protocol.availability.tasks.RequestIsOfferAvailable;
@ -28,11 +31,9 @@ import io.bitsquare.trade.protocol.placeoffer.tasks.ValidateOffer;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererProtocol; import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererProtocol;
import io.bitsquare.trade.protocol.trade.offerer.tasks.GetOffererDepositTxInputs; import io.bitsquare.trade.protocol.trade.offerer.tasks.GetOffererDepositTxInputs;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessPayoutTxPublishedMessage; import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessPayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessRequestOffererPublishDepositTxMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessRequestTakeOfferMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessRequestDepositTxInputsMessage; import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessRequestDepositTxInputsMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessRequestOffererPublishDepositTxMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.RequestDepositPayment; import io.bitsquare.trade.protocol.trade.offerer.tasks.RequestDepositPayment;
import io.bitsquare.trade.protocol.trade.offerer.tasks.RespondToTakeOfferRequest;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SendBankTransferStartedMessage; import io.bitsquare.trade.protocol.trade.offerer.tasks.SendBankTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SendDepositTxIdToTaker; import io.bitsquare.trade.protocol.trade.offerer.tasks.SendDepositTxIdToTaker;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SetupListenerForBlockChainConfirmation; import io.bitsquare.trade.protocol.trade.offerer.tasks.SetupListenerForBlockChainConfirmation;
@ -47,19 +48,14 @@ import io.bitsquare.trade.protocol.trade.taker.tasks.CreateTakeOfferFeeTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessBankTransferStartedMessage; import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessBankTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessDepositTxPublishedMessage; import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessDepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessRequestDepositPaymentMessage; import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessRequestDepositPaymentMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessRespondToTakeOfferRequestMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.RequestTakeOffer;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendPayoutTxToOfferer; import io.bitsquare.trade.protocol.trade.taker.tasks.SendPayoutTxToOfferer;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendSignedTakerDepositTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendRequestDepositTxInputsMessage; import io.bitsquare.trade.protocol.trade.taker.tasks.SendRequestDepositTxInputsMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendSignedTakerDepositTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.SignAndPublishPayoutTx; import io.bitsquare.trade.protocol.trade.taker.tasks.SignAndPublishPayoutTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerCommitDepositTx; import io.bitsquare.trade.protocol.trade.taker.tasks.TakerCommitDepositTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerCreatesAndSignsDepositTx; import io.bitsquare.trade.protocol.trade.taker.tasks.TakerCreatesAndSignsDepositTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.VerifyOfferFeePayment; import io.bitsquare.trade.protocol.trade.taker.tasks.VerifyOfferFeePayment;
import io.bitsquare.trade.protocol.trade.taker.tasks.VerifyOffererAccount; import io.bitsquare.trade.protocol.trade.taker.tasks.VerifyOffererAccount;
import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.viewfx.view.FxmlView;
import io.bitsquare.common.viewfx.view.InitializableView;
import java.util.Arrays; import java.util.Arrays;
@ -106,9 +102,6 @@ public class DebugView extends InitializableView {
/*---- Protocol ----*/ /*---- Protocol ----*/
BuyerAsOffererProtocol.class, BuyerAsOffererProtocol.class,
ProcessRequestTakeOfferMessage.class,
RespondToTakeOfferRequest.class,
ProcessRequestDepositTxInputsMessage.class, ProcessRequestDepositTxInputsMessage.class,
GetOffererDepositTxInputs.class, GetOffererDepositTxInputs.class,
RequestDepositPayment.class, RequestDepositPayment.class,
@ -130,10 +123,6 @@ public class DebugView extends InitializableView {
/*---- Protocol ----*/ /*---- Protocol ----*/
SellerAsTakerProtocol.class, SellerAsTakerProtocol.class,
io.bitsquare.trade.protocol.trade.taker.tasks.GetPeerAddress.class,
RequestTakeOffer.class,
ProcessRespondToTakeOfferRequestMessage.class,
CreateTakeOfferFeeTx.class, CreateTakeOfferFeeTx.class,
SendRequestDepositTxInputsMessage.class, SendRequestDepositTxInputsMessage.class,

View File

@ -17,20 +17,20 @@
package io.bitsquare.gui.main.portfolio.offer; package io.bitsquare.gui.main.portfolio.offer;
import io.bitsquare.offer.OpenOffer; import io.bitsquare.offer.Offer;
/** /**
* We could remove that wrapper if it is not needed for additional UI only fields. * We could remove that wrapper if it is not needed for additional UI only fields.
*/ */
class OpenOfferListItem { class OfferListItem {
private final OpenOffer openOffer; private final Offer offer;
public OpenOfferListItem(OpenOffer openOffer) { public OfferListItem(Offer offer) {
this.openOffer = openOffer; this.offer = offer;
} }
public OpenOffer getOpenOffer() { public Offer getOffer() {
return openOffer; return offer;
} }
} }

View File

@ -17,15 +17,14 @@
package io.bitsquare.gui.main.portfolio.offer; package io.bitsquare.gui.main.portfolio.offer;
import io.bitsquare.offer.Direction;
import io.bitsquare.offer.Offer;
import io.bitsquare.offer.OpenOffer;
import io.bitsquare.trade.TradeManager;
import io.bitsquare.user.User;
import io.bitsquare.common.handlers.ErrorMessageHandler; import io.bitsquare.common.handlers.ErrorMessageHandler;
import io.bitsquare.common.handlers.ResultHandler; import io.bitsquare.common.handlers.ResultHandler;
import io.bitsquare.common.viewfx.model.Activatable; import io.bitsquare.common.viewfx.model.Activatable;
import io.bitsquare.common.viewfx.model.DataModel; import io.bitsquare.common.viewfx.model.DataModel;
import io.bitsquare.offer.Direction;
import io.bitsquare.offer.Offer;
import io.bitsquare.trade.TradeManager;
import io.bitsquare.user.User;
import com.google.inject.Inject; import com.google.inject.Inject;
@ -44,8 +43,8 @@ class OffersDataModel implements Activatable, DataModel {
private final TradeManager tradeManager; private final TradeManager tradeManager;
private final User user; private final User user;
private final ObservableList<OpenOfferListItem> list = FXCollections.observableArrayList(); private final ObservableList<OfferListItem> list = FXCollections.observableArrayList();
private final MapChangeListener<String, OpenOffer> offerMapChangeListener; private final MapChangeListener<String, Offer> offerMapChangeListener;
@Inject @Inject
@ -55,19 +54,19 @@ class OffersDataModel implements Activatable, DataModel {
this.offerMapChangeListener = change -> { this.offerMapChangeListener = change -> {
if (change.wasAdded()) if (change.wasAdded())
list.add(new OpenOfferListItem(change.getValueAdded())); list.add(new OfferListItem(change.getValueAdded()));
else if (change.wasRemoved()) else if (change.wasRemoved())
list.removeIf(e -> e.getOpenOffer().getId().equals(change.getValueRemoved().getId())); list.removeIf(e -> e.getOffer().getId().equals(change.getValueRemoved().getId()));
}; };
} }
@Override @Override
public void activate() { public void activate() {
list.clear(); list.clear();
list.addAll(tradeManager.getOpenOffers().values().stream().map(OpenOfferListItem::new).collect(Collectors.toList())); list.addAll(tradeManager.getOpenOffers().values().stream().map(OfferListItem::new).collect(Collectors.toList()));
// we sort by date, earliest first // we sort by date, earliest first
list.sort((o1, o2) -> o2.getOpenOffer().getOffer().getCreationDate().compareTo(o1.getOpenOffer().getOffer().getCreationDate())); list.sort((o1, o2) -> o2.getOffer().getCreationDate().compareTo(o1.getOffer().getCreationDate()));
tradeManager.getOpenOffers().addListener(offerMapChangeListener); tradeManager.getOpenOffers().addListener(offerMapChangeListener);
} }
@ -82,12 +81,11 @@ class OffersDataModel implements Activatable, DataModel {
} }
public ObservableList<OpenOfferListItem> getList() { public ObservableList<OfferListItem> getList() {
return list; return list;
} }
public Direction getDirection(OpenOffer openOffer) { public Direction getDirection(Offer offer) {
Offer offer = openOffer.getOffer();
return offer.getMessagePublicKey().equals(user.getNetworkPubKey()) ? return offer.getMessagePublicKey().equals(user.getNetworkPubKey()) ?
offer.getDirection() : offer.getMirroredDirection(); offer.getDirection() : offer.getMirroredDirection();
} }

View File

@ -35,8 +35,8 @@ import javafx.util.Callback;
@FxmlView @FxmlView
public class OffersView extends ActivatableViewAndModel<GridPane, OffersViewModel> { public class OffersView extends ActivatableViewAndModel<GridPane, OffersViewModel> {
@FXML TableView<OpenOfferListItem> table; @FXML TableView<OfferListItem> table;
@FXML TableColumn<OpenOfferListItem, OpenOfferListItem> priceColumn, amountColumn, volumeColumn, @FXML TableColumn<OfferListItem, OfferListItem> priceColumn, amountColumn, volumeColumn,
directionColumn, dateColumn, offerIdColumn, removeItemColumn; directionColumn, dateColumn, offerIdColumn, removeItemColumn;
@Inject @Inject
@ -67,10 +67,10 @@ public class OffersView extends ActivatableViewAndModel<GridPane, OffersViewMode
model.removeOpenOffer(offer); model.removeOpenOffer(offer);
} }
private void openOfferDetails(OpenOfferListItem item) { private void openOfferDetails(OfferListItem item) {
// TODO Open popup with details view // TODO Open popup with details view
log.debug("openOfferDetails " + item); log.debug("openOfferDetails " + item);
Utilities.copyToClipboard(item.getOpenOffer().getId()); Utilities.copyToClipboard(item.getOffer().getId());
Popups.openWarningPopup("Under construction", Popups.openWarningPopup("Under construction",
"The offer ID was copied to the clipboard. " + "The offer ID was copied to the clipboard. " +
"Use that to identify your trading peer in the IRC chat room \n\n" + "Use that to identify your trading peer in the IRC chat room \n\n" +
@ -80,16 +80,16 @@ public class OffersView extends ActivatableViewAndModel<GridPane, OffersViewMode
private void setOfferIdColumnCellFactory() { private void setOfferIdColumnCellFactory() {
offerIdColumn.setCellValueFactory((offerListItem) -> new ReadOnlyObjectWrapper<>(offerListItem.getValue())); offerIdColumn.setCellValueFactory((offerListItem) -> new ReadOnlyObjectWrapper<>(offerListItem.getValue()));
offerIdColumn.setCellFactory( offerIdColumn.setCellFactory(
new Callback<TableColumn<OpenOfferListItem, OpenOfferListItem>, TableCell<OpenOfferListItem, OpenOfferListItem>>() { new Callback<TableColumn<OfferListItem, OfferListItem>, TableCell<OfferListItem, OfferListItem>>() {
@Override @Override
public TableCell<OpenOfferListItem, OpenOfferListItem> call(TableColumn<OpenOfferListItem, public TableCell<OfferListItem, OfferListItem> call(TableColumn<OfferListItem,
OpenOfferListItem> column) { OfferListItem> column) {
return new TableCell<OpenOfferListItem, OpenOfferListItem>() { return new TableCell<OfferListItem, OfferListItem>() {
private Hyperlink hyperlink; private Hyperlink hyperlink;
@Override @Override
public void updateItem(final OpenOfferListItem item, boolean empty) { public void updateItem(final OfferListItem item, boolean empty) {
super.updateItem(item, empty); super.updateItem(item, empty);
if (item != null && !empty) { if (item != null && !empty) {
@ -112,14 +112,14 @@ public class OffersView extends ActivatableViewAndModel<GridPane, OffersViewMode
private void setDateColumnCellFactory() { private void setDateColumnCellFactory() {
dateColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue())); dateColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
dateColumn.setCellFactory( dateColumn.setCellFactory(
new Callback<TableColumn<OpenOfferListItem, OpenOfferListItem>, TableCell<OpenOfferListItem, new Callback<TableColumn<OfferListItem, OfferListItem>, TableCell<OfferListItem,
OpenOfferListItem>>() { OfferListItem>>() {
@Override @Override
public TableCell<OpenOfferListItem, OpenOfferListItem> call( public TableCell<OfferListItem, OfferListItem> call(
TableColumn<OpenOfferListItem, OpenOfferListItem> column) { TableColumn<OfferListItem, OfferListItem> column) {
return new TableCell<OpenOfferListItem, OpenOfferListItem>() { return new TableCell<OfferListItem, OfferListItem>() {
@Override @Override
public void updateItem(final OpenOfferListItem item, boolean empty) { public void updateItem(final OfferListItem item, boolean empty) {
super.updateItem(item, empty); super.updateItem(item, empty);
if (item != null) if (item != null)
setText(model.getDate(item)); setText(model.getDate(item));
@ -134,14 +134,14 @@ public class OffersView extends ActivatableViewAndModel<GridPane, OffersViewMode
private void setAmountColumnCellFactory() { private void setAmountColumnCellFactory() {
amountColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue())); amountColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
amountColumn.setCellFactory( amountColumn.setCellFactory(
new Callback<TableColumn<OpenOfferListItem, OpenOfferListItem>, TableCell<OpenOfferListItem, new Callback<TableColumn<OfferListItem, OfferListItem>, TableCell<OfferListItem,
OpenOfferListItem>>() { OfferListItem>>() {
@Override @Override
public TableCell<OpenOfferListItem, OpenOfferListItem> call( public TableCell<OfferListItem, OfferListItem> call(
TableColumn<OpenOfferListItem, OpenOfferListItem> column) { TableColumn<OfferListItem, OfferListItem> column) {
return new TableCell<OpenOfferListItem, OpenOfferListItem>() { return new TableCell<OfferListItem, OfferListItem>() {
@Override @Override
public void updateItem(final OpenOfferListItem item, boolean empty) { public void updateItem(final OfferListItem item, boolean empty) {
super.updateItem(item, empty); super.updateItem(item, empty);
setText(model.getAmount(item)); setText(model.getAmount(item));
} }
@ -153,14 +153,14 @@ public class OffersView extends ActivatableViewAndModel<GridPane, OffersViewMode
private void setPriceColumnCellFactory() { private void setPriceColumnCellFactory() {
priceColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue())); priceColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
priceColumn.setCellFactory( priceColumn.setCellFactory(
new Callback<TableColumn<OpenOfferListItem, OpenOfferListItem>, TableCell<OpenOfferListItem, new Callback<TableColumn<OfferListItem, OfferListItem>, TableCell<OfferListItem,
OpenOfferListItem>>() { OfferListItem>>() {
@Override @Override
public TableCell<OpenOfferListItem, OpenOfferListItem> call( public TableCell<OfferListItem, OfferListItem> call(
TableColumn<OpenOfferListItem, OpenOfferListItem> column) { TableColumn<OfferListItem, OfferListItem> column) {
return new TableCell<OpenOfferListItem, OpenOfferListItem>() { return new TableCell<OfferListItem, OfferListItem>() {
@Override @Override
public void updateItem(final OpenOfferListItem item, boolean empty) { public void updateItem(final OfferListItem item, boolean empty) {
super.updateItem(item, empty); super.updateItem(item, empty);
setText(model.getPrice(item)); setText(model.getPrice(item));
} }
@ -172,14 +172,14 @@ public class OffersView extends ActivatableViewAndModel<GridPane, OffersViewMode
private void setVolumeColumnCellFactory() { private void setVolumeColumnCellFactory() {
volumeColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue())); volumeColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
volumeColumn.setCellFactory( volumeColumn.setCellFactory(
new Callback<TableColumn<OpenOfferListItem, OpenOfferListItem>, TableCell<OpenOfferListItem, new Callback<TableColumn<OfferListItem, OfferListItem>, TableCell<OfferListItem,
OpenOfferListItem>>() { OfferListItem>>() {
@Override @Override
public TableCell<OpenOfferListItem, OpenOfferListItem> call( public TableCell<OfferListItem, OfferListItem> call(
TableColumn<OpenOfferListItem, OpenOfferListItem> column) { TableColumn<OfferListItem, OfferListItem> column) {
return new TableCell<OpenOfferListItem, OpenOfferListItem>() { return new TableCell<OfferListItem, OfferListItem>() {
@Override @Override
public void updateItem(final OpenOfferListItem item, boolean empty) { public void updateItem(final OfferListItem item, boolean empty) {
super.updateItem(item, empty); super.updateItem(item, empty);
if (item != null) if (item != null)
setText(model.getVolume(item)); setText(model.getVolume(item));
@ -194,14 +194,14 @@ public class OffersView extends ActivatableViewAndModel<GridPane, OffersViewMode
private void setDirectionColumnCellFactory() { private void setDirectionColumnCellFactory() {
directionColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue())); directionColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
directionColumn.setCellFactory( directionColumn.setCellFactory(
new Callback<TableColumn<OpenOfferListItem, OpenOfferListItem>, TableCell<OpenOfferListItem, new Callback<TableColumn<OfferListItem, OfferListItem>, TableCell<OfferListItem,
OpenOfferListItem>>() { OfferListItem>>() {
@Override @Override
public TableCell<OpenOfferListItem, OpenOfferListItem> call( public TableCell<OfferListItem, OfferListItem> call(
TableColumn<OpenOfferListItem, OpenOfferListItem> column) { TableColumn<OfferListItem, OfferListItem> column) {
return new TableCell<OpenOfferListItem, OpenOfferListItem>() { return new TableCell<OfferListItem, OfferListItem>() {
@Override @Override
public void updateItem(final OpenOfferListItem item, boolean empty) { public void updateItem(final OfferListItem item, boolean empty) {
super.updateItem(item, empty); super.updateItem(item, empty);
setText(model.getDirectionLabel(item)); setText(model.getDirectionLabel(item));
} }
@ -213,11 +213,11 @@ public class OffersView extends ActivatableViewAndModel<GridPane, OffersViewMode
private void setRemoveColumnCellFactory() { private void setRemoveColumnCellFactory() {
removeItemColumn.setCellValueFactory((offerListItem) -> new ReadOnlyObjectWrapper<>(offerListItem.getValue())); removeItemColumn.setCellValueFactory((offerListItem) -> new ReadOnlyObjectWrapper<>(offerListItem.getValue()));
removeItemColumn.setCellFactory( removeItemColumn.setCellFactory(
new Callback<TableColumn<OpenOfferListItem, OpenOfferListItem>, TableCell<OpenOfferListItem, OpenOfferListItem>>() { new Callback<TableColumn<OfferListItem, OfferListItem>, TableCell<OfferListItem, OfferListItem>>() {
@Override @Override
public TableCell<OpenOfferListItem, OpenOfferListItem> call(TableColumn<OpenOfferListItem, public TableCell<OfferListItem, OfferListItem> call(TableColumn<OfferListItem,
OpenOfferListItem> directionColumn) { OfferListItem> directionColumn) {
return new TableCell<OpenOfferListItem, OpenOfferListItem>() { return new TableCell<OfferListItem, OfferListItem>() {
final ImageView iconView = new ImageView(); final ImageView iconView = new ImageView();
final Button button = new Button(); final Button button = new Button();
@ -229,11 +229,11 @@ public class OffersView extends ActivatableViewAndModel<GridPane, OffersViewMode
} }
@Override @Override
public void updateItem(final OpenOfferListItem item, boolean empty) { public void updateItem(final OfferListItem item, boolean empty) {
super.updateItem(item, empty); super.updateItem(item, empty);
if (item != null) { if (item != null) {
button.setOnAction(event -> removeOpenOffer(item.getOpenOffer().getOffer())); button.setOnAction(event -> removeOpenOffer(item.getOffer()));
setGraphic(button); setGraphic(button);
} }
else { else {

View File

@ -56,32 +56,32 @@ class OffersViewModel extends ActivatableWithDataModel<OffersDataModel> implemen
}); });
} }
public ObservableList<OpenOfferListItem> getList() { public ObservableList<OfferListItem> getList() {
return dataModel.getList(); return dataModel.getList();
} }
String getTradeId(OpenOfferListItem item) { String getTradeId(OfferListItem item) {
return item.getOpenOffer().getId(); return item.getOffer().getId();
} }
String getAmount(OpenOfferListItem item) { String getAmount(OfferListItem item) {
return (item != null) ? formatter.formatAmountWithMinAmount(item.getOpenOffer().getOffer()) : ""; return (item != null) ? formatter.formatAmountWithMinAmount(item.getOffer()) : "";
} }
String getPrice(OpenOfferListItem item) { String getPrice(OfferListItem item) {
return (item != null) ? formatter.formatFiat(item.getOpenOffer().getOffer().getPrice()) : ""; return (item != null) ? formatter.formatFiat(item.getOffer().getPrice()) : "";
} }
String getVolume(OpenOfferListItem item) { String getVolume(OfferListItem item) {
return (item != null) ? formatter.formatVolumeWithMinVolume(item.getOpenOffer().getOffer()) : ""; return (item != null) ? formatter.formatVolumeWithMinVolume(item.getOffer()) : "";
} }
String getDirectionLabel(OpenOfferListItem item) { String getDirectionLabel(OfferListItem item) {
return (item != null) ? formatter.formatDirection(dataModel.getDirection(item.getOpenOffer())) : ""; return (item != null) ? formatter.formatDirection(dataModel.getDirection(item.getOffer())) : "";
} }
String getDate(OpenOfferListItem item) { String getDate(OfferListItem item) {
return formatter.formatDateTime(item.getOpenOffer().getOffer().getCreationDate()); return formatter.formatDateTime(item.getOffer().getCreationDate());
} }
} }

View File

@ -277,8 +277,7 @@ class PendingTradesDataModel implements Activatable, DataModel {
log.trace("updateConfidence getTrade().getState() " + getTrade().getState()); log.trace("updateConfidence getTrade().getState() " + getTrade().getState());
if (confidence != null && if (confidence != null &&
confidence.getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING confidence.getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING
&& (getTrade().getState() == Trade.State.DEPOSIT_PUBLISHED || && getTrade().getState() == Trade.State.DEPOSIT_PUBLISHED) {
getTrade().getState() == Trade.State.OFFERER_ACCEPTED)) {
// only set it once when actual state is DEPOSIT_PUBLISHED, and remove listener afterwards // only set it once when actual state is DEPOSIT_PUBLISHED, and remove listener afterwards
getTrade().setState(Trade.State.DEPOSIT_CONFIRMED); getTrade().setState(Trade.State.DEPOSIT_CONFIRMED);
walletService.removeTxConfidenceListener(txConfidenceListener); walletService.removeTxConfidenceListener(txConfidenceListener);

View File

@ -217,8 +217,6 @@ class PendingTradesViewModel extends ActivatableWithDataModel<PendingTradesDataM
log.trace("tradeState " + tradeState); log.trace("tradeState " + tradeState);
if (tradeState != null) { if (tradeState != null) {
switch (tradeState) { switch (tradeState) {
// TODO Check why OFFERER_ACCEPTED can happen, refactor state handling
case OFFERER_ACCEPTED:
case DEPOSIT_PUBLISHED: case DEPOSIT_PUBLISHED:
state.set(dataModel.isOfferer() ? State.OFFERER_BUYER_WAIT_TX_CONF : State.TAKER_SELLER_WAIT_TX_CONF); state.set(dataModel.isOfferer() ? State.OFFERER_BUYER_WAIT_TX_CONF : State.TAKER_SELLER_WAIT_TX_CONF);
break; break;

View File

@ -17,6 +17,8 @@
package io.bitsquare.gui.main.trade.offerbook; package io.bitsquare.gui.main.trade.offerbook;
import io.bitsquare.common.viewfx.view.ActivatableViewAndModel;
import io.bitsquare.common.viewfx.view.FxmlView;
import io.bitsquare.gui.Navigation; import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.OverlayManager; import io.bitsquare.gui.OverlayManager;
import io.bitsquare.gui.components.InputTextField; import io.bitsquare.gui.components.InputTextField;
@ -33,8 +35,6 @@ import io.bitsquare.gui.util.validation.OptionalFiatValidator;
import io.bitsquare.locale.BSResources; import io.bitsquare.locale.BSResources;
import io.bitsquare.offer.Direction; import io.bitsquare.offer.Direction;
import io.bitsquare.offer.Offer; import io.bitsquare.offer.Offer;
import io.bitsquare.common.viewfx.view.ActivatableViewAndModel;
import io.bitsquare.common.viewfx.view.FxmlView;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -220,10 +220,6 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
private void takeOffer(Offer offer) { private void takeOffer(Offer offer) {
if (model.isRegistered()) { if (model.isRegistered()) {
if (offer.getDirection() == Direction.BUY) { if (offer.getDirection() == Direction.BUY) {
// reset available state
if (offer.getState() != Offer.State.REMOVED)
offer.setState(Offer.State.UNKNOWN);
offerActionHandler.takeOffer(model.getAmountAsCoin(), model.getPriceAsCoin(), offer); offerActionHandler.takeOffer(model.getAmountAsCoin(), model.getPriceAsCoin(), offer);
} }
else { else {
@ -527,7 +523,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
iconView.setId("image-offer_state_available"); iconView.setId("image-offer_state_available");
break; break;
case OFFERER_OFFLINE: case OFFERER_OFFLINE:
case NOT_AVAILABLE: case RESERVED:
case FAULT: case FAULT:
case REMOVED: case REMOVED:
iconView.setId("image-offer_state_not_available"); iconView.setId("image-offer_state_not_available");

View File

@ -25,8 +25,8 @@ import io.bitsquare.common.viewfx.model.Activatable;
import io.bitsquare.common.viewfx.model.DataModel; import io.bitsquare.common.viewfx.model.DataModel;
import io.bitsquare.offer.Offer; import io.bitsquare.offer.Offer;
import io.bitsquare.persistence.Persistence; import io.bitsquare.persistence.Persistence;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.TradeManager; import io.bitsquare.trade.TradeManager;
import io.bitsquare.trade.handlers.TradeResultHandler;
import io.bitsquare.user.Preferences; import io.bitsquare.user.Preferences;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
@ -128,8 +128,8 @@ class TakeOfferDataModel implements Activatable, DataModel {
tradeManager.checkOfferAvailability(offer); tradeManager.checkOfferAvailability(offer);
} }
Trade takeOffer() { void takeOffer(TradeResultHandler handler) {
return tradeManager.takeOffer(amountAsCoin.get(), offer); tradeManager.requestTakeOffer(amountAsCoin.get(), offer, (trade) -> handler.handleTradeResult(trade));
} }
void calculateVolume() { void calculateVolume() {

View File

@ -26,7 +26,6 @@ import io.bitsquare.gui.util.validation.InputValidator;
import io.bitsquare.locale.BSResources; import io.bitsquare.locale.BSResources;
import io.bitsquare.offer.Direction; import io.bitsquare.offer.Direction;
import io.bitsquare.offer.Offer; import io.bitsquare.offer.Offer;
import io.bitsquare.trade.Trade;
import org.bitcoinj.core.Address; import org.bitcoinj.core.Address;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
@ -152,10 +151,25 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
switch (newValue) { switch (newValue) {
case UNKNOWN: case UNKNOWN:
log.error("Must not happen.");
break; break;
case AVAILABLE: case AVAILABLE:
state.set(State.AMOUNT_SCREEN); state.set(State.AMOUNT_SCREEN);
break; break;
case RESERVED:
if (takeOfferRequested)
errorMessage.set("Take offer request failed because offer is not available anymore. " +
"Maybe another trader has taken the offer in the meantime.");
else
errorMessage.set("You cannot take that offer because the offer was already taken by another trader.");
takeOfferRequested = false;
break;
case REMOVED:
if (!takeOfferRequested)
errorMessage.set("You cannot take that offer because the offer has been removed in the meantime.");
takeOfferRequested = false;
break;
case OFFERER_OFFLINE: case OFFERER_OFFLINE:
if (takeOfferRequested) if (takeOfferRequested)
errorMessage.set("Take offer request failed because offerer is not online anymore."); errorMessage.set("Take offer request failed because offerer is not online anymore.");
@ -163,26 +177,12 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
errorMessage.set("You cannot take that offer because the offerer is offline."); errorMessage.set("You cannot take that offer because the offerer is offline.");
takeOfferRequested = false; takeOfferRequested = false;
break; break;
case NOT_AVAILABLE:
if (takeOfferRequested)
errorMessage.set("Take offer request failed because offer is not available anymore. " +
"Maybe another trader has taken the offer in the meantime.");
else
errorMessage.set("You cannot take that offer because the offer was already taken by another trader.");
takeOfferRequested = false;
break;
case FAULT: case FAULT:
if (takeOfferRequested) if (takeOfferRequested)
errorMessage.set("Take offer request failed."); errorMessage.set("Take offer request failed.");
else else
errorMessage.set("The check for the offer availability failed."); errorMessage.set("The check for the offer availability failed.");
takeOfferRequested = false;
break;
case REMOVED:
if (!takeOfferRequested)
errorMessage.set("You cannot take that offer because the offer has been removed in the meantime.");
takeOfferRequested = false; takeOfferRequested = false;
break; break;
default: default:
@ -207,8 +207,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
isTakeOfferSpinnerVisible.set(true); isTakeOfferSpinnerVisible.set(true);
Trade trade = dataModel.takeOffer(); dataModel.takeOffer((trade) -> {
trade.stateProperty().addListener((ov, oldValue, newValue) -> { trade.stateProperty().addListener((ov, oldValue, newValue) -> {
log.debug("trade state = " + newValue); log.debug("trade state = " + newValue);
String msg = ""; String msg = "";
@ -218,12 +217,6 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
switch (newValue) { switch (newValue) {
case OPEN: case OPEN:
break; break;
case OFFERER_ACCEPTED:
break;
case OFFERER_REJECTED:
errorMessage.set("Your take offer request got rejected. Maybe another trader has taken the offer in the meantime.");
takeOfferRequested = false;
break;
case TAKE_OFFER_FEE_TX_CREATED: case TAKE_OFFER_FEE_TX_CREATED:
break; break;
case DEPOSIT_PUBLISHED: case DEPOSIT_PUBLISHED:
@ -260,6 +253,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
}); });
evaluateState(); evaluateState();
});
} }
void securityDepositInfoDisplayed() { void securityDepositInfoDisplayed() {

View File

@ -18,8 +18,8 @@
package io.bitsquare.offer; package io.bitsquare.offer;
import io.bitsquare.arbitration.Arbitrator; import io.bitsquare.arbitration.Arbitrator;
import io.bitsquare.fiat.FiatAccountType;
import io.bitsquare.btc.Restrictions; import io.bitsquare.btc.Restrictions;
import io.bitsquare.fiat.FiatAccountType;
import io.bitsquare.locale.Country; import io.bitsquare.locale.Country;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
@ -51,21 +51,11 @@ public class Offer implements Serializable {
public enum State { public enum State {
UNKNOWN, UNKNOWN,
OFFERER_OFFLINE,
AVAILABLE, AVAILABLE,
NOT_AVAILABLE, RESERVED,
FAULT, REMOVED,
REMOVED; OFFERER_OFFLINE,
FAULT
private String errorMessage;
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
public String getErrorMessage() {
return errorMessage;
}
} }
// key attributes for lookup // key attributes for lookup
@ -92,9 +82,9 @@ public class Offer implements Serializable {
// Mutable property. Has to be set before offer is save in DHT as it changes the objects hash! // Mutable property. Has to be set before offer is save in DHT as it changes the objects hash!
private String offerFeePaymentTxID; private String offerFeePaymentTxID;
private State state;
// Those state properties are transient and only used at runtime! // Those state properties are transient and only used at runtime!
private transient State state;
// don't access directly as it might be null; use getStateProperty() which creates an object if not instantiated // don't access directly as it might be null; use getStateProperty() which creates an object if not instantiated
private transient ObjectProperty<State> stateProperty; private transient ObjectProperty<State> stateProperty;

View File

@ -1,78 +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.offer;
import java.io.Serializable;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// Offerer has his own offers wrapped in that OpenOffer object. Taker never has an OpenOffer object.
public class OpenOffer implements Serializable {
private static final long serialVersionUID = -7523483764145982933L;
private static final Logger log = LoggerFactory.getLogger(OpenOffer.class);
///////////////////////////////////////////////////////////////////////////////////////////
// Enum
///////////////////////////////////////////////////////////////////////////////////////////
public static enum State {
OPEN,
OFFER_ACCEPTED
}
private final Offer offer;
private State state;
transient private ObjectProperty<State> _state;
public OpenOffer(Offer offer) {
this.offer = offer;
state = State.OPEN;
}
public Offer getOffer() {
return offer;
}
public String getId() {
return offer.getId();
}
public void setState(State state) {
this.state = state;
stateProperty().set(state);
}
public State getState() {
return state;
}
public ObjectProperty<State> stateProperty() {
if (_state == null)
_state = new SimpleObjectProperty<>(state);
return _state;
}
}

View File

@ -40,8 +40,6 @@ public class Trade implements Serializable {
public static enum State { public static enum State {
OPEN, OPEN,
OFFERER_ACCEPTED,
OFFERER_REJECTED, /* For taker only*/
TAKE_OFFER_FEE_PUBLISH_FAILED, TAKE_OFFER_FEE_PUBLISH_FAILED,
TAKE_OFFER_FEE_TX_CREATED, TAKE_OFFER_FEE_TX_CREATED,
DEPOSIT_PUBLISHED, DEPOSIT_PUBLISHED,

View File

@ -28,8 +28,8 @@ import io.bitsquare.network.Peer;
import io.bitsquare.offer.Direction; import io.bitsquare.offer.Direction;
import io.bitsquare.offer.Offer; import io.bitsquare.offer.Offer;
import io.bitsquare.offer.OfferBookService; import io.bitsquare.offer.OfferBookService;
import io.bitsquare.offer.OpenOffer;
import io.bitsquare.persistence.Persistence; import io.bitsquare.persistence.Persistence;
import io.bitsquare.trade.handlers.TradeResultHandler;
import io.bitsquare.trade.handlers.TransactionResultHandler; import io.bitsquare.trade.handlers.TransactionResultHandler;
import io.bitsquare.trade.listeners.SendMessageListener; import io.bitsquare.trade.listeners.SendMessageListener;
import io.bitsquare.trade.protocol.availability.CheckOfferAvailabilityModel; import io.bitsquare.trade.protocol.availability.CheckOfferAvailabilityModel;
@ -77,7 +77,7 @@ public class TradeManager {
private final Map<String, BuyerAsOffererProtocol> buyerAcceptsOfferProtocolMap = new HashMap<>(); private final Map<String, BuyerAsOffererProtocol> buyerAcceptsOfferProtocolMap = new HashMap<>();
private final Map<String, CheckOfferAvailabilityProtocol> checkOfferAvailabilityProtocolMap = new HashMap<>(); private final Map<String, CheckOfferAvailabilityProtocol> checkOfferAvailabilityProtocolMap = new HashMap<>();
private final ObservableMap<String, OpenOffer> openOffers = FXCollections.observableHashMap(); private final ObservableMap<String, Offer> openOffers = FXCollections.observableHashMap();
private final ObservableMap<String, Trade> pendingTrades = FXCollections.observableHashMap(); private final ObservableMap<String, Trade> pendingTrades = FXCollections.observableHashMap();
private final ObservableMap<String, Trade> closedTrades = FXCollections.observableHashMap(); private final ObservableMap<String, Trade> closedTrades = FXCollections.observableHashMap();
@ -104,7 +104,7 @@ public class TradeManager {
Object openOffersObject = persistence.read(this, "openOffers"); Object openOffersObject = persistence.read(this, "openOffers");
if (openOffersObject instanceof Map<?, ?>) { if (openOffersObject instanceof Map<?, ?>) {
openOffers.putAll((Map<String, OpenOffer>) openOffersObject); openOffers.putAll((Map<String, Offer>) openOffersObject);
} }
Object pendingTradesObject = persistence.read(this, "pendingTrades"); Object pendingTradesObject = persistence.read(this, "pendingTrades");
@ -122,9 +122,12 @@ public class TradeManager {
// When all services are initialized we create the protocols for our open offers (which will listen for take offer requests) // When all services are initialized we create the protocols for our open offers (which will listen for take offer requests)
public void onAllServicesInitialized() { public void onAllServicesInitialized() {
for (Map.Entry<String, OpenOffer> entry : openOffers.entrySet()) { for (Map.Entry<String, Offer> entry : openOffers.entrySet()) {
createBuyerAcceptsOfferProtocol(entry.getValue()); createBuyerAcceptsOfferProtocol(entry.getValue());
} }
/* for (Map.Entry<String, Trade> entry : pendingTrades.entrySet()) {
createBuyerAcceptsOfferProtocol(entry.getValue().getOffer());
}*/
} }
@ -134,13 +137,13 @@ public class TradeManager {
public void checkOfferAvailability(Offer offer) { public void checkOfferAvailability(Offer offer) {
if (!checkOfferAvailabilityProtocolMap.containsKey(offer.getId())) { if (!checkOfferAvailabilityProtocolMap.containsKey(offer.getId())) {
CheckOfferAvailabilityModel model = new CheckOfferAvailabilityModel( CheckOfferAvailabilityModel model = new CheckOfferAvailabilityModel(
offer, offer,
tradeMessageService, tradeMessageService);
() -> disposeCheckOfferAvailabilityRequest(offer));
CheckOfferAvailabilityProtocol protocol = new CheckOfferAvailabilityProtocol(model); CheckOfferAvailabilityProtocol protocol = new CheckOfferAvailabilityProtocol(model,
() -> disposeCheckOfferAvailabilityRequest(offer),
(errorMessage) -> disposeCheckOfferAvailabilityRequest(offer));
checkOfferAvailabilityProtocolMap.put(offer.getId(), protocol); checkOfferAvailabilityProtocolMap.put(offer.getId(), protocol);
protocol.checkOfferAvailability(); protocol.checkOfferAvailability();
} }
@ -183,8 +186,9 @@ public class TradeManager {
PlaceOfferProtocol placeOfferProtocol = new PlaceOfferProtocol( PlaceOfferProtocol placeOfferProtocol = new PlaceOfferProtocol(
model, model,
(transaction) -> { (transaction) -> {
OpenOffer openOffer = createOpenOffer(offer); openOffers.put(offer.getId(), offer);
createBuyerAcceptsOfferProtocol(openOffer); persistOpenOffers();
createBuyerAcceptsOfferProtocol(offer);
resultHandler.handleResult(transaction); resultHandler.handleResult(transaction);
}, },
(message) -> errorMessageHandler.handleErrorMessage(message) (message) -> errorMessageHandler.handleErrorMessage(message)
@ -197,41 +201,33 @@ public class TradeManager {
removeOpenOffer(offer, resultHandler, errorMessageHandler, true); removeOpenOffer(offer, resultHandler, errorMessageHandler, true);
} }
public Trade takeOffer(Coin amount, Offer offer) { public void requestTakeOffer(Coin amount, Offer offer, TradeResultHandler tradeResultHandler) {
CheckOfferAvailabilityModel model = new CheckOfferAvailabilityModel(
offer,
tradeMessageService);
CheckOfferAvailabilityProtocol protocol = new CheckOfferAvailabilityProtocol(model,
() -> {
disposeCheckOfferAvailabilityRequest(offer);
if (offer.getState() == Offer.State.AVAILABLE) {
Trade trade = takeAvailableOffer(amount, offer, model.getPeer());
tradeResultHandler.handleTradeResult(trade);
}
},
(errorMessage) -> disposeCheckOfferAvailabilityRequest(offer));
checkOfferAvailabilityProtocolMap.put(offer.getId(), protocol);
protocol.checkOfferAvailability();
}
private Trade takeAvailableOffer(Coin amount, Offer offer, Peer peer) {
Trade trade = createTrade(offer); Trade trade = createTrade(offer);
trade.setTradeAmount(amount); trade.setTradeAmount(amount);
offer.stateProperty().addListener((ov, oldValue, newValue) -> {
log.debug("trade state = " + newValue);
switch (newValue) {
case UNKNOWN:
break;
case AVAILABLE:
break;
case OFFERER_OFFLINE:
case NOT_AVAILABLE:
case FAULT:
removeFailedTrade(trade);
break;
case REMOVED:
if (oldValue != Offer.State.AVAILABLE) {
removeFailedTrade(trade);
}
break;
default:
log.error("Unhandled trade state: " + newValue);
break;
}
});
// TODO check
trade.stateProperty().addListener((ov, oldValue, newValue) -> { trade.stateProperty().addListener((ov, oldValue, newValue) -> {
log.debug("trade state = " + newValue); log.debug("trade state = " + newValue);
switch (newValue) { switch (newValue) {
case OPEN: case OPEN:
break; break;
case OFFERER_ACCEPTED:
case TAKE_OFFER_FEE_TX_CREATED: case TAKE_OFFER_FEE_TX_CREATED:
case DEPOSIT_PUBLISHED: case DEPOSIT_PUBLISHED:
case DEPOSIT_CONFIRMED: case DEPOSIT_CONFIRMED:
@ -240,7 +236,6 @@ public class TradeManager {
case PAYOUT_PUBLISHED: case PAYOUT_PUBLISHED:
persistPendingTrades(); persistPendingTrades();
break; break;
case OFFERER_REJECTED:
case MESSAGE_SENDING_FAILED: case MESSAGE_SENDING_FAILED:
case FAULT: case FAULT:
removeFailedTrade(trade); removeFailedTrade(trade);
@ -253,6 +248,7 @@ public class TradeManager {
SellerAsTakerModel model = new SellerAsTakerModel( SellerAsTakerModel model = new SellerAsTakerModel(
trade, trade,
peer,
tradeMessageService, tradeMessageService,
walletService, walletService,
blockChainService, blockChainService,
@ -261,8 +257,7 @@ public class TradeManager {
SellerAsTakerProtocol sellerTakesOfferProtocol = new SellerAsTakerProtocol(model); SellerAsTakerProtocol sellerTakesOfferProtocol = new SellerAsTakerProtocol(model);
sellerAsTakerProtocolMap.put(trade.getId(), sellerTakesOfferProtocol); sellerAsTakerProtocolMap.put(trade.getId(), sellerTakesOfferProtocol);
sellerTakesOfferProtocol.takeAvailableOffer();
sellerTakesOfferProtocol.takeOffer();
return trade; return trade;
} }
@ -325,12 +320,6 @@ public class TradeManager {
// Private // Private
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
private OpenOffer createOpenOffer(Offer offer) {
OpenOffer openOffer = new OpenOffer(offer);
openOffers.put(openOffer.getId(), openOffer);
persistOpenOffers();
return openOffer;
}
private void removeOpenOffer(Offer offer, private void removeOpenOffer(Offer offer,
ResultHandler resultHandler, ResultHandler resultHandler,
@ -340,8 +329,8 @@ public class TradeManager {
offerBookService.removeOffer(offer, offerBookService.removeOffer(offer,
() -> { () -> {
if (openOffers.containsKey(offerId)) { if (openOffers.containsKey(offerId)) {
OpenOffer openOffer = openOffers.remove(offerId); openOffers.remove(offerId);
disposeCheckOfferAvailabilityRequest(openOffer.getOffer()); disposeCheckOfferAvailabilityRequest(offer);
persistOpenOffers(); persistOpenOffers();
if (removeFromBuyerAcceptsOfferProtocolMap && buyerAcceptsOfferProtocolMap.containsKey(offerId)) { if (removeFromBuyerAcceptsOfferProtocolMap && buyerAcceptsOfferProtocolMap.containsKey(offerId)) {
buyerAcceptsOfferProtocolMap.get(offerId).cleanup(); buyerAcceptsOfferProtocolMap.get(offerId).cleanup();
@ -371,50 +360,50 @@ public class TradeManager {
return trade; return trade;
} }
private void createBuyerAcceptsOfferProtocol(OpenOffer openOffer) { private void createBuyerAcceptsOfferProtocol(Offer offer) {
BuyerAsOffererModel model = new BuyerAsOffererModel( BuyerAsOffererModel model = new BuyerAsOffererModel(
openOffer, offer,
tradeMessageService, tradeMessageService,
walletService, walletService,
blockChainService, blockChainService,
signatureService, signatureService,
user); user);
if (pendingTrades.containsKey(openOffer.getId())) Trade trade;
model.setTrade(pendingTrades.get(openOffer.getId())); if (pendingTrades.containsKey(offer.getId())) {
trade = pendingTrades.get(offer.getId());
openOffer.stateProperty().addListener((ov, oldValue, newValue) -> { }
log.debug("openOffer state = " + newValue); else {
switch (newValue) { trade = new Trade(offer);
case OPEN:
break;
case OFFER_ACCEPTED:
removeOpenOffer(openOffer.getOffer(),
() -> log.debug("remove offer was successful"),
(message) -> log.error(message),
false);
Trade trade = model.getTrade();
pendingTrades.put(trade.getId(), trade); pendingTrades.put(trade.getId(), trade);
persistPendingTrades(); persistPendingTrades();
}
model.setTrade(trade);
currentPendingTrade = trade; currentPendingTrade = trade;
// TODO check, remove listener // TODO check, remove listener
trade.stateProperty().addListener((ov2, oldValue2, newValue2) -> { trade.stateProperty().addListener((ov, oldValue, newValue) -> {
log.debug("trade state = " + newValue); log.debug("trade state = " + newValue);
switch (newValue2) { switch (newValue) {
case OPEN: case OPEN:
break; break;
case OFFERER_ACCEPTED: // only taker side
case TAKE_OFFER_FEE_TX_CREATED: case TAKE_OFFER_FEE_TX_CREATED:
persistPendingTrades();
break;
case DEPOSIT_PUBLISHED: case DEPOSIT_PUBLISHED:
removeOpenOffer(offer,
() -> log.debug("remove offer was successful"),
(message) -> log.error(message),
false);
persistPendingTrades();
break;
case DEPOSIT_CONFIRMED: case DEPOSIT_CONFIRMED:
case FIAT_PAYMENT_STARTED: case FIAT_PAYMENT_STARTED:
case FIAT_PAYMENT_RECEIVED: case FIAT_PAYMENT_RECEIVED:
case PAYOUT_PUBLISHED: case PAYOUT_PUBLISHED:
persistPendingTrades(); persistPendingTrades();
break; break;
case OFFERER_REJECTED:
case TAKE_OFFER_FEE_PUBLISH_FAILED: case TAKE_OFFER_FEE_PUBLISH_FAILED:
case MESSAGE_SENDING_FAILED: case MESSAGE_SENDING_FAILED:
case FAULT: case FAULT:
@ -426,15 +415,9 @@ public class TradeManager {
break; break;
} }
}); });
break;
default:
log.error("Unhandled openOffer state: " + newValue);
break;
}
});
BuyerAsOffererProtocol buyerAcceptsOfferProtocol = new BuyerAsOffererProtocol(model); BuyerAsOffererProtocol buyerAcceptsOfferProtocol = new BuyerAsOffererProtocol(model);
buyerAcceptsOfferProtocolMap.put(openOffer.getId(), buyerAcceptsOfferProtocol); buyerAcceptsOfferProtocolMap.put(offer.getId(), buyerAcceptsOfferProtocol);
} }
private void removeFailedTrade(Trade trade) { private void removeFailedTrade(Trade trade) {
@ -478,14 +461,16 @@ public class TradeManager {
boolean isOfferOpen(String offerId) { boolean isOfferOpen(String offerId) {
// Don't use openOffers as the offer gets removed async from DHT, but is added sync to pendingTrades // Don't use openOffers as the offer gets removed async from DHT, but is added sync to pendingTrades
return !pendingTrades.containsKey(offerId) && !closedTrades.containsKey(offerId); return openOffers.containsKey(offerId)
&& (openOffers.get(offerId).getState() == Offer.State.UNKNOWN
|| openOffers.get(offerId).getState() == Offer.State.AVAILABLE);
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Getters // Getters
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public ObservableMap<String, OpenOffer> getOpenOffers() { public ObservableMap<String, Offer> getOpenOffers() {
return openOffers; return openOffers;
} }
@ -507,7 +492,7 @@ public class TradeManager {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
private void persistOpenOffers() { private void persistOpenOffers() {
persistence.write(this, "openOffers", (Map<String, OpenOffer>) new HashMap<>(openOffers)); persistence.write(this, "openOffers", (Map<String, Offer>) new HashMap<>(openOffers));
} }
private void persistPendingTrades() { private void persistPendingTrades() {
@ -517,5 +502,4 @@ public class TradeManager {
private void persistClosedTrades() { private void persistClosedTrades() {
persistence.write(this, "closedTrades", (Map<String, Trade>) new HashMap<>(closedTrades)); persistence.write(this, "closedTrades", (Map<String, Trade>) new HashMap<>(closedTrades));
} }
} }

View File

@ -15,25 +15,11 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>. * along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/ */
package io.bitsquare.trade.protocol.trade.taker.messages; package io.bitsquare.trade.handlers;
import io.bitsquare.trade.protocol.trade.TradeMessage; import io.bitsquare.offer.Offer;
import java.io.Serializable;
public class RequestTakeOfferMessage implements Serializable, TradeMessage {
private static final long serialVersionUID = 4660151440192191798L;
private final String tradeId;
public RequestTakeOfferMessage(String tradeId) {
this.tradeId = tradeId;
}
@Override
public String getTradeId() {
return tradeId;
}
public interface OfferStateResultHandler {
void handleStateResult(Offer.State state);
} }

View File

@ -0,0 +1,25 @@
/*
* 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.handlers;
import io.bitsquare.trade.Trade;
public interface TradeResultHandler {
void handleTradeResult(Trade trade);
}

View File

@ -17,12 +17,11 @@
package io.bitsquare.trade.protocol.availability; package io.bitsquare.trade.protocol.availability;
import io.bitsquare.common.taskrunner.SharedModel;
import io.bitsquare.network.Peer; import io.bitsquare.network.Peer;
import io.bitsquare.offer.Offer; import io.bitsquare.offer.Offer;
import io.bitsquare.trade.TradeMessageService; import io.bitsquare.trade.TradeMessageService;
import io.bitsquare.trade.protocol.trade.OfferMessage; import io.bitsquare.trade.protocol.trade.OfferMessage;
import io.bitsquare.common.handlers.ResultHandler;
import io.bitsquare.common.taskrunner.SharedModel;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -32,15 +31,13 @@ public class CheckOfferAvailabilityModel extends SharedModel {
private final Offer offer; private final Offer offer;
private final TradeMessageService tradeMessageService; private final TradeMessageService tradeMessageService;
private final ResultHandler resultHandler;
private Peer peer; private Peer peer;
private OfferMessage message; private OfferMessage message;
public CheckOfferAvailabilityModel(Offer offer, TradeMessageService tradeMessageService, ResultHandler resultHandler) { public CheckOfferAvailabilityModel(Offer offer, TradeMessageService tradeMessageService) {
this.offer = offer; this.offer = offer;
this.tradeMessageService = tradeMessageService; this.tradeMessageService = tradeMessageService;
this.resultHandler = resultHandler;
} }
// getter/setter // getter/setter
@ -67,8 +64,4 @@ public class CheckOfferAvailabilityModel extends SharedModel {
public OfferMessage getMessage() { public OfferMessage getMessage() {
return message; return message;
} }
public ResultHandler getResultHandler() {
return resultHandler;
}
} }

View File

@ -17,6 +17,8 @@
package io.bitsquare.trade.protocol.availability; package io.bitsquare.trade.protocol.availability;
import io.bitsquare.common.handlers.ErrorMessageHandler;
import io.bitsquare.common.handlers.ResultHandler;
import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.network.Message; import io.bitsquare.network.Message;
import io.bitsquare.network.Peer; import io.bitsquare.network.Peer;
@ -26,8 +28,6 @@ import io.bitsquare.trade.protocol.availability.tasks.GetPeerAddress;
import io.bitsquare.trade.protocol.availability.tasks.ProcessReportOfferAvailabilityMessage; import io.bitsquare.trade.protocol.availability.tasks.ProcessReportOfferAvailabilityMessage;
import io.bitsquare.trade.protocol.availability.tasks.RequestIsOfferAvailable; import io.bitsquare.trade.protocol.availability.tasks.RequestIsOfferAvailable;
import javafx.application.Platform;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -35,6 +35,8 @@ public class CheckOfferAvailabilityProtocol {
private static final Logger log = LoggerFactory.getLogger(CheckOfferAvailabilityProtocol.class); private static final Logger log = LoggerFactory.getLogger(CheckOfferAvailabilityProtocol.class);
private final CheckOfferAvailabilityModel model; private final CheckOfferAvailabilityModel model;
private final ResultHandler resultHandler;
private ErrorMessageHandler errorMessageHandler;
private final MessageHandler messageHandler; private final MessageHandler messageHandler;
private boolean isCanceled; private boolean isCanceled;
@ -45,14 +47,15 @@ public class CheckOfferAvailabilityProtocol {
// Constructor // Constructor
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public CheckOfferAvailabilityProtocol(CheckOfferAvailabilityModel model) { public CheckOfferAvailabilityProtocol(CheckOfferAvailabilityModel model, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
this.model = model; this.model = model;
this.resultHandler = resultHandler;
this.errorMessageHandler = errorMessageHandler;
messageHandler = this::handleMessage; messageHandler = this::handleMessage;
} }
public void cleanup() { public void cleanup() {
// Cannot remove listener in same execution cycle, so we delay it model.getTradeMessageService().removeMessageHandler(messageHandler);
Platform.runLater(() -> model.getTradeMessageService().removeMessageHandler(messageHandler));
} }
@ -101,10 +104,11 @@ public class CheckOfferAvailabilityProtocol {
taskRunner = new TaskRunner<>(model, taskRunner = new TaskRunner<>(model,
() -> { () -> {
log.debug("sequence at handleReportOfferAvailabilityMessage completed"); log.debug("sequence at handleReportOfferAvailabilityMessage completed");
model.getResultHandler().handleResult(); resultHandler.handleResult();
}, },
(errorMessage) -> { (errorMessage) -> {
log.error(errorMessage); log.error(errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
} }
); );
taskRunner.addTasks(ProcessReportOfferAvailabilityMessage.class); taskRunner.addTasks(ProcessReportOfferAvailabilityMessage.class);

View File

@ -17,12 +17,12 @@
package io.bitsquare.trade.protocol.availability.tasks; package io.bitsquare.trade.protocol.availability.tasks;
import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.network.Peer; import io.bitsquare.network.Peer;
import io.bitsquare.offer.Offer; import io.bitsquare.offer.Offer;
import io.bitsquare.trade.listeners.GetPeerAddressListener; import io.bitsquare.trade.listeners.GetPeerAddressListener;
import io.bitsquare.trade.protocol.availability.CheckOfferAvailabilityModel; import io.bitsquare.trade.protocol.availability.CheckOfferAvailabilityModel;
import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -38,11 +38,10 @@ public class GetPeerAddress extends Task<CheckOfferAvailabilityModel> {
@Override @Override
protected void doRun() { protected void doRun() {
try {
model.getTradeMessageService().getPeerAddress(model.getOffer().getMessagePublicKey(), new GetPeerAddressListener() { model.getTradeMessageService().getPeerAddress(model.getOffer().getMessagePublicKey(), new GetPeerAddressListener() {
@Override @Override
public void onResult(Peer peer) { public void onResult(Peer peer) {
log.trace("Found peer: " + peer.toString());
model.setPeer(peer); model.setPeer(peer);
complete(); complete();
@ -50,14 +49,16 @@ public class GetPeerAddress extends Task<CheckOfferAvailabilityModel> {
@Override @Override
public void onFailed() { public void onFailed() {
model.getOffer().setState(Offer.State.OFFERER_OFFLINE);
failed(); failed();
} }
}); });
} } catch (Throwable t) {
model.getOffer().setState(Offer.State.FAULT);
@Override failed(t);
protected void updateStateOnFault() { }
model.getOffer().setState(Offer.State.OFFERER_OFFLINE);
} }
} }

View File

@ -26,7 +26,7 @@ import io.bitsquare.trade.protocol.availability.messages.ReportOfferAvailability
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import static io.bitsquare.util.Validator.nonEmptyStringOf; import static com.google.inject.internal.util.$Preconditions.checkState;
public class ProcessReportOfferAvailabilityMessage extends Task<CheckOfferAvailabilityModel> { public class ProcessReportOfferAvailabilityMessage extends Task<CheckOfferAvailabilityModel> {
private static final Logger log = LoggerFactory.getLogger(ProcessReportOfferAvailabilityMessage.class); private static final Logger log = LoggerFactory.getLogger(ProcessReportOfferAvailabilityMessage.class);
@ -39,13 +39,13 @@ public class ProcessReportOfferAvailabilityMessage extends Task<CheckOfferAvaila
protected void doRun() { protected void doRun() {
try { try {
ReportOfferAvailabilityMessage reportOfferAvailabilityMessage = (ReportOfferAvailabilityMessage) model.getMessage(); ReportOfferAvailabilityMessage reportOfferAvailabilityMessage = (ReportOfferAvailabilityMessage) model.getMessage();
nonEmptyStringOf(reportOfferAvailabilityMessage.getOfferId()); checkState(model.getOffer().getId().equals(reportOfferAvailabilityMessage.getOfferId()));
if (model.getOffer().getState() != Offer.State.REMOVED) { if (model.getOffer().getState() != Offer.State.REMOVED) {
if (reportOfferAvailabilityMessage.isOfferOpen()) if (reportOfferAvailabilityMessage.isOfferOpen())
model.getOffer().setState(Offer.State.AVAILABLE); model.getOffer().setState(Offer.State.AVAILABLE);
else else
model.getOffer().setState(Offer.State.NOT_AVAILABLE); model.getOffer().setState(Offer.State.RESERVED);
} }
complete(); complete();
@ -55,8 +55,4 @@ public class ProcessReportOfferAvailabilityMessage extends Task<CheckOfferAvaila
failed(t); failed(t);
} }
} }
@Override
protected void updateStateOnFault() {
}
} }

View File

@ -57,9 +57,5 @@ public class RequestIsOfferAvailable extends Task<CheckOfferAvailabilityModel> {
failed(t); failed(t);
} }
} }
@Override
protected void updateStateOnFault() {
}
} }

View File

@ -17,12 +17,12 @@
package io.bitsquare.trade.protocol.trade.offerer; package io.bitsquare.trade.protocol.trade.offerer;
import io.bitsquare.fiat.FiatAccount;
import io.bitsquare.btc.BlockChainService; import io.bitsquare.btc.BlockChainService;
import io.bitsquare.btc.WalletService; import io.bitsquare.btc.WalletService;
import io.bitsquare.crypto.SignatureService; import io.bitsquare.crypto.SignatureService;
import io.bitsquare.fiat.FiatAccount;
import io.bitsquare.network.Peer; import io.bitsquare.network.Peer;
import io.bitsquare.offer.OpenOffer; import io.bitsquare.offer.Offer;
import io.bitsquare.trade.Trade; import io.bitsquare.trade.Trade;
import io.bitsquare.trade.TradeMessageService; import io.bitsquare.trade.TradeMessageService;
import io.bitsquare.trade.protocol.trade.OfferSharedModel; import io.bitsquare.trade.protocol.trade.OfferSharedModel;
@ -44,9 +44,6 @@ public class BuyerAsOffererModel extends OfferSharedModel {
private static final Logger log = LoggerFactory.getLogger(BuyerAsOffererModel.class); private static final Logger log = LoggerFactory.getLogger(BuyerAsOffererModel.class);
// provided
private final OpenOffer openOffer;
// derived // derived
private final byte[] offererPubKey; private final byte[] offererPubKey;
@ -78,19 +75,18 @@ public class BuyerAsOffererModel extends OfferSharedModel {
// Constructor // Constructor
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public BuyerAsOffererModel(OpenOffer openOffer, public BuyerAsOffererModel(Offer offer,
TradeMessageService tradeMessageService, TradeMessageService tradeMessageService,
WalletService walletService, WalletService walletService,
BlockChainService blockChainService, BlockChainService blockChainService,
SignatureService signatureService, SignatureService signatureService,
User user) { User user) {
super(openOffer.getOffer(), super(offer,
tradeMessageService, tradeMessageService,
walletService, walletService,
blockChainService, blockChainService,
signatureService, signatureService,
user); user);
this.openOffer = openOffer;
offererPubKey = getAddressEntry().getPubKey(); offererPubKey = getAddressEntry().getPubKey();
} }
@ -112,10 +108,6 @@ public class BuyerAsOffererModel extends OfferSharedModel {
this.offererOutputs = offererOutputs; this.offererOutputs = offererOutputs;
} }
public OpenOffer getOpenOffer() {
return openOffer;
}
public Peer getTaker() { public Peer getTaker() {
return taker; return taker;
} }

View File

@ -24,11 +24,9 @@ import io.bitsquare.trade.handlers.MessageHandler;
import io.bitsquare.trade.protocol.trade.TradeMessage; import io.bitsquare.trade.protocol.trade.TradeMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.GetOffererDepositTxInputs; import io.bitsquare.trade.protocol.trade.offerer.tasks.GetOffererDepositTxInputs;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessPayoutTxPublishedMessage; import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessPayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessRequestOffererPublishDepositTxMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessRequestTakeOfferMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessRequestDepositTxInputsMessage; import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessRequestDepositTxInputsMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessRequestOffererPublishDepositTxMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.RequestDepositPayment; import io.bitsquare.trade.protocol.trade.offerer.tasks.RequestDepositPayment;
import io.bitsquare.trade.protocol.trade.offerer.tasks.RespondToTakeOfferRequest;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SendBankTransferStartedMessage; import io.bitsquare.trade.protocol.trade.offerer.tasks.SendBankTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SendDepositTxIdToTaker; import io.bitsquare.trade.protocol.trade.offerer.tasks.SendDepositTxIdToTaker;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SetupListenerForBlockChainConfirmation; import io.bitsquare.trade.protocol.trade.offerer.tasks.SetupListenerForBlockChainConfirmation;
@ -38,9 +36,8 @@ import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyAndSignContract;
import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyTakeOfferFeePayment; import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyTakeOfferFeePayment;
import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyTakerAccount; import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyTakerAccount;
import io.bitsquare.trade.protocol.trade.taker.messages.PayoutTxPublishedMessage; import io.bitsquare.trade.protocol.trade.taker.messages.PayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.taker.messages.RequestOffererPublishDepositTxMessage;
import io.bitsquare.trade.protocol.trade.taker.messages.RequestTakeOfferMessage;
import io.bitsquare.trade.protocol.trade.taker.messages.RequestDepositTxInputsMessage; import io.bitsquare.trade.protocol.trade.taker.messages.RequestDepositTxInputsMessage;
import io.bitsquare.trade.protocol.trade.taker.messages.RequestOffererPublishDepositTxMessage;
import org.bitcoinj.core.Transaction; import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionConfidence; import org.bitcoinj.core.TransactionConfidence;
@ -53,7 +50,6 @@ import org.slf4j.LoggerFactory;
import static io.bitsquare.util.Validator.nonEmptyStringOf; import static io.bitsquare.util.Validator.nonEmptyStringOf;
public class BuyerAsOffererProtocol { public class BuyerAsOffererProtocol {
private static final Logger log = LoggerFactory.getLogger(BuyerAsOffererProtocol.class); private static final Logger log = LoggerFactory.getLogger(BuyerAsOffererProtocol.class);
private final BuyerAsOffererModel model; private final BuyerAsOffererModel model;
@ -84,27 +80,9 @@ public class BuyerAsOffererProtocol {
// Incoming message handling // Incoming message handling
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
private void handleRequestTakeOfferMessage(RequestTakeOfferMessage tradeMessage, Peer peer) { private void handleRequestDepositTxInputsMessage(RequestDepositTxInputsMessage tradeMessage, Peer taker) {
model.setTradeMessage(tradeMessage);
model.setTaker(peer);
BuyerAsOffererTaskRunner<BuyerAsOffererModel> taskRunner = new BuyerAsOffererTaskRunner<>(model,
() -> {
log.debug("sequence at handleRequestTakeOfferMessage completed");
},
(errorMessage) -> {
log.error(errorMessage);
}
);
taskRunner.addTasks(
ProcessRequestTakeOfferMessage.class,
RespondToTakeOfferRequest.class
);
taskRunner.run();
}
private void handleRequestDepositTxInputsMessage(RequestDepositTxInputsMessage tradeMessage) {
model.setTradeMessage(tradeMessage); model.setTradeMessage(tradeMessage);
model.setTaker(taker);
BuyerAsOffererTaskRunner<BuyerAsOffererModel> taskRunner = new BuyerAsOffererTaskRunner<>(model, BuyerAsOffererTaskRunner<BuyerAsOffererModel> taskRunner = new BuyerAsOffererTaskRunner<>(model,
() -> { () -> {
@ -213,11 +191,8 @@ public class BuyerAsOffererProtocol {
nonEmptyStringOf(tradeMessage.getTradeId()); nonEmptyStringOf(tradeMessage.getTradeId());
if (tradeMessage.getTradeId().equals(model.getOffer().getId())) { if (tradeMessage.getTradeId().equals(model.getOffer().getId())) {
if (tradeMessage instanceof RequestTakeOfferMessage) { if (tradeMessage instanceof RequestDepositTxInputsMessage) {
handleRequestTakeOfferMessage((RequestTakeOfferMessage) tradeMessage, peer); handleRequestDepositTxInputsMessage((RequestDepositTxInputsMessage) tradeMessage, peer);
}
else if (tradeMessage instanceof RequestDepositTxInputsMessage) {
handleRequestDepositTxInputsMessage((RequestDepositTxInputsMessage) tradeMessage);
} }
else if (tradeMessage instanceof RequestOffererPublishDepositTxMessage) { else if (tradeMessage instanceof RequestOffererPublishDepositTxMessage) {

View File

@ -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.trade.offerer.messages;
import io.bitsquare.trade.protocol.trade.TradeMessage;
import java.io.Serializable;
public class RespondToTakeOfferRequestMessage implements Serializable, TradeMessage {
private static final long serialVersionUID = 6177387534087739018L;
private final String tradeId;
private final boolean offerIsAvailable;
public RespondToTakeOfferRequestMessage(String tradeId, boolean offerIsAvailable) {
this.tradeId = tradeId;
this.offerIsAvailable = offerIsAvailable;
}
@Override
public String getTradeId() {
return tradeId;
}
public boolean isOfferIsAvailable() {
return offerIsAvailable;
}
}

View File

@ -1,51 +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.trade.offerer.tasks;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererModel;
import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static io.bitsquare.util.Validator.checkTradeId;
public class ProcessRequestTakeOfferMessage extends Task<BuyerAsOffererModel> {
private static final Logger log = LoggerFactory.getLogger(ProcessRequestTakeOfferMessage.class);
public ProcessRequestTakeOfferMessage(TaskRunner taskHandler, BuyerAsOffererModel model) {
super(taskHandler, model);
}
@Override
protected void doRun() {
try {
checkTradeId(model.getOffer().getId(), model.getTradeMessage());
complete();
} catch (Throwable t) {
failed(t);
}
}
@Override
protected void updateStateOnFault() {
// do nothing
}
}

View File

@ -1,73 +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.trade.offerer.tasks;
import io.bitsquare.offer.OpenOffer;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.listeners.SendMessageListener;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererModel;
import io.bitsquare.trade.protocol.trade.offerer.messages.RespondToTakeOfferRequestMessage;
import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RespondToTakeOfferRequest extends Task<BuyerAsOffererModel> {
private static final Logger log = LoggerFactory.getLogger(RespondToTakeOfferRequest.class);
private boolean offerIsAvailable;
public RespondToTakeOfferRequest(TaskRunner taskHandler, BuyerAsOffererModel model) {
super(taskHandler, model);
}
@Override
protected void doRun() {
offerIsAvailable = model.getOpenOffer().getState() == OpenOffer.State.OPEN;
if (offerIsAvailable) {
Trade trade = new Trade(model.getOpenOffer().getOffer());
model.setTrade(trade);
model.getOpenOffer().setState(OpenOffer.State.OFFER_ACCEPTED);
}
else {
log.info("Received take offer request but the offer not marked as open anymore.");
}
RespondToTakeOfferRequestMessage tradeMessage = new RespondToTakeOfferRequestMessage(model.getOpenOffer().getId(), offerIsAvailable);
model.getTradeMessageService().sendMessage(model.getTaker(), tradeMessage, new SendMessageListener() {
@Override
public void handleResult() {
complete();
}
@Override
public void handleFault() {
failed();
}
});
}
@Override
protected void updateStateOnFault() {
if (offerIsAvailable && model.getOpenOffer().getState() == OpenOffer.State.OFFER_ACCEPTED) {
model.setTrade(null);
model.getOpenOffer().setState(OpenOffer.State.OPEN);
}
}
}

View File

@ -42,13 +42,12 @@ public class SellerAsTakerModel extends OfferSharedModel {
// provided // provided
private final Trade trade; private final Trade trade;
private final Peer offerer;
// derived // derived
private final byte[] takerPubKey; private final byte[] takerPubKey;
// written/read by task // written/read by task
private Peer offerer;
private Transaction depositTx; private Transaction depositTx;
private Transaction payoutTx; private Transaction payoutTx;
private Coin takerPayoutAmount; private Coin takerPayoutAmount;
@ -67,6 +66,7 @@ public class SellerAsTakerModel extends OfferSharedModel {
private Transaction takeOfferFeeTx; private Transaction takeOfferFeeTx;
public SellerAsTakerModel(Trade trade, public SellerAsTakerModel(Trade trade,
Peer offerer,
TradeMessageService tradeMessageService, TradeMessageService tradeMessageService,
WalletService walletService, WalletService walletService,
BlockChainService blockChainService, BlockChainService blockChainService,
@ -80,6 +80,7 @@ public class SellerAsTakerModel extends OfferSharedModel {
user); user);
this.trade = trade; this.trade = trade;
this.offerer = offerer;
takerPubKey = getAddressEntry().getPubKey(); takerPubKey = getAddressEntry().getPubKey();
} }
@ -116,10 +117,6 @@ public class SellerAsTakerModel extends OfferSharedModel {
return offerer; return offerer;
} }
public void setOfferer(Peer offerer) {
this.offerer = offerer;
}
public Transaction getPayoutTx() { public Transaction getPayoutTx() {
return payoutTx; return payoutTx;
} }
@ -227,4 +224,5 @@ public class SellerAsTakerModel extends OfferSharedModel {
public Transaction getTakeOfferFeeTx() { public Transaction getTakeOfferFeeTx() {
return takeOfferFeeTx; return takeOfferFeeTx;
} }
} }

View File

@ -19,23 +19,18 @@ package io.bitsquare.trade.protocol.trade.taker;
import io.bitsquare.network.Message; import io.bitsquare.network.Message;
import io.bitsquare.network.Peer; import io.bitsquare.network.Peer;
import io.bitsquare.offer.Offer;
import io.bitsquare.trade.Trade; import io.bitsquare.trade.Trade;
import io.bitsquare.trade.handlers.MessageHandler; import io.bitsquare.trade.handlers.MessageHandler;
import io.bitsquare.trade.protocol.trade.TradeMessage; import io.bitsquare.trade.protocol.trade.TradeMessage;
import io.bitsquare.trade.protocol.trade.offerer.messages.BankTransferStartedMessage; import io.bitsquare.trade.protocol.trade.offerer.messages.BankTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.offerer.messages.DepositTxPublishedMessage; import io.bitsquare.trade.protocol.trade.offerer.messages.DepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.offerer.messages.RequestDepositPaymentMessage; import io.bitsquare.trade.protocol.trade.offerer.messages.RequestDepositPaymentMessage;
import io.bitsquare.trade.protocol.trade.offerer.messages.RespondToTakeOfferRequestMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.BroadcastTakeOfferFeeTx; import io.bitsquare.trade.protocol.trade.taker.tasks.BroadcastTakeOfferFeeTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.CreateAndSignContract; import io.bitsquare.trade.protocol.trade.taker.tasks.CreateAndSignContract;
import io.bitsquare.trade.protocol.trade.taker.tasks.CreateTakeOfferFeeTx; import io.bitsquare.trade.protocol.trade.taker.tasks.CreateTakeOfferFeeTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.GetPeerAddress;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessBankTransferStartedMessage; import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessBankTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessDepositTxPublishedMessage; import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessDepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessRequestDepositPaymentMessage; import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessRequestDepositPaymentMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessRespondToTakeOfferRequestMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.RequestTakeOffer;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendPayoutTxToOfferer; import io.bitsquare.trade.protocol.trade.taker.tasks.SendPayoutTxToOfferer;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendRequestDepositTxInputsMessage; import io.bitsquare.trade.protocol.trade.taker.tasks.SendRequestDepositTxInputsMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendSignedTakerDepositTx; import io.bitsquare.trade.protocol.trade.taker.tasks.SendSignedTakerDepositTx;
@ -63,6 +58,7 @@ public class SellerAsTakerProtocol {
private final MessageHandler messageHandler; private final MessageHandler messageHandler;
private AnimationTimer timeoutTimer; private AnimationTimer timeoutTimer;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Constructor // Constructor
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -70,63 +66,28 @@ public class SellerAsTakerProtocol {
public SellerAsTakerProtocol(SellerAsTakerModel model) { public SellerAsTakerProtocol(SellerAsTakerModel model) {
this.model = model; this.model = model;
messageHandler = this::handleMessage; messageHandler = this::handleMessage;
model.getTradeMessageService().addMessageHandler(messageHandler);
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Called from UI // Public methods
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public void cleanup() { public void cleanup() {
model.getTradeMessageService().removeMessageHandler(messageHandler); model.getTradeMessageService().removeMessageHandler(messageHandler);
} }
public void takeOffer() { public void takeAvailableOffer() {
model.getTradeMessageService().addMessageHandler(messageHandler);
SellerAsTakerTaskRunner<SellerAsTakerModel> taskRunner = new SellerAsTakerTaskRunner<>(model, SellerAsTakerTaskRunner<SellerAsTakerModel> taskRunner = new SellerAsTakerTaskRunner<>(model,
() -> { () -> {
log.debug("taskRunner at takeOffer completed"); log.debug("taskRunner at takeAvailableOffer completed");
startTimeout(animationTimer -> {
Offer.State offerState = Offer.State.FAULT;
offerState.setErrorMessage("We did not get any reply for the take offer request. " +
"Seems that there are connection problems to your peer.");
model.getOffer().setState(Offer.State.FAULT);
return null;
});
}, },
(errorMessage) -> { (errorMessage) -> {
log.error(errorMessage); log.error(errorMessage);
} }
); );
taskRunner.addTasks( taskRunner.addTasks(
GetPeerAddress.class,
RequestTakeOffer.class
);
taskRunner.run();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message handling
///////////////////////////////////////////////////////////////////////////////////////////
private void handleRespondToTakeOfferRequestMessage(RespondToTakeOfferRequestMessage tradeMessage) {
stopTimeout();
model.setTradeMessage(tradeMessage);
SellerAsTakerTaskRunner<SellerAsTakerModel> taskRunner = new SellerAsTakerTaskRunner<>(model,
() -> {
log.debug("taskRunner at handleRespondToTakeOfferRequestMessage completed");
},
(errorMessage) -> {
log.error(errorMessage);
}
);
taskRunner.addTasks(
ProcessRespondToTakeOfferRequestMessage.class,
CreateTakeOfferFeeTx.class, CreateTakeOfferFeeTx.class,
BroadcastTakeOfferFeeTx.class, BroadcastTakeOfferFeeTx.class,
SendRequestDepositTxInputsMessage.class SendRequestDepositTxInputsMessage.class
@ -134,6 +95,10 @@ public class SellerAsTakerProtocol {
taskRunner.run(); taskRunner.run();
} }
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message handling
///////////////////////////////////////////////////////////////////////////////////////////
private void handleRequestDepositPaymentMessage(RequestDepositPaymentMessage tradeMessage) { private void handleRequestDepositPaymentMessage(RequestDepositPaymentMessage tradeMessage) {
model.setTradeMessage(tradeMessage); model.setTradeMessage(tradeMessage);
@ -222,11 +187,8 @@ public class SellerAsTakerProtocol {
TradeMessage tradeMessage = (TradeMessage) message; TradeMessage tradeMessage = (TradeMessage) message;
nonEmptyStringOf(tradeMessage.getTradeId()); nonEmptyStringOf(tradeMessage.getTradeId());
if (tradeMessage.getTradeId().equals(model.getOffer().getId())) { if (tradeMessage.getTradeId().equals(model.getId())) {
if (tradeMessage instanceof RespondToTakeOfferRequestMessage) { if (tradeMessage instanceof RequestDepositPaymentMessage) {
handleRespondToTakeOfferRequestMessage((RespondToTakeOfferRequestMessage) tradeMessage);
}
else if (tradeMessage instanceof RequestDepositPaymentMessage) {
handleRequestDepositPaymentMessage((RequestDepositPaymentMessage) tradeMessage); handleRequestDepositPaymentMessage((RequestDepositPaymentMessage) tradeMessage);
} }
else if (tradeMessage instanceof DepositTxPublishedMessage) { else if (tradeMessage instanceof DepositTxPublishedMessage) {

View File

@ -1,67 +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.trade.taker.tasks;
import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.network.Peer;
import io.bitsquare.offer.Offer;
import io.bitsquare.trade.listeners.GetPeerAddressListener;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class GetPeerAddress extends Task<SellerAsTakerModel> {
private static final Logger log = LoggerFactory.getLogger(GetPeerAddress.class);
public GetPeerAddress(TaskRunner taskHandler, SellerAsTakerModel model) {
super(taskHandler, model);
errorMessage = "DHT lookup for peer address failed. Maybe the offerer was offline for too long time.";
}
@Override
protected void doRun() {
try {
model.getTradeMessageService().getPeerAddress(model.getOffer().getMessagePublicKey(), new GetPeerAddressListener() {
@Override
public void onResult(Peer peer) {
model.setOfferer(peer);
complete();
}
@Override
public void onFailed() {
model.getOffer().setState(Offer.State.OFFERER_OFFLINE);
failed();
}
});
} catch (Throwable t) {
model.getOffer().setState(Offer.State.FAULT);
failed(t);
}
}
@Override
protected void updateStateOnFault() {
}
}

View File

@ -1,67 +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.trade.taker.tasks;
import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.offer.Offer;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.offerer.messages.RespondToTakeOfferRequestMessage;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static io.bitsquare.util.Validator.checkTradeId;
public class ProcessRespondToTakeOfferRequestMessage extends Task<SellerAsTakerModel> {
private static final Logger log = LoggerFactory.getLogger(ProcessRespondToTakeOfferRequestMessage.class);
public ProcessRespondToTakeOfferRequestMessage(TaskRunner taskHandler, SellerAsTakerModel model) {
super(taskHandler, model);
}
@Override
protected void doRun() {
try {
checkTradeId(model.getId(), model.getTradeMessage());
if (((RespondToTakeOfferRequestMessage) model.getTradeMessage()).isOfferIsAvailable()) {
model.getOffer().setState(Offer.State.AVAILABLE);
model.getTrade().setState(Trade.State.OFFERER_ACCEPTED);
complete();
}
else {
model.getOffer().setState(Offer.State.NOT_AVAILABLE);
model.getTrade().setState(Trade.State.OFFERER_REJECTED);
failed("Requested offer rejected because it is not available anymore.");
}
} catch (Throwable t) {
model.getOffer().setState(Offer.State.FAULT);
model.getTrade().setState(Trade.State.FAULT);
failed(t);
}
}
@Override
protected void updateStateOnFault() {
}
}

View File

@ -1,64 +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.trade.taker.tasks;
import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.offer.Offer;
import io.bitsquare.trade.listeners.SendMessageListener;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import io.bitsquare.trade.protocol.trade.taker.messages.RequestTakeOfferMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RequestTakeOffer extends Task<SellerAsTakerModel> {
private static final Logger log = LoggerFactory.getLogger(RequestTakeOffer.class);
public RequestTakeOffer(TaskRunner taskHandler, SellerAsTakerModel model) {
super(taskHandler, model);
}
@Override
protected void doRun() {
try {
model.getTradeMessageService().sendMessage(model.getOfferer(), new RequestTakeOfferMessage(model.getId()),
new SendMessageListener() {
@Override
public void handleResult() {
complete();
}
@Override
public void handleFault() {
model.getOffer().setState(Offer.State.OFFERER_OFFLINE);
failed();
}
});
} catch (Throwable t) {
model.getOffer().setState(Offer.State.FAULT);
failed(t);
}
}
@Override
protected void updateStateOnFault() {
}
}

View File

@ -58,7 +58,7 @@ public class SendRequestDepositTxInputsMessage extends Task<SellerAsTakerModel>
// We try to repeat once and if that fails as well we persist the state for a later retry. // We try to repeat once and if that fails as well we persist the state for a later retry.
if (retryCounter == 0) { if (retryCounter == 0) {
retryCounter++; retryCounter++;
doRun(); // doRun();
} }
else { else {
failed(); failed();

View File

@ -28,8 +28,8 @@ import io.bitsquare.trade.listeners.SendMessageListener;
import java.security.PublicKey; import java.security.PublicKey;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import net.tomp2p.dht.FutureGet; import net.tomp2p.dht.FutureGet;
@ -55,7 +55,7 @@ public class TomP2PTradeMessageService implements TradeMessageService {
private static final Logger log = LoggerFactory.getLogger(TomP2PTradeMessageService.class); private static final Logger log = LoggerFactory.getLogger(TomP2PTradeMessageService.class);
private final TomP2PNode tomP2PNode; private final TomP2PNode tomP2PNode;
private final List<MessageHandler> messageHandlers = new ArrayList<>(); private final List<MessageHandler> messageHandlers = new CopyOnWriteArrayList<>();
private Executor executor; private Executor executor;