mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-16 12:49:55 +01:00
Unshared messages.
This commit is contained in:
@@ -56,7 +56,7 @@ public interface DatabaseComponent {
|
|||||||
void addLocalAuthor(LocalAuthor a) throws DbException;
|
void addLocalAuthor(LocalAuthor a) throws DbException;
|
||||||
|
|
||||||
/** Stores a local message. */
|
/** Stores a local message. */
|
||||||
void addLocalMessage(Message m, ClientId c, Metadata meta)
|
void addLocalMessage(Message m, ClientId c, Metadata meta, boolean shared)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -277,8 +277,11 @@ public interface DatabaseComponent {
|
|||||||
void setLocalAuthorStatus(AuthorId a, StorageStatus s)
|
void setLocalAuthorStatus(AuthorId a, StorageStatus s)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
|
/** Marks the given message as shared or unshared. */
|
||||||
|
void setMessageShared(Message m, boolean shared) throws DbException;
|
||||||
|
|
||||||
/** Marks the given message as valid or invalid. */
|
/** Marks the given message as valid or invalid. */
|
||||||
void setMessageValidity(Message m, ClientId c, boolean valid)
|
void setMessageValid(Message m, ClientId c, boolean valid)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package org.briarproject.api.event;
|
||||||
|
|
||||||
|
import org.briarproject.api.sync.Message;
|
||||||
|
|
||||||
|
/** An event that is broadcast when a message is shared. */
|
||||||
|
public class MessageSharedEvent extends Event {
|
||||||
|
|
||||||
|
private final Message message;
|
||||||
|
|
||||||
|
public MessageSharedEvent(Message message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Message getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,13 +6,13 @@ package org.briarproject.api.sync;
|
|||||||
*/
|
*/
|
||||||
public interface ValidationManager {
|
public interface ValidationManager {
|
||||||
|
|
||||||
enum Status {
|
enum Validity {
|
||||||
|
|
||||||
UNKNOWN(0), INVALID(1), VALID(2);
|
UNKNOWN(0), INVALID(1), VALID(2);
|
||||||
|
|
||||||
private final int value;
|
private final int value;
|
||||||
|
|
||||||
Status(int value) {
|
Validity(int value) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,8 +20,8 @@ public interface ValidationManager {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Status fromValue(int value) {
|
public static Validity fromValue(int value) {
|
||||||
for (Status s : values()) if (s.value == value) return s;
|
for (Validity s : values()) if (s.value == value) return s;
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import org.briarproject.api.sync.MessageId;
|
|||||||
import org.briarproject.api.sync.MessageStatus;
|
import org.briarproject.api.sync.MessageStatus;
|
||||||
import org.briarproject.api.sync.SubscriptionAck;
|
import org.briarproject.api.sync.SubscriptionAck;
|
||||||
import org.briarproject.api.sync.SubscriptionUpdate;
|
import org.briarproject.api.sync.SubscriptionUpdate;
|
||||||
|
import org.briarproject.api.sync.ValidationManager.Validity;
|
||||||
import org.briarproject.api.transport.TransportKeys;
|
import org.briarproject.api.transport.TransportKeys;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -111,7 +112,8 @@ interface Database<T> {
|
|||||||
* <p>
|
* <p>
|
||||||
* Locking: write.
|
* Locking: write.
|
||||||
*/
|
*/
|
||||||
void addMessage(T txn, Message m, boolean local) throws DbException;
|
void addMessage(T txn, Message m, Validity validity, boolean shared)
|
||||||
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Records that a message has been offered by the given contact.
|
* Records that a message has been offered by the given contact.
|
||||||
@@ -617,13 +619,20 @@ interface Database<T> {
|
|||||||
void setLocalAuthorStatus(T txn, AuthorId a, StorageStatus s)
|
void setLocalAuthorStatus(T txn, AuthorId a, StorageStatus s)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks the given message as shared or unshared.
|
||||||
|
* <p>
|
||||||
|
* Locking: write.
|
||||||
|
*/
|
||||||
|
void setMessageShared(T txn, MessageId m, boolean shared)
|
||||||
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks the given message as valid or invalid.
|
* Marks the given message as valid or invalid.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: write.
|
* Locking: write.
|
||||||
*/
|
*/
|
||||||
void setMessageValidity(T txn, MessageId m, boolean valid)
|
void setMessageValid(T txn, MessageId m, boolean valid) throws DbException;
|
||||||
throws DbException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the reordering window for the given contact and transport in the
|
* Sets the reordering window for the given contact and transport in the
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import org.briarproject.api.event.EventBus;
|
|||||||
import org.briarproject.api.event.LocalSubscriptionsUpdatedEvent;
|
import org.briarproject.api.event.LocalSubscriptionsUpdatedEvent;
|
||||||
import org.briarproject.api.event.MessageAddedEvent;
|
import org.briarproject.api.event.MessageAddedEvent;
|
||||||
import org.briarproject.api.event.MessageRequestedEvent;
|
import org.briarproject.api.event.MessageRequestedEvent;
|
||||||
|
import org.briarproject.api.event.MessageSharedEvent;
|
||||||
import org.briarproject.api.event.MessageToAckEvent;
|
import org.briarproject.api.event.MessageToAckEvent;
|
||||||
import org.briarproject.api.event.MessageToRequestEvent;
|
import org.briarproject.api.event.MessageToRequestEvent;
|
||||||
import org.briarproject.api.event.MessageValidatedEvent;
|
import org.briarproject.api.event.MessageValidatedEvent;
|
||||||
@@ -47,6 +48,7 @@ import org.briarproject.api.sync.Offer;
|
|||||||
import org.briarproject.api.sync.Request;
|
import org.briarproject.api.sync.Request;
|
||||||
import org.briarproject.api.sync.SubscriptionAck;
|
import org.briarproject.api.sync.SubscriptionAck;
|
||||||
import org.briarproject.api.sync.SubscriptionUpdate;
|
import org.briarproject.api.sync.SubscriptionUpdate;
|
||||||
|
import org.briarproject.api.sync.ValidationManager.Validity;
|
||||||
import org.briarproject.api.transport.TransportKeys;
|
import org.briarproject.api.transport.TransportKeys;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -64,6 +66,8 @@ import java.util.logging.Logger;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.api.sync.ValidationManager.Validity.UNKNOWN;
|
||||||
|
import static org.briarproject.api.sync.ValidationManager.Validity.VALID;
|
||||||
import static org.briarproject.db.DatabaseConstants.MAX_OFFERED_MESSAGES;
|
import static org.briarproject.db.DatabaseConstants.MAX_OFFERED_MESSAGES;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -214,8 +218,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addLocalMessage(Message m, ClientId c, Metadata meta)
|
public void addLocalMessage(Message m, ClientId c, Metadata meta,
|
||||||
throws DbException {
|
boolean shared) throws DbException {
|
||||||
lock.writeLock().lock();
|
lock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
T txn = db.startTransaction();
|
T txn = db.startTransaction();
|
||||||
@@ -224,7 +228,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
throw new MessageExistsException();
|
throw new MessageExistsException();
|
||||||
if (!db.containsGroup(txn, m.getGroupId()))
|
if (!db.containsGroup(txn, m.getGroupId()))
|
||||||
throw new NoSuchSubscriptionException();
|
throw new NoSuchSubscriptionException();
|
||||||
addMessage(txn, m, null);
|
addMessage(txn, m, VALID, shared, null);
|
||||||
db.mergeMessageMetadata(txn, m.getId(), meta);
|
db.mergeMessageMetadata(txn, m.getId(), meta);
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
@@ -244,9 +248,9 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
* Locking: write.
|
* Locking: write.
|
||||||
* @param sender null for a locally generated message.
|
* @param sender null for a locally generated message.
|
||||||
*/
|
*/
|
||||||
private void addMessage(T txn, Message m, ContactId sender)
|
private void addMessage(T txn, Message m, Validity validity, boolean shared,
|
||||||
throws DbException {
|
ContactId sender) throws DbException {
|
||||||
db.addMessage(txn, m, sender == null);
|
db.addMessage(txn, m, validity, shared);
|
||||||
GroupId g = m.getGroupId();
|
GroupId g = m.getGroupId();
|
||||||
Collection<ContactId> visibility = db.getVisibility(txn, g);
|
Collection<ContactId> visibility = db.getVisibility(txn, g);
|
||||||
visibility = new HashSet<ContactId>(visibility);
|
visibility = new HashSet<ContactId>(visibility);
|
||||||
@@ -982,7 +986,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
duplicate = db.containsMessage(txn, m.getId());
|
duplicate = db.containsMessage(txn, m.getId());
|
||||||
visible = db.containsVisibleGroup(txn, c, m.getGroupId());
|
visible = db.containsVisibleGroup(txn, c, m.getGroupId());
|
||||||
if (visible) {
|
if (visible) {
|
||||||
if (!duplicate) addMessage(txn, m, c);
|
if (!duplicate) addMessage(txn, m, UNKNOWN, true, c);
|
||||||
db.raiseAckFlag(txn, c, m.getId());
|
db.raiseAckFlag(txn, c, m.getId());
|
||||||
}
|
}
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
@@ -1214,7 +1218,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMessageValidity(Message m, ClientId c, boolean valid)
|
public void setMessageShared(Message m, boolean shared)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
lock.writeLock().lock();
|
lock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
@@ -1222,7 +1226,27 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
try {
|
try {
|
||||||
if (!db.containsMessage(txn, m.getId()))
|
if (!db.containsMessage(txn, m.getId()))
|
||||||
throw new NoSuchMessageException();
|
throw new NoSuchMessageException();
|
||||||
db.setMessageValidity(txn, m.getId(), valid);
|
db.setMessageShared(txn, m.getId(), shared);
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} catch (DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
lock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
if (shared) eventBus.broadcast(new MessageSharedEvent(m));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessageValid(Message m, ClientId c, boolean valid)
|
||||||
|
throws DbException {
|
||||||
|
lock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
T txn = db.startTransaction();
|
||||||
|
try {
|
||||||
|
if (!db.containsMessage(txn, m.getId()))
|
||||||
|
throw new NoSuchMessageException();
|
||||||
|
db.setMessageValid(txn, m.getId(), valid);
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
db.abortTransaction(txn);
|
db.abortTransaction(txn);
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import org.briarproject.api.sync.MessageId;
|
|||||||
import org.briarproject.api.sync.MessageStatus;
|
import org.briarproject.api.sync.MessageStatus;
|
||||||
import org.briarproject.api.sync.SubscriptionAck;
|
import org.briarproject.api.sync.SubscriptionAck;
|
||||||
import org.briarproject.api.sync.SubscriptionUpdate;
|
import org.briarproject.api.sync.SubscriptionUpdate;
|
||||||
|
import org.briarproject.api.sync.ValidationManager.Validity;
|
||||||
import org.briarproject.api.system.Clock;
|
import org.briarproject.api.system.Clock;
|
||||||
import org.briarproject.api.transport.IncomingKeys;
|
import org.briarproject.api.transport.IncomingKeys;
|
||||||
import org.briarproject.api.transport.OutgoingKeys;
|
import org.briarproject.api.transport.OutgoingKeys;
|
||||||
@@ -54,9 +55,9 @@ import static java.util.logging.Level.WARNING;
|
|||||||
import static org.briarproject.api.db.Metadata.REMOVE;
|
import static org.briarproject.api.db.Metadata.REMOVE;
|
||||||
import static org.briarproject.api.db.StorageStatus.ADDING;
|
import static org.briarproject.api.db.StorageStatus.ADDING;
|
||||||
import static org.briarproject.api.sync.SyncConstants.MAX_SUBSCRIPTIONS;
|
import static org.briarproject.api.sync.SyncConstants.MAX_SUBSCRIPTIONS;
|
||||||
import static org.briarproject.api.sync.ValidationManager.Status.INVALID;
|
import static org.briarproject.api.sync.ValidationManager.Validity.INVALID;
|
||||||
import static org.briarproject.api.sync.ValidationManager.Status.UNKNOWN;
|
import static org.briarproject.api.sync.ValidationManager.Validity.UNKNOWN;
|
||||||
import static org.briarproject.api.sync.ValidationManager.Status.VALID;
|
import static org.briarproject.api.sync.ValidationManager.Validity.VALID;
|
||||||
import static org.briarproject.db.DatabaseConstants.DB_SETTINGS_NAMESPACE;
|
import static org.briarproject.db.DatabaseConstants.DB_SETTINGS_NAMESPACE;
|
||||||
import static org.briarproject.db.DatabaseConstants.DEVICE_ID_KEY;
|
import static org.briarproject.db.DatabaseConstants.DEVICE_ID_KEY;
|
||||||
import static org.briarproject.db.DatabaseConstants.DEVICE_SETTINGS_NAMESPACE;
|
import static org.briarproject.db.DatabaseConstants.DEVICE_SETTINGS_NAMESPACE;
|
||||||
@@ -70,8 +71,8 @@ import static org.briarproject.db.ExponentialBackoff.calculateExpiry;
|
|||||||
*/
|
*/
|
||||||
abstract class JdbcDatabase implements Database<Connection> {
|
abstract class JdbcDatabase implements Database<Connection> {
|
||||||
|
|
||||||
private static final int SCHEMA_VERSION = 18;
|
private static final int SCHEMA_VERSION = 19;
|
||||||
private static final int MIN_SCHEMA_VERSION = 18;
|
private static final int MIN_SCHEMA_VERSION = 19;
|
||||||
|
|
||||||
private static final String CREATE_SETTINGS =
|
private static final String CREATE_SETTINGS =
|
||||||
"CREATE TABLE settings"
|
"CREATE TABLE settings"
|
||||||
@@ -164,8 +165,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " (messageId HASH NOT NULL,"
|
+ " (messageId HASH NOT NULL,"
|
||||||
+ " groupId HASH NOT NULL,"
|
+ " groupId HASH NOT NULL,"
|
||||||
+ " timestamp BIGINT NOT NULL,"
|
+ " timestamp BIGINT NOT NULL,"
|
||||||
+ " local BOOLEAN NOT NULL,"
|
|
||||||
+ " valid INT NOT NULL,"
|
+ " valid INT NOT NULL,"
|
||||||
|
+ " shared BOOLEAN NOT NULL,"
|
||||||
+ " length INT NOT NULL,"
|
+ " length INT NOT NULL,"
|
||||||
+ " raw BLOB NOT NULL,"
|
+ " raw BLOB NOT NULL,"
|
||||||
+ " PRIMARY KEY (messageId),"
|
+ " PRIMARY KEY (messageId),"
|
||||||
@@ -674,19 +675,19 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addMessage(Connection txn, Message m, boolean local)
|
public void addMessage(Connection txn, Message m, Validity validity,
|
||||||
throws DbException {
|
boolean shared) throws DbException {
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
try {
|
try {
|
||||||
String sql = "INSERT INTO messages (messageId, groupId, timestamp,"
|
String sql = "INSERT INTO messages (messageId, groupId, timestamp,"
|
||||||
+ " local, valid, length, raw)"
|
+ " valid, shared, length, raw)"
|
||||||
+ " VALUES (?, ?, ?, ?, ?, ?, ?)";
|
+ " VALUES (?, ?, ?, ?, ?, ?, ?)";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setBytes(1, m.getId().getBytes());
|
ps.setBytes(1, m.getId().getBytes());
|
||||||
ps.setBytes(2, m.getGroupId().getBytes());
|
ps.setBytes(2, m.getGroupId().getBytes());
|
||||||
ps.setLong(3, m.getTimestamp());
|
ps.setLong(3, m.getTimestamp());
|
||||||
ps.setBoolean(4, local);
|
ps.setInt(4, validity.getValue());
|
||||||
ps.setInt(5, local ? VALID.getValue() : UNKNOWN.getValue());
|
ps.setBoolean(5, shared);
|
||||||
byte[] raw = m.getRaw();
|
byte[] raw = m.getRaw();
|
||||||
ps.setInt(6, raw.length);
|
ps.setInt(6, raw.length);
|
||||||
ps.setBytes(7, raw);
|
ps.setBytes(7, raw);
|
||||||
@@ -1031,7 +1032,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " JOIN groupVisibilities AS gv"
|
+ " JOIN groupVisibilities AS gv"
|
||||||
+ " ON m.groupId = gv.groupId"
|
+ " ON m.groupId = gv.groupId"
|
||||||
+ " WHERE messageId = ?"
|
+ " WHERE messageId = ?"
|
||||||
+ " AND contactId = ?";
|
+ " AND contactId = ?"
|
||||||
|
+ " AND shared = TRUE";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setBytes(1, m.getBytes());
|
ps.setBytes(1, m.getBytes());
|
||||||
ps.setInt(2, c.getInt());
|
ps.setInt(2, c.getInt());
|
||||||
@@ -1482,7 +1484,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " ON m.messageId = s.messageId"
|
+ " ON m.messageId = s.messageId"
|
||||||
+ " AND cg.contactId = s.contactId"
|
+ " AND cg.contactId = s.contactId"
|
||||||
+ " WHERE cg.contactId = ?"
|
+ " WHERE cg.contactId = ?"
|
||||||
+ " AND valid = ?"
|
+ " AND valid = ? AND shared = TRUE"
|
||||||
+ " AND seen = FALSE AND requested = FALSE"
|
+ " AND seen = FALSE AND requested = FALSE"
|
||||||
+ " AND s.expiry < ?"
|
+ " AND s.expiry < ?"
|
||||||
+ " ORDER BY timestamp DESC LIMIT ?";
|
+ " ORDER BY timestamp DESC LIMIT ?";
|
||||||
@@ -1544,7 +1546,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " ON m.messageId = s.messageId"
|
+ " ON m.messageId = s.messageId"
|
||||||
+ " AND cg.contactId = s.contactId"
|
+ " AND cg.contactId = s.contactId"
|
||||||
+ " WHERE cg.contactId = ?"
|
+ " WHERE cg.contactId = ?"
|
||||||
+ " AND valid = ?"
|
+ " AND valid = ? AND shared = TRUE"
|
||||||
+ " AND seen = FALSE"
|
+ " AND seen = FALSE"
|
||||||
+ " AND s.expiry < ?"
|
+ " AND s.expiry < ?"
|
||||||
+ " ORDER BY timestamp DESC";
|
+ " ORDER BY timestamp DESC";
|
||||||
@@ -1633,7 +1635,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " ON m.messageId = s.messageId"
|
+ " ON m.messageId = s.messageId"
|
||||||
+ " AND cg.contactId = s.contactId"
|
+ " AND cg.contactId = s.contactId"
|
||||||
+ " WHERE cg.contactId = ?"
|
+ " WHERE cg.contactId = ?"
|
||||||
+ " AND valid = ?"
|
+ " AND valid = ? AND shared = TRUE"
|
||||||
+ " AND seen = FALSE AND requested = TRUE"
|
+ " AND seen = FALSE AND requested = TRUE"
|
||||||
+ " AND s.expiry < ?"
|
+ " AND s.expiry < ?"
|
||||||
+ " ORDER BY timestamp DESC";
|
+ " ORDER BY timestamp DESC";
|
||||||
@@ -1660,7 +1662,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Settings getSettings(Connection txn, String namespace) throws DbException {
|
public Settings getSettings(Connection txn, String namespace)
|
||||||
|
throws DbException {
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
try {
|
try {
|
||||||
@@ -2397,7 +2400,24 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMessageValidity(Connection txn, MessageId m, boolean valid)
|
public void setMessageShared(Connection txn, MessageId m, boolean shared)
|
||||||
|
throws DbException {
|
||||||
|
PreparedStatement ps = null;
|
||||||
|
try {
|
||||||
|
String sql = "UPDATE messages SET shared = ? WHERE messageId = ?";
|
||||||
|
ps = txn.prepareStatement(sql);
|
||||||
|
ps.setBoolean(1, shared);
|
||||||
|
ps.setBytes(2, m.getBytes());
|
||||||
|
int affected = ps.executeUpdate();
|
||||||
|
if (affected < 0) throw new DbStateException();
|
||||||
|
ps.close();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
tryToClose(ps);
|
||||||
|
throw new DbException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessageValid(Connection txn, MessageId m, boolean valid)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ class ForumManagerImpl implements ForumManager {
|
|||||||
d.put("read", true);
|
d.put("read", true);
|
||||||
try {
|
try {
|
||||||
Metadata meta = metadataEncoder.encode(d);
|
Metadata meta = metadataEncoder.encode(d);
|
||||||
db.addLocalMessage(p.getMessage(), CLIENT_ID, meta);
|
db.addLocalMessage(p.getMessage(), CLIENT_ID, meta, true);
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ class MessagingManagerImpl implements MessagingManager, AddContactHook,
|
|||||||
d.put("read", true);
|
d.put("read", true);
|
||||||
try {
|
try {
|
||||||
Metadata meta = metadataEncoder.encode(d);
|
Metadata meta = metadataEncoder.encode(d);
|
||||||
db.addLocalMessage(m.getMessage(), CLIENT_ID, meta);
|
db.addLocalMessage(m.getMessage(), CLIENT_ID, meta, true);
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
|
|||||||
d.put("transportId", t.getString());
|
d.put("transportId", t.getString());
|
||||||
d.put("version", version);
|
d.put("version", version);
|
||||||
d.put("local", true);
|
d.put("local", true);
|
||||||
db.addLocalMessage(m, CLIENT_ID, metadataEncoder.encode(d));
|
db.addLocalMessage(m, CLIENT_ID, metadataEncoder.encode(d), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] encodeProperties(DeviceId dev, TransportId t,
|
private byte[] encodeProperties(DeviceId dev, TransportId t,
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import org.briarproject.api.event.EventBus;
|
|||||||
import org.briarproject.api.event.EventListener;
|
import org.briarproject.api.event.EventListener;
|
||||||
import org.briarproject.api.event.LocalSubscriptionsUpdatedEvent;
|
import org.briarproject.api.event.LocalSubscriptionsUpdatedEvent;
|
||||||
import org.briarproject.api.event.MessageRequestedEvent;
|
import org.briarproject.api.event.MessageRequestedEvent;
|
||||||
|
import org.briarproject.api.event.MessageSharedEvent;
|
||||||
import org.briarproject.api.event.MessageToAckEvent;
|
import org.briarproject.api.event.MessageToAckEvent;
|
||||||
import org.briarproject.api.event.MessageToRequestEvent;
|
import org.briarproject.api.event.MessageToRequestEvent;
|
||||||
import org.briarproject.api.event.MessageValidatedEvent;
|
import org.briarproject.api.event.MessageValidatedEvent;
|
||||||
@@ -154,6 +155,8 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
|
|||||||
if (e instanceof ContactRemovedEvent) {
|
if (e instanceof ContactRemovedEvent) {
|
||||||
ContactRemovedEvent c = (ContactRemovedEvent) e;
|
ContactRemovedEvent c = (ContactRemovedEvent) e;
|
||||||
if (c.getContactId().equals(contactId)) interrupt();
|
if (c.getContactId().equals(contactId)) interrupt();
|
||||||
|
} else if (e instanceof MessageSharedEvent) {
|
||||||
|
dbExecutor.execute(new GenerateOffer());
|
||||||
} else if (e instanceof MessageValidatedEvent) {
|
} else if (e instanceof MessageValidatedEvent) {
|
||||||
if (((MessageValidatedEvent) e).isValid())
|
if (((MessageValidatedEvent) e).isValid())
|
||||||
dbExecutor.execute(new GenerateOffer());
|
dbExecutor.execute(new GenerateOffer());
|
||||||
|
|||||||
@@ -117,10 +117,10 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
|||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
if (meta == null) {
|
if (meta == null) {
|
||||||
db.setMessageValidity(m, c, false);
|
db.setMessageValid(m, c, false);
|
||||||
} else {
|
} else {
|
||||||
db.mergeMessageMetadata(m.getId(), meta);
|
db.mergeMessageMetadata(m.getId(), meta);
|
||||||
db.setMessageValidity(m, c, true);
|
db.setMessageValid(m, c, true);
|
||||||
}
|
}
|
||||||
} catch (NoSuchMessageException e) {
|
} catch (NoSuchMessageException e) {
|
||||||
LOG.info("Message removed during validation");
|
LOG.info("Message removed during validation");
|
||||||
|
|||||||
@@ -53,6 +53,8 @@ import java.util.Collections;
|
|||||||
|
|
||||||
import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
||||||
import static org.briarproject.api.sync.SyncConstants.MAX_GROUP_DESCRIPTOR_LENGTH;
|
import static org.briarproject.api.sync.SyncConstants.MAX_GROUP_DESCRIPTOR_LENGTH;
|
||||||
|
import static org.briarproject.api.sync.ValidationManager.Validity.UNKNOWN;
|
||||||
|
import static org.briarproject.api.sync.ValidationManager.Validity.VALID;
|
||||||
import static org.briarproject.db.DatabaseConstants.MAX_OFFERED_MESSAGES;
|
import static org.briarproject.db.DatabaseConstants.MAX_OFFERED_MESSAGES;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
@@ -211,7 +213,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
|
|||||||
shutdown);
|
shutdown);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
db.addLocalMessage(message, clientId, metadata);
|
db.addLocalMessage(message, clientId, metadata, true);
|
||||||
fail();
|
fail();
|
||||||
} catch (MessageExistsException expected) {
|
} catch (MessageExistsException expected) {
|
||||||
// Expected
|
// Expected
|
||||||
@@ -241,7 +243,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
|
|||||||
shutdown);
|
shutdown);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
db.addLocalMessage(message, clientId, metadata);
|
db.addLocalMessage(message, clientId, metadata, true);
|
||||||
fail();
|
fail();
|
||||||
} catch (NoSuchSubscriptionException expected) {
|
} catch (NoSuchSubscriptionException expected) {
|
||||||
// Expected
|
// Expected
|
||||||
@@ -264,7 +266,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
|
|||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
oneOf(database).containsGroup(txn, groupId);
|
oneOf(database).containsGroup(txn, groupId);
|
||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
oneOf(database).addMessage(txn, message, true);
|
oneOf(database).addMessage(txn, message, VALID, true);
|
||||||
oneOf(database).mergeMessageMetadata(txn, messageId, metadata);
|
oneOf(database).mergeMessageMetadata(txn, messageId, metadata);
|
||||||
oneOf(database).getVisibility(txn, groupId);
|
oneOf(database).getVisibility(txn, groupId);
|
||||||
will(returnValue(Collections.singletonList(contactId)));
|
will(returnValue(Collections.singletonList(contactId)));
|
||||||
@@ -281,7 +283,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
|
|||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
shutdown);
|
shutdown);
|
||||||
|
|
||||||
db.addLocalMessage(message, clientId, metadata);
|
db.addLocalMessage(message, clientId, metadata, true);
|
||||||
|
|
||||||
context.assertIsSatisfied();
|
context.assertIsSatisfied();
|
||||||
}
|
}
|
||||||
@@ -559,11 +561,11 @@ public class DatabaseComponentImplTest extends BriarTestCase {
|
|||||||
final EventBus eventBus = context.mock(EventBus.class);
|
final EventBus eventBus = context.mock(EventBus.class);
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// Check whether the message is in the DB (which it's not)
|
// Check whether the message is in the DB (which it's not)
|
||||||
exactly(4).of(database).startTransaction();
|
exactly(6).of(database).startTransaction();
|
||||||
will(returnValue(txn));
|
will(returnValue(txn));
|
||||||
exactly(4).of(database).containsMessage(txn, messageId);
|
exactly(6).of(database).containsMessage(txn, messageId);
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
exactly(4).of(database).abortTransaction(txn);
|
exactly(6).of(database).abortTransaction(txn);
|
||||||
// This is needed for getMessageStatus() to proceed
|
// This is needed for getMessageStatus() to proceed
|
||||||
exactly(1).of(database).containsContact(txn, contactId);
|
exactly(1).of(database).containsContact(txn, contactId);
|
||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
@@ -599,6 +601,20 @@ public class DatabaseComponentImplTest extends BriarTestCase {
|
|||||||
// Expected
|
// Expected
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
db.setMessageShared(message, true);
|
||||||
|
fail();
|
||||||
|
} catch (NoSuchMessageException expected) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
db.setMessageValid(message, clientId, true);
|
||||||
|
fail();
|
||||||
|
} catch (NoSuchMessageException expected) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
|
||||||
context.assertIsSatisfied();
|
context.assertIsSatisfied();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -932,7 +948,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
|
|||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
oneOf(database).containsVisibleGroup(txn, contactId, groupId);
|
oneOf(database).containsVisibleGroup(txn, contactId, groupId);
|
||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
oneOf(database).addMessage(txn, message, false);
|
oneOf(database).addMessage(txn, message, UNKNOWN, true);
|
||||||
oneOf(database).getVisibility(txn, groupId);
|
oneOf(database).getVisibility(txn, groupId);
|
||||||
will(returnValue(Collections.singletonList(contactId)));
|
will(returnValue(Collections.singletonList(contactId)));
|
||||||
oneOf(database).getContactIds(txn);
|
oneOf(database).getContactIds(txn);
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
@@ -47,6 +46,8 @@ import static org.briarproject.api.db.Metadata.REMOVE;
|
|||||||
import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
||||||
import static org.briarproject.api.sync.SyncConstants.MAX_GROUP_DESCRIPTOR_LENGTH;
|
import static org.briarproject.api.sync.SyncConstants.MAX_GROUP_DESCRIPTOR_LENGTH;
|
||||||
import static org.briarproject.api.sync.SyncConstants.MAX_MESSAGE_LENGTH;
|
import static org.briarproject.api.sync.SyncConstants.MAX_MESSAGE_LENGTH;
|
||||||
|
import static org.briarproject.api.sync.ValidationManager.Validity.UNKNOWN;
|
||||||
|
import static org.briarproject.api.sync.ValidationManager.Validity.VALID;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
@@ -113,7 +114,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
db.addGroup(txn, group);
|
db.addGroup(txn, group);
|
||||||
assertTrue(db.containsGroup(txn, groupId));
|
assertTrue(db.containsGroup(txn, groupId));
|
||||||
assertFalse(db.containsMessage(txn, messageId));
|
assertFalse(db.containsMessage(txn, messageId));
|
||||||
db.addMessage(txn, message, true);
|
db.addMessage(txn, message, VALID, true);
|
||||||
assertTrue(db.containsMessage(txn, messageId));
|
assertTrue(db.containsMessage(txn, messageId));
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
db.close();
|
db.close();
|
||||||
@@ -126,6 +127,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
assertTrue(db.containsMessage(txn, messageId));
|
assertTrue(db.containsMessage(txn, messageId));
|
||||||
byte[] raw1 = db.getRawMessage(txn, messageId);
|
byte[] raw1 = db.getRawMessage(txn, messageId);
|
||||||
assertArrayEquals(raw, raw1);
|
assertArrayEquals(raw, raw1);
|
||||||
|
|
||||||
// Delete the records
|
// Delete the records
|
||||||
db.removeMessage(txn, messageId);
|
db.removeMessage(txn, messageId);
|
||||||
db.removeContact(txn, contactId);
|
db.removeContact(txn, contactId);
|
||||||
@@ -150,7 +152,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
|
|
||||||
// Subscribe to a group and store a message
|
// Subscribe to a group and store a message
|
||||||
db.addGroup(txn, group);
|
db.addGroup(txn, group);
|
||||||
db.addMessage(txn, message, true);
|
db.addMessage(txn, message, VALID, true);
|
||||||
|
|
||||||
// Unsubscribing from the group should remove the message
|
// Unsubscribing from the group should remove the message
|
||||||
assertTrue(db.containsMessage(txn, messageId));
|
assertTrue(db.containsMessage(txn, messageId));
|
||||||
@@ -172,26 +174,106 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
db.addGroup(txn, group);
|
db.addGroup(txn, group);
|
||||||
db.addVisibility(txn, contactId, groupId);
|
db.addVisibility(txn, contactId, groupId);
|
||||||
db.setGroups(txn, contactId, Collections.singletonList(group), 1);
|
db.setGroups(txn, contactId, Collections.singletonList(group), 1);
|
||||||
db.addMessage(txn, message, true);
|
db.addMessage(txn, message, VALID, true);
|
||||||
|
|
||||||
// The message has no status yet, so it should not be sendable
|
// The message has no status yet, so it should not be sendable
|
||||||
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
||||||
ONE_MEGABYTE);
|
ONE_MEGABYTE);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
|
ids = db.getMessagesToOffer(txn, contactId, 100);
|
||||||
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
// Adding a status with seen = false should make the message sendable
|
// Adding a status with seen = false should make the message sendable
|
||||||
db.addStatus(txn, contactId, messageId, false, false);
|
db.addStatus(txn, contactId, messageId, false, false);
|
||||||
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
||||||
assertFalse(ids.isEmpty());
|
assertEquals(Collections.singletonList(messageId), ids);
|
||||||
Iterator<MessageId> it = ids.iterator();
|
ids = db.getMessagesToOffer(txn, contactId, 100);
|
||||||
assertTrue(it.hasNext());
|
assertEquals(Collections.singletonList(messageId), ids);
|
||||||
assertEquals(messageId, it.next());
|
|
||||||
assertFalse(it.hasNext());
|
|
||||||
|
|
||||||
// Changing the status to seen = true should make the message unsendable
|
// Changing the status to seen = true should make the message unsendable
|
||||||
db.raiseSeenFlag(txn, contactId, messageId);
|
db.raiseSeenFlag(txn, contactId, messageId);
|
||||||
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
|
ids = db.getMessagesToOffer(txn, contactId, 100);
|
||||||
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSendableMessagesMustBeValid() throws Exception {
|
||||||
|
Database<Connection> db = open(false);
|
||||||
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
|
// Add a contact, subscribe to a group and store an unvalidated message
|
||||||
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
|
||||||
|
db.addGroup(txn, group);
|
||||||
|
db.addVisibility(txn, contactId, groupId);
|
||||||
|
db.setGroups(txn, contactId, Collections.singletonList(group), 1);
|
||||||
|
db.addMessage(txn, message, UNKNOWN, true);
|
||||||
|
db.addStatus(txn, contactId, messageId, false, false);
|
||||||
|
|
||||||
|
// The message has not been validated, so it should not be sendable
|
||||||
|
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
||||||
|
ONE_MEGABYTE);
|
||||||
|
assertTrue(ids.isEmpty());
|
||||||
|
ids = db.getMessagesToOffer(txn, contactId, 100);
|
||||||
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
|
// Marking the message valid should make it sendable
|
||||||
|
db.setMessageValid(txn, messageId, true);
|
||||||
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
||||||
|
assertEquals(Collections.singletonList(messageId), ids);
|
||||||
|
ids = db.getMessagesToOffer(txn, contactId, 100);
|
||||||
|
assertEquals(Collections.singletonList(messageId), ids);
|
||||||
|
|
||||||
|
// Marking the message invalid should make it unsendable
|
||||||
|
db.setMessageValid(txn, messageId, false);
|
||||||
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
||||||
|
assertTrue(ids.isEmpty());
|
||||||
|
ids = db.getMessagesToOffer(txn, contactId, 100);
|
||||||
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSendableMessagesMustBeShared() throws Exception {
|
||||||
|
Database<Connection> db = open(false);
|
||||||
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
|
// Add a contact, subscribe to a group and store an unshared message
|
||||||
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
|
||||||
|
db.addGroup(txn, group);
|
||||||
|
db.addVisibility(txn, contactId, groupId);
|
||||||
|
db.setGroups(txn, contactId, Collections.singletonList(group), 1);
|
||||||
|
db.addMessage(txn, message, VALID, false);
|
||||||
|
db.addStatus(txn, contactId, messageId, false, false);
|
||||||
|
|
||||||
|
// The message is not shared, so it should not be sendable
|
||||||
|
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
||||||
|
ONE_MEGABYTE);
|
||||||
|
assertTrue(ids.isEmpty());
|
||||||
|
ids = db.getMessagesToOffer(txn, contactId, 100);
|
||||||
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
|
// Sharing the message should make it sendable
|
||||||
|
db.setMessageShared(txn, messageId, true);
|
||||||
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
||||||
|
assertEquals(Collections.singletonList(messageId), ids);
|
||||||
|
ids = db.getMessagesToOffer(txn, contactId, 100);
|
||||||
|
assertEquals(Collections.singletonList(messageId), ids);
|
||||||
|
|
||||||
|
// Unsharing the message should make it unsendable
|
||||||
|
db.setMessageShared(txn, messageId, false);
|
||||||
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
||||||
|
assertTrue(ids.isEmpty());
|
||||||
|
ids = db.getMessagesToOffer(txn, contactId, 100);
|
||||||
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
db.close();
|
db.close();
|
||||||
@@ -207,27 +289,29 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
|
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
|
||||||
db.addGroup(txn, group);
|
db.addGroup(txn, group);
|
||||||
db.addVisibility(txn, contactId, groupId);
|
db.addVisibility(txn, contactId, groupId);
|
||||||
db.addMessage(txn, message, true);
|
db.addMessage(txn, message, VALID, true);
|
||||||
db.addStatus(txn, contactId, messageId, false, false);
|
db.addStatus(txn, contactId, messageId, false, false);
|
||||||
|
|
||||||
// The contact is not subscribed, so the message should not be sendable
|
// The contact is not subscribed, so the message should not be sendable
|
||||||
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
||||||
ONE_MEGABYTE);
|
ONE_MEGABYTE);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
|
ids = db.getMessagesToOffer(txn, contactId, 100);
|
||||||
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
// The contact subscribing should make the message sendable
|
// The contact subscribing should make the message sendable
|
||||||
db.setGroups(txn, contactId, Collections.singletonList(group), 1);
|
db.setGroups(txn, contactId, Collections.singletonList(group), 1);
|
||||||
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
||||||
assertFalse(ids.isEmpty());
|
assertEquals(Collections.singletonList(messageId), ids);
|
||||||
Iterator<MessageId> it = ids.iterator();
|
ids = db.getMessagesToOffer(txn, contactId, 100);
|
||||||
assertTrue(it.hasNext());
|
assertEquals(Collections.singletonList(messageId), ids);
|
||||||
assertEquals(messageId, it.next());
|
|
||||||
assertFalse(it.hasNext());
|
|
||||||
|
|
||||||
// The contact unsubscribing should make the message unsendable
|
// The contact unsubscribing should make the message unsendable
|
||||||
db.setGroups(txn, contactId, Collections.<Group>emptyList(), 2);
|
db.setGroups(txn, contactId, Collections.<Group>emptyList(), 2);
|
||||||
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
|
ids = db.getMessagesToOffer(txn, contactId, 100);
|
||||||
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
db.close();
|
db.close();
|
||||||
@@ -244,7 +328,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
db.addGroup(txn, group);
|
db.addGroup(txn, group);
|
||||||
db.addVisibility(txn, contactId, groupId);
|
db.addVisibility(txn, contactId, groupId);
|
||||||
db.setGroups(txn, contactId, Collections.singletonList(group), 1);
|
db.setGroups(txn, contactId, Collections.singletonList(group), 1);
|
||||||
db.addMessage(txn, message, true);
|
db.addMessage(txn, message, VALID, true);
|
||||||
db.addStatus(txn, contactId, messageId, false, false);
|
db.addStatus(txn, contactId, messageId, false, false);
|
||||||
|
|
||||||
// The message is sendable, but too large to send
|
// The message is sendable, but too large to send
|
||||||
@@ -254,11 +338,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
|
|
||||||
// The message is just the right size to send
|
// The message is just the right size to send
|
||||||
ids = db.getMessagesToSend(txn, contactId, size);
|
ids = db.getMessagesToSend(txn, contactId, size);
|
||||||
assertFalse(ids.isEmpty());
|
assertEquals(Collections.singletonList(messageId), ids);
|
||||||
Iterator<MessageId> it = ids.iterator();
|
|
||||||
assertTrue(it.hasNext());
|
|
||||||
assertEquals(messageId, it.next());
|
|
||||||
assertFalse(it.hasNext());
|
|
||||||
|
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
db.close();
|
db.close();
|
||||||
@@ -274,7 +354,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
|
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
|
||||||
db.addGroup(txn, group);
|
db.addGroup(txn, group);
|
||||||
db.setGroups(txn, contactId, Collections.singletonList(group), 1);
|
db.setGroups(txn, contactId, Collections.singletonList(group), 1);
|
||||||
db.addMessage(txn, message, true);
|
db.addMessage(txn, message, VALID, true);
|
||||||
db.addStatus(txn, contactId, messageId, false, false);
|
db.addStatus(txn, contactId, messageId, false, false);
|
||||||
|
|
||||||
// The subscription is not visible to the contact, so the message
|
// The subscription is not visible to the contact, so the message
|
||||||
@@ -282,15 +362,22 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
||||||
ONE_MEGABYTE);
|
ONE_MEGABYTE);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
|
ids = db.getMessagesToOffer(txn, contactId, 100);
|
||||||
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
// Making the subscription visible should make the message sendable
|
// Making the subscription visible should make the message sendable
|
||||||
db.addVisibility(txn, contactId, groupId);
|
db.addVisibility(txn, contactId, groupId);
|
||||||
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
||||||
assertFalse(ids.isEmpty());
|
assertEquals(Collections.singletonList(messageId), ids);
|
||||||
Iterator<MessageId> it = ids.iterator();
|
ids = db.getMessagesToOffer(txn, contactId, 100);
|
||||||
assertTrue(it.hasNext());
|
assertEquals(Collections.singletonList(messageId), ids);
|
||||||
assertEquals(messageId, it.next());
|
|
||||||
assertFalse(it.hasNext());
|
// Making the subscription invisible should make the message unsendable
|
||||||
|
db.removeVisibility(txn, contactId, groupId);
|
||||||
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
||||||
|
assertTrue(ids.isEmpty());
|
||||||
|
ids = db.getMessagesToOffer(txn, contactId, 100);
|
||||||
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
db.close();
|
db.close();
|
||||||
@@ -310,16 +397,16 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
// Add some messages to ack
|
// Add some messages to ack
|
||||||
MessageId messageId1 = new MessageId(TestUtils.getRandomId());
|
MessageId messageId1 = new MessageId(TestUtils.getRandomId());
|
||||||
Message message1 = new Message(messageId1, groupId, timestamp, raw);
|
Message message1 = new Message(messageId1, groupId, timestamp, raw);
|
||||||
db.addMessage(txn, message, true);
|
db.addMessage(txn, message, VALID, true);
|
||||||
db.addStatus(txn, contactId, messageId, false, true);
|
db.addStatus(txn, contactId, messageId, false, true);
|
||||||
db.raiseAckFlag(txn, contactId, messageId);
|
db.raiseAckFlag(txn, contactId, messageId);
|
||||||
db.addMessage(txn, message1, true);
|
db.addMessage(txn, message1, VALID, true);
|
||||||
db.addStatus(txn, contactId, messageId1, false, true);
|
db.addStatus(txn, contactId, messageId1, false, true);
|
||||||
db.raiseAckFlag(txn, contactId, messageId1);
|
db.raiseAckFlag(txn, contactId, messageId1);
|
||||||
|
|
||||||
// Both message IDs should be returned
|
// Both message IDs should be returned
|
||||||
Collection<MessageId> ids = Arrays.asList(messageId, messageId1);
|
Collection<MessageId> ids = db.getMessagesToAck(txn, contactId, 1234);
|
||||||
assertEquals(ids, db.getMessagesToAck(txn, contactId, 1234));
|
assertEquals(Arrays.asList(messageId, messageId1), ids);
|
||||||
|
|
||||||
// Remove both message IDs
|
// Remove both message IDs
|
||||||
db.lowerAckFlag(txn, contactId, Arrays.asList(messageId, messageId1));
|
db.lowerAckFlag(txn, contactId, Arrays.asList(messageId, messageId1));
|
||||||
@@ -332,38 +419,6 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testDuplicateMessageReceived() throws Exception {
|
|
||||||
Database<Connection> db = open(false);
|
|
||||||
Connection txn = db.startTransaction();
|
|
||||||
|
|
||||||
// Add a contact and subscribe to a group
|
|
||||||
db.addLocalAuthor(txn, localAuthor);
|
|
||||||
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
|
|
||||||
db.addGroup(txn, group);
|
|
||||||
db.setGroups(txn, contactId, Collections.singletonList(group), 1);
|
|
||||||
|
|
||||||
// Receive the same message twice
|
|
||||||
db.addMessage(txn, message, true);
|
|
||||||
db.addStatus(txn, contactId, messageId, false, true);
|
|
||||||
db.raiseAckFlag(txn, contactId, messageId);
|
|
||||||
db.raiseAckFlag(txn, contactId, messageId);
|
|
||||||
|
|
||||||
// The message ID should only be returned once
|
|
||||||
Collection<MessageId> ids = db.getMessagesToAck(txn, contactId, 1234);
|
|
||||||
assertEquals(Collections.singletonList(messageId), ids);
|
|
||||||
|
|
||||||
// Remove the message ID
|
|
||||||
db.lowerAckFlag(txn, contactId, Collections.singletonList(messageId));
|
|
||||||
|
|
||||||
// The message ID should have been removed
|
|
||||||
assertEquals(Collections.emptyList(), db.getMessagesToAck(txn,
|
|
||||||
contactId, 1234));
|
|
||||||
|
|
||||||
db.commitTransaction(txn);
|
|
||||||
db.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOutstandingMessageAcked() throws Exception {
|
public void testOutstandingMessageAcked() throws Exception {
|
||||||
Database<Connection> db = open(false);
|
Database<Connection> db = open(false);
|
||||||
@@ -375,27 +430,25 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
db.addGroup(txn, group);
|
db.addGroup(txn, group);
|
||||||
db.addVisibility(txn, contactId, groupId);
|
db.addVisibility(txn, contactId, groupId);
|
||||||
db.setGroups(txn, contactId, Collections.singletonList(group), 1);
|
db.setGroups(txn, contactId, Collections.singletonList(group), 1);
|
||||||
db.addMessage(txn, message, true);
|
db.addMessage(txn, message, VALID, true);
|
||||||
db.addStatus(txn, contactId, messageId, false, false);
|
db.addStatus(txn, contactId, messageId, false, false);
|
||||||
|
|
||||||
// Retrieve the message from the database and mark it as sent
|
// Retrieve the message from the database and mark it as sent
|
||||||
Iterator<MessageId> it =
|
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
||||||
db.getMessagesToSend(txn, contactId, ONE_MEGABYTE).iterator();
|
ONE_MEGABYTE);
|
||||||
assertTrue(it.hasNext());
|
assertEquals(Collections.singletonList(messageId), ids);
|
||||||
assertEquals(messageId, it.next());
|
|
||||||
assertFalse(it.hasNext());
|
|
||||||
db.updateExpiryTime(txn, contactId, messageId, Integer.MAX_VALUE);
|
db.updateExpiryTime(txn, contactId, messageId, Integer.MAX_VALUE);
|
||||||
|
|
||||||
// The message should no longer be sendable
|
// The message should no longer be sendable
|
||||||
it = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE).iterator();
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
||||||
assertFalse(it.hasNext());
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
// Pretend that the message was acked
|
// Pretend that the message was acked
|
||||||
db.raiseSeenFlag(txn, contactId, messageId);
|
db.raiseSeenFlag(txn, contactId, messageId);
|
||||||
|
|
||||||
// The message still should not be sendable
|
// The message still should not be sendable
|
||||||
it = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE).iterator();
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
||||||
assertFalse(it.hasNext());
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
db.close();
|
db.close();
|
||||||
@@ -419,7 +472,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
// Storing a message should reduce the free space
|
// Storing a message should reduce the free space
|
||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
db.addGroup(txn, group);
|
db.addGroup(txn, group);
|
||||||
db.addMessage(txn, message, true);
|
db.addMessage(txn, message, VALID, true);
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
assertTrue(db.getFreeSpace() < free);
|
assertTrue(db.getFreeSpace() < free);
|
||||||
|
|
||||||
@@ -579,7 +632,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
|
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
|
||||||
db.addGroup(txn, group);
|
db.addGroup(txn, group);
|
||||||
db.setGroups(txn, contactId, Collections.singletonList(group), 1);
|
db.setGroups(txn, contactId, Collections.singletonList(group), 1);
|
||||||
db.addMessage(txn, message, true);
|
db.addMessage(txn, message, VALID, true);
|
||||||
db.addStatus(txn, contactId, messageId, false, false);
|
db.addStatus(txn, contactId, messageId, false, false);
|
||||||
|
|
||||||
// The subscription is not visible
|
// The subscription is not visible
|
||||||
@@ -904,7 +957,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
db.addVisibility(txn, contactId, groupId);
|
db.addVisibility(txn, contactId, groupId);
|
||||||
|
|
||||||
// Add a message - it should be sendable to the contact
|
// Add a message - it should be sendable to the contact
|
||||||
db.addMessage(txn, message, true);
|
db.addMessage(txn, message, VALID, true);
|
||||||
db.addStatus(txn, contactId, messageId, false, false);
|
db.addStatus(txn, contactId, messageId, false, false);
|
||||||
Collection<MessageId> sendable = db.getMessagesToSend(txn, contactId,
|
Collection<MessageId> sendable = db.getMessagesToSend(txn, contactId,
|
||||||
ONE_MEGABYTE);
|
ONE_MEGABYTE);
|
||||||
@@ -974,7 +1027,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
|
|
||||||
// Add a group and a message
|
// Add a group and a message
|
||||||
db.addGroup(txn, group);
|
db.addGroup(txn, group);
|
||||||
db.addMessage(txn, message, true);
|
db.addMessage(txn, message, VALID, true);
|
||||||
|
|
||||||
// Attach some metadata to the message
|
// Attach some metadata to the message
|
||||||
Metadata metadata = new Metadata();
|
Metadata metadata = new Metadata();
|
||||||
@@ -1042,7 +1095,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
db.addVisibility(txn, contactId, groupId);
|
db.addVisibility(txn, contactId, groupId);
|
||||||
|
|
||||||
// Add a message to the group
|
// Add a message to the group
|
||||||
db.addMessage(txn, message, true);
|
db.addMessage(txn, message, VALID, true);
|
||||||
db.addStatus(txn, contactId, messageId, false, false);
|
db.addStatus(txn, contactId, messageId, false, false);
|
||||||
|
|
||||||
// The message should not be sent or seen
|
// The message should not be sent or seen
|
||||||
|
|||||||
Reference in New Issue
Block a user