Add mailbox client for our own mailbox.

This commit is contained in:
akwizgran
2022-07-15 18:00:13 +01:00
parent 0865a06ac8
commit 8982964fbf
6 changed files with 370 additions and 7 deletions

View File

@@ -10,7 +10,6 @@ import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import javax.inject.Inject;
import static java.util.logging.Logger.getLogger;
@@ -30,7 +29,6 @@ class ContactMailboxClient implements MailboxClient {
@Nullable
private MailboxWorker uploadWorker = null, downloadWorker = null;
@Inject
ContactMailboxClient(MailboxWorkerFactory workerFactory,
ConnectivityChecker connectivityChecker,
TorReachabilityMonitor reachabilityMonitor) {

View File

@@ -24,4 +24,8 @@ interface MailboxWorkerFactory {
ConnectivityChecker connectivityChecker,
TorReachabilityMonitor reachabilityMonitor,
MailboxProperties properties);
MailboxWorker createContactListWorkerForOwnMailbox(
ConnectivityChecker connectivityChecker,
MailboxProperties properties);
}

View File

@@ -6,6 +6,7 @@ import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.mailbox.MailboxFolderId;
import org.briarproject.bramble.api.mailbox.MailboxProperties;
import org.briarproject.bramble.api.mailbox.MailboxUpdateManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.TaskScheduler;
@@ -27,6 +28,7 @@ class MailboxWorkerFactoryImpl implements MailboxWorkerFactory {
private final MailboxApiCaller mailboxApiCaller;
private final MailboxApi mailboxApi;
private final MailboxFileManager mailboxFileManager;
private final MailboxUpdateManager mailboxUpdateManager;
@Inject
MailboxWorkerFactoryImpl(@IoExecutor Executor ioExecutor,
@@ -36,7 +38,8 @@ class MailboxWorkerFactoryImpl implements MailboxWorkerFactory {
EventBus eventBus,
MailboxApiCaller mailboxApiCaller,
MailboxApi mailboxApi,
MailboxFileManager mailboxFileManager) {
MailboxFileManager mailboxFileManager,
MailboxUpdateManager mailboxUpdateManager) {
this.ioExecutor = ioExecutor;
this.db = db;
this.clock = clock;
@@ -45,6 +48,7 @@ class MailboxWorkerFactoryImpl implements MailboxWorkerFactory {
this.mailboxApiCaller = mailboxApiCaller;
this.mailboxApi = mailboxApi;
this.mailboxFileManager = mailboxFileManager;
this.mailboxUpdateManager = mailboxUpdateManager;
}
@Override
@@ -75,7 +79,17 @@ class MailboxWorkerFactoryImpl implements MailboxWorkerFactory {
ConnectivityChecker connectivityChecker,
TorReachabilityMonitor reachabilityMonitor,
MailboxProperties properties) {
// TODO
throw new UnsupportedOperationException();
return new OwnMailboxDownloadWorker(connectivityChecker,
reachabilityMonitor, mailboxApiCaller, mailboxApi,
mailboxFileManager, properties);
}
@Override
public MailboxWorker createContactListWorkerForOwnMailbox(
ConnectivityChecker connectivityChecker,
MailboxProperties properties) {
return new OwnMailboxContactListWorker(ioExecutor, db, eventBus,
connectivityChecker, mailboxApiCaller, mailboxApi,
mailboxUpdateManager, properties);
}
}

View File

@@ -0,0 +1,139 @@
package org.briarproject.bramble.mailbox;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.mailbox.MailboxFolderId;
import org.briarproject.bramble.api.mailbox.MailboxProperties;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import static java.util.logging.Logger.getLogger;
@ThreadSafe
@NotNullByDefault
class OwnMailboxClient implements MailboxClient {
private static final Logger LOG =
getLogger(OwnMailboxClient.class.getName());
private final MailboxWorkerFactory workerFactory;
private final ConnectivityChecker connectivityChecker;
private final TorReachabilityMonitor reachabilityMonitor;
private final MailboxWorker contactListWorker;
private final Object lock = new Object();
@GuardedBy("lock")
private final Map<ContactId, MailboxWorker> uploadWorkers = new HashMap<>();
@GuardedBy("lock")
@Nullable
private MailboxWorker downloadWorker = null;
@GuardedBy("lock")
private final Set<ContactId> assignedForDownload = new HashSet<>();
OwnMailboxClient(MailboxWorkerFactory workerFactory,
ConnectivityChecker connectivityChecker,
TorReachabilityMonitor reachabilityMonitor,
MailboxProperties properties) {
this.workerFactory = workerFactory;
this.connectivityChecker = connectivityChecker;
this.reachabilityMonitor = reachabilityMonitor;
contactListWorker = workerFactory.createContactListWorkerForOwnMailbox(
connectivityChecker, properties);
}
@Override
public void start() {
LOG.info("Started");
contactListWorker.start();
}
@Override
public void destroy() {
LOG.info("Destroyed");
List<MailboxWorker> uploadWorkers;
MailboxWorker downloadWorker;
synchronized (lock) {
uploadWorkers = new ArrayList<>(this.uploadWorkers.values());
this.uploadWorkers.clear();
downloadWorker = this.downloadWorker;
this.downloadWorker = null;
}
for (MailboxWorker worker : uploadWorkers) worker.destroy();
if (downloadWorker != null) downloadWorker.destroy();
contactListWorker.destroy();
}
@Override
public void assignContactForUpload(ContactId contactId,
MailboxProperties properties, MailboxFolderId folderId) {
LOG.info("Contact assigned for upload");
if (!properties.isOwner()) throw new IllegalArgumentException();
MailboxWorker uploadWorker = workerFactory.createUploadWorker(
connectivityChecker, properties, folderId, contactId);
synchronized (lock) {
MailboxWorker old = uploadWorkers.put(contactId, uploadWorker);
if (old != null) throw new IllegalStateException();
}
uploadWorker.start();
}
@Override
public void deassignContactForUpload(ContactId contactId) {
LOG.info("Contact deassigned for upload");
MailboxWorker uploadWorker;
synchronized (lock) {
uploadWorker = uploadWorkers.remove(contactId);
}
if (uploadWorker != null) uploadWorker.destroy();
}
@Override
public void assignContactForDownload(ContactId contactId,
MailboxProperties properties, MailboxFolderId folderId) {
LOG.info("Contact assigned for download");
if (!properties.isOwner()) throw new IllegalArgumentException();
MailboxWorker toStart = null;
synchronized (lock) {
if (!assignedForDownload.add(contactId)) {
throw new IllegalStateException();
}
// Create a download worker if we don't already have one
if (downloadWorker == null) {
toStart = workerFactory.createDownloadWorkerForOwnMailbox(
connectivityChecker, reachabilityMonitor, properties);
downloadWorker = toStart;
}
}
if (toStart != null) toStart.start();
}
@Override
public void deassignContactForDownload(ContactId contactId) {
LOG.info("Contact deassigned for download");
MailboxWorker toDestroy = null;
synchronized (lock) {
if (!assignedForDownload.remove(contactId)) {
throw new IllegalStateException();
}
// If there are no more contacts assigned for download, destroy
// the download worker
if (assignedForDownload.isEmpty()) {
toDestroy = downloadWorker;
downloadWorker = null;
}
}
if (toDestroy != null) toDestroy.destroy();
}
}

View File

@@ -75,7 +75,7 @@ public class ContactMailboxClientTest extends BrambleMockTestCase {
}
@Test
public void assignContactForDownloadAndDestroyClient() {
public void testAssignContactForDownloadAndDestroyClient() {
client.start();
// When the contact is assigned, the worker should be created and
@@ -89,7 +89,7 @@ public class ContactMailboxClientTest extends BrambleMockTestCase {
}
@Test
public void assignAndDeassignContactForDownload() {
public void testAssignAndDeassignContactForDownload() {
client.start();
// When the contact is assigned, the worker should be created and

View File

@@ -0,0 +1,208 @@
package org.briarproject.bramble.mailbox;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.mailbox.MailboxFolderId;
import org.briarproject.bramble.api.mailbox.MailboxProperties;
import org.briarproject.bramble.test.BrambleMockTestCase;
import org.jmock.Expectations;
import org.junit.Test;
import static org.briarproject.bramble.api.mailbox.MailboxConstants.CLIENT_SUPPORTS;
import static org.briarproject.bramble.test.TestUtils.getContactId;
import static org.briarproject.bramble.test.TestUtils.getMailboxProperties;
import static org.briarproject.bramble.test.TestUtils.getRandomId;
public class OwnMailboxClientTest extends BrambleMockTestCase {
private final MailboxWorkerFactory workerFactory =
context.mock(MailboxWorkerFactory.class);
private final ConnectivityChecker connectivityChecker =
context.mock(ConnectivityChecker.class);
private final TorReachabilityMonitor reachabilityMonitor =
context.mock(TorReachabilityMonitor.class);
private final MailboxWorker contactListWorker =
context.mock(MailboxWorker.class, "contactListWorker");
private final MailboxWorker uploadWorker1 =
context.mock(MailboxWorker.class, "uploadWorker1");
private final MailboxWorker uploadWorker2 =
context.mock(MailboxWorker.class, "uploadWorker2");
private final MailboxWorker downloadWorker =
context.mock(MailboxWorker.class, "downloadWorker");
private final MailboxProperties properties =
getMailboxProperties(true, CLIENT_SUPPORTS);
private final MailboxFolderId folderId = new MailboxFolderId(getRandomId());
private final ContactId contactId1 = getContactId();
private final ContactId contactId2 = getContactId();
private final OwnMailboxClient client;
public OwnMailboxClientTest() {
expectCreateContactListWorker();
client = new OwnMailboxClient(workerFactory, connectivityChecker,
reachabilityMonitor, properties);
context.assertIsSatisfied();
}
@Test
public void testStartAndDestroyWithNoContactsAssigned() {
expectStartWorker(contactListWorker);
client.start();
expectDestroyWorker(contactListWorker);
client.destroy();
}
@Test
public void testAssignContactForUploadAndDestroyClient() {
expectStartWorker(contactListWorker);
client.start();
// When the contact is assigned, the worker should be created and
// started
expectCreateUploadWorker(contactId1, uploadWorker1);
expectStartWorker(uploadWorker1);
client.assignContactForUpload(contactId1, properties, folderId);
// When the client is destroyed, the worker should be destroyed
expectDestroyWorker(uploadWorker1);
expectDestroyWorker(contactListWorker);
client.destroy();
}
@Test
public void testAssignAndDeassignContactForUpload() {
expectStartWorker(contactListWorker);
client.start();
// When the contact is assigned, the worker should be created and
// started
expectCreateUploadWorker(contactId1, uploadWorker1);
expectStartWorker(uploadWorker1);
client.assignContactForUpload(contactId1, properties, folderId);
// When the contact is deassigned, the worker should be destroyed
expectDestroyWorker(uploadWorker1);
client.deassignContactForUpload(contactId1);
context.assertIsSatisfied();
expectDestroyWorker(contactListWorker);
client.destroy();
}
@Test
public void testAssignAndDeassignTwoContactsForUpload() {
expectStartWorker(contactListWorker);
client.start();
// When the first contact is assigned, the first worker should be
// created and started
expectCreateUploadWorker(contactId1, uploadWorker1);
expectStartWorker(uploadWorker1);
client.assignContactForUpload(contactId1, properties, folderId);
// When the second contact is assigned, the second worker should be
// created and started
expectCreateUploadWorker(contactId2, uploadWorker2);
expectStartWorker(uploadWorker2);
client.assignContactForUpload(contactId2, properties, folderId);
// When the second contact is deassigned, the second worker should be
// destroyed
expectDestroyWorker(uploadWorker2);
client.deassignContactForUpload(contactId2);
context.assertIsSatisfied();
// When the first contact is deassigned, the first worker should be
// destroyed
expectDestroyWorker(uploadWorker1);
client.deassignContactForUpload(contactId1);
context.assertIsSatisfied();
expectDestroyWorker(contactListWorker);
client.destroy();
}
@Test
public void testAssignContactForDownloadAndDestroyClient() {
expectStartWorker(contactListWorker);
client.start();
// When the contact is assigned, the worker should be created and
// started
expectCreateDownloadWorker();
expectStartWorker(downloadWorker);
client.assignContactForDownload(contactId1, properties, folderId);
// When the client is destroyed, the worker should be destroyed
expectDestroyWorker(downloadWorker);
expectDestroyWorker(contactListWorker);
client.destroy();
}
@Test
public void testAssignAndDeassignTwoContactsForDownload() {
expectStartWorker(contactListWorker);
client.start();
// When the first contact is assigned, the worker should be created and
// started
expectCreateDownloadWorker();
expectStartWorker(downloadWorker);
client.assignContactForDownload(contactId1, properties, folderId);
// When the second contact is assigned, nothing should happen to the
// worker
client.assignContactForDownload(contactId2, properties, folderId);
// When the first contact is deassigned, nothing should happen to the
// worker
client.deassignContactForDownload(contactId1);
// When the second contact is deassigned, the worker should be
// destroyed
expectDestroyWorker(downloadWorker);
client.deassignContactForDownload(contactId2);
context.assertIsSatisfied();
expectDestroyWorker(contactListWorker);
client.destroy();
}
private void expectCreateContactListWorker() {
context.checking(new Expectations() {{
oneOf(workerFactory).createContactListWorkerForOwnMailbox(
connectivityChecker, properties);
will(returnValue(contactListWorker));
}});
}
private void expectCreateUploadWorker(ContactId contactId,
MailboxWorker worker) {
context.checking(new Expectations() {{
oneOf(workerFactory).createUploadWorker(connectivityChecker,
properties, folderId, contactId);
will(returnValue(worker));
}});
}
private void expectCreateDownloadWorker() {
context.checking(new Expectations() {{
oneOf(workerFactory).createDownloadWorkerForOwnMailbox(
connectivityChecker, reachabilityMonitor, properties);
will(returnValue(downloadWorker));
}});
}
private void expectStartWorker(MailboxWorker worker) {
context.checking(new Expectations() {{
oneOf(worker).start();
}});
}
private void expectDestroyWorker(MailboxWorker worker) {
context.checking(new Expectations() {{
oneOf(worker).destroy();
}});
}
}