Refactor check offer availability

This commit is contained in:
Manfred Karrer 2015-03-12 18:15:33 +01:00
parent 6888eacc24
commit 87539db93d
13 changed files with 320 additions and 302 deletions

@ -134,7 +134,7 @@ class TakeOfferDataModel implements Activatable, DataModel {
offer.getStateProperty().addListener((observable, oldValue, newValue) -> {
offerIsAvailable.set(newValue);
});
tradeManager.onGetOfferAvailableStateRequested(offer);
tradeManager.onCheckOfferAvailability(offer);
}
void takeOffer() {

@ -30,16 +30,16 @@ import io.bitsquare.offer.OfferBookService;
import io.bitsquare.offer.OpenOffer;
import io.bitsquare.persistence.Persistence;
import io.bitsquare.trade.handlers.TransactionResultHandler;
import io.bitsquare.trade.listeners.SendMessageListener;
import io.bitsquare.trade.protocol.offer.CheckOfferAvailabilityModel;
import io.bitsquare.trade.protocol.offer.CheckOfferAvailabilityProtocol;
import io.bitsquare.trade.protocol.offer.messages.ReportOfferAvailabilityMessage;
import io.bitsquare.trade.protocol.offer.messages.RequestIsOfferAvailableMessage;
import io.bitsquare.trade.protocol.placeoffer.PlaceOfferProtocol;
import io.bitsquare.trade.protocol.trade.OfferMessage;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererModel;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererProtocol;
import io.bitsquare.trade.protocol.trade.offerer.messages.IsOfferAvailableResponseMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.IsOfferAvailableResponse;
import io.bitsquare.trade.protocol.trade.taker.RequestIsOfferAvailableProtocol;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerProtocol;
import io.bitsquare.trade.protocol.trade.taker.messages.RequestIsOfferAvailableMessage;
import io.bitsquare.user.User;
import io.bitsquare.util.handlers.ErrorMessageHandler;
import io.bitsquare.util.handlers.ResultHandler;
@ -55,8 +55,6 @@ import javax.inject.Inject;
import javafx.collections.FXCollections;
import javafx.collections.ObservableMap;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -81,7 +79,7 @@ public class TradeManager {
//TODO store TakerAsSellerProtocol in trade
private final Map<String, SellerAsTakerProtocol> takerAsSellerProtocolMap = new HashMap<>();
private final Map<String, BuyerAsOffererProtocol> offererAsBuyerProtocolMap = new HashMap<>();
private final Map<String, RequestIsOfferAvailableProtocol> requestIsOfferAvailableProtocolMap = new HashMap<>();
private final Map<String, CheckOfferAvailabilityProtocol> checkOfferAvailabilityProtocolMap = new HashMap<>();
private final ObservableMap<String, OpenOffer> openOffers = FXCollections.observableHashMap();
private final ObservableMap<String, Trade> pendingTrades = FXCollections.observableHashMap();
@ -124,16 +122,7 @@ public class TradeManager {
closedTrades.putAll((Map<String, Trade>) closedTradesObject);
}
tradeMessageService.addMessageHandler(this::handleNewMessage);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Public Methods
///////////////////////////////////////////////////////////////////////////////////////////
public void cleanup() {
tradeMessageService.removeMessageHandler(this::handleNewMessage);
tradeMessageService.addMessageHandler(this::handleMessage);
}
@ -141,20 +130,23 @@ public class TradeManager {
// Called from UI
///////////////////////////////////////////////////////////////////////////////////////////
public void onGetOfferAvailableStateRequested(Offer offer) {
if (!requestIsOfferAvailableProtocolMap.containsKey(offer.getId())) {
RequestIsOfferAvailableProtocol protocol = new RequestIsOfferAvailableProtocol(offer, tradeMessageService);
requestIsOfferAvailableProtocolMap.put(offer.getId(), protocol);
protocol.start();
public void onCheckOfferAvailability(Offer offer) {
if (!checkOfferAvailabilityProtocolMap.containsKey(offer.getId())) {
CheckOfferAvailabilityModel model = new CheckOfferAvailabilityModel(offer, tradeMessageService, () -> {
});
CheckOfferAvailabilityProtocol protocol = new CheckOfferAvailabilityProtocol(model);
checkOfferAvailabilityProtocolMap.put(offer.getId(), protocol);
protocol.onCheckOfferAvailability();
}
else {
log.warn("requestIsOfferAvailable already called for offer with ID:" + offer.getId());
log.error("onGetOfferAvailableStateRequested already called for offer with ID:" + offer.getId());
}
}
// When closing take offer view, we are not interested in the requestIsOfferAvailable result anymore, so remove from the map
public void onGetOfferAvailableStateRequestCanceled(Offer offer) {
requestIsOfferAvailableProtocolMap.remove(offer.getId());
cleanupCheckOfferAvailabilityProtocolMap(offer);
}
public void onPlaceOfferRequested(String id,
@ -201,7 +193,6 @@ public class TradeManager {
removeOpenOffer(offerId, resultHandler, errorMessageHandler, true);
}
public Trade onTakeOfferRequested(Coin amount, Offer offer) {
Trade trade = createTrade(offer);
trade.setTradeAmount(amount);
@ -263,16 +254,42 @@ public class TradeManager {
closeTrade(trade, false);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Called from Offerbook (DHT)
///////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////
// Called from Offerbook when offer gets removed from DHT
///////////////////////////////////////////////////////////////////////////////////////////
public void onOfferRemovedFromRemoteOfferBook(Offer offer) {
requestIsOfferAvailableProtocolMap.remove(offer.getId());
cleanupCheckOfferAvailabilityProtocolMap(offer);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Process new tradeMessages
///////////////////////////////////////////////////////////////////////////////////////////
// Routes the incoming messages to the responsible protocol
private void handleMessage(Message message, Peer sender) {
if (message instanceof RequestIsOfferAvailableMessage) {
String offerId = ((RequestIsOfferAvailableMessage) message).getOfferId();
checkNotNull(offerId);
ReportOfferAvailabilityMessage reportOfferAvailabilityMessage = new ReportOfferAvailabilityMessage(offerId, isOfferOpen(offerId));
tradeMessageService.sendMessage(sender, reportOfferAvailabilityMessage, new SendMessageListener() {
@Override
public void handleResult() {
log.trace("ReportOfferAvailabilityMessage successfully arrived at peer");
}
@Override
public void handleFault() {
log.warn("Sending ReportOfferAvailabilityMessage failed.");
}
});
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private
///////////////////////////////////////////////////////////////////////////////////////////
@ -291,12 +308,14 @@ public class TradeManager {
offerBookService.removeOffer(openOffers.get(offerId).getOffer(),
() -> {
if (openOffers.containsKey(offerId)) {
openOffers.remove(offerId);
OpenOffer openOffer = openOffers.remove(offerId);
cleanupCheckOfferAvailabilityProtocolMap(openOffer.getOffer());
persistOpenOffers();
if (removeFromOffererAsBuyerProtocolMap && offererAsBuyerProtocolMap.containsKey(offerId)) {
offererAsBuyerProtocolMap.get(offerId).cleanup();
offererAsBuyerProtocolMap.remove(offerId);
}
resultHandler.handleResult();
}
else {
@ -400,7 +419,6 @@ public class TradeManager {
offererAsBuyerProtocolMap.remove(trade.getId());
}
if (!failed) {
closedTrades.put(trade.getId(), trade);
persistClosedTrades();
@ -410,51 +428,19 @@ public class TradeManager {
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// Process new tradeMessages
///////////////////////////////////////////////////////////////////////////////////////////
// TODO remove
// Routes the incoming messages to the responsible protocol
private void handleNewMessage(Message message, Peer sender) {
log.trace("handleNewMessage: message = " + message.getClass().getSimpleName());
log.trace("handleNewMessage: sender = " + sender);
if (message instanceof OfferMessage) {
OfferMessage offerMessage = (OfferMessage) message;
// Before starting any take offer activity we check if the offer is still available.
if (offerMessage instanceof RequestIsOfferAvailableMessage) {
// That message arrives at the offerer and he returns if the offer is still available (if there is no trade already created with that offerId).
String offerId = offerMessage.getOfferId();
checkNotNull(offerId);
boolean isOfferOpen = getTrade(offerId) == null;
// no handling of results or faults needed
IsOfferAvailableResponse.run(sender, tradeMessageService, offerId, isOfferOpen);
}
else if (offerMessage instanceof IsOfferAvailableResponseMessage) {
// That message arrives at the taker in response to a previous requestIsOfferAvailable call.
// It might be that the offer got removed form the offer book, so lets check if its still there.
if (requestIsOfferAvailableProtocolMap.containsKey(offerMessage.getOfferId())) {
RequestIsOfferAvailableProtocol protocol = requestIsOfferAvailableProtocolMap.get(offerMessage.getOfferId());
protocol.handleIsOfferAvailableResponseMessage((IsOfferAvailableResponseMessage) offerMessage);
requestIsOfferAvailableProtocolMap.remove(offerMessage.getOfferId());
}
else {
log.info("Offer might have been removed in the meantime. No protocol found for offer with ID:" + offerMessage.getOfferId());
}
}
else {
log.error("Incoming offerMessage not supported. " + offerMessage);
}
private void cleanupCheckOfferAvailabilityProtocolMap(Offer offer) {
if (checkOfferAvailabilityProtocolMap.containsKey(offer.getId())) {
CheckOfferAvailabilityProtocol protocol = checkOfferAvailabilityProtocolMap.get(offer.getId());
protocol.cancel();
protocol.cleanup();
checkOfferAvailabilityProtocolMap.remove(offer.getId());
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// Setters
///////////////////////////////////////////////////////////////////////////////////////////
public boolean isOfferOpen(String offerId) {
// 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);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters
@ -493,16 +479,4 @@ public class TradeManager {
persistence.write(this, "closedTrades", (Map<String, Trade>) new HashMap<>(closedTrades));
}
@Nullable
public Trade getTrade(String tradeId) {
if (pendingTrades.containsKey(tradeId)) {
return pendingTrades.get(tradeId);
}
else {
return null;
}
}
}
}

@ -0,0 +1,74 @@
/*
* 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.offer;
import io.bitsquare.network.Peer;
import io.bitsquare.offer.Offer;
import io.bitsquare.trade.TradeMessageService;
import io.bitsquare.trade.protocol.trade.OfferMessage;
import io.bitsquare.util.handlers.ResultHandler;
import io.bitsquare.util.tasks.SharedModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CheckOfferAvailabilityModel extends SharedModel {
private static final Logger log = LoggerFactory.getLogger(CheckOfferAvailabilityModel.class);
private final Offer offer;
private final TradeMessageService tradeMessageService;
private final ResultHandler resultHandler;
private Peer peer;
private OfferMessage message;
public CheckOfferAvailabilityModel(Offer offer, TradeMessageService tradeMessageService, ResultHandler resultHandler) {
this.offer = offer;
this.tradeMessageService = tradeMessageService;
this.resultHandler = resultHandler;
}
// getter/setter
public Offer getOffer() {
return offer;
}
public TradeMessageService getTradeMessageService() {
return tradeMessageService;
}
public Peer getPeer() {
return peer;
}
public void setPeer(Peer peer) {
this.peer = peer;
}
public void setMessage(OfferMessage message) {
this.message = message;
}
public OfferMessage getMessage() {
return message;
}
public ResultHandler getResultHandler() {
return resultHandler;
}
}

@ -0,0 +1,102 @@
/*
* 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.offer;
import io.bitsquare.network.Message;
import io.bitsquare.network.Peer;
import io.bitsquare.offer.Offer;
import io.bitsquare.trade.protocol.offer.messages.ReportOfferAvailabilityMessage;
import io.bitsquare.trade.protocol.offer.tasks.GetPeerAddress;
import io.bitsquare.trade.protocol.offer.tasks.RequestIsOfferAvailable;
import io.bitsquare.util.tasks.TaskRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static io.bitsquare.util.Validator.nonEmptyStringOf;
public class CheckOfferAvailabilityProtocol {
private static final Logger log = LoggerFactory.getLogger(CheckOfferAvailabilityProtocol.class);
private CheckOfferAvailabilityModel model;
private boolean isCanceled;
private TaskRunner<CheckOfferAvailabilityModel> sequence;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public CheckOfferAvailabilityProtocol(CheckOfferAvailabilityModel model) {
this.model = model;
}
public void cleanup() {
model.getTradeMessageService().removeMessageHandler(this::handleMessage);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Called from UI
///////////////////////////////////////////////////////////////////////////////////////////
public void onCheckOfferAvailability() {
model.getTradeMessageService().addMessageHandler(this::handleMessage);
sequence = new TaskRunner<>(model,
() -> {
log.debug("sequence at onCheckOfferAvailability completed");
},
(message, throwable) -> {
log.error(message);
}
);
sequence.addTasks(
GetPeerAddress.class,
RequestIsOfferAvailable.class
);
sequence.run();
}
public void cancel() {
isCanceled = true;
sequence.cancel();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message handling
///////////////////////////////////////////////////////////////////////////////////////////
private void handleMessage(Message message, Peer sender) {
if (!isCanceled) {
if (message instanceof ReportOfferAvailabilityMessage) {
ReportOfferAvailabilityMessage reportOfferAvailabilityMessage = (ReportOfferAvailabilityMessage) message;
nonEmptyStringOf(reportOfferAvailabilityMessage.getOfferId());
if (model.getOffer().getState() != Offer.State.OFFER_REMOVED) {
if (reportOfferAvailabilityMessage.isOfferOpen())
model.getOffer().setState(Offer.State.OFFER_AVAILABLE);
else
model.getOffer().setState(Offer.State.OFFER_NOT_AVAILABLE);
}
}
}
model.getResultHandler().handleResult();
}
}

@ -15,18 +15,18 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.offerer.messages;
package io.bitsquare.trade.protocol.offer.messages;
import io.bitsquare.trade.protocol.trade.OfferMessage;
import java.io.Serializable;
public class IsOfferAvailableResponseMessage implements Serializable, OfferMessage {
public class ReportOfferAvailabilityMessage implements Serializable, OfferMessage {
private static final long serialVersionUID = 6177387534187739018L;
private final String offerId;
private final boolean isOfferOpen;
public IsOfferAvailableResponseMessage(String offerId, boolean isOfferOpen) {
public ReportOfferAvailabilityMessage(String offerId, boolean isOfferOpen) {
this.offerId = offerId;
this.isOfferOpen = isOfferOpen;
}

@ -15,7 +15,7 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.taker.messages;
package io.bitsquare.trade.protocol.offer.messages;
import io.bitsquare.trade.protocol.trade.OfferMessage;

@ -0,0 +1,55 @@
/*
* 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.offer.tasks;
import io.bitsquare.network.Peer;
import io.bitsquare.trade.listeners.GetPeerAddressListener;
import io.bitsquare.trade.protocol.offer.CheckOfferAvailabilityModel;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class GetPeerAddress extends Task<CheckOfferAvailabilityModel> {
private static final Logger log = LoggerFactory.getLogger(GetPeerAddress.class);
public GetPeerAddress(TaskRunner taskHandler, CheckOfferAvailabilityModel model) {
super(taskHandler, model);
}
@Override
protected void run() {
model.getTradeMessageService().getPeerAddress(model.getOffer().getMessagePublicKey(), new GetPeerAddressListener() {
@Override
public void onResult(Peer peer) {
log.trace("Found peer: " + peer.toString());
model.setPeer(peer);
complete();
}
@Override
public void onFailed() {
failed("DHT lookup for peer address failed.");
}
});
}
}

@ -15,36 +15,37 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.taker.tasks;
package io.bitsquare.trade.protocol.offer.tasks;
import io.bitsquare.network.Peer;
import io.bitsquare.trade.TradeMessageService;
import io.bitsquare.trade.listeners.SendMessageListener;
import io.bitsquare.trade.protocol.trade.taker.messages.RequestIsOfferAvailableMessage;
import io.bitsquare.util.handlers.ErrorMessageHandler;
import io.bitsquare.trade.protocol.offer.CheckOfferAvailabilityModel;
import io.bitsquare.trade.protocol.offer.messages.RequestIsOfferAvailableMessage;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RequestIsOfferAvailable {
public class RequestIsOfferAvailable extends Task<CheckOfferAvailabilityModel> {
private static final Logger log = LoggerFactory.getLogger(RequestIsOfferAvailable.class);
public static void run(ErrorMessageHandler errorMessageHandler,
Peer peer, TradeMessageService tradeMessageService, String offerId) {
log.trace("Run RequestIsOfferAvailable task");
public RequestIsOfferAvailable(TaskRunner taskHandler, CheckOfferAvailabilityModel model) {
super(taskHandler, model);
}
tradeMessageService.sendMessage(peer, new RequestIsOfferAvailableMessage(offerId),
@Override
protected void run() {
model.getTradeMessageService().sendMessage(model.getPeer(), new RequestIsOfferAvailableMessage(model.getOffer().getId()),
new SendMessageListener() {
@Override
public void handleResult() {
log.trace("RequestIsOfferAvailableMessage successfully arrived at peer");
// nothing to do
complete();
}
@Override
public void handleFault() {
log.error("RequestIsOfferAvailableMessage did not arrive at peer");
errorMessageHandler.handleErrorMessage("RequestIsOfferAvailableMessage did not arrive at peer");
failed("Sending RequestIsOfferAvailableMessage failed.");
}
});
}

@ -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.network.Peer;
import io.bitsquare.trade.TradeMessageService;
import io.bitsquare.trade.listeners.SendMessageListener;
import io.bitsquare.trade.protocol.trade.offerer.messages.IsOfferAvailableResponseMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class IsOfferAvailableResponse {
private static final Logger log = LoggerFactory.getLogger(IsOfferAvailableResponse.class);
public static void run(Peer peer,
TradeMessageService tradeMessageService,
String offerId,
boolean isOfferOpen) {
log.trace("Run RespondToIsOfferAvailable task");
IsOfferAvailableResponseMessage message = new IsOfferAvailableResponseMessage(offerId, isOfferOpen);
tradeMessageService.sendMessage(peer, message, new SendMessageListener() {
@Override
public void handleResult() {
log.trace("RespondToIsOfferAvailableMessage successfully arrived at peer");
// Nothing to do. Taker knows now offer available state.
}
@Override
public void handleFault() {
log.error("RespondToIsOfferAvailableMessage did not arrive at peer");
// Ignore that. Taker might have gone offline
}
});
}
}

@ -1,116 +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;
import io.bitsquare.network.Peer;
import io.bitsquare.offer.Offer;
import io.bitsquare.trade.TradeMessageService;
import io.bitsquare.trade.protocol.trade.offerer.messages.IsOfferAvailableResponseMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.GetPeerAddress;
import io.bitsquare.trade.protocol.trade.taker.tasks.RequestIsOfferAvailable;
import java.security.PublicKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Responsible for the correct execution of the sequence of tasks, message passing to the peer and message processing
* from the peer.
* That class handles the role of the taker as the Bitcoin seller.
* It uses sub tasks to not pollute the main class too much with all the async result/fault handling.
* Any data from incoming messages as well data used to send to the peer need to be validated before further processing.
*/
public class RequestIsOfferAvailableProtocol {
private static final Logger log = LoggerFactory.getLogger(RequestIsOfferAvailableProtocol.class);
// provided data
private final Offer offer;
private final TradeMessageService tradeMessageService;
// derived
private final String offerId;
private final PublicKey offererMessagePublicKey;
// written/read by task
private Peer peer;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public RequestIsOfferAvailableProtocol(Offer offer,
TradeMessageService tradeMessageService) {
this.offer = offer;
this.tradeMessageService = tradeMessageService;
offerId = offer.getId();
offererMessagePublicKey = offer.getMessagePublicKey();
}
public void start() {
getPeerAddress();
}
// 1. GetPeerAddress
// Async
// In case of an error: Don't repeat call for now, maybe in production repeat once.
private void getPeerAddress() {
log.debug("getPeerAddress called");
GetPeerAddress.run(this::onResultGetPeerAddress, this::handleErrorMessage, tradeMessageService, offererMessagePublicKey);
}
/* private void onGetPeerAddressFault(String errorMessage) {
GetPeerAddress.run(this::onResultGetPeerAddress, this::handleErrorMessage, tradeMessageService, offererMessagePublicKey);
}*/
// 2. RequestTakeOffer
// Async
// In case of an error: Don't repeat call for now, maybe in production repeat once.
public void onResultGetPeerAddress(Peer peer) {
log.debug("onResultGetPeerAddress called");
this.peer = peer;
RequestIsOfferAvailable.run(this::handleErrorMessage, peer, tradeMessageService, offerId);
}
/* private void onRequestIsOfferAvailableFault(String errorMessage) {
RequestIsOfferAvailable.run(this::handleErrorMessage, peer, tradeMessageService, offerId);
}*/
// generic
private void handleErrorMessage(String errorMessage) {
offer.setState(Offer.State.OFFER_NOT_AVAILABLE);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer
///////////////////////////////////////////////////////////////////////////////////////////
public void handleIsOfferAvailableResponseMessage(IsOfferAvailableResponseMessage offerMessage) {
if (offer.getState() != Offer.State.OFFER_REMOVED) {
if (offerMessage.isOfferOpen())
offer.setState(Offer.State.OFFER_AVAILABLE);
else
offer.setState(Offer.State.OFFER_NOT_AVAILABLE);
}
}
}

@ -47,7 +47,6 @@ import org.slf4j.LoggerFactory;
import static io.bitsquare.util.Validator.nonEmptyStringOf;
public class SellerAsTakerProtocol {
private static final Logger log = LoggerFactory.getLogger(SellerAsTakerProtocol.class);

@ -18,15 +18,11 @@
package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.network.Peer;
import io.bitsquare.trade.TradeMessageService;
import io.bitsquare.trade.listeners.GetPeerAddressListener;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import io.bitsquare.util.handlers.ErrorMessageHandler;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
import java.security.PublicKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -49,32 +45,9 @@ public class GetPeerAddress extends Task<SellerAsTakerModel> {
@Override
public void onFailed() {
failed("DHT lookup for peer address failed.", null);
failed("DHT lookup for peer address failed.");
}
});
}
public static void run(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler,
TradeMessageService tradeMessageService, PublicKey messagePublicKey) {
log.trace("Run GetPeerAddress task");
tradeMessageService.getPeerAddress(messagePublicKey, new GetPeerAddressListener() {
@Override
public void onResult(Peer peer) {
log.trace("Received peer = " + peer.toString());
resultHandler.onResult(peer);
}
@Override
public void onFailed() {
log.error("DHT lookup for peer address failed.");
errorMessageHandler.handleErrorMessage("DHT lookup for peer address failed.");
}
});
}
public interface ResultHandler {
void onResult(Peer peer);
}
}

@ -41,6 +41,8 @@ public class TaskRunner<T extends SharedModel> {
private Class<? extends Task> currentTask;
private Class<? extends Task> previousTask;
private boolean isCanceled;
public TaskRunner(T sharedModel, ResultHandler resultHandler, FaultHandler faultHandler) {
this.sharedModel = sharedModel;
this.resultHandler = resultHandler;
@ -56,7 +58,7 @@ public class TaskRunner<T extends SharedModel> {
}
protected void next() {
if (!failed) {
if (!failed && !isCanceled) {
if (tasks.size() > 0) {
try {
setCurrentTask(tasks.poll());
@ -74,6 +76,10 @@ public class TaskRunner<T extends SharedModel> {
}
}
public void cancel() {
isCanceled = true;
}
protected void setPreviousTask(Class<? extends Task> task) {
previousTask = task;
}
@ -103,4 +109,5 @@ public class TaskRunner<T extends SharedModel> {
failed = true;
faultHandler.handleFault(message, throwable);
}
}