mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 10:49:06 +01:00
Merge branch '1580-offline-state' into 'master'
Add offline state for pending contacts Closes #1580 See merge request briar/briar!1138
This commit is contained in:
@@ -3,6 +3,7 @@ package org.briarproject.bramble.api.contact;
|
||||
public enum PendingContactState {
|
||||
|
||||
WAITING_FOR_CONNECTION,
|
||||
OFFLINE,
|
||||
CONNECTING,
|
||||
ADDING_CONTACT,
|
||||
FAILED
|
||||
|
||||
@@ -147,7 +147,6 @@ class ContactManagerImpl implements ContactManager, EventListener {
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
states.put(p.getId(), WAITING_FOR_CONNECTION);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@ import static java.util.logging.Level.WARNING;
|
||||
import static java.util.logging.Logger.getLogger;
|
||||
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.OFFLINE;
|
||||
import static org.briarproject.bramble.api.contact.PendingContactState.WAITING_FOR_CONNECTION;
|
||||
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNull;
|
||||
import static org.briarproject.bramble.rendezvous.RendezvousConstants.POLLING_INTERVAL_MS;
|
||||
@@ -158,9 +159,7 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
|
||||
private void addPendingContact(PendingContact p) {
|
||||
long now = clock.currentTimeMillis();
|
||||
long expiry = p.getTimestamp() + RENDEZVOUS_TIMEOUT_MS;
|
||||
if (expiry > now) {
|
||||
broadcastState(p.getId(), WAITING_FOR_CONNECTION);
|
||||
} else {
|
||||
if (expiry <= now) {
|
||||
broadcastState(p.getId(), FAILED);
|
||||
return;
|
||||
}
|
||||
@@ -180,9 +179,13 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
|
||||
for (PluginState ps : pluginStates.values()) {
|
||||
RendezvousEndpoint endpoint =
|
||||
createEndpoint(ps.plugin, p.getId(), cs);
|
||||
if (endpoint != null)
|
||||
if (endpoint != null) {
|
||||
requireNull(ps.endpoints.put(p.getId(), endpoint));
|
||||
cs.numEndpoints++;
|
||||
}
|
||||
}
|
||||
if (cs.numEndpoints == 0) broadcastState(p.getId(), OFFLINE);
|
||||
else broadcastState(p.getId(), WAITING_FOR_CONNECTION);
|
||||
} catch (DbException | GeneralSecurityException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
}
|
||||
@@ -328,9 +331,14 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
|
||||
TransportId t = plugin.getId();
|
||||
Map<PendingContactId, RendezvousEndpoint> endpoints = new HashMap<>();
|
||||
for (Entry<PendingContactId, CryptoState> e : cryptoStates.entrySet()) {
|
||||
RendezvousEndpoint endpoint =
|
||||
createEndpoint(plugin, e.getKey(), e.getValue());
|
||||
if (endpoint != null) endpoints.put(e.getKey(), endpoint);
|
||||
PendingContactId p = e.getKey();
|
||||
CryptoState cs = e.getValue();
|
||||
RendezvousEndpoint endpoint = createEndpoint(plugin, p, cs);
|
||||
if (endpoint != null) {
|
||||
endpoints.put(p, endpoint);
|
||||
if (++cs.numEndpoints == 1)
|
||||
broadcastState(p, WAITING_FOR_CONNECTION);
|
||||
}
|
||||
}
|
||||
requireNull(pluginStates.put(t, new PluginState(plugin, endpoints)));
|
||||
}
|
||||
@@ -344,8 +352,11 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
|
||||
private void removeTransport(TransportId t) {
|
||||
PluginState ps = pluginStates.remove(t);
|
||||
if (ps != null) {
|
||||
for (RendezvousEndpoint endpoint : ps.endpoints.values()) {
|
||||
tryToClose(endpoint, LOG, INFO);
|
||||
for (Entry<PendingContactId, RendezvousEndpoint> e :
|
||||
ps.endpoints.entrySet()) {
|
||||
tryToClose(e.getValue(), LOG, INFO);
|
||||
CryptoState cs = cryptoStates.get(e.getKey());
|
||||
if (--cs.numEndpoints == 0) broadcastState(e.getKey(), OFFLINE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -391,6 +402,8 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
|
||||
private final boolean alice;
|
||||
private final long expiry;
|
||||
|
||||
private int numEndpoints = 0;
|
||||
|
||||
private CryptoState(SecretKey rendezvousKey, boolean alice,
|
||||
long expiry) {
|
||||
this.rendezvousKey = rendezvousKey;
|
||||
|
||||
@@ -6,11 +6,15 @@ import org.briarproject.bramble.api.contact.ContactManager;
|
||||
import org.briarproject.bramble.api.contact.PendingContact;
|
||||
import org.briarproject.bramble.api.contact.PendingContactState;
|
||||
import org.briarproject.bramble.api.contact.event.ContactAddedEvent;
|
||||
import org.briarproject.bramble.api.contact.event.PendingContactStateChangedEvent;
|
||||
import org.briarproject.bramble.api.crypto.PublicKey;
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
import org.briarproject.bramble.api.event.EventListener;
|
||||
import org.briarproject.bramble.api.identity.Identity;
|
||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.test.BrambleTestCase;
|
||||
import org.briarproject.bramble.test.TestDatabaseConfigModule;
|
||||
import org.briarproject.bramble.test.TestDuplexTransportConnection;
|
||||
@@ -27,7 +31,7 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static junit.framework.TestCase.assertNotNull;
|
||||
import static junit.framework.TestCase.assertNull;
|
||||
import static junit.framework.TestCase.fail;
|
||||
import static org.briarproject.bramble.api.contact.PendingContactState.WAITING_FOR_CONNECTION;
|
||||
import static org.briarproject.bramble.api.contact.PendingContactState.OFFLINE;
|
||||
import static org.briarproject.bramble.test.TestDuplexTransportConnection.createPair;
|
||||
import static org.briarproject.bramble.test.TestPluginConfigModule.DUPLEX_TRANSPORT_ID;
|
||||
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
|
||||
@@ -188,9 +192,14 @@ public class ContactExchangeIntegrationTest extends BrambleTestCase {
|
||||
private PendingContact addPendingContact(
|
||||
ContactExchangeIntegrationTestComponent local,
|
||||
ContactExchangeIntegrationTestComponent remote) throws Exception {
|
||||
EventWaiter waiter = new EventWaiter();
|
||||
local.getEventBus().addListener(waiter);
|
||||
String link = remote.getContactManager().getHandshakeLink();
|
||||
String alias = remote.getIdentityManager().getLocalAuthor().getName();
|
||||
return local.getContactManager().addPendingContact(link, alias);
|
||||
PendingContact pendingContact =
|
||||
local.getContactManager().addPendingContact(link, alias);
|
||||
waiter.latch.await(TIMEOUT, MILLISECONDS);
|
||||
return pendingContact;
|
||||
}
|
||||
|
||||
private void assertContacts(boolean verified,
|
||||
@@ -237,7 +246,7 @@ public class ContactExchangeIntegrationTest extends BrambleTestCase {
|
||||
assertEquals(1, pairs.size());
|
||||
Pair<PendingContact, PendingContactState> pair =
|
||||
pairs.iterator().next();
|
||||
assertEquals(WAITING_FOR_CONNECTION, pair.getSecond());
|
||||
assertEquals(OFFLINE, pair.getSecond());
|
||||
PendingContact pendingContact = pair.getFirst();
|
||||
assertEquals(expectedIdentity.getLocalAuthor().getName(),
|
||||
pendingContact.getAlias());
|
||||
@@ -261,4 +270,19 @@ public class ContactExchangeIntegrationTest extends BrambleTestCase {
|
||||
tearDown(bob);
|
||||
deleteTestDirectory(testDir);
|
||||
}
|
||||
|
||||
@NotNullByDefault
|
||||
private static class EventWaiter implements EventListener {
|
||||
|
||||
private final CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
@Override
|
||||
public void eventOccurred(Event e) {
|
||||
if (e instanceof PendingContactStateChangedEvent) {
|
||||
PendingContactStateChangedEvent p =
|
||||
(PendingContactStateChangedEvent) e;
|
||||
if (p.getPendingContactState() == OFFLINE) latch.countDown();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ import static java.util.Collections.singletonList;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
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.OFFLINE;
|
||||
import static org.briarproject.bramble.api.contact.PendingContactState.WAITING_FOR_CONNECTION;
|
||||
import static org.briarproject.bramble.rendezvous.RendezvousConstants.POLLING_INTERVAL_MS;
|
||||
import static org.briarproject.bramble.rendezvous.RendezvousConstants.RENDEZVOUS_TIMEOUT_MS;
|
||||
@@ -120,7 +121,7 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
|
||||
will(returnValue(beforeExpiry));
|
||||
oneOf(eventBus).broadcast(with(new PredicateMatcher<>(
|
||||
PendingContactStateChangedEvent.class, e ->
|
||||
e.getPendingContactState() == WAITING_FOR_CONNECTION)));
|
||||
e.getPendingContactState() == OFFLINE)));
|
||||
// Capture the poll task
|
||||
oneOf(scheduler).scheduleAtFixedRate(with(any(Runnable.class)),
|
||||
with(POLLING_INTERVAL_MS), with(POLLING_INTERVAL_MS),
|
||||
@@ -184,7 +185,7 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
|
||||
context.assertIsSatisfied();
|
||||
|
||||
// Add the pending contact - endpoint should be created and polled
|
||||
expectAddUnexpiredPendingContact(beforeExpiry);
|
||||
expectAddPendingContact(beforeExpiry, WAITING_FOR_CONNECTION);
|
||||
expectDeriveRendezvousKey();
|
||||
expectCreateEndpoint();
|
||||
|
||||
@@ -205,9 +206,7 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
|
||||
context.assertIsSatisfied();
|
||||
|
||||
// Remove the pending contact - endpoint should be closed
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(rendezvousEndpoint).close();
|
||||
}});
|
||||
expectCloseEndpoint();
|
||||
|
||||
rendezvousPoller.eventOccurred(
|
||||
new PendingContactRemovedEvent(pendingContact.getId()));
|
||||
@@ -238,7 +237,7 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
|
||||
context.assertIsSatisfied();
|
||||
|
||||
// Add the pending contact - endpoint should be created and polled
|
||||
expectAddUnexpiredPendingContact(beforeExpiry);
|
||||
expectAddPendingContact(beforeExpiry, WAITING_FOR_CONNECTION);
|
||||
expectDeriveRendezvousKey();
|
||||
expectCreateEndpoint();
|
||||
|
||||
@@ -260,10 +259,7 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
|
||||
|
||||
// Run the poll task - pending contact expires, endpoint is closed
|
||||
expectPendingContactExpires(afterExpiry);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(rendezvousEndpoint).close();
|
||||
}});
|
||||
expectCloseEndpoint();
|
||||
|
||||
capturePollTask.get().run();
|
||||
context.assertIsSatisfied();
|
||||
@@ -289,7 +285,7 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
|
||||
context.assertIsSatisfied();
|
||||
|
||||
// Add the pending contact - no endpoints should be created yet
|
||||
expectAddUnexpiredPendingContact(beforeExpiry);
|
||||
expectAddPendingContact(beforeExpiry, OFFLINE);
|
||||
expectDeriveRendezvousKey();
|
||||
|
||||
rendezvousPoller.eventOccurred(
|
||||
@@ -299,14 +295,14 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
|
||||
// Enable the transport - endpoint should be created
|
||||
expectGetPlugin();
|
||||
expectCreateEndpoint();
|
||||
expectStateChangedEvent(WAITING_FOR_CONNECTION);
|
||||
|
||||
rendezvousPoller.eventOccurred(new TransportEnabledEvent(transportId));
|
||||
context.assertIsSatisfied();
|
||||
|
||||
// Disable the transport - endpoint should be closed
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(rendezvousEndpoint).close();
|
||||
}});
|
||||
expectCloseEndpoint();
|
||||
expectStateChangedEvent(OFFLINE);
|
||||
|
||||
rendezvousPoller.eventOccurred(new TransportDisabledEvent(transportId));
|
||||
context.assertIsSatisfied();
|
||||
@@ -482,13 +478,14 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
|
||||
return capturePollTask;
|
||||
}
|
||||
|
||||
private void expectAddUnexpiredPendingContact(long now) {
|
||||
private void expectAddPendingContact(long now,
|
||||
PendingContactState initialState) {
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(clock).currentTimeMillis();
|
||||
will(returnValue(now));
|
||||
oneOf(eventBus).broadcast(with(new PredicateMatcher<>(
|
||||
PendingContactStateChangedEvent.class, e ->
|
||||
e.getPendingContactState() == WAITING_FOR_CONNECTION)));
|
||||
e.getPendingContactState() == initialState)));
|
||||
}});
|
||||
}
|
||||
|
||||
@@ -546,7 +543,7 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
|
||||
will(returnValue(now));
|
||||
oneOf(eventBus).broadcast(with(new PredicateMatcher<>(
|
||||
PendingContactStateChangedEvent.class, e ->
|
||||
e.getPendingContactState() == WAITING_FOR_CONNECTION)));
|
||||
e.getPendingContactState() == OFFLINE)));
|
||||
// Capture the poll task
|
||||
oneOf(scheduler).scheduleAtFixedRate(with(any(Runnable.class)),
|
||||
with(POLLING_INTERVAL_MS), with(POLLING_INTERVAL_MS),
|
||||
@@ -576,4 +573,10 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
|
||||
e.getPendingContactState() == state)));
|
||||
}});
|
||||
}
|
||||
|
||||
private void expectCloseEndpoint() throws Exception {
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(rendezvousEndpoint).close();
|
||||
}});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,11 @@ class PendingContactViewHolder extends ViewHolder {
|
||||
.getColor(status.getContext(), R.color.briar_yellow);
|
||||
status.setText(R.string.waiting_for_contact_to_come_online);
|
||||
break;
|
||||
case OFFLINE:
|
||||
color = ContextCompat
|
||||
.getColor(status.getContext(), R.color.briar_yellow);
|
||||
status.setText("");
|
||||
break;
|
||||
case CONNECTING:
|
||||
status.setText(R.string.connecting);
|
||||
break;
|
||||
|
||||
@@ -131,6 +131,7 @@ This will return a JSON array of pending contacts and their states:
|
||||
The state can be one of these values:
|
||||
|
||||
* `waiting_for_connection`
|
||||
* `offline`
|
||||
* `connecting`
|
||||
* `adding_contact`
|
||||
* `failed`
|
||||
|
||||
@@ -16,6 +16,7 @@ internal fun PendingContact.output() = JsonDict(
|
||||
|
||||
internal fun PendingContactState.output() = when(this) {
|
||||
WAITING_FOR_CONNECTION -> "waiting_for_connection"
|
||||
OFFLINE -> "offline"
|
||||
CONNECTING -> "connecting"
|
||||
ADDING_CONTACT -> "adding_contact"
|
||||
FAILED -> "failed"
|
||||
|
||||
Reference in New Issue
Block a user