Commit 66652357 authored by Torsten Grote's avatar Torsten Grote

Merge branch '1232-pending-contact-states' into 'master'

Add ContactManager support for pending contact states

See merge request !1122
parents b9283ea6 64ae99bb
Pipeline #3500 passed with stage
in 8 minutes and 16 seconds
......@@ -8,6 +8,7 @@ import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.contact.PendingContact;
import org.briarproject.bramble.api.contact.PendingContactId;
import org.briarproject.bramble.api.contact.PendingContactState;
import org.briarproject.bramble.api.contact.event.PendingContactStateChangedEvent;
import org.briarproject.bramble.api.crypto.KeyPair;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.crypto.SecretKey;
......@@ -15,24 +16,34 @@ import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.NoSuchContactException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.identity.AuthorInfo;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.rendezvous.event.RendezvousConnectionClosedEvent;
import org.briarproject.bramble.api.rendezvous.event.RendezvousConnectionOpenedEvent;
import org.briarproject.bramble.api.rendezvous.event.RendezvousFailedEvent;
import org.briarproject.bramble.api.transport.KeyManager;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
import javax.inject.Inject;
import static org.briarproject.bramble.api.contact.PendingContactState.ADDING_CONTACT;
import static org.briarproject.bramble.api.contact.PendingContactState.FAILED;
import static org.briarproject.bramble.api.contact.PendingContactState.WAITING_FOR_CONNECTION;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.OURSELVES;
......@@ -43,24 +54,29 @@ import static org.briarproject.bramble.util.StringUtils.toUtf8;
@ThreadSafe
@NotNullByDefault
class ContactManagerImpl implements ContactManager {
class ContactManagerImpl implements ContactManager, EventListener {
private final DatabaseComponent db;
private final KeyManager keyManager;
private final IdentityManager identityManager;
private final PendingContactFactory pendingContactFactory;
private final EventBus eventBus;
private final List<ContactHook> hooks;
private final List<ContactHook> hooks = new CopyOnWriteArrayList<>();
private final ConcurrentMap<PendingContactId, PendingContactState> states =
new ConcurrentHashMap<>();
@Inject
ContactManagerImpl(DatabaseComponent db, KeyManager keyManager,
ContactManagerImpl(DatabaseComponent db,
KeyManager keyManager,
IdentityManager identityManager,
PendingContactFactory pendingContactFactory) {
PendingContactFactory pendingContactFactory,
EventBus eventBus) {
this.db = db;
this.keyManager = keyManager;
this.identityManager = identityManager;
this.pendingContactFactory = pendingContactFactory;
hooks = new CopyOnWriteArrayList<>();
this.eventBus = eventBus;
}
@Override
......@@ -86,6 +102,7 @@ class ContactManagerImpl implements ContactManager {
throws DbException, GeneralSecurityException {
PendingContact pendingContact = db.getPendingContact(txn, p);
db.removePendingContact(txn, p);
states.remove(p);
PublicKey theirPublicKey = pendingContact.getPublicKey();
ContactId c =
db.addContact(txn, remote, local, theirPublicKey, verified);
......@@ -139,6 +156,7 @@ class ContactManagerImpl implements ContactManager {
} finally {
db.endTransaction(txn);
}
setState(p.getId(), WAITING_FOR_CONNECTION);
return p;
}
......@@ -156,7 +174,9 @@ class ContactManagerImpl implements ContactManager {
List<Pair<PendingContact, PendingContactState>> pairs =
new ArrayList<>(pendingContacts.size());
for (PendingContact p : pendingContacts) {
pairs.add(new Pair<>(p, WAITING_FOR_CONNECTION)); // TODO
PendingContactState state = states.get(p.getId());
if (state == null) state = WAITING_FOR_CONNECTION;
pairs.add(new Pair<>(p, state));
}
return pairs;
}
......@@ -164,6 +184,7 @@ class ContactManagerImpl implements ContactManager {
@Override
public void removePendingContact(PendingContactId p) throws DbException {
db.transaction(false, txn -> db.removePendingContact(txn, p));
states.remove(p);
}
@Override
......@@ -263,4 +284,48 @@ class ContactManagerImpl implements ContactManager {
else return new AuthorInfo(UNVERIFIED, c.getAlias());
}
@Override
public void eventOccurred(Event e) {
if (e instanceof RendezvousConnectionOpenedEvent) {
RendezvousConnectionOpenedEvent r =
(RendezvousConnectionOpenedEvent) e;
setStateConnected(r.getPendingContactId());
} else if (e instanceof RendezvousConnectionClosedEvent) {
RendezvousConnectionClosedEvent r =
(RendezvousConnectionClosedEvent) e;
// We're only interested in failures - if the rendezvous succeeds
// the pending contact will be removed
if (!r.isSuccess()) setStateDisconnected(r.getPendingContactId());
} else if (e instanceof RendezvousFailedEvent) {
RendezvousFailedEvent r = (RendezvousFailedEvent) e;
setState(r.getPendingContactId(), FAILED);
}
}
/**
* Sets the state of the given pending contact and broadcasts an event.
*/
private void setState(PendingContactId p, PendingContactState state) {
states.put(p, state);
eventBus.broadcast(new PendingContactStateChangedEvent(p, state));
}
private void setStateConnected(PendingContactId p) {
// Set the state to ADDING_CONTACT if there's no current state or the
// current state is WAITING_FOR_CONNECTION
if (states.putIfAbsent(p, ADDING_CONTACT) == null ||
states.replace(p, WAITING_FOR_CONNECTION, ADDING_CONTACT)) {
eventBus.broadcast(new PendingContactStateChangedEvent(p,
ADDING_CONTACT));
}
}
private void setStateDisconnected(PendingContactId p) {
// Set the state to WAITING_FOR_CONNECTION if the current state is
// ADDING_CONTACT
if (states.replace(p, ADDING_CONTACT, WAITING_FOR_CONNECTION)) {
eventBus.broadcast(new PendingContactStateChangedEvent(p,
WAITING_FOR_CONNECTION));
}
}
}
......@@ -3,6 +3,7 @@ package org.briarproject.bramble.contact;
import org.briarproject.bramble.api.contact.ContactExchangeManager;
import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.contact.HandshakeManager;
import org.briarproject.bramble.api.event.EventBus;
import javax.inject.Inject;
import javax.inject.Singleton;
......@@ -20,7 +21,9 @@ public class ContactModule {
@Provides
@Singleton
ContactManager provideContactManager(ContactManagerImpl contactManager) {
ContactManager provideContactManager(EventBus eventBus,
ContactManagerImpl contactManager) {
eventBus.addListener(contactManager);
return contactManager;
}
......
package org.briarproject.bramble.test;
import org.briarproject.bramble.api.Predicate;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
public class PredicateMatcher<T> extends BaseMatcher<T> {
private final Class<T> matchedClass;
private final Predicate<T> predicate;
public PredicateMatcher(Class<T> matchedClass, Predicate<T> predicate) {
this.matchedClass = matchedClass;
this.predicate = predicate;
}
@Override
public boolean matches(Object item) {
if (matchedClass.isInstance(item))
return predicate.test(matchedClass.cast(item));
return false;
}
@Override
public void describeTo(Description description) {
description.appendText("matches an item against a predicate");
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment