Move post/message creation into clients

This way the forum and private group client do not need to keep track of
message timestamps themselves and do not need to interact with
post/message factories.
This commit is contained in:
Torsten Grote
2016-10-11 18:28:37 -03:00
parent 6db59ffce5
commit 7bf4aebdaf
12 changed files with 217 additions and 218 deletions

View File

@@ -3,16 +3,14 @@ package org.briarproject;
import net.jodah.concurrentunit.Waiter; import net.jodah.concurrentunit.Waiter;
import org.briarproject.api.Bytes; import org.briarproject.api.Bytes;
import org.briarproject.api.clients.MessageQueueManager;
import org.briarproject.api.clients.ContactGroupFactory; import org.briarproject.api.clients.ContactGroupFactory;
import org.briarproject.api.clients.MessageQueueManager;
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;
import org.briarproject.api.contact.ContactManager; import org.briarproject.api.contact.ContactManager;
import org.briarproject.api.crypto.CryptoComponent; import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.KeyPair; import org.briarproject.api.crypto.KeyPair;
import org.briarproject.api.crypto.KeyParser;
import org.briarproject.api.crypto.PrivateKey;
import org.briarproject.api.crypto.SecretKey; import org.briarproject.api.crypto.SecretKey;
import org.briarproject.api.data.BdfList; import org.briarproject.api.data.BdfList;
import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.db.DatabaseComponent;
@@ -820,12 +818,10 @@ public class ForumSharingIntegrationTest extends BriarTestCase {
// sharer posts into the forum // sharer posts into the forum
long time = clock.currentTimeMillis(); long time = clock.currentTimeMillis();
byte[] body = TestUtils.getRandomBytes(42); String body = TestUtils.getRandomString(42);
KeyParser keyParser = cryptoComponent.getSignatureKeyParser();
PrivateKey key = keyParser.parsePrivateKey(author0.getPrivateKey());
ForumPost p = forumPostFactory ForumPost p = forumPostFactory
.createPseudonymousPost(forum0.getId(), time, null, author0, .createPseudonymousPost(forum0.getId(), time, null, author0,
"text/plain", body, key); body);
forumManager0.addLocalPost(p); forumManager0.addLocalPost(p);
// sync forum post // sync forum post
@@ -841,11 +837,10 @@ public class ForumSharingIntegrationTest extends BriarTestCase {
// now invitee creates a post // now invitee creates a post
time = clock.currentTimeMillis(); time = clock.currentTimeMillis();
body = TestUtils.getRandomBytes(42); body = TestUtils.getRandomString(42);
key = keyParser.parsePrivateKey(author1.getPrivateKey());
p = forumPostFactory p = forumPostFactory
.createPseudonymousPost(forum0.getId(), time, null, author1, .createPseudonymousPost(forum0.getId(), time, null, author1,
"text/plain", body, key); body);
forumManager1.addLocalPost(p); forumManager1.addLocalPost(p);
// sync forum post // sync forum post
@@ -886,11 +881,10 @@ public class ForumSharingIntegrationTest extends BriarTestCase {
// now invitee creates a post // now invitee creates a post
time = clock.currentTimeMillis(); time = clock.currentTimeMillis();
body = TestUtils.getRandomBytes(42); body = TestUtils.getRandomString(42);
key = keyParser.parsePrivateKey(author1.getPrivateKey());
p = forumPostFactory p = forumPostFactory
.createPseudonymousPost(forum0.getId(), time, null, author1, .createPseudonymousPost(forum0.getId(), time, null, author1,
"text/plain", body, key); body);
forumManager1.addLocalPost(p); forumManager1.addLocalPost(p);
// sync forum post // sync forum post

View File

@@ -6,8 +6,8 @@ import org.briarproject.api.crypto.PrivateKey;
import org.briarproject.api.forum.ForumConstants; import org.briarproject.api.forum.ForumConstants;
import org.briarproject.api.forum.ForumPost; import org.briarproject.api.forum.ForumPost;
import org.briarproject.api.forum.ForumPostFactory; import org.briarproject.api.forum.ForumPostFactory;
import org.briarproject.api.identity.Author;
import org.briarproject.api.identity.AuthorFactory; import org.briarproject.api.identity.AuthorFactory;
import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.messaging.MessagingConstants; import org.briarproject.api.messaging.MessagingConstants;
import org.briarproject.api.messaging.PrivateMessage; import org.briarproject.api.messaging.PrivateMessage;
import org.briarproject.api.messaging.PrivateMessageFactory; import org.briarproject.api.messaging.PrivateMessageFactory;
@@ -68,17 +68,17 @@ public class MessageSizeIntegrationTest extends BriarTestCase {
String authorName = TestUtils.getRandomString( String authorName = TestUtils.getRandomString(
MAX_AUTHOR_NAME_LENGTH); MAX_AUTHOR_NAME_LENGTH);
byte[] authorPublic = new byte[MAX_PUBLIC_KEY_LENGTH]; byte[] authorPublic = new byte[MAX_PUBLIC_KEY_LENGTH];
Author author = authorFactory.createAuthor(authorName, authorPublic); PrivateKey privateKey = crypto.generateSignatureKeyPair().getPrivate();
LocalAuthor author = authorFactory
.createLocalAuthor(authorName, authorPublic,
privateKey.getEncoded());
// Create a maximum-length forum post // Create a maximum-length forum post
GroupId groupId = new GroupId(TestUtils.getRandomId()); GroupId groupId = new GroupId(TestUtils.getRandomId());
long timestamp = Long.MAX_VALUE; long timestamp = Long.MAX_VALUE;
MessageId parent = new MessageId(TestUtils.getRandomId()); MessageId parent = new MessageId(TestUtils.getRandomId());
String contentType = TestUtils.getRandomString( String body = TestUtils.getRandomString(MAX_FORUM_POST_BODY_LENGTH);
ForumConstants.MAX_CONTENT_TYPE_LENGTH);
byte[] body = new byte[MAX_FORUM_POST_BODY_LENGTH];
PrivateKey privateKey = crypto.generateSignatureKeyPair().getPrivate();
ForumPost post = forumPostFactory.createPseudonymousPost(groupId, ForumPost post = forumPostFactory.createPseudonymousPost(groupId,
timestamp, parent, author, contentType, body, privateKey); timestamp, parent, author, body);
// Check the size of the serialised message // Check the size of the serialised message
int length = post.getMessage().getRaw().length; int length = post.getMessage().getRaw().length;
assertTrue(length > UniqueId.LENGTH + 8 + UniqueId.LENGTH assertTrue(length > UniqueId.LENGTH + 8 + UniqueId.LENGTH

View File

@@ -19,7 +19,6 @@ import org.briarproject.api.db.DatabaseExecutor;
import org.briarproject.api.event.EventBus; import org.briarproject.api.event.EventBus;
import org.briarproject.api.feed.FeedManager; import org.briarproject.api.feed.FeedManager;
import org.briarproject.api.forum.ForumManager; import org.briarproject.api.forum.ForumManager;
import org.briarproject.api.forum.ForumPostFactory;
import org.briarproject.api.forum.ForumSharingManager; import org.briarproject.api.forum.ForumSharingManager;
import org.briarproject.api.identity.AuthorFactory; import org.briarproject.api.identity.AuthorFactory;
import org.briarproject.api.identity.IdentityManager; import org.briarproject.api.identity.IdentityManager;
@@ -35,7 +34,6 @@ import org.briarproject.api.messaging.MessagingManager;
import org.briarproject.api.messaging.PrivateMessageFactory; import org.briarproject.api.messaging.PrivateMessageFactory;
import org.briarproject.api.plugins.ConnectionRegistry; import org.briarproject.api.plugins.ConnectionRegistry;
import org.briarproject.api.plugins.PluginManager; import org.briarproject.api.plugins.PluginManager;
import org.briarproject.api.privategroup.GroupMessageFactory;
import org.briarproject.api.privategroup.PrivateGroupManager; import org.briarproject.api.privategroup.PrivateGroupManager;
import org.briarproject.api.settings.SettingsManager; import org.briarproject.api.settings.SettingsManager;
import org.briarproject.plugins.AndroidPluginsModule; import org.briarproject.plugins.AndroidPluginsModule;
@@ -97,16 +95,12 @@ public interface AndroidComponent extends CoreEagerSingletons {
PrivateGroupManager privateGroupManager(); PrivateGroupManager privateGroupManager();
GroupMessageFactory groupMessageFactory();
ForumManager forumManager(); ForumManager forumManager();
ForumSharingManager forumSharingManager(); ForumSharingManager forumSharingManager();
BlogSharingManager blogSharingManager(); BlogSharingManager blogSharingManager();
ForumPostFactory forumPostFactory();
BlogManager blogManager(); BlogManager blogManager();
BlogPostFactory blogPostFactory(); BlogPostFactory blogPostFactory();

View File

@@ -3,13 +3,8 @@ package org.briarproject.android.forum;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import org.briarproject.android.api.AndroidNotificationManager; import org.briarproject.android.api.AndroidNotificationManager;
import org.briarproject.android.controller.handler.ResultExceptionHandler;
import org.briarproject.android.threaded.ThreadListControllerImpl; import org.briarproject.android.threaded.ThreadListControllerImpl;
import org.briarproject.api.FormatException;
import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.CryptoExecutor; import org.briarproject.api.crypto.CryptoExecutor;
import org.briarproject.api.crypto.KeyParser;
import org.briarproject.api.crypto.PrivateKey;
import org.briarproject.api.db.DatabaseExecutor; import org.briarproject.api.db.DatabaseExecutor;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
import org.briarproject.api.event.Event; import org.briarproject.api.event.Event;
@@ -18,47 +13,36 @@ import org.briarproject.api.event.ForumPostReceivedEvent;
import org.briarproject.api.forum.Forum; import org.briarproject.api.forum.Forum;
import org.briarproject.api.forum.ForumManager; import org.briarproject.api.forum.ForumManager;
import org.briarproject.api.forum.ForumPost; import org.briarproject.api.forum.ForumPost;
import org.briarproject.api.forum.ForumPostFactory;
import org.briarproject.api.forum.ForumPostHeader; import org.briarproject.api.forum.ForumPostHeader;
import org.briarproject.api.identity.IdentityManager;
import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.lifecycle.LifecycleManager; import org.briarproject.api.lifecycle.LifecycleManager;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageId;
import org.briarproject.util.StringUtils; import org.briarproject.util.StringUtils;
import java.security.GeneralSecurityException;
import java.util.Collection; import java.util.Collection;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.inject.Inject; import javax.inject.Inject;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static org.briarproject.api.identity.Author.Status.OURSELVES;
public class ForumControllerImpl public class ForumControllerImpl
extends ThreadListControllerImpl<Forum, ForumEntry, ForumPostHeader> extends ThreadListControllerImpl<Forum, ForumEntry, ForumPostHeader, ForumPost>
implements ForumController { implements ForumController {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(ForumControllerImpl.class.getName()); Logger.getLogger(ForumControllerImpl.class.getName());
private final ForumPostFactory forumPostFactory;
private final ForumManager forumManager; private final ForumManager forumManager;
@Inject @Inject
ForumControllerImpl(@DatabaseExecutor Executor dbExecutor, ForumControllerImpl(@DatabaseExecutor Executor dbExecutor,
LifecycleManager lifecycleManager, LifecycleManager lifecycleManager,
@CryptoExecutor Executor cryptoExecutor, @CryptoExecutor Executor cryptoExecutor,
ForumPostFactory forumPostFactory, CryptoComponent crypto,
ForumManager forumManager, EventBus eventBus, ForumManager forumManager, EventBus eventBus,
IdentityManager identityManager,
AndroidNotificationManager notificationManager) { AndroidNotificationManager notificationManager) {
super(dbExecutor, lifecycleManager, cryptoExecutor, crypto, eventBus, super(dbExecutor, lifecycleManager, cryptoExecutor, eventBus,
identityManager, notificationManager); notificationManager);
this.forumManager = forumManager; this.forumManager = forumManager;
this.forumPostFactory = forumPostFactory;
} }
@Override @Override
@@ -76,7 +60,6 @@ public class ForumControllerImpl
if (pe.getGroupId().equals(groupId)) { if (pe.getGroupId().equals(groupId)) {
LOG.info("Forum post received, adding..."); LOG.info("Forum post received, adding...");
final ForumPostHeader fph = pe.getForumPostHeader(); final ForumPostHeader fph = pe.getForumPostHeader();
updateNewestTimestamp(fph.getTimestamp());
listener.runOnUiThreadUnlessDestroyed(new Runnable() { listener.runOnUiThreadUnlessDestroyed(new Runnable() {
@Override @Override
public void run() { public void run() {
@@ -115,65 +98,15 @@ public class ForumControllerImpl
} }
@Override @Override
public void send(final String body, @Nullable final MessageId parentId, protected ForumPost createLocalMessage(GroupId g, String body,
final ResultExceptionHandler<ForumEntry, DbException> handler) { @Nullable MessageId parentId) throws DbException {
cryptoExecutor.execute(new Runnable() { return forumManager.createLocalPost(groupId, body, parentId);
@Override
public void run() {
LOG.info("Create post...");
long timestamp = System.currentTimeMillis();
timestamp = Math.max(timestamp, newestTimeStamp.get());
ForumPost p;
try {
LocalAuthor a = identityManager.getLocalAuthor();
KeyParser keyParser = crypto.getSignatureKeyParser();
byte[] k = a.getPrivateKey();
PrivateKey authorKey = keyParser.parsePrivateKey(k);
byte[] b = StringUtils.toUtf8(body);
p = forumPostFactory
.createPseudonymousPost(groupId, timestamp,
parentId, a, "text/plain", b, authorKey);
} catch (GeneralSecurityException | FormatException e) {
throw new RuntimeException(e);
} catch (DbException e) {
if (LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
handler.onException(e);
return;
}
bodyCache.put(p.getMessage().getId(), body);
storePost(p, handler);
}
});
} }
private void storePost(final ForumPost p, @Override
final ResultExceptionHandler<ForumEntry, DbException> resultHandler) { protected ForumPostHeader addLocalMessage(ForumPost p)
runOnDbThread(new Runnable() { throws DbException {
@Override return forumManager.addLocalPost(p);
public void run() {
try {
LOG.info("Store post...");
long now = System.currentTimeMillis();
forumManager.addLocalPost(p);
long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
LOG.info("Storing message took " + duration + " ms");
ForumPostHeader h =
new ForumPostHeader(p.getMessage().getId(),
p.getParent(),
p.getMessage().getTimestamp(),
p.getAuthor(), OURSELVES, true);
resultHandler.onResult(buildItem(h));
} catch (DbException e) {
if (LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
resultHandler.onException(e);
}
}
});
} }
@Override @Override

View File

@@ -2,45 +2,46 @@ package org.briarproject.android.privategroup.conversation;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import org.briarproject.android.controller.handler.ResultExceptionHandler; import org.briarproject.android.api.AndroidNotificationManager;
import org.briarproject.android.threaded.ThreadListControllerImpl; import org.briarproject.android.threaded.ThreadListControllerImpl;
import org.briarproject.api.FormatException; import org.briarproject.api.crypto.CryptoExecutor;
import org.briarproject.api.db.DatabaseExecutor;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
import org.briarproject.api.event.Event; import org.briarproject.api.event.Event;
import org.briarproject.api.event.EventBus;
import org.briarproject.api.event.GroupMessageAddedEvent; import org.briarproject.api.event.GroupMessageAddedEvent;
import org.briarproject.api.identity.LocalAuthor; import org.briarproject.api.lifecycle.LifecycleManager;
import org.briarproject.api.privategroup.GroupMessage; import org.briarproject.api.privategroup.GroupMessage;
import org.briarproject.api.privategroup.GroupMessageFactory;
import org.briarproject.api.privategroup.GroupMessageHeader; import org.briarproject.api.privategroup.GroupMessageHeader;
import org.briarproject.api.privategroup.PrivateGroup; import org.briarproject.api.privategroup.PrivateGroup;
import org.briarproject.api.privategroup.PrivateGroupManager; import org.briarproject.api.privategroup.PrivateGroupManager;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageId;
import java.security.GeneralSecurityException;
import java.util.Collection; import java.util.Collection;
import java.util.concurrent.Executor;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.inject.Inject; import javax.inject.Inject;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static org.briarproject.api.identity.Author.Status.OURSELVES;
public class GroupControllerImpl public class GroupControllerImpl
extends ThreadListControllerImpl<PrivateGroup, GroupMessageItem, GroupMessageHeader> extends ThreadListControllerImpl<PrivateGroup, GroupMessageItem, GroupMessageHeader, GroupMessage>
implements GroupController { implements GroupController {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(GroupControllerImpl.class.getName()); Logger.getLogger(GroupControllerImpl.class.getName());
@Inject private final PrivateGroupManager privateGroupManager;
volatile GroupMessageFactory groupMessageFactory;
@Inject
volatile PrivateGroupManager privateGroupManager;
@Inject @Inject
GroupControllerImpl() { GroupControllerImpl(@DatabaseExecutor Executor dbExecutor,
super(); LifecycleManager lifecycleManager,
@CryptoExecutor Executor cryptoExecutor,
PrivateGroupManager privateGroupManager, EventBus eventBus,
AndroidNotificationManager notificationManager) {
super(dbExecutor, lifecycleManager, cryptoExecutor, eventBus,
notificationManager);
this.privateGroupManager = privateGroupManager;
} }
@Override @Override
@@ -58,7 +59,6 @@ public class GroupControllerImpl
if (!pe.isLocal() && pe.getGroupId().equals(groupId)) { if (!pe.isLocal() && pe.getGroupId().equals(groupId)) {
LOG.info("Group message received, adding..."); LOG.info("Group message received, adding...");
final GroupMessageHeader fph = pe.getHeader(); final GroupMessageHeader fph = pe.getHeader();
updateNewestTimestamp(fph.getTimestamp());
listener.runOnUiThreadUnlessDestroyed(new Runnable() { listener.runOnUiThreadUnlessDestroyed(new Runnable() {
@Override @Override
public void run() { public void run() {
@@ -97,59 +97,15 @@ public class GroupControllerImpl
} }
@Override @Override
public void send(final String body, @Nullable final MessageId parentId, protected GroupMessage createLocalMessage(GroupId g, String body,
final ResultExceptionHandler<GroupMessageItem, DbException> handler) { @Nullable MessageId parentId) throws DbException {
cryptoExecutor.execute(new Runnable() { return privateGroupManager.createLocalMessage(groupId, body, parentId);
@Override
public void run() {
LOG.info("Create message...");
long timestamp = System.currentTimeMillis();
timestamp = Math.max(timestamp, newestTimeStamp.get());
GroupMessage gm;
try {
LocalAuthor a = identityManager.getLocalAuthor();
gm = groupMessageFactory.createGroupMessage(groupId,
timestamp, parentId, a, body);
} catch (GeneralSecurityException | FormatException e) {
throw new RuntimeException(e);
} catch (DbException e) {
if (LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
handler.onException(e);
return;
}
bodyCache.put(gm.getMessage().getId(), body);
storeMessage(gm, handler);
}
});
} }
private void storeMessage(final GroupMessage gm, @Override
final ResultExceptionHandler<GroupMessageItem, DbException> handler) { protected GroupMessageHeader addLocalMessage(GroupMessage message)
runOnDbThread(new Runnable() { throws DbException {
@Override return privateGroupManager.addLocalMessage(message);
public void run() {
try {
LOG.info("Store message...");
long now = System.currentTimeMillis();
privateGroupManager.addLocalMessage(gm);
long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
LOG.info("Storing message took " + duration + " ms");
GroupMessageHeader h = new GroupMessageHeader(groupId,
gm.getMessage().getId(), gm.getParent(),
gm.getMessage().getTimestamp(), gm.getAuthor(),
OURSELVES, true);
handler.onResult(buildItem(h));
} catch (DbException e) {
if (LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
handler.onException(e);
}
}
});
} }
@Override @Override

View File

@@ -2,13 +2,14 @@ package org.briarproject.android.threaded;
import android.app.Activity; import android.app.Activity;
import android.support.annotation.CallSuper; import android.support.annotation.CallSuper;
import android.support.annotation.Nullable;
import org.briarproject.android.api.AndroidNotificationManager; import org.briarproject.android.api.AndroidNotificationManager;
import org.briarproject.android.controller.DbControllerImpl; import org.briarproject.android.controller.DbControllerImpl;
import org.briarproject.android.controller.handler.ResultExceptionHandler; import org.briarproject.android.controller.handler.ResultExceptionHandler;
import org.briarproject.api.clients.BaseGroup; import org.briarproject.api.clients.BaseGroup;
import org.briarproject.api.clients.BaseMessage;
import org.briarproject.api.clients.PostHeader; import org.briarproject.api.clients.PostHeader;
import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.CryptoExecutor; import org.briarproject.api.crypto.CryptoExecutor;
import org.briarproject.api.db.DatabaseExecutor; import org.briarproject.api.db.DatabaseExecutor;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
@@ -16,9 +17,6 @@ import org.briarproject.api.event.Event;
import org.briarproject.api.event.EventBus; import org.briarproject.api.event.EventBus;
import org.briarproject.api.event.EventListener; import org.briarproject.api.event.EventListener;
import org.briarproject.api.event.GroupRemovedEvent; import org.briarproject.api.event.GroupRemovedEvent;
import org.briarproject.api.forum.ForumManager;
import org.briarproject.api.forum.ForumPostFactory;
import org.briarproject.api.identity.IdentityManager;
import org.briarproject.api.lifecycle.LifecycleManager; import org.briarproject.api.lifecycle.LifecycleManager;
import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageId;
@@ -30,13 +28,12 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Logger; import java.util.logging.Logger;
import static java.util.logging.Level.INFO; import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
public abstract class ThreadListControllerImpl<G extends BaseGroup, I extends ThreadItem, H extends PostHeader> public abstract class ThreadListControllerImpl<G extends BaseGroup, I extends ThreadItem, H extends PostHeader, M extends BaseMessage>
extends DbControllerImpl extends DbControllerImpl
implements ThreadListController<G, I, H>, EventListener { implements ThreadListController<G, I, H>, EventListener {
@@ -44,14 +41,11 @@ public abstract class ThreadListControllerImpl<G extends BaseGroup, I extends Th
Logger.getLogger(ThreadListControllerImpl.class.getName()); Logger.getLogger(ThreadListControllerImpl.class.getName());
protected final Executor cryptoExecutor; protected final Executor cryptoExecutor;
protected final CryptoComponent crypto;
protected final EventBus eventBus;
protected final IdentityManager identityManager;
protected final AndroidNotificationManager notificationManager; protected final AndroidNotificationManager notificationManager;
private final EventBus eventBus;
protected final Map<MessageId, String> bodyCache = protected final Map<MessageId, String> bodyCache =
new ConcurrentHashMap<>(); new ConcurrentHashMap<>();
protected final AtomicLong newestTimeStamp = new AtomicLong();
protected volatile GroupId groupId; protected volatile GroupId groupId;
@@ -59,14 +53,11 @@ public abstract class ThreadListControllerImpl<G extends BaseGroup, I extends Th
protected ThreadListControllerImpl(@DatabaseExecutor Executor dbExecutor, protected ThreadListControllerImpl(@DatabaseExecutor Executor dbExecutor,
LifecycleManager lifecycleManager, LifecycleManager lifecycleManager,
@CryptoExecutor Executor cryptoExecutor, CryptoComponent crypto, @CryptoExecutor Executor cryptoExecutor, EventBus eventBus,
EventBus eventBus, IdentityManager identityManager,
AndroidNotificationManager notificationManager) { AndroidNotificationManager notificationManager) {
super(dbExecutor, lifecycleManager); super(dbExecutor, lifecycleManager);
this.cryptoExecutor = cryptoExecutor; this.cryptoExecutor = cryptoExecutor;
this.crypto = crypto;
this.eventBus = eventBus; this.eventBus = eventBus;
this.identityManager = identityManager;
this.notificationManager = notificationManager; this.notificationManager = notificationManager;
} }
@@ -164,9 +155,6 @@ public abstract class ThreadListControllerImpl<G extends BaseGroup, I extends Th
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Loading headers took " + duration + " ms"); LOG.info("Loading headers took " + duration + " ms");
// Update timestamp of newest item
updateNewestTimeStamp(headers);
// Load bodies // Load bodies
now = System.currentTimeMillis(); now = System.currentTimeMillis();
loadBodies(headers); loadBodies(headers);
@@ -259,6 +247,63 @@ public abstract class ThreadListControllerImpl<G extends BaseGroup, I extends Th
send(body, null, resultHandler); send(body, null, resultHandler);
} }
@Override
public void send(final String body, @Nullable final MessageId parentId,
final ResultExceptionHandler<I, DbException> handler) {
cryptoExecutor.execute(new Runnable() {
@Override
public void run() {
LOG.info("Creating message...");
try {
M msg = createLocalMessage(groupId, body, parentId);
bodyCache.put(msg.getMessage().getId(), body);
storePost(msg, handler);
} catch (DbException e) {
if (LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
handler.onException(e);
}
}
});
}
/**
* This should only be run from the DbThread.
*
* @throws DbException
*/
protected abstract M createLocalMessage(GroupId g, String body,
@Nullable MessageId parentId) throws DbException;
private void storePost(final M p,
final ResultExceptionHandler<I, DbException> resultHandler) {
runOnDbThread(new Runnable() {
@Override
public void run() {
try {
LOG.info("Store message...");
long now = System.currentTimeMillis();
H h = addLocalMessage(p);
long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
LOG.info("Storing message took " + duration + " ms");
resultHandler.onResult(buildItem(h));
} catch (DbException e) {
if (LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
resultHandler.onException(e);
}
}
});
}
/**
* This should only be run from the DbThread.
*
* @throws DbException
*/
protected abstract H addLocalMessage(M message) throws DbException;
@Override @Override
public void deleteGroupItem( public void deleteGroupItem(
final ResultExceptionHandler<Void, DbException> handler) { final ResultExceptionHandler<Void, DbException> handler) {
@@ -303,20 +348,6 @@ public abstract class ThreadListControllerImpl<G extends BaseGroup, I extends Th
*/ */
protected abstract I buildItem(H header); protected abstract I buildItem(H header);
private void updateNewestTimeStamp(Collection<H> headers) {
for (H h : headers) {
updateNewestTimestamp(h.getTimestamp());
}
}
protected void updateNewestTimestamp(long update) {
long newest = newestTimeStamp.get();
while (newest < update) {
if (newestTimeStamp.compareAndSet(newest, update)) return;
newest = newestTimeStamp.get();
}
}
private void checkGroupId() { private void checkGroupId() {
if (groupId == null) { if (groupId == null) {
throw new IllegalStateException( throw new IllegalStateException(

View File

@@ -6,6 +6,7 @@ import org.briarproject.api.db.Transaction;
import org.briarproject.api.sync.ClientId; import org.briarproject.api.sync.ClientId;
import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageId;
import org.jetbrains.annotations.Nullable;
import java.util.Collection; import java.util.Collection;
@@ -20,8 +21,12 @@ public interface ForumManager extends MessageTracker {
/** Unsubscribes from a forum. */ /** Unsubscribes from a forum. */
void removeForum(Forum f) throws DbException; void removeForum(Forum f) throws DbException;
/** Creates a local forum post. */
ForumPost createLocalPost(GroupId groupId, String text,
@Nullable MessageId parentId) throws DbException;
/** Stores a local forum post. */ /** Stores a local forum post. */
void addLocalPost(ForumPost p) throws DbException; ForumPostHeader addLocalPost(ForumPost p) throws DbException;
/** Returns the forum with the given ID. */ /** Returns the forum with the given ID. */
Forum getForum(GroupId g) throws DbException; Forum getForum(GroupId g) throws DbException;

View File

@@ -1,8 +1,7 @@
package org.briarproject.api.forum; package org.briarproject.api.forum;
import org.briarproject.api.FormatException; import org.briarproject.api.FormatException;
import org.briarproject.api.crypto.PrivateKey; import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.identity.Author;
import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageId;
@@ -15,7 +14,6 @@ public interface ForumPostFactory {
throws FormatException; throws FormatException;
ForumPost createPseudonymousPost(GroupId groupId, long timestamp, ForumPost createPseudonymousPost(GroupId groupId, long timestamp,
MessageId parent, Author author, String contentType, byte[] body, MessageId parent, LocalAuthor author, String body)
PrivateKey privateKey) throws FormatException, throws FormatException, GeneralSecurityException;
GeneralSecurityException;
} }

View File

@@ -7,6 +7,7 @@ import org.briarproject.api.sync.ClientId;
import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageId;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection; import java.util.Collection;
@@ -19,8 +20,12 @@ public interface PrivateGroupManager extends MessageTracker {
/** Removes a dissolved private group. */ /** Removes a dissolved private group. */
void removePrivateGroup(GroupId g) throws DbException; void removePrivateGroup(GroupId g) throws DbException;
/** Creates a local group message. */
GroupMessage createLocalMessage(GroupId groupId, String text,
@Nullable MessageId parentId) throws DbException;
/** Stores (and sends) a local group message. */ /** Stores (and sends) a local group message. */
void addLocalMessage(GroupMessage p) throws DbException; GroupMessageHeader addLocalMessage(GroupMessage p) throws DbException;
/** Returns the private group with the given ID. */ /** Returns the private group with the given ID. */
@NotNull @NotNull

View File

@@ -13,19 +13,24 @@ import org.briarproject.api.forum.Forum;
import org.briarproject.api.forum.ForumFactory; import org.briarproject.api.forum.ForumFactory;
import org.briarproject.api.forum.ForumManager; import org.briarproject.api.forum.ForumManager;
import org.briarproject.api.forum.ForumPost; import org.briarproject.api.forum.ForumPost;
import org.briarproject.api.forum.ForumPostFactory;
import org.briarproject.api.forum.ForumPostHeader; import org.briarproject.api.forum.ForumPostHeader;
import org.briarproject.api.identity.Author; import org.briarproject.api.identity.Author;
import org.briarproject.api.identity.Author.Status; import org.briarproject.api.identity.Author.Status;
import org.briarproject.api.identity.AuthorId; import org.briarproject.api.identity.AuthorId;
import org.briarproject.api.identity.IdentityManager; import org.briarproject.api.identity.IdentityManager;
import org.briarproject.api.identity.LocalAuthor;
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.system.Clock;
import org.briarproject.clients.BdfIncomingMessageHook; import org.briarproject.clients.BdfIncomingMessageHook;
import org.briarproject.util.StringUtils; import org.briarproject.util.StringUtils;
import org.jetbrains.annotations.Nullable;
import java.security.GeneralSecurityException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@@ -47,6 +52,7 @@ 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_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.api.identity.Author.Status.OURSELVES;
import static org.briarproject.clients.BdfConstants.MSG_KEY_READ; import static org.briarproject.clients.BdfConstants.MSG_KEY_READ;
class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager { class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
@@ -57,16 +63,21 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
private final IdentityManager identityManager; private final IdentityManager identityManager;
private final ForumFactory forumFactory; private final ForumFactory forumFactory;
private final ForumPostFactory forumPostFactory;
private final Clock clock;
private final List<RemoveForumHook> removeHooks; private final List<RemoveForumHook> removeHooks;
@Inject @Inject
ForumManagerImpl(DatabaseComponent db, IdentityManager identityManager, ForumManagerImpl(DatabaseComponent db, IdentityManager identityManager,
ClientHelper clientHelper, MetadataParser metadataParser, ClientHelper clientHelper, MetadataParser metadataParser,
ForumFactory forumFactory) { ForumFactory forumFactory, ForumPostFactory forumPostFactory,
Clock clock) {
super(db, clientHelper, metadataParser); super(db, clientHelper, metadataParser);
this.identityManager = identityManager; this.identityManager = identityManager;
this.forumFactory = forumFactory; this.forumFactory = forumFactory;
this.forumPostFactory = forumPostFactory;
this.clock = clock;
removeHooks = new CopyOnWriteArrayList<RemoveForumHook>(); removeHooks = new CopyOnWriteArrayList<RemoveForumHook>();
} }
@@ -118,7 +129,38 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
} }
@Override @Override
public void addLocalPost(ForumPost p) throws DbException { public ForumPost createLocalPost(final GroupId groupId,
final String body, final @Nullable MessageId parentId)
throws DbException {
LocalAuthor author;
GroupCount count;
Transaction txn = db.startTransaction(true);
try {
author = identityManager.getLocalAuthor(txn);
count = getGroupCount(txn, groupId);
txn.setComplete();
} finally {
db.endTransaction(txn);
}
long timestamp = clock.currentTimeMillis();
timestamp = Math.max(timestamp, count.getLatestMsgTime());
ForumPost p;
try {
p = forumPostFactory
.createPseudonymousPost(groupId, timestamp, parentId,
author, body);
} catch (GeneralSecurityException e) {
throw new RuntimeException(e);
} catch (FormatException e) {
throw new DbException(e);
}
return p;
}
@Override
public ForumPostHeader addLocalPost(ForumPost p) throws DbException {
Transaction txn = db.startTransaction(false); Transaction txn = db.startTransaction(false);
try { try {
BdfDictionary meta = new BdfDictionary(); BdfDictionary meta = new BdfDictionary();
@@ -142,6 +184,8 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
} finally { } finally {
db.endTransaction(txn); db.endTransaction(txn);
} }
return new ForumPostHeader(p.getMessage().getId(), p.getParent(),
p.getMessage().getTimestamp(), p.getAuthor(), OURSELVES, true);
} }
@Override @Override

View File

@@ -3,12 +3,13 @@ package org.briarproject.forum;
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.crypto.CryptoComponent; import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.KeyParser;
import org.briarproject.api.crypto.PrivateKey; import org.briarproject.api.crypto.PrivateKey;
import org.briarproject.api.crypto.Signature; import org.briarproject.api.crypto.Signature;
import org.briarproject.api.data.BdfList; import org.briarproject.api.data.BdfList;
import org.briarproject.api.forum.ForumPost; import org.briarproject.api.forum.ForumPost;
import org.briarproject.api.forum.ForumPostFactory; import org.briarproject.api.forum.ForumPostFactory;
import org.briarproject.api.identity.Author; import org.briarproject.api.identity.LocalAuthor;
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;
@@ -49,9 +50,10 @@ class ForumPostFactoryImpl implements ForumPostFactory {
@Override @Override
public ForumPost createPseudonymousPost(GroupId groupId, long timestamp, public ForumPost createPseudonymousPost(GroupId groupId, long timestamp,
MessageId parent, Author author, String contentType, byte[] body, MessageId parent, LocalAuthor author, String bodyStr)
PrivateKey privateKey) throws FormatException, throws FormatException, GeneralSecurityException {
GeneralSecurityException { String contentType = "text/plain";
byte[] body = StringUtils.toUtf8(bodyStr);
// Validate the arguments // Validate the arguments
if (StringUtils.toUtf8(contentType).length > MAX_CONTENT_TYPE_LENGTH) if (StringUtils.toUtf8(contentType).length > MAX_CONTENT_TYPE_LENGTH)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
@@ -62,6 +64,10 @@ class ForumPostFactoryImpl implements ForumPostFactory {
author.getPublicKey()); author.getPublicKey());
BdfList signed = BdfList.of(groupId, timestamp, parent, authorList, BdfList signed = BdfList.of(groupId, timestamp, parent, authorList,
contentType, body); contentType, body);
// Get private key
KeyParser keyParser = crypto.getSignatureKeyParser();
byte[] k = author.getPrivateKey();
PrivateKey privateKey = keyParser.parsePrivateKey(k);
// Generate the signature // Generate the signature
Signature signature = crypto.getSignature(); Signature signature = crypto.getSignature();
signature.initSign(privateKey); signature.initSign(privateKey);

View File

@@ -9,7 +9,9 @@ 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.IdentityManager; import org.briarproject.api.identity.IdentityManager;
import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.privategroup.GroupMessage; import org.briarproject.api.privategroup.GroupMessage;
import org.briarproject.api.privategroup.GroupMessageFactory;
import org.briarproject.api.privategroup.GroupMessageHeader; import org.briarproject.api.privategroup.GroupMessageHeader;
import org.briarproject.api.privategroup.PrivateGroup; import org.briarproject.api.privategroup.PrivateGroup;
import org.briarproject.api.privategroup.PrivateGroupFactory; import org.briarproject.api.privategroup.PrivateGroupFactory;
@@ -19,16 +21,21 @@ 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.system.Clock;
import org.briarproject.clients.BdfIncomingMessageHook; import org.briarproject.clients.BdfIncomingMessageHook;
import org.briarproject.util.StringUtils; import org.briarproject.util.StringUtils;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.security.GeneralSecurityException;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.inject.Inject; import javax.inject.Inject;
import static org.briarproject.api.identity.Author.Status.OURSELVES;
public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
PrivateGroupManager { PrivateGroupManager {
@@ -40,16 +47,21 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
private final IdentityManager identityManager; private final IdentityManager identityManager;
private final PrivateGroupFactory privateGroupFactory; private final PrivateGroupFactory privateGroupFactory;
private final GroupMessageFactory groupMessageFactory;
private final Clock clock;
@Inject @Inject
PrivateGroupManagerImpl(ClientHelper clientHelper, PrivateGroupManagerImpl(ClientHelper clientHelper,
MetadataParser metadataParser, DatabaseComponent db, MetadataParser metadataParser, DatabaseComponent db,
IdentityManager identityManager, IdentityManager identityManager,
PrivateGroupFactory privateGroupFactory) { PrivateGroupFactory privateGroupFactory,
GroupMessageFactory groupMessageFactory, Clock clock) {
super(db, clientHelper, metadataParser); super(db, clientHelper, metadataParser);
this.identityManager = identityManager; this.identityManager = identityManager;
this.privateGroupFactory = privateGroupFactory; this.privateGroupFactory = privateGroupFactory;
this.groupMessageFactory = groupMessageFactory;
this.clock = clock;
} }
@NotNull @NotNull
@@ -64,7 +76,25 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
} }
@Override @Override
public void addLocalMessage(GroupMessage m) throws DbException { public GroupMessage createLocalMessage(GroupId groupId, String body,
@Nullable MessageId parentId) throws DbException {
long timestamp = clock.currentTimeMillis();
LocalAuthor author = identityManager.getLocalAuthor();
try {
return groupMessageFactory
.createGroupMessage(groupId, timestamp, parentId, author,
body);
} catch (FormatException e) {
throw new DbException(e);
} catch (GeneralSecurityException e) {
throw new RuntimeException(e);
}
}
@Override
public GroupMessageHeader addLocalMessage(GroupMessage m)
throws DbException {
Transaction txn = db.startTransaction(false); Transaction txn = db.startTransaction(false);
try { try {
BdfDictionary meta = new BdfDictionary(); BdfDictionary meta = new BdfDictionary();
@@ -76,6 +106,9 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
} finally { } finally {
db.endTransaction(txn); db.endTransaction(txn);
} }
return new GroupMessageHeader(m.getMessage().getGroupId(),
m.getMessage().getId(), m.getParent(),
m.getMessage().getTimestamp(), m.getAuthor(), OURSELVES, true);
} }
@NotNull @NotNull