Make rpc GetOfferCategory service work for my+avail offers

There are some use cases where the CLI needs to know what kind of offer
is being acted on before the request is made, For example:

There are differences between a BsqSwap 'takeoffer'request, and a v1
'takeoffer' request.

A BsqSwap offer cannot be edited by an 'editoffer' request, and an
attempt should be blocked by the CLI.

- Append isMyOffer GetOfferCategoryRequest rpc msg def.

- Adjust daemon.grpc services for new boolean GetOfferCategoryRequest param.

- Adjust core.api for new boolean GetOfferCategoryRequest param.

- Add validation check in core.api EditOfferValidator to block attempt to
  edit a BsqSwap offer.

- Refactor CoreOffersService get*offer(id) methods to optionally throw
  excpetions.
This commit is contained in:
ghubstan 2021-11-27 14:01:14 -03:00
parent 05d1916ae9
commit 64f228d872
No known key found for this signature in database
GPG Key ID: E35592D6800A861E
6 changed files with 82 additions and 53 deletions

View File

@ -120,16 +120,16 @@ public class CoreApi {
// Offers
///////////////////////////////////////////////////////////////////////////////////////////
public boolean isAvailableFiatOffer(String id) {
return coreOffersService.isAvailableFiatOffer(id);
public boolean isFiatOffer(String id, boolean isMyOffer) {
return coreOffersService.isFiatOffer(id, isMyOffer);
}
public boolean isAvailableAltcoinOffer(String id) {
return coreOffersService.isAvailableAltcoinOffer(id);
public boolean isAltcoinOffer(String id, boolean isMyOffer) {
return coreOffersService.isAltcoinOffer(id, isMyOffer);
}
public boolean isAvailableBsqSwapOffer(String id) {
return coreOffersService.isAvailableBsqSwapOffer(id);
public boolean isBsqSwapOffer(String id, boolean isMyOffer) {
return coreOffersService.isBsqSwapOffer(id, isMyOffer);
}
public Offer getBsqSwapOffer(String id) {

View File

@ -48,6 +48,8 @@ import java.math.BigDecimal;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@ -61,8 +63,6 @@ import static bisq.core.locale.CurrencyUtil.isCryptoCurrency;
import static bisq.core.offer.Offer.State;
import static bisq.core.offer.OfferDirection.BUY;
import static bisq.core.offer.OfferUtil.getRandomOfferId;
import static bisq.core.offer.OfferUtil.isAltcoinOffer;
import static bisq.core.offer.OfferUtil.isFiatOffer;
import static bisq.core.offer.OpenOffer.State.AVAILABLE;
import static bisq.core.offer.OpenOffer.State.DEACTIVATED;
import static bisq.core.payment.PaymentAccountUtil.isPaymentAccountValidForOffer;
@ -81,6 +81,9 @@ class CoreOffersService {
private final Supplier<Comparator<OpenOffer>> openOfferPriceComparator = () ->
comparing(openOffer -> openOffer.getOffer().getPrice());
private final BiFunction<String, Boolean, Offer> toOfferWithId = (id, isMyOffer) ->
isMyOffer ? getMyOffer(id).getOffer() : getOffer(id);
private final CoreContext coreContext;
private final KeyRing keyRing;
// Dependencies on core api services in this package must be kept to an absolute
@ -121,63 +124,48 @@ class CoreOffersService {
this.user = user;
}
boolean isAvailableFiatOffer(String id) {
return isFiatOffer(getOffer(id));
boolean isFiatOffer(String id, boolean isMyOffer) {
var offer = toOfferWithId.apply(id, isMyOffer);
return OfferUtil.isFiatOffer(offer);
}
boolean isAvailableAltcoinOffer(String id) {
return isAltcoinOffer(getOffer(id));
boolean isAltcoinOffer(String id, boolean isMyOffer) {
var offer = toOfferWithId.apply(id, isMyOffer);
return OfferUtil.isAltcoinOffer(offer);
}
boolean isAvailableBsqSwapOffer(String id) {
var offer = getOffer(id);
boolean isBsqSwapOffer(String id, boolean isMyOffer) {
var offer = toOfferWithId.apply(id, isMyOffer);
return offer.isBsqSwapOffer();
}
Offer getBsqSwapOffer(String id) {
return offerBookService.getOffers().stream()
.filter(o -> o.getId().equals(id))
.filter(o -> !o.isMyOffer(keyRing))
.filter(o -> offerFilterService.canTakeOffer(o, coreContext.isApiUser()).isValid())
.filter(o -> o.isBsqSwapOffer())
.findAny().orElseThrow(() ->
new IllegalStateException(format("offer with id '%s' not found", id)));
}
Offer getOffer(String id) {
return offerBookService.getOffers().stream()
.filter(o -> o.getId().equals(id))
.filter(o -> !o.isMyOffer(keyRing))
.filter(o -> offerFilterService.canTakeOffer(o, coreContext.isApiUser()).isValid())
.findAny().orElseThrow(() ->
new IllegalStateException(format("offer with id '%s' not found", id)));
return findAvailableOffer(id).orElseThrow(() ->
new IllegalStateException(format("offer with id '%s' not found", id)));
}
OpenOffer getMyOffer(String id) {
return openOfferManager.getObservableList().stream()
.filter(o -> o.getId().equals(id))
.filter(o -> o.getOffer().isMyOffer(keyRing))
.findAny().orElseThrow(() ->
new IllegalStateException(format("offer with id '%s' not found", id)));
return findMyOpenOffer(id).orElseThrow(() ->
new IllegalStateException(format("offer with id '%s' not found", id)));
}
Offer getBsqSwapOffer(String id) {
return findAvailableBsqSwapOffer(id).orElseThrow(() ->
new IllegalStateException(format("offer with id '%s' not found", id)));
}
Offer getMyBsqSwapOffer(String id) {
return offerBookService.getOffers().stream()
.filter(o -> o.getId().equals(id))
.filter(o -> o.isMyOffer(keyRing))
.filter(o -> o.isBsqSwapOffer())
.findAny().orElseThrow(() ->
new IllegalStateException(format("offer with id '%s' not found", id)));
return findMyBsqSwapOffer(id).orElseThrow(() ->
new IllegalStateException(format("offer with id '%s' not found", id)));
}
List<Offer> getBsqSwapOffers(String direction) {
var offers = offerBookService.getOffers().stream()
return offerBookService.getOffers().stream()
.filter(o -> !o.isMyOffer(keyRing))
.filter(o -> o.getDirection().name().equalsIgnoreCase(direction))
.filter(o -> o.isBsqSwapOffer())
.filter(Offer::isBsqSwapOffer)
.sorted(priceComparator(direction))
.collect(Collectors.toList());
return offers;
}
List<Offer> getOffers(String direction, String currencyCode) {
@ -198,13 +186,12 @@ class CoreOffersService {
}
List<Offer> getMyBsqSwapOffers(String direction) {
var offers = offerBookService.getOffers().stream()
return offerBookService.getOffers().stream()
.filter(o -> o.isMyOffer(keyRing))
.filter(o -> o.getDirection().name().equalsIgnoreCase(direction))
.filter(Offer::isBsqSwapOffer)
.sorted(priceComparator(direction))
.collect(Collectors.toList());
return offers;
}
OpenOffer getMyOpenBsqSwapOffer(String id) {
@ -393,6 +380,38 @@ class CoreOffersService {
throw new IllegalStateException(offer.getErrorMessage());
}
private Optional<Offer> findAvailableBsqSwapOffer(String id) {
return offerBookService.getOffers().stream()
.filter(o -> o.getId().equals(id))
.filter(o -> !o.isMyOffer(keyRing))
.filter(o -> offerFilterService.canTakeOffer(o, coreContext.isApiUser()).isValid())
.filter(Offer::isBsqSwapOffer)
.findAny();
}
private Optional<Offer> findMyBsqSwapOffer(String id) {
return offerBookService.getOffers().stream()
.filter(o -> o.getId().equals(id))
.filter(o -> o.isMyOffer(keyRing))
.filter(Offer::isBsqSwapOffer)
.findAny();
}
private Optional<Offer> findAvailableOffer(String id) {
return offerBookService.getOffers().stream()
.filter(o -> o.getId().equals(id))
.filter(o -> !o.isMyOffer(keyRing))
.filter(o -> offerFilterService.canTakeOffer(o, coreContext.isApiUser()).isValid())
.findAny();
}
private Optional<OpenOffer> findMyOpenOffer(String id) {
return openOfferManager.getObservableList().stream()
.filter(o -> o.getId().equals(id))
.filter(o -> o.getOffer().isMyOffer(keyRing))
.findAny();
}
private OfferPayload getMergedOfferPayload(OpenOffer openOffer,
String editedPriceAsString,
double editedMarketPriceMargin,

View File

@ -45,7 +45,8 @@ class EditOfferValidator {
}
void validate() {
log.info("Verifying 'editoffer' params OK for editType {}", editType);
log.info("Verifying 'editoffer' params for editType {}", editType);
checkNotBsqSwapOffer();
switch (editType) {
case ACTIVATION_STATE_ONLY: {
validateEditedActivationState();
@ -138,4 +139,11 @@ class EditOfferValidator {
currentlyOpenOffer.getId()));
}
}
private void checkNotBsqSwapOffer() {
if (currentlyOpenOffer.getOffer().isBsqSwapOffer()) {
throw new IllegalStateException(
format("cannot edit bsq swap offer with id '%s'", currentlyOpenOffer.getId()));
}
}
}

View File

@ -92,7 +92,7 @@ class GrpcOffersService extends OffersImplBase {
public void getOfferCategory(GetOfferCategoryRequest req,
StreamObserver<GetOfferCategoryReply> responseObserver) {
try {
OfferCategory category = getAvailableOfferCategory(req.getId());
OfferCategory category = getOfferCategory(req.getId(), req.getIsMyOffer());
var reply = newBuilder()
.setOfferCategory(category)
.build();
@ -335,6 +335,7 @@ class GrpcOffersService extends OffersImplBase {
return getCustomRateMeteringInterceptor(coreApi.getConfig().appDataDir, this.getClass())
.or(() -> Optional.of(CallRateMeteringInterceptor.valueOf(
new HashMap<>() {{
put(getGetOfferCategoryMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
put(getGetOfferMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
put(getGetMyOfferMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
put(getGetOffersMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
@ -346,12 +347,12 @@ class GrpcOffersService extends OffersImplBase {
)));
}
private OfferCategory getAvailableOfferCategory(String offerId) {
if (coreApi.isAvailableAltcoinOffer(offerId))
private OfferCategory getOfferCategory(String offerId, boolean isMyOffer) {
if (coreApi.isAltcoinOffer(offerId, isMyOffer))
return ALTCOIN;
else if (coreApi.isAvailableFiatOffer(offerId))
else if (coreApi.isFiatOffer(offerId, isMyOffer))
return FIAT;
else if (coreApi.isAvailableBsqSwapOffer(offerId))
else if (coreApi.isBsqSwapOffer(offerId, isMyOffer))
return BSQ_SWAP;
else
return UNKNOWN;

View File

@ -79,7 +79,7 @@ class GrpcTradesService extends TradesImplBase {
exceptionHandler,
log);
if (coreApi.isAvailableBsqSwapOffer(req.getOfferId())) {
if (coreApi.isBsqSwapOffer(req.getOfferId(), false)) {
coreApi.takeBsqSwapOffer(req.getOfferId(),
bsqSwapTrade -> {
var reply = buildTakeOfferReply(bsqSwapTrade);

View File

@ -92,6 +92,7 @@ service Offers {
message GetOfferCategoryRequest {
string id = 1;
bool isMyOffer = 2;
}
message GetOfferCategoryReply {