diff --git a/bramble-core/src/main/java/org/briarproject/bramble/properties/PropertiesModule.java b/bramble-core/src/main/java/org/briarproject/bramble/properties/PropertiesModule.java index 0078beba5b229396f896a993b15582c17227498e..b9d9e578897547f78980e24abd560a439e14ebb2 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/properties/PropertiesModule.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/properties/PropertiesModule.java @@ -40,9 +40,12 @@ public class PropertiesModule { @Provides @Singleton TransportPropertyManager getTransportPropertyManager( - LifecycleManager lifecycleManager, ContactManager contactManager, + LifecycleManager lifecycleManager, + ValidationManager validationManager, ContactManager contactManager, TransportPropertyManagerImpl transportPropertyManager) { lifecycleManager.registerClient(transportPropertyManager); + validationManager.registerIncomingMessageHook(CLIENT_ID, + transportPropertyManager); contactManager.registerAddContactHook(transportPropertyManager); contactManager.registerRemoveContactHook(transportPropertyManager); return transportPropertyManager; diff --git a/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java index 2c3aa556aa8399e51ce3e4b54e33e65b161c3205..cdd4d57abda90c72f4385615073330a59702366a 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java @@ -9,8 +9,10 @@ import org.briarproject.bramble.api.contact.ContactManager.AddContactHook; import org.briarproject.bramble.api.contact.ContactManager.RemoveContactHook; import org.briarproject.bramble.api.data.BdfDictionary; import org.briarproject.bramble.api.data.BdfList; +import org.briarproject.bramble.api.data.MetadataParser; import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.db.Metadata; import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.plugin.TransportId; @@ -19,8 +21,10 @@ import org.briarproject.bramble.api.properties.TransportPropertyManager; import org.briarproject.bramble.api.sync.Client; import org.briarproject.bramble.api.sync.Group; import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.InvalidMessageException; import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.bramble.api.sync.ValidationManager.IncomingMessageHook; import org.briarproject.bramble.api.system.Clock; import java.util.HashMap; @@ -36,20 +40,22 @@ import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; @Immutable @NotNullByDefault class TransportPropertyManagerImpl implements TransportPropertyManager, - Client, AddContactHook, RemoveContactHook { + Client, AddContactHook, RemoveContactHook, IncomingMessageHook { private final DatabaseComponent db; private final ClientHelper clientHelper; + private final MetadataParser metadataParser; private final ContactGroupFactory contactGroupFactory; private final Clock clock; private final Group localGroup; @Inject TransportPropertyManagerImpl(DatabaseComponent db, - ClientHelper clientHelper, ContactGroupFactory contactGroupFactory, - Clock clock) { + ClientHelper clientHelper, MetadataParser metadataParser, + ContactGroupFactory contactGroupFactory, Clock clock) { this.db = db; this.clientHelper = clientHelper; + this.metadataParser = metadataParser; this.contactGroupFactory = contactGroupFactory; this.clock = clock; localGroup = contactGroupFactory.createLocalGroup(CLIENT_ID); @@ -84,6 +90,31 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, db.removeGroup(txn, getContactGroup(c)); } + @Override + public boolean incomingMessage(Transaction txn, Message m, Metadata meta) + throws DbException, InvalidMessageException { + try { + // Find the latest update for this transport, if any + BdfDictionary d = metadataParser.parse(meta); + TransportId t = new TransportId(d.getString("transportId")); + LatestUpdate latest = findLatest(txn, m.getGroupId(), t, false); + if (latest != null) { + if (d.getLong("version") > latest.version) { + // This update is newer - delete the previous update + db.deleteMessage(txn, latest.messageId); + db.deleteMessageMetadata(txn, latest.messageId); + } else { + // We've already received a newer update - delete this one + db.deleteMessage(txn, m.getId()); + db.deleteMessageMetadata(txn, m.getId()); + } + } + } catch (FormatException e) { + throw new InvalidMessageException(e); + } + return false; + } + @Override public void addRemoteProperties(Transaction txn, ContactId c, Map<TransportId, TransportProperties> props) throws DbException { @@ -115,8 +146,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, Map<TransportId, TransportProperties> local = new HashMap<TransportId, TransportProperties>(); // Find the latest local update for each transport - Map<TransportId, LatestUpdate> latest = findLatest(txn, - localGroup.getId(), true); + Map<TransportId, LatestUpdate> latest = findLatestLocal(txn); // Retrieve and parse the latest local properties for (Entry<TransportId, LatestUpdate> e : latest.entrySet()) { BdfList message = clientHelper.getMessageAsList(txn, @@ -234,6 +264,11 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, long version = latest == null ? 1 : latest.version + 1; storeMessage(txn, localGroup.getId(), t, merged, version, true, false); + // Delete the previous update, if any + if (latest != null) { + db.deleteMessage(txn, latest.messageId); + db.deleteMessageMetadata(txn, latest.messageId); + } // Store the merged properties in each contact's group for (Contact c : db.getContacts(txn)) { Group g = getContactGroup(c); @@ -241,6 +276,11 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, version = latest == null ? 1 : latest.version + 1; storeMessage(txn, g.getId(), t, merged, version, true, true); + // Delete the previous update, if any + if (latest != null) { + db.deleteMessage(txn, latest.messageId); + db.deleteMessageMetadata(txn, latest.messageId); + } } } db.commitTransaction(txn); @@ -278,20 +318,29 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, return BdfList.of(t.getString(), version, p); } - private Map<TransportId, LatestUpdate> findLatest(Transaction txn, - GroupId g, boolean local) throws DbException, FormatException { + private Map<TransportId, LatestUpdate> findLatestLocal(Transaction txn) + throws DbException, FormatException { + // TODO: This can be simplified before 1.0 Map<TransportId, LatestUpdate> latestUpdates = new HashMap<TransportId, LatestUpdate>(); - Map<MessageId, BdfDictionary> metadata = - clientHelper.getMessageMetadataAsDictionary(txn, g); + Map<MessageId, BdfDictionary> metadata = clientHelper + .getMessageMetadataAsDictionary(txn, localGroup.getId()); for (Entry<MessageId, BdfDictionary> e : metadata.entrySet()) { BdfDictionary meta = e.getValue(); - if (meta.getBoolean("local") == local) { - TransportId t = new TransportId(meta.getString("transportId")); - long version = meta.getLong("version"); - LatestUpdate latest = latestUpdates.get(t); - if (latest == null || version > latest.version) - latestUpdates.put(t, new LatestUpdate(e.getKey(), version)); + TransportId t = new TransportId(meta.getString("transportId")); + long version = meta.getLong("version"); + LatestUpdate latest = latestUpdates.get(t); + if (latest == null) { + latestUpdates.put(t, new LatestUpdate(e.getKey(), version)); + } else if (version > latest.version) { + // This update is newer - delete the previous one + db.deleteMessage(txn, latest.messageId); + db.deleteMessageMetadata(txn, latest.messageId); + latestUpdates.put(t, new LatestUpdate(e.getKey(), version)); + } else { + // We've already found a newer update - delete this one + db.deleteMessage(txn, e.getKey()); + db.deleteMessageMetadata(txn, e.getKey()); } } return latestUpdates; @@ -300,6 +349,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, @Nullable private LatestUpdate findLatest(Transaction txn, GroupId g, TransportId t, boolean local) throws DbException, FormatException { + // TODO: This can be simplified before 1.0 LatestUpdate latest = null; Map<MessageId, BdfDictionary> metadata = clientHelper.getMessageMetadataAsDictionary(txn, g); @@ -308,8 +358,18 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, if (meta.getString("transportId").equals(t.getString()) && meta.getBoolean("local") == local) { long version = meta.getLong("version"); - if (latest == null || version > latest.version) + if (latest == null) { + latest = new LatestUpdate(e.getKey(), version); + } else if (version > latest.version) { + // This update is newer - delete the previous one + db.deleteMessage(txn, latest.messageId); + db.deleteMessageMetadata(txn, latest.messageId); latest = new LatestUpdate(e.getKey(), version); + } else { + // We've already found a newer update - delete this one + db.deleteMessage(txn, e.getKey()); + db.deleteMessageMetadata(txn, e.getKey()); + } } } return latest;