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:
akwizgran
2016-10-05 16:20:32 +00:00
25 changed files with 421 additions and 141 deletions

View File

@@ -8,6 +8,7 @@ import org.briarproject.api.blogs.BlogInvitationResponse;
import org.briarproject.api.blogs.BlogManager; import org.briarproject.api.blogs.BlogManager;
import org.briarproject.api.blogs.BlogPostFactory; import org.briarproject.api.blogs.BlogPostFactory;
import org.briarproject.api.blogs.BlogSharingManager; import org.briarproject.api.blogs.BlogSharingManager;
import org.briarproject.api.clients.ContactGroupFactory;
import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.Contact;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.contact.ContactManager; 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.identity.LocalAuthor;
import org.briarproject.api.lifecycle.LifecycleManager; import org.briarproject.api.lifecycle.LifecycleManager;
import org.briarproject.api.sharing.InvitationMessage; import org.briarproject.api.sharing.InvitationMessage;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.SyncSession; import org.briarproject.api.sync.SyncSession;
import org.briarproject.api.sync.SyncSessionFactory; import org.briarproject.api.sync.SyncSessionFactory;
import org.briarproject.api.sync.ValidationManager.State; 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.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
public class BlogSharingIntegrationTest extends BriarTestCase { public class BlogSharingIntegrationTest extends BriarIntegrationTest {
private LifecycleManager lifecycleManager0, lifecycleManager1, private LifecycleManager lifecycleManager0, lifecycleManager1,
lifecycleManager2; lifecycleManager2;
private SyncSessionFactory sync0, sync1, sync2; private SyncSessionFactory sync0, sync1;
private BlogManager blogManager0, blogManager1, blogManager2; private BlogManager blogManager0, blogManager1;
private ContactManager contactManager0, contactManager1, contactManager2; private ContactManager contactManager0, contactManager1, contactManager2;
private Contact contact1, contact2, contact01, contact02; private Contact contact1, contact2, contact01, contact02;
private ContactId contactId1, contactId2, contactId01, contactId02; private ContactId contactId1, contactId2, contactId01, contactId02;
@@ -83,6 +85,8 @@ public class BlogSharingIntegrationTest extends BriarTestCase {
@Inject @Inject
AuthorFactory authorFactory; AuthorFactory authorFactory;
@Inject @Inject
ContactGroupFactory contactGroupFactory;
@Inject
BlogPostFactory blogPostFactory; BlogPostFactory blogPostFactory;
@Inject @Inject
CryptoComponent cryptoComponent; CryptoComponent cryptoComponent;
@@ -138,13 +142,11 @@ public class BlogSharingIntegrationTest extends BriarTestCase {
contactManager2 = t2.getContactManager(); contactManager2 = t2.getContactManager();
blogManager0 = t0.getBlogManager(); blogManager0 = t0.getBlogManager();
blogManager1 = t1.getBlogManager(); blogManager1 = t1.getBlogManager();
blogManager2 = t2.getBlogManager();
blogSharingManager0 = t0.getBlogSharingManager(); blogSharingManager0 = t0.getBlogSharingManager();
blogSharingManager1 = t1.getBlogSharingManager(); blogSharingManager1 = t1.getBlogSharingManager();
blogSharingManager2 = t2.getBlogSharingManager(); blogSharingManager2 = t2.getBlogSharingManager();
sync0 = t0.getSyncSessionFactory(); sync0 = t0.getSyncSessionFactory();
sync1 = t1.getSyncSessionFactory(); sync1 = t1.getSyncSessionFactory();
sync2 = t2.getSyncSessionFactory();
// initialize waiters fresh for each test // initialize waiters fresh for each test
eventWaiter = new Waiter(); eventWaiter = new Waiter();
@@ -187,15 +189,23 @@ public class BlogSharingIntegrationTest extends BriarTestCase {
// invitee has own blog and that of the sharer // invitee has own blog and that of the sharer
assertEquals(2, blogManager1.getBlogs().size()); 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 // sync first request message
sync0To1(); sync0To1();
eventWaiter.await(TIMEOUT, 1); eventWaiter.await(TIMEOUT, 1);
assertTrue(listener1.requestReceived); assertTrue(listener1.requestReceived);
assertGroupCount(blogSharingManager1, g, 2, 1);
// sync response back // sync response back
sync1To0(); sync1To0();
eventWaiter.await(TIMEOUT, 1); eventWaiter.await(TIMEOUT, 1);
assertTrue(listener0.responseReceived); assertTrue(listener0.responseReceived);
assertGroupCount(blogSharingManager0, g, 2, 1);
// blog was added successfully // blog was added successfully
assertEquals(0, blogSharingManager0.getInvitations().size()); assertEquals(0, blogSharingManager0.getInvitations().size());
@@ -232,6 +242,10 @@ public class BlogSharingIntegrationTest extends BriarTestCase {
assertFalse(blogSharingManager0.canBeShared(blog2.getId(), contact1)); assertFalse(blogSharingManager0.canBeShared(blog2.getId(), contact1));
assertFalse(blogSharingManager1.canBeShared(blog2.getId(), contact01)); assertFalse(blogSharingManager1.canBeShared(blog2.getId(), contact01));
// group message count is still correct
assertGroupCount(blogSharingManager0, g, 2, 1);
assertGroupCount(blogSharingManager1, g, 2, 1);
stopLifecycles(); stopLifecycles();
} }
@@ -510,8 +524,7 @@ public class BlogSharingIntegrationTest extends BriarTestCase {
private class SharerListener implements EventListener { private class SharerListener implements EventListener {
volatile boolean requestReceived = false; private volatile boolean responseReceived = false;
volatile boolean responseReceived = false;
@Override @Override
public void eventOccurred(Event e) { public void eventOccurred(Event e) {
@@ -534,7 +547,6 @@ public class BlogSharingIntegrationTest extends BriarTestCase {
BlogInvitationReceivedEvent event = BlogInvitationReceivedEvent event =
(BlogInvitationReceivedEvent) e; (BlogInvitationReceivedEvent) e;
eventWaiter.assertEquals(contactId1, event.getContactId()); eventWaiter.assertEquals(contactId1, event.getContactId());
requestReceived = true;
Blog b = event.getBlog(); Blog b = event.getBlog();
try { try {
Contact c = contactManager0.getContact(contactId1); Contact c = contactManager0.getContact(contactId1);
@@ -550,17 +562,16 @@ public class BlogSharingIntegrationTest extends BriarTestCase {
private class InviteeListener implements EventListener { private class InviteeListener implements EventListener {
volatile boolean requestReceived = false; private volatile boolean requestReceived = false;
volatile boolean responseReceived = false;
private final boolean accept, answer; private final boolean accept, answer;
InviteeListener(boolean accept, boolean answer) { private InviteeListener(boolean accept, boolean answer) {
this.accept = accept; this.accept = accept;
this.answer = answer; this.answer = answer;
} }
InviteeListener(boolean accept) { private InviteeListener(boolean accept) {
this(accept, true); this(accept, true);
} }
@@ -596,7 +607,6 @@ public class BlogSharingIntegrationTest extends BriarTestCase {
BlogInvitationResponseReceivedEvent event = BlogInvitationResponseReceivedEvent event =
(BlogInvitationResponseReceivedEvent) e; (BlogInvitationResponseReceivedEvent) e;
eventWaiter.assertEquals(contactId01, event.getContactId()); eventWaiter.assertEquals(contactId01, event.getContactId());
responseReceived = true;
eventWaiter.resume(); eventWaiter.resume();
} }
} }

View File

@@ -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());
}
}

View File

@@ -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.briarproject.api.sync.ValidationManager.State.PENDING;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
public class ForumManagerTest { public class ForumManagerTest extends BriarIntegrationTest {
private LifecycleManager lifecycleManager0, lifecycleManager1; private LifecycleManager lifecycleManager0, lifecycleManager1;
private SyncSessionFactory sync0, sync1; private SyncSessionFactory sync0, sync1;
@@ -150,9 +150,19 @@ public class ForumManagerTest {
createForumPost(forum.getGroup().getId(), post1, body2, ms2); createForumPost(forum.getGroup().getId(), post1, body2, ms2);
assertEquals(ms2, post2.getMessage().getTimestamp()); assertEquals(ms2, post2.getMessage().getTimestamp());
forumManager0.addLocalPost(post1); 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.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 = Collection<ForumPostHeader> headers =
forumManager0.getPostHeaders(forum.getGroup().getId()); forumManager0.getPostHeaders(forum.getGroup().getId());
assertEquals(2, headers.size()); assertEquals(2, headers.size());
@@ -202,23 +212,29 @@ public class ForumManagerTest {
forumManager0.addLocalPost(post1); forumManager0.addLocalPost(post1);
assertEquals(1, forumManager0.getPostHeaders(g).size()); assertEquals(1, forumManager0.getPostHeaders(g).size());
assertEquals(0, forumManager1.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 // send post to 1
sync0To1(); sync0To1();
deliveryWaiter.await(TIMEOUT, 1); deliveryWaiter.await(TIMEOUT, 1);
assertEquals(1, forumManager1.getPostHeaders(g).size()); assertEquals(1, forumManager1.getPostHeaders(g).size());
assertGroupCount(forumManager1, g, 1, 1, time);
// add another forum post // add another forum post
time = clock.currentTimeMillis(); long time2 = clock.currentTimeMillis();
ForumPost post2 = createForumPost(g, null, "b", time); ForumPost post2 = createForumPost(g, null, "b", time2);
forumManager1.addLocalPost(post2); forumManager1.addLocalPost(post2);
assertEquals(1, forumManager0.getPostHeaders(g).size()); assertEquals(1, forumManager0.getPostHeaders(g).size());
assertEquals(2, forumManager1.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 // send post to 0
sync1To0(); sync1To0();
deliveryWaiter.await(TIMEOUT, 1); deliveryWaiter.await(TIMEOUT, 1);
assertEquals(2, forumManager1.getPostHeaders(g).size()); assertEquals(2, forumManager1.getPostHeaders(g).size());
assertGroupCount(forumManager0, g, 2, 1, time2);
stopLifecycles(); stopLifecycles();
} }

View File

@@ -4,7 +4,7 @@ import android.support.annotation.Nullable;
import net.jodah.concurrentunit.Waiter; import net.jodah.concurrentunit.Waiter;
import org.briarproject.BriarTestCase; import org.briarproject.BriarIntegrationTest;
import org.briarproject.TestDatabaseModule; import org.briarproject.TestDatabaseModule;
import org.briarproject.TestUtils; import org.briarproject.TestUtils;
import org.briarproject.api.FormatException; 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.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
public class IntroductionIntegrationTest extends BriarTestCase { public class IntroductionIntegrationTest extends BriarIntegrationTest {
private LifecycleManager lifecycleManager0, lifecycleManager1, private LifecycleManager lifecycleManager0, lifecycleManager1,
lifecycleManager2; lifecycleManager2;
@@ -200,29 +200,43 @@ public class IntroductionIntegrationTest extends BriarTestCase {
introductionManager0 introductionManager0
.makeIntroduction(introducee1, introducee2, "Hi!", time); .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 // sync first request message
deliverMessage(sync0, contactId0, sync1, contactId1, "0 to 1"); deliverMessage(sync0, contactId0, sync1, contactId1, "0 to 1");
eventWaiter.await(TIMEOUT, 1); eventWaiter.await(TIMEOUT, 1);
assertTrue(listener1.requestReceived); assertTrue(listener1.requestReceived);
assertGroupCount(introductionManager1, g1.getId(), 2, 1);
// sync second request message // sync second request message
deliverMessage(sync0, contactId0, sync2, contactId2, "0 to 2"); deliverMessage(sync0, contactId0, sync2, contactId2, "0 to 2");
eventWaiter.await(TIMEOUT, 1); eventWaiter.await(TIMEOUT, 1);
assertTrue(listener2.requestReceived); assertTrue(listener2.requestReceived);
assertGroupCount(introductionManager2, g2.getId(), 2, 1);
// sync first response // sync first response
deliverMessage(sync1, contactId1, sync0, contactId0, "1 to 0"); deliverMessage(sync1, contactId1, sync0, contactId0, "1 to 0");
eventWaiter.await(TIMEOUT, 1); eventWaiter.await(TIMEOUT, 1);
assertTrue(listener0.response1Received); assertTrue(listener0.response1Received);
assertGroupCount(introductionManager0, g1.getId(), 2, 1);
// sync second response // sync second response
deliverMessage(sync2, contactId2, sync0, contactId0, "2 to 0"); deliverMessage(sync2, contactId2, sync0, contactId0, "2 to 0");
eventWaiter.await(TIMEOUT, 1); eventWaiter.await(TIMEOUT, 1);
assertTrue(listener0.response2Received); assertTrue(listener0.response2Received);
assertGroupCount(introductionManager0, g2.getId(), 2, 1);
// sync forwarded responses to introducees // sync forwarded responses to introducees
deliverMessage(sync0, contactId0, sync1, contactId1, "0 to 1"); deliverMessage(sync0, contactId0, sync1, contactId1, "0 to 1");
deliverMessage(sync0, contactId0, sync2, contactId2, "0 to 2"); 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 // sync first ACK and its forward
deliverMessage(sync1, contactId1, sync0, contactId0, "1 to 0"); deliverMessage(sync1, contactId1, sync0, contactId0, "1 to 0");
@@ -255,6 +269,10 @@ public class IntroductionIntegrationTest extends BriarTestCase {
} }
assertDefaultUiMessages(); 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 { } finally {
stopLifecycles(); stopLifecycles();
} }

View File

@@ -499,7 +499,7 @@ public class ConversationActivity extends BriarActivity
for (MessageId m : unread) for (MessageId m : unread)
// not really clean, but the messaging manager can // not really clean, but the messaging manager can
// handle introduction messages as well // handle introduction messages as well
messagingManager.setReadFlag(m, true); messagingManager.setReadFlag(groupId, m, true);
long duration = System.currentTimeMillis() - now; long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Marking read took " + duration + " ms"); LOG.info("Marking read took " + duration + " ms");
@@ -614,7 +614,7 @@ public class ConversationActivity extends BriarActivity
@Override @Override
public void run() { public void run() {
try { try {
messagingManager.setReadFlag(m, true); messagingManager.setReadFlag(groupId, m, true);
loadMessages(); loadMessages();
} catch (DbException e) { } catch (DbException e) {
if (LOG.isLoggable(WARNING)) if (LOG.isLoggable(WARNING))

View File

@@ -291,13 +291,15 @@ public class ForumControllerImpl extends DbControllerImpl
@Override @Override
public void entriesRead(final Collection<ForumEntry> forumEntries) { public void entriesRead(final Collection<ForumEntry> forumEntries) {
if (forum == null) return;
runOnDbThread(new Runnable() { runOnDbThread(new Runnable() {
@Override @Override
public void run() { public void run() {
try { try {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
for (ForumEntry fe : forumEntries) { for (ForumEntry fe : forumEntries) {
forumManager.setReadFlag(fe.getId(), true); forumManager
.setReadFlag(forum.getId(), fe.getId(), true);
} }
long duration = System.currentTimeMillis() - now; long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))

View File

@@ -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;
}
}
}

View File

@@ -28,6 +28,5 @@ public interface ForumConstants {
String KEY_PUBLIC_NAME = "publicKey"; String KEY_PUBLIC_NAME = "publicKey";
String KEY_AUTHOR = "author"; String KEY_AUTHOR = "author";
String KEY_LOCAL = "local"; String KEY_LOCAL = "local";
String KEY_READ = "read";
} }

View File

@@ -1,5 +1,6 @@
package org.briarproject.api.forum; package org.briarproject.api.forum;
import org.briarproject.api.clients.MessageTracker;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
import org.briarproject.api.db.Transaction; import org.briarproject.api.db.Transaction;
import org.briarproject.api.sync.ClientId; import org.briarproject.api.sync.ClientId;
@@ -8,7 +9,7 @@ import org.briarproject.api.sync.MessageId;
import java.util.Collection; import java.util.Collection;
public interface ForumManager { public interface ForumManager extends MessageTracker {
/** Returns the unique ID of the forum client. */ /** Returns the unique ID of the forum client. */
ClientId getClientId(); ClientId getClientId();
@@ -37,9 +38,6 @@ public interface ForumManager {
/** Returns the headers of all posts in the given forum. */ /** Returns the headers of all posts in the given forum. */
Collection<ForumPostHeader> getPostHeaders(GroupId g) throws DbException; 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. */ /** Registers a hook to be called whenever a forum is removed. */
void registerRemoveForumHook(RemoveForumHook hook); void registerRemoveForumHook(RemoveForumHook hook);

View File

@@ -45,7 +45,6 @@ public interface IntroductionConstants {
String CONTACT_ID_2 = "contactId2"; String CONTACT_ID_2 = "contactId2";
String RESPONSE_1 = "response1"; String RESPONSE_1 = "response1";
String RESPONSE_2 = "response2"; String RESPONSE_2 = "response2";
String READ = "read";
/* Introduction Request Action */ /* Introduction Request Action */
String PUBLIC_KEY1 = "publicKey1"; String PUBLIC_KEY1 = "publicKey1";

View File

@@ -1,6 +1,7 @@
package org.briarproject.api.introduction; package org.briarproject.api.introduction;
import org.briarproject.api.FormatException; import org.briarproject.api.FormatException;
import org.briarproject.api.clients.MessageTracker;
import org.briarproject.api.clients.SessionId; import org.briarproject.api.clients.SessionId;
import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.Contact;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
@@ -9,7 +10,7 @@ import org.briarproject.api.sync.ClientId;
import java.util.Collection; import java.util.Collection;
public interface IntroductionManager { public interface IntroductionManager extends MessageTracker {
/** Returns the unique ID of the introduction client. */ /** Returns the unique ID of the introduction client. */
ClientId getClientId(); ClientId getClientId();

View File

@@ -1,5 +1,6 @@
package org.briarproject.api.messaging; package org.briarproject.api.messaging;
import org.briarproject.api.clients.MessageTracker;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
import org.briarproject.api.sync.ClientId; import org.briarproject.api.sync.ClientId;
@@ -8,7 +9,7 @@ import org.briarproject.api.sync.MessageId;
import java.util.Collection; import java.util.Collection;
public interface MessagingManager { public interface MessagingManager extends MessageTracker {
/** Returns the unique ID of the messaging client. */ /** Returns the unique ID of the messaging client. */
ClientId getClientId(); ClientId getClientId();
@@ -31,6 +32,4 @@ public interface MessagingManager {
/** Returns the body of the private message with the given ID. */ /** Returns the body of the private message with the given ID. */
byte[] getMessageBody(MessageId m) throws DbException; byte[] getMessageBody(MessageId m) throws DbException;
/** Marks a private message as read or unread. */
void setReadFlag(MessageId m, boolean read) throws DbException;
} }

View File

@@ -1,5 +1,6 @@
package org.briarproject.api.privategroup; package org.briarproject.api.privategroup;
import org.briarproject.api.clients.MessageTracker;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
import org.briarproject.api.db.Transaction; import org.briarproject.api.db.Transaction;
import org.briarproject.api.sync.ClientId; import org.briarproject.api.sync.ClientId;
@@ -9,7 +10,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.Collection; import java.util.Collection;
public interface PrivateGroupManager { public interface PrivateGroupManager extends MessageTracker {
/** Returns the unique ID of the private group client. */ /** Returns the unique ID of the private group client. */
@NotNull @NotNull
@@ -40,7 +41,4 @@ public interface PrivateGroupManager {
@NotNull @NotNull
Collection<GroupMessageHeader> getHeaders(GroupId g) throws DbException; Collection<GroupMessageHeader> getHeaders(GroupId g) throws DbException;
/** Marks a group message as read or unread. */
void setReadFlag(MessageId m, boolean read) throws DbException;
} }

View File

@@ -16,7 +16,6 @@ public interface SharingConstants {
String STATE = "state"; String STATE = "state";
String LOCAL = "local"; String LOCAL = "local";
String TIME = "time"; String TIME = "time";
String READ = "read";
String IS_SHARER = "isSharer"; String IS_SHARER = "isSharer";
String SHAREABLE_ID = "shareableId"; String SHAREABLE_ID = "shareableId";
String INVITATION_MSG = "invitationMsg"; String INVITATION_MSG = "invitationMsg";

View File

@@ -1,5 +1,6 @@
package org.briarproject.api.sharing; package org.briarproject.api.sharing;
import org.briarproject.api.clients.MessageTracker;
import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.Contact;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
@@ -8,7 +9,7 @@ import org.briarproject.api.sync.GroupId;
import java.util.Collection; 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. */ /** Returns the unique ID of the group sharing client. */
ClientId getClientId(); ClientId getClientId();

View File

@@ -86,7 +86,6 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager,
"dafbe56f0c8971365cea4bb5f08ec9a6" + "dafbe56f0c8971365cea4bb5f08ec9a6" +
"1d686e058b943997b6ff259ba423f613")); "1d686e058b943997b6ff259ba423f613"));
private final DatabaseComponent db;
private final IdentityManager identityManager; private final IdentityManager identityManager;
private final ContactManager contactManager; private final ContactManager contactManager;
private final BlogFactory blogFactory; private final BlogFactory blogFactory;
@@ -98,9 +97,8 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager,
ClientHelper clientHelper, MetadataParser metadataParser, ClientHelper clientHelper, MetadataParser metadataParser,
ContactManager contactManager, BlogFactory blogFactory, ContactManager contactManager, BlogFactory blogFactory,
BlogPostFactory blogPostFactory) { BlogPostFactory blogPostFactory) {
super(clientHelper, metadataParser); super(db, clientHelper, metadataParser);
this.db = db;
this.identityManager = identityManager; this.identityManager = identityManager;
this.contactManager = contactManager; this.contactManager = contactManager;
this.blogFactory = blogFactory; this.blogFactory = blogFactory;

View 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";
}

View File

@@ -3,27 +3,38 @@ package org.briarproject.clients;
import org.briarproject.api.FormatException; import org.briarproject.api.FormatException;
import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.clients.ClientHelper;
import org.briarproject.api.clients.MessageQueueManager.IncomingQueueMessageHook; import org.briarproject.api.clients.MessageQueueManager.IncomingQueueMessageHook;
import org.briarproject.api.clients.MessageTracker;
import org.briarproject.api.clients.QueueMessage; import org.briarproject.api.clients.QueueMessage;
import org.briarproject.api.data.BdfDictionary; import org.briarproject.api.data.BdfDictionary;
import org.briarproject.api.data.BdfEntry;
import org.briarproject.api.data.BdfList; import org.briarproject.api.data.BdfList;
import org.briarproject.api.data.MetadataParser; import org.briarproject.api.data.MetadataParser;
import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
import org.briarproject.api.db.Metadata; import org.briarproject.api.db.Metadata;
import org.briarproject.api.db.Transaction; import org.briarproject.api.db.Transaction;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.Message; import org.briarproject.api.sync.Message;
import org.briarproject.api.sync.MessageId;
import org.briarproject.api.sync.ValidationManager.IncomingMessageHook; import org.briarproject.api.sync.ValidationManager.IncomingMessageHook;
import static org.briarproject.api.clients.QueueMessage.QUEUE_MESSAGE_HEADER_LENGTH; 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.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, public abstract class BdfIncomingMessageHook implements IncomingMessageHook,
IncomingQueueMessageHook { IncomingQueueMessageHook, MessageTracker {
protected final DatabaseComponent db;
protected final ClientHelper clientHelper; protected final ClientHelper clientHelper;
protected final MetadataParser metadataParser; protected final MetadataParser metadataParser;
protected BdfIncomingMessageHook(ClientHelper clientHelper, protected BdfIncomingMessageHook(DatabaseComponent db,
MetadataParser metadataParser) { ClientHelper clientHelper, MetadataParser metadataParser) {
this.db = db;
this.clientHelper = clientHelper; this.clientHelper = clientHelper;
this.metadataParser = metadataParser; this.metadataParser = metadataParser;
} }
@@ -56,4 +67,102 @@ public abstract class BdfIncomingMessageHook implements IncomingMessageHook,
throw new DbException(e); 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);
}
}
} }

View File

@@ -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_NAME;
import static org.briarproject.api.forum.ForumConstants.KEY_PARENT; 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_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.forum.ForumConstants.KEY_TIMESTAMP;
import static org.briarproject.api.identity.Author.Status.ANONYMOUS; import static org.briarproject.api.identity.Author.Status.ANONYMOUS;
import static org.briarproject.clients.BdfConstants.MSG_KEY_READ;
class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager { class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
@@ -55,7 +55,6 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
"859a7be50dca035b64bd6902fb797097" "859a7be50dca035b64bd6902fb797097"
+ "795af837abbf8c16d750b3c2ccc186ea")); + "795af837abbf8c16d750b3c2ccc186ea"));
private final DatabaseComponent db;
private final IdentityManager identityManager; private final IdentityManager identityManager;
private final ForumFactory forumFactory; private final ForumFactory forumFactory;
private final List<RemoveForumHook> removeHooks; private final List<RemoveForumHook> removeHooks;
@@ -64,9 +63,8 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
ForumManagerImpl(DatabaseComponent db, IdentityManager identityManager, ForumManagerImpl(DatabaseComponent db, IdentityManager identityManager,
ClientHelper clientHelper, MetadataParser metadataParser, ClientHelper clientHelper, MetadataParser metadataParser,
ForumFactory forumFactory) { ForumFactory forumFactory) {
super(db, clientHelper, metadataParser);
super(clientHelper, metadataParser);
this.db = db;
this.identityManager = identityManager; this.identityManager = identityManager;
this.forumFactory = forumFactory; this.forumFactory = forumFactory;
removeHooks = new CopyOnWriteArrayList<RemoveForumHook>(); removeHooks = new CopyOnWriteArrayList<RemoveForumHook>();
@@ -76,6 +74,8 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
protected boolean incomingMessage(Transaction txn, Message m, BdfList body, protected boolean incomingMessage(Transaction txn, Message m, BdfList body,
BdfDictionary meta) throws DbException, FormatException { BdfDictionary meta) throws DbException, FormatException {
trackIncomingMessage(txn, m);
ForumPostHeader post = getForumPostHeader(txn, m.getId(), meta); ForumPostHeader post = getForumPostHeader(txn, m.getId(), meta);
ForumPostReceivedEvent event = ForumPostReceivedEvent event =
new ForumPostReceivedEvent(post, m.getGroupId()); new ForumPostReceivedEvent(post, m.getGroupId());
@@ -119,6 +119,7 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
@Override @Override
public void addLocalPost(ForumPost p) throws DbException { public void addLocalPost(ForumPost p) throws DbException {
Transaction txn = db.startTransaction(false);
try { try {
BdfDictionary meta = new BdfDictionary(); BdfDictionary meta = new BdfDictionary();
meta.put(KEY_TIMESTAMP, p.getMessage().getTimestamp()); 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_AUTHOR, authorMeta);
} }
meta.put(KEY_LOCAL, true); meta.put(KEY_LOCAL, true);
meta.put(KEY_READ, true); meta.put(MSG_KEY_READ, true);
clientHelper.addLocalMessage(p.getMessage(), meta, true); clientHelper.addLocalMessage(txn, p.getMessage(), meta, true);
trackOutgoingMessage(txn, p.getMessage());
txn.setComplete();
} catch (FormatException e) { } catch (FormatException e) {
throw new RuntimeException(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 @Override
public void registerRemoveForumHook(RemoveForumHook hook) { public void registerRemoveForumHook(RemoveForumHook hook) {
removeHooks.add(hook); removeHooks.add(hook);
@@ -281,7 +275,7 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
status = identityManager.getAuthorStatus(txn, author.getId()); 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, return new ForumPostHeader(id, parentId, timestamp, author, status,
read); read);

View File

@@ -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.MSG;
import static org.briarproject.api.introduction.IntroductionConstants.NAME; 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.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_ID;
import static org.briarproject.api.introduction.IntroductionConstants.REMOTE_AUTHOR_IS_US; import static org.briarproject.api.introduction.IntroductionConstants.REMOTE_AUTHOR_IS_US;
import static org.briarproject.api.introduction.IntroductionConstants.RESPONSE_1; 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_ACK;
import static org.briarproject.api.introduction.IntroductionConstants.TYPE_REQUEST; import static org.briarproject.api.introduction.IntroductionConstants.TYPE_REQUEST;
import static org.briarproject.api.introduction.IntroductionConstants.TYPE_RESPONSE; 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 BdfIncomingMessageHook
implements IntroductionManager, Client, AddContactHook, implements IntroductionManager, Client, AddContactHook,
@@ -87,7 +87,6 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(IntroductionManagerImpl.class.getName()); Logger.getLogger(IntroductionManagerImpl.class.getName());
private final DatabaseComponent db;
private final IntroducerManager introducerManager; private final IntroducerManager introducerManager;
private final IntroduceeManager introduceeManager; private final IntroduceeManager introduceeManager;
private final IntroductionGroupFactory introductionGroupFactory; private final IntroductionGroupFactory introductionGroupFactory;
@@ -98,8 +97,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
IntroduceeManager introduceeManager, IntroduceeManager introduceeManager,
IntroductionGroupFactory introductionGroupFactory) { IntroductionGroupFactory introductionGroupFactory) {
super(clientHelper, metadataParser); super(db, clientHelper, metadataParser);
this.db = db;
this.introducerManager = introducerManager; this.introducerManager = introducerManager;
this.introduceeManager = introduceeManager; this.introduceeManager = introduceeManager;
this.introductionGroupFactory = introductionGroupFactory; this.introductionGroupFactory = introductionGroupFactory;
@@ -208,7 +206,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
*/ */
@Override @Override
protected boolean incomingMessage(Transaction txn, Message m, BdfList body, protected boolean incomingMessage(Transaction txn, Message m, BdfList body,
BdfDictionary message) throws DbException { BdfDictionary message) throws DbException {
// Get message data and type // Get message data and type
GroupId groupId = m.getGroupId(); GroupId groupId = m.getGroupId();
@@ -237,6 +235,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
} }
try { try {
introduceeManager.incomingMessage(txn, state, message); introduceeManager.incomingMessage(txn, state, message);
trackIncomingMessage(txn, m);
} catch (DbException e) { } catch (DbException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
introduceeManager.abort(txn, state); introduceeManager.abort(txn, state);
@@ -270,6 +269,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
deleteMessage(txn, m.getId()); deleteMessage(txn, m.getId());
} }
} }
if (type == TYPE_RESPONSE) trackIncomingMessage(txn, m);
} catch (DbException e) { } catch (DbException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
if (role == ROLE_INTRODUCER) introducerManager.abort(txn, state); if (role == ROLE_INTRODUCER) introducerManager.abort(txn, state);
@@ -296,6 +296,10 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
Transaction txn = db.startTransaction(false); Transaction txn = db.startTransaction(false);
try { try {
introducerManager.makeIntroduction(txn, c1, c2, msg, timestamp); 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(); txn.setComplete();
} finally { } finally {
db.endTransaction(txn); db.endTransaction(txn);
@@ -315,6 +319,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
getSessionState(txn, g.getId(), sessionId.getBytes()); getSessionState(txn, g.getId(), sessionId.getBytes());
introduceeManager.acceptIntroduction(txn, state, timestamp); introduceeManager.acceptIntroduction(txn, state, timestamp);
trackMessage(txn, g.getId(), timestamp, true);
txn.setComplete(); txn.setComplete();
} finally { } finally {
db.endTransaction(txn); db.endTransaction(txn);
@@ -334,6 +339,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
getSessionState(txn, g.getId(), sessionId.getBytes()); getSessionState(txn, g.getId(), sessionId.getBytes());
introduceeManager.declineIntroduction(txn, state, timestamp); introduceeManager.declineIntroduction(txn, state, timestamp);
trackMessage(txn, g.getId(), timestamp, true);
txn.setComplete(); txn.setComplete();
} finally { } finally {
db.endTransaction(txn); db.endTransaction(txn);
@@ -377,7 +383,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
boolean local; boolean local;
long time = msg.getLong(MESSAGE_TIME); long time = msg.getLong(MESSAGE_TIME);
boolean accepted = msg.getBoolean(ACCEPT, false); boolean accepted = msg.getBoolean(ACCEPT, false);
boolean read = msg.getBoolean(READ, false); boolean read = msg.getBoolean(MSG_KEY_READ, false);
AuthorId authorId; AuthorId authorId;
String name; String name;
if (type == TYPE_RESPONSE) { if (type == TYPE_RESPONSE) {

View File

@@ -33,6 +33,8 @@ import java.util.Map;
import javax.inject.Inject; import javax.inject.Inject;
import static org.briarproject.clients.BdfConstants.MSG_KEY_READ;
class MessagingManagerImpl extends BdfIncomingMessageHook class MessagingManagerImpl extends BdfIncomingMessageHook
implements MessagingManager, Client, AddContactHook, RemoveContactHook { implements MessagingManager, Client, AddContactHook, RemoveContactHook {
@@ -40,16 +42,13 @@ class MessagingManagerImpl extends BdfIncomingMessageHook
"6bcdc006c0910b0f44e40644c3b31f1a" "6bcdc006c0910b0f44e40644c3b31f1a"
+ "8bf9a6d6021d40d219c86b731b903070")); + "8bf9a6d6021d40d219c86b731b903070"));
private final DatabaseComponent db;
private final ContactGroupFactory contactGroupFactory; private final ContactGroupFactory contactGroupFactory;
@Inject @Inject
MessagingManagerImpl(DatabaseComponent db, ClientHelper clientHelper, MessagingManagerImpl(DatabaseComponent db, ClientHelper clientHelper,
MetadataParser metadataParser, MetadataParser metadataParser,
ContactGroupFactory contactGroupFactory) { ContactGroupFactory contactGroupFactory) {
super(clientHelper, metadataParser); super(db, clientHelper, metadataParser);
this.db = db;
this.contactGroupFactory = contactGroupFactory; this.contactGroupFactory = contactGroupFactory;
} }
@@ -100,12 +99,13 @@ class MessagingManagerImpl extends BdfIncomingMessageHook
long timestamp = meta.getLong("timestamp"); long timestamp = meta.getLong("timestamp");
String contentType = meta.getString("contentType"); String contentType = meta.getString("contentType");
boolean local = meta.getBoolean("local"); boolean local = meta.getBoolean("local");
boolean read = meta.getBoolean("read"); boolean read = meta.getBoolean(MSG_KEY_READ);
PrivateMessageHeader header = new PrivateMessageHeader( PrivateMessageHeader header = new PrivateMessageHeader(
m.getId(), timestamp, contentType, local, read, false, false); m.getId(), timestamp, contentType, local, read, false, false);
PrivateMessageReceivedEvent event = new PrivateMessageReceivedEvent( PrivateMessageReceivedEvent event = new PrivateMessageReceivedEvent(
header, groupId); header, groupId);
txn.attach(event); txn.attach(event);
trackIncomingMessage(txn, m);
// don't share message // don't share message
return false; return false;
@@ -113,6 +113,7 @@ class MessagingManagerImpl extends BdfIncomingMessageHook
@Override @Override
public void addLocalMessage(PrivateMessage m) throws DbException { public void addLocalMessage(PrivateMessage m) throws DbException {
Transaction txn = db.startTransaction(false);
try { try {
BdfDictionary meta = new BdfDictionary(); BdfDictionary meta = new BdfDictionary();
meta.put("timestamp", m.getMessage().getTimestamp()); meta.put("timestamp", m.getMessage().getTimestamp());
@@ -120,9 +121,13 @@ class MessagingManagerImpl extends BdfIncomingMessageHook
meta.put("contentType", m.getContentType()); meta.put("contentType", m.getContentType());
meta.put("local", true); meta.put("local", true);
meta.put("read", 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) { } catch (FormatException e) {
throw new RuntimeException(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);
}
}
} }

View File

@@ -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_CONTENT_TYPE_LENGTH;
import static org.briarproject.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_BODY_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 { class PrivateMessageValidator extends BdfMessageValidator {
@@ -42,7 +43,7 @@ class PrivateMessageValidator extends BdfMessageValidator {
if (parentId != null) meta.put("parent", parentId); if (parentId != null) meta.put("parent", parentId);
meta.put("contentType", contentType); meta.put("contentType", contentType);
meta.put("local", false); meta.put("local", false);
meta.put("read", false); meta.put(MSG_KEY_READ, false);
return new BdfMessageContext(meta); return new BdfMessageContext(meta);
} }
} }

View File

@@ -28,8 +28,6 @@ import java.util.Collections;
import javax.inject.Inject; import javax.inject.Inject;
import static org.briarproject.privategroup.Constants.KEY_READ;
public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
PrivateGroupManager { PrivateGroupManager {
@@ -37,7 +35,6 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
StringUtils.fromHexString("5072697661746547726f75704d616e61" StringUtils.fromHexString("5072697661746547726f75704d616e61"
+ "67657220627920546f727374656e2047")); + "67657220627920546f727374656e2047"));
private final DatabaseComponent db;
private final IdentityManager identityManager; private final IdentityManager identityManager;
private final PrivateGroupFactory privateGroupFactory; private final PrivateGroupFactory privateGroupFactory;
@@ -46,9 +43,8 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
MetadataParser metadataParser, DatabaseComponent db, MetadataParser metadataParser, DatabaseComponent db,
IdentityManager identityManager, IdentityManager identityManager,
PrivateGroupFactory privateGroupFactory) { PrivateGroupFactory privateGroupFactory) {
super(clientHelper, metadataParser); super(db, clientHelper, metadataParser);
this.db = db;
this.identityManager = identityManager; this.identityManager = identityManager;
this.privateGroupFactory = privateGroupFactory; this.privateGroupFactory = privateGroupFactory;
} }
@@ -61,11 +57,16 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
@Override @Override
public void addLocalMessage(GroupMessage m) throws DbException { public void addLocalMessage(GroupMessage m) throws DbException {
Transaction txn = db.startTransaction(false);
try { try {
BdfDictionary meta = new BdfDictionary(); 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) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);
} finally {
db.endTransaction(txn);
} }
} }
@@ -104,21 +105,12 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
return Collections.emptyList(); 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 @Override
protected boolean incomingMessage(Transaction txn, Message m, BdfList body, protected boolean incomingMessage(Transaction txn, Message m, BdfList body,
BdfDictionary meta) throws DbException, FormatException { BdfDictionary meta) throws DbException, FormatException {
trackIncomingMessage(txn, m);
return true; return true;
} }

View File

@@ -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.CONTACT_ID;
import static org.briarproject.api.sharing.SharingConstants.IS_SHARER; import static org.briarproject.api.sharing.SharingConstants.IS_SHARER;
import static org.briarproject.api.sharing.SharingConstants.LOCAL; 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.SESSION_ID;
import static org.briarproject.api.sharing.SharingConstants.SHAREABLE_ID; import static org.briarproject.api.sharing.SharingConstants.SHAREABLE_ID;
import static org.briarproject.api.sharing.SharingConstants.SHARED_BY_US; 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.SharingConstants.TYPE;
import static org.briarproject.api.sharing.SharingMessage.BaseMessage; import static org.briarproject.api.sharing.SharingMessage.BaseMessage;
import static org.briarproject.api.sharing.SharingMessage.Invitation; 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; 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> 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 = private static final Logger LOG =
Logger.getLogger(SharingManagerImpl.class.getName()); Logger.getLogger(SharingManagerImpl.class.getName());
private final DatabaseComponent db;
private final MessageQueueManager messageQueueManager; private final MessageQueueManager messageQueueManager;
private final MetadataEncoder metadataEncoder; private final MetadataEncoder metadataEncoder;
private final SecureRandom random; private final SecureRandom random;
@@ -106,9 +105,8 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
MetadataParser metadataParser, MetadataEncoder metadataEncoder, MetadataParser metadataParser, MetadataEncoder metadataEncoder,
SecureRandom random, ContactGroupFactory contactGroupFactory, SecureRandom random, ContactGroupFactory contactGroupFactory,
Clock clock) { Clock clock) {
super(db, clientHelper, metadataParser);
super(clientHelper, metadataParser);
this.db = db;
this.messageQueueManager = messageQueueManager; this.messageQueueManager = messageQueueManager;
this.metadataEncoder = metadataEncoder; this.metadataEncoder = metadataEncoder;
this.random = random; this.random = random;
@@ -226,6 +224,7 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
new InviteeEngine<IS, IR>(getIRFactory()); new InviteeEngine<IS, IR>(getIRFactory());
processInviteeStateUpdate(txn, m.getId(), processInviteeStateUpdate(txn, m.getId(),
engine.onMessageReceived(state, msg)); engine.onMessageReceived(state, msg));
trackIncomingMessage(txn, m);
} catch (FormatException e) { } catch (FormatException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
deleteMessage(txn, m.getId()); deleteMessage(txn, m.getId());
@@ -239,6 +238,7 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
getIRRFactory()); getIRRFactory());
processSharerStateUpdate(txn, m.getId(), processSharerStateUpdate(txn, m.getId(),
engine.onMessageReceived(state, msg)); engine.onMessageReceived(state, msg));
trackIncomingMessage(txn, m);
} else if (msg.getType() == SHARE_MSG_TYPE_LEAVE || } else if (msg.getType() == SHARE_MSG_TYPE_LEAVE ||
msg.getType() == SHARE_MSG_TYPE_ABORT) { msg.getType() == SHARE_MSG_TYPE_ABORT) {
// we don't know who we are, so figure it out // 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, engine.onLocalAction(localState,
SharerSessionState.Action.LOCAL_INVITATION)); SharerSessionState.Action.LOCAL_INVITATION));
// track message
long time = clock.currentTimeMillis();
trackMessage(txn, localState.getGroupId(), time, true);
txn.setComplete(); txn.setComplete();
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(); throw new DbException();
@@ -321,6 +325,10 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
processInviteeStateUpdate(txn, null, processInviteeStateUpdate(txn, null,
engine.onLocalAction(localState, localAction)); engine.onLocalAction(localState, localAction));
// track message
long time = clock.currentTimeMillis();
trackMessage(txn, localState.getGroupId(), time, true);
txn.setComplete(); txn.setComplete();
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(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()); db.getMessageStatus(txn, contactId, m.getKey());
long time = d.getLong(TIME); long time = d.getLong(TIME);
boolean local = d.getBoolean(LOCAL); boolean local = d.getBoolean(LOCAL);
boolean read = d.getBoolean(READ, false); boolean read = d.getBoolean(MSG_KEY_READ, false);
boolean available = false; boolean available = false;
if (type == SHARE_MSG_TYPE_INVITATION) { if (type == SHARE_MSG_TYPE_INVITATION) {

View File

@@ -4,28 +4,24 @@ import org.briarproject.BriarTestCase;
import org.briarproject.TestUtils; import org.briarproject.TestUtils;
import org.briarproject.api.FormatException; import org.briarproject.api.FormatException;
import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.clients.ClientHelper;
import org.briarproject.api.clients.MessageQueueManager; import org.briarproject.api.clients.SessionId;
import org.briarproject.api.clients.ContactGroupFactory;
import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.Contact;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.data.BdfDictionary; import org.briarproject.api.data.BdfDictionary;
import org.briarproject.api.data.BdfEntry; import org.briarproject.api.data.BdfEntry;
import org.briarproject.api.data.BdfList; import org.briarproject.api.data.BdfList;
import org.briarproject.api.data.MetadataEncoder;
import org.briarproject.api.data.MetadataParser; import org.briarproject.api.data.MetadataParser;
import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
import org.briarproject.api.db.Transaction; import org.briarproject.api.db.Transaction;
import org.briarproject.api.identity.Author; import org.briarproject.api.identity.Author;
import org.briarproject.api.identity.AuthorId; import org.briarproject.api.identity.AuthorId;
import org.briarproject.api.clients.SessionId;
import org.briarproject.api.sync.ClientId; import org.briarproject.api.sync.ClientId;
import org.briarproject.api.sync.Group; import org.briarproject.api.sync.Group;
import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.Message; import org.briarproject.api.sync.Message;
import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageId;
import org.briarproject.api.sync.MessageStatus; import org.briarproject.api.sync.MessageStatus;
import org.briarproject.api.system.Clock;
import org.jmock.Expectations; import org.jmock.Expectations;
import org.jmock.Mockery; import org.jmock.Mockery;
import org.jmock.lib.legacy.ClassImposteriser; 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_REQUEST;
import static org.briarproject.api.introduction.IntroductionConstants.TYPE_RESPONSE; import static org.briarproject.api.introduction.IntroductionConstants.TYPE_RESPONSE;
import static org.briarproject.api.sync.SyncConstants.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.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
public class IntroductionManagerImplTest extends BriarTestCase { public class IntroductionManagerImplTest extends BriarTestCase {
final Mockery context; private final Mockery context;
final IntroductionManagerImpl introductionManager; private final IntroductionManagerImpl introductionManager;
final IntroducerManager introducerManager; private final IntroducerManager introducerManager;
final IntroduceeManager introduceeManager; private final IntroduceeManager introduceeManager;
final DatabaseComponent db; private final DatabaseComponent db;
final ContactGroupFactory contactGroupFactory; private final ClientHelper clientHelper;
final ClientHelper clientHelper; private final IntroductionGroupFactory introductionGroupFactory;
final MetadataEncoder metadataEncoder; private final SessionId sessionId = new SessionId(TestUtils.getRandomId());
final MessageQueueManager messageQueueManager; private final long time = 42L;
final IntroductionGroupFactory introductionGroupFactory; private final Contact introducee1;
final Clock clock; private final Contact introducee2;
final SessionId sessionId = new SessionId(TestUtils.getRandomId()); private final Group introductionGroup1;
final long time = 42L; private final Group introductionGroup2;
final Contact introducee1; private final Message message1;
final Contact introducee2; private Transaction txn;
final Group localGroup0; private BdfDictionary metadataBefore, metadataAfter;
final Group introductionGroup1;
final Group introductionGroup2;
final Message message1;
Transaction txn;
public IntroductionManagerImplTest() { public IntroductionManagerImplTest() {
AuthorId authorId1 = new AuthorId(TestUtils.getRandomId()); AuthorId authorId1 = new AuthorId(TestUtils.getRandomId());
@@ -89,8 +84,6 @@ public class IntroductionManagerImplTest extends BriarTestCase {
new Contact(contactId2, author2, localAuthorId2, true, true); new Contact(contactId2, author2, localAuthorId2, true, true);
ClientId clientId = new ClientId(TestUtils.getRandomId()); ClientId clientId = new ClientId(TestUtils.getRandomId());
localGroup0 = new Group(new GroupId(TestUtils.getRandomId()),
clientId, new byte[0]);
introductionGroup1 = new Group(new GroupId(TestUtils.getRandomId()), introductionGroup1 = new Group(new GroupId(TestUtils.getRandomId()),
clientId, new byte[0]); clientId, new byte[0]);
introductionGroup2 = new Group(new GroupId(TestUtils.getRandomId()), introductionGroup2 = new Group(new GroupId(TestUtils.getRandomId()),
@@ -102,6 +95,14 @@ public class IntroductionManagerImplTest extends BriarTestCase {
time, time,
TestUtils.getRandomBytes(MESSAGE_HEADER_LENGTH + 1) 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!!! // mock ALL THE THINGS!!!
context = new Mockery(); context = new Mockery();
@@ -109,15 +110,9 @@ public class IntroductionManagerImplTest extends BriarTestCase {
introducerManager = context.mock(IntroducerManager.class); introducerManager = context.mock(IntroducerManager.class);
introduceeManager = context.mock(IntroduceeManager.class); introduceeManager = context.mock(IntroduceeManager.class);
db = context.mock(DatabaseComponent.class); db = context.mock(DatabaseComponent.class);
contactGroupFactory = context.mock(ContactGroupFactory.class);
clientHelper = context.mock(ClientHelper.class); clientHelper = context.mock(ClientHelper.class);
metadataEncoder =
context.mock(MetadataEncoder.class);
messageQueueManager =
context.mock(MessageQueueManager.class);
MetadataParser metadataParser = context.mock(MetadataParser.class); MetadataParser metadataParser = context.mock(MetadataParser.class);
introductionGroupFactory = context.mock(IntroductionGroupFactory.class); introductionGroupFactory = context.mock(IntroductionGroupFactory.class);
clock = context.mock(Clock.class);
introductionManager = new IntroductionManagerImpl( introductionManager = new IntroductionManagerImpl(
db, clientHelper, metadataParser, introducerManager, db, clientHelper, metadataParser, introducerManager,
@@ -135,6 +130,27 @@ public class IntroductionManagerImplTest extends BriarTestCase {
oneOf(introducerManager) oneOf(introducerManager)
.makeIntroduction(txn, introducee1, introducee2, null, .makeIntroduction(txn, introducee1, introducee2, null,
time); 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); oneOf(db).endTransaction(txn);
}}); }});
@@ -163,6 +179,13 @@ public class IntroductionManagerImplTest extends BriarTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, sessionId); oneOf(clientHelper).getMessageMetadataAsDictionary(txn, sessionId);
will(returnValue(state)); will(returnValue(state));
oneOf(introduceeManager).acceptIntroduction(txn, state, time); 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); oneOf(db).endTransaction(txn);
}}); }});
@@ -191,6 +214,13 @@ public class IntroductionManagerImplTest extends BriarTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, sessionId); oneOf(clientHelper).getMessageMetadataAsDictionary(txn, sessionId);
will(returnValue(state)); will(returnValue(state));
oneOf(introduceeManager).declineIntroduction(txn, state, time); 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); oneOf(db).endTransaction(txn);
}}); }});
@@ -241,12 +271,22 @@ public class IntroductionManagerImplTest extends BriarTestCase {
final BdfDictionary state = new BdfDictionary(); final BdfDictionary state = new BdfDictionary();
txn = new Transaction(null, false); txn = new Transaction(null, false);
metadataBefore.put(GROUP_KEY_UNREAD_COUNT, 1L);
metadataAfter.put(GROUP_KEY_UNREAD_COUNT, 2L);
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(introduceeManager) oneOf(introduceeManager)
.initialize(txn, introductionGroup1.getId(), msg); .initialize(txn, introductionGroup1.getId(), msg);
will(returnValue(state)); will(returnValue(state));
oneOf(introduceeManager) oneOf(introduceeManager)
.incomingMessage(txn, state, msg); .incomingMessage(txn, state, msg);
// track message
oneOf(clientHelper).getGroupMetadataAsDictionary(txn,
introductionGroup1.getId());
will(returnValue(metadataBefore));
oneOf(clientHelper)
.mergeGroupMetadata(txn, introductionGroup1.getId(),
metadataAfter);
}}); }});
introductionManager introductionManager
@@ -272,10 +312,20 @@ public class IntroductionManagerImplTest extends BriarTestCase {
txn = new Transaction(null, false); txn = new Transaction(null, false);
metadataBefore.put(GROUP_KEY_UNREAD_COUNT, 41L);
metadataAfter.put(GROUP_KEY_UNREAD_COUNT, 42L);
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, sessionId); oneOf(clientHelper).getMessageMetadataAsDictionary(txn, sessionId);
will(returnValue(state)); will(returnValue(state));
oneOf(introducerManager).incomingMessage(txn, state, msg); 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 introductionManager