Allow observers to be removed.

This commit is contained in:
akwizgran
2022-05-27 16:34:26 +01:00
parent 2b4a1cf54b
commit 9aacd9d3d8
5 changed files with 64 additions and 2 deletions

View File

@@ -22,10 +22,21 @@ interface ConnectivityChecker {
* the check succeeds. If a check is already running then the observer is * the check succeeds. If a check is already running then the observer is
* called when the check succeeds. If a connectivity check has recently * called when the check succeeds. If a connectivity check has recently
* succeeded then the observer is called immediately. * succeeded then the observer is called immediately.
* <p>
* Observers are removed after being called, or when the checker is
* {@link #destroy() destroyed}.
*/ */
void checkConnectivity(MailboxProperties properties, void checkConnectivity(MailboxProperties properties,
ConnectivityObserver o); ConnectivityObserver o);
/**
* Removes an observer that was added via
* {@link #checkConnectivity(MailboxProperties, ConnectivityObserver)}. If
* there are no remaining observers and a connectivity check is running
* then the check will be cancelled.
*/
void removeObserver(ConnectivityObserver o);
interface ConnectivityObserver { interface ConnectivityObserver {
void onConnectivityCheckSucceeded(); void onConnectivityCheckSucceeded();
} }

View File

@@ -80,8 +80,7 @@ abstract class ConnectivityCheckerImpl implements ConnectivityChecker {
> CONNECTIVITY_CHECK_FRESHNESS_MS) { > CONNECTIVITY_CHECK_FRESHNESS_MS) {
// The last connectivity check is stale, start a new one // The last connectivity check is stale, start a new one
connectivityObservers.add(o); connectivityObservers.add(o);
ApiCall task = ApiCall task = createConnectivityCheckTask(properties);
createConnectivityCheckTask(properties);
connectivityCheck = mailboxApiCaller.retryWithBackoff(task); connectivityCheck = mailboxApiCaller.retryWithBackoff(task);
} else { } else {
// The last connectivity check is fresh // The last connectivity check is fresh
@@ -108,4 +107,16 @@ abstract class ConnectivityCheckerImpl implements ConnectivityChecker {
o.onConnectivityCheckSucceeded(); o.onConnectivityCheckSucceeded();
} }
} }
@Override
public void removeObserver(ConnectivityObserver o) {
synchronized (lock) {
if (destroyed) return;
connectivityObservers.remove(o);
if (connectivityObservers.isEmpty() && connectivityCheck != null) {
connectivityCheck.cancel();
connectivityCheck = null;
}
}
}
} }

View File

@@ -38,6 +38,12 @@ interface TorReachabilityMonitor {
*/ */
void addOneShotObserver(TorReachabilityObserver o); void addOneShotObserver(TorReachabilityObserver o);
/**
* Removes an observer that was added via
* {@link #addOneShotObserver(TorReachabilityObserver)}.
*/
void removeObserver(TorReachabilityObserver o);
interface TorReachabilityObserver { interface TorReachabilityObserver {
void onTorReachable(); void onTorReachable();

View File

@@ -87,6 +87,14 @@ class TorReachabilityMonitorImpl
if (callNow) o.onTorReachable(); if (callNow) o.onTorReachable();
} }
@Override
public void removeObserver(TorReachabilityObserver o) {
synchronized (lock) {
if (destroyed) return;
observers.remove(o);
}
}
@Override @Override
public void eventOccurred(Event e) { public void eventOccurred(Event e) {
if (e instanceof TransportActiveEvent) { if (e instanceof TransportActiveEvent) {

View File

@@ -187,6 +187,32 @@ public class ConnectivityCheckerImplTest extends BrambleMockTestCase {
checker.onConnectivityCheckSucceeded(now); checker.onConnectivityCheckSucceeded(now);
} }
@Test
public void testCheckIsCancelledWhenObserverIsRemoved() {
ConnectivityCheckerImpl checker = createChecker();
// When checkConnectivity() is called a check should be started
context.checking(new Expectations() {{
oneOf(clock).currentTimeMillis();
will(returnValue(now));
oneOf(mailboxApiCaller).retryWithBackoff(apiCall);
will(returnValue(task));
}});
checker.checkConnectivity(properties, observer1);
// When the observer is removed the check should be cancelled
context.checking(new Expectations() {{
oneOf(task).cancel();
}});
checker.removeObserver(observer1);
// If the check runs anyway (cancellation came too late) the observer
// should not be called
checker.onConnectivityCheckSucceeded(now);
}
private ConnectivityCheckerImpl createChecker() { private ConnectivityCheckerImpl createChecker() {
return new ConnectivityCheckerImpl(clock, mailboxApiCaller) { return new ConnectivityCheckerImpl(clock, mailboxApiCaller) {