Search in sources :

Example 1 with BroadcastMessage

use of io.bitsquare.p2p.storage.messages.BroadcastMessage in project bitsquare by bitsquare.

the class BroadcastHandler method broadcast.

///////////////////////////////////////////////////////////////////////////////////////////
// API
///////////////////////////////////////////////////////////////////////////////////////////
public void broadcast(BroadcastMessage message, @Nullable NodeAddress sender, ResultHandler resultHandler, @Nullable Listener listener, boolean isDataOwner) {
    this.message = message;
    this.resultHandler = resultHandler;
    this.listener = listener;
    Log.traceCall("Sender=" + sender + "\n\t" + "Message=" + Utilities.toTruncatedString(message));
    Set<Connection> connectedPeersSet = networkNode.getConfirmedConnections().stream().filter(connection -> !connection.getPeersNodeAddressOptional().get().equals(sender)).collect(Collectors.toSet());
    if (!connectedPeersSet.isEmpty()) {
        numOfCompletedBroadcasts = 0;
        List<Connection> connectedPeersList = new ArrayList<>(connectedPeersSet);
        Collections.shuffle(connectedPeersList);
        numOfPeers = connectedPeersList.size();
        int delay = 50;
        if (!isDataOwner) {
            // for not data owner (relay nodes) we send to max. 7 nodes and use a longer delay
            numOfPeers = Math.min(7, connectedPeersList.size());
            delay = 100;
        }
        long timeoutDelay = TIMEOUT_PER_PEER_SEC * numOfPeers;
        timeoutTimer = UserThread.runAfter(() -> {
            // setup before sending to avoid race conditions
            String errorMessage = "Timeout: Broadcast did not complete after " + timeoutDelay + " sec.";
            log.debug(errorMessage + "\n\t" + "numOfPeers=" + numOfPeers + "\n\t" + "numOfCompletedBroadcasts=" + numOfCompletedBroadcasts + "\n\t" + "numOfCompletedBroadcasts=" + numOfCompletedBroadcasts + "\n\t" + "numOfFailedBroadcasts=" + numOfFailedBroadcasts);
            onFault(errorMessage, false);
        }, timeoutDelay);
        log.debug("Broadcast message to {} peers out of {} total connected peers.", numOfPeers, connectedPeersSet.size());
        for (int i = 0; i < numOfPeers; i++) {
            if (stopped)
                // do not continue sending after a timeout or a cancellation
                break;
            final long minDelay = (i + 1) * delay;
            final long maxDelay = (i + 2) * delay;
            final Connection connection = connectedPeersList.get(i);
            UserThread.runAfterRandomDelay(() -> sendToPeer(connection, message), minDelay, maxDelay, TimeUnit.MILLISECONDS);
        }
    } else {
        onFault("Message not broadcasted because we have no available peers yet.\n\t" + "message = " + Utilities.toTruncatedString(message), false);
    }
}
Also used : java.util(java.util) Utilities(io.bitsquare.common.util.Utilities) Logger(org.slf4j.Logger) UserThread(io.bitsquare.common.UserThread) LoggerFactory(org.slf4j.LoggerFactory) NodeAddress(io.bitsquare.p2p.NodeAddress) Connection(io.bitsquare.p2p.network.Connection) Timer(io.bitsquare.common.Timer) SettableFuture(com.google.common.util.concurrent.SettableFuture) Collectors(java.util.stream.Collectors) FutureCallback(com.google.common.util.concurrent.FutureCallback) BroadcastMessage(io.bitsquare.p2p.storage.messages.BroadcastMessage) TimeUnit(java.util.concurrent.TimeUnit) Nullable(org.jetbrains.annotations.Nullable) Futures(com.google.common.util.concurrent.Futures) NotNull(org.jetbrains.annotations.NotNull) NetworkNode(io.bitsquare.p2p.network.NetworkNode) Log(io.bitsquare.app.Log) Connection(io.bitsquare.p2p.network.Connection)

Example 2 with BroadcastMessage

use of io.bitsquare.p2p.storage.messages.BroadcastMessage in project bitsquare by bitsquare.

the class P2PService method addMailboxData.

private void addMailboxData(MailboxStoragePayload expirableMailboxStoragePayload, PublicKey receiversPublicKey, SendMailboxMessageListener sendMailboxMessageListener) {
    Log.traceCall();
    checkArgument(optionalKeyRing.isPresent(), "keyRing not set. Seems that is called on a seed node which must not happen.");
    if (isBootstrapped()) {
        if (!networkNode.getAllConnections().isEmpty()) {
            try {
                ProtectedMailboxStorageEntry protectedMailboxStorageEntry = p2PDataStorage.getMailboxDataWithSignedSeqNr(expirableMailboxStoragePayload, optionalKeyRing.get().getSignatureKeyPair(), receiversPublicKey);
                BroadcastHandler.Listener listener = new BroadcastHandler.Listener() {

                    @Override
                    public void onBroadcasted(BroadcastMessage message, int numOfCompletedBroadcasts) {
                    }

                    @Override
                    public void onBroadcastedToFirstPeer(BroadcastMessage message) {
                        // We only want to notify our sendMailboxMessageListener for the calls he is interested in.
                        if (message instanceof AddDataMessage && ((AddDataMessage) message).protectedStorageEntry.equals(protectedMailboxStorageEntry)) {
                            // We delay a bit to give more time for sufficient propagation in the P2P network.
                            // This should help to avoid situations where a user closes the app too early and the msg
                            // does not arrive.
                            // We could use onBroadcastCompleted instead but it might take too long if one peer
                            // is very badly connected.
                            // TODO We could check for a certain threshold of no. of incoming messages of the same msg 
                            // to see how well it is propagated. BitcoinJ uses such an approach for tx propagation.
                            UserThread.runAfter(() -> {
                                log.info("Broadcasted to first peer (with 3 sec. delayed):  Message = {}", Utilities.toTruncatedString(message));
                                sendMailboxMessageListener.onStoredInMailbox();
                            }, 3);
                        }
                    }

                    @Override
                    public void onBroadcastCompleted(BroadcastMessage message, int numOfCompletedBroadcasts, int numOfFailedBroadcasts) {
                        log.info("Broadcast completed: Sent to {} peers (failed: {}). Message = {}", numOfCompletedBroadcasts, numOfFailedBroadcasts, Utilities.toTruncatedString(message));
                        if (numOfCompletedBroadcasts == 0)
                            sendMailboxMessageListener.onFault("Broadcast completed without any successful broadcast");
                    }

                    @Override
                    public void onBroadcastFailed(String errorMessage) {
                    // TODO investigate why not sending sendMailboxMessageListener.onFault. Related probably 
                    // to the logic from BroadcastHandler.sendToPeer
                    }
                };
                boolean result = p2PDataStorage.add(protectedMailboxStorageEntry, networkNode.getNodeAddress(), listener, true);
                if (!result) {
                    //TODO remove and add again with a delay to ensure the data will be broadcasted
                    // The p2PDataStorage.remove makes probably sense but need to be analysed more.
                    // Don't change that if it is not 100% clear.
                    sendMailboxMessageListener.onFault("Data already exists in our local database");
                    boolean removeResult = p2PDataStorage.remove(protectedMailboxStorageEntry, networkNode.getNodeAddress(), true);
                    log.debug("remove result=" + removeResult);
                }
            } catch (CryptoException e) {
                log.error("Signing at getDataWithSignedSeqNr failed. That should never happen.");
            }
        } else {
            sendMailboxMessageListener.onFault("There are no P2P network nodes connected. " + "Please check your internet connection.");
        }
    } else {
        throw new NetworkNotReadyException();
    }
}
Also used : AddDataMessage(io.bitsquare.p2p.storage.messages.AddDataMessage) HashMapChangedListener(io.bitsquare.p2p.storage.HashMapChangedListener) BroadcastMessage(io.bitsquare.p2p.storage.messages.BroadcastMessage) ProtectedMailboxStorageEntry(io.bitsquare.p2p.storage.storageentry.ProtectedMailboxStorageEntry) CryptoException(io.bitsquare.common.crypto.CryptoException) BroadcastHandler(io.bitsquare.p2p.peers.BroadcastHandler)

Aggregations

BroadcastMessage (io.bitsquare.p2p.storage.messages.BroadcastMessage)2 FutureCallback (com.google.common.util.concurrent.FutureCallback)1 Futures (com.google.common.util.concurrent.Futures)1 SettableFuture (com.google.common.util.concurrent.SettableFuture)1 Log (io.bitsquare.app.Log)1 Timer (io.bitsquare.common.Timer)1 UserThread (io.bitsquare.common.UserThread)1 CryptoException (io.bitsquare.common.crypto.CryptoException)1 Utilities (io.bitsquare.common.util.Utilities)1 NodeAddress (io.bitsquare.p2p.NodeAddress)1 Connection (io.bitsquare.p2p.network.Connection)1 NetworkNode (io.bitsquare.p2p.network.NetworkNode)1 BroadcastHandler (io.bitsquare.p2p.peers.BroadcastHandler)1 HashMapChangedListener (io.bitsquare.p2p.storage.HashMapChangedListener)1 AddDataMessage (io.bitsquare.p2p.storage.messages.AddDataMessage)1 ProtectedMailboxStorageEntry (io.bitsquare.p2p.storage.storageentry.ProtectedMailboxStorageEntry)1 java.util (java.util)1 TimeUnit (java.util.concurrent.TimeUnit)1 Collectors (java.util.stream.Collectors)1 NotNull (org.jetbrains.annotations.NotNull)1