Merge branch '373-slow-contact-list' into 'master'

Use new group metadata for showing lists

What was supposed to be a minimal change turned into a rather large MR. I did my best to keep things in separate commits, so I can still split this into smaller MRs if desired.

While making use of the new group metadata in the contact and forum list, I noticed some other things in need of improvement to get rid of needing to load all messages:
* Refactor `SharingManager` so its events provide message headers that can be used to update list items
* Add `GroupId` to conversation items, so the metadata of the respective group can be updated as well when marking the items read
* Create a very basic `ConversationManager` so the GroupCount for the various clients can be queried in one go without needing to know all their groups per contact
* Fix a nasty bug that caused forum and blog invitation to not update their read state
* Fix some bugs related to displaying the forum list with proper unread count

Some casual measurements with just a few contacts and messages showed a reduction of the contact list load time by one third.

See merge request !343
This commit is contained in:
akwizgran
2016-10-10 14:00:36 +00:00
80 changed files with 856 additions and 639 deletions

View File

@@ -17,6 +17,7 @@ import org.briarproject.event.EventModule;
import org.briarproject.forum.ForumModule;
import org.briarproject.identity.IdentityModule;
import org.briarproject.lifecycle.LifecycleModule;
import org.briarproject.messaging.MessagingModule;
import org.briarproject.properties.PropertiesModule;
import org.briarproject.sharing.SharingModule;
import org.briarproject.sync.SyncModule;
@@ -46,7 +47,8 @@ import dagger.Component;
SharingModule.class,
SyncModule.class,
SystemModule.class,
TransportModule.class
TransportModule.class,
MessagingModule.class
})
interface BlogSharingIntegrationTestComponent {

View File

@@ -17,6 +17,7 @@ import org.briarproject.event.EventModule;
import org.briarproject.forum.ForumModule;
import org.briarproject.identity.IdentityModule;
import org.briarproject.lifecycle.LifecycleModule;
import org.briarproject.messaging.MessagingModule;
import org.briarproject.properties.PropertiesModule;
import org.briarproject.sharing.SharingModule;
import org.briarproject.sync.SyncModule;
@@ -46,7 +47,8 @@ import dagger.Component;
SharingModule.class,
SyncModule.class,
SystemModule.class,
TransportModule.class
TransportModule.class,
MessagingModule.class
})
interface ForumManagerTestComponent {

View File

@@ -21,6 +21,7 @@ import org.briarproject.event.EventModule;
import org.briarproject.forum.ForumModule;
import org.briarproject.identity.IdentityModule;
import org.briarproject.lifecycle.LifecycleModule;
import org.briarproject.messaging.MessagingModule;
import org.briarproject.properties.PropertiesModule;
import org.briarproject.sharing.SharingModule;
import org.briarproject.sync.SyncModule;
@@ -50,7 +51,8 @@ import dagger.Component;
SharingModule.class,
SyncModule.class,
SystemModule.class,
TransportModule.class
TransportModule.class,
MessagingModule.class
})
interface ForumSharingIntegrationTestComponent {

View File

@@ -20,6 +20,7 @@ import org.briarproject.db.DatabaseModule;
import org.briarproject.event.EventModule;
import org.briarproject.identity.IdentityModule;
import org.briarproject.lifecycle.LifecycleModule;
import org.briarproject.messaging.MessagingModule;
import org.briarproject.properties.PropertiesModule;
import org.briarproject.sync.SyncModule;
import org.briarproject.system.SystemModule;
@@ -46,7 +47,8 @@ import dagger.Component;
SyncModule.class,
SystemModule.class,
DataModule.class,
PropertiesModule.class
PropertiesModule.class,
MessagingModule.class
})
public interface IntroductionIntegrationTestComponent {

View File

@@ -30,6 +30,7 @@ import org.briarproject.api.keyagreement.PayloadEncoder;
import org.briarproject.api.keyagreement.PayloadParser;
import org.briarproject.api.lifecycle.IoExecutor;
import org.briarproject.api.lifecycle.LifecycleManager;
import org.briarproject.api.messaging.ConversationManager;
import org.briarproject.api.messaging.MessagingManager;
import org.briarproject.api.messaging.PrivateMessageFactory;
import org.briarproject.api.plugins.ConnectionRegistry;
@@ -86,6 +87,8 @@ public interface AndroidComponent extends CoreEagerSingletons {
ContactManager contactManager();
ConversationManager conversationManager();
MessagingManager messagingManager();
PrivateMessageFactory privateMessageFactory();

View File

@@ -28,7 +28,7 @@ import org.briarproject.api.event.ForumPostReceivedEvent;
import org.briarproject.api.event.IntroductionRequestReceivedEvent;
import org.briarproject.api.event.IntroductionResponseReceivedEvent;
import org.briarproject.api.event.IntroductionSucceededEvent;
import org.briarproject.api.event.InvitationReceivedEvent;
import org.briarproject.api.event.InvitationRequestReceivedEvent;
import org.briarproject.api.event.InvitationResponseReceivedEvent;
import org.briarproject.api.event.PrivateMessageReceivedEvent;
import org.briarproject.api.event.SettingsUpdatedEvent;
@@ -235,8 +235,8 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
} else if (e instanceof IntroductionResponseReceivedEvent) {
ContactId c = ((IntroductionResponseReceivedEvent) e).getContactId();
showNotificationForPrivateConversation(c);
} else if (e instanceof InvitationReceivedEvent) {
ContactId c = ((InvitationReceivedEvent) e).getContactId();
} else if (e instanceof InvitationRequestReceivedEvent) {
ContactId c = ((InvitationRequestReceivedEvent) e).getContactId();
showNotificationForPrivateConversation(c);
} else if (e instanceof InvitationResponseReceivedEvent) {
ContactId c = ((InvitationResponseReceivedEvent) e).getContactId();

View File

@@ -50,10 +50,8 @@ public abstract class BaseContactListAdapter<VH extends BaseContactListAdapter.B
}
});
if (item.getGroupId() != null) {
ViewCompat.setTransitionName(ui.avatar, "avatar" +
StringUtils.toHexString(item.getGroupId().getBytes()));
}
ViewCompat.setTransitionName(ui.avatar, "avatar" +
StringUtils.toHexString(item.getGroupId().getBytes()));
}
@Override
@@ -96,8 +94,9 @@ public abstract class BaseContactListAdapter<VH extends BaseContactListAdapter.B
int count = getItemCount();
for (int i = 0; i < count; i++) {
ContactListItem item = getItemAt(i);
if (item != null && item.getGroupId().equals(g))
if (item != null && item.getGroupId().equals(g)) {
return i;
}
}
return INVALID_POSITION; // Not found
}

View File

@@ -21,13 +21,12 @@ import org.briarproject.android.api.AndroidNotificationManager;
import org.briarproject.android.fragment.BaseFragment;
import org.briarproject.android.keyagreement.KeyAgreementActivity;
import org.briarproject.android.view.BriarRecyclerView;
import org.briarproject.api.blogs.BlogSharingManager;
import org.briarproject.api.clients.MessageTracker.GroupCount;
import org.briarproject.api.contact.Contact;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.contact.ContactManager;
import org.briarproject.api.db.DbException;
import org.briarproject.api.db.NoSuchContactException;
import org.briarproject.api.event.ContactAddedEvent;
import org.briarproject.api.event.ContactConnectedEvent;
import org.briarproject.api.event.ContactDisconnectedEvent;
import org.briarproject.api.event.ContactRemovedEvent;
@@ -37,24 +36,21 @@ import org.briarproject.api.event.EventBus;
import org.briarproject.api.event.EventListener;
import org.briarproject.api.event.IntroductionRequestReceivedEvent;
import org.briarproject.api.event.IntroductionResponseReceivedEvent;
import org.briarproject.api.event.InvitationReceivedEvent;
import org.briarproject.api.event.InvitationRequestReceivedEvent;
import org.briarproject.api.event.InvitationResponseReceivedEvent;
import org.briarproject.api.event.PrivateMessageReceivedEvent;
import org.briarproject.api.forum.ForumSharingManager;
import org.briarproject.api.identity.IdentityManager;
import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.introduction.IntroductionManager;
import org.briarproject.api.introduction.IntroductionMessage;
import org.briarproject.api.introduction.IntroductionRequest;
import org.briarproject.api.introduction.IntroductionResponse;
import org.briarproject.api.messaging.MessagingManager;
import org.briarproject.api.messaging.ConversationManager;
import org.briarproject.api.messaging.PrivateMessageHeader;
import org.briarproject.api.plugins.ConnectionRegistry;
import org.briarproject.api.sharing.InvitationMessage;
import org.briarproject.api.sharing.InvitationRequest;
import org.briarproject.api.sharing.InvitationResponse;
import org.briarproject.api.sync.GroupId;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.logging.Logger;
@@ -88,13 +84,7 @@ public class ContactListFragment extends BaseFragment implements EventListener {
@Inject
protected volatile IdentityManager identityManager;
@Inject
protected volatile MessagingManager messagingManager;
@Inject
protected volatile IntroductionManager introductionManager;
@Inject
protected volatile ForumSharingManager forumSharingManager;
@Inject
protected volatile BlogSharingManager blogSharingManager;
protected volatile ConversationManager conversationManager;
public static ContactListFragment newInstance() {
@@ -130,7 +120,6 @@ public class ContactListFragment extends BaseFragment implements EventListener {
new ContactListAdapter.OnItemClickListener() {
@Override
public void onItemClick(View view, ContactListItem item) {
GroupId groupId = item.getGroupId();
Intent i = new Intent(getActivity(),
ConversationActivity.class);
@@ -215,15 +204,15 @@ public class ContactListFragment extends BaseFragment implements EventListener {
try {
ContactId id = c.getId();
GroupId groupId =
messagingManager.getConversationId(id);
Collection<ConversationItem> messages =
getMessages(id);
conversationManager.getConversationId(id);
GroupCount count =
conversationManager.getGroupCount(id);
boolean connected =
connectionRegistry.isConnected(c.getId());
LocalAuthor localAuthor = identityManager
.getLocalAuthor(c.getLocalAuthorId());
contacts.add(new ContactListItem(c, localAuthor,
connected, groupId, messages));
connected, groupId, count));
} catch (NoSuchContactException e) {
// Continue
}
@@ -252,14 +241,9 @@ public class ContactListFragment extends BaseFragment implements EventListener {
@Override
public void eventOccurred(Event e) {
if (e instanceof ContactAddedEvent) {
if (((ContactAddedEvent) e).isActive()) {
LOG.info("Contact added as active, reloading");
loadContacts();
}
} else if (e instanceof ContactStatusChangedEvent) {
if (e instanceof ContactStatusChangedEvent) {
LOG.info("Contact Status changed, reloading");
// TODO We can update the contact state without needing to reload
// is also broadcast when contact was added
loadContacts();
} else if (e instanceof ContactConnectedEvent) {
setConnected(((ContactConnectedEvent) e).getContactId(), true);
@@ -285,50 +269,20 @@ public class ContactListFragment extends BaseFragment implements EventListener {
(IntroductionResponseReceivedEvent) e;
IntroductionResponse ir = m.getIntroductionResponse();
updateItem(m.getContactId(), ConversationItem.from(ir));
} else if (e instanceof InvitationReceivedEvent) {
LOG.info("Invitation received, reloading conversation...");
InvitationReceivedEvent m = (InvitationReceivedEvent) e;
reloadConversation(m.getContactId());
} else if (e instanceof InvitationRequestReceivedEvent) {
LOG.info("Invitation Request received, update contact");
InvitationRequestReceivedEvent m = (InvitationRequestReceivedEvent) e;
InvitationRequest ir = m.getRequest();
updateItem(m.getContactId(), ConversationItem.from(ir));
} else if (e instanceof InvitationResponseReceivedEvent) {
LOG.info("Invitation Response received, reloading ...");
LOG.info("Invitation Response received, update contact");
InvitationResponseReceivedEvent m =
(InvitationResponseReceivedEvent) e;
reloadConversation(m.getContactId());
InvitationResponse ir = m.getResponse();
updateItem(m.getContactId(), ConversationItem.from(ir));
}
}
private void reloadConversation(final ContactId c) {
listener.runOnDbThread(new Runnable() {
@Override
public void run() {
try {
Collection<ConversationItem> messages = getMessages(c);
updateItem(c, messages);
} catch (NoSuchContactException e) {
LOG.info("Contact removed");
} catch (DbException e) {
if (LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
}
}
});
}
private void updateItem(final ContactId c,
final Collection<ConversationItem> messages) {
listener.runOnUiThread(new Runnable() {
@Override
public void run() {
int position = adapter.findItemPosition(c);
ContactListItem item = adapter.getItemAt(position);
if (item != null) {
item.setMessages(messages);
adapter.updateItemAt(position, item);
}
}
});
}
private void updateItem(final ContactId c, final ConversationItem m) {
listener.runOnUiThread(new Runnable() {
@Override
@@ -382,50 +336,4 @@ public class ContactListFragment extends BaseFragment implements EventListener {
});
}
// This needs to be called from the DB thread
// Do not call getActivty() here as it might return null
private Collection<ConversationItem> getMessages(ContactId id)
throws DbException {
long now = System.currentTimeMillis();
Collection<ConversationItem> messages = new ArrayList<>();
Collection<PrivateMessageHeader> headers =
messagingManager.getMessageHeaders(id);
for (PrivateMessageHeader h : headers) {
messages.add(ConversationItem.from(h));
}
long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
LOG.info("Loading message headers took " + duration + " ms");
now = System.currentTimeMillis();
Collection<IntroductionMessage> introductions =
introductionManager
.getIntroductionMessages(id);
for (IntroductionMessage m : introductions) {
messages.add(ConversationItem.from(m));
}
duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
LOG.info("Loading introduction messages took " + duration + " ms");
now = System.currentTimeMillis();
Collection<InvitationMessage> forumInvitations =
forumSharingManager.getInvitationMessages(id);
for (InvitationMessage i : forumInvitations) {
messages.add(ConversationItem.from(i));
}
Collection<InvitationMessage> blogInvitations =
blogSharingManager.getInvitationMessages(id);
for (InvitationMessage i : blogInvitations) {
messages.add(ConversationItem.from(i));
}
duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
LOG.info("Loading invitations took " + duration + " ms");
return messages;
}
}

View File

@@ -1,14 +1,14 @@
package org.briarproject.android.contact;
import org.briarproject.api.clients.MessageTracker.GroupCount;
import org.briarproject.api.contact.Contact;
import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.sync.GroupId;
import java.util.Collection;
import org.jetbrains.annotations.NotNull;
import static org.briarproject.android.contact.ConversationItem.IncomingItem;
// This class is not thread-safe
// This class is NOT thread-safe
public class ContactListItem {
private final Contact contact;
@@ -18,26 +18,16 @@ public class ContactListItem {
private long timestamp;
private int unread;
public ContactListItem(Contact contact, LocalAuthor localAuthor,
boolean connected,
GroupId groupId,
Collection<ConversationItem> messages) {
public ContactListItem(@NotNull Contact contact,
@NotNull LocalAuthor localAuthor, boolean connected,
@NotNull GroupId groupId, @NotNull GroupCount count) {
this.contact = contact;
this.localAuthor = localAuthor;
this.groupId = groupId;
this.connected = connected;
setMessages(messages);
}
void setMessages(Collection<ConversationItem> messages) {
empty = messages == null || messages.isEmpty();
timestamp = 0;
unread = 0;
if (!empty) {
for (ConversationItem i : messages) {
addMessage(i);
}
}
this.empty = count.getMsgCount() == 0;
this.unread = count.getUnreadCount();
this.timestamp = count.getLatestMsgTime();
}
void addMessage(ConversationItem message) {

View File

@@ -34,6 +34,7 @@ import org.briarproject.android.view.TextInputView;
import org.briarproject.android.view.TextInputView.TextInputListener;
import org.briarproject.api.FormatException;
import org.briarproject.api.blogs.BlogSharingManager;
import org.briarproject.api.clients.BaseMessageHeader;
import org.briarproject.api.clients.SessionId;
import org.briarproject.api.contact.Contact;
import org.briarproject.api.contact.ContactId;
@@ -50,7 +51,7 @@ import org.briarproject.api.event.EventBus;
import org.briarproject.api.event.EventListener;
import org.briarproject.api.event.IntroductionRequestReceivedEvent;
import org.briarproject.api.event.IntroductionResponseReceivedEvent;
import org.briarproject.api.event.InvitationReceivedEvent;
import org.briarproject.api.event.InvitationRequestReceivedEvent;
import org.briarproject.api.event.InvitationResponseReceivedEvent;
import org.briarproject.api.event.MessagesAckedEvent;
import org.briarproject.api.event.MessagesSentEvent;
@@ -76,7 +77,7 @@ import org.briarproject.util.StringUtils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -476,28 +477,28 @@ public class ConversationActivity extends BriarActivity
}
private void markMessagesRead() {
List<MessageId> unread = new ArrayList<>();
Map<MessageId, GroupId> unread = new HashMap<>();
SparseArray<IncomingItem> list = adapter.getIncomingMessages();
for (int i = 0; i < list.size(); i++) {
IncomingItem item = list.valueAt(i);
if (!item.isRead()) unread.add(item.getId());
if (!item.isRead())
unread.put(item.getId(), item.getGroupId());
}
if (unread.isEmpty()) return;
if (LOG.isLoggable(INFO))
LOG.info("Marking " + unread.size() + " messages read");
markMessagesRead(Collections.unmodifiableList(unread));
markMessagesRead(unread);
}
private void markMessagesRead(final Collection<MessageId> unread) {
private void markMessagesRead(final Map<MessageId, GroupId> unread) {
runOnDbThread(new Runnable() {
@Override
public void run() {
try {
long now = System.currentTimeMillis();
for (MessageId m : unread)
// not really clean, but the messaging manager can
// handle introduction messages as well
messagingManager.setReadFlag(groupId, m, true);
for (Map.Entry<MessageId, GroupId> e : unread.entrySet())
messagingManager
.setReadFlag(e.getValue(), e.getKey(), true);
long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
LOG.info("Marking read took " + duration + " ms");
@@ -560,6 +561,7 @@ public class ConversationActivity extends BriarActivity
IntroductionRequest ir = event.getIntroductionRequest();
ConversationItem item = new ConversationIntroductionInItem(ir);
addConversationItem(item);
markMessageReadIfNew(ir);
}
} else if (e instanceof IntroductionResponseReceivedEvent) {
IntroductionResponseReceivedEvent event =
@@ -570,25 +572,33 @@ public class ConversationActivity extends BriarActivity
ConversationItem item =
ConversationItem.from(this, contactName, ir);
addConversationItem(item);
markMessageReadIfNew(ir);
}
} else if (e instanceof InvitationReceivedEvent) {
InvitationReceivedEvent event =
(InvitationReceivedEvent) e;
} else if (e instanceof InvitationRequestReceivedEvent) {
InvitationRequestReceivedEvent event =
(InvitationRequestReceivedEvent) e;
if (event.getContactId().equals(contactId)) {
LOG.info("Invitation received, reloading...");
loadMessages();
LOG.info("Invitation received, adding...");
InvitationRequest ir = event.getRequest();
ConversationItem item = ConversationItem.from(ir);
addConversationItem(item);
markMessageReadIfNew(ir);
}
} else if (e instanceof InvitationResponseReceivedEvent) {
InvitationResponseReceivedEvent event =
(InvitationResponseReceivedEvent) e;
if (event.getContactId().equals(contactId)) {
LOG.info("Invitation response received, reloading...");
loadMessages();
LOG.info("Invitation response received, adding...");
InvitationResponse ir = event.getResponse();
ConversationItem item =
ConversationItem.from(this, contactName, ir);
addConversationItem(item);
markMessageReadIfNew(ir);
}
}
}
private void markMessageReadIfNew(final PrivateMessageHeader h) {
private void markMessageReadIfNew(final BaseMessageHeader h) {
runOnUiThread(new Runnable() {
@Override
public void run() {
@@ -597,22 +607,23 @@ public class ConversationActivity extends BriarActivity
// Mark the message read if it's the newest message
long lastMsgTime = item.getTime();
long newMsgTime = h.getTimestamp();
if (newMsgTime > lastMsgTime) markNewMessageRead(h.getId());
if (newMsgTime > lastMsgTime)
markNewMessageRead(h.getGroupId(), h.getId());
else loadMessages();
} else {
// mark the message as read as well if it is the first one
markNewMessageRead(h.getId());
markNewMessageRead(h.getGroupId(), h.getId());
}
}
});
}
private void markNewMessageRead(final MessageId m) {
private void markNewMessageRead(final GroupId g, final MessageId m) {
runOnDbThread(new Runnable() {
@Override
public void run() {
try {
messagingManager.setReadFlag(groupId, m, true);
messagingManager.setReadFlag(g, m, true);
loadMessages();
} catch (DbException e) {
if (LOG.isLoggable(WARNING))
@@ -681,11 +692,10 @@ public class ConversationActivity extends BriarActivity
long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
LOG.info("Storing message took " + duration + " ms");
MessageId id = m.getMessage().getId();
PrivateMessageHeader h = new PrivateMessageHeader(id,
m.getMessage().getTimestamp(), m.getContentType(),
true, false, false, false);
groupId, m.getMessage().getTimestamp(),
m.getContentType(), true, false, false, false);
ConversationMessageItem item = ConversationItem.from(h);
item.setBody(body);
bodyCache.put(id, body);

View File

@@ -1,14 +1,16 @@
package org.briarproject.android.contact;
import org.briarproject.android.contact.ConversationItem.IncomingItem;
import org.briarproject.api.introduction.IntroductionRequest;
import org.jetbrains.annotations.NotNull;
// This class is not thread-safe
class ConversationIntroductionInItem extends ConversationIntroductionItem
implements ConversationItem.IncomingItem {
implements IncomingItem {
private boolean read;
ConversationIntroductionInItem(IntroductionRequest ir) {
ConversationIntroductionInItem(@NotNull IntroductionRequest ir) {
super(ir);
this.read = ir.isRead();

View File

@@ -1,6 +1,7 @@
package org.briarproject.android.contact;
import org.briarproject.api.introduction.IntroductionRequest;
import org.jetbrains.annotations.NotNull;
// This class is not thread-safe
abstract class ConversationIntroductionItem extends ConversationItem {
@@ -8,13 +9,14 @@ abstract class ConversationIntroductionItem extends ConversationItem {
private final IntroductionRequest ir;
private boolean answered;
ConversationIntroductionItem(IntroductionRequest ir) {
super(ir.getMessageId(), ir.getTimestamp());
ConversationIntroductionItem(@NotNull IntroductionRequest ir) {
super(ir.getMessageId(), ir.getGroupId(), ir.getTimestamp());
this.ir = ir;
this.answered = ir.wasAnswered();
}
@NotNull
IntroductionRequest getIntroductionRequest() {
return ir;
}

View File

@@ -12,7 +12,9 @@ import org.briarproject.api.messaging.PrivateMessageHeader;
import org.briarproject.api.sharing.InvitationMessage;
import org.briarproject.api.sharing.InvitationRequest;
import org.briarproject.api.sharing.InvitationResponse;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId;
import org.jetbrains.annotations.NotNull;
// This class is not thread-safe
public abstract class ConversationItem {
@@ -30,20 +32,29 @@ public abstract class ConversationItem {
final static int BLOG_INVITATION_IN = 9;
final static int BLOG_INVITATION_OUT = 10;
private MessageId id;
private long time;
final private MessageId id;
final private GroupId groupId;
final private long time;
public ConversationItem(MessageId id, long time) {
public ConversationItem(@NotNull MessageId id, @NotNull GroupId groupId,
long time) {
this.id = id;
this.groupId = groupId;
this.time = time;
}
abstract int getType();
@NotNull
public MessageId getId() {
return id;
}
@NotNull
public GroupId getGroupId() {
return groupId;
}
long getTime() {
return time;
}
@@ -78,8 +89,9 @@ public abstract class ConversationItem {
R.string.introduction_response_declined_sent,
ir.getName());
}
return new ConversationNoticeOutItem(ir.getMessageId(), text,
ir.getTimestamp(), ir.isSent(), ir.isSeen());
return new ConversationNoticeOutItem(ir.getMessageId(),
ir.getGroupId(), text, ir.getTimestamp(), ir.isSent(),
ir.isSeen());
} else {
String text;
if (ir.wasAccepted()) {
@@ -97,8 +109,8 @@ public abstract class ConversationItem {
contactName, ir.getName());
}
}
return new ConversationNoticeInItem(ir.getMessageId(), text,
ir.getTimestamp(), ir.isRead());
return new ConversationNoticeInItem(ir.getMessageId(),
ir.getGroupId(), text, ir.getTimestamp(), ir.isRead());
}
}
@@ -137,8 +149,8 @@ public abstract class ConversationItem {
R.string.forum_invitation_response_declined_sent,
contactName);
}
return new ConversationNoticeOutItem(fir.getId(), text,
fir.getTimestamp(), fir.isSent(), fir.isSeen());
return new ConversationNoticeOutItem(fir.getId(), fir.getGroupId(),
text, fir.getTimestamp(), fir.isSent(), fir.isSeen());
} else {
String text;
if (fir.wasAccepted()) {
@@ -150,8 +162,8 @@ public abstract class ConversationItem {
R.string.forum_invitation_response_declined_received,
contactName);
}
return new ConversationNoticeInItem(fir.getId(), text,
fir.getTimestamp(), fir.isRead());
return new ConversationNoticeInItem(fir.getId(), fir.getGroupId(),
text, fir.getTimestamp(), fir.isRead());
}
}
@@ -169,8 +181,8 @@ public abstract class ConversationItem {
R.string.blogs_sharing_response_declined_sent,
contactName);
}
return new ConversationNoticeOutItem(fir.getId(), text,
fir.getTimestamp(), fir.isSent(), fir.isSeen());
return new ConversationNoticeOutItem(fir.getId(), fir.getGroupId(),
text, fir.getTimestamp(), fir.isSent(), fir.isSeen());
} else {
String text;
if (fir.wasAccepted()) {
@@ -182,8 +194,8 @@ public abstract class ConversationItem {
R.string.blogs_sharing_response_declined_received,
contactName);
}
return new ConversationNoticeInItem(fir.getId(), text,
fir.getTimestamp(), fir.isRead());
return new ConversationNoticeInItem(fir.getId(), fir.getGroupId(),
text, fir.getTimestamp(), fir.isRead());
}
}
@@ -193,10 +205,10 @@ public abstract class ConversationItem {
*/
public static ConversationItem from(IntroductionMessage im) {
if (im.isLocal())
return new ConversationNoticeOutItem(im.getMessageId(), "",
im.getTimestamp(), false, false);
return new ConversationNoticeInItem(im.getMessageId(), "",
im.getTimestamp(), im.isRead());
return new ConversationNoticeOutItem(im.getMessageId(),
im.getGroupId(), "", im.getTimestamp(), false, false);
return new ConversationNoticeInItem(im.getMessageId(), im.getGroupId(),
"", im.getTimestamp(), im.isRead());
}
/**
@@ -205,14 +217,15 @@ public abstract class ConversationItem {
*/
public static ConversationItem from(InvitationMessage im) {
if (im.isLocal())
return new ConversationNoticeOutItem(im.getId(), "",
im.getTimestamp(), false, false);
return new ConversationNoticeInItem(im.getId(), "",
return new ConversationNoticeOutItem(im.getId(), im.getGroupId(),
"", im.getTimestamp(), false, false);
return new ConversationNoticeInItem(im.getId(), im.getGroupId(), "",
im.getTimestamp(), im.isRead());
}
interface OutgoingItem {
@NotNull
MessageId getId();
boolean isSent();
@@ -226,8 +239,12 @@ public abstract class ConversationItem {
interface IncomingItem {
@NotNull
MessageId getId();
@NotNull
GroupId getGroupId();
boolean isRead();
void setRead(boolean read);

View File

@@ -9,7 +9,7 @@ abstract class ConversationMessageItem extends ConversationItem {
private byte[] body;
ConversationMessageItem(PrivateMessageHeader header) {
super(header.getId(), header.getTimestamp());
super(header.getId(), header.getGroupId(), header.getTimestamp());
this.header = header;
body = null;

View File

@@ -1,5 +1,6 @@
package org.briarproject.android.contact;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId;
// This class is not thread-safe
@@ -8,9 +9,9 @@ class ConversationNoticeInItem extends ConversationNoticeItem
private boolean read;
ConversationNoticeInItem(MessageId id, String text, long time,
boolean read) {
super(id, text, time);
ConversationNoticeInItem(MessageId id, GroupId groupId, String text,
long time, boolean read) {
super(id, groupId, text, time);
this.read = read;
}

View File

@@ -1,13 +1,15 @@
package org.briarproject.android.contact;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId;
abstract class ConversationNoticeItem extends ConversationItem {
private final String text;
ConversationNoticeItem(MessageId id, String text, long time) {
super(id, time);
ConversationNoticeItem(MessageId id, GroupId groupId, String text,
long time) {
super(id, groupId, time);
this.text = text;
}

View File

@@ -1,5 +1,6 @@
package org.briarproject.android.contact;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId;
// This class is not thread-safe
@@ -8,9 +9,9 @@ class ConversationNoticeOutItem extends ConversationNoticeItem
private boolean sent, seen;
ConversationNoticeOutItem(MessageId id, String text, long time,
boolean sent, boolean seen) {
super(id, text, time);
ConversationNoticeOutItem(MessageId id, GroupId groupId, String text,
long time, boolean sent, boolean seen) {
super(id, groupId, text, time);
this.sent = sent;
this.seen = seen;

View File

@@ -7,7 +7,7 @@ abstract class ConversationShareableInvitationItem extends ConversationItem {
private final InvitationRequest fim;
ConversationShareableInvitationItem(InvitationRequest fim) {
super(fim.getId(), fim.getTimestamp());
super(fim.getId(), fim.getGroupId(), fim.getTimestamp());
this.fim = fim;
}

View File

@@ -1,27 +0,0 @@
package org.briarproject.android.forum;
import org.briarproject.api.forum.ForumPostHeader;
// This class is not thread-safe
class ForumItem {
private final ForumPostHeader header;
private byte[] body;
ForumItem(ForumPostHeader header) {
this.header = header;
body = null;
}
ForumPostHeader getHeader() {
return header;
}
byte[] getBody() {
return body;
}
void setBody(byte[] body) {
this.body = body;
}
}

View File

@@ -1,17 +0,0 @@
package org.briarproject.android.forum;
import java.util.Comparator;
class ForumItemComparator implements Comparator<ForumItem> {
static final ForumItemComparator INSTANCE = new ForumItemComparator();
public int compare(ForumItem a, ForumItem b) {
// The oldest message comes first
long aTime = a.getHeader().getTimestamp();
long bTime = b.getHeader().getTimestamp();
if (aTime < bTime) return -1;
if (aTime > bTime) return 1;
return 0;
}
}

View File

@@ -17,6 +17,7 @@ import org.briarproject.android.view.TextAvatarView;
import org.briarproject.api.forum.Forum;
import org.briarproject.api.sync.GroupId;
import static android.support.v7.util.SortedList.INVALID_POSITION;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static org.briarproject.android.BriarActivity.GROUP_ID;
@@ -104,7 +105,7 @@ class ForumListAdapter
@Override
public boolean areContentsTheSame(ForumListItem a, ForumListItem b) {
return a.getForum().equals(b.getForum()) &&
return a.isEmpty() == b.isEmpty() &&
a.getTimestamp() == b.getTimestamp() &&
a.getUnreadCount() == b.getUnreadCount();
}
@@ -125,10 +126,14 @@ class ForumListAdapter
return null;
}
void updateItem(ForumListItem item) {
ForumListItem oldItem = findItem(item.getForum().getGroup().getId());
int position = items.indexOf(oldItem);
items.updateItemAt(position, item);
int findItemPosition(GroupId g) {
int count = getItemCount();
for (int i = 0; i < count; i++) {
ForumListItem item = getItemAt(i);
if (item != null && item.getForum().getGroup().getId().equals(g))
return i;
}
return INVALID_POSITION; // Not found
}
static class ForumViewHolder extends RecyclerView.ViewHolder {

View File

@@ -20,6 +20,7 @@ import org.briarproject.android.api.AndroidNotificationManager;
import org.briarproject.android.fragment.BaseEventFragment;
import org.briarproject.android.sharing.InvitationsForumActivity;
import org.briarproject.android.view.BriarRecyclerView;
import org.briarproject.api.clients.MessageTracker.GroupCount;
import org.briarproject.api.db.DbException;
import org.briarproject.api.db.NoSuchGroupException;
import org.briarproject.api.event.ContactRemovedEvent;
@@ -47,11 +48,8 @@ import static java.util.logging.Level.WARNING;
public class ForumListFragment extends BaseEventFragment implements
OnClickListener {
public final static String TAG = "ForumListFragment";
private static final Logger LOG =
Logger.getLogger(ForumListFragment.class.getName());
public final static String TAG = ForumListFragment.class.getName();
private final static Logger LOG = Logger.getLogger(TAG);
private BriarRecyclerView list;
private ForumListAdapter adapter;
@@ -118,7 +116,7 @@ public class ForumListFragment extends BaseEventFragment implements
notificationManager.blockAllForumPostNotifications();
notificationManager.clearAllForumPostNotifications();
loadForumHeaders();
loadForums();
loadAvailableForums();
list.startPeriodicUpdate();
}
@@ -153,7 +151,7 @@ public class ForumListFragment extends BaseEventFragment implements
}
}
private void loadForumHeaders() {
private void loadForums() {
listener.runOnDbThread(new Runnable() {
@Override
public void run() {
@@ -163,14 +161,14 @@ public class ForumListFragment extends BaseEventFragment implements
Collection<ForumListItem> forums = new ArrayList<>();
for (Forum f : forumManager.getForums()) {
try {
Collection<ForumPostHeader> headers =
forumManager.getPostHeaders(f.getId());
forums.add(new ForumListItem(f, headers));
GroupCount count =
forumManager.getGroupCount(f.getId());
forums.add(new ForumListItem(f, count));
} catch (NoSuchGroupException e) {
// Continue
}
}
displayForumHeaders(forums);
displayForums(forums);
long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
LOG.info("Full load took " + duration + " ms");
@@ -182,7 +180,7 @@ public class ForumListFragment extends BaseEventFragment implements
});
}
private void displayForumHeaders(final Collection<ForumListItem> forums) {
private void displayForums(final Collection<ForumListItem> forums) {
listener.runOnUiThread(new Runnable() {
@Override
public void run() {
@@ -238,7 +236,7 @@ public class ForumListFragment extends BaseEventFragment implements
GroupAddedEvent g = (GroupAddedEvent) e;
if (g.getGroup().getClientId().equals(forumManager.getClientId())) {
LOG.info("Forum added, reloading forums");
loadForumHeaders();
loadForums();
}
} else if (e instanceof GroupRemovedEvent) {
GroupRemovedEvent g = (GroupRemovedEvent) e;
@@ -248,39 +246,23 @@ public class ForumListFragment extends BaseEventFragment implements
}
} else if (e instanceof ForumPostReceivedEvent) {
ForumPostReceivedEvent m = (ForumPostReceivedEvent) e;
LOG.info("Forum post added, reloading");
loadForumHeaders(m.getGroupId());
LOG.info("Forum post added, updating...");
updateItem(m.getGroupId(), m.getForumPostHeader());
} else if (e instanceof ForumInvitationReceivedEvent) {
loadAvailableForums();
}
}
private void loadForumHeaders(final GroupId g) {
listener.runOnDbThread(new Runnable() {
@Override
public void run() {
try {
long now = System.currentTimeMillis();
Forum f = forumManager.getForum(g);
Collection<ForumPostHeader> headers =
forumManager.getPostHeaders(g);
long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
LOG.info("Partial load took " + duration + " ms");
updateForum(new ForumListItem(f, headers));
} catch (DbException e) {
if (LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
}
}
});
}
private void updateForum(final ForumListItem item) {
private void updateItem(final GroupId g, final ForumPostHeader m) {
listener.runOnUiThread(new Runnable() {
@Override
public void run() {
adapter.updateItem(item);
int position = adapter.findItemPosition(g);
ForumListItem item = adapter.getItemAt(position);
if (item != null) {
item.addHeader(m);
adapter.updateItemAt(position, item);
}
}
});
}
@@ -289,7 +271,8 @@ public class ForumListFragment extends BaseEventFragment implements
listener.runOnUiThread(new Runnable() {
@Override
public void run() {
ForumListItem item = adapter.findItem(g);
int position = adapter.findItemPosition(g);
ForumListItem item = adapter.getItemAt(position);
if (item != null) adapter.remove(item);
}
});

View File

@@ -1,40 +1,27 @@
package org.briarproject.android.forum;
import org.briarproject.api.clients.MessageTracker.GroupCount;
import org.briarproject.api.forum.Forum;
import org.briarproject.api.forum.ForumPostHeader;
import java.util.Collection;
// This class is NOT thread-safe
class ForumListItem {
private final Forum forum;
private final boolean empty;
private final int postCount;
private final long timestamp;
private final int unread;
private int postCount, unread;
private long timestamp;
ForumListItem(Forum forum, Collection<ForumPostHeader> headers) {
ForumListItem(Forum forum, GroupCount count) {
this.forum = forum;
empty = headers.isEmpty();
if (empty) {
postCount = 0;
timestamp = 0;
unread = 0;
} else {
ForumPostHeader newest = null;
long timestamp = -1;
int unread = 0;
for (ForumPostHeader h : headers) {
if (h.getTimestamp() > timestamp) {
timestamp = h.getTimestamp();
newest = h;
}
if (!h.isRead()) unread++;
}
this.postCount = headers.size();
this.timestamp = newest.getTimestamp();
this.unread = unread;
}
this.postCount = count.getMsgCount();
this.unread = count.getUnreadCount();
this.timestamp = count.getLatestMsgTime();
}
void addHeader(ForumPostHeader h) {
postCount++;
if (!h.isRead()) unread++;
if (h.getTimestamp() > timestamp) timestamp = h.getTimestamp();
}
Forum getForum() {
@@ -42,7 +29,7 @@ class ForumListItem {
}
boolean isEmpty() {
return empty;
return postCount == 0;
}
int getPostCount() {

View File

@@ -15,9 +15,9 @@ import org.briarproject.R;
import org.briarproject.android.ActivityComponent;
import org.briarproject.android.contact.ContactListAdapter;
import org.briarproject.android.contact.ContactListItem;
import org.briarproject.android.contact.ConversationItem;
import org.briarproject.android.fragment.BaseFragment;
import org.briarproject.android.view.BriarRecyclerView;
import org.briarproject.api.clients.MessageTracker.GroupCount;
import org.briarproject.api.contact.Contact;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.contact.ContactManager;
@@ -25,21 +25,16 @@ import org.briarproject.api.db.DbException;
import org.briarproject.api.identity.AuthorId;
import org.briarproject.api.identity.IdentityManager;
import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.introduction.IntroductionManager;
import org.briarproject.api.introduction.IntroductionMessage;
import org.briarproject.api.messaging.MessagingManager;
import org.briarproject.api.messaging.PrivateMessageHeader;
import org.briarproject.api.messaging.ConversationManager;
import org.briarproject.api.plugins.ConnectionRegistry;
import org.briarproject.api.sync.GroupId;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.logging.Logger;
import javax.inject.Inject;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
public class ContactChooserFragment extends BaseFragment {
@@ -61,9 +56,7 @@ public class ContactChooserFragment extends BaseFragment {
@Inject
protected volatile IdentityManager identityManager;
@Inject
protected volatile MessagingManager messagingManager;
@Inject
protected volatile IntroductionManager introductionManager;
protected volatile ConversationManager conversationManager;
@Inject
protected volatile ConnectionRegistry connectionRegistry;
@@ -159,23 +152,23 @@ public class ContactChooserFragment extends BaseFragment {
public void run() {
try {
List<ContactListItem> contacts = new ArrayList<>();
AuthorId localAuthorId = null;
AuthorId localAuthorId =
identityManager.getLocalAuthor().getId();
for (Contact c : contactManager.getActiveContacts()) {
if (c.getId().getInt() == contactId) {
c1 = c;
localAuthorId = c1.getLocalAuthorId();
} else {
ContactId id = c.getId();
GroupId groupId =
messagingManager.getConversationId(id);
Collection<ConversationItem> messages =
getMessages(id);
conversationManager.getConversationId(id);
GroupCount count =
conversationManager.getGroupCount(id);
boolean connected =
connectionRegistry.isConnected(c.getId());
LocalAuthor localAuthor = identityManager
.getLocalAuthor(c.getLocalAuthorId());
contacts.add(new ContactListItem(c, localAuthor,
connected, groupId, messages));
connected, groupId, count));
}
}
displayContacts(localAuthorId, contacts);
@@ -220,36 +213,4 @@ public class ContactChooserFragment extends BaseFragment {
builder.show();
}
/**
* This needs to be called from the DbThread
*/
private Collection<ConversationItem> getMessages(ContactId id)
throws DbException {
long now = System.currentTimeMillis();
Collection<ConversationItem> messages = new ArrayList<>();
Collection<PrivateMessageHeader> headers =
messagingManager.getMessageHeaders(id);
for (PrivateMessageHeader h : headers) {
messages.add(ConversationItem.from(h));
}
long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
LOG.info("Loading message headers took " + duration + " ms");
now = System.currentTimeMillis();
Collection<IntroductionMessage> introductions =
introductionManager
.getIntroductionMessages(id);
for (IntroductionMessage m : introductions) {
messages.add(ConversationItem.from(m));
}
duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
LOG.info("Loading introduction messages took " + duration + " ms");
return messages;
}
}

View File

@@ -3,6 +3,7 @@ package org.briarproject.android.sharing;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.widget.LinearLayoutManager;
import android.transition.Fade;
import android.view.LayoutInflater;
@@ -39,6 +40,7 @@ import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static org.briarproject.android.sharing.ShareActivity.CONTACTS;
import static org.briarproject.android.sharing.ShareActivity.getContactsFromIds;
import static org.briarproject.android.sharing.ShareActivity.getContactsFromIntegers;
import static org.briarproject.api.sharing.SharingConstants.GROUP_ID;
public class ContactSelectorFragment extends BaseFragment implements
@@ -122,8 +124,9 @@ public class ContactSelectorFragment extends BaseFragment implements
if (savedInstanceState != null) {
ArrayList<Integer> intContacts =
savedInstanceState.getIntegerArrayList(CONTACTS);
selectedContacts = ShareActivity.getContactsFromIntegers(
intContacts);
if (intContacts != null) {
selectedContacts = getContactsFromIntegers(intContacts);
}
}
return contentView;
@@ -185,7 +188,7 @@ public class ContactSelectorFragment extends BaseFragment implements
updateMenuItem();
}
private void loadContacts(final Collection<ContactId> selection) {
private void loadContacts(@Nullable final Collection<ContactId> selection) {
shareActivity.runOnDbThread(new Runnable() {
@Override
public void run() {

View File

@@ -1,14 +1,14 @@
package org.briarproject.android.sharing;
import android.support.annotation.UiThread;
import org.briarproject.android.contact.ContactListItem;
import org.briarproject.android.contact.ConversationItem;
import org.briarproject.api.clients.MessageTracker.GroupCount;
import org.briarproject.api.contact.Contact;
import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.sync.GroupId;
import java.util.Collections;
// This class is not thread-safe
// This class is NOT thread-safe
public class SelectableContactListItem extends ContactListItem {
private boolean selected, disabled;
@@ -16,8 +16,7 @@ public class SelectableContactListItem extends ContactListItem {
public SelectableContactListItem(Contact contact, LocalAuthor localAuthor,
GroupId groupId, boolean selected, boolean disabled) {
super(contact, localAuthor, false, groupId,
Collections.<ConversationItem>emptyList());
super(contact, localAuthor, false, groupId, new GroupCount(0, 0, 0));
this.selected = selected;
this.disabled = disabled;

View File

@@ -9,6 +9,7 @@ import org.briarproject.R;
import org.briarproject.android.BriarActivity;
import org.briarproject.android.contact.ContactListItem;
import org.briarproject.android.view.BriarRecyclerView;
import org.briarproject.api.clients.MessageTracker.GroupCount;
import org.briarproject.api.contact.Contact;
import org.briarproject.api.db.DbException;
import org.briarproject.api.identity.IdentityManager;
@@ -105,8 +106,8 @@ abstract class SharingStatusActivity extends BriarActivity {
LocalAuthor localAuthor = identityManager
.getLocalAuthor(c.getLocalAuthorId());
ContactListItem item =
new ContactListItem(c, localAuthor, false, null,
null);
new ContactListItem(c, localAuthor, false,
groupId, new GroupCount(0, 0, 0));
contactItems.add(item);
}
} catch (DbException e) {
@@ -141,8 +142,8 @@ abstract class SharingStatusActivity extends BriarActivity {
LocalAuthor localAuthor = identityManager
.getLocalAuthor(c.getLocalAuthorId());
ContactListItem item =
new ContactListItem(c, localAuthor, false, null,
null);
new ContactListItem(c, localAuthor, false,
groupId, new GroupCount(0, 0, 0));
contactItems.add(item);
}
} catch (DbException e) {

View File

@@ -48,11 +48,12 @@ public class TextAvatarView extends FrameLayout {
}
public void setUnreadCount(int count) {
unreadCount = count;
if (count > 0) {
this.unreadCount = count;
badge.setBackgroundResource(R.drawable.bubble);
badge.setText(String.valueOf(count));
badge.setTextColor(ContextCompat.getColor(getContext(), R.color.briar_text_primary_inverse));
badge.setTextColor(ContextCompat.getColor(getContext(),
R.color.briar_text_primary_inverse));
badge.setVisibility(VISIBLE);
} else {
badge.setVisibility(INVISIBLE);
@@ -63,12 +64,11 @@ public class TextAvatarView extends FrameLayout {
if (problem) {
badge.setBackgroundResource(R.drawable.bubble_problem);
badge.setText("!");
badge.setTextColor(ContextCompat.getColor(getContext(), R.color.briar_primary));
badge.setTextColor(ContextCompat
.getColor(getContext(), R.color.briar_primary));
badge.setVisibility(VISIBLE);
} else if (unreadCount > 0) {
setUnreadCount(unreadCount);
} else {
badge.setVisibility(INVISIBLE);
setUnreadCount(unreadCount);
}
}

View File

@@ -9,18 +9,13 @@ import android.support.annotation.CallSuper;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.annotation.UiThread;
import android.support.v7.widget.AppCompatImageButton;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import org.briarproject.R;
import org.thoughtcrime.securesms.components.KeyboardAwareLinearLayout;
@@ -32,7 +27,6 @@ import org.thoughtcrime.securesms.components.emoji.EmojiToggle;
import java.util.logging.Logger;
import static android.content.Context.INPUT_METHOD_SERVICE;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
@UiThread
public class TextInputView extends KeyboardAwareLinearLayout

View File

@@ -2,8 +2,8 @@ package org.briarproject.api.blogs;
import org.briarproject.api.clients.SessionId;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.sharing.InvitationMessage;
import org.briarproject.api.sharing.InvitationRequest;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId;
public class BlogInvitationRequest extends InvitationRequest {
@@ -11,12 +11,12 @@ public class BlogInvitationRequest extends InvitationRequest {
private final String blogAuthorName;
public BlogInvitationRequest(MessageId id, SessionId sessionId,
ContactId contactId, String blogAuthorName, String message,
boolean available, long time, boolean local, boolean sent,
boolean seen, boolean read) {
GroupId groupId, ContactId contactId, String blogAuthorName,
String message, boolean available, long time, boolean local,
boolean sent, boolean seen, boolean read) {
super(id, sessionId, contactId, message, available, time, local, sent,
seen, read);
super(id, sessionId, groupId, contactId, message, available, time,
local, sent, seen, read);
this.blogAuthorName = blogAuthorName;
}

View File

@@ -3,15 +3,18 @@ package org.briarproject.api.blogs;
import org.briarproject.api.clients.SessionId;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.sharing.InvitationResponse;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId;
import org.jetbrains.annotations.NotNull;
public class BlogInvitationResponse extends InvitationResponse {
public BlogInvitationResponse(MessageId id, SessionId sessionId,
ContactId contactId, boolean accept, long time, boolean local,
boolean sent, boolean seen, boolean read) {
public BlogInvitationResponse(@NotNull MessageId id, SessionId sessionId,
GroupId groupId, ContactId contactId, boolean accept, long time,
boolean local, boolean sent, boolean seen, boolean read) {
super(id, sessionId, contactId, accept, time, local, sent, seen, read);
super(id, sessionId, groupId, contactId, accept, time, local, sent,
seen, read);
}
}

View File

@@ -13,6 +13,7 @@ import static org.briarproject.api.blogs.BlogConstants.BLOG_PUBLIC_KEY;
import static org.briarproject.api.blogs.BlogConstants.BLOG_TITLE;
import static org.briarproject.api.sharing.SharingConstants.INVITATION_MSG;
import static org.briarproject.api.sharing.SharingConstants.SESSION_ID;
import static org.briarproject.api.sharing.SharingConstants.TIME;
public interface BlogSharingMessage {
@@ -25,9 +26,9 @@ public interface BlogSharingMessage {
public BlogInvitation(GroupId groupId, SessionId sessionId,
String blogTitle, String blogDesc, String blogAuthorName,
byte[] blogPublicKey, String message) {
byte[] blogPublicKey, long time, String message) {
super(groupId, sessionId, message);
super(groupId, sessionId, time, message);
this.blogTitle = blogTitle;
this.blogDesc = blogDesc;
@@ -65,9 +66,10 @@ public interface BlogSharingMessage {
String blogAuthorName = d.getString(BLOG_AUTHOR_NAME);
byte[] blogPublicKey = d.getRaw(BLOG_PUBLIC_KEY);
String message = d.getOptionalString(INVITATION_MSG);
long time = d.getLong(TIME);
return new BlogInvitation(groupId, sessionId, blogTitle,
blogDesc, blogAuthorName, blogPublicKey, message);
blogDesc, blogAuthorName, blogPublicKey, time, message);
}
public String getBlogTitle() {

View File

@@ -1,17 +1,22 @@
package org.briarproject.api.clients;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId;
import org.jetbrains.annotations.NotNull;
public abstract class BaseMessageHeader {
private final MessageId id;
private final GroupId groupId;
private final long timestamp;
private final boolean local, read, sent, seen;
public BaseMessageHeader(MessageId id, long timestamp, boolean local,
boolean read, boolean sent, boolean seen) {
public BaseMessageHeader(@NotNull MessageId id, @NotNull GroupId groupId,
long timestamp, boolean local, boolean read, boolean sent,
boolean seen) {
this.id = id;
this.groupId = groupId;
this.timestamp = timestamp;
this.local = local;
this.read = read;
@@ -19,10 +24,16 @@ public abstract class BaseMessageHeader {
this.seen = seen;
}
@NotNull
public MessageId getId() {
return id;
}
@NotNull
public GroupId getGroupId() {
return groupId;
}
public long getTimestamp() {
return timestamp;
}
@@ -42,4 +53,5 @@ public abstract class BaseMessageHeader {
public boolean isSeen() {
return seen;
}
}

View File

@@ -1,9 +1,7 @@
package org.briarproject.api.clients;
import org.briarproject.api.db.DbException;
import org.briarproject.api.db.Transaction;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.Message;
import org.briarproject.api.sync.MessageId;
public interface MessageTracker {
@@ -20,19 +18,20 @@ public interface MessageTracker {
void setReadFlag(GroupId g, MessageId m, boolean read) throws DbException;
class GroupCount {
private final long msgCount, unreadCount, latestMsgTime;
private final int msgCount, unreadCount;
private final long latestMsgTime;
public GroupCount(long msgCount, long unreadCount, long latestMsgTime) {
public GroupCount(int msgCount, int unreadCount, long latestMsgTime) {
this.msgCount = msgCount;
this.unreadCount = unreadCount;
this.latestMsgTime = latestMsgTime;
}
public long getMsgCount() {
public int getMsgCount() {
return msgCount;
}
public long getUnreadCount() {
public int getUnreadCount() {
return unreadCount;
}

View File

@@ -2,13 +2,16 @@ package org.briarproject.api.event;
import org.briarproject.api.blogs.Blog;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.sharing.InvitationRequest;
public class BlogInvitationReceivedEvent extends InvitationReceivedEvent {
public class BlogInvitationReceivedEvent extends
InvitationRequestReceivedEvent {
private final Blog blog;
public BlogInvitationReceivedEvent(Blog blog, ContactId contactId) {
super(contactId);
public BlogInvitationReceivedEvent(Blog blog, ContactId contactId,
InvitationRequest request) {
super(contactId, request);
this.blog = blog;
}

View File

@@ -1,5 +1,6 @@
package org.briarproject.api.event;
import org.briarproject.api.blogs.BlogInvitationResponse;
import org.briarproject.api.contact.ContactId;
public class BlogInvitationResponseReceivedEvent extends InvitationResponseReceivedEvent {
@@ -7,8 +8,8 @@ public class BlogInvitationResponseReceivedEvent extends InvitationResponseRecei
private final String blogTitle;
public BlogInvitationResponseReceivedEvent(String blogTitle,
ContactId contactId) {
super(contactId);
ContactId contactId, BlogInvitationResponse response) {
super(contactId, response);
this.blogTitle = blogTitle;
}

View File

@@ -2,17 +2,21 @@ package org.briarproject.api.event;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.forum.Forum;
import org.briarproject.api.forum.ForumInvitationRequest;
public class ForumInvitationReceivedEvent extends InvitationReceivedEvent {
public class ForumInvitationReceivedEvent extends
InvitationRequestReceivedEvent {
private final Forum forum;
public ForumInvitationReceivedEvent(Forum forum, ContactId contactId) {
super(contactId);
public ForumInvitationReceivedEvent(Forum forum, ContactId contactId,
ForumInvitationRequest request) {
super(contactId, request);
this.forum = forum;
}
public Forum getForum() {
return forum;
}
}

View File

@@ -1,14 +1,15 @@
package org.briarproject.api.event;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.forum.ForumInvitationResponse;
public class ForumInvitationResponseReceivedEvent extends InvitationResponseReceivedEvent {
private final String forumName;
public ForumInvitationResponseReceivedEvent(String forumName,
ContactId contactId) {
super(contactId);
ContactId contactId, ForumInvitationResponse response) {
super(contactId, response);
this.forumName = forumName;
}

View File

@@ -1,16 +0,0 @@
package org.briarproject.api.event;
import org.briarproject.api.contact.ContactId;
public abstract class InvitationReceivedEvent extends Event {
private final ContactId contactId;
InvitationReceivedEvent(ContactId contactId) {
this.contactId = contactId;
}
public ContactId getContactId() {
return contactId;
}
}

View File

@@ -0,0 +1,24 @@
package org.briarproject.api.event;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.sharing.InvitationRequest;
public abstract class InvitationRequestReceivedEvent extends Event {
private final ContactId contactId;
private final InvitationRequest request;
InvitationRequestReceivedEvent(ContactId contactId,
InvitationRequest request) {
this.contactId = contactId;
this.request = request;
}
public ContactId getContactId() {
return contactId;
}
public InvitationRequest getRequest() {
return request;
}
}

View File

@@ -1,16 +1,24 @@
package org.briarproject.api.event;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.sharing.InvitationResponse;
public abstract class InvitationResponseReceivedEvent extends Event {
private final ContactId contactId;
private final InvitationResponse response;
public InvitationResponseReceivedEvent(ContactId contactId) {
public InvitationResponseReceivedEvent(ContactId contactId,
InvitationResponse response) {
this.contactId = contactId;
this.response = response;
}
public ContactId getContactId() {
return contactId;
}
public InvitationResponse getResponse() {
return response;
}
}

View File

@@ -3,19 +3,21 @@ package org.briarproject.api.forum;
import org.briarproject.api.clients.SessionId;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.sharing.InvitationRequest;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId;
import org.jetbrains.annotations.Nullable;
public class ForumInvitationRequest extends InvitationRequest {
private final String forumName;
public ForumInvitationRequest(MessageId id, SessionId sessionId,
ContactId contactId, String forumName, String message,
GroupId groupId, ContactId contactId, String forumName, String message,
boolean available, long time, boolean local, boolean sent,
boolean seen, boolean read) {
super(id, sessionId, contactId, message, available, time, local, sent,
seen, read);
super(id, sessionId, groupId, contactId, message, available, time,
local, sent, seen, read);
this.forumName = forumName;
}

View File

@@ -3,15 +3,19 @@ package org.briarproject.api.forum;
import org.briarproject.api.clients.SessionId;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.sharing.InvitationResponse;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class ForumInvitationResponse extends InvitationResponse {
public ForumInvitationResponse(MessageId id, SessionId sessionId,
ContactId contactId, boolean accept, long time, boolean local,
public ForumInvitationResponse(@NotNull MessageId id, SessionId sessionId,
GroupId groupId, ContactId contactId, boolean accept, long time, boolean local,
boolean sent, boolean seen, boolean read) {
super(id, sessionId, contactId, accept, time, local, sent, seen, read);
super(id, sessionId, groupId, contactId, accept, time, local, sent,
seen, read);
}
}

View File

@@ -11,6 +11,7 @@ import static org.briarproject.api.forum.ForumConstants.FORUM_NAME;
import static org.briarproject.api.forum.ForumConstants.FORUM_SALT;
import static org.briarproject.api.sharing.SharingConstants.INVITATION_MSG;
import static org.briarproject.api.sharing.SharingConstants.SESSION_ID;
import static org.briarproject.api.sharing.SharingConstants.TIME;
public interface ForumSharingMessage {
@@ -20,9 +21,9 @@ public interface ForumSharingMessage {
private final byte[] forumSalt;
public ForumInvitation(GroupId groupId, SessionId sessionId,
String forumName, byte[] forumSalt, String message) {
String forumName, byte[] forumSalt, long time, String message) {
super(groupId, sessionId, message);
super(groupId, sessionId, time, message);
this.forumName = forumName;
this.forumSalt = forumSalt;
@@ -53,9 +54,10 @@ public interface ForumSharingMessage {
String forumName = d.getString(FORUM_NAME);
byte[] forumSalt = d.getRaw(FORUM_SALT);
String message = d.getOptionalString(INVITATION_MSG);
long time = d.getLong(TIME);
return new ForumInvitation(groupId, sessionId, forumName, forumSalt,
message);
time, message);
}
public String getForumName() {

View File

@@ -1,32 +1,36 @@
package org.briarproject.api.introduction;
import org.briarproject.api.clients.SessionId;
import org.briarproject.api.clients.BaseMessageHeader;
import org.briarproject.api.clients.SessionId;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId;
import org.jetbrains.annotations.NotNull;
import static org.briarproject.api.introduction.IntroductionConstants.ROLE_INTRODUCEE;
import static org.briarproject.api.introduction.IntroductionConstants.ROLE_INTRODUCER;
public class IntroductionMessage extends BaseMessageHeader {
public class IntroductionMessage extends BaseMessageHeader {
private final SessionId sessionId;
private final MessageId messageId;
private final int role;
public IntroductionMessage(SessionId sessionId, MessageId messageId,
int role, long time, boolean local, boolean sent, boolean seen,
public IntroductionMessage(@NotNull SessionId sessionId,
@NotNull MessageId messageId, @NotNull GroupId groupId, int role,
long time, boolean local, boolean sent, boolean seen,
boolean read) {
super(messageId, time, local, read, sent, seen);
super(messageId, groupId, time, local, read, sent, seen);
this.sessionId = sessionId;
this.messageId = messageId;
this.role = role;
}
@NotNull
public SessionId getSessionId() {
return sessionId;
}
@NotNull
public MessageId getMessageId() {
return messageId;
}
@@ -35,9 +39,4 @@ import static org.briarproject.api.introduction.IntroductionConstants.ROLE_INTRO
return role == ROLE_INTRODUCER;
}
public boolean isIntroducee() {
return role == ROLE_INTRODUCEE;
}
}

View File

@@ -2,21 +2,25 @@ package org.briarproject.api.introduction;
import org.briarproject.api.clients.SessionId;
import org.briarproject.api.identity.AuthorId;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class IntroductionRequest extends IntroductionResponse {
private final String message;
private final boolean answered, exists, introducesOtherIdentity;
public IntroductionRequest(SessionId sessionId, MessageId messageId,
int role, long time, boolean local, boolean sent, boolean seen,
boolean read, AuthorId authorId, String name, boolean accepted,
String message, boolean answered, boolean exists,
public IntroductionRequest(@NotNull SessionId sessionId,
@NotNull MessageId messageId, @NotNull GroupId groupId, int role,
long time, boolean local, boolean sent, boolean seen, boolean read,
AuthorId authorId, String name, boolean accepted,
@Nullable String message, boolean answered, boolean exists,
boolean introducesOtherIdentity) {
super(sessionId, messageId, role, time, local, sent, seen, read,
authorId, name, accepted);
super(sessionId, messageId, groupId, role, time, local, sent, seen,
read, authorId, name, accepted);
this.message = message;
this.answered = answered;
@@ -24,6 +28,7 @@ public class IntroductionRequest extends IntroductionResponse {
this.introducesOtherIdentity = introducesOtherIdentity;
}
@Nullable
public String getMessage() {
return message;
}

View File

@@ -2,7 +2,9 @@ package org.briarproject.api.introduction;
import org.briarproject.api.clients.SessionId;
import org.briarproject.api.identity.AuthorId;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId;
import org.jetbrains.annotations.NotNull;
public class IntroductionResponse extends IntroductionMessage {
@@ -10,12 +12,13 @@ public class IntroductionResponse extends IntroductionMessage {
private final String name;
private final boolean accepted;
public IntroductionResponse(SessionId sessionId, MessageId messageId,
int role, long time, boolean local, boolean sent, boolean seen,
boolean read, AuthorId remoteAuthorId, String name,
boolean accepted) {
public IntroductionResponse(@NotNull SessionId sessionId,
@NotNull MessageId messageId, @NotNull GroupId groupId, int role,
long time, boolean local, boolean sent, boolean seen, boolean read,
AuthorId remoteAuthorId, String name, boolean accepted) {
super(sessionId, messageId, role, time, local, sent, seen, read);
super(sessionId, messageId, groupId, role, time, local, sent, seen,
read);
this.remoteAuthorId = remoteAuthorId;
this.name = name;

View File

@@ -0,0 +1,28 @@
package org.briarproject.api.messaging;
import org.briarproject.api.clients.MessageTracker.GroupCount;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.db.DbException;
import org.briarproject.api.db.Transaction;
import org.briarproject.api.sync.GroupId;
public interface ConversationManager {
/**
* Clients that present messages in a private conversation need to
* register themselves here.
*/
void registerConversationClient(ConversationClient client);
/** Get the main group ID that represents this conversation */
GroupId getConversationId(ContactId contactId) throws DbException;
/** Get the unified group count for all private conversation messages. */
GroupCount getGroupCount(ContactId contactId) throws DbException;
interface ConversationClient {
GroupCount getGroupCount(Transaction txn, ContactId contactId)
throws DbException;
}
}

View File

@@ -1,17 +1,18 @@
package org.briarproject.api.messaging;
import org.briarproject.api.clients.BaseMessageHeader;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId;
public class PrivateMessageHeader extends BaseMessageHeader {
private final String contentType;
public PrivateMessageHeader(MessageId id, long timestamp,
public PrivateMessageHeader(MessageId id, GroupId groupId, long timestamp,
String contentType, boolean local, boolean read, boolean sent,
boolean seen) {
super(id, timestamp, local, read, sent, seen);
super(id, groupId, timestamp, local, read, sent, seen);
this.contentType = contentType;
}

View File

@@ -1,28 +1,33 @@
package org.briarproject.api.sharing;
import org.briarproject.api.clients.BaseMessageHeader;
import org.briarproject.api.clients.SessionId;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.clients.BaseMessageHeader;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId;
import org.jetbrains.annotations.NotNull;
public abstract class InvitationMessage extends BaseMessageHeader {
private final SessionId sessionId;
private final ContactId contactId;
public InvitationMessage(MessageId id, SessionId sessionId,
ContactId contactId, long time, boolean local, boolean sent,
boolean seen, boolean read) {
public InvitationMessage(@NotNull MessageId id,
@NotNull SessionId sessionId, @NotNull GroupId groupId,
@NotNull ContactId contactId, long time, boolean local,
boolean sent, boolean seen, boolean read) {
super(id, time, local, read, sent, seen);
super(id, groupId, time, local, read, sent, seen);
this.sessionId = sessionId;
this.contactId = contactId;
}
@NotNull
public SessionId getSessionId() {
return sessionId;
}
@NotNull
public ContactId getContactId() {
return contactId;
}

View File

@@ -2,23 +2,28 @@ package org.briarproject.api.sharing;
import org.briarproject.api.clients.SessionId;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public abstract class InvitationRequest extends InvitationMessage {
private final String message;
private final boolean available;
public InvitationRequest(MessageId id, SessionId sessionId,
ContactId contactId, String message,
public InvitationRequest(@NotNull MessageId id,
@NotNull SessionId sessionId, @NotNull GroupId groupId,
@NotNull ContactId contactId, @Nullable String message,
boolean available, long time, boolean local, boolean sent,
boolean seen, boolean read) {
super(id, sessionId, contactId, time, local, read, sent, seen);
super(id, sessionId, groupId, contactId, time, local, sent, seen, read);
this.message = message;
this.available = available;
}
@Nullable
public String getMessage() {
return message;
}

View File

@@ -2,17 +2,19 @@ package org.briarproject.api.sharing;
import org.briarproject.api.clients.SessionId;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId;
import org.jetbrains.annotations.NotNull;
public abstract class InvitationResponse extends InvitationMessage {
private final boolean accept;
public InvitationResponse(MessageId id, SessionId sessionId,
ContactId contactId, boolean accept, long time, boolean local,
boolean sent, boolean seen, boolean read) {
public InvitationResponse(@NotNull MessageId id, SessionId sessionId,
GroupId groupId, ContactId contactId, boolean accept, long time,
boolean local, boolean sent, boolean seen, boolean read) {
super(id, sessionId, contactId, time, local, read, sent, seen);
super(id, sessionId, groupId, contactId, time, local, sent, seen, read);
this.accept = accept;
}

View File

@@ -19,6 +19,8 @@ public interface SharingConstants {
String IS_SHARER = "isSharer";
String SHAREABLE_ID = "shareableId";
String INVITATION_MSG = "invitationMsg";
String INVITATION_ID = "invitationId";
String RESPONSE_ID = "responseId";
int SHARE_MSG_TYPE_INVITATION = 1;
int SHARE_MSG_TYPE_ACCEPT = 2;
int SHARE_MSG_TYPE_DECLINE = 3;

View File

@@ -14,6 +14,7 @@ import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_ACCEP
import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_DECLINE;
import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_INVITATION;
import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_LEAVE;
import static org.briarproject.api.sharing.SharingConstants.TIME;
import static org.briarproject.api.sharing.SharingConstants.TYPE;
public interface SharingMessage {
@@ -21,10 +22,12 @@ public interface SharingMessage {
abstract class BaseMessage {
private final GroupId groupId;
private final SessionId sessionId;
private final long time;
BaseMessage(GroupId groupId, SessionId sessionId) {
BaseMessage(GroupId groupId, SessionId sessionId, long time) {
this.groupId = groupId;
this.sessionId = sessionId;
this.time = time;
}
public BdfList toBdfList() {
@@ -62,16 +65,20 @@ public interface SharingMessage {
public SessionId getSessionId() {
return sessionId;
}
public long getTime() {
return time;
}
}
abstract class Invitation extends BaseMessage {
protected final String message;
public Invitation(GroupId groupId, SessionId sessionId,
public Invitation(GroupId groupId, SessionId sessionId, long time,
String message) {
super(groupId, sessionId);
super(groupId, sessionId, time);
this.message = message;
}
@@ -90,8 +97,9 @@ public interface SharingMessage {
private final long type;
public SimpleMessage(long type, GroupId groupId, SessionId sessionId) {
super(groupId, sessionId);
public SimpleMessage(long type, GroupId groupId, SessionId sessionId,
long time) {
super(groupId, sessionId, time);
this.type = type;
}
@@ -114,7 +122,8 @@ public interface SharingMessage {
type != SHARE_MSG_TYPE_ABORT) throw new FormatException();
SessionId sessionId = new SessionId(d.getRaw(SESSION_ID));
return new SimpleMessage(type, groupId, sessionId);
long time = d.getLong(TIME);
return new SimpleMessage(type, groupId, sessionId, time);
}
}

View File

@@ -81,8 +81,8 @@ public abstract class BdfIncomingMessageHook implements IncomingMessageHook,
protected void trackMessage(Transaction txn, GroupId g, long time,
boolean read) throws DbException {
GroupCount c = getGroupCount(txn, g);
long msgCount = c.getMsgCount() + 1;
long unreadCount = c.getUnreadCount() + (read ? 0 : 1);
int msgCount = c.getMsgCount() + 1;
int unreadCount = c.getUnreadCount() + (read ? 0 : 1);
long latestTime =
time > c.getLatestMsgTime() ? time : c.getLatestMsgTime();
storeGroupCount(txn, g,
@@ -103,14 +103,14 @@ public abstract class BdfIncomingMessageHook implements IncomingMessageHook,
return count;
}
private GroupCount getGroupCount(Transaction txn, GroupId g)
protected GroupCount getGroupCount(Transaction txn, GroupId g)
throws DbException {
GroupCount count;
try {
BdfDictionary d = clientHelper.getGroupMetadataAsDictionary(txn, g);
count = new GroupCount(
d.getLong(GROUP_KEY_MSG_COUNT, 0L),
d.getLong(GROUP_KEY_UNREAD_COUNT, 0L),
d.getLong(GROUP_KEY_MSG_COUNT, 0L).intValue(),
d.getLong(GROUP_KEY_UNREAD_COUNT, 0L).intValue(),
d.getLong(GROUP_KEY_LATEST_MSG, 0L)
);
} catch (FormatException e) {

View File

@@ -0,0 +1,33 @@
package org.briarproject.clients;
import org.briarproject.api.clients.ClientHelper;
import org.briarproject.api.contact.Contact;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.data.MetadataParser;
import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DbException;
import org.briarproject.api.db.Transaction;
import org.briarproject.api.messaging.ConversationManager;
import org.briarproject.api.messaging.ConversationManager.ConversationClient;
import org.briarproject.api.sync.Group;
import org.briarproject.api.sync.GroupId;
public abstract class ConversationClientImpl extends BdfIncomingMessageHook
implements ConversationClient {
protected ConversationClientImpl(DatabaseComponent db,
ClientHelper clientHelper, MetadataParser metadataParser) {
super(db, clientHelper, metadataParser);
}
protected abstract Group getContactGroup(Contact contact);
@Override
public GroupCount getGroupCount(Transaction txn, ContactId contactId)
throws DbException {
Contact contact = db.getContact(txn, contactId);
GroupId groupId = getContactGroup(contact).getId();
return getGroupCount(txn, groupId);
}
}

View File

@@ -12,6 +12,7 @@ import org.briarproject.api.introduction.IntroduceeAction;
import org.briarproject.api.introduction.IntroduceeProtocolState;
import org.briarproject.api.introduction.IntroductionRequest;
import org.briarproject.api.clients.SessionId;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId;
import java.util.ArrayList;
@@ -343,6 +344,7 @@ public class IntroduceeEngine
SessionId sessionId = new SessionId(localState.getRaw(SESSION_ID));
MessageId messageId = new MessageId(msg.getRaw(MESSAGE_ID));
GroupId groupId = new GroupId(msg.getRaw(GROUP_ID));
long time = msg.getLong(MESSAGE_TIME);
String name = msg.getString(NAME);
String message = msg.getOptionalString(MSG);
@@ -351,8 +353,9 @@ public class IntroduceeEngine
localState.getBoolean(REMOTE_AUTHOR_IS_US);
IntroductionRequest ir = new IntroductionRequest(sessionId, messageId,
ROLE_INTRODUCEE, time, false, false, false, false, authorId,
name, false, message, false, exists, introducesOtherIdentity);
groupId, ROLE_INTRODUCEE, time, false, false, false, false,
authorId, name, false, message, false, exists,
introducesOtherIdentity);
return new IntroductionRequestReceivedEvent(contactId, ir);
}

View File

@@ -12,6 +12,7 @@ import org.briarproject.api.introduction.IntroducerAction;
import org.briarproject.api.introduction.IntroducerProtocolState;
import org.briarproject.api.introduction.IntroductionResponse;
import org.briarproject.api.clients.SessionId;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId;
import java.util.ArrayList;
@@ -298,14 +299,15 @@ public class IntroducerEngine
SessionId sessionId = new SessionId(localState.getRaw(SESSION_ID));
MessageId messageId = new MessageId(msg.getRaw(MESSAGE_ID));
GroupId groupId = new GroupId(msg.getRaw(GROUP_ID));
long time = msg.getLong(MESSAGE_TIME);
String name = getOtherContact(localState, msg);
boolean accept = msg.getBoolean(ACCEPT);
IntroductionResponse ir =
new IntroductionResponse(sessionId, messageId, ROLE_INTRODUCER,
time, false, false, false, false, authorId, name,
accept);
new IntroductionResponse(sessionId, messageId, groupId,
ROLE_INTRODUCER, time, false, false, false, false,
authorId, name, accept);
return new IntroductionResponseReceivedEvent(contactId, ir);
}

View File

@@ -29,7 +29,7 @@ import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.Message;
import org.briarproject.api.sync.MessageId;
import org.briarproject.api.sync.MessageStatus;
import org.briarproject.clients.BdfIncomingMessageHook;
import org.briarproject.clients.ConversationClientImpl;
import org.briarproject.util.StringUtils;
import java.io.IOException;
@@ -76,7 +76,7 @@ import static org.briarproject.api.introduction.IntroductionConstants.TYPE_REQUE
import static org.briarproject.api.introduction.IntroductionConstants.TYPE_RESPONSE;
import static org.briarproject.clients.BdfConstants.MSG_KEY_READ;
class IntroductionManagerImpl extends BdfIncomingMessageHook
class IntroductionManagerImpl extends ConversationClientImpl
implements IntroductionManager, Client, AddContactHook,
RemoveContactHook {
@@ -119,7 +119,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
public void addingContact(Transaction txn, Contact c) throws DbException {
try {
// Create an introduction group for sending introduction messages
Group g = introductionGroupFactory.createIntroductionGroup(c);
Group g = getContactGroup(c);
// Return if we've already set things up for this contact
if (db.containsGroup(txn, g.getId())) return;
// Store the group and share it with the contact
@@ -196,7 +196,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
// remove the group (all messages will be removed with it)
// this contact won't get our abort message, but the other will
db.removeGroup(txn, introductionGroupFactory.createIntroductionGroup(c));
db.removeGroup(txn, getContactGroup(c));
}
/**
@@ -288,6 +288,11 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
return false;
}
@Override
protected Group getContactGroup(Contact contact) {
return introductionGroupFactory.createIntroductionGroup(contact);
}
@Override
public void makeIntroduction(Contact c1, Contact c2, String msg,
final long timestamp)
@@ -296,8 +301,8 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
Transaction txn = db.startTransaction(false);
try {
introducerManager.makeIntroduction(txn, c1, c2, msg, timestamp);
Group g1 = introductionGroupFactory.createIntroductionGroup(c1);
Group g2 = introductionGroupFactory.createIntroductionGroup(c2);
Group g1 = getContactGroup(c1);
Group g2 = getContactGroup(c2);
trackMessage(txn, g1.getId(), timestamp, true);
trackMessage(txn, g2.getId(), timestamp, true);
txn.setComplete();
@@ -314,7 +319,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
Transaction txn = db.startTransaction(false);
try {
Contact c = db.getContact(txn, contactId);
Group g = introductionGroupFactory.createIntroductionGroup(c);
Group g = getContactGroup(c);
BdfDictionary state =
getSessionState(txn, g.getId(), sessionId.getBytes());
@@ -334,7 +339,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
Transaction txn = db.startTransaction(false);
try {
Contact c = db.getContact(txn, contactId);
Group g = introductionGroupFactory.createIntroductionGroup(c);
Group g = getContactGroup(c);
BdfDictionary state =
getSessionState(txn, g.getId(), sessionId.getBytes());
@@ -358,9 +363,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
Transaction txn = db.startTransaction(true);
try {
// get messages and their status
GroupId g = introductionGroupFactory
.createIntroductionGroup(db.getContact(txn, contactId))
.getId();
GroupId g = getContactGroup(db.getContact(txn, contactId)).getId();
metadata = clientHelper.getMessageMetadataAsDictionary(txn, g);
statuses = db.getMessageStatus(txn, contactId, g);
@@ -415,7 +418,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
name = state.getString(NAME);
}
IntroductionResponse ir = new IntroductionResponse(
sessionId, messageId, role, time, local,
sessionId, messageId, g, role, time, local,
s.isSent(), s.isSeen(), read, authorId, name,
accepted);
list.add(ir);
@@ -445,7 +448,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
state.getBoolean(REMOTE_AUTHOR_IS_US);
}
IntroductionRequest ir = new IntroductionRequest(
sessionId, messageId, role, time, local,
sessionId, messageId, g, role, time, local,
s.isSent(), s.isSeen(), read, authorId, name,
accepted, message, answered, exists,
introducesOtherIdentity);

View File

@@ -6,6 +6,7 @@ import org.briarproject.api.contact.ContactManager;
import org.briarproject.api.data.MetadataEncoder;
import org.briarproject.api.introduction.IntroductionManager;
import org.briarproject.api.lifecycle.LifecycleManager;
import org.briarproject.api.messaging.ConversationManager;
import org.briarproject.api.system.Clock;
import javax.inject.Inject;
@@ -47,6 +48,7 @@ public class IntroductionModule {
LifecycleManager lifecycleManager,
ContactManager contactManager,
MessageQueueManager messageQueueManager,
ConversationManager conversationManager,
IntroductionManagerImpl introductionManager) {
lifecycleManager.registerClient(introductionManager);
@@ -55,6 +57,7 @@ public class IntroductionModule {
messageQueueManager.registerIncomingMessageHook(
introductionManager.getClientId(),
introductionManager);
conversationManager.registerConversationClient(introductionManager);
return introductionManager;
}

View File

@@ -0,0 +1,80 @@
package org.briarproject.messaging;
import org.briarproject.api.clients.ContactGroupFactory;
import org.briarproject.api.clients.MessageTracker.GroupCount;
import org.briarproject.api.contact.Contact;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DbException;
import org.briarproject.api.db.Transaction;
import org.briarproject.api.messaging.ConversationManager;
import org.briarproject.api.sync.Group;
import org.briarproject.api.sync.GroupId;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.inject.Inject;
class ConversationManagerImpl implements ConversationManager {
private final DatabaseComponent db;
private final ContactGroupFactory contactGroupFactory;
private final Set<ConversationClient> clients;
@Inject
ConversationManagerImpl(DatabaseComponent db,
ContactGroupFactory contactGroupFactory) {
this.db = db;
this.contactGroupFactory = contactGroupFactory;
clients = new CopyOnWriteArraySet<ConversationClient>();
}
@Override
public void registerConversationClient(ConversationClient client) {
if (!clients.add(client)) {
throw new IllegalStateException(
"This client is already registered");
}
}
@Override
public GroupId getConversationId(ContactId contactId) throws DbException {
// TODO we should probably transition this to its own group
// and/or work with the ContactId in the UI instead
Contact contact;
Transaction txn = db.startTransaction(true);
try {
contact = db.getContact(txn, contactId);
txn.setComplete();
} finally {
db.endTransaction(txn);
}
Group group = contactGroupFactory
.createContactGroup(MessagingManagerImpl.CLIENT_ID, contact);
return group.getId();
}
@Override
public GroupCount getGroupCount(ContactId contactId)
throws DbException {
int msgCount = 0, unreadCount = 0;
long latestTime = 0;
Transaction txn = db.startTransaction(true);
try {
for (ConversationClient client : clients) {
GroupCount count = client.getGroupCount(txn, contactId);
msgCount += count.getMsgCount();
unreadCount += count.getUnreadCount();
if (count.getLatestMsgTime() > latestTime)
latestTime = count.getLatestMsgTime();
}
txn.setComplete();
} finally {
db.endTransaction(txn);
}
return new GroupCount(msgCount, unreadCount, latestTime);
}
}

View File

@@ -24,7 +24,7 @@ import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.Message;
import org.briarproject.api.sync.MessageId;
import org.briarproject.api.sync.MessageStatus;
import org.briarproject.clients.BdfIncomingMessageHook;
import org.briarproject.clients.ConversationClientImpl;
import org.briarproject.util.StringUtils;
import java.util.ArrayList;
@@ -35,7 +35,7 @@ import javax.inject.Inject;
import static org.briarproject.clients.BdfConstants.MSG_KEY_READ;
class MessagingManagerImpl extends BdfIncomingMessageHook
class MessagingManagerImpl extends ConversationClientImpl
implements MessagingManager, Client, AddContactHook, RemoveContactHook {
static final ClientId CLIENT_ID = new ClientId(StringUtils.fromHexString(
@@ -77,7 +77,8 @@ class MessagingManagerImpl extends BdfIncomingMessageHook
}
}
private Group getContactGroup(Contact c) {
@Override
protected Group getContactGroup(Contact c) {
return contactGroupFactory.createContactGroup(CLIENT_ID, c);
}
@@ -101,7 +102,8 @@ class MessagingManagerImpl extends BdfIncomingMessageHook
boolean local = meta.getBoolean("local");
boolean read = meta.getBoolean(MSG_KEY_READ);
PrivateMessageHeader header = new PrivateMessageHeader(
m.getId(), timestamp, contentType, local, read, false, false);
m.getId(), m.getGroupId(), timestamp, contentType, local, read,
false, false);
PrivateMessageReceivedEvent event = new PrivateMessageReceivedEvent(
header, groupId);
txn.attach(event);
@@ -159,9 +161,10 @@ class MessagingManagerImpl extends BdfIncomingMessageHook
throws DbException {
Map<MessageId, BdfDictionary> metadata;
Collection<MessageStatus> statuses;
GroupId g;
Transaction txn = db.startTransaction(true);
try {
GroupId g = getContactGroup(db.getContact(txn, c)).getId();
g = getContactGroup(db.getContact(txn, c)).getId();
metadata = clientHelper.getMessageMetadataAsDictionary(txn, g);
statuses = db.getMessageStatus(txn, c, g);
txn.setComplete();
@@ -181,8 +184,8 @@ class MessagingManagerImpl extends BdfIncomingMessageHook
String contentType = meta.getString("contentType");
boolean local = meta.getBoolean("local");
boolean read = meta.getBoolean("read");
headers.add(new PrivateMessageHeader(id, timestamp, contentType,
local, read, s.isSent(), s.isSeen()));
headers.add(new PrivateMessageHeader(id, g, timestamp,
contentType, local, read, s.isSent(), s.isSeen()));
} catch (FormatException e) {
throw new DbException(e);
}
@@ -201,4 +204,14 @@ class MessagingManagerImpl extends BdfIncomingMessageHook
}
}
@Override
public GroupCount getGroupCount(Transaction txn, ContactId contactId)
throws DbException {
Contact contact = db.getContact(txn, contactId);
GroupId groupId = getContactGroup(contact).getId();
return getGroupCount(txn, groupId);
}
}

View File

@@ -4,6 +4,7 @@ import org.briarproject.api.clients.ClientHelper;
import org.briarproject.api.contact.ContactManager;
import org.briarproject.api.data.MetadataEncoder;
import org.briarproject.api.lifecycle.LifecycleManager;
import org.briarproject.api.messaging.ConversationManager;
import org.briarproject.api.messaging.MessagingManager;
import org.briarproject.api.messaging.PrivateMessageFactory;
import org.briarproject.api.sync.ValidationManager;
@@ -22,6 +23,7 @@ public class MessagingModule {
public static class EagerSingletons {
@Inject MessagingManager messagingManager;
@Inject ConversationManager conversationManager;
@Inject PrivateMessageValidator privateMessageValidator;
}
@@ -46,12 +48,22 @@ public class MessagingModule {
@Singleton
MessagingManager getMessagingManager(LifecycleManager lifecycleManager,
ContactManager contactManager, ValidationManager validationManager,
ConversationManager conversationManager,
MessagingManagerImpl messagingManager) {
lifecycleManager.registerClient(messagingManager);
contactManager.registerAddContactHook(messagingManager);
contactManager.registerRemoveContactHook(messagingManager);
validationManager
.registerIncomingMessageHook(CLIENT_ID, messagingManager);
conversationManager.registerConversationClient(messagingManager);
return messagingManager;
}
@Provides
@Singleton
ConversationManager getConversationManager(
ConversationManagerImpl conversationManager) {
return conversationManager;
}
}

View File

@@ -5,6 +5,8 @@ import org.briarproject.api.contact.ContactId;
import org.briarproject.api.data.BdfDictionary;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static org.briarproject.api.blogs.BlogConstants.BLOG_AUTHOR_NAME;
import static org.briarproject.api.blogs.BlogConstants.BLOG_DESC;
@@ -21,8 +23,9 @@ public class BlogInviteeSessionState extends InviteeSessionState {
public BlogInviteeSessionState(SessionId sessionId, MessageId storageId,
GroupId groupId, State state, ContactId contactId, GroupId blogId,
String blogTitle, String blogDesc, String blogAuthorName,
byte[] blogPublicKey) {
super(sessionId, storageId, groupId, state, contactId, blogId);
byte[] blogPublicKey, @NotNull MessageId invitationId) {
super(sessionId, storageId, groupId, state, contactId, blogId,
invitationId);
this.blogTitle = blogTitle;
this.blogDesc = blogDesc;

View File

@@ -5,6 +5,7 @@ import org.briarproject.api.contact.ContactId;
import org.briarproject.api.data.BdfDictionary;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId;
import org.jetbrains.annotations.Nullable;
import static org.briarproject.api.blogs.BlogConstants.BLOG_AUTHOR_NAME;
import static org.briarproject.api.blogs.BlogConstants.BLOG_DESC;
@@ -21,8 +22,9 @@ public class BlogSharerSessionState extends SharerSessionState {
public BlogSharerSessionState(SessionId sessionId, MessageId storageId,
GroupId groupId, State state, ContactId contactId, GroupId blogId,
String blogTitle, String blogDesc, String blogAuthorName,
byte[] blogPublicKey) {
super(sessionId, storageId, groupId, state, contactId, blogId);
byte[] blogPublicKey, @Nullable MessageId responseId) {
super(sessionId, storageId, groupId, state, contactId, blogId,
responseId);
this.blogTitle = blogTitle;
this.blogDesc = blogDesc;

View File

@@ -10,8 +10,8 @@ import org.briarproject.api.blogs.BlogManager.RemoveBlogHook;
import org.briarproject.api.blogs.BlogSharingManager;
import org.briarproject.api.blogs.BlogSharingMessage.BlogInvitation;
import org.briarproject.api.clients.ClientHelper;
import org.briarproject.api.clients.MessageQueueManager;
import org.briarproject.api.clients.ContactGroupFactory;
import org.briarproject.api.clients.MessageQueueManager;
import org.briarproject.api.clients.SessionId;
import org.briarproject.api.contact.Contact;
import org.briarproject.api.contact.ContactId;
@@ -43,6 +43,8 @@ import static org.briarproject.api.blogs.BlogConstants.BLOG_AUTHOR_NAME;
import static org.briarproject.api.blogs.BlogConstants.BLOG_DESC;
import static org.briarproject.api.blogs.BlogConstants.BLOG_PUBLIC_KEY;
import static org.briarproject.api.blogs.BlogConstants.BLOG_TITLE;
import static org.briarproject.api.sharing.SharingConstants.INVITATION_ID;
import static org.briarproject.api.sharing.SharingConstants.RESPONSE_ID;
class BlogSharingManagerImpl extends
SharingManagerImpl<Blog, BlogInvitation, BlogInviteeSessionState, BlogSharerSessionState, BlogInvitationReceivedEvent, BlogInvitationResponseReceivedEvent>
@@ -108,17 +110,18 @@ class BlogSharingManagerImpl extends
BlogInvitation msg, ContactId contactId, boolean available,
long time, boolean local, boolean sent, boolean seen,
boolean read) {
return new BlogInvitationRequest(id, msg.getSessionId(), contactId,
msg.getBlogAuthorName(), msg.getMessage(), available, time,
local, sent, seen, read);
return new BlogInvitationRequest(id, msg.getSessionId(),
msg.getGroupId(), contactId, msg.getBlogAuthorName(),
msg.getMessage(), available, time, local, sent, seen, read);
}
@Override
protected InvitationMessage createInvitationResponse(MessageId id,
SessionId sessionId, ContactId contactId, boolean accept, long time,
SessionId sessionId, GroupId groupId, ContactId contactId,
boolean accept, long time,
boolean local, boolean sent, boolean seen, boolean read) {
return new BlogInvitationResponse(id, sessionId, contactId, accept,
time, local, sent, seen, read);
return new BlogInvitationResponse(id, sessionId, groupId, contactId,
accept, time, local, sent, seen, read);
}
@Override
@@ -163,7 +166,7 @@ class BlogSharingManagerImpl extends
private final BlogFactory blogFactory;
private final BlogManager blogManager;
SFactory(AuthorFactory authorFactory, BlogFactory BlogFactory,
private SFactory(AuthorFactory authorFactory, BlogFactory BlogFactory,
BlogManager BlogManager) {
this.authorFactory = authorFactory;
this.blogFactory = BlogFactory;
@@ -230,11 +233,13 @@ class BlogSharingManagerImpl extends
}
@Override
public BlogInvitation build(BlogSharerSessionState localState) {
public BlogInvitation build(BlogSharerSessionState localState,
long time) {
return new BlogInvitation(localState.getGroupId(),
localState.getSessionId(), localState.getBlogTitle(),
localState.getBlogDesc(), localState.getBlogAuthorName(),
localState.getBlogPublicKey(), localState.getMessage());
localState.getBlogPublicKey(), time,
localState.getMessage());
}
}
@@ -249,20 +254,21 @@ class BlogSharingManagerImpl extends
String blogDesc = d.getString(BLOG_DESC);
String blogAuthorName = d.getString(BLOG_AUTHOR_NAME);
byte[] blogPublicKey = d.getRaw(BLOG_PUBLIC_KEY);
MessageId invitationId = new MessageId(d.getRaw(INVITATION_ID));
return new BlogInviteeSessionState(sessionId, storageId,
groupId, state, contactId, blogId, blogTitle, blogDesc,
blogAuthorName, blogPublicKey);
blogAuthorName, blogPublicKey, invitationId);
}
@Override
public BlogInviteeSessionState build(SessionId sessionId,
MessageId storageId, GroupId groupId,
InviteeSessionState.State state, ContactId contactId,
Blog blog) {
Blog blog, MessageId invitationId) {
return new BlogInviteeSessionState(sessionId, storageId,
groupId, state, contactId, blog.getId(), blog.getName(),
blog.getDescription(), blog.getAuthor().getName(),
blog.getAuthor().getPublicKey());
blog.getAuthor().getPublicKey(), invitationId);
}
}
@@ -277,9 +283,13 @@ class BlogSharingManagerImpl extends
String blogDesc = d.getString(BLOG_DESC);
String blogAuthorName = d.getString(BLOG_AUTHOR_NAME);
byte[] blogPublicKey = d.getRaw(BLOG_PUBLIC_KEY);
MessageId responseId = null;
byte[] responseIdBytes = d.getOptionalRaw(RESPONSE_ID);
if (responseIdBytes != null)
responseId = new MessageId(responseIdBytes);
return new BlogSharerSessionState(sessionId, storageId,
groupId, state, contactId, blogId, blogTitle, blogDesc,
blogAuthorName, blogPublicKey);
blogAuthorName, blogPublicKey, responseId);
}
@Override
@@ -290,7 +300,7 @@ class BlogSharingManagerImpl extends
return new BlogSharerSessionState(sessionId, storageId,
groupId, state, contactId, blog.getId(), blog.getName(),
blog.getDescription(), blog.getAuthor().getName(),
blog.getAuthor().getPublicKey());
blog.getAuthor().getPublicKey(), null);
}
}
@@ -299,16 +309,21 @@ class BlogSharingManagerImpl extends
private final SFactory sFactory;
IRFactory(SFactory sFactory) {
private IRFactory(SFactory sFactory) {
this.sFactory = sFactory;
}
@Override
public BlogInvitationReceivedEvent build(
BlogInviteeSessionState localState) {
BlogInviteeSessionState localState, long time, String msg) {
Blog blog = sFactory.parse(localState);
ContactId contactId = localState.getContactId();
return new BlogInvitationReceivedEvent(blog, contactId);
BlogInvitationRequest request =
new BlogInvitationRequest(localState.getInvitationId(),
localState.getSessionId(), localState.getGroupId(),
contactId, blog.getAuthor().getName(), msg, true,
time, false, false, false, false);
return new BlogInvitationReceivedEvent(blog, contactId, request);
}
}
@@ -316,10 +331,18 @@ class BlogSharingManagerImpl extends
InvitationResponseReceivedEventFactory<BlogSharerSessionState, BlogInvitationResponseReceivedEvent> {
@Override
public BlogInvitationResponseReceivedEvent build(
BlogSharerSessionState localState) {
BlogSharerSessionState localState, boolean accept, long time) {
String title = localState.getBlogTitle();
ContactId c = localState.getContactId();
return new BlogInvitationResponseReceivedEvent(title, c);
MessageId responseId = localState.getResponseId();
if (responseId == null)
throw new IllegalStateException("No responseId");
BlogInvitationResponse response =
new BlogInvitationResponse(responseId,
localState.getSessionId(), localState.getGroupId(),
localState.getContactId(), accept, time, false,
false, false, false);
return new BlogInvitationResponseReceivedEvent(title, c, response);
}
}
}

View File

@@ -5,6 +5,7 @@ import org.briarproject.api.contact.ContactId;
import org.briarproject.api.data.BdfDictionary;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId;
import org.jetbrains.annotations.NotNull;
import static org.briarproject.api.forum.ForumConstants.FORUM_NAME;
import static org.briarproject.api.forum.ForumConstants.FORUM_SALT;
@@ -16,8 +17,10 @@ public class ForumInviteeSessionState extends InviteeSessionState {
public ForumInviteeSessionState(SessionId sessionId, MessageId storageId,
GroupId groupId, State state, ContactId contactId, GroupId forumId,
String forumName, byte[] forumSalt) {
super(sessionId, storageId, groupId, state, contactId, forumId);
String forumName, byte[] forumSalt,
@NotNull MessageId invitationId) {
super(sessionId, storageId, groupId, state, contactId, forumId,
invitationId);
this.forumName = forumName;
this.forumSalt = forumSalt;

View File

@@ -5,6 +5,7 @@ import org.briarproject.api.contact.ContactId;
import org.briarproject.api.data.BdfDictionary;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId;
import org.jetbrains.annotations.Nullable;
import static org.briarproject.api.forum.ForumConstants.FORUM_NAME;
import static org.briarproject.api.forum.ForumConstants.FORUM_SALT;
@@ -16,8 +17,10 @@ class ForumSharerSessionState extends SharerSessionState {
ForumSharerSessionState(SessionId sessionId, MessageId storageId,
GroupId groupId, State state, ContactId contactId, GroupId forumId,
String forumName, byte[] forumSalt) {
super(sessionId, storageId, groupId, state, contactId, forumId);
String forumName, byte[] forumSalt,
@Nullable MessageId responseId) {
super(sessionId, storageId, groupId, state, contactId, forumId,
responseId);
this.forumName = forumName;
this.forumSalt = forumSalt;

View File

@@ -2,8 +2,8 @@ package org.briarproject.sharing;
import org.briarproject.api.FormatException;
import org.briarproject.api.clients.ClientHelper;
import org.briarproject.api.clients.MessageQueueManager;
import org.briarproject.api.clients.ContactGroupFactory;
import org.briarproject.api.clients.MessageQueueManager;
import org.briarproject.api.clients.SessionId;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.data.BdfDictionary;
@@ -35,6 +35,8 @@ import javax.inject.Inject;
import static org.briarproject.api.forum.ForumConstants.FORUM_NAME;
import static org.briarproject.api.forum.ForumConstants.FORUM_SALT;
import static org.briarproject.api.sharing.SharingConstants.INVITATION_ID;
import static org.briarproject.api.sharing.SharingConstants.RESPONSE_ID;
class ForumSharingManagerImpl extends
SharingManagerImpl<Forum, ForumInvitation, ForumInviteeSessionState, ForumSharerSessionState, ForumInvitationReceivedEvent, ForumInvitationResponseReceivedEvent>
@@ -82,17 +84,18 @@ class ForumSharingManagerImpl extends
ForumInvitation msg, ContactId contactId, boolean available,
long time, boolean local, boolean sent, boolean seen,
boolean read) {
return new ForumInvitationRequest(id, msg.getSessionId(), contactId,
msg.getForumName(), msg.getMessage(), available, time, local,
sent, seen, read);
return new ForumInvitationRequest(id, msg.getSessionId(),
msg.getGroupId(), contactId, msg.getForumName(),
msg.getMessage(), available, time, local, sent, seen, read);
}
@Override
protected InvitationMessage createInvitationResponse(MessageId id,
SessionId sessionId, ContactId contactId, boolean accept,
long time, boolean local, boolean sent, boolean seen, boolean read) {
return new ForumInvitationResponse(id, sessionId, contactId, accept,
time, local, sent, seen, read);
SessionId sessionId, GroupId groupId, ContactId contactId,
boolean accept, long time, boolean local, boolean sent,
boolean seen, boolean read) {
return new ForumInvitationResponse(id, sessionId, groupId, contactId,
accept, time, local, sent, seen, read);
}
@Override
@@ -136,7 +139,7 @@ class ForumSharingManagerImpl extends
private final ForumFactory forumFactory;
private final ForumManager forumManager;
SFactory(ForumFactory forumFactory, ForumManager forumManager) {
private SFactory(ForumFactory forumFactory, ForumManager forumManager) {
this.forumFactory = forumFactory;
this.forumManager = forumManager;
}
@@ -185,10 +188,11 @@ class ForumSharingManagerImpl extends
}
@Override
public ForumInvitation build(ForumSharerSessionState localState) {
public ForumInvitation build(ForumSharerSessionState localState,
long time) {
return new ForumInvitation(localState.getGroupId(),
localState.getSessionId(), localState.getForumName(),
localState.getForumSalt(), localState.getMessage());
localState.getForumSalt(), time, localState.getMessage());
}
}
@@ -201,18 +205,20 @@ class ForumSharingManagerImpl extends
GroupId forumId, BdfDictionary d) throws FormatException {
String forumName = d.getString(FORUM_NAME);
byte[] forumSalt = d.getRaw(FORUM_SALT);
MessageId invitationId = new MessageId(d.getRaw(INVITATION_ID));
return new ForumInviteeSessionState(sessionId, storageId,
groupId, state, contactId, forumId, forumName, forumSalt);
groupId, state, contactId, forumId, forumName, forumSalt,
invitationId);
}
@Override
public ForumInviteeSessionState build(SessionId sessionId,
MessageId storageId, GroupId groupId,
InviteeSessionState.State state, ContactId contactId,
Forum forum) {
Forum forum, MessageId invitationId) {
return new ForumInviteeSessionState(sessionId, storageId,
groupId, state, contactId, forum.getId(), forum.getName(),
forum.getSalt());
forum.getSalt(), invitationId);
}
}
@@ -225,8 +231,13 @@ class ForumSharingManagerImpl extends
GroupId forumId, BdfDictionary d) throws FormatException {
String forumName = d.getString(FORUM_NAME);
byte[] forumSalt = d.getRaw(FORUM_SALT);
MessageId responseId = null;
byte[] responseIdBytes = d.getOptionalRaw(RESPONSE_ID);
if (responseIdBytes != null)
responseId = new MessageId(responseIdBytes);
return new ForumSharerSessionState(sessionId, storageId,
groupId, state, contactId, forumId, forumName, forumSalt);
groupId, state, contactId, forumId, forumName, forumSalt,
responseId);
}
@Override
@@ -236,7 +247,7 @@ class ForumSharingManagerImpl extends
Forum forum) {
return new ForumSharerSessionState(sessionId, storageId,
groupId, state, contactId, forum.getId(), forum.getName(),
forum.getSalt());
forum.getSalt(), null);
}
}
@@ -245,16 +256,20 @@ class ForumSharingManagerImpl extends
private final SFactory sFactory;
IRFactory(SFactory sFactory) {
private IRFactory(SFactory sFactory) {
this.sFactory = sFactory;
}
@Override
public ForumInvitationReceivedEvent build(
ForumInviteeSessionState localState) {
ForumInviteeSessionState localState, long time, String msg) {
Forum forum = sFactory.parse(localState);
ContactId contactId = localState.getContactId();
return new ForumInvitationReceivedEvent(forum, contactId);
ForumInvitationRequest request = new ForumInvitationRequest(
localState.getInvitationId(), localState.getSessionId(),
localState.getGroupId(), contactId, forum.getName(), msg,
true, time, false, false, false, false);
return new ForumInvitationReceivedEvent(forum, contactId, request);
}
}
@@ -262,10 +277,17 @@ class ForumSharingManagerImpl extends
InvitationResponseReceivedEventFactory<ForumSharerSessionState, ForumInvitationResponseReceivedEvent> {
@Override
public ForumInvitationResponseReceivedEvent build(
ForumSharerSessionState localState) {
ForumSharerSessionState localState, boolean accept, long time) {
String name = localState.getForumName();
ContactId c = localState.getContactId();
return new ForumInvitationResponseReceivedEvent(name, c);
MessageId responseId = localState.getResponseId();
if (responseId == null)
throw new IllegalStateException("No responseId");
ForumInvitationResponse response = new ForumInvitationResponse(
responseId, localState.getSessionId(),
localState.getGroupId(), localState.getContactId(), accept,
time, false, false, false, false);
return new ForumInvitationResponseReceivedEvent(name, c, response);
}
}
}

View File

@@ -5,5 +5,5 @@ import org.briarproject.api.sharing.SharingMessage;
public interface InvitationFactory<I extends SharingMessage.Invitation, SS extends SharerSessionState> extends
org.briarproject.api.sharing.InvitationFactory<I> {
I build(SS localState);
I build(SS localState, long time);
}

View File

@@ -1,8 +1,8 @@
package org.briarproject.sharing;
import org.briarproject.api.event.InvitationReceivedEvent;
import org.briarproject.api.event.InvitationRequestReceivedEvent;
public interface InvitationReceivedEventFactory<IS extends InviteeSessionState, IR extends InvitationReceivedEvent> {
public interface InvitationReceivedEventFactory<IS extends InviteeSessionState, IR extends InvitationRequestReceivedEvent> {
IR build(IS localState);
IR build(IS localState, long time, String msg);
}

View File

@@ -4,5 +4,5 @@ import org.briarproject.api.event.InvitationResponseReceivedEvent;
public interface InvitationResponseReceivedEventFactory<SS extends SharerSessionState, IRR extends InvitationResponseReceivedEvent> {
IRR build(SS localState);
IRR build(SS localState, boolean accept, long time);
}

View File

@@ -3,7 +3,9 @@ package org.briarproject.sharing;
import org.briarproject.api.FormatException;
import org.briarproject.api.clients.ProtocolEngine;
import org.briarproject.api.event.Event;
import org.briarproject.api.event.InvitationReceivedEvent;
import org.briarproject.api.event.InvitationRequestReceivedEvent;
import org.briarproject.api.sharing.SharingMessage.Invitation;
import org.briarproject.api.system.Clock;
import java.util.Collections;
import java.util.List;
@@ -23,16 +25,20 @@ import static org.briarproject.api.sharing.SharingConstants.TASK_UNSHARE_SHAREAB
import static org.briarproject.api.sharing.SharingMessage.BaseMessage;
import static org.briarproject.api.sharing.SharingMessage.SimpleMessage;
class InviteeEngine<IS extends InviteeSessionState, IR extends InvitationReceivedEvent>
class InviteeEngine<IS extends InviteeSessionState, IR extends InvitationRequestReceivedEvent>
implements ProtocolEngine<InviteeSessionState.Action, IS, BaseMessage> {
private static final Logger LOG =
Logger.getLogger(InviteeEngine.class.getName());
private final InvitationReceivedEventFactory<IS, IR> invitationReceivedEventFactory;
private final Clock clock;
InviteeEngine(InvitationReceivedEventFactory<IS, IR> invitationReceivedEventFactory) {
InviteeEngine(
InvitationReceivedEventFactory<IS, IR> invitationReceivedEventFactory,
Clock clock) {
this.invitationReceivedEventFactory = invitationReceivedEventFactory;
this.clock = clock;
}
@Override
@@ -63,19 +69,22 @@ class InviteeEngine<IS extends InviteeSessionState, IR extends InvitationReceive
if (action == InviteeSessionState.Action.LOCAL_ACCEPT) {
localState.setTask(TASK_ADD_SHARED_SHAREABLE);
msg = new SimpleMessage(SHARE_MSG_TYPE_ACCEPT,
localState.getGroupId(), localState.getSessionId());
localState.getGroupId(), localState.getSessionId(),
clock.currentTimeMillis());
} else {
localState.setTask(
TASK_REMOVE_SHAREABLE_FROM_LIST_SHARED_WITH_US);
msg = new SimpleMessage(SHARE_MSG_TYPE_DECLINE,
localState.getGroupId(), localState.getSessionId());
localState.getGroupId(), localState.getSessionId(),
clock.currentTimeMillis());
}
messages = Collections.singletonList(msg);
logLocalAction(currentState, localState, msg);
}
else if (action == InviteeSessionState.Action.LOCAL_LEAVE) {
BaseMessage msg = new SimpleMessage(SHARE_MSG_TYPE_LEAVE,
localState.getGroupId(), localState.getSessionId());
localState.getGroupId(), localState.getSessionId(),
clock.currentTimeMillis());
messages = Collections.singletonList(msg);
logLocalAction(currentState, localState, msg);
}
@@ -133,7 +142,9 @@ class InviteeEngine<IS extends InviteeSessionState, IR extends InvitationReceive
// we have just received our invitation
else if (action == InviteeSessionState.Action.REMOTE_INVITATION) {
localState.setTask(TASK_ADD_SHAREABLE_TO_LIST_SHARED_WITH_US);
Event event = invitationReceivedEventFactory.build(localState);
Invitation invitation = (Invitation) msg;
Event event = invitationReceivedEventFactory.build(localState,
msg.getTime(), invitation.getMessage());
events = Collections.singletonList(event);
}
else {
@@ -203,7 +214,7 @@ class InviteeEngine<IS extends InviteeSessionState, IR extends InvitationReceive
localState.setState(InviteeSessionState.State.ERROR);
BaseMessage msg =
new SimpleMessage(SHARE_MSG_TYPE_ABORT, localState.getGroupId(),
localState.getSessionId());
localState.getSessionId(), clock.currentTimeMillis());
List<BaseMessage> messages = Collections.singletonList(msg);
List<Event> events = Collections.emptyList();

View File

@@ -5,7 +5,9 @@ import org.briarproject.api.contact.ContactId;
import org.briarproject.api.data.BdfDictionary;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId;
import org.jetbrains.annotations.NotNull;
import static org.briarproject.api.sharing.SharingConstants.INVITATION_ID;
import static org.briarproject.api.sharing.SharingConstants.IS_SHARER;
import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_ABORT;
import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_INVITATION;
@@ -21,19 +23,23 @@ import static org.briarproject.sharing.InviteeSessionState.Action.REMOTE_LEAVE;
public abstract class InviteeSessionState extends SharingSessionState {
private State state;
@NotNull
private final MessageId invitationId;
public InviteeSessionState(SessionId sessionId, MessageId storageId,
GroupId groupId, State state, ContactId contactId,
GroupId shareableId) {
GroupId shareableId, @NotNull MessageId invitationId) {
super(sessionId, storageId, groupId, contactId, shareableId);
this.state = state;
this.invitationId = invitationId;
}
public BdfDictionary toBdfDictionary() {
BdfDictionary d = super.toBdfDictionary();
d.put(STATE, getState().getValue());
d.put(IS_SHARER, false);
d.put(INVITATION_ID, invitationId);
return d;
}
@@ -45,6 +51,11 @@ public abstract class InviteeSessionState extends SharingSessionState {
return state;
}
@NotNull
public MessageId getInvitationId() {
return invitationId;
}
public enum State {
ERROR(0),
AWAIT_INVITATION(1) {

View File

@@ -15,5 +15,6 @@ public interface InviteeSessionStateFactory<S extends Shareable, IS extends Invi
GroupId shareableId, BdfDictionary d) throws FormatException;
IS build(SessionId sessionId, MessageId storageId, GroupId groupId,
InviteeSessionState.State state, ContactId contactId, S shareable);
InviteeSessionState.State state, ContactId contactId, S shareable,
MessageId invitationId);
}

View File

@@ -4,6 +4,7 @@ import org.briarproject.api.FormatException;
import org.briarproject.api.clients.ProtocolEngine;
import org.briarproject.api.event.Event;
import org.briarproject.api.event.InvitationResponseReceivedEvent;
import org.briarproject.api.system.Clock;
import java.util.Collections;
import java.util.List;
@@ -22,6 +23,8 @@ import static org.briarproject.api.sharing.SharingConstants.TASK_UNSHARE_SHAREAB
import static org.briarproject.api.sharing.SharingMessage.BaseMessage;
import static org.briarproject.api.sharing.SharingMessage.Invitation;
import static org.briarproject.api.sharing.SharingMessage.SimpleMessage;
import static org.briarproject.sharing.SharerSessionState.Action.REMOTE_ACCEPT;
import static org.briarproject.sharing.SharerSessionState.Action.REMOTE_DECLINE;
class SharerEngine<I extends Invitation, SS extends SharerSessionState, IRR extends InvitationResponseReceivedEvent>
implements ProtocolEngine<SharerSessionState.Action, SS, BaseMessage> {
@@ -32,12 +35,15 @@ class SharerEngine<I extends Invitation, SS extends SharerSessionState, IRR exte
private final InvitationFactory<I, SS> invitationFactory;
private final InvitationResponseReceivedEventFactory<SS, IRR>
invitationResponseReceivedEventFactory;
private final Clock clock;
SharerEngine(InvitationFactory<I, SS> invitationFactory,
InvitationResponseReceivedEventFactory<SS, IRR> invitationResponseReceivedEventFactory) {
InvitationResponseReceivedEventFactory<SS, IRR> invitationResponseReceivedEventFactory,
Clock clock) {
this.invitationFactory = invitationFactory;
this.invitationResponseReceivedEventFactory =
invitationResponseReceivedEventFactory;
this.clock = clock;
}
@Override
@@ -65,7 +71,8 @@ class SharerEngine<I extends Invitation, SS extends SharerSessionState, IRR exte
List<Event> events = Collections.emptyList();
if (action == SharerSessionState.Action.LOCAL_INVITATION) {
BaseMessage msg = invitationFactory.build(localState);
BaseMessage msg = invitationFactory.build(localState,
clock.currentTimeMillis());
messages = Collections.singletonList(msg);
logLocalAction(currentState, nextState, msg);
@@ -74,7 +81,8 @@ class SharerEngine<I extends Invitation, SS extends SharerSessionState, IRR exte
.setTask(TASK_ADD_SHAREABLE_TO_LIST_TO_BE_SHARED_BY_US);
} else if (action == SharerSessionState.Action.LOCAL_LEAVE) {
BaseMessage msg = new SimpleMessage(SHARE_MSG_TYPE_LEAVE,
localState.getGroupId(), localState.getSessionId());
localState.getGroupId(), localState.getSessionId(),
clock.currentTimeMillis());
messages = Collections.singletonList(msg);
logLocalAction(currentState, nextState, msg);
} else {
@@ -122,9 +130,8 @@ class SharerEngine<I extends Invitation, SS extends SharerSessionState, IRR exte
deleteMsg = true;
}
// we have sent our invitation and just got a response
else if (action == SharerSessionState.Action.REMOTE_ACCEPT ||
action == SharerSessionState.Action.REMOTE_DECLINE) {
if (action == SharerSessionState.Action.REMOTE_ACCEPT) {
else if (action == REMOTE_ACCEPT || action == REMOTE_DECLINE) {
if (action == REMOTE_ACCEPT) {
localState.setTask(TASK_SHARE_SHAREABLE);
} else {
// this ensures that the forum can be shared again
@@ -132,7 +139,8 @@ class SharerEngine<I extends Invitation, SS extends SharerSessionState, IRR exte
TASK_REMOVE_SHAREABLE_FROM_LIST_TO_BE_SHARED_BY_US);
}
Event event = invitationResponseReceivedEventFactory
.build(localState);
.build(localState, action == REMOTE_ACCEPT,
msg.getTime());
events = Collections.singletonList(event);
} else {
throw new IllegalArgumentException("Bad state");
@@ -204,7 +212,8 @@ class SharerEngine<I extends Invitation, SS extends SharerSessionState, IRR exte
localState.setState(SharerSessionState.State.ERROR);
BaseMessage msg = new SimpleMessage(SHARE_MSG_TYPE_ABORT,
localState.getGroupId(), localState.getSessionId());
localState.getGroupId(), localState.getSessionId(),
clock.currentTimeMillis());
List<BaseMessage> messages = Collections.singletonList(msg);
List<Event> events = Collections.emptyList();

View File

@@ -5,8 +5,10 @@ import org.briarproject.api.contact.ContactId;
import org.briarproject.api.data.BdfDictionary;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId;
import org.jetbrains.annotations.Nullable;
import static org.briarproject.api.sharing.SharingConstants.IS_SHARER;
import static org.briarproject.api.sharing.SharingConstants.RESPONSE_ID;
import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_ABORT;
import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_ACCEPT;
import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_DECLINE;
@@ -22,20 +24,25 @@ import static org.briarproject.sharing.SharerSessionState.Action.REMOTE_LEAVE;
public abstract class SharerSessionState extends SharingSessionState {
private State state;
@Nullable
private String msg = null;
@Nullable
private MessageId responseId;
public SharerSessionState(SessionId sessionId, MessageId storageId,
GroupId groupId, State state, ContactId contactId,
GroupId shareableId) {
GroupId shareableId, @Nullable MessageId responseId) {
super(sessionId, storageId, groupId, contactId, shareableId);
this.state = state;
this.responseId = responseId;
}
public BdfDictionary toBdfDictionary() {
BdfDictionary d = super.toBdfDictionary();
d.put(STATE, getState().getValue());
d.put(IS_SHARER, true);
if (responseId != null) d.put(RESPONSE_ID, responseId);
return d;
}
@@ -55,6 +62,15 @@ public abstract class SharerSessionState extends SharingSessionState {
return this.msg;
}
public void setResponseId(@Nullable MessageId responseId) {
this.responseId = responseId;
}
@Nullable
public MessageId getResponseId() {
return responseId;
}
public enum State {
ERROR(0),
PREPARE_INVITATION(1) {

View File

@@ -4,8 +4,8 @@ import org.briarproject.api.Bytes;
import org.briarproject.api.FormatException;
import org.briarproject.api.clients.Client;
import org.briarproject.api.clients.ClientHelper;
import org.briarproject.api.clients.MessageQueueManager;
import org.briarproject.api.clients.ContactGroupFactory;
import org.briarproject.api.clients.MessageQueueManager;
import org.briarproject.api.clients.SessionId;
import org.briarproject.api.contact.Contact;
import org.briarproject.api.contact.ContactId;
@@ -22,7 +22,7 @@ import org.briarproject.api.db.Metadata;
import org.briarproject.api.db.NoSuchMessageException;
import org.briarproject.api.db.Transaction;
import org.briarproject.api.event.Event;
import org.briarproject.api.event.InvitationReceivedEvent;
import org.briarproject.api.event.InvitationRequestReceivedEvent;
import org.briarproject.api.event.InvitationResponseReceivedEvent;
import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.sharing.InvitationItem;
@@ -36,7 +36,7 @@ import org.briarproject.api.sync.Message;
import org.briarproject.api.sync.MessageId;
import org.briarproject.api.sync.MessageStatus;
import org.briarproject.api.system.Clock;
import org.briarproject.clients.BdfIncomingMessageHook;
import org.briarproject.clients.ConversationClientImpl;
import org.briarproject.util.StringUtils;
import java.io.IOException;
@@ -85,8 +85,8 @@ import static org.briarproject.api.sharing.SharingMessage.Invitation;
import static org.briarproject.clients.BdfConstants.MSG_KEY_READ;
import static org.briarproject.sharing.InviteeSessionState.State.AWAIT_LOCAL_RESPONSE;
abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS extends InviteeSessionState, SS extends SharerSessionState, IR extends InvitationReceivedEvent, IRR extends InvitationResponseReceivedEvent>
extends BdfIncomingMessageHook
abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS extends InviteeSessionState, SS extends SharerSessionState, IR extends InvitationRequestReceivedEvent, IRR extends InvitationResponseReceivedEvent>
extends ConversationClientImpl
implements SharingManager<S>, Client, AddContactHook,
RemoveContactHook {
@@ -117,13 +117,14 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
public abstract ClientId getClientId();
protected abstract InvitationMessage createInvitationRequest(MessageId id, I msg,
ContactId contactId, boolean available, long time, boolean local,
boolean sent, boolean seen, boolean read);
protected abstract InvitationMessage createInvitationRequest(MessageId id,
I msg, ContactId contactId, boolean available, long time,
boolean local, boolean sent, boolean seen, boolean read);
protected abstract InvitationMessage createInvitationResponse(MessageId id,
SessionId sessionId, ContactId contactId, boolean accept, long time,
boolean local, boolean sent, boolean seen, boolean read);
SessionId sessionId, GroupId groupId, ContactId contactId,
boolean accept, long time, boolean local, boolean sent,
boolean seen, boolean read);
protected abstract ShareableFactory<S, I, IS, SS> getSFactory();
@@ -219,9 +220,10 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
checkForRaceCondition(txn, f, contact);
// initialize state and process invitation
IS state = initializeInviteeState(txn, contactId, invitation);
IS state = initializeInviteeState(txn, contactId, invitation,
m.getId());
InviteeEngine<IS, IR> engine =
new InviteeEngine<IS, IR>(getIRFactory());
new InviteeEngine<IS, IR>(getIRFactory(), clock);
processInviteeStateUpdate(txn, m.getId(),
engine.onMessageReceived(state, msg));
trackIncomingMessage(txn, m);
@@ -233,9 +235,10 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
msg.getType() == SHARE_MSG_TYPE_DECLINE) {
// we are a sharer who just received a response
SS state = getSessionStateForSharer(txn, sessionId);
state.setResponseId(m.getId());
SharerEngine<I, SS, IRR> engine =
new SharerEngine<I, SS, IRR>(getIFactory(),
getIRRFactory());
getIRRFactory(), clock);
processSharerStateUpdate(txn, m.getId(),
engine.onMessageReceived(state, msg));
trackIncomingMessage(txn, m);
@@ -248,14 +251,14 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
SS state = (SS) s;
SharerEngine<I, SS, IRR> engine =
new SharerEngine<I, SS, IRR>(getIFactory(),
getIRRFactory());
getIRRFactory(), clock);
processSharerStateUpdate(txn, m.getId(),
engine.onMessageReceived(state, msg));
} else {
// we are an invitee and the sharer wants to leave or abort
IS state = (IS) s;
InviteeEngine<IS, IR> engine =
new InviteeEngine<IS, IR>(getIRFactory());
new InviteeEngine<IS, IR>(getIRFactory(), clock);
processInviteeStateUpdate(txn, m.getId(),
engine.onMessageReceived(state, msg));
}
@@ -285,13 +288,15 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
// start engine and process its state update
SharerEngine<I, SS, IRR> engine =
new SharerEngine<I, SS, IRR>(getIFactory(),
getIRRFactory());
processSharerStateUpdate(txn, null,
getIRRFactory(), clock);
StateUpdate<SS, BaseMessage> update =
engine.onLocalAction(localState,
SharerSessionState.Action.LOCAL_INVITATION));
SharerSessionState.Action.LOCAL_INVITATION);
processSharerStateUpdate(txn, null, update);
// track message
long time = clock.currentTimeMillis();
// TODO handle this properly without engine hacks (#376)
long time = update.toSend.get(0).getTime();
trackMessage(txn, localState.getGroupId(), time, true);
txn.setComplete();
@@ -321,12 +326,14 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
// start engine and process its state update
InviteeEngine<IS, IR> engine =
new InviteeEngine<IS, IR>(getIRFactory());
processInviteeStateUpdate(txn, null,
engine.onLocalAction(localState, localAction));
new InviteeEngine<IS, IR>(getIRFactory(), clock);
StateUpdate<IS, BaseMessage> update =
engine.onLocalAction(localState, localAction);
processInviteeStateUpdate(txn, null, update);
// track message
long time = clock.currentTimeMillis();
// TODO handle this properly without engine hacks (#376)
long time = update.toSend.get(0).getTime();
trackMessage(txn, localState.getGroupId(), time, true);
txn.setComplete();
@@ -387,8 +394,9 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
.from(getIFactory(), group.getId(), d);
SessionId sessionId = msg.getSessionId();
InvitationMessage im = createInvitationResponse(
m.getKey(), sessionId, contactId, accept, time,
local, status.isSent(), status.isSeen(), read);
m.getKey(), sessionId, group.getId(), contactId,
accept, time, local, status.isSent(),
status.isSeen(), read);
list.add(im);
}
else {
@@ -555,6 +563,16 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
}
}
@Override
public GroupCount getGroupCount(Transaction txn, ContactId contactId)
throws DbException {
Contact contact = db.getContact(txn, contactId);
GroupId groupId = getContactGroup(contact).getId();
return getGroupCount(txn, groupId);
}
void removingShareable(Transaction txn, S f) throws DbException {
try {
for (Contact c : db.getContacts(txn)) {
@@ -642,7 +660,7 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
}
private IS initializeInviteeState(Transaction txn,
ContactId contactId, I msg)
ContactId contactId, I msg, MessageId id)
throws FormatException, DbException {
Contact c = db.getContact(txn, contactId);
@@ -656,9 +674,10 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
Message m = clientHelper.createMessage(localGroup.getId(), now,
BdfList.of(mSalt));
IS s = getISFactory().build(msg.getSessionId(),
m.getId(), group.getId(),
InviteeSessionState.State.AWAIT_INVITATION, contactId, f);
IS s = getISFactory()
.build(msg.getSessionId(), m.getId(), group.getId(),
InviteeSessionState.State.AWAIT_INVITATION, contactId,
f, id);
// save local state to database
BdfDictionary d = s.toBdfDictionary();
@@ -898,19 +917,19 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
byte[] body = clientHelper.toByteArray(m.toBdfList());
Group group = db.getGroup(txn, m.getGroupId());
long timestamp = clock.currentTimeMillis();
// add message itself as metadata
BdfDictionary d = m.toBdfDictionary();
d.put(LOCAL, true);
d.put(TIME, timestamp);
d.put(TIME, m.getTime());
Metadata meta = metadataEncoder.encode(d);
messageQueueManager
.sendMessage(txn, group, timestamp, body, meta);
.sendMessage(txn, group, m.getTime(), body, meta);
}
private Group getContactGroup(Contact c) {
@Override
protected Group getContactGroup(Contact c) {
return contactGroupFactory.createContactGroup(getClientId(), c);
}
@@ -930,14 +949,14 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
SharerSessionState.Action.LOCAL_LEAVE;
SharerEngine<I, SS, IRR> engine =
new SharerEngine<I, SS, IRR>(getIFactory(),
getIRRFactory());
getIRRFactory(), clock);
processSharerStateUpdate(txn, null,
engine.onLocalAction((SS) state, action));
} else {
InviteeSessionState.Action action =
InviteeSessionState.Action.LOCAL_LEAVE;
InviteeEngine<IS, IR> engine =
new InviteeEngine<IS, IR>(getIRFactory());
new InviteeEngine<IS, IR>(getIRFactory(), clock);
processInviteeStateUpdate(txn, null,
engine.onLocalAction((IS) state, action));
}

View File

@@ -9,6 +9,7 @@ import org.briarproject.api.data.MetadataEncoder;
import org.briarproject.api.forum.ForumManager;
import org.briarproject.api.forum.ForumSharingManager;
import org.briarproject.api.lifecycle.LifecycleManager;
import org.briarproject.api.messaging.ConversationManager;
import org.briarproject.api.system.Clock;
import javax.inject.Inject;
@@ -52,6 +53,7 @@ public class SharingModule {
LifecycleManager lifecycleManager,
ContactManager contactManager,
MessageQueueManager messageQueueManager,
ConversationManager conversationManager,
BlogManager blogManager,
BlogSharingManagerImpl blogSharingManager) {
@@ -60,6 +62,7 @@ public class SharingModule {
contactManager.registerRemoveContactHook(blogSharingManager);
messageQueueManager.registerIncomingMessageHook(
BlogSharingManagerImpl.CLIENT_ID, blogSharingManager);
conversationManager.registerConversationClient(blogSharingManager);
blogManager.registerRemoveBlogHook(blogSharingManager);
return blogSharingManager;
@@ -86,6 +89,7 @@ public class SharingModule {
LifecycleManager lifecycleManager,
ContactManager contactManager,
MessageQueueManager messageQueueManager,
ConversationManager conversationManager,
ForumManager forumManager,
ForumSharingManagerImpl forumSharingManager) {
@@ -94,6 +98,7 @@ public class SharingModule {
contactManager.registerRemoveContactHook(forumSharingManager);
messageQueueManager.registerIncomingMessageHook(
ForumSharingManagerImpl.CLIENT_ID, forumSharingManager);
conversationManager.registerConversationClient(forumSharingManager);
forumManager.registerRemoveForumHook(forumSharingManager);
return forumSharingManager;

View File

@@ -96,13 +96,13 @@ public class IntroductionManagerImplTest extends BriarTestCase {
TestUtils.getRandomBytes(MESSAGE_HEADER_LENGTH + 1)
);
metadataBefore = BdfDictionary.of(
new BdfEntry(GROUP_KEY_MSG_COUNT, 41L),
new BdfEntry(GROUP_KEY_UNREAD_COUNT, 0L),
new BdfEntry(GROUP_KEY_LATEST_MSG, 0L)
new BdfEntry(GROUP_KEY_MSG_COUNT, 41),
new BdfEntry(GROUP_KEY_UNREAD_COUNT, 0),
new BdfEntry(GROUP_KEY_LATEST_MSG, 0)
);
metadataAfter = BdfDictionary.of(
new BdfEntry(GROUP_KEY_MSG_COUNT, 42L),
new BdfEntry(GROUP_KEY_UNREAD_COUNT, 0L),
new BdfEntry(GROUP_KEY_MSG_COUNT, 42),
new BdfEntry(GROUP_KEY_UNREAD_COUNT, 0),
new BdfEntry(GROUP_KEY_LATEST_MSG, time)
);
@@ -273,8 +273,8 @@ public class IntroductionManagerImplTest extends BriarTestCase {
final BdfDictionary state = new BdfDictionary();
txn = new Transaction(null, false);
metadataBefore.put(GROUP_KEY_UNREAD_COUNT, 1L);
metadataAfter.put(GROUP_KEY_UNREAD_COUNT, 2L);
metadataBefore.put(GROUP_KEY_UNREAD_COUNT, 1);
metadataAfter.put(GROUP_KEY_UNREAD_COUNT, 2);
context.checking(new Expectations() {{
oneOf(introduceeManager)
@@ -314,8 +314,8 @@ public class IntroductionManagerImplTest extends BriarTestCase {
txn = new Transaction(null, false);
metadataBefore.put(GROUP_KEY_UNREAD_COUNT, 41L);
metadataAfter.put(GROUP_KEY_UNREAD_COUNT, 42L);
metadataBefore.put(GROUP_KEY_UNREAD_COUNT, 41);
metadataAfter.put(GROUP_KEY_UNREAD_COUNT, 42);
context.checking(new Expectations() {{
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, sessionId);