onUpdatedDataReceived must be called in the correct order.

We cannot use a listener at RequestDataManager as the order
is not defined if doing so.
So we use P2PService as our controlling entity to call
further clients in the correct order.
This commit is contained in:
chimp1984 2021-01-31 13:35:28 -05:00 committed by Christoph Atteneder
parent 3757ec36f7
commit 9041bf4938
No known key found for this signature in database
GPG key ID: CD5DC1C529CDFD3B
3 changed files with 36 additions and 38 deletions

View file

@ -147,7 +147,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
this.networkNode.addConnectionListener(this); this.networkNode.addConnectionListener(this);
this.networkNode.addMessageListener(this); this.networkNode.addMessageListener(this);
this.requestDataManager.addListener(this); this.requestDataManager.setListener(this);
// We need to have both the initial data delivered and the hidden service published // We need to have both the initial data delivered and the hidden service published
networkReadyBinding = EasyBind.combine(hiddenServicePublished, preliminaryDataReceived, networkReadyBinding = EasyBind.combine(hiddenServicePublished, preliminaryDataReceived,
@ -317,6 +317,11 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
public void onUpdatedDataReceived() { public void onUpdatedDataReceived() {
if (!isBootstrapped) { if (!isBootstrapped) {
isBootstrapped = true; isBootstrapped = true;
// We don't use a listener at mailboxMessageService as we require the correct
// order of execution. The p2pServiceListeners must be called after
// mailboxMessageService.onUpdatedDataReceived.
mailboxMessageService.onUpdatedDataReceived();
p2pServiceListeners.forEach(P2PServiceListener::onUpdatedDataReceived); p2pServiceListeners.forEach(P2PServiceListener::onUpdatedDataReceived);
p2PDataStorage.onBootstrapComplete(); p2PDataStorage.onBootstrapComplete();
} }

View file

@ -112,7 +112,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
*/ */
@Singleton @Singleton
@Slf4j @Slf4j
public class MailboxMessageService implements SetupListener, RequestDataManager.Listener, HashMapChangedListener, public class MailboxMessageService implements SetupListener, HashMapChangedListener,
PersistedDataHost { PersistedDataHost {
private static final long REPUBLISH_DELAY_SEC = TimeUnit.MINUTES.toSeconds(2); private static final long REPUBLISH_DELAY_SEC = TimeUnit.MINUTES.toSeconds(2);
@ -155,7 +155,6 @@ public class MailboxMessageService implements SetupListener, RequestDataManager.
this.clock = clock; this.clock = clock;
this.republishMailboxEntries = republishMailboxEntries; this.republishMailboxEntries = republishMailboxEntries;
this.requestDataManager.addListener(this);
this.networkNode.addSetupListener(this); this.networkNode.addSetupListener(this);
this.persistenceManager.initialize(mailboxMessageList, PersistenceManager.Source.PRIVATE_LOW_PRIO); this.persistenceManager.initialize(mailboxMessageList, PersistenceManager.Source.PRIVATE_LOW_PRIO);
@ -224,6 +223,19 @@ public class MailboxMessageService implements SetupListener, RequestDataManager.
// API // API
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// We don't listen on requestDataManager directly as we require the correct
// order of execution. The p2pService is handling the correct order of execution and we get called
// directly from there.
public void onUpdatedDataReceived() {
if (!isBootstrapped) {
isBootstrapped = true;
// Only now we start listening and processing. The p2PDataStorage is our cache for data we have received
// after the hidden service was ready.
addHashMapChangedListenerAndApply();
maybeRepublishMailBoxMessages();
}
}
public void sendEncryptedMailboxMessage(NodeAddress peer, public void sendEncryptedMailboxMessage(NodeAddress peer,
PubKeyRing peersPubKeyRing, PubKeyRing peersPubKeyRing,
MailboxMessage mailboxMessage, MailboxMessage mailboxMessage,
@ -238,8 +250,9 @@ public class MailboxMessageService implements SetupListener, RequestDataManager.
"My node address must not be null at sendEncryptedMailboxMessage"); "My node address must not be null at sendEncryptedMailboxMessage");
checkArgument(!keyRing.getPubKeyRing().equals(peersPubKeyRing), "We got own keyring instead of that from peer"); checkArgument(!keyRing.getPubKeyRing().equals(peersPubKeyRing), "We got own keyring instead of that from peer");
if (!isBootstrapped) if (!isBootstrapped) {
throw new NetworkNotReadyException(); throw new NetworkNotReadyException();
}
if (networkNode.getAllConnections().isEmpty()) { if (networkNode.getAllConnections().isEmpty()) {
sendMailboxMessageListener.onFault("There are no P2P network nodes connected. " + sendMailboxMessageListener.onFault("There are no P2P network nodes connected. " +
@ -349,30 +362,6 @@ public class MailboxMessageService implements SetupListener, RequestDataManager.
} }
///////////////////////////////////////////////////////////////////////////////////////////
// RequestDataManager.Listener implementation
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void onPreliminaryDataReceived() {
}
@Override
public void onUpdatedDataReceived() {
if (!isBootstrapped) {
isBootstrapped = true;
// Only now we start listening and processing. The p2PDataStorage is our cache for data we have received
// after the hidden service was ready.
addHashMapChangedListenerAndApply();
maybeRepublishMailBoxMessages();
}
}
@Override
public void onDataReceived() {
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// HashMapChangedListener implementation for ProtectedStorageEntry items // HashMapChangedListener implementation for ProtectedStorageEntry items
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////

View file

@ -40,11 +40,9 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -53,6 +51,7 @@ import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
@Slf4j @Slf4j
public class RequestDataManager implements MessageListener, ConnectionListener, PeerManager.Listener { public class RequestDataManager implements MessageListener, ConnectionListener, PeerManager.Listener {
@ -91,7 +90,10 @@ public class RequestDataManager implements MessageListener, ConnectionListener,
private final P2PDataStorage dataStorage; private final P2PDataStorage dataStorage;
private final PeerManager peerManager; private final PeerManager peerManager;
private final List<NodeAddress> seedNodeAddresses; private final List<NodeAddress> seedNodeAddresses;
private final Set<Listener> listeners = new HashSet<>();
// As we use Guice injection we cannot set the listener in our constructor but the P2PService calls the setListener
// in it's constructor so we can guarantee it is not null.
private Listener listener;
private final Map<NodeAddress, RequestDataHandler> handlerMap = new HashMap<>(); private final Map<NodeAddress, RequestDataHandler> handlerMap = new HashMap<>();
private final Map<String, GetDataRequestHandler> getDataRequestHandlers = new HashMap<>(); private final Map<String, GetDataRequestHandler> getDataRequestHandlers = new HashMap<>();
@ -147,8 +149,10 @@ public class RequestDataManager implements MessageListener, ConnectionListener,
// API // API
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public void addListener(Listener listener) { // We only support one listener as P2PService will manage calls on other clients in the correct order of execution.
listeners.add(listener); // The listener is set from the P2PService constructor so we can guarantee it is not null.
public void setListener(Listener listener) {
this.listener = listener;
} }
public boolean requestPreliminaryData() { public boolean requestPreliminaryData() {
@ -334,16 +338,16 @@ public class RequestDataManager implements MessageListener, ConnectionListener,
// We delay because it can be that we get the HS published before we receive the // We delay because it can be that we get the HS published before we receive the
// preliminary data and the onPreliminaryDataReceived call triggers the // preliminary data and the onPreliminaryDataReceived call triggers the
// dataUpdateRequested set to true, so we would also call the onUpdatedDataReceived. // dataUpdateRequested set to true, so we would also call the onUpdatedDataReceived.
UserThread.runAfter(() -> listeners.forEach(Listener::onPreliminaryDataReceived), 100, TimeUnit.MILLISECONDS); UserThread.runAfter(checkNotNull(listener)::onPreliminaryDataReceived, 100, TimeUnit.MILLISECONDS);
} }
// 2. Later we get a response from requestUpdatesData // 2. Later we get a response from requestUpdatesData
if (dataUpdateRequested) { if (dataUpdateRequested) {
dataUpdateRequested = false; dataUpdateRequested = false;
listeners.forEach(Listener::onUpdatedDataReceived); checkNotNull(listener).onUpdatedDataReceived();
} }
listeners.forEach(Listener::onDataReceived); checkNotNull(listener).onDataReceived();
} }
@Override @Override
@ -371,9 +375,9 @@ public class RequestDataManager implements MessageListener, ConnectionListener,
// Notify listeners // Notify listeners
if (!nodeAddressOfPreliminaryDataRequest.isPresent()) { if (!nodeAddressOfPreliminaryDataRequest.isPresent()) {
if (peerManager.isSeedNode(nodeAddress)) { if (peerManager.isSeedNode(nodeAddress)) {
listeners.forEach(Listener::onNoSeedNodeAvailable); checkNotNull(listener).onNoSeedNodeAvailable();
} else { } else {
listeners.forEach(Listener::onNoPeersAvailable); checkNotNull(listener).onNoPeersAvailable();
} }
} }