Use ClientHelper in ForumSharingManagerImpl.

This commit is contained in:
akwizgran
2016-02-29 15:43:40 +00:00
parent 2ccd1dee33
commit 9d5924fc24

View File

@@ -3,18 +3,14 @@ package org.briarproject.forum;
import com.google.inject.Inject; import com.google.inject.Inject;
import org.briarproject.api.FormatException; import org.briarproject.api.FormatException;
import org.briarproject.api.clients.ClientHelper;
import org.briarproject.api.clients.PrivateGroupFactory; import org.briarproject.api.clients.PrivateGroupFactory;
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.AddContactHook; import org.briarproject.api.contact.ContactManager.AddContactHook;
import org.briarproject.api.contact.ContactManager.RemoveContactHook; import org.briarproject.api.contact.ContactManager.RemoveContactHook;
import org.briarproject.api.data.BdfDictionary; import org.briarproject.api.data.BdfDictionary;
import org.briarproject.api.data.BdfReader; import org.briarproject.api.data.BdfList;
import org.briarproject.api.data.BdfReaderFactory;
import org.briarproject.api.data.BdfWriter;
import org.briarproject.api.data.BdfWriterFactory;
import org.briarproject.api.data.MetadataEncoder;
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.Metadata; import org.briarproject.api.db.Metadata;
@@ -27,14 +23,11 @@ import org.briarproject.api.sync.Group;
import org.briarproject.api.sync.GroupFactory; import org.briarproject.api.sync.GroupFactory;
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.MessageFactory;
import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageId;
import org.briarproject.api.sync.ValidationManager.ValidationHook; import org.briarproject.api.sync.ValidationManager.ValidationHook;
import org.briarproject.api.system.Clock; import org.briarproject.api.system.Clock;
import org.briarproject.util.StringUtils; import org.briarproject.util.StringUtils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.ArrayList; import java.util.ArrayList;
@@ -61,33 +54,23 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook,
private final DatabaseComponent db; private final DatabaseComponent db;
private final ForumManager forumManager; private final ForumManager forumManager;
private final ClientHelper clientHelper;
private final GroupFactory groupFactory; private final GroupFactory groupFactory;
private final PrivateGroupFactory privateGroupFactory; private final PrivateGroupFactory privateGroupFactory;
private final MessageFactory messageFactory;
private final BdfReaderFactory bdfReaderFactory;
private final BdfWriterFactory bdfWriterFactory;
private final MetadataEncoder metadataEncoder;
private final MetadataParser metadataParser;
private final SecureRandom random; private final SecureRandom random;
private final Clock clock; private final Clock clock;
private final Group localGroup; private final Group localGroup;
@Inject @Inject
ForumSharingManagerImpl(DatabaseComponent db, ForumSharingManagerImpl(DatabaseComponent db, ForumManager forumManager,
ForumManager forumManager, GroupFactory groupFactory, ClientHelper clientHelper, GroupFactory groupFactory,
PrivateGroupFactory privateGroupFactory, PrivateGroupFactory privateGroupFactory, SecureRandom random,
MessageFactory messageFactory, BdfReaderFactory bdfReaderFactory, Clock clock) {
BdfWriterFactory bdfWriterFactory, MetadataEncoder metadataEncoder,
MetadataParser metadataParser, SecureRandom random, Clock clock) {
this.db = db; this.db = db;
this.forumManager = forumManager; this.forumManager = forumManager;
this.clientHelper = clientHelper;
this.groupFactory = groupFactory; this.groupFactory = groupFactory;
this.privateGroupFactory = privateGroupFactory; this.privateGroupFactory = privateGroupFactory;
this.messageFactory = messageFactory;
this.bdfReaderFactory = bdfReaderFactory;
this.bdfWriterFactory = bdfWriterFactory;
this.metadataEncoder = metadataEncoder;
this.metadataParser = metadataParser;
this.random = random; this.random = random;
this.clock = clock; this.clock = clock;
localGroup = groupFactory.createGroup(CLIENT_ID, localGroup = groupFactory.createGroup(CLIENT_ID,
@@ -103,9 +86,9 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook,
db.addGroup(txn, g); db.addGroup(txn, g);
db.setVisibleToContact(txn, c.getId(), g.getId(), true); db.setVisibleToContact(txn, c.getId(), g.getId(), true);
// Attach the contact ID to the group // Attach the contact ID to the group
BdfDictionary d = new BdfDictionary(); BdfDictionary meta = new BdfDictionary();
d.put("contactId", c.getId().getInt()); meta.put("contactId", c.getId().getInt());
db.mergeGroupMetadata(txn, g.getId(), metadataEncoder.encode(d)); clientHelper.mergeGroupMetadata(txn, g.getId(), meta);
// Share any forums that are shared with all contacts // Share any forums that are shared with all contacts
List<Forum> shared = getForumsSharedWithAllContacts(txn); List<Forum> shared = getForumsSharedWithAllContacts(txn);
storeMessage(txn, g.getId(), shared, 0); storeMessage(txn, g.getId(), shared, 0);
@@ -193,8 +176,9 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook,
LatestUpdate latest = findLatest(txn, g.getId(), false); LatestUpdate latest = findLatest(txn, g.getId(), false);
if (latest != null) { if (latest != null) {
// Retrieve and parse the latest update // Retrieve and parse the latest update
byte[] raw = db.getRawMessage(txn, latest.messageId); BdfList message = clientHelper.getMessageAsList(txn,
for (Forum f : parseForumList(raw)) { latest.messageId);
for (Forum f : parseForumList(message)) {
if (!subscribed.contains(f.getGroup())) if (!subscribed.contains(f.getGroup()))
available.add(f); available.add(f);
} }
@@ -321,94 +305,64 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook,
LatestUpdate latest = findLatest(txn, localGroup.getId(), true); LatestUpdate latest = findLatest(txn, localGroup.getId(), true);
if (latest == null) return Collections.emptyList(); if (latest == null) return Collections.emptyList();
// Retrieve and parse the latest update // Retrieve and parse the latest update
return parseForumList(db.getRawMessage(txn, latest.messageId)); BdfList message = clientHelper.getMessageAsList(txn, latest.messageId);
return parseForumList(message);
} }
private LatestUpdate findLatest(Transaction txn, GroupId g, boolean local) private LatestUpdate findLatest(Transaction txn, GroupId g, boolean local)
throws DbException, FormatException { throws DbException, FormatException {
LatestUpdate latest = null; LatestUpdate latest = null;
Map<MessageId, Metadata> metadata = db.getMessageMetadata(txn, g); Map<MessageId, BdfDictionary> metadata =
for (Entry<MessageId, Metadata> e : metadata.entrySet()) { clientHelper.getMessageMetadataAsDictionary(txn, g);
BdfDictionary d = metadataParser.parse(e.getValue()); for (Entry<MessageId, BdfDictionary> e : metadata.entrySet()) {
if (d.getBoolean("local") != local) continue; BdfDictionary meta = e.getValue();
long version = d.getLong("version"); if (meta.getBoolean("local") != local) continue;
long version = meta.getLong("version");
if (latest == null || version > latest.version) if (latest == null || version > latest.version)
latest = new LatestUpdate(e.getKey(), version); latest = new LatestUpdate(e.getKey(), version);
} }
return latest; return latest;
} }
private List<Forum> parseForumList(byte[] raw) throws FormatException { private List<Forum> parseForumList(BdfList message) throws FormatException {
List<Forum> forums = new ArrayList<Forum>(); // Version, forum list
ByteArrayInputStream in = new ByteArrayInputStream(raw, BdfList forumList = message.getList(1);
MESSAGE_HEADER_LENGTH, raw.length - MESSAGE_HEADER_LENGTH); List<Forum> forums = new ArrayList<Forum>(forumList.size());
BdfReader r = bdfReaderFactory.createReader(in); for (int i = 0; i < forumList.size(); i++) {
try { // Name, salt
r.readListStart(); BdfList forum = forumList.getList(i);
r.skipLong(); // Version forums.add(createForum(forum.getString(0), forum.getRaw(1)));
r.readListStart();
while (!r.hasListEnd()) {
r.readListStart();
String name = r.readString(MAX_FORUM_NAME_LENGTH);
byte[] salt = r.readRaw(FORUM_SALT_LENGTH);
r.readListEnd();
forums.add(createForum(name, salt));
}
r.readListEnd();
r.readListEnd();
if (!r.eof()) throw new FormatException();
return forums;
} catch (FormatException e) {
throw e;
} catch (IOException e) {
// Shouldn't happen with ByteArrayInputStream
throw new RuntimeException(e);
} }
return forums;
} }
private void storeMessage(Transaction txn, GroupId g, List<Forum> forums, private void storeMessage(Transaction txn, GroupId g, List<Forum> forums,
long version) throws DbException { long version) throws DbException {
try { try {
byte[] body = encodeForumList(forums, version); BdfList body = encodeForumList(forums, version);
long now = clock.currentTimeMillis(); long now = clock.currentTimeMillis();
Message m = messageFactory.createMessage(g, now, body); Message m = clientHelper.createMessage(g, now, body);
BdfDictionary d = new BdfDictionary(); BdfDictionary meta = new BdfDictionary();
d.put("version", version); meta.put("version", version);
d.put("local", true); meta.put("local", true);
Metadata meta = metadataEncoder.encode(d); clientHelper.addLocalMessage(txn, m, CLIENT_ID, meta, true);
db.addLocalMessage(txn, m, CLIENT_ID, meta, true);
} catch (FormatException e) { } catch (FormatException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
private byte[] encodeForumList(List<Forum> forums, long version) { private BdfList encodeForumList(List<Forum> forums, long version) {
ByteArrayOutputStream out = new ByteArrayOutputStream(); BdfList forumList = new BdfList();
BdfWriter w = bdfWriterFactory.createWriter(out); for (Forum f : forums)
try { forumList.add(BdfList.of(f.getName(), f.getSalt()));
w.writeListStart(); return BdfList.of(version, forumList);
w.writeLong(version);
w.writeListStart();
for (Forum f : forums) {
w.writeListStart();
w.writeString(f.getName());
w.writeRaw(f.getSalt());
w.writeListEnd();
}
w.writeListEnd();
w.writeListEnd();
} catch (IOException e) {
// Shouldn't happen with ByteArrayOutputStream
throw new RuntimeException(e);
}
return out.toByteArray();
} }
private ContactId getContactId(Transaction txn, GroupId contactGroupId) private ContactId getContactId(Transaction txn, GroupId contactGroupId)
throws DbException, FormatException { throws DbException, FormatException {
Metadata meta = db.getGroupMetadata(txn, contactGroupId); BdfDictionary meta = clientHelper.getGroupMetadataAsDictionary(txn,
BdfDictionary d = metadataParser.parse(meta); contactGroupId);
return new ContactId(d.getLong("contactId").intValue()); return new ContactId(meta.getLong("contactId").intValue());
} }
private Set<GroupId> getVisibleForums(Transaction txn, private Set<GroupId> getVisibleForums(Transaction txn,
@@ -418,9 +372,13 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook,
// If there's no local update, no forums are visible // If there's no local update, no forums are visible
if (local == null) return Collections.emptySet(); if (local == null) return Collections.emptySet();
// Intersect the sets of shared forums // Intersect the sets of shared forums
byte[] localRaw = db.getRawMessage(txn, local.messageId); BdfList localMessage = clientHelper.getMessageAsList(txn,
Set<Forum> shared = new HashSet<Forum>(parseForumList(localRaw)); local.messageId);
shared.retainAll(parseForumList(remoteUpdate.getRaw())); Set<Forum> shared = new HashSet<Forum>(parseForumList(localMessage));
byte[] raw = remoteUpdate.getRaw();
BdfList remoteMessage = clientHelper.toList(raw, MESSAGE_HEADER_LENGTH,
raw.length - MESSAGE_HEADER_LENGTH);
shared.retainAll(parseForumList(remoteMessage));
// Forums in the intersection should be visible // Forums in the intersection should be visible
Set<GroupId> visible = new HashSet<GroupId>(shared.size()); Set<GroupId> visible = new HashSet<GroupId>(shared.size());
for (Forum f : shared) visible.add(f.getId()); for (Forum f : shared) visible.add(f.getId());
@@ -440,46 +398,30 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook,
} }
private Forum createForum(String name, byte[] salt) { private Forum createForum(String name, byte[] salt) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
BdfWriter w = bdfWriterFactory.createWriter(out);
try { try {
w.writeListStart(); BdfList forum = BdfList.of(name, salt);
w.writeString(name); byte[] descriptor = clientHelper.toByteArray(forum);
w.writeRaw(salt); Group g = groupFactory.createGroup(forumManager.getClientId(),
w.writeListEnd(); descriptor);
} catch (IOException e) { return new Forum(g, name, salt);
// Shouldn't happen with ByteArrayOutputStream } catch (FormatException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
Group g = groupFactory.createGroup(forumManager.getClientId(),
out.toByteArray());
return new Forum(g, name, salt);
} }
private Forum parseForum(Group g) throws FormatException { private Forum parseForum(Group g) throws FormatException {
ByteArrayInputStream in = new ByteArrayInputStream(g.getDescriptor()); byte[] descriptor = g.getDescriptor();
BdfReader r = bdfReaderFactory.createReader(in); // Name, salt
try { BdfList forum = clientHelper.toList(descriptor, 0, descriptor.length);
r.readListStart(); return new Forum(g, forum.getString(0), forum.getRaw(1));
String name = r.readString(MAX_FORUM_NAME_LENGTH);
byte[] salt = r.readRaw(FORUM_SALT_LENGTH);
r.readListEnd();
if (!r.eof()) throw new FormatException();
return new Forum(g, name, salt);
} catch (FormatException e) {
throw e;
} catch (IOException e) {
// Shouldn't happen with ByteArrayInputStream
throw new RuntimeException(e);
}
} }
private boolean listContains(Transaction txn, GroupId g, GroupId forum, private boolean listContains(Transaction txn, GroupId g, GroupId forum,
boolean local) throws DbException, FormatException { boolean local) throws DbException, FormatException {
LatestUpdate latest = findLatest(txn, g, local); LatestUpdate latest = findLatest(txn, g, local);
if (latest == null) return false; if (latest == null) return false;
byte[] raw = db.getRawMessage(txn, latest.messageId); BdfList message = clientHelper.getMessageAsList(txn, latest.messageId);
List<Forum> list = parseForumList(raw); List<Forum> list = parseForumList(message);
for (Forum f : list) if (f.getId().equals(forum)) return true; for (Forum f : list) if (f.getId().equals(forum)) return true;
return false; return false;
} }
@@ -491,8 +433,8 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook,
storeMessage(txn, g, Collections.singletonList(f), 0); storeMessage(txn, g, Collections.singletonList(f), 0);
return true; return true;
} }
byte[] raw = db.getRawMessage(txn, latest.messageId); BdfList message = clientHelper.getMessageAsList(txn, latest.messageId);
List<Forum> list = parseForumList(raw); List<Forum> list = parseForumList(message);
if (list.contains(f)) return false; if (list.contains(f)) return false;
list.add(f); list.add(f);
storeMessage(txn, g, list, latest.version + 1); storeMessage(txn, g, list, latest.version + 1);
@@ -503,8 +445,8 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook,
throws DbException, FormatException { throws DbException, FormatException {
LatestUpdate latest = findLatest(txn, g, true); LatestUpdate latest = findLatest(txn, g, true);
if (latest == null) return; if (latest == null) return;
byte[] raw = db.getRawMessage(txn, latest.messageId); BdfList message = clientHelper.getMessageAsList(txn, latest.messageId);
List<Forum> list = parseForumList(raw); List<Forum> list = parseForumList(message);
if (list.remove(f)) storeMessage(txn, g, list, latest.version + 1); if (list.remove(f)) storeMessage(txn, g, list, latest.version + 1);
} }