Compare commits

...

2 Commits

Author SHA1 Message Date
akwizgran
21d6dfe817 Add transactional helper methods to DbViewModel. 2021-01-26 14:52:25 +00:00
akwizgran
c1e83b22c1 Add helper method for running a DB task and logging any exception it throws. 2021-01-26 13:51:03 +00:00
24 changed files with 321 additions and 433 deletions

View File

@@ -0,0 +1,6 @@
package org.briarproject.bramble.api;
public interface ThrowingRunnable<T extends Throwable> {
void run() throws T;
}

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.sync; package org.briarproject.bramble.sync;
import org.briarproject.bramble.api.ThrowingRunnable;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent; import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.DatabaseComponent;

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.sync; package org.briarproject.bramble.sync;
import org.briarproject.bramble.api.ThrowingRunnable;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent; import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.DatabaseComponent;

View File

@@ -1,6 +0,0 @@
package org.briarproject.bramble.sync;
interface ThrowingRunnable<T extends Throwable> {
void run() throws T;
}

View File

@@ -45,10 +45,8 @@ import androidx.arch.core.util.Function;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
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.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.LogUtils.now; import static org.briarproject.bramble.util.LogUtils.now;
@NotNullByDefault @NotNullByDefault
@@ -173,14 +171,9 @@ class ContactListViewModel extends DbViewModel implements EventListener {
} }
void checkForPendingContacts() { void checkForPendingContacts() {
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try { boolean hasPending = !contactManager.getPendingContacts().isEmpty();
boolean hasPending =
!contactManager.getPendingContacts().isEmpty();
hasPendingContacts.postValue(hasPending); hasPendingContacts.postValue(hasPending);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }

View File

@@ -2,12 +2,9 @@ package org.briarproject.briar.android.contact.add.remote;
import android.app.Application; import android.app.Application;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.UnsupportedVersionException;
import org.briarproject.bramble.api.contact.ContactManager; import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.contact.PendingContact; import org.briarproject.bramble.api.contact.PendingContact;
import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.NoSuchPendingContactException; import org.briarproject.bramble.api.db.NoSuchPendingContactException;
import org.briarproject.bramble.api.db.TransactionManager; import org.briarproject.bramble.api.db.TransactionManager;
import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.lifecycle.LifecycleManager;
@@ -18,7 +15,6 @@ import org.briarproject.briar.android.viewmodel.LiveEvent;
import org.briarproject.briar.android.viewmodel.LiveResult; import org.briarproject.briar.android.viewmodel.LiveResult;
import org.briarproject.briar.android.viewmodel.MutableLiveEvent; import org.briarproject.briar.android.viewmodel.MutableLiveEvent;
import java.security.GeneralSecurityException;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.logging.Logger; import java.util.logging.Logger;
@@ -66,15 +62,10 @@ public class AddContactViewModel extends DbViewModel {
} }
private void loadHandshakeLink() { private void loadHandshakeLink() {
runOnDbThread(() -> { // If an exception is thrown the UI should stay disabled,
try {
handshakeLink.postValue(contactManager.getHandshakeLink());
} catch (DbException e) {
logException(LOG, WARNING, e);
// the UI should stay disabled in this case,
// leaving the user unable to proceed // leaving the user unable to proceed
} runOnDbThreadOrLogException(() ->
}); handshakeLink.postValue(contactManager.getHandshakeLink()));
} }
LiveData<String> getHandshakeLink() { LiveData<String> getHandshakeLink() {
@@ -106,17 +97,11 @@ public class AddContactViewModel extends DbViewModel {
void addContact(String nickname) { void addContact(String nickname) {
if (remoteHandshakeLink == null) throw new IllegalStateException(); if (remoteHandshakeLink == null) throw new IllegalStateException();
runOnDbThread(() -> { runOnDbThread(() -> {
try {
contactManager.addPendingContact(remoteHandshakeLink, nickname); contactManager.addPendingContact(remoteHandshakeLink, nickname);
addContactResult.postValue(new LiveResult<>(true)); addContactResult.postValue(new LiveResult<>(true));
} catch (UnsupportedVersionException e) { }, e -> {
logException(LOG, WARNING, e); logException(LOG, WARNING, e);
addContactResult.postValue(new LiveResult<>(e)); addContactResult.postValue(new LiveResult<>(e));
} catch (DbException | FormatException
| GeneralSecurityException e) {
logException(LOG, WARNING, e);
addContactResult.postValue(new LiveResult<>(e));
}
}); });
} }
@@ -126,13 +111,13 @@ public class AddContactViewModel extends DbViewModel {
public void updatePendingContact(String name, PendingContact p) { public void updatePendingContact(String name, PendingContact p) {
runOnDbThread(() -> { runOnDbThread(() -> {
try {
contactManager.removePendingContact(p.getId()); contactManager.removePendingContact(p.getId());
addContact(name); addContact(name);
} catch (NoSuchPendingContactException e) { }, e -> {
if (e instanceof NoSuchPendingContactException) {
logException(LOG, WARNING, e); logException(LOG, WARNING, e);
// no error in UI as pending contact was converted into contact // no error in UI as pending contact was converted into contact
} catch (DbException e) { } else {
logException(LOG, WARNING, e); logException(LOG, WARNING, e);
addContactResult.postValue(new LiveResult<>(e)); addContactResult.postValue(new LiveResult<>(e));
} }

View File

@@ -10,7 +10,6 @@ import org.briarproject.bramble.api.contact.PendingContactState;
import org.briarproject.bramble.api.contact.event.PendingContactRemovedEvent; import org.briarproject.bramble.api.contact.event.PendingContactRemovedEvent;
import org.briarproject.bramble.api.contact.event.PendingContactStateChangedEvent; import org.briarproject.bramble.api.contact.event.PendingContactStateChangedEvent;
import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.TransactionManager; import org.briarproject.bramble.api.db.TransactionManager;
import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventBus;
@@ -33,10 +32,8 @@ import javax.inject.Inject;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
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.OFFLINE; import static org.briarproject.bramble.api.contact.PendingContactState.OFFLINE;
import static org.briarproject.bramble.util.LogUtils.logException;
@NotNullByDefault @NotNullByDefault
public class PendingContactListViewModel extends DbViewModel public class PendingContactListViewModel extends DbViewModel
@@ -90,8 +87,7 @@ public class PendingContactListViewModel extends DbViewModel
} }
private void loadPendingContacts() { private void loadPendingContacts() {
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try {
Collection<Pair<PendingContact, PendingContactState>> pairs = Collection<Pair<PendingContact, PendingContactState>> pairs =
contactManager.getPendingContacts(); contactManager.getPendingContacts();
List<PendingContactItem> items = new ArrayList<>(pairs.size()); List<PendingContactItem> items = new ArrayList<>(pairs.size());
@@ -105,9 +101,6 @@ public class PendingContactListViewModel extends DbViewModel
} }
pendingContacts.postValue(items); pendingContacts.postValue(items);
hasInternetConnection.postValue(online); hasInternetConnection.postValue(online);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }
@@ -116,13 +109,8 @@ public class PendingContactListViewModel extends DbViewModel
} }
void removePendingContact(PendingContactId id) { void removePendingContact(PendingContactId id) {
runOnDbThread(() -> { runOnDbThreadOrLogException(() ->
try { contactManager.removePendingContact(id));
contactManager.removePendingContact(id);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
});
} }
LiveData<Boolean> getHasInternetConnection() { LiveData<Boolean> getHasInternetConnection() {

View File

@@ -149,7 +149,7 @@ public class ConversationViewModel extends DbViewModel
AttachmentReceivedEvent a = (AttachmentReceivedEvent) e; AttachmentReceivedEvent a = (AttachmentReceivedEvent) e;
if (a.getContactId().equals(contactId)) { if (a.getContactId().equals(contactId)) {
LOG.info("Attachment received"); LOG.info("Attachment received");
runOnDbThread(() -> attachmentRetriever runOnDbThreadOrLogException(() -> attachmentRetriever
.loadAttachmentItem(a.getMessageId())); .loadAttachmentItem(a.getMessageId()));
} }
} else if (e instanceof AvatarUpdatedEvent) { } else if (e instanceof AvatarUpdatedEvent) {
@@ -194,7 +194,6 @@ public class ConversationViewModel extends DbViewModel
private void loadContact(ContactId contactId) { private void loadContact(ContactId contactId) {
runOnDbThread(() -> { runOnDbThread(() -> {
try {
long start = now(); long start = now();
Contact c = contactManager.getContact(contactId); Contact c = contactManager.getContact(contactId);
AuthorInfo authorInfo = authorManager.getAuthorInfo(c); AuthorInfo authorInfo = authorManager.getAuthorInfo(c);
@@ -203,35 +202,28 @@ public class ConversationViewModel extends DbViewModel
start = now(); start = now();
checkFeaturesAndOnboarding(contactId); checkFeaturesAndOnboarding(contactId);
logDuration(LOG, "Checking for image support", start); logDuration(LOG, "Checking for image support", start);
} catch (NoSuchContactException e) { }, e -> {
if (e instanceof NoSuchContactException) {
contactDeleted.postValue(true); contactDeleted.postValue(true);
} catch (DbException e) { } else {
logException(LOG, WARNING, e); logException(LOG, WARNING, e);
} }
}); });
} }
void markMessageRead(GroupId g, MessageId m) { void markMessageRead(GroupId g, MessageId m) {
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try {
long start = now(); long start = now();
messagingManager.setReadFlag(g, m, true); messagingManager.setReadFlag(g, m, true);
logDuration(LOG, "Marking read", start); logDuration(LOG, "Marking read", start);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }
void setContactAlias(String alias) { void setContactAlias(String alias) {
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try {
contactManager.setContactAlias(requireNonNull(contactId), contactManager.setContactAlias(requireNonNull(contactId),
alias.isEmpty() ? null : alias); alias.isEmpty() ? null : alias);
loadContact(contactId); loadContact(contactId);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }
@@ -327,8 +319,7 @@ public class ConversationViewModel extends DbViewModel
@UiThread @UiThread
private void storeMessage(PrivateMessage m) { private void storeMessage(PrivateMessage m) {
attachmentCreator.onAttachmentsSent(m.getMessage().getId()); attachmentCreator.onAttachmentsSent(m.getMessage().getId());
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try {
long start = now(); long start = now();
messagingManager.addLocalMessage(m); messagingManager.addLocalMessage(m);
logDuration(LOG, "Storing message", start); logDuration(LOG, "Storing message", start);
@@ -339,9 +330,6 @@ public class ConversationViewModel extends DbViewModel
m.hasText(), m.getAttachmentHeaders()); m.hasText(), m.getAttachmentHeaders());
// TODO add text to cache when available here // TODO add text to cache when available here
addedHeader.postEvent(h); addedHeader.postEvent(h);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }
@@ -383,12 +371,7 @@ public class ConversationViewModel extends DbViewModel
@UiThread @UiThread
void recheckFeaturesAndOnboarding(ContactId contactId) { void recheckFeaturesAndOnboarding(ContactId contactId) {
runOnDbThread(() -> { runOnDbThreadOrLogException(() ->
try { checkFeaturesAndOnboarding(contactId));
checkFeaturesAndOnboarding(contactId);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
});
} }
} }

View File

@@ -6,7 +6,6 @@ import android.net.Uri;
import android.view.View; import android.view.View;
import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.TransactionManager; import org.briarproject.bramble.api.db.TransactionManager;
import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventBus;
@@ -198,14 +197,12 @@ public class ImageViewModel extends DbViewModel implements EventListener {
private void saveImage(AttachmentItem attachment, OutputStreamProvider osp, private void saveImage(AttachmentItem attachment, OutputStreamProvider osp,
@Nullable Runnable afterCopy) { @Nullable Runnable afterCopy) {
runOnDbThread(() -> { runOnDbThread(() -> {
try {
Attachment a = Attachment a =
attachmentReader.getAttachment(attachment.getHeader()); attachmentReader.getAttachment(attachment.getHeader());
copyImageFromDb(a, osp, afterCopy); copyImageFromDb(a, osp, afterCopy);
} catch (DbException e) { }, e -> {
logException(LOG, WARNING, e); logException(LOG, WARNING, e);
saveState.postEvent(true); saveState.postEvent(true);
}
}); });
} }

View File

@@ -40,10 +40,8 @@ import androidx.annotation.UiThread;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
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.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.LogUtils.now; import static org.briarproject.bramble.util.LogUtils.now;
import static org.briarproject.briar.api.forum.ForumManager.CLIENT_ID; import static org.briarproject.briar.api.forum.ForumManager.CLIENT_ID;
@@ -164,15 +162,11 @@ class ForumListViewModel extends DbViewModel implements EventListener {
} }
void loadForumInvitations() { void loadForumInvitations() {
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try {
long start = now(); long start = now();
int available = forumSharingManager.getInvitations().size(); int available = forumSharingManager.getInvitations().size();
logDuration(LOG, "Loading available", start); logDuration(LOG, "Loading available", start);
numInvitations.postValue(available); numInvitations.postValue(available);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }

View File

@@ -51,10 +51,8 @@ import androidx.lifecycle.MutableLiveData;
import static android.widget.Toast.LENGTH_SHORT; import static android.widget.Toast.LENGTH_SHORT;
import static java.lang.Math.max; import static java.lang.Math.max;
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.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.LogUtils.now; import static org.briarproject.bramble.util.LogUtils.now;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@@ -122,14 +120,8 @@ class ForumViewModel extends ThreadListViewModel<ForumPostItem> {
LiveData<Forum> loadForum() { LiveData<Forum> loadForum() {
MutableLiveData<Forum> forum = new MutableLiveData<>(); MutableLiveData<Forum> forum = new MutableLiveData<>();
runOnDbThread(() -> { runOnDbThreadOrLogException(() ->
try { forum.postValue(forumManager.getForum(groupId)));
Forum f = forumManager.getForum(groupId);
forum.postValue(f);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
});
return forum; return forum;
} }
@@ -147,16 +139,12 @@ class ForumViewModel extends ThreadListViewModel<ForumPostItem> {
@Override @Override
public void createAndStoreMessage(String text, public void createAndStoreMessage(String text,
@Nullable MessageId parentId) { @Nullable MessageId parentId) {
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try {
LocalAuthor author = identityManager.getLocalAuthor(); LocalAuthor author = identityManager.getLocalAuthor();
GroupCount count = forumManager.getGroupCount(groupId); GroupCount count = forumManager.getGroupCount(groupId);
long timestamp = max(count.getLatestMsgTime() + 1, long timestamp = max(count.getLatestMsgTime() + 1,
clock.currentTimeMillis()); clock.currentTimeMillis());
createMessage(text, timestamp, parentId, author); createMessage(text, timestamp, parentId, author);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }
@@ -171,15 +159,11 @@ class ForumViewModel extends ThreadListViewModel<ForumPostItem> {
} }
private void storePost(ForumPost msg, String text) { private void storePost(ForumPost msg, String text) {
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try {
long start = now(); long start = now();
ForumPostHeader header = forumManager.addLocalPost(msg); ForumPostHeader header = forumManager.addLocalPost(msg);
addItemAsync(buildItem(header, text)); addItemAsync(buildItem(header, text));
logDuration(LOG, "Storing forum post", start); logDuration(LOG, "Storing forum post", start);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }
@@ -195,39 +179,23 @@ class ForumViewModel extends ThreadListViewModel<ForumPostItem> {
@Override @Override
protected void markItemRead(ForumPostItem item) { protected void markItemRead(ForumPostItem item) {
runOnDbThread(() -> { runOnDbThreadOrLogException(() ->
try { forumManager.setReadFlag(groupId, item.getId(), true));
forumManager.setReadFlag(groupId, item.getId(), true);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
});
} }
public void loadSharingContacts() { public void loadSharingContacts() {
runOnDbThread(() -> { runOnDbThreadOrLogException(true, txn -> {
try {
Collection<Contact> contacts = Collection<Contact> contacts =
forumSharingManager.getSharedWith(groupId); forumSharingManager.getSharedWith(txn, groupId);
Collection<ContactId> contactIds = Collection<ContactId> contactIds = new ArrayList<>(contacts.size());
new ArrayList<>(contacts.size());
for (Contact c : contacts) contactIds.add(c.getId()); for (Contact c : contacts) contactIds.add(c.getId());
sharingController.addAll(contactIds); txn.attach(() -> sharingController.addAll(contactIds));
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }
void deleteForum() { void deleteForum() {
runOnDbThread(() -> { runOnDbThreadOrLogException(() ->
try { forumManager.removeForum(forumManager.getForum(groupId)));
Forum f = forumManager.getForum(groupId);
forumManager.removeForum(f);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
});
Toast.makeText(getApplication(), R.string.forum_left_toast, Toast.makeText(getApplication(), R.string.forum_left_toast,
LENGTH_SHORT).show(); LENGTH_SHORT).show();
} }

View File

@@ -3,7 +3,6 @@ package org.briarproject.briar.android.navdrawer;
import android.app.Application; import android.app.Application;
import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.TransactionManager; import org.briarproject.bramble.api.db.TransactionManager;
import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -66,10 +65,8 @@ public class NavDrawerViewModel extends DbViewModel {
@UiThread @UiThread
void checkExpiryWarning() { void checkExpiryWarning() {
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try { Settings settings = settingsManager.getSettings(SETTINGS_NAMESPACE);
Settings settings =
settingsManager.getSettings(SETTINGS_NAMESPACE);
int warningInt = settings.getInt(EXPIRY_DATE_WARNING, 0); int warningInt = settings.getInt(EXPIRY_DATE_WARNING, 0);
if (warningInt == 0) { if (warningInt == 0) {
@@ -80,36 +77,27 @@ public class NavDrawerViewModel extends DbViewModel {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
long daysSinceLastWarning = long daysSinceLastWarning =
(now - warningLong) / DAYS.toMillis(1); (now - warningLong) / DAYS.toMillis(1);
long daysBeforeExpiry = long daysBeforeExpiry = (EXPIRY_DATE - now) / DAYS.toMillis(1);
(EXPIRY_DATE - now) / DAYS.toMillis(1);
if (daysSinceLastWarning >= 30) { if (daysSinceLastWarning >= 30) {
showExpiryWarning.postValue(true); showExpiryWarning.postValue(true);
} else if (daysBeforeExpiry <= 3 && } else if (daysBeforeExpiry <= 3 && daysSinceLastWarning > 0) {
daysSinceLastWarning > 0) {
showExpiryWarning.postValue(true); showExpiryWarning.postValue(true);
} else { } else {
showExpiryWarning.postValue(false); showExpiryWarning.postValue(false);
} }
} }
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }
@UiThread @UiThread
void expiryWarningDismissed() { void expiryWarningDismissed() {
showExpiryWarning.setValue(false); showExpiryWarning.setValue(false);
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try {
Settings settings = new Settings(); Settings settings = new Settings();
int date = (int) (System.currentTimeMillis() / 1000L); int date = (int) (System.currentTimeMillis() / 1000L);
settings.putInt(EXPIRY_DATE_WARNING, date); settings.putInt(EXPIRY_DATE_WARNING, date);
settingsManager.mergeSettings(settings, SETTINGS_NAMESPACE); settingsManager.mergeSettings(settings, SETTINGS_NAMESPACE);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }
@@ -125,15 +113,12 @@ public class NavDrawerViewModel extends DbViewModel {
return; return;
} }
runOnDbThread(() -> { runOnDbThread(() -> {
try { Settings settings = settingsManager.getSettings(SETTINGS_NAMESPACE);
Settings settings =
settingsManager.getSettings(SETTINGS_NAMESPACE);
boolean ask = settings.getBoolean(DOZE_ASK_AGAIN, true); boolean ask = settings.getBoolean(DOZE_ASK_AGAIN, true);
shouldAskForDozeWhitelisting.postValue(ask); shouldAskForDozeWhitelisting.postValue(ask);
} catch (DbException e) { }, e -> {
logException(LOG, WARNING, e); logException(LOG, WARNING, e);
shouldAskForDozeWhitelisting.postValue(true); shouldAskForDozeWhitelisting.postValue(true);
}
}); });
} }
@@ -145,30 +130,21 @@ public class NavDrawerViewModel extends DbViewModel {
@UiThread @UiThread
void checkTransportsOnboarding() { void checkTransportsOnboarding() {
if (showTransportsOnboarding.getValue() != null) return; if (showTransportsOnboarding.getValue() != null) return;
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try { Settings settings = settingsManager.getSettings(SETTINGS_NAMESPACE);
Settings settings =
settingsManager.getSettings(SETTINGS_NAMESPACE);
boolean show = boolean show =
settings.getBoolean(SHOW_TRANSPORTS_ONBOARDING, true); settings.getBoolean(SHOW_TRANSPORTS_ONBOARDING, true);
showTransportsOnboarding.postValue(show); showTransportsOnboarding.postValue(show);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }
@UiThread @UiThread
void transportsOnboardingShown() { void transportsOnboardingShown() {
showTransportsOnboarding.setValue(false); showTransportsOnboarding.setValue(false);
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try {
Settings settings = new Settings(); Settings settings = new Settings();
settings.putBoolean(SHOW_TRANSPORTS_ONBOARDING, false); settings.putBoolean(SHOW_TRANSPORTS_ONBOARDING, false);
settingsManager.mergeSettings(settings, SETTINGS_NAMESPACE); settingsManager.mergeSettings(settings, SETTINGS_NAMESPACE);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }
} }

View File

@@ -45,12 +45,10 @@ import static android.bluetooth.BluetoothAdapter.ACTION_STATE_CHANGED;
import static android.bluetooth.BluetoothAdapter.EXTRA_STATE; import static android.bluetooth.BluetoothAdapter.EXTRA_STATE;
import static android.bluetooth.BluetoothAdapter.STATE_ON; import static android.bluetooth.BluetoothAdapter.STATE_ON;
import static java.util.logging.Level.INFO; import static java.util.logging.Level.INFO;
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.plugin.Plugin.PREF_PLUGIN_ENABLE; import static org.briarproject.bramble.api.plugin.Plugin.PREF_PLUGIN_ENABLE;
import static org.briarproject.bramble.api.plugin.Plugin.State.STARTING_STOPPING; import static org.briarproject.bramble.api.plugin.Plugin.State.STARTING_STOPPING;
import static org.briarproject.bramble.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.LogUtils.now; import static org.briarproject.bramble.util.LogUtils.now;
@NotNullByDefault @NotNullByDefault
@@ -185,8 +183,7 @@ public class PluginViewModel extends DbViewModel implements EventListener {
} }
private void loadSettings() { private void loadSettings() {
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try {
boolean tor = isPluginEnabled(TorConstants.ID, boolean tor = isPluginEnabled(TorConstants.ID,
TorConstants.DEFAULT_PREF_PLUGIN_ENABLE); TorConstants.DEFAULT_PREF_PLUGIN_ENABLE);
torEnabledSetting.postValue(tor); torEnabledSetting.postValue(tor);
@@ -196,9 +193,6 @@ public class PluginViewModel extends DbViewModel implements EventListener {
boolean bt = isPluginEnabled(BluetoothConstants.ID, boolean bt = isPluginEnabled(BluetoothConstants.ID,
BluetoothConstants.DEFAULT_PREF_PLUGIN_ENABLE); BluetoothConstants.DEFAULT_PREF_PLUGIN_ENABLE);
btEnabledSetting.postValue(bt); btEnabledSetting.postValue(bt);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }
@@ -222,14 +216,10 @@ public class PluginViewModel extends DbViewModel implements EventListener {
} }
private void mergeSettings(Settings s, String namespace) { private void mergeSettings(Settings s, String namespace) {
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try {
long start = now(); long start = now();
settingsManager.mergeSettings(s, namespace); settingsManager.mergeSettings(s, namespace);
logDuration(LOG, "Merging settings", start); logDuration(LOG, "Merging settings", start);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }

View File

@@ -52,10 +52,8 @@ import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
import static java.lang.Math.max; import static java.lang.Math.max;
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.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.LogUtils.now; import static org.briarproject.bramble.util.LogUtils.now;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@@ -143,15 +141,11 @@ class GroupViewModel extends ThreadListViewModel<GroupMessageItem> {
} }
private void loadPrivateGroup(GroupId groupId) { private void loadPrivateGroup(GroupId groupId) {
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try {
PrivateGroup g = privateGroupManager.getPrivateGroup(groupId); PrivateGroup g = privateGroupManager.getPrivateGroup(groupId);
privateGroup.postValue(g); privateGroup.postValue(g);
Author author = identityManager.getLocalAuthor(); Author author = identityManager.getLocalAuthor();
isCreator.postValue(g.getCreator().equals(author)); isCreator.postValue(g.getCreator().equals(author));
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }
@@ -190,8 +184,7 @@ class GroupViewModel extends ThreadListViewModel<GroupMessageItem> {
@Override @Override
public void createAndStoreMessage(String text, public void createAndStoreMessage(String text,
@Nullable MessageId parentId) { @Nullable MessageId parentId) {
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try {
LocalAuthor author = identityManager.getLocalAuthor(); LocalAuthor author = identityManager.getLocalAuthor();
MessageId previousMsgId = MessageId previousMsgId =
privateGroupManager.getPreviousMsgId(groupId); privateGroupManager.getPreviousMsgId(groupId);
@@ -199,9 +192,6 @@ class GroupViewModel extends ThreadListViewModel<GroupMessageItem> {
long timestamp = count.getLatestMsgTime(); long timestamp = count.getLatestMsgTime();
timestamp = max(clock.currentTimeMillis(), timestamp + 1); timestamp = max(clock.currentTimeMillis(), timestamp + 1);
createMessage(text, timestamp, parentId, author, previousMsgId); createMessage(text, timestamp, parentId, author, previousMsgId);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }
@@ -217,55 +207,36 @@ class GroupViewModel extends ThreadListViewModel<GroupMessageItem> {
} }
private void storePost(GroupMessage msg, String text) { private void storePost(GroupMessage msg, String text) {
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try {
long start = now(); long start = now();
GroupMessageHeader header = GroupMessageHeader header =
privateGroupManager.addLocalMessage(msg); privateGroupManager.addLocalMessage(msg);
addItemAsync(buildItem(header, text)); addItemAsync(buildItem(header, text));
logDuration(LOG, "Storing group message", start); logDuration(LOG, "Storing group message", start);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }
@Override @Override
protected void markItemRead(GroupMessageItem item) { protected void markItemRead(GroupMessageItem item) {
runOnDbThread(() -> { runOnDbThreadOrLogException(() ->
try { privateGroupManager.setReadFlag(groupId, item.getId(), true));
privateGroupManager.setReadFlag(groupId, item.getId(), true);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
});
} }
public void loadSharingContacts() { public void loadSharingContacts() {
runOnDbThread(() -> { runOnDbThreadOrLogException(true, txn -> {
try {
Collection<GroupMember> members = Collection<GroupMember> members =
privateGroupManager.getMembers(groupId); privateGroupManager.getMembers(txn, groupId);
Collection<ContactId> contactIds = new ArrayList<>(); Collection<ContactId> contactIds = new ArrayList<>();
for (GroupMember m : members) { for (GroupMember m : members) {
if (m.getContactId() != null) if (m.getContactId() != null) contactIds.add(m.getContactId());
contactIds.add(m.getContactId());
}
sharingController.addAll(contactIds);
} catch (DbException e) {
logException(LOG, WARNING, e);
} }
txn.attach(() -> sharingController.addAll(contactIds));
}); });
} }
void deletePrivateGroup() { void deletePrivateGroup() {
runOnDbThread(() -> { runOnDbThreadOrLogException(() ->
try { privateGroupManager.removePrivateGroup(groupId));
privateGroupManager.removePrivateGroup(groupId);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
});
} }
LiveData<PrivateGroup> getPrivateGroup() { LiveData<PrivateGroup> getPrivateGroup() {

View File

@@ -2,7 +2,6 @@ package org.briarproject.briar.android.privategroup.list;
import android.app.Application; import android.app.Application;
import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
@@ -49,10 +48,8 @@ import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
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.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.LogUtils.now; import static org.briarproject.bramble.util.LogUtils.now;
import static org.briarproject.briar.api.privategroup.PrivateGroupManager.CLIENT_ID; import static org.briarproject.briar.api.privategroup.PrivateGroupManager.CLIENT_ID;
@@ -200,25 +197,17 @@ class GroupListViewModel extends DbViewModel implements EventListener {
} }
void removeGroup(GroupId g) { void removeGroup(GroupId g) {
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try {
long start = now(); long start = now();
groupManager.removePrivateGroup(g); groupManager.removePrivateGroup(g);
logDuration(LOG, "Removing group", start); logDuration(LOG, "Removing group", start);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }
void loadNumInvitations() { void loadNumInvitations() {
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try {
int i = groupInvitationManager.getInvitations().size(); int i = groupInvitationManager.getInvitations().size();
numInvitations.postValue(i); numInvitations.postValue(i);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }

View File

@@ -1,7 +1,6 @@
package org.briarproject.briar.android.sharing; package org.briarproject.briar.android.sharing;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -28,7 +27,7 @@ public interface SharingController {
/** /**
* Adds a collection of contacts to be tracked. * Adds a collection of contacts to be tracked.
*/ */
@DatabaseExecutor @UiThread
void addAll(Collection<ContactId> contacts); void addAll(Collection<ContactId> contacts);
/** /**

View File

@@ -2,14 +2,12 @@ package org.briarproject.briar.android.sharing;
import org.briarproject.bramble.api.connection.ConnectionRegistry; import org.briarproject.bramble.api.connection.ConnectionRegistry;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventListener; import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.event.ContactConnectedEvent; import org.briarproject.bramble.api.plugin.event.ContactConnectedEvent;
import org.briarproject.bramble.api.plugin.event.ContactDisconnectedEvent; import org.briarproject.bramble.api.plugin.event.ContactDisconnectedEvent;
import org.briarproject.bramble.api.system.AndroidExecutor;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
@@ -26,7 +24,6 @@ public class SharingControllerImpl implements SharingController, EventListener {
private final EventBus eventBus; private final EventBus eventBus;
private final ConnectionRegistry connectionRegistry; private final ConnectionRegistry connectionRegistry;
private final AndroidExecutor executor;
// UI thread // UI thread
private final Set<ContactId> contacts = new HashSet<>(); private final Set<ContactId> contacts = new HashSet<>();
@@ -35,11 +32,9 @@ public class SharingControllerImpl implements SharingController, EventListener {
@Inject @Inject
SharingControllerImpl(EventBus eventBus, SharingControllerImpl(EventBus eventBus,
ConnectionRegistry connectionRegistry, ConnectionRegistry connectionRegistry) {
AndroidExecutor executor) {
this.eventBus = eventBus; this.eventBus = eventBus;
this.connectionRegistry = connectionRegistry; this.connectionRegistry = connectionRegistry;
this.executor = executor;
eventBus.addListener(this); eventBus.addListener(this);
} }
@@ -78,13 +73,11 @@ public class SharingControllerImpl implements SharingController, EventListener {
return online; return online;
} }
@UiThread
@Override @Override
@DatabaseExecutor
public void addAll(Collection<ContactId> c) { public void addAll(Collection<ContactId> c) {
executor.runOnUiThread(() -> {
contacts.addAll(c); contacts.addAll(c);
updateLiveData(); updateLiveData();
});
} }
@UiThread @UiThread

View File

@@ -44,10 +44,8 @@ import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
import static java.util.logging.Level.INFO; import static java.util.logging.Level.INFO;
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.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.LogUtils.now; import static org.briarproject.bramble.util.LogUtils.now;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@@ -145,17 +143,12 @@ public abstract class ThreadListViewModel<I extends ThreadItem>
} }
private void loadStoredMessageId() { private void loadStoredMessageId() {
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try { storedMessageId.set(messageTracker.loadStoredMessageId(groupId));
storedMessageId
.set(messageTracker.loadStoredMessageId(groupId));
if (LOG.isLoggable(INFO)) { if (LOG.isLoggable(INFO)) {
LOG.info("Loaded last top visible message id " + LOG.info("Loaded last top visible message id " +
storedMessageId); storedMessageId);
} }
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }
@@ -229,13 +222,10 @@ public abstract class ThreadListViewModel<I extends ThreadItem>
} }
void storeMessageId(@Nullable MessageId messageId) { void storeMessageId(@Nullable MessageId messageId) {
if (messageId != null) runOnDbThread(() -> { if (messageId != null) {
try { runOnDbThreadOrLogException(() ->
messageTracker.storeMessageId(groupId, messageId); messageTracker.storeMessageId(groupId, messageId));
} catch (DbException e) {
logException(LOG, WARNING, e);
} }
});
} }
protected abstract void markItemRead(I item); protected abstract void markItemRead(I item);

View File

@@ -2,9 +2,11 @@ package org.briarproject.briar.android.viewmodel;
import android.app.Application; import android.app.Application;
import org.briarproject.bramble.api.ThrowingRunnable;
import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbCallable; import org.briarproject.bramble.api.db.DbCallable;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.DbRunnable;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.db.TransactionManager; import org.briarproject.bramble.api.db.TransactionManager;
import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.lifecycle.LifecycleManager;
@@ -23,6 +25,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.UiThread; import androidx.annotation.UiThread;
import androidx.arch.core.util.Function; import androidx.arch.core.util.Function;
import androidx.core.util.Consumer;
import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
@@ -57,14 +60,15 @@ public abstract class DbViewModel extends AndroidViewModel {
} }
/** /**
* Runs the given task on the {@link DatabaseExecutor} * Waits for the DB to open and runs the given task on the
* and waits for the DB to open. * {@link DatabaseExecutor}.
* <p> * <p>
* If you need a list of items to be displayed in a * If you need a list of items to be displayed in a
* {@link RecyclerView.Adapter}, * {@link RecyclerView.Adapter},
* use {@link #loadList(DbCallable, UiConsumer)} instead. * use {@link #loadList(DbCallable, UiConsumer)} instead.
*/ */
protected void runOnDbThread(Runnable task) { protected void runOnDbThread(ThrowingRunnable<Exception> task,
Consumer<Exception> err) {
dbExecutor.execute(() -> { dbExecutor.execute(() -> {
try { try {
lifecycleManager.waitForDatabase(); lifecycleManager.waitForDatabase();
@@ -72,10 +76,63 @@ public abstract class DbViewModel extends AndroidViewModel {
} catch (InterruptedException e) { } catch (InterruptedException e) {
LOG.warning("Interrupted while waiting for database"); LOG.warning("Interrupted while waiting for database");
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
} catch (Exception e) {
err.accept(e);
} }
}); });
} }
/**
* Waits for the DB to open and runs the given task on the
* {@link DatabaseExecutor}.
* <p>
* If you need a list of items to be displayed in a
* {@link RecyclerView.Adapter},
* use {@link #loadList(DbCallable, UiConsumer)} instead.
*/
protected void runOnDbThread(boolean readOnly,
DbRunnable<Exception> task, Consumer<Exception> err) {
dbExecutor.execute(() -> {
try {
lifecycleManager.waitForDatabase();
db.transaction(readOnly, task);
} catch (InterruptedException e) {
LOG.warning("Interrupted while waiting for database");
Thread.currentThread().interrupt();
} catch (Exception e) {
err.accept(e);
}
});
}
/**
* Waits for the DB to open and runs the given task on the
* {@link DatabaseExecutor}. If the task throws a {@link DbException}
* it's caught and logged.
* <p>
* If you need a list of items to be displayed in a
* {@link RecyclerView.Adapter},
* use {@link #loadList(DbCallable, UiConsumer)} instead.
*/
protected void runOnDbThreadOrLogException(boolean readOnly,
DbRunnable<Exception> task) {
runOnDbThread(readOnly, task, e -> logException(LOG, WARNING, e));
}
/**
* Waits for the DB to open and runs the given task on the
* {@link DatabaseExecutor}. If the task throws a {@link DbException}
* it's caught and logged.
* <p>
* If you need a list of items to be displayed in a
* {@link RecyclerView.Adapter},
* use {@link #loadList(DbCallable, UiConsumer)} instead.
*/
protected void runOnDbThreadOrLogException(
ThrowingRunnable<Exception> task) {
runOnDbThread(task, e -> logException(LOG, WARNING, e));
}
/** /**
* Loads a list of items on the {@link DatabaseExecutor} within a single * Loads a list of items on the {@link DatabaseExecutor} within a single
* {@link Transaction} and publishes it as a {@link LiveResult} * {@link Transaction} and publishes it as a {@link LiveResult}

View File

@@ -129,6 +129,12 @@ public interface PrivateGroupManager {
*/ */
Collection<GroupMember> getMembers(GroupId g) throws DbException; Collection<GroupMember> getMembers(GroupId g) throws DbException;
/**
* Returns all members of the given private group.
*/
Collection<GroupMember> getMembers(Transaction txn, GroupId g)
throws DbException;
/** /**
* Returns true if the given author is a member of the given private group. * Returns true if the given author is a member of the given private group.
*/ */

View File

@@ -3,6 +3,7 @@ package org.briarproject.briar.api.sharing;
import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.client.SessionId;
@@ -45,6 +46,12 @@ public interface SharingManager<S extends Shareable>
*/ */
Collection<Contact> getSharedWith(GroupId g) throws DbException; Collection<Contact> getSharedWith(GroupId g) throws DbException;
/**
* Returns all contacts with whom the given group is shared.
*/
Collection<Contact> getSharedWith(Transaction txn, GroupId g)
throws DbException;
/** /**
* Returns true if the group not already shared and no invitation is open * Returns true if the group not already shared and no invitation is open
*/ */

View File

@@ -407,17 +407,21 @@ class PrivateGroupManagerImpl extends BdfIncomingMessageHook
} }
@Override @Override
public Collection<GroupMember> getMembers(GroupId g) throws DbException { public Collection<GroupMember> getMembers(GroupId g)
Transaction txn = db.startTransaction(true); throws DbException {
try { return db.transactionWithResult(true, txn -> getMembers(txn, g));
}
@Override
public Collection<GroupMember> getMembers(Transaction txn, GroupId g)
throws DbException {
Collection<GroupMember> members = new ArrayList<>(); Collection<GroupMember> members = new ArrayList<>();
Map<Author, Visibility> authors = getMembers(txn, g); Map<Author, Visibility> authors = getMemberAuthors(txn, g);
LocalAuthor la = identityManager.getLocalAuthor(txn); LocalAuthor la = identityManager.getLocalAuthor(txn);
PrivateGroup privateGroup = getPrivateGroup(txn, g); PrivateGroup privateGroup = getPrivateGroup(txn, g);
for (Entry<Author, Visibility> m : authors.entrySet()) { for (Entry<Author, Visibility> m : authors.entrySet()) {
Author a = m.getKey(); Author a = m.getKey();
AuthorInfo authorInfo = AuthorInfo authorInfo = authorManager.getAuthorInfo(txn, a.getId());
authorManager.getAuthorInfo(txn, a.getId());
Status status = authorInfo.getStatus(); Status status = authorInfo.getStatus();
Visibility v = m.getValue(); Visibility v = m.getValue();
ContactId c = null; ContactId c = null;
@@ -429,14 +433,10 @@ class PrivateGroupManagerImpl extends BdfIncomingMessageHook
boolean isCreator = privateGroup.getCreator().equals(a); boolean isCreator = privateGroup.getCreator().equals(a);
members.add(new GroupMember(a, authorInfo, isCreator, c, v)); members.add(new GroupMember(a, authorInfo, isCreator, c, v));
} }
db.commitTransaction(txn);
return members; return members;
} finally {
db.endTransaction(txn);
}
} }
private Map<Author, Visibility> getMembers(Transaction txn, GroupId g) private Map<Author, Visibility> getMemberAuthors(Transaction txn, GroupId g)
throws DbException { throws DbException {
try { try {
BdfDictionary meta = BdfDictionary meta =
@@ -458,7 +458,7 @@ class PrivateGroupManagerImpl extends BdfIncomingMessageHook
@Override @Override
public boolean isMember(Transaction txn, GroupId g, Author a) public boolean isMember(Transaction txn, GroupId g, Author a)
throws DbException { throws DbException {
for (Author member : getMembers(txn, g).keySet()) { for (Author member : getMemberAuthors(txn, g).keySet()) {
if (member.equals(a)) return true; if (member.equals(a)) return true;
} }
return false; return false;

View File

@@ -426,18 +426,18 @@ abstract class SharingManagerImpl<S extends Shareable>
@Override @Override
public Collection<Contact> getSharedWith(GroupId g) throws DbException { public Collection<Contact> getSharedWith(GroupId g) throws DbException {
return db.transactionWithResult(true, txn -> getSharedWith(txn, g));
}
@Override
public Collection<Contact> getSharedWith(Transaction txn, GroupId g)
throws DbException {
// TODO report also pending invitations // TODO report also pending invitations
Collection<Contact> contacts = new ArrayList<>(); Collection<Contact> contacts = new ArrayList<>();
Transaction txn = db.startTransaction(true);
try {
for (Contact c : db.getContacts(txn)) { for (Contact c : db.getContacts(txn)) {
if (db.getGroupVisibility(txn, c.getId(), g) == SHARED) if (db.getGroupVisibility(txn, c.getId(), g) == SHARED)
contacts.add(c); contacts.add(c);
} }
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return contacts; return contacts;
} }

View File

@@ -20,10 +20,10 @@ import org.junit.Test;
import java.util.Collection; import java.util.Collection;
import static org.briarproject.briar.api.identity.AuthorInfo.Status.VERIFIED;
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
import static org.briarproject.bramble.test.TestUtils.getRandomId; import static org.briarproject.bramble.test.TestUtils.getRandomId;
import static org.briarproject.briar.api.identity.AuthorInfo.Status.VERIFIED;
import static org.briarproject.briar.api.privategroup.Visibility.INVISIBLE; import static org.briarproject.briar.api.privategroup.Visibility.INVISIBLE;
import static org.briarproject.briar.api.privategroup.Visibility.REVEALED_BY_CONTACT; import static org.briarproject.briar.api.privategroup.Visibility.REVEALED_BY_CONTACT;
import static org.briarproject.briar.api.privategroup.Visibility.REVEALED_BY_US; import static org.briarproject.briar.api.privategroup.Visibility.REVEALED_BY_US;