Skip to content
Snippets Groups Projects
Verified Commit b0e97d78 authored by akwizgran's avatar akwizgran
Browse files

Add offline state for pending contacts.

parent 9c20e6b3
No related branches found
No related tags found
1 merge request!1138Add offline state for pending contacts
Pipeline #3565 failed
...@@ -3,6 +3,7 @@ package org.briarproject.bramble.api.contact; ...@@ -3,6 +3,7 @@ package org.briarproject.bramble.api.contact;
public enum PendingContactState { public enum PendingContactState {
WAITING_FOR_CONNECTION, WAITING_FOR_CONNECTION,
OFFLINE,
CONNECTING, CONNECTING,
ADDING_CONTACT, ADDING_CONTACT,
FAILED FAILED
......
...@@ -66,6 +66,7 @@ import static java.util.logging.Level.WARNING; ...@@ -66,6 +66,7 @@ import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger; 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.ADDING_CONTACT;
import static org.briarproject.bramble.api.contact.PendingContactState.FAILED; 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.contact.PendingContactState.WAITING_FOR_CONNECTION;
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNull; import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNull;
import static org.briarproject.bramble.rendezvous.RendezvousConstants.POLLING_INTERVAL_MS; import static org.briarproject.bramble.rendezvous.RendezvousConstants.POLLING_INTERVAL_MS;
...@@ -158,9 +159,7 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener { ...@@ -158,9 +159,7 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
private void addPendingContact(PendingContact p) { private void addPendingContact(PendingContact p) {
long now = clock.currentTimeMillis(); long now = clock.currentTimeMillis();
long expiry = p.getTimestamp() + RENDEZVOUS_TIMEOUT_MS; long expiry = p.getTimestamp() + RENDEZVOUS_TIMEOUT_MS;
if (expiry > now) { if (expiry <= now) {
broadcastState(p.getId(), WAITING_FOR_CONNECTION);
} else {
broadcastState(p.getId(), FAILED); broadcastState(p.getId(), FAILED);
return; return;
} }
...@@ -180,9 +179,13 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener { ...@@ -180,9 +179,13 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
for (PluginState ps : pluginStates.values()) { for (PluginState ps : pluginStates.values()) {
RendezvousEndpoint endpoint = RendezvousEndpoint endpoint =
createEndpoint(ps.plugin, p.getId(), cs); createEndpoint(ps.plugin, p.getId(), cs);
if (endpoint != null) if (endpoint != null) {
requireNull(ps.endpoints.put(p.getId(), endpoint)); requireNull(ps.endpoints.put(p.getId(), endpoint));
cs.endpoints++;
}
} }
if (cs.endpoints == 0) broadcastState(p.getId(), OFFLINE);
else broadcastState(p.getId(), WAITING_FOR_CONNECTION);
} catch (DbException | GeneralSecurityException e) { } catch (DbException | GeneralSecurityException e) {
logException(LOG, WARNING, e); logException(LOG, WARNING, e);
} }
...@@ -328,9 +331,14 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener { ...@@ -328,9 +331,14 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
TransportId t = plugin.getId(); TransportId t = plugin.getId();
Map<PendingContactId, RendezvousEndpoint> endpoints = new HashMap<>(); Map<PendingContactId, RendezvousEndpoint> endpoints = new HashMap<>();
for (Entry<PendingContactId, CryptoState> e : cryptoStates.entrySet()) { for (Entry<PendingContactId, CryptoState> e : cryptoStates.entrySet()) {
RendezvousEndpoint endpoint = PendingContactId p = e.getKey();
createEndpoint(plugin, e.getKey(), e.getValue()); CryptoState cs = e.getValue();
if (endpoint != null) endpoints.put(e.getKey(), endpoint); RendezvousEndpoint endpoint = createEndpoint(plugin, p, cs);
if (endpoint != null) {
endpoints.put(p, endpoint);
if (++cs.endpoints == 1)
broadcastState(p, WAITING_FOR_CONNECTION);
}
} }
requireNull(pluginStates.put(t, new PluginState(plugin, endpoints))); requireNull(pluginStates.put(t, new PluginState(plugin, endpoints)));
} }
...@@ -344,8 +352,11 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener { ...@@ -344,8 +352,11 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
private void removeTransport(TransportId t) { private void removeTransport(TransportId t) {
PluginState ps = pluginStates.remove(t); PluginState ps = pluginStates.remove(t);
if (ps != null) { if (ps != null) {
for (RendezvousEndpoint endpoint : ps.endpoints.values()) { for (Entry<PendingContactId, RendezvousEndpoint> e :
tryToClose(endpoint, LOG, INFO); ps.endpoints.entrySet()) {
tryToClose(e.getValue(), LOG, INFO);
CryptoState cs = cryptoStates.get(e.getKey());
if (--cs.endpoints == 0) broadcastState(e.getKey(), OFFLINE);
} }
} }
} }
...@@ -391,6 +402,8 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener { ...@@ -391,6 +402,8 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
private final boolean alice; private final boolean alice;
private final long expiry; private final long expiry;
private int endpoints = 0;
private CryptoState(SecretKey rendezvousKey, boolean alice, private CryptoState(SecretKey rendezvousKey, boolean alice,
long expiry) { long expiry) {
this.rendezvousKey = rendezvousKey; this.rendezvousKey = rendezvousKey;
......
...@@ -45,6 +45,7 @@ import static java.util.Collections.singletonList; ...@@ -45,6 +45,7 @@ import static java.util.Collections.singletonList;
import static java.util.concurrent.TimeUnit.MILLISECONDS; 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.ADDING_CONTACT;
import static org.briarproject.bramble.api.contact.PendingContactState.FAILED; 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.contact.PendingContactState.WAITING_FOR_CONNECTION;
import static org.briarproject.bramble.rendezvous.RendezvousConstants.POLLING_INTERVAL_MS; import static org.briarproject.bramble.rendezvous.RendezvousConstants.POLLING_INTERVAL_MS;
import static org.briarproject.bramble.rendezvous.RendezvousConstants.RENDEZVOUS_TIMEOUT_MS; import static org.briarproject.bramble.rendezvous.RendezvousConstants.RENDEZVOUS_TIMEOUT_MS;
...@@ -120,7 +121,7 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase { ...@@ -120,7 +121,7 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
will(returnValue(beforeExpiry)); will(returnValue(beforeExpiry));
oneOf(eventBus).broadcast(with(new PredicateMatcher<>( oneOf(eventBus).broadcast(with(new PredicateMatcher<>(
PendingContactStateChangedEvent.class, e -> PendingContactStateChangedEvent.class, e ->
e.getPendingContactState() == WAITING_FOR_CONNECTION))); e.getPendingContactState() == OFFLINE)));
// Capture the poll task // Capture the poll task
oneOf(scheduler).scheduleAtFixedRate(with(any(Runnable.class)), oneOf(scheduler).scheduleAtFixedRate(with(any(Runnable.class)),
with(POLLING_INTERVAL_MS), with(POLLING_INTERVAL_MS), with(POLLING_INTERVAL_MS), with(POLLING_INTERVAL_MS),
...@@ -184,7 +185,7 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase { ...@@ -184,7 +185,7 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
context.assertIsSatisfied(); context.assertIsSatisfied();
// Add the pending contact - endpoint should be created and polled // Add the pending contact - endpoint should be created and polled
expectAddUnexpiredPendingContact(beforeExpiry); expectAddPendingContact(beforeExpiry, WAITING_FOR_CONNECTION);
expectDeriveRendezvousKey(); expectDeriveRendezvousKey();
expectCreateEndpoint(); expectCreateEndpoint();
...@@ -205,9 +206,7 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase { ...@@ -205,9 +206,7 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
context.assertIsSatisfied(); context.assertIsSatisfied();
// Remove the pending contact - endpoint should be closed // Remove the pending contact - endpoint should be closed
context.checking(new Expectations() {{ expectCloseEndpoint();
oneOf(rendezvousEndpoint).close();
}});
rendezvousPoller.eventOccurred( rendezvousPoller.eventOccurred(
new PendingContactRemovedEvent(pendingContact.getId())); new PendingContactRemovedEvent(pendingContact.getId()));
...@@ -238,7 +237,7 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase { ...@@ -238,7 +237,7 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
context.assertIsSatisfied(); context.assertIsSatisfied();
// Add the pending contact - endpoint should be created and polled // Add the pending contact - endpoint should be created and polled
expectAddUnexpiredPendingContact(beforeExpiry); expectAddPendingContact(beforeExpiry, WAITING_FOR_CONNECTION);
expectDeriveRendezvousKey(); expectDeriveRendezvousKey();
expectCreateEndpoint(); expectCreateEndpoint();
...@@ -260,10 +259,7 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase { ...@@ -260,10 +259,7 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
// Run the poll task - pending contact expires, endpoint is closed // Run the poll task - pending contact expires, endpoint is closed
expectPendingContactExpires(afterExpiry); expectPendingContactExpires(afterExpiry);
expectCloseEndpoint();
context.checking(new Expectations() {{
oneOf(rendezvousEndpoint).close();
}});
capturePollTask.get().run(); capturePollTask.get().run();
context.assertIsSatisfied(); context.assertIsSatisfied();
...@@ -289,7 +285,7 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase { ...@@ -289,7 +285,7 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
context.assertIsSatisfied(); context.assertIsSatisfied();
// Add the pending contact - no endpoints should be created yet // Add the pending contact - no endpoints should be created yet
expectAddUnexpiredPendingContact(beforeExpiry); expectAddPendingContact(beforeExpiry, OFFLINE);
expectDeriveRendezvousKey(); expectDeriveRendezvousKey();
rendezvousPoller.eventOccurred( rendezvousPoller.eventOccurred(
...@@ -299,14 +295,14 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase { ...@@ -299,14 +295,14 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
// Enable the transport - endpoint should be created // Enable the transport - endpoint should be created
expectGetPlugin(); expectGetPlugin();
expectCreateEndpoint(); expectCreateEndpoint();
expectStateChangedEvent(WAITING_FOR_CONNECTION);
rendezvousPoller.eventOccurred(new TransportEnabledEvent(transportId)); rendezvousPoller.eventOccurred(new TransportEnabledEvent(transportId));
context.assertIsSatisfied(); context.assertIsSatisfied();
// Disable the transport - endpoint should be closed // Disable the transport - endpoint should be closed
context.checking(new Expectations() {{ expectCloseEndpoint();
oneOf(rendezvousEndpoint).close(); expectStateChangedEvent(OFFLINE);
}});
rendezvousPoller.eventOccurred(new TransportDisabledEvent(transportId)); rendezvousPoller.eventOccurred(new TransportDisabledEvent(transportId));
context.assertIsSatisfied(); context.assertIsSatisfied();
...@@ -482,13 +478,14 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase { ...@@ -482,13 +478,14 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
return capturePollTask; return capturePollTask;
} }
private void expectAddUnexpiredPendingContact(long now) { private void expectAddPendingContact(long now,
PendingContactState initialState) {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(clock).currentTimeMillis(); oneOf(clock).currentTimeMillis();
will(returnValue(now)); will(returnValue(now));
oneOf(eventBus).broadcast(with(new PredicateMatcher<>( oneOf(eventBus).broadcast(with(new PredicateMatcher<>(
PendingContactStateChangedEvent.class, e -> PendingContactStateChangedEvent.class, e ->
e.getPendingContactState() == WAITING_FOR_CONNECTION))); e.getPendingContactState() == initialState)));
}}); }});
} }
...@@ -546,7 +543,7 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase { ...@@ -546,7 +543,7 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
will(returnValue(now)); will(returnValue(now));
oneOf(eventBus).broadcast(with(new PredicateMatcher<>( oneOf(eventBus).broadcast(with(new PredicateMatcher<>(
PendingContactStateChangedEvent.class, e -> PendingContactStateChangedEvent.class, e ->
e.getPendingContactState() == WAITING_FOR_CONNECTION))); e.getPendingContactState() == OFFLINE)));
// Capture the poll task // Capture the poll task
oneOf(scheduler).scheduleAtFixedRate(with(any(Runnable.class)), oneOf(scheduler).scheduleAtFixedRate(with(any(Runnable.class)),
with(POLLING_INTERVAL_MS), with(POLLING_INTERVAL_MS), with(POLLING_INTERVAL_MS), with(POLLING_INTERVAL_MS),
...@@ -576,4 +573,10 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase { ...@@ -576,4 +573,10 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
e.getPendingContactState() == state))); e.getPendingContactState() == state)));
}}); }});
} }
private void expectCloseEndpoint() throws Exception {
context.checking(new Expectations() {{
oneOf(rendezvousEndpoint).close();
}});
}
} }
...@@ -52,6 +52,11 @@ class PendingContactViewHolder extends ViewHolder { ...@@ -52,6 +52,11 @@ class PendingContactViewHolder extends ViewHolder {
.getColor(status.getContext(), R.color.briar_yellow); .getColor(status.getContext(), R.color.briar_yellow);
status.setText(R.string.waiting_for_contact_to_come_online); status.setText(R.string.waiting_for_contact_to_come_online);
break; break;
case OFFLINE:
color = ContextCompat
.getColor(status.getContext(), R.color.briar_yellow);
status.setText(R.string.offline_state);
break;
case CONNECTING: case CONNECTING:
status.setText(R.string.connecting); status.setText(R.string.connecting);
break; break;
......
...@@ -131,6 +131,7 @@ This will return a JSON array of pending contacts and their states: ...@@ -131,6 +131,7 @@ This will return a JSON array of pending contacts and their states:
The state can be one of these values: The state can be one of these values:
* `waiting_for_connection` * `waiting_for_connection`
* `offline`
* `connecting` * `connecting`
* `adding_contact` * `adding_contact`
* `failed` * `failed`
......
...@@ -16,6 +16,7 @@ internal fun PendingContact.output() = JsonDict( ...@@ -16,6 +16,7 @@ internal fun PendingContact.output() = JsonDict(
internal fun PendingContactState.output() = when(this) { internal fun PendingContactState.output() = when(this) {
WAITING_FOR_CONNECTION -> "waiting_for_connection" WAITING_FOR_CONNECTION -> "waiting_for_connection"
OFFLINE -> "offline"
CONNECTING -> "connecting" CONNECTING -> "connecting"
ADDING_CONTACT -> "adding_contact" ADDING_CONTACT -> "adding_contact"
FAILED -> "failed" FAILED -> "failed"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment