diff --git a/core/src/main/java/bisq/core/api/CoreApi.java b/core/src/main/java/bisq/core/api/CoreApi.java index ac4c8dcd00..e446aa6c60 100644 --- a/core/src/main/java/bisq/core/api/CoreApi.java +++ b/core/src/main/java/bisq/core/api/CoreApi.java @@ -32,6 +32,7 @@ import bisq.core.payment.payload.PaymentMethod; import bisq.core.support.dispute.Attachment; import bisq.core.support.dispute.Dispute; import bisq.core.support.dispute.DisputeResult; +import bisq.core.support.messages.ChatMessage; import bisq.core.trade.Trade; import bisq.core.trade.statistics.TradeStatistics3; import bisq.core.trade.statistics.TradeStatisticsManager; @@ -543,4 +544,12 @@ public class CoreApi { public String getTradeRole(String tradeId) { return coreTradesService.getTradeRole(tradeId); } + + public List getChatMessages(String tradeId) { + return coreTradesService.getChatMessages(tradeId); + } + + public void sendChatMessage(String tradeId, String message) { + coreTradesService.sendChatMessage(tradeId, message); + } } diff --git a/core/src/main/java/bisq/core/api/CoreTradesService.java b/core/src/main/java/bisq/core/api/CoreTradesService.java index 16f291523c..8e81e2aee3 100644 --- a/core/src/main/java/bisq/core/api/CoreTradesService.java +++ b/core/src/main/java/bisq/core/api/CoreTradesService.java @@ -22,6 +22,10 @@ import bisq.core.btc.wallet.BtcWalletService; import bisq.core.offer.Offer; import bisq.core.offer.OfferUtil; import bisq.core.offer.takeoffer.TakeOfferModel; +import bisq.core.support.dispute.Dispute; +import bisq.core.support.messages.ChatMessage; +import bisq.core.support.traderchat.TradeChatSession; +import bisq.core.support.traderchat.TraderChatManager; import bisq.core.trade.Tradable; import bisq.core.trade.Trade; import bisq.core.trade.TradeManager; @@ -58,10 +62,10 @@ class CoreTradesService { // exception is made in this case. private final CoreWalletsService coreWalletsService; private final BtcWalletService btcWalletService; - private final OfferUtil offerUtil; private final ClosedTradableManager closedTradableManager; private final TakeOfferModel takeOfferModel; private final TradeManager tradeManager; + private final TraderChatManager traderChatManager; private final TradeUtil tradeUtil; private final User user; @@ -69,19 +73,19 @@ class CoreTradesService { public CoreTradesService(CoreContext coreContext, CoreWalletsService coreWalletsService, BtcWalletService btcWalletService, - OfferUtil offerUtil, ClosedTradableManager closedTradableManager, TakeOfferModel takeOfferModel, TradeManager tradeManager, + TraderChatManager traderChatManager, TradeUtil tradeUtil, User user) { this.coreContext = coreContext; this.coreWalletsService = coreWalletsService; this.btcWalletService = btcWalletService; - this.offerUtil = offerUtil; this.closedTradableManager = closedTradableManager; this.takeOfferModel = takeOfferModel; this.tradeManager = tradeManager; + this.traderChatManager = traderChatManager; this.tradeUtil = tradeUtil; this.user = user; } @@ -237,6 +241,34 @@ class CoreTradesService { return trades; } + List getChatMessages(String tradeId) { + Trade trade; + var tradeOptional = tradeManager.getTradeById(tradeId); + if (tradeOptional.isPresent()) trade = tradeOptional.get(); + else throw new IllegalStateException(format("trade with id '%s' not found", tradeId)); + boolean isMaker = tradeManager.isMyOffer(trade.getOffer()); + TradeChatSession tradeChatSession = new TradeChatSession(trade, !isMaker); + return tradeChatSession.getObservableChatMessageList(); + } + + void sendChatMessage(String tradeId, String message) { + Trade trade; + var tradeOptional = tradeManager.getTradeById(tradeId); + if (tradeOptional.isPresent()) trade = tradeOptional.get(); + else throw new IllegalStateException(format("trade with id '%s' not found", tradeId)); + boolean isMaker = tradeManager.isMyOffer(trade.getOffer()); + TradeChatSession tradeChatSession = new TradeChatSession(trade, !isMaker); + ChatMessage chatMessage = new ChatMessage( + traderChatManager.getSupportType(), + tradeChatSession.getTradeId(), + tradeChatSession.getClientId(), + tradeChatSession.isClient(), + message, + traderChatManager.getMyAddress()); + traderChatManager.addAndPersistChatMessage(chatMessage); + traderChatManager.sendChatMessage(chatMessage); + } + private boolean isFollowingBuyerProtocol(Trade trade) { return tradeManager.getTradeProtocol(trade) instanceof BuyerProtocol; } diff --git a/daemon/src/main/java/bisq/daemon/grpc/GrpcTradesService.java b/daemon/src/main/java/bisq/daemon/grpc/GrpcTradesService.java index 19f74724df..8f2c62086f 100644 --- a/daemon/src/main/java/bisq/daemon/grpc/GrpcTradesService.java +++ b/daemon/src/main/java/bisq/daemon/grpc/GrpcTradesService.java @@ -19,18 +19,23 @@ package bisq.daemon.grpc; import bisq.core.api.CoreApi; import bisq.core.api.model.TradeInfo; +import bisq.core.support.messages.ChatMessage; import bisq.core.trade.Trade; import bisq.proto.grpc.ConfirmPaymentReceivedReply; import bisq.proto.grpc.ConfirmPaymentReceivedRequest; import bisq.proto.grpc.ConfirmPaymentStartedReply; import bisq.proto.grpc.ConfirmPaymentStartedRequest; +import bisq.proto.grpc.GetChatMessagesReply; +import bisq.proto.grpc.GetChatMessagesRequest; import bisq.proto.grpc.GetTradeReply; import bisq.proto.grpc.GetTradeRequest; import bisq.proto.grpc.GetTradesReply; import bisq.proto.grpc.GetTradesRequest; import bisq.proto.grpc.KeepFundsReply; import bisq.proto.grpc.KeepFundsRequest; +import bisq.proto.grpc.SendChatMessageReply; +import bisq.proto.grpc.SendChatMessageRequest; import bisq.proto.grpc.TakeOfferReply; import bisq.proto.grpc.TakeOfferRequest; import bisq.proto.grpc.WithdrawFundsReply; @@ -185,6 +190,37 @@ class GrpcTradesService extends TradesImplBase { } } + @Override + public void getChatMessages(GetChatMessagesRequest req, + StreamObserver responseObserver) { + try { + var tradeChats = coreApi.getChatMessages(req.getTradeId()) + .stream() + .map(msg -> msg.toProtoNetworkEnvelope().getChatMessage()) + .collect(Collectors.toList()); + var reply = GetChatMessagesReply.newBuilder() + .addAllMessage(tradeChats) + .build(); + responseObserver.onNext(reply); + responseObserver.onCompleted(); + } catch (Throwable cause) { + exceptionHandler.handleException(log, cause, responseObserver); + } + } + + @Override + public void sendChatMessage(SendChatMessageRequest req, + StreamObserver responseObserver) { + try { + coreApi.sendChatMessage(req.getTradeId(), req.getMessage()); + var reply = SendChatMessageReply.newBuilder().build(); + responseObserver.onNext(reply); + responseObserver.onCompleted(); + } catch (Throwable cause) { + exceptionHandler.handleException(log, cause, responseObserver); + } + } + final ServerInterceptor[] interceptors() { Optional rateMeteringInterceptor = rateMeteringInterceptor(); return rateMeteringInterceptor.map(serverInterceptor -> @@ -202,6 +238,8 @@ class GrpcTradesService extends TradesImplBase { put(getConfirmPaymentReceivedMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS)); put(getKeepFundsMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES)); put(getWithdrawFundsMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES)); + put(getGetChatMessagesMethod().getFullMethodName(), new GrpcCallRateMeter(10, SECONDS)); + put(getSendChatMessageMethod().getFullMethodName(), new GrpcCallRateMeter(10, SECONDS)); }} ))); } diff --git a/proto/src/main/proto/grpc.proto b/proto/src/main/proto/grpc.proto index 3a68ca9271..0eb765ebe0 100644 --- a/proto/src/main/proto/grpc.proto +++ b/proto/src/main/proto/grpc.proto @@ -655,6 +655,10 @@ service Trades { } rpc WithdrawFunds (WithdrawFundsRequest) returns (WithdrawFundsReply) { } + rpc GetChatMessages (GetChatMessagesRequest) returns (GetChatMessagesReply) { + } + rpc SendChatMessage (SendChatMessageRequest) returns (SendChatMessageReply) { + } } message TakeOfferRequest { @@ -712,6 +716,22 @@ message WithdrawFundsRequest { message WithdrawFundsReply { } +message GetChatMessagesRequest { + string trade_id = 1; +} + +message GetChatMessagesReply { + repeated ChatMessage message = 1; +} + +message SendChatMessageRequest { + string trade_id = 1; + string message = 2; +} + +message SendChatMessageReply { +} + message TradeInfo { OfferInfo offer = 1; string trade_id = 2;