mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 02:39:05 +01:00
Merge branch '584-store-latest-timestamp-and-unread-count-in-group-metadata-for-private-messaging' into 'master'
Store message count, unread count and timestamp of latest message in group metadata This is to eventually address #373 and slowness of other lists. The group metadata is not yet used, but if this MR isn't merged fast, another commit that actually uses it and thus takes care of the slowness will be added. Closes #584, #585, #586 See merge request !336
This commit is contained in:
@@ -8,6 +8,7 @@ import org.briarproject.api.blogs.BlogInvitationResponse;
|
||||
import org.briarproject.api.blogs.BlogManager;
|
||||
import org.briarproject.api.blogs.BlogPostFactory;
|
||||
import org.briarproject.api.blogs.BlogSharingManager;
|
||||
import org.briarproject.api.clients.ContactGroupFactory;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.contact.ContactManager;
|
||||
@@ -25,6 +26,7 @@ import org.briarproject.api.identity.IdentityManager;
|
||||
import org.briarproject.api.identity.LocalAuthor;
|
||||
import org.briarproject.api.lifecycle.LifecycleManager;
|
||||
import org.briarproject.api.sharing.InvitationMessage;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
import org.briarproject.api.sync.SyncSession;
|
||||
import org.briarproject.api.sync.SyncSessionFactory;
|
||||
import org.briarproject.api.sync.ValidationManager.State;
|
||||
@@ -62,12 +64,12 @@ import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class BlogSharingIntegrationTest extends BriarTestCase {
|
||||
public class BlogSharingIntegrationTest extends BriarIntegrationTest {
|
||||
|
||||
private LifecycleManager lifecycleManager0, lifecycleManager1,
|
||||
lifecycleManager2;
|
||||
private SyncSessionFactory sync0, sync1, sync2;
|
||||
private BlogManager blogManager0, blogManager1, blogManager2;
|
||||
private SyncSessionFactory sync0, sync1;
|
||||
private BlogManager blogManager0, blogManager1;
|
||||
private ContactManager contactManager0, contactManager1, contactManager2;
|
||||
private Contact contact1, contact2, contact01, contact02;
|
||||
private ContactId contactId1, contactId2, contactId01, contactId02;
|
||||
@@ -83,6 +85,8 @@ public class BlogSharingIntegrationTest extends BriarTestCase {
|
||||
@Inject
|
||||
AuthorFactory authorFactory;
|
||||
@Inject
|
||||
ContactGroupFactory contactGroupFactory;
|
||||
@Inject
|
||||
BlogPostFactory blogPostFactory;
|
||||
@Inject
|
||||
CryptoComponent cryptoComponent;
|
||||
@@ -138,13 +142,11 @@ public class BlogSharingIntegrationTest extends BriarTestCase {
|
||||
contactManager2 = t2.getContactManager();
|
||||
blogManager0 = t0.getBlogManager();
|
||||
blogManager1 = t1.getBlogManager();
|
||||
blogManager2 = t2.getBlogManager();
|
||||
blogSharingManager0 = t0.getBlogSharingManager();
|
||||
blogSharingManager1 = t1.getBlogSharingManager();
|
||||
blogSharingManager2 = t2.getBlogSharingManager();
|
||||
sync0 = t0.getSyncSessionFactory();
|
||||
sync1 = t1.getSyncSessionFactory();
|
||||
sync2 = t2.getSyncSessionFactory();
|
||||
|
||||
// initialize waiters fresh for each test
|
||||
eventWaiter = new Waiter();
|
||||
@@ -187,15 +189,23 @@ public class BlogSharingIntegrationTest extends BriarTestCase {
|
||||
// invitee has own blog and that of the sharer
|
||||
assertEquals(2, blogManager1.getBlogs().size());
|
||||
|
||||
// get sharing group and assert group message count
|
||||
GroupId g = contactGroupFactory
|
||||
.createContactGroup(blogSharingManager0.getClientId(),
|
||||
contact1).getId();
|
||||
assertGroupCount(blogSharingManager0, g, 1, 0);
|
||||
|
||||
// sync first request message
|
||||
sync0To1();
|
||||
eventWaiter.await(TIMEOUT, 1);
|
||||
assertTrue(listener1.requestReceived);
|
||||
assertGroupCount(blogSharingManager1, g, 2, 1);
|
||||
|
||||
// sync response back
|
||||
sync1To0();
|
||||
eventWaiter.await(TIMEOUT, 1);
|
||||
assertTrue(listener0.responseReceived);
|
||||
assertGroupCount(blogSharingManager0, g, 2, 1);
|
||||
|
||||
// blog was added successfully
|
||||
assertEquals(0, blogSharingManager0.getInvitations().size());
|
||||
@@ -232,6 +242,10 @@ public class BlogSharingIntegrationTest extends BriarTestCase {
|
||||
assertFalse(blogSharingManager0.canBeShared(blog2.getId(), contact1));
|
||||
assertFalse(blogSharingManager1.canBeShared(blog2.getId(), contact01));
|
||||
|
||||
// group message count is still correct
|
||||
assertGroupCount(blogSharingManager0, g, 2, 1);
|
||||
assertGroupCount(blogSharingManager1, g, 2, 1);
|
||||
|
||||
stopLifecycles();
|
||||
}
|
||||
|
||||
@@ -510,8 +524,7 @@ public class BlogSharingIntegrationTest extends BriarTestCase {
|
||||
|
||||
private class SharerListener implements EventListener {
|
||||
|
||||
volatile boolean requestReceived = false;
|
||||
volatile boolean responseReceived = false;
|
||||
private volatile boolean responseReceived = false;
|
||||
|
||||
@Override
|
||||
public void eventOccurred(Event e) {
|
||||
@@ -534,7 +547,6 @@ public class BlogSharingIntegrationTest extends BriarTestCase {
|
||||
BlogInvitationReceivedEvent event =
|
||||
(BlogInvitationReceivedEvent) e;
|
||||
eventWaiter.assertEquals(contactId1, event.getContactId());
|
||||
requestReceived = true;
|
||||
Blog b = event.getBlog();
|
||||
try {
|
||||
Contact c = contactManager0.getContact(contactId1);
|
||||
@@ -550,17 +562,16 @@ public class BlogSharingIntegrationTest extends BriarTestCase {
|
||||
|
||||
private class InviteeListener implements EventListener {
|
||||
|
||||
volatile boolean requestReceived = false;
|
||||
volatile boolean responseReceived = false;
|
||||
private volatile boolean requestReceived = false;
|
||||
|
||||
private final boolean accept, answer;
|
||||
|
||||
InviteeListener(boolean accept, boolean answer) {
|
||||
private InviteeListener(boolean accept, boolean answer) {
|
||||
this.accept = accept;
|
||||
this.answer = answer;
|
||||
}
|
||||
|
||||
InviteeListener(boolean accept) {
|
||||
private InviteeListener(boolean accept) {
|
||||
this(accept, true);
|
||||
}
|
||||
|
||||
@@ -596,7 +607,6 @@ public class BlogSharingIntegrationTest extends BriarTestCase {
|
||||
BlogInvitationResponseReceivedEvent event =
|
||||
(BlogInvitationResponseReceivedEvent) e;
|
||||
eventWaiter.assertEquals(contactId01, event.getContactId());
|
||||
responseReceived = true;
|
||||
eventWaiter.resume();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package org.briarproject;
|
||||
|
||||
import org.briarproject.api.clients.MessageTracker;
|
||||
import org.briarproject.api.clients.MessageTracker.GroupCount;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public abstract class BriarIntegrationTest extends BriarTestCase {
|
||||
|
||||
// TODO maybe we could add uncaught exception handlers for other threads here (#670)
|
||||
|
||||
protected void assertGroupCount(MessageTracker tracker, GroupId g,
|
||||
long msgCount, long unreadCount, long latestMsg)
|
||||
throws DbException {
|
||||
|
||||
GroupCount groupCount = tracker.getGroupCount(g);
|
||||
assertEquals(msgCount, groupCount.getMsgCount());
|
||||
assertEquals(unreadCount, groupCount.getUnreadCount());
|
||||
assertEquals(latestMsg, groupCount.getLatestMsgTime());
|
||||
}
|
||||
|
||||
protected void assertGroupCount(MessageTracker tracker, GroupId g,
|
||||
long msgCount, long unreadCount) throws DbException {
|
||||
|
||||
GroupCount c1 = tracker.getGroupCount(g);
|
||||
assertEquals(msgCount, c1.getMsgCount());
|
||||
assertEquals(unreadCount, c1.getUnreadCount());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -59,7 +59,7 @@ import static org.briarproject.api.sync.ValidationManager.State.INVALID;
|
||||
import static org.briarproject.api.sync.ValidationManager.State.PENDING;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ForumManagerTest {
|
||||
public class ForumManagerTest extends BriarIntegrationTest {
|
||||
|
||||
private LifecycleManager lifecycleManager0, lifecycleManager1;
|
||||
private SyncSessionFactory sync0, sync1;
|
||||
@@ -150,9 +150,19 @@ public class ForumManagerTest {
|
||||
createForumPost(forum.getGroup().getId(), post1, body2, ms2);
|
||||
assertEquals(ms2, post2.getMessage().getTimestamp());
|
||||
forumManager0.addLocalPost(post1);
|
||||
forumManager0.setReadFlag(post1.getMessage().getId(), true);
|
||||
forumManager0.setReadFlag(forum.getGroup().getId(),
|
||||
post1.getMessage().getId(), true);
|
||||
assertGroupCount(forumManager0, forum.getGroup().getId(), 1, 0,
|
||||
post1.getMessage().getTimestamp());
|
||||
forumManager0.addLocalPost(post2);
|
||||
forumManager0.setReadFlag(post2.getMessage().getId(), false);
|
||||
forumManager0.setReadFlag(forum.getGroup().getId(),
|
||||
post2.getMessage().getId(), false);
|
||||
assertGroupCount(forumManager0, forum.getGroup().getId(), 2, 1,
|
||||
post2.getMessage().getTimestamp());
|
||||
forumManager0.setReadFlag(forum.getGroup().getId(),
|
||||
post2.getMessage().getId(), false);
|
||||
assertGroupCount(forumManager0, forum.getGroup().getId(), 2, 1,
|
||||
post2.getMessage().getTimestamp());
|
||||
Collection<ForumPostHeader> headers =
|
||||
forumManager0.getPostHeaders(forum.getGroup().getId());
|
||||
assertEquals(2, headers.size());
|
||||
@@ -202,23 +212,29 @@ public class ForumManagerTest {
|
||||
forumManager0.addLocalPost(post1);
|
||||
assertEquals(1, forumManager0.getPostHeaders(g).size());
|
||||
assertEquals(0, forumManager1.getPostHeaders(g).size());
|
||||
assertGroupCount(forumManager0, g, 1, 0, time);
|
||||
assertGroupCount(forumManager1, g, 0, 0, 0);
|
||||
|
||||
// send post to 1
|
||||
sync0To1();
|
||||
deliveryWaiter.await(TIMEOUT, 1);
|
||||
assertEquals(1, forumManager1.getPostHeaders(g).size());
|
||||
assertGroupCount(forumManager1, g, 1, 1, time);
|
||||
|
||||
// add another forum post
|
||||
time = clock.currentTimeMillis();
|
||||
ForumPost post2 = createForumPost(g, null, "b", time);
|
||||
long time2 = clock.currentTimeMillis();
|
||||
ForumPost post2 = createForumPost(g, null, "b", time2);
|
||||
forumManager1.addLocalPost(post2);
|
||||
assertEquals(1, forumManager0.getPostHeaders(g).size());
|
||||
assertEquals(2, forumManager1.getPostHeaders(g).size());
|
||||
assertGroupCount(forumManager0, g, 1, 0, time);
|
||||
assertGroupCount(forumManager1, g, 2, 1, time2);
|
||||
|
||||
// send post to 0
|
||||
sync1To0();
|
||||
deliveryWaiter.await(TIMEOUT, 1);
|
||||
assertEquals(2, forumManager1.getPostHeaders(g).size());
|
||||
assertGroupCount(forumManager0, g, 2, 1, time2);
|
||||
|
||||
stopLifecycles();
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import android.support.annotation.Nullable;
|
||||
|
||||
import net.jodah.concurrentunit.Waiter;
|
||||
|
||||
import org.briarproject.BriarTestCase;
|
||||
import org.briarproject.BriarIntegrationTest;
|
||||
import org.briarproject.TestDatabaseModule;
|
||||
import org.briarproject.TestUtils;
|
||||
import org.briarproject.api.FormatException;
|
||||
@@ -99,7 +99,7 @@ import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public class IntroductionIntegrationTest extends BriarTestCase {
|
||||
public class IntroductionIntegrationTest extends BriarIntegrationTest {
|
||||
|
||||
private LifecycleManager lifecycleManager0, lifecycleManager1,
|
||||
lifecycleManager2;
|
||||
@@ -200,29 +200,43 @@ public class IntroductionIntegrationTest extends BriarTestCase {
|
||||
introductionManager0
|
||||
.makeIntroduction(introducee1, introducee2, "Hi!", time);
|
||||
|
||||
// check that messages are tracked properly
|
||||
Group g1 = introductionGroupFactory
|
||||
.createIntroductionGroup(introducee1);
|
||||
Group g2 = introductionGroupFactory
|
||||
.createIntroductionGroup(introducee2);
|
||||
assertGroupCount(introductionManager0, g1.getId(), 1, 0, time);
|
||||
assertGroupCount(introductionManager0, g2.getId(), 1, 0, time);
|
||||
|
||||
// sync first request message
|
||||
deliverMessage(sync0, contactId0, sync1, contactId1, "0 to 1");
|
||||
eventWaiter.await(TIMEOUT, 1);
|
||||
assertTrue(listener1.requestReceived);
|
||||
assertGroupCount(introductionManager1, g1.getId(), 2, 1);
|
||||
|
||||
// sync second request message
|
||||
deliverMessage(sync0, contactId0, sync2, contactId2, "0 to 2");
|
||||
eventWaiter.await(TIMEOUT, 1);
|
||||
assertTrue(listener2.requestReceived);
|
||||
assertGroupCount(introductionManager2, g2.getId(), 2, 1);
|
||||
|
||||
// sync first response
|
||||
deliverMessage(sync1, contactId1, sync0, contactId0, "1 to 0");
|
||||
eventWaiter.await(TIMEOUT, 1);
|
||||
assertTrue(listener0.response1Received);
|
||||
assertGroupCount(introductionManager0, g1.getId(), 2, 1);
|
||||
|
||||
// sync second response
|
||||
deliverMessage(sync2, contactId2, sync0, contactId0, "2 to 0");
|
||||
eventWaiter.await(TIMEOUT, 1);
|
||||
assertTrue(listener0.response2Received);
|
||||
assertGroupCount(introductionManager0, g2.getId(), 2, 1);
|
||||
|
||||
// sync forwarded responses to introducees
|
||||
deliverMessage(sync0, contactId0, sync1, contactId1, "0 to 1");
|
||||
deliverMessage(sync0, contactId0, sync2, contactId2, "0 to 2");
|
||||
assertGroupCount(introductionManager1, g1.getId(), 3, 2);
|
||||
assertGroupCount(introductionManager2, g2.getId(), 3, 2);
|
||||
|
||||
// sync first ACK and its forward
|
||||
deliverMessage(sync1, contactId1, sync0, contactId0, "1 to 0");
|
||||
@@ -255,6 +269,10 @@ public class IntroductionIntegrationTest extends BriarTestCase {
|
||||
}
|
||||
|
||||
assertDefaultUiMessages();
|
||||
assertGroupCount(introductionManager0, g1.getId(), 2, 1);
|
||||
assertGroupCount(introductionManager0, g2.getId(), 2, 1);
|
||||
assertGroupCount(introductionManager1, g1.getId(), 3, 2);
|
||||
assertGroupCount(introductionManager2, g2.getId(), 3, 2);
|
||||
} finally {
|
||||
stopLifecycles();
|
||||
}
|
||||
|
||||
@@ -499,7 +499,7 @@ public class ConversationActivity extends BriarActivity
|
||||
for (MessageId m : unread)
|
||||
// not really clean, but the messaging manager can
|
||||
// handle introduction messages as well
|
||||
messagingManager.setReadFlag(m, true);
|
||||
messagingManager.setReadFlag(groupId, m, true);
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Marking read took " + duration + " ms");
|
||||
@@ -614,7 +614,7 @@ public class ConversationActivity extends BriarActivity
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
messagingManager.setReadFlag(m, true);
|
||||
messagingManager.setReadFlag(groupId, m, true);
|
||||
loadMessages();
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
|
||||
@@ -291,13 +291,15 @@ public class ForumControllerImpl extends DbControllerImpl
|
||||
|
||||
@Override
|
||||
public void entriesRead(final Collection<ForumEntry> forumEntries) {
|
||||
if (forum == null) return;
|
||||
runOnDbThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
long now = System.currentTimeMillis();
|
||||
for (ForumEntry fe : forumEntries) {
|
||||
forumManager.setReadFlag(fe.getId(), true);
|
||||
forumManager
|
||||
.setReadFlag(forum.getId(), fe.getId(), true);
|
||||
}
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if (LOG.isLoggable(INFO))
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
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 {
|
||||
|
||||
/**
|
||||
* Gets the number of visible and unread messages in the group
|
||||
* as well as the timestamp of the latest message
|
||||
**/
|
||||
GroupCount getGroupCount(GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Marks a message as read or unread and updates the group counts in g.
|
||||
**/
|
||||
void setReadFlag(GroupId g, MessageId m, boolean read) throws DbException;
|
||||
|
||||
class GroupCount {
|
||||
private final long msgCount, unreadCount, latestMsgTime;
|
||||
|
||||
public GroupCount(long msgCount, long unreadCount, long latestMsgTime) {
|
||||
this.msgCount = msgCount;
|
||||
this.unreadCount = unreadCount;
|
||||
this.latestMsgTime = latestMsgTime;
|
||||
}
|
||||
|
||||
public long getMsgCount() {
|
||||
return msgCount;
|
||||
}
|
||||
|
||||
public long getUnreadCount() {
|
||||
return unreadCount;
|
||||
}
|
||||
|
||||
public long getLatestMsgTime() {
|
||||
return latestMsgTime;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -28,6 +28,5 @@ public interface ForumConstants {
|
||||
String KEY_PUBLIC_NAME = "publicKey";
|
||||
String KEY_AUTHOR = "author";
|
||||
String KEY_LOCAL = "local";
|
||||
String KEY_READ = "read";
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.briarproject.api.forum;
|
||||
|
||||
import org.briarproject.api.clients.MessageTracker;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.db.Transaction;
|
||||
import org.briarproject.api.sync.ClientId;
|
||||
@@ -8,7 +9,7 @@ import org.briarproject.api.sync.MessageId;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface ForumManager {
|
||||
public interface ForumManager extends MessageTracker {
|
||||
|
||||
/** Returns the unique ID of the forum client. */
|
||||
ClientId getClientId();
|
||||
@@ -37,9 +38,6 @@ public interface ForumManager {
|
||||
/** Returns the headers of all posts in the given forum. */
|
||||
Collection<ForumPostHeader> getPostHeaders(GroupId g) throws DbException;
|
||||
|
||||
/** Marks a forum post as read or unread. */
|
||||
void setReadFlag(MessageId m, boolean read) throws DbException;
|
||||
|
||||
/** Registers a hook to be called whenever a forum is removed. */
|
||||
void registerRemoveForumHook(RemoveForumHook hook);
|
||||
|
||||
|
||||
@@ -45,7 +45,6 @@ public interface IntroductionConstants {
|
||||
String CONTACT_ID_2 = "contactId2";
|
||||
String RESPONSE_1 = "response1";
|
||||
String RESPONSE_2 = "response2";
|
||||
String READ = "read";
|
||||
|
||||
/* Introduction Request Action */
|
||||
String PUBLIC_KEY1 = "publicKey1";
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.briarproject.api.introduction;
|
||||
|
||||
import org.briarproject.api.FormatException;
|
||||
import org.briarproject.api.clients.MessageTracker;
|
||||
import org.briarproject.api.clients.SessionId;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
@@ -9,7 +10,7 @@ import org.briarproject.api.sync.ClientId;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface IntroductionManager {
|
||||
public interface IntroductionManager extends MessageTracker {
|
||||
|
||||
/** Returns the unique ID of the introduction client. */
|
||||
ClientId getClientId();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.briarproject.api.messaging;
|
||||
|
||||
import org.briarproject.api.clients.MessageTracker;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.sync.ClientId;
|
||||
@@ -8,7 +9,7 @@ import org.briarproject.api.sync.MessageId;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface MessagingManager {
|
||||
public interface MessagingManager extends MessageTracker {
|
||||
|
||||
/** Returns the unique ID of the messaging client. */
|
||||
ClientId getClientId();
|
||||
@@ -31,6 +32,4 @@ public interface MessagingManager {
|
||||
/** Returns the body of the private message with the given ID. */
|
||||
byte[] getMessageBody(MessageId m) throws DbException;
|
||||
|
||||
/** Marks a private message as read or unread. */
|
||||
void setReadFlag(MessageId m, boolean read) throws DbException;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.briarproject.api.privategroup;
|
||||
|
||||
import org.briarproject.api.clients.MessageTracker;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.db.Transaction;
|
||||
import org.briarproject.api.sync.ClientId;
|
||||
@@ -9,7 +10,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface PrivateGroupManager {
|
||||
public interface PrivateGroupManager extends MessageTracker {
|
||||
|
||||
/** Returns the unique ID of the private group client. */
|
||||
@NotNull
|
||||
@@ -40,7 +41,4 @@ public interface PrivateGroupManager {
|
||||
@NotNull
|
||||
Collection<GroupMessageHeader> getHeaders(GroupId g) throws DbException;
|
||||
|
||||
/** Marks a group message as read or unread. */
|
||||
void setReadFlag(MessageId m, boolean read) throws DbException;
|
||||
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ public interface SharingConstants {
|
||||
String STATE = "state";
|
||||
String LOCAL = "local";
|
||||
String TIME = "time";
|
||||
String READ = "read";
|
||||
String IS_SHARER = "isSharer";
|
||||
String SHAREABLE_ID = "shareableId";
|
||||
String INVITATION_MSG = "invitationMsg";
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.briarproject.api.sharing;
|
||||
|
||||
import org.briarproject.api.clients.MessageTracker;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.db.DbException;
|
||||
@@ -8,7 +9,7 @@ import org.briarproject.api.sync.GroupId;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface SharingManager<S extends Shareable> {
|
||||
public interface SharingManager<S extends Shareable> extends MessageTracker {
|
||||
|
||||
/** Returns the unique ID of the group sharing client. */
|
||||
ClientId getClientId();
|
||||
|
||||
@@ -86,7 +86,6 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager,
|
||||
"dafbe56f0c8971365cea4bb5f08ec9a6" +
|
||||
"1d686e058b943997b6ff259ba423f613"));
|
||||
|
||||
private final DatabaseComponent db;
|
||||
private final IdentityManager identityManager;
|
||||
private final ContactManager contactManager;
|
||||
private final BlogFactory blogFactory;
|
||||
@@ -98,9 +97,8 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager,
|
||||
ClientHelper clientHelper, MetadataParser metadataParser,
|
||||
ContactManager contactManager, BlogFactory blogFactory,
|
||||
BlogPostFactory blogPostFactory) {
|
||||
super(clientHelper, metadataParser);
|
||||
super(db, clientHelper, metadataParser);
|
||||
|
||||
this.db = db;
|
||||
this.identityManager = identityManager;
|
||||
this.contactManager = contactManager;
|
||||
this.blogFactory = blogFactory;
|
||||
|
||||
11
briar-core/src/org/briarproject/clients/BdfConstants.java
Normal file
11
briar-core/src/org/briarproject/clients/BdfConstants.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package org.briarproject.clients;
|
||||
|
||||
public interface BdfConstants {
|
||||
|
||||
String GROUP_KEY_MSG_COUNT = "messageCount";
|
||||
String GROUP_KEY_UNREAD_COUNT = "unreadCount";
|
||||
String GROUP_KEY_LATEST_MSG = "latestMessageTime";
|
||||
|
||||
String MSG_KEY_READ = "read";
|
||||
|
||||
}
|
||||
@@ -3,27 +3,38 @@ package org.briarproject.clients;
|
||||
import org.briarproject.api.FormatException;
|
||||
import org.briarproject.api.clients.ClientHelper;
|
||||
import org.briarproject.api.clients.MessageQueueManager.IncomingQueueMessageHook;
|
||||
import org.briarproject.api.clients.MessageTracker;
|
||||
import org.briarproject.api.clients.QueueMessage;
|
||||
import org.briarproject.api.data.BdfDictionary;
|
||||
import org.briarproject.api.data.BdfEntry;
|
||||
import org.briarproject.api.data.BdfList;
|
||||
import org.briarproject.api.data.MetadataParser;
|
||||
import org.briarproject.api.db.DatabaseComponent;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.db.Metadata;
|
||||
import org.briarproject.api.db.Transaction;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
import org.briarproject.api.sync.Message;
|
||||
import org.briarproject.api.sync.MessageId;
|
||||
import org.briarproject.api.sync.ValidationManager.IncomingMessageHook;
|
||||
|
||||
import static org.briarproject.api.clients.QueueMessage.QUEUE_MESSAGE_HEADER_LENGTH;
|
||||
import static org.briarproject.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
|
||||
import static org.briarproject.clients.BdfConstants.GROUP_KEY_LATEST_MSG;
|
||||
import static org.briarproject.clients.BdfConstants.GROUP_KEY_MSG_COUNT;
|
||||
import static org.briarproject.clients.BdfConstants.GROUP_KEY_UNREAD_COUNT;
|
||||
import static org.briarproject.clients.BdfConstants.MSG_KEY_READ;
|
||||
|
||||
public abstract class BdfIncomingMessageHook implements IncomingMessageHook,
|
||||
IncomingQueueMessageHook {
|
||||
IncomingQueueMessageHook, MessageTracker {
|
||||
|
||||
protected final DatabaseComponent db;
|
||||
protected final ClientHelper clientHelper;
|
||||
protected final MetadataParser metadataParser;
|
||||
|
||||
protected BdfIncomingMessageHook(ClientHelper clientHelper,
|
||||
MetadataParser metadataParser) {
|
||||
protected BdfIncomingMessageHook(DatabaseComponent db,
|
||||
ClientHelper clientHelper, MetadataParser metadataParser) {
|
||||
this.db = db;
|
||||
this.clientHelper = clientHelper;
|
||||
this.metadataParser = metadataParser;
|
||||
}
|
||||
@@ -56,4 +67,102 @@ public abstract class BdfIncomingMessageHook implements IncomingMessageHook,
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void trackIncomingMessage(Transaction txn, Message m)
|
||||
throws DbException {
|
||||
trackMessage(txn, m.getGroupId(), m.getTimestamp(), false);
|
||||
}
|
||||
|
||||
protected void trackOutgoingMessage(Transaction txn, Message m)
|
||||
throws DbException {
|
||||
trackMessage(txn, m.getGroupId(), m.getTimestamp(), true);
|
||||
}
|
||||
|
||||
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);
|
||||
long latestTime =
|
||||
time > c.getLatestMsgTime() ? time : c.getLatestMsgTime();
|
||||
storeGroupCount(txn, g,
|
||||
new GroupCount(msgCount, unreadCount, latestTime));
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupCount getGroupCount(GroupId g) throws DbException {
|
||||
GroupCount count;
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
count = getGroupCount(txn, g);
|
||||
txn.setComplete();
|
||||
}
|
||||
finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private 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_LATEST_MSG, 0L)
|
||||
);
|
||||
} catch (FormatException e) {
|
||||
throw new DbException(e);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private void storeGroupCount(Transaction txn, GroupId g, GroupCount c)
|
||||
throws DbException{
|
||||
try {
|
||||
BdfDictionary d = BdfDictionary.of(
|
||||
new BdfEntry(GROUP_KEY_MSG_COUNT, c.getMsgCount()),
|
||||
new BdfEntry(GROUP_KEY_UNREAD_COUNT, c.getUnreadCount()),
|
||||
new BdfEntry(GROUP_KEY_LATEST_MSG, c.getLatestMsgTime())
|
||||
);
|
||||
clientHelper.mergeGroupMetadata(txn, g, d);
|
||||
} catch (FormatException e) {
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReadFlag(GroupId g, MessageId m, boolean read)
|
||||
throws DbException {
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
// check current read status of message
|
||||
BdfDictionary old =
|
||||
clientHelper.getMessageMetadataAsDictionary(txn, m);
|
||||
boolean wasRead = old.getBoolean(MSG_KEY_READ, false);
|
||||
|
||||
// if status changed
|
||||
if (wasRead != read) {
|
||||
// mark individual message as read
|
||||
BdfDictionary meta = new BdfDictionary();
|
||||
meta.put(MSG_KEY_READ, read);
|
||||
clientHelper.mergeMessageMetadata(txn, m, meta);
|
||||
|
||||
// update unread counter in group metadata
|
||||
GroupCount c = getGroupCount(txn, g);
|
||||
BdfDictionary d = new BdfDictionary();
|
||||
d.put(GROUP_KEY_UNREAD_COUNT,
|
||||
c.getUnreadCount() + (read ? -1 : 1));
|
||||
clientHelper.mergeGroupMetadata(txn, g, d);
|
||||
}
|
||||
txn.setComplete();
|
||||
} catch (FormatException e) {
|
||||
throw new DbException(e);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -45,9 +45,9 @@ import static org.briarproject.api.forum.ForumConstants.KEY_LOCAL;
|
||||
import static org.briarproject.api.forum.ForumConstants.KEY_NAME;
|
||||
import static org.briarproject.api.forum.ForumConstants.KEY_PARENT;
|
||||
import static org.briarproject.api.forum.ForumConstants.KEY_PUBLIC_NAME;
|
||||
import static org.briarproject.api.forum.ForumConstants.KEY_READ;
|
||||
import static org.briarproject.api.forum.ForumConstants.KEY_TIMESTAMP;
|
||||
import static org.briarproject.api.identity.Author.Status.ANONYMOUS;
|
||||
import static org.briarproject.clients.BdfConstants.MSG_KEY_READ;
|
||||
|
||||
class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
|
||||
|
||||
@@ -55,7 +55,6 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
|
||||
"859a7be50dca035b64bd6902fb797097"
|
||||
+ "795af837abbf8c16d750b3c2ccc186ea"));
|
||||
|
||||
private final DatabaseComponent db;
|
||||
private final IdentityManager identityManager;
|
||||
private final ForumFactory forumFactory;
|
||||
private final List<RemoveForumHook> removeHooks;
|
||||
@@ -64,9 +63,8 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
|
||||
ForumManagerImpl(DatabaseComponent db, IdentityManager identityManager,
|
||||
ClientHelper clientHelper, MetadataParser metadataParser,
|
||||
ForumFactory forumFactory) {
|
||||
super(db, clientHelper, metadataParser);
|
||||
|
||||
super(clientHelper, metadataParser);
|
||||
this.db = db;
|
||||
this.identityManager = identityManager;
|
||||
this.forumFactory = forumFactory;
|
||||
removeHooks = new CopyOnWriteArrayList<RemoveForumHook>();
|
||||
@@ -76,6 +74,8 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
|
||||
protected boolean incomingMessage(Transaction txn, Message m, BdfList body,
|
||||
BdfDictionary meta) throws DbException, FormatException {
|
||||
|
||||
trackIncomingMessage(txn, m);
|
||||
|
||||
ForumPostHeader post = getForumPostHeader(txn, m.getId(), meta);
|
||||
ForumPostReceivedEvent event =
|
||||
new ForumPostReceivedEvent(post, m.getGroupId());
|
||||
@@ -119,6 +119,7 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
|
||||
|
||||
@Override
|
||||
public void addLocalPost(ForumPost p) throws DbException {
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
BdfDictionary meta = new BdfDictionary();
|
||||
meta.put(KEY_TIMESTAMP, p.getMessage().getTimestamp());
|
||||
@@ -132,10 +133,14 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
|
||||
meta.put(KEY_AUTHOR, authorMeta);
|
||||
}
|
||||
meta.put(KEY_LOCAL, true);
|
||||
meta.put(KEY_READ, true);
|
||||
clientHelper.addLocalMessage(p.getMessage(), meta, true);
|
||||
meta.put(MSG_KEY_READ, true);
|
||||
clientHelper.addLocalMessage(txn, p.getMessage(), meta, true);
|
||||
trackOutgoingMessage(txn, p.getMessage());
|
||||
txn.setComplete();
|
||||
} catch (FormatException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,17 +235,6 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReadFlag(MessageId m, boolean read) throws DbException {
|
||||
try {
|
||||
BdfDictionary meta = new BdfDictionary();
|
||||
meta.put(KEY_READ, read);
|
||||
clientHelper.mergeMessageMetadata(m, meta);
|
||||
} catch (FormatException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerRemoveForumHook(RemoveForumHook hook) {
|
||||
removeHooks.add(hook);
|
||||
@@ -281,7 +275,7 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
|
||||
status = identityManager.getAuthorStatus(txn, author.getId());
|
||||
}
|
||||
}
|
||||
boolean read = meta.getBoolean(KEY_READ);
|
||||
boolean read = meta.getBoolean(MSG_KEY_READ);
|
||||
|
||||
return new ForumPostHeader(id, parentId, timestamp, author, status,
|
||||
read);
|
||||
|
||||
@@ -60,7 +60,6 @@ import static org.briarproject.api.introduction.IntroductionConstants.MESSAGE_TI
|
||||
import static org.briarproject.api.introduction.IntroductionConstants.MSG;
|
||||
import static org.briarproject.api.introduction.IntroductionConstants.NAME;
|
||||
import static org.briarproject.api.introduction.IntroductionConstants.NOT_OUR_RESPONSE;
|
||||
import static org.briarproject.api.introduction.IntroductionConstants.READ;
|
||||
import static org.briarproject.api.introduction.IntroductionConstants.REMOTE_AUTHOR_ID;
|
||||
import static org.briarproject.api.introduction.IntroductionConstants.REMOTE_AUTHOR_IS_US;
|
||||
import static org.briarproject.api.introduction.IntroductionConstants.RESPONSE_1;
|
||||
@@ -75,6 +74,7 @@ import static org.briarproject.api.introduction.IntroductionConstants.TYPE_ABORT
|
||||
import static org.briarproject.api.introduction.IntroductionConstants.TYPE_ACK;
|
||||
import static org.briarproject.api.introduction.IntroductionConstants.TYPE_REQUEST;
|
||||
import static org.briarproject.api.introduction.IntroductionConstants.TYPE_RESPONSE;
|
||||
import static org.briarproject.clients.BdfConstants.MSG_KEY_READ;
|
||||
|
||||
class IntroductionManagerImpl extends BdfIncomingMessageHook
|
||||
implements IntroductionManager, Client, AddContactHook,
|
||||
@@ -87,7 +87,6 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(IntroductionManagerImpl.class.getName());
|
||||
|
||||
private final DatabaseComponent db;
|
||||
private final IntroducerManager introducerManager;
|
||||
private final IntroduceeManager introduceeManager;
|
||||
private final IntroductionGroupFactory introductionGroupFactory;
|
||||
@@ -98,8 +97,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
|
||||
IntroduceeManager introduceeManager,
|
||||
IntroductionGroupFactory introductionGroupFactory) {
|
||||
|
||||
super(clientHelper, metadataParser);
|
||||
this.db = db;
|
||||
super(db, clientHelper, metadataParser);
|
||||
this.introducerManager = introducerManager;
|
||||
this.introduceeManager = introduceeManager;
|
||||
this.introductionGroupFactory = introductionGroupFactory;
|
||||
@@ -208,7 +206,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
|
||||
*/
|
||||
@Override
|
||||
protected boolean incomingMessage(Transaction txn, Message m, BdfList body,
|
||||
BdfDictionary message) throws DbException {
|
||||
BdfDictionary message) throws DbException {
|
||||
|
||||
// Get message data and type
|
||||
GroupId groupId = m.getGroupId();
|
||||
@@ -237,6 +235,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
|
||||
}
|
||||
try {
|
||||
introduceeManager.incomingMessage(txn, state, message);
|
||||
trackIncomingMessage(txn, m);
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
introduceeManager.abort(txn, state);
|
||||
@@ -270,6 +269,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
|
||||
deleteMessage(txn, m.getId());
|
||||
}
|
||||
}
|
||||
if (type == TYPE_RESPONSE) trackIncomingMessage(txn, m);
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
if (role == ROLE_INTRODUCER) introducerManager.abort(txn, state);
|
||||
@@ -296,6 +296,10 @@ 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);
|
||||
trackMessage(txn, g1.getId(), timestamp, true);
|
||||
trackMessage(txn, g2.getId(), timestamp, true);
|
||||
txn.setComplete();
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
@@ -315,6 +319,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
|
||||
getSessionState(txn, g.getId(), sessionId.getBytes());
|
||||
|
||||
introduceeManager.acceptIntroduction(txn, state, timestamp);
|
||||
trackMessage(txn, g.getId(), timestamp, true);
|
||||
txn.setComplete();
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
@@ -334,6 +339,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
|
||||
getSessionState(txn, g.getId(), sessionId.getBytes());
|
||||
|
||||
introduceeManager.declineIntroduction(txn, state, timestamp);
|
||||
trackMessage(txn, g.getId(), timestamp, true);
|
||||
txn.setComplete();
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
@@ -377,7 +383,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
|
||||
boolean local;
|
||||
long time = msg.getLong(MESSAGE_TIME);
|
||||
boolean accepted = msg.getBoolean(ACCEPT, false);
|
||||
boolean read = msg.getBoolean(READ, false);
|
||||
boolean read = msg.getBoolean(MSG_KEY_READ, false);
|
||||
AuthorId authorId;
|
||||
String name;
|
||||
if (type == TYPE_RESPONSE) {
|
||||
|
||||
@@ -33,6 +33,8 @@ import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static org.briarproject.clients.BdfConstants.MSG_KEY_READ;
|
||||
|
||||
class MessagingManagerImpl extends BdfIncomingMessageHook
|
||||
implements MessagingManager, Client, AddContactHook, RemoveContactHook {
|
||||
|
||||
@@ -40,16 +42,13 @@ class MessagingManagerImpl extends BdfIncomingMessageHook
|
||||
"6bcdc006c0910b0f44e40644c3b31f1a"
|
||||
+ "8bf9a6d6021d40d219c86b731b903070"));
|
||||
|
||||
private final DatabaseComponent db;
|
||||
private final ContactGroupFactory contactGroupFactory;
|
||||
|
||||
@Inject
|
||||
MessagingManagerImpl(DatabaseComponent db, ClientHelper clientHelper,
|
||||
MetadataParser metadataParser,
|
||||
ContactGroupFactory contactGroupFactory) {
|
||||
super(clientHelper, metadataParser);
|
||||
|
||||
this.db = db;
|
||||
super(db, clientHelper, metadataParser);
|
||||
this.contactGroupFactory = contactGroupFactory;
|
||||
}
|
||||
|
||||
@@ -100,12 +99,13 @@ class MessagingManagerImpl extends BdfIncomingMessageHook
|
||||
long timestamp = meta.getLong("timestamp");
|
||||
String contentType = meta.getString("contentType");
|
||||
boolean local = meta.getBoolean("local");
|
||||
boolean read = meta.getBoolean("read");
|
||||
boolean read = meta.getBoolean(MSG_KEY_READ);
|
||||
PrivateMessageHeader header = new PrivateMessageHeader(
|
||||
m.getId(), timestamp, contentType, local, read, false, false);
|
||||
PrivateMessageReceivedEvent event = new PrivateMessageReceivedEvent(
|
||||
header, groupId);
|
||||
txn.attach(event);
|
||||
trackIncomingMessage(txn, m);
|
||||
|
||||
// don't share message
|
||||
return false;
|
||||
@@ -113,6 +113,7 @@ class MessagingManagerImpl extends BdfIncomingMessageHook
|
||||
|
||||
@Override
|
||||
public void addLocalMessage(PrivateMessage m) throws DbException {
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
BdfDictionary meta = new BdfDictionary();
|
||||
meta.put("timestamp", m.getMessage().getTimestamp());
|
||||
@@ -120,9 +121,13 @@ class MessagingManagerImpl extends BdfIncomingMessageHook
|
||||
meta.put("contentType", m.getContentType());
|
||||
meta.put("local", true);
|
||||
meta.put("read", true);
|
||||
clientHelper.addLocalMessage(m.getMessage(), meta, true);
|
||||
clientHelper.addLocalMessage(txn, m.getMessage(), meta, true);
|
||||
trackOutgoingMessage(txn, m.getMessage());
|
||||
txn.setComplete();
|
||||
} catch (FormatException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,14 +201,4 @@ class MessagingManagerImpl extends BdfIncomingMessageHook
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReadFlag(MessageId m, boolean read) throws DbException {
|
||||
try {
|
||||
BdfDictionary meta = new BdfDictionary();
|
||||
meta.put("read", read);
|
||||
clientHelper.mergeMessageMetadata(m, meta);
|
||||
} catch (FormatException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import org.briarproject.clients.BdfMessageValidator;
|
||||
|
||||
import static org.briarproject.api.messaging.MessagingConstants.MAX_CONTENT_TYPE_LENGTH;
|
||||
import static org.briarproject.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_BODY_LENGTH;
|
||||
import static org.briarproject.clients.BdfConstants.MSG_KEY_READ;
|
||||
|
||||
class PrivateMessageValidator extends BdfMessageValidator {
|
||||
|
||||
@@ -42,7 +43,7 @@ class PrivateMessageValidator extends BdfMessageValidator {
|
||||
if (parentId != null) meta.put("parent", parentId);
|
||||
meta.put("contentType", contentType);
|
||||
meta.put("local", false);
|
||||
meta.put("read", false);
|
||||
meta.put(MSG_KEY_READ, false);
|
||||
return new BdfMessageContext(meta);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,8 +28,6 @@ import java.util.Collections;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static org.briarproject.privategroup.Constants.KEY_READ;
|
||||
|
||||
public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
|
||||
PrivateGroupManager {
|
||||
|
||||
@@ -37,7 +35,6 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
|
||||
StringUtils.fromHexString("5072697661746547726f75704d616e61"
|
||||
+ "67657220627920546f727374656e2047"));
|
||||
|
||||
private final DatabaseComponent db;
|
||||
private final IdentityManager identityManager;
|
||||
private final PrivateGroupFactory privateGroupFactory;
|
||||
|
||||
@@ -46,9 +43,8 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
|
||||
MetadataParser metadataParser, DatabaseComponent db,
|
||||
IdentityManager identityManager,
|
||||
PrivateGroupFactory privateGroupFactory) {
|
||||
super(clientHelper, metadataParser);
|
||||
super(db, clientHelper, metadataParser);
|
||||
|
||||
this.db = db;
|
||||
this.identityManager = identityManager;
|
||||
this.privateGroupFactory = privateGroupFactory;
|
||||
}
|
||||
@@ -61,11 +57,16 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
|
||||
|
||||
@Override
|
||||
public void addLocalMessage(GroupMessage m) throws DbException {
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
BdfDictionary meta = new BdfDictionary();
|
||||
clientHelper.addLocalMessage(m.getMessage(), meta, true);
|
||||
clientHelper.addLocalMessage(txn, m.getMessage(), meta, true);
|
||||
trackOutgoingMessage(txn, m.getMessage());
|
||||
txn.setComplete();
|
||||
} catch (FormatException e) {
|
||||
throw new DbException(e);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,21 +105,12 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReadFlag(MessageId m, boolean read) throws DbException {
|
||||
try {
|
||||
BdfDictionary meta = new BdfDictionary();
|
||||
meta.put(KEY_READ, read);
|
||||
clientHelper.mergeMessageMetadata(m, meta);
|
||||
} catch (FormatException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean incomingMessage(Transaction txn, Message m, BdfList body,
|
||||
BdfDictionary meta) throws DbException, FormatException {
|
||||
|
||||
trackIncomingMessage(txn, m);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,6 @@ import static org.briarproject.api.clients.ProtocolEngine.StateUpdate;
|
||||
import static org.briarproject.api.sharing.SharingConstants.CONTACT_ID;
|
||||
import static org.briarproject.api.sharing.SharingConstants.IS_SHARER;
|
||||
import static org.briarproject.api.sharing.SharingConstants.LOCAL;
|
||||
import static org.briarproject.api.sharing.SharingConstants.READ;
|
||||
import static org.briarproject.api.sharing.SharingConstants.SESSION_ID;
|
||||
import static org.briarproject.api.sharing.SharingConstants.SHAREABLE_ID;
|
||||
import static org.briarproject.api.sharing.SharingConstants.SHARED_BY_US;
|
||||
@@ -83,6 +82,7 @@ import static org.briarproject.api.sharing.SharingConstants.TO_BE_SHARED_BY_US;
|
||||
import static org.briarproject.api.sharing.SharingConstants.TYPE;
|
||||
import static org.briarproject.api.sharing.SharingMessage.BaseMessage;
|
||||
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>
|
||||
@@ -93,7 +93,6 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(SharingManagerImpl.class.getName());
|
||||
|
||||
private final DatabaseComponent db;
|
||||
private final MessageQueueManager messageQueueManager;
|
||||
private final MetadataEncoder metadataEncoder;
|
||||
private final SecureRandom random;
|
||||
@@ -106,9 +105,8 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
|
||||
MetadataParser metadataParser, MetadataEncoder metadataEncoder,
|
||||
SecureRandom random, ContactGroupFactory contactGroupFactory,
|
||||
Clock clock) {
|
||||
super(db, clientHelper, metadataParser);
|
||||
|
||||
super(clientHelper, metadataParser);
|
||||
this.db = db;
|
||||
this.messageQueueManager = messageQueueManager;
|
||||
this.metadataEncoder = metadataEncoder;
|
||||
this.random = random;
|
||||
@@ -226,6 +224,7 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
|
||||
new InviteeEngine<IS, IR>(getIRFactory());
|
||||
processInviteeStateUpdate(txn, m.getId(),
|
||||
engine.onMessageReceived(state, msg));
|
||||
trackIncomingMessage(txn, m);
|
||||
} catch (FormatException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
deleteMessage(txn, m.getId());
|
||||
@@ -239,6 +238,7 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
|
||||
getIRRFactory());
|
||||
processSharerStateUpdate(txn, m.getId(),
|
||||
engine.onMessageReceived(state, msg));
|
||||
trackIncomingMessage(txn, m);
|
||||
} else if (msg.getType() == SHARE_MSG_TYPE_LEAVE ||
|
||||
msg.getType() == SHARE_MSG_TYPE_ABORT) {
|
||||
// we don't know who we are, so figure it out
|
||||
@@ -290,6 +290,10 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
|
||||
engine.onLocalAction(localState,
|
||||
SharerSessionState.Action.LOCAL_INVITATION));
|
||||
|
||||
// track message
|
||||
long time = clock.currentTimeMillis();
|
||||
trackMessage(txn, localState.getGroupId(), time, true);
|
||||
|
||||
txn.setComplete();
|
||||
} catch (FormatException e) {
|
||||
throw new DbException();
|
||||
@@ -321,6 +325,10 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
|
||||
processInviteeStateUpdate(txn, null,
|
||||
engine.onLocalAction(localState, localAction));
|
||||
|
||||
// track message
|
||||
long time = clock.currentTimeMillis();
|
||||
trackMessage(txn, localState.getGroupId(), time, true);
|
||||
|
||||
txn.setComplete();
|
||||
} catch (FormatException e) {
|
||||
throw new DbException(e);
|
||||
@@ -352,7 +360,7 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
|
||||
db.getMessageStatus(txn, contactId, m.getKey());
|
||||
long time = d.getLong(TIME);
|
||||
boolean local = d.getBoolean(LOCAL);
|
||||
boolean read = d.getBoolean(READ, false);
|
||||
boolean read = d.getBoolean(MSG_KEY_READ, false);
|
||||
boolean available = false;
|
||||
|
||||
if (type == SHARE_MSG_TYPE_INVITATION) {
|
||||
|
||||
@@ -4,28 +4,24 @@ import org.briarproject.BriarTestCase;
|
||||
import org.briarproject.TestUtils;
|
||||
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.SessionId;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.data.BdfDictionary;
|
||||
import org.briarproject.api.data.BdfEntry;
|
||||
import org.briarproject.api.data.BdfList;
|
||||
import org.briarproject.api.data.MetadataEncoder;
|
||||
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.identity.Author;
|
||||
import org.briarproject.api.identity.AuthorId;
|
||||
import org.briarproject.api.clients.SessionId;
|
||||
import org.briarproject.api.sync.ClientId;
|
||||
import org.briarproject.api.sync.Group;
|
||||
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.api.system.Clock;
|
||||
import org.jmock.Expectations;
|
||||
import org.jmock.Mockery;
|
||||
import org.jmock.lib.legacy.ClassImposteriser;
|
||||
@@ -46,30 +42,29 @@ import static org.briarproject.api.introduction.IntroductionConstants.TYPE;
|
||||
import static org.briarproject.api.introduction.IntroductionConstants.TYPE_REQUEST;
|
||||
import static org.briarproject.api.introduction.IntroductionConstants.TYPE_RESPONSE;
|
||||
import static org.briarproject.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
|
||||
import static org.briarproject.clients.BdfConstants.GROUP_KEY_LATEST_MSG;
|
||||
import static org.briarproject.clients.BdfConstants.GROUP_KEY_MSG_COUNT;
|
||||
import static org.briarproject.clients.BdfConstants.GROUP_KEY_UNREAD_COUNT;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
public class IntroductionManagerImplTest extends BriarTestCase {
|
||||
|
||||
final Mockery context;
|
||||
final IntroductionManagerImpl introductionManager;
|
||||
final IntroducerManager introducerManager;
|
||||
final IntroduceeManager introduceeManager;
|
||||
final DatabaseComponent db;
|
||||
final ContactGroupFactory contactGroupFactory;
|
||||
final ClientHelper clientHelper;
|
||||
final MetadataEncoder metadataEncoder;
|
||||
final MessageQueueManager messageQueueManager;
|
||||
final IntroductionGroupFactory introductionGroupFactory;
|
||||
final Clock clock;
|
||||
final SessionId sessionId = new SessionId(TestUtils.getRandomId());
|
||||
final long time = 42L;
|
||||
final Contact introducee1;
|
||||
final Contact introducee2;
|
||||
final Group localGroup0;
|
||||
final Group introductionGroup1;
|
||||
final Group introductionGroup2;
|
||||
final Message message1;
|
||||
Transaction txn;
|
||||
private final Mockery context;
|
||||
private final IntroductionManagerImpl introductionManager;
|
||||
private final IntroducerManager introducerManager;
|
||||
private final IntroduceeManager introduceeManager;
|
||||
private final DatabaseComponent db;
|
||||
private final ClientHelper clientHelper;
|
||||
private final IntroductionGroupFactory introductionGroupFactory;
|
||||
private final SessionId sessionId = new SessionId(TestUtils.getRandomId());
|
||||
private final long time = 42L;
|
||||
private final Contact introducee1;
|
||||
private final Contact introducee2;
|
||||
private final Group introductionGroup1;
|
||||
private final Group introductionGroup2;
|
||||
private final Message message1;
|
||||
private Transaction txn;
|
||||
private BdfDictionary metadataBefore, metadataAfter;
|
||||
|
||||
public IntroductionManagerImplTest() {
|
||||
AuthorId authorId1 = new AuthorId(TestUtils.getRandomId());
|
||||
@@ -89,8 +84,6 @@ public class IntroductionManagerImplTest extends BriarTestCase {
|
||||
new Contact(contactId2, author2, localAuthorId2, true, true);
|
||||
|
||||
ClientId clientId = new ClientId(TestUtils.getRandomId());
|
||||
localGroup0 = new Group(new GroupId(TestUtils.getRandomId()),
|
||||
clientId, new byte[0]);
|
||||
introductionGroup1 = new Group(new GroupId(TestUtils.getRandomId()),
|
||||
clientId, new byte[0]);
|
||||
introductionGroup2 = new Group(new GroupId(TestUtils.getRandomId()),
|
||||
@@ -102,6 +95,14 @@ public class IntroductionManagerImplTest extends BriarTestCase {
|
||||
time,
|
||||
TestUtils.getRandomBytes(MESSAGE_HEADER_LENGTH + 1)
|
||||
);
|
||||
metadataBefore = BdfDictionary.of(
|
||||
new BdfEntry(GROUP_KEY_MSG_COUNT, 41L),
|
||||
new BdfEntry(GROUP_KEY_LATEST_MSG, 0L)
|
||||
);
|
||||
metadataAfter = BdfDictionary.of(
|
||||
new BdfEntry(GROUP_KEY_MSG_COUNT, 42L),
|
||||
new BdfEntry(GROUP_KEY_LATEST_MSG, time)
|
||||
);
|
||||
|
||||
// mock ALL THE THINGS!!!
|
||||
context = new Mockery();
|
||||
@@ -109,15 +110,9 @@ public class IntroductionManagerImplTest extends BriarTestCase {
|
||||
introducerManager = context.mock(IntroducerManager.class);
|
||||
introduceeManager = context.mock(IntroduceeManager.class);
|
||||
db = context.mock(DatabaseComponent.class);
|
||||
contactGroupFactory = context.mock(ContactGroupFactory.class);
|
||||
clientHelper = context.mock(ClientHelper.class);
|
||||
metadataEncoder =
|
||||
context.mock(MetadataEncoder.class);
|
||||
messageQueueManager =
|
||||
context.mock(MessageQueueManager.class);
|
||||
MetadataParser metadataParser = context.mock(MetadataParser.class);
|
||||
introductionGroupFactory = context.mock(IntroductionGroupFactory.class);
|
||||
clock = context.mock(Clock.class);
|
||||
|
||||
introductionManager = new IntroductionManagerImpl(
|
||||
db, clientHelper, metadataParser, introducerManager,
|
||||
@@ -135,6 +130,27 @@ public class IntroductionManagerImplTest extends BriarTestCase {
|
||||
oneOf(introducerManager)
|
||||
.makeIntroduction(txn, introducee1, introducee2, null,
|
||||
time);
|
||||
// get both introduction groups
|
||||
oneOf(introductionGroupFactory)
|
||||
.createIntroductionGroup(introducee1);
|
||||
will(returnValue(introductionGroup1));
|
||||
oneOf(introductionGroupFactory)
|
||||
.createIntroductionGroup(introducee2);
|
||||
will(returnValue(introductionGroup2));
|
||||
// track message for group 1
|
||||
oneOf(clientHelper).getGroupMetadataAsDictionary(txn,
|
||||
introductionGroup1.getId());
|
||||
will(returnValue(metadataBefore));
|
||||
oneOf(clientHelper)
|
||||
.mergeGroupMetadata(txn, introductionGroup1.getId(),
|
||||
metadataAfter);
|
||||
// track message for group 2
|
||||
oneOf(clientHelper).getGroupMetadataAsDictionary(txn,
|
||||
introductionGroup2.getId());
|
||||
will(returnValue(metadataBefore));
|
||||
oneOf(clientHelper)
|
||||
.mergeGroupMetadata(txn, introductionGroup2.getId(),
|
||||
metadataAfter);
|
||||
oneOf(db).endTransaction(txn);
|
||||
}});
|
||||
|
||||
@@ -163,6 +179,13 @@ public class IntroductionManagerImplTest extends BriarTestCase {
|
||||
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, sessionId);
|
||||
will(returnValue(state));
|
||||
oneOf(introduceeManager).acceptIntroduction(txn, state, time);
|
||||
// track message
|
||||
oneOf(clientHelper).getGroupMetadataAsDictionary(txn,
|
||||
introductionGroup1.getId());
|
||||
will(returnValue(metadataBefore));
|
||||
oneOf(clientHelper)
|
||||
.mergeGroupMetadata(txn, introductionGroup1.getId(),
|
||||
metadataAfter);
|
||||
oneOf(db).endTransaction(txn);
|
||||
}});
|
||||
|
||||
@@ -191,6 +214,13 @@ public class IntroductionManagerImplTest extends BriarTestCase {
|
||||
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, sessionId);
|
||||
will(returnValue(state));
|
||||
oneOf(introduceeManager).declineIntroduction(txn, state, time);
|
||||
// track message
|
||||
oneOf(clientHelper).getGroupMetadataAsDictionary(txn,
|
||||
introductionGroup1.getId());
|
||||
will(returnValue(metadataBefore));
|
||||
oneOf(clientHelper)
|
||||
.mergeGroupMetadata(txn, introductionGroup1.getId(),
|
||||
metadataAfter);
|
||||
oneOf(db).endTransaction(txn);
|
||||
}});
|
||||
|
||||
@@ -241,12 +271,22 @@ 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);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(introduceeManager)
|
||||
.initialize(txn, introductionGroup1.getId(), msg);
|
||||
will(returnValue(state));
|
||||
oneOf(introduceeManager)
|
||||
.incomingMessage(txn, state, msg);
|
||||
// track message
|
||||
oneOf(clientHelper).getGroupMetadataAsDictionary(txn,
|
||||
introductionGroup1.getId());
|
||||
will(returnValue(metadataBefore));
|
||||
oneOf(clientHelper)
|
||||
.mergeGroupMetadata(txn, introductionGroup1.getId(),
|
||||
metadataAfter);
|
||||
}});
|
||||
|
||||
introductionManager
|
||||
@@ -272,10 +312,20 @@ public class IntroductionManagerImplTest extends BriarTestCase {
|
||||
|
||||
txn = new Transaction(null, false);
|
||||
|
||||
metadataBefore.put(GROUP_KEY_UNREAD_COUNT, 41L);
|
||||
metadataAfter.put(GROUP_KEY_UNREAD_COUNT, 42L);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, sessionId);
|
||||
will(returnValue(state));
|
||||
oneOf(introducerManager).incomingMessage(txn, state, msg);
|
||||
// track message
|
||||
oneOf(clientHelper).getGroupMetadataAsDictionary(txn,
|
||||
introductionGroup1.getId());
|
||||
will(returnValue(metadataBefore));
|
||||
oneOf(clientHelper)
|
||||
.mergeGroupMetadata(txn, introductionGroup1.getId(),
|
||||
metadataAfter);
|
||||
}});
|
||||
|
||||
introductionManager
|
||||
|
||||
Reference in New Issue
Block a user