diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxSettingsManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxSettingsManager.java index ab9e96d5e..33c97ee76 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxSettingsManager.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxSettingsManager.java @@ -15,4 +15,12 @@ public interface MailboxSettingsManager { void setOwnMailboxProperties(Transaction txn, MailboxProperties p) throws DbException; + + MailboxStatus getOwnMailboxStatus(Transaction txn) throws DbException; + + void recordSuccessfulConnection(Transaction txn, long now) + throws DbException; + + void recordFailedConnectionAttempt(Transaction txn, long now) + throws DbException; } diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxStatus.java b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxStatus.java new file mode 100644 index 000000000..40d566b44 --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxStatus.java @@ -0,0 +1,59 @@ +package org.briarproject.bramble.api.mailbox; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +public class MailboxStatus { + + private final long lastAttempt, lastSuccess; + private final int attemptsSinceSuccess; + + public MailboxStatus(long lastAttempt, long lastSuccess, + int attemptsSinceSuccess) { + this.lastAttempt = lastAttempt; + this.lastSuccess = lastSuccess; + this.attemptsSinceSuccess = attemptsSinceSuccess; + } + + /** + * Returns the time of the last attempt to connect to the mailbox, in + * milliseconds since the Unix epoch, or -1 if no attempt has been made. + *

+ * If an attempt is in progress and has not yet succeeded or failed then + * this method returns the time of the previous attempt, or -1 if the + * current attempt is the first. + */ + public long getTimeOfLastAttempt() { + return lastAttempt; + } + + /** + * Returns the time of the last successful attempt to connect to the + * mailbox, in milliseconds since the Unix epoch, or -1 if no attempt has + * succeeded. + *

+ * If the last attempt was successful then this method returns the same + * value as {@link #getTimeOfLastAttempt()}. If an attempt is in progress + * and has not yet succeeded or failed then this method returns the time + * of the previous successful connection, or -1 if no attempt has + * succeeded. + */ + public long getTimeOfLastSuccess() { + return lastSuccess; + } + + /** + * Returns the number of attempts to connect to the mailbox that have + * failed since the last attempt succeeded, or the number of attempts that + * have been made, if no attempt has ever succeeded. + *

+ * If an attempt is in progress and has not yet succeeded or failed then + * it is not included in this count. + */ + public int getAttemptsSinceSuccess() { + return attemptsSinceSuccess; + } +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxSettingsManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxSettingsManagerImpl.java index f9b7c953e..4c8478269 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxSettingsManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxSettingsManagerImpl.java @@ -4,6 +4,7 @@ import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.mailbox.MailboxProperties; import org.briarproject.bramble.api.mailbox.MailboxSettingsManager; +import org.briarproject.bramble.api.mailbox.MailboxStatus; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.settings.Settings; import org.briarproject.bramble.api.settings.SettingsManager; @@ -21,6 +22,9 @@ class MailboxSettingsManagerImpl implements MailboxSettingsManager { static final String SETTINGS_NAMESPACE = "mailbox"; static final String SETTINGS_KEY_ONION = "onion"; static final String SETTINGS_KEY_TOKEN = "token"; + static final String SETTINGS_KEY_LAST_ATTEMPT = "lastAttempt"; + static final String SETTINGS_KEY_LAST_SUCCESS = "lastSuccess"; + static final String SETTINGS_KEY_ATTEMPTS = "attempts"; private final SettingsManager settingsManager; @@ -47,4 +51,36 @@ class MailboxSettingsManagerImpl implements MailboxSettingsManager { s.put(SETTINGS_KEY_TOKEN, p.getAuthToken()); settingsManager.mergeSettings(txn, s, SETTINGS_NAMESPACE); } + + @Override + public MailboxStatus getOwnMailboxStatus(Transaction txn) + throws DbException { + Settings s = settingsManager.getSettings(txn, SETTINGS_NAMESPACE); + long lastAttempt = s.getLong(SETTINGS_KEY_LAST_ATTEMPT, -1); + long lastSuccess = s.getLong(SETTINGS_KEY_LAST_SUCCESS, -1); + int attempts = s.getInt(SETTINGS_KEY_ATTEMPTS, 0); + return new MailboxStatus(lastAttempt, lastSuccess, attempts); + } + + @Override + public void recordSuccessfulConnection(Transaction txn, long now) + throws DbException { + Settings s = new Settings(); + s.putLong(SETTINGS_KEY_LAST_ATTEMPT, now); + s.putLong(SETTINGS_KEY_LAST_SUCCESS, now); + s.putInt(SETTINGS_KEY_ATTEMPTS, 0); + settingsManager.mergeSettings(txn, s, SETTINGS_NAMESPACE); + } + + @Override + public void recordFailedConnectionAttempt(Transaction txn, long now) + throws DbException { + Settings oldSettings = + settingsManager.getSettings(txn, SETTINGS_NAMESPACE); + int attempts = oldSettings.getInt(SETTINGS_KEY_ATTEMPTS, 0); + Settings newSettings = new Settings(); + newSettings.putLong(SETTINGS_KEY_LAST_ATTEMPT, now); + newSettings.putInt(SETTINGS_KEY_ATTEMPTS, attempts + 1); + settingsManager.mergeSettings(txn, newSettings, SETTINGS_NAMESPACE); + } } diff --git a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxSettingsManagerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxSettingsManagerImplTest.java index 7380bcc1a..7187b6a87 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxSettingsManagerImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxSettingsManagerImplTest.java @@ -3,12 +3,16 @@ package org.briarproject.bramble.mailbox; import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.mailbox.MailboxProperties; import org.briarproject.bramble.api.mailbox.MailboxSettingsManager; +import org.briarproject.bramble.api.mailbox.MailboxStatus; import org.briarproject.bramble.api.settings.Settings; import org.briarproject.bramble.api.settings.SettingsManager; import org.briarproject.bramble.test.BrambleMockTestCase; import org.jmock.Expectations; import org.junit.Test; +import static org.briarproject.bramble.mailbox.MailboxSettingsManagerImpl.SETTINGS_KEY_ATTEMPTS; +import static org.briarproject.bramble.mailbox.MailboxSettingsManagerImpl.SETTINGS_KEY_LAST_ATTEMPT; +import static org.briarproject.bramble.mailbox.MailboxSettingsManagerImpl.SETTINGS_KEY_LAST_SUCCESS; import static org.briarproject.bramble.mailbox.MailboxSettingsManagerImpl.SETTINGS_KEY_ONION; import static org.briarproject.bramble.mailbox.MailboxSettingsManagerImpl.SETTINGS_KEY_TOKEN; import static org.briarproject.bramble.mailbox.MailboxSettingsManagerImpl.SETTINGS_NAMESPACE; @@ -27,9 +31,13 @@ public class MailboxSettingsManagerImplTest extends BrambleMockTestCase { new MailboxSettingsManagerImpl(settingsManager); private final String onion = getRandomString(64); private final String token = getRandomString(64); + private final long now = System.currentTimeMillis(); + private final long lastAttempt = now - 1234; + private final long lastSuccess = now - 2345; + private final int attempts = 123; @Test - public void testReturnsNullIfSettingsAreEmpty() throws Exception { + public void testReturnsNullPropertiesIfSettingsAreEmpty() throws Exception { Transaction txn = new Transaction(null, true); Settings emptySettings = new Settings(); @@ -76,4 +84,86 @@ public class MailboxSettingsManagerImplTest extends BrambleMockTestCase { manager.setOwnMailboxProperties(txn, properties); } + + @Test + public void testReturnsDefaultStatusIfSettingsAreEmpty() throws Exception { + Transaction txn = new Transaction(null, true); + Settings emptySettings = new Settings(); + + context.checking(new Expectations() {{ + oneOf(settingsManager).getSettings(txn, SETTINGS_NAMESPACE); + will(returnValue(emptySettings)); + }}); + + MailboxStatus status = manager.getOwnMailboxStatus(txn); + assertEquals(-1, status.getTimeOfLastAttempt()); + assertEquals(-1, status.getTimeOfLastSuccess()); + assertEquals(0, status.getAttemptsSinceSuccess()); + } + + @Test + public void testReturnsStatus() throws Exception { + Transaction txn = new Transaction(null, true); + Settings settings = new Settings(); + settings.putLong(SETTINGS_KEY_LAST_ATTEMPT, lastAttempt); + settings.putLong(SETTINGS_KEY_LAST_SUCCESS, lastSuccess); + settings.putInt(SETTINGS_KEY_ATTEMPTS, attempts); + + context.checking(new Expectations() {{ + oneOf(settingsManager).getSettings(txn, SETTINGS_NAMESPACE); + will(returnValue(settings)); + }}); + + MailboxStatus status = manager.getOwnMailboxStatus(txn); + assertEquals(lastAttempt, status.getTimeOfLastAttempt()); + assertEquals(lastSuccess, status.getTimeOfLastSuccess()); + assertEquals(attempts, status.getAttemptsSinceSuccess()); + } + + @Test + public void testRecordsSuccess() throws Exception { + Transaction txn = new Transaction(null, false); + Settings expectedSettings = new Settings(); + expectedSettings.putLong(SETTINGS_KEY_LAST_ATTEMPT, now); + expectedSettings.putLong(SETTINGS_KEY_LAST_SUCCESS, now); + expectedSettings.putInt(SETTINGS_KEY_ATTEMPTS, 0); + + context.checking(new Expectations() {{ + oneOf(settingsManager).mergeSettings(txn, expectedSettings, + SETTINGS_NAMESPACE); + }}); + + manager.recordSuccessfulConnection(txn, now); + } + + @Test + public void testRecordsFailureOnFirstAttempt() throws Exception { + testRecordsFailure(new Settings(), 0); + } + + @Test + public void testRecordsFailureOnLaterAttempt() throws Exception { + Settings oldSettings = new Settings(); + oldSettings.putLong(SETTINGS_KEY_LAST_ATTEMPT, lastAttempt); + oldSettings.putLong(SETTINGS_KEY_LAST_SUCCESS, lastSuccess); + oldSettings.putInt(SETTINGS_KEY_ATTEMPTS, attempts); + testRecordsFailure(oldSettings, attempts); + } + + private void testRecordsFailure(Settings oldSettings, int oldAttempts) + throws Exception { + Transaction txn = new Transaction(null, false); + Settings expectedSettings = new Settings(); + expectedSettings.putLong(SETTINGS_KEY_LAST_ATTEMPT, now); + expectedSettings.putInt(SETTINGS_KEY_ATTEMPTS, oldAttempts + 1); + + context.checking(new Expectations() {{ + oneOf(settingsManager).getSettings(txn, SETTINGS_NAMESPACE); + will(returnValue(oldSettings)); + oneOf(settingsManager).mergeSettings(txn, expectedSettings, + SETTINGS_NAMESPACE); + }}); + + manager.recordFailedConnectionAttempt(txn, now); + } }