refactor with master and fixed files that were accidentally clobbered

This commit is contained in:
Ernir Erlingsson
2016-03-13 23:01:58 +01:00
parent 4da63b3800
commit 686729b045
4 changed files with 123 additions and 301 deletions

View File

@@ -1,15 +1,12 @@
package org.briarproject.forum; package org.briarproject.forum;
import org.briarproject.api.FormatException; import org.briarproject.api.FormatException;
import org.briarproject.api.clients.ClientHelper;
import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.Contact;
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.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.Transaction; import org.briarproject.api.db.Transaction;
import org.briarproject.api.forum.Forum; import org.briarproject.api.forum.Forum;
import org.briarproject.api.forum.ForumManager; import org.briarproject.api.forum.ForumManager;
@@ -24,8 +21,6 @@ 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.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@@ -34,18 +29,12 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import java.util.logging.Logger;
import javax.inject.Inject; import javax.inject.Inject;
import static java.util.logging.Level.WARNING;
import static org.briarproject.api.forum.ForumConstants.FORUM_SALT_LENGTH;
import static org.briarproject.api.forum.ForumConstants.MAX_FORUM_NAME_LENGTH;
import static org.briarproject.api.forum.ForumConstants.MAX_FORUM_POST_BODY_LENGTH;
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.UNKNOWN; import static org.briarproject.api.identity.Author.Status.UNKNOWN;
import static org.briarproject.api.identity.Author.Status.VERIFIED; import static org.briarproject.api.identity.Author.Status.VERIFIED;
import static org.briarproject.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
class ForumManagerImpl implements ForumManager { class ForumManagerImpl implements ForumManager {
@@ -53,21 +42,13 @@ class ForumManagerImpl implements ForumManager {
"859a7be50dca035b64bd6902fb797097" "859a7be50dca035b64bd6902fb797097"
+ "795af837abbf8c16d750b3c2ccc186ea")); + "795af837abbf8c16d750b3c2ccc186ea"));
private static final Logger LOG =
Logger.getLogger(ForumManagerImpl.class.getName());
private final DatabaseComponent db; private final DatabaseComponent db;
private final BdfReaderFactory bdfReaderFactory; private final ClientHelper clientHelper;
private final MetadataEncoder metadataEncoder;
private final MetadataParser metadataParser;
@Inject @Inject
ForumManagerImpl(DatabaseComponent db, BdfReaderFactory bdfReaderFactory, ForumManagerImpl(DatabaseComponent db, ClientHelper clientHelper) {
MetadataEncoder metadataEncoder, MetadataParser metadataParser) {
this.db = db; this.db = db;
this.bdfReaderFactory = bdfReaderFactory; this.clientHelper = clientHelper;
this.metadataEncoder = metadataEncoder;
this.metadataParser = metadataParser;
} }
@Override @Override
@@ -78,29 +59,21 @@ class ForumManagerImpl implements ForumManager {
@Override @Override
public void addLocalPost(ForumPost p) throws DbException { public void addLocalPost(ForumPost p) throws DbException {
try { try {
BdfDictionary d = new BdfDictionary(); BdfDictionary meta = new BdfDictionary();
d.put("timestamp", p.getMessage().getTimestamp()); meta.put("timestamp", p.getMessage().getTimestamp());
if (p.getParent() != null) if (p.getParent() != null) meta.put("parent", p.getParent());
d.put("parent", p.getParent().getBytes());
if (p.getAuthor() != null) { if (p.getAuthor() != null) {
Author a = p.getAuthor(); Author a = p.getAuthor();
BdfDictionary d1 = new BdfDictionary(); BdfDictionary authorMeta = new BdfDictionary();
d1.put("id", a.getId().getBytes()); authorMeta.put("id", a.getId());
d1.put("name", a.getName()); authorMeta.put("name", a.getName());
d1.put("publicKey", a.getPublicKey()); authorMeta.put("publicKey", a.getPublicKey());
d.put("author", d1); meta.put("author", authorMeta);
}
d.put("contentType", p.getContentType());
d.put("local", true);
d.put("read", true);
Metadata meta = metadataEncoder.encode(d);
Transaction txn = db.startTransaction();
try {
db.addLocalMessage(txn, p.getMessage(), CLIENT_ID, meta, true);
txn.setComplete();
} finally {
db.endTransaction(txn);
} }
meta.put("contentType", p.getContentType());
meta.put("local", true);
meta.put("read", true);
clientHelper.addLocalMessage(p.getMessage(), CLIENT_ID, meta, true);
} catch (FormatException e) { } catch (FormatException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@@ -145,34 +118,11 @@ class ForumManagerImpl implements ForumManager {
@Override @Override
public byte[] getPostBody(MessageId m) throws DbException { public byte[] getPostBody(MessageId m) throws DbException {
try { try {
byte[] raw; // Parent ID, author, content type, forum post body, signature
Transaction txn = db.startTransaction(); BdfList message = clientHelper.getMessageAsList(m);
try { return message.getRaw(3);
raw = db.getRawMessage(txn, m);
txn.setComplete();
} finally {
db.endTransaction(txn);
}
ByteArrayInputStream in = new ByteArrayInputStream(raw,
MESSAGE_HEADER_LENGTH, raw.length - MESSAGE_HEADER_LENGTH);
BdfReader r = bdfReaderFactory.createReader(in);
r.readListStart();
if (r.hasRaw()) r.skipRaw(); // Parent ID
else r.skipNull(); // No parent
if (r.hasList()) r.skipList(); // Author
else r.skipNull(); // No author
r.skipString(); // Content type
byte[] postBody = r.readRaw(MAX_FORUM_POST_BODY_LENGTH);
if (r.hasRaw()) r.skipRaw(); // Signature
else r.skipNull();
r.readListEnd();
if (!r.eof()) throw new FormatException();
return postBody;
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);
} catch (IOException e) {
// Shouldn't happen with ByteArrayInputStream
throw new RuntimeException(e);
} }
} }
@@ -181,7 +131,7 @@ class ForumManagerImpl implements ForumManager {
throws DbException { throws DbException {
Set<AuthorId> localAuthorIds = new HashSet<AuthorId>(); Set<AuthorId> localAuthorIds = new HashSet<AuthorId>();
Set<AuthorId> contactAuthorIds = new HashSet<AuthorId>(); Set<AuthorId> contactAuthorIds = new HashSet<AuthorId>();
Map<MessageId, Metadata> metadata; Map<MessageId, BdfDictionary> metadata;
Transaction txn = db.startTransaction(); Transaction txn = db.startTransaction();
try { try {
// Load the IDs of the user's identities // Load the IDs of the user's identities
@@ -191,20 +141,22 @@ class ForumManagerImpl implements ForumManager {
for (Contact c : db.getContacts(txn)) for (Contact c : db.getContacts(txn))
contactAuthorIds.add(c.getAuthor().getId()); contactAuthorIds.add(c.getAuthor().getId());
// Load the metadata // Load the metadata
metadata = db.getMessageMetadata(txn, g); metadata = clientHelper.getMessageMetadataAsDictionary(txn, g);
txn.setComplete(); txn.setComplete();
} catch (FormatException e) {
throw new DbException(e);
} finally { } finally {
db.endTransaction(txn); db.endTransaction(txn);
} }
// Parse the metadata // Parse the metadata
Collection<ForumPostHeader> headers = new ArrayList<ForumPostHeader>(); Collection<ForumPostHeader> headers = new ArrayList<ForumPostHeader>();
for (Entry<MessageId, Metadata> e : metadata.entrySet()) { for (Entry<MessageId, BdfDictionary> entry : metadata.entrySet()) {
try { try {
BdfDictionary d = metadataParser.parse(e.getValue()); BdfDictionary meta = entry.getValue();
long timestamp = d.getLong("timestamp"); long timestamp = meta.getLong("timestamp");
Author author = null; Author author = null;
Author.Status authorStatus = ANONYMOUS; Author.Status authorStatus = ANONYMOUS;
BdfDictionary d1 = d.getDictionary("author", null); BdfDictionary d1 = meta.getDictionary("author", null);
if (d1 != null) { if (d1 != null) {
AuthorId authorId = new AuthorId(d1.getRaw("id")); AuthorId authorId = new AuthorId(d1.getRaw("id"));
String name = d1.getString("name"); String name = d1.getString("name");
@@ -216,13 +168,12 @@ class ForumManagerImpl implements ForumManager {
authorStatus = VERIFIED; authorStatus = VERIFIED;
else authorStatus = UNKNOWN; else authorStatus = UNKNOWN;
} }
String contentType = d.getString("contentType"); String contentType = meta.getString("contentType");
boolean read = d.getBoolean("read"); boolean read = meta.getBoolean("read");
headers.add(new ForumPostHeader(e.getKey(), timestamp, author, headers.add(new ForumPostHeader(entry.getKey(), timestamp,
authorStatus, contentType, read)); author, authorStatus, contentType, read));
} catch (FormatException ex) { } catch (FormatException e) {
if (LOG.isLoggable(WARNING)) throw new DbException(e);
LOG.log(WARNING, ex.toString(), ex);
} }
} }
return headers; return headers;
@@ -231,36 +182,18 @@ class ForumManagerImpl implements ForumManager {
@Override @Override
public void setReadFlag(MessageId m, boolean read) throws DbException { public void setReadFlag(MessageId m, boolean read) throws DbException {
try { try {
BdfDictionary d = new BdfDictionary(); BdfDictionary meta = new BdfDictionary();
d.put("read", read); meta.put("read", read);
Metadata meta = metadataEncoder.encode(d); clientHelper.mergeMessageMetadata(m, meta);
Transaction txn = db.startTransaction();
try {
db.mergeMessageMetadata(txn, m, meta);
txn.setComplete();
} finally {
db.endTransaction(txn);
}
} catch (FormatException e) { } catch (FormatException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
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);
}
} }
} }

View File

@@ -35,10 +35,8 @@ public class ForumModule {
@Provides @Provides
@Singleton @Singleton
ForumManager provideForumManager(DatabaseComponent db, ForumManager provideForumManager(DatabaseComponent db,
ContactManager contactManager, BdfReaderFactory bdfReaderFactory, ClientHelper clientHelper) {
MetadataEncoder metadataEncoder, MetadataParser metadataParser) { return new ForumManagerImpl(db, clientHelper);
return new ForumManagerImpl(db, bdfReaderFactory, metadataEncoder,
metadataParser);
} }
@Provides @Provides

View File

@@ -1,19 +1,16 @@
package org.briarproject.messaging; package org.briarproject.messaging;
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.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.Transaction; import org.briarproject.api.db.Transaction;
import org.briarproject.api.messaging.MessagingManager; import org.briarproject.api.messaging.MessagingManager;
import org.briarproject.api.messaging.PrivateMessage; import org.briarproject.api.messaging.PrivateMessage;
@@ -25,19 +22,12 @@ import org.briarproject.api.sync.MessageId;
import org.briarproject.api.sync.MessageStatus; import org.briarproject.api.sync.MessageStatus;
import org.briarproject.util.StringUtils; import org.briarproject.util.StringUtils;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
import java.util.logging.Logger;
import javax.inject.Inject; import javax.inject.Inject;
import static java.util.logging.Level.WARNING;
import static org.briarproject.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_BODY_LENGTH;
import static org.briarproject.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
class MessagingManagerImpl implements MessagingManager, AddContactHook, class MessagingManagerImpl implements MessagingManager, AddContactHook,
RemoveContactHook { RemoveContactHook {
@@ -45,25 +35,16 @@ class MessagingManagerImpl implements MessagingManager, AddContactHook,
"6bcdc006c0910b0f44e40644c3b31f1a" "6bcdc006c0910b0f44e40644c3b31f1a"
+ "8bf9a6d6021d40d219c86b731b903070")); + "8bf9a6d6021d40d219c86b731b903070"));
private static final Logger LOG =
Logger.getLogger(MessagingManagerImpl.class.getName());
private final DatabaseComponent db; private final DatabaseComponent db;
private final ClientHelper clientHelper;
private final PrivateGroupFactory privateGroupFactory; private final PrivateGroupFactory privateGroupFactory;
private final BdfReaderFactory bdfReaderFactory;
private final MetadataEncoder metadataEncoder;
private final MetadataParser metadataParser;
@Inject @Inject
MessagingManagerImpl(DatabaseComponent db, MessagingManagerImpl(DatabaseComponent db, ClientHelper clientHelper,
PrivateGroupFactory privateGroupFactory, PrivateGroupFactory privateGroupFactory) {
BdfReaderFactory bdfReaderFactory, MetadataEncoder metadataEncoder,
MetadataParser metadataParser) {
this.db = db; this.db = db;
this.clientHelper = clientHelper;
this.privateGroupFactory = privateGroupFactory; this.privateGroupFactory = privateGroupFactory;
this.bdfReaderFactory = bdfReaderFactory;
this.metadataEncoder = metadataEncoder;
this.metadataParser = metadataParser;
} }
@Override @Override
@@ -77,7 +58,7 @@ class MessagingManagerImpl implements MessagingManager, AddContactHook,
// Attach the contact ID to the group // Attach the contact ID to the group
BdfDictionary d = new BdfDictionary(); BdfDictionary d = new BdfDictionary();
d.put("contactId", c.getId().getInt()); d.put("contactId", c.getId().getInt());
db.mergeGroupMetadata(txn, g.getId(), metadataEncoder.encode(d)); clientHelper.mergeGroupMetadata(txn, g.getId(), d);
} catch (FormatException e) { } catch (FormatException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@@ -100,21 +81,13 @@ class MessagingManagerImpl implements MessagingManager, AddContactHook,
@Override @Override
public void addLocalMessage(PrivateMessage m) throws DbException { public void addLocalMessage(PrivateMessage m) throws DbException {
try { try {
BdfDictionary d = new BdfDictionary(); BdfDictionary meta = new BdfDictionary();
d.put("timestamp", m.getMessage().getTimestamp()); meta.put("timestamp", m.getMessage().getTimestamp());
if (m.getParent() != null) if (m.getParent() != null) meta.put("parent", m.getParent());
d.put("parent", m.getParent().getBytes()); meta.put("contentType", m.getContentType());
d.put("contentType", m.getContentType()); meta.put("local", true);
d.put("local", true); meta.put("read", true);
d.put("read", true); clientHelper.addLocalMessage(m.getMessage(), CLIENT_ID, meta, true);
Metadata meta = metadataEncoder.encode(d);
Transaction txn = db.startTransaction();
try {
db.addLocalMessage(txn, m.getMessage(), CLIENT_ID, meta, true);
txn.setComplete();
} finally {
db.endTransaction(txn);
}
} catch (FormatException e) { } catch (FormatException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@@ -123,16 +96,8 @@ class MessagingManagerImpl implements MessagingManager, AddContactHook,
@Override @Override
public ContactId getContactId(GroupId g) throws DbException { public ContactId getContactId(GroupId g) throws DbException {
try { try {
Metadata meta; BdfDictionary meta = clientHelper.getGroupMetadataAsDictionary(g);
Transaction txn = db.startTransaction(); return new ContactId(meta.getLong("contactId").intValue());
try {
meta = db.getGroupMetadata(txn, g);
txn.setComplete();
} finally {
db.endTransaction(txn);
}
BdfDictionary d = metadataParser.parse(meta);
return new ContactId(d.getLong("contactId").intValue());
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);
} }
@@ -154,14 +119,16 @@ class MessagingManagerImpl implements MessagingManager, AddContactHook,
@Override @Override
public Collection<PrivateMessageHeader> getMessageHeaders(ContactId c) public Collection<PrivateMessageHeader> getMessageHeaders(ContactId c)
throws DbException { throws DbException {
Map<MessageId, Metadata> metadata; Map<MessageId, BdfDictionary> metadata;
Collection<MessageStatus> statuses; Collection<MessageStatus> statuses;
Transaction txn = db.startTransaction(); Transaction txn = db.startTransaction();
try { try {
GroupId g = getContactGroup(db.getContact(txn, c)).getId(); GroupId g = getContactGroup(db.getContact(txn, c)).getId();
metadata = db.getMessageMetadata(txn, g); metadata = clientHelper.getMessageMetadataAsDictionary(txn, g);
statuses = db.getMessageStatus(txn, c, g); statuses = db.getMessageStatus(txn, c, g);
txn.setComplete(); txn.setComplete();
} catch (FormatException e) {
throw new DbException(e);
} finally { } finally {
db.endTransaction(txn); db.endTransaction(txn);
} }
@@ -169,18 +136,17 @@ class MessagingManagerImpl implements MessagingManager, AddContactHook,
new ArrayList<PrivateMessageHeader>(); new ArrayList<PrivateMessageHeader>();
for (MessageStatus s : statuses) { for (MessageStatus s : statuses) {
MessageId id = s.getMessageId(); MessageId id = s.getMessageId();
Metadata m = metadata.get(id); BdfDictionary meta = metadata.get(id);
if (m == null) continue; if (meta == null) continue;
try { try {
BdfDictionary d = metadataParser.parse(m); long timestamp = meta.getLong("timestamp");
long timestamp = d.getLong("timestamp"); String contentType = meta.getString("contentType");
String contentType = d.getString("contentType"); boolean local = meta.getBoolean("local");
boolean local = d.getBoolean("local"); boolean read = meta.getBoolean("read");
boolean read = d.getBoolean("read");
headers.add(new PrivateMessageHeader(id, timestamp, contentType, headers.add(new PrivateMessageHeader(id, timestamp, contentType,
local, read, s.isSent(), s.isSeen())); local, read, s.isSent(), s.isSeen()));
} catch (FormatException e) { } catch (FormatException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); throw new DbException(e);
} }
} }
return headers; return headers;
@@ -188,47 +154,21 @@ class MessagingManagerImpl implements MessagingManager, AddContactHook,
@Override @Override
public byte[] getMessageBody(MessageId m) throws DbException { public byte[] getMessageBody(MessageId m) throws DbException {
byte[] raw;
Transaction txn = db.startTransaction();
try { try {
raw = db.getRawMessage(txn, m); // Parent ID, content type, private message body
txn.setComplete(); BdfList message = clientHelper.getMessageAsList(m);
} finally { return message.getRaw(2);
db.endTransaction(txn);
}
ByteArrayInputStream in = new ByteArrayInputStream(raw,
MESSAGE_HEADER_LENGTH, raw.length - MESSAGE_HEADER_LENGTH);
BdfReader r = bdfReaderFactory.createReader(in);
try {
r.readListStart();
if (r.hasRaw()) r.skipRaw(); // Parent ID
else r.skipNull(); // No parent
r.skipString(); // Content type
byte[] messageBody = r.readRaw(MAX_PRIVATE_MESSAGE_BODY_LENGTH);
r.readListEnd();
if (!r.eof()) throw new FormatException();
return messageBody;
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);
} catch (IOException e) {
// Shouldn't happen with ByteArrayInputStream
throw new RuntimeException(e);
} }
} }
@Override @Override
public void setReadFlag(MessageId m, boolean read) throws DbException { public void setReadFlag(MessageId m, boolean read) throws DbException {
try { try {
BdfDictionary d = new BdfDictionary(); BdfDictionary meta = new BdfDictionary();
d.put("read", read); meta.put("read", read);
Metadata meta = metadataEncoder.encode(d); clientHelper.mergeMessageMetadata(m, meta);
Transaction txn = db.startTransaction();
try {
db.mergeMessageMetadata(txn, m, meta);
txn.setComplete();
} finally {
db.endTransaction(txn);
}
} catch (FormatException e) { } catch (FormatException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }

View File

@@ -3,21 +3,16 @@ package org.briarproject.properties;
import org.briarproject.api.DeviceId; import org.briarproject.api.DeviceId;
import org.briarproject.api.FormatException; import org.briarproject.api.FormatException;
import org.briarproject.api.TransportId; import org.briarproject.api.TransportId;
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.NoSuchGroupException; import org.briarproject.api.db.NoSuchGroupException;
import org.briarproject.api.db.Transaction; import org.briarproject.api.db.Transaction;
import org.briarproject.api.properties.TransportProperties; import org.briarproject.api.properties.TransportProperties;
@@ -27,14 +22,10 @@ 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.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.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@@ -42,9 +33,6 @@ import java.util.Map.Entry;
import javax.inject.Inject; import javax.inject.Inject;
import static org.briarproject.api.properties.TransportPropertyConstants.MAX_PROPERTY_LENGTH;
import static org.briarproject.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
class TransportPropertyManagerImpl implements TransportPropertyManager, class TransportPropertyManagerImpl implements TransportPropertyManager,
AddContactHook, RemoveContactHook { AddContactHook, RemoveContactHook {
@@ -55,28 +43,18 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
private static final byte[] LOCAL_GROUP_DESCRIPTOR = new byte[0]; private static final byte[] LOCAL_GROUP_DESCRIPTOR = new byte[0];
private final DatabaseComponent db; private final DatabaseComponent db;
private final ClientHelper clientHelper;
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 Clock clock; private final Clock clock;
private final Group localGroup; private final Group localGroup;
@Inject @Inject
TransportPropertyManagerImpl(DatabaseComponent db, TransportPropertyManagerImpl(DatabaseComponent db,
GroupFactory groupFactory, PrivateGroupFactory privateGroupFactory, ClientHelper clientHelper, GroupFactory groupFactory,
MessageFactory messageFactory, BdfReaderFactory bdfReaderFactory, PrivateGroupFactory privateGroupFactory, Clock clock) {
BdfWriterFactory bdfWriterFactory, MetadataEncoder metadataEncoder,
MetadataParser metadataParser, Clock clock) {
this.db = db; this.db = db;
this.clientHelper = clientHelper;
this.privateGroupFactory = privateGroupFactory; this.privateGroupFactory = privateGroupFactory;
this.messageFactory = messageFactory;
this.bdfReaderFactory = bdfReaderFactory;
this.bdfWriterFactory = bdfWriterFactory;
this.metadataEncoder = metadataEncoder;
this.metadataParser = metadataParser;
this.clock = clock; this.clock = clock;
localGroup = groupFactory.createGroup(CLIENT_ID, localGroup = groupFactory.createGroup(CLIENT_ID,
LOCAL_GROUP_DESCRIPTOR); LOCAL_GROUP_DESCRIPTOR);
@@ -145,8 +123,9 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
true); true);
if (latest != null) { if (latest != null) {
// Retrieve and parse the latest local properties // Retrieve and parse the latest local properties
byte[] raw = db.getRawMessage(txn, latest.messageId); BdfList message = clientHelper.getMessageAsList(txn,
p = parseProperties(raw); latest.messageId);
p = parseProperties(message);
} }
txn.setComplete(); txn.setComplete();
} finally { } finally {
@@ -175,8 +154,9 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
LatestUpdate latest = findLatest(txn, g.getId(), t, false); LatestUpdate latest = findLatest(txn, g.getId(), t, false);
if (latest != null) { if (latest != null) {
// Retrieve and parse the latest remote properties // Retrieve and parse the latest remote properties
byte[] raw = db.getRawMessage(txn, latest.messageId); BdfList message = clientHelper.getMessageAsList(txn,
remote.put(c.getId(), parseProperties(raw)); latest.messageId);
remote.put(c.getId(), parseProperties(message));
} }
} }
txn.setComplete(); txn.setComplete();
@@ -206,8 +186,9 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
merged = p; merged = p;
changed = true; changed = true;
} else { } else {
byte[] raw = db.getRawMessage(txn, latest.messageId); BdfList message = clientHelper.getMessageAsList(txn,
TransportProperties old = parseProperties(raw); latest.messageId);
TransportProperties old = parseProperties(message);
merged = new TransportProperties(old); merged = new TransportProperties(old);
merged.putAll(p); merged.putAll(p);
changed = !merged.equals(old); changed = !merged.equals(old);
@@ -250,8 +231,9 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
localGroup.getId(), true); localGroup.getId(), true);
// Retrieve and parse the latest local properties // Retrieve and parse the latest local properties
for (Entry<TransportId, LatestUpdate> e : latest.entrySet()) { for (Entry<TransportId, LatestUpdate> e : latest.entrySet()) {
byte[] raw = db.getRawMessage(txn, e.getValue().messageId); BdfList message = clientHelper.getMessageAsList(txn,
local.put(e.getKey(), parseProperties(raw)); e.getValue().messageId);
local.put(e.getKey(), parseProperties(message));
} }
return local; return local;
} catch (NoSuchGroupException e) { } catch (NoSuchGroupException e) {
@@ -266,48 +248,35 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
TransportId t, TransportProperties p, long version, boolean local, TransportId t, TransportProperties p, long version, boolean local,
boolean shared) throws DbException { boolean shared) throws DbException {
try { try {
byte[] body = encodeProperties(dev, t, p, version); BdfList body = encodeProperties(dev, t, p, 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("transportId", t.getString()); meta.put("transportId", t.getString());
d.put("version", version); meta.put("version", version);
d.put("local", local); meta.put("local", local);
Metadata meta = metadataEncoder.encode(d); clientHelper.addLocalMessage(txn, m, CLIENT_ID, meta, shared);
db.addLocalMessage(txn, m, CLIENT_ID, meta, shared);
} catch (FormatException e) { } catch (FormatException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
private byte[] encodeProperties(DeviceId dev, TransportId t, private BdfList encodeProperties(DeviceId dev, TransportId t,
TransportProperties p, long version) { TransportProperties p, long version) {
ByteArrayOutputStream out = new ByteArrayOutputStream(); return BdfList.of(dev, t.getString(), version, p);
BdfWriter w = bdfWriterFactory.createWriter(out);
try {
w.writeListStart();
w.writeRaw(dev.getBytes());
w.writeString(t.getString());
w.writeLong(version);
w.writeDictionary(p);
w.writeListEnd();
} catch (IOException e) {
// Shouldn't happen with ByteArrayOutputStream
throw new RuntimeException(e);
}
return out.toByteArray();
} }
private Map<TransportId, LatestUpdate> findLatest(Transaction txn, private Map<TransportId, LatestUpdate> findLatest(Transaction txn,
GroupId g, boolean local) throws DbException, FormatException { GroupId g, boolean local) throws DbException, FormatException {
Map<TransportId, LatestUpdate> latestUpdates = Map<TransportId, LatestUpdate> latestUpdates =
new HashMap<TransportId, LatestUpdate>(); new HashMap<TransportId, LatestUpdate>();
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) { BdfDictionary meta = e.getValue();
TransportId t = new TransportId(d.getString("transportId")); if (meta.getBoolean("local") == local) {
long version = d.getLong("version"); TransportId t = new TransportId(meta.getString("transportId"));
long version = meta.getLong("version");
LatestUpdate latest = latestUpdates.get(t); LatestUpdate latest = latestUpdates.get(t);
if (latest == null || version > latest.version) if (latest == null || version > latest.version)
latestUpdates.put(t, new LatestUpdate(e.getKey(), version)); latestUpdates.put(t, new LatestUpdate(e.getKey(), version));
@@ -319,12 +288,13 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
private LatestUpdate findLatest(Transaction txn, GroupId g, TransportId t, private LatestUpdate findLatest(Transaction txn, GroupId g, TransportId t,
boolean local) throws DbException, FormatException { boolean local) 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.getString("transportId").equals(t.getString()) BdfDictionary meta = e.getValue();
&& d.getBoolean("local") == local) { if (meta.getString("transportId").equals(t.getString())
long version = d.getLong("version"); && meta.getBoolean("local") == local) {
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);
} }
@@ -332,33 +302,14 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
return latest; return latest;
} }
private TransportProperties parseProperties(byte[] raw) private TransportProperties parseProperties(BdfList message)
throws FormatException { throws FormatException {
// Device ID, transport ID, version, properties
BdfDictionary dictionary = message.getDictionary(3);
TransportProperties p = new TransportProperties(); TransportProperties p = new TransportProperties();
ByteArrayInputStream in = new ByteArrayInputStream(raw, for (String key : dictionary.keySet())
MESSAGE_HEADER_LENGTH, raw.length - MESSAGE_HEADER_LENGTH); p.put(key, dictionary.getString(key));
BdfReader r = bdfReaderFactory.createReader(in); return p;
try {
r.readListStart();
r.skipRaw(); // Device ID
r.skipString(); // Transport ID
r.skipLong(); // Version
r.readDictionaryStart();
while (!r.hasDictionaryEnd()) {
String key = r.readString(MAX_PROPERTY_LENGTH);
String value = r.readString(MAX_PROPERTY_LENGTH);
p.put(key, value);
}
r.readDictionaryEnd();
r.readListEnd();
if (!r.eof()) throw new FormatException();
return p;
} catch (FormatException e) {
throw e;
} catch (IOException e) {
// Shouldn't happen with ByteArrayInputStream
throw new RuntimeException(e);
}
} }
private static class LatestUpdate { private static class LatestUpdate {