mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-14 19:59:05 +01:00
Replaced the Status enum with a seen flag and an expiry time.
This commit is contained in:
@@ -104,12 +104,13 @@ interface Database<T> {
|
|||||||
void addMessageToAck(T txn, ContactId c, MessageId m) throws DbException;
|
void addMessageToAck(T txn, ContactId c, MessageId m) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Records a collection of sent messages as needing to be acknowledged.
|
* Records the given messages as needing to be acknowledged by the given
|
||||||
|
* expiry time.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: contact read, message write.
|
* Locking: contact read, message write.
|
||||||
*/
|
*/
|
||||||
void addOutstandingMessages(T txn, ContactId c, Collection<MessageId> sent)
|
void addOutstandingMessages(T txn, ContactId c, Collection<MessageId> sent,
|
||||||
throws DbException;
|
long expiry) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores the given message, or returns false if the message is already in
|
* Stores the given message, or returns false if the message is already in
|
||||||
@@ -128,6 +129,15 @@ interface Database<T> {
|
|||||||
void addSecrets(T txn, Collection<TemporarySecret> secrets)
|
void addSecrets(T txn, Collection<TemporarySecret> secrets)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialises the status (seen or unseen) of the given message with
|
||||||
|
* respect to the given contact.
|
||||||
|
* <p>
|
||||||
|
* Locking: contact read, message write.
|
||||||
|
*/
|
||||||
|
void addStatus(T txn, ContactId c, MessageId m, boolean seen)
|
||||||
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subscribes to the given group.
|
* Subscribes to the given group.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -614,14 +624,6 @@ interface Database<T> {
|
|||||||
boolean setStarredFlag(T txn, MessageId m, boolean starred)
|
boolean setStarredFlag(T txn, MessageId m, boolean starred)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the status of the given message with respect to the given contact.
|
|
||||||
* <p>
|
|
||||||
* Locking: contact read, message write.
|
|
||||||
*/
|
|
||||||
void setStatus(T txn, ContactId c, MessageId m, Status s)
|
|
||||||
throws DbException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the database contains the given message and it belongs to a group
|
* If the database contains the given message and it belongs to a group
|
||||||
* that is visible to the given contact, marks the message as seen by the
|
* that is visible to the given contact, marks the message as seen by the
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ import static net.sf.briar.db.DatabaseConstants.CRITICAL_FREE_SPACE;
|
|||||||
import static net.sf.briar.db.DatabaseConstants.MAX_BYTES_BETWEEN_SPACE_CHECKS;
|
import static net.sf.briar.db.DatabaseConstants.MAX_BYTES_BETWEEN_SPACE_CHECKS;
|
||||||
import static net.sf.briar.db.DatabaseConstants.MAX_MS_BETWEEN_SPACE_CHECKS;
|
import static net.sf.briar.db.DatabaseConstants.MAX_MS_BETWEEN_SPACE_CHECKS;
|
||||||
import static net.sf.briar.db.DatabaseConstants.MIN_FREE_SPACE;
|
import static net.sf.briar.db.DatabaseConstants.MIN_FREE_SPACE;
|
||||||
import static net.sf.briar.db.Status.NEW;
|
|
||||||
import static net.sf.briar.db.Status.SEEN;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -277,11 +275,11 @@ DatabaseCleaner.Callback {
|
|||||||
boolean stored = db.addGroupMessage(txn, m);
|
boolean stored = db.addGroupMessage(txn, m);
|
||||||
// Mark the message as seen by the sender
|
// Mark the message as seen by the sender
|
||||||
MessageId id = m.getId();
|
MessageId id = m.getId();
|
||||||
if(sender != null) db.setStatus(txn, sender, id, SEEN);
|
if(sender != null) db.addStatus(txn, sender, id, true);
|
||||||
if(stored) {
|
if(stored) {
|
||||||
// Mark the message as unseen by other contacts
|
// Mark the message as unseen by other contacts
|
||||||
for(ContactId c : db.getContacts(txn)) {
|
for(ContactId c : db.getContacts(txn)) {
|
||||||
if(!c.equals(sender)) db.setStatus(txn, c, id, NEW);
|
if(!c.equals(sender)) db.addStatus(txn, c, id, false);
|
||||||
}
|
}
|
||||||
// Calculate and store the message's sendability
|
// Calculate and store the message's sendability
|
||||||
int sendability = calculateSendability(txn, m);
|
int sendability = calculateSendability(txn, m);
|
||||||
@@ -441,8 +439,8 @@ DatabaseCleaner.Callback {
|
|||||||
if(m.getAuthor() != null) throw new IllegalArgumentException();
|
if(m.getAuthor() != null) throw new IllegalArgumentException();
|
||||||
if(!db.addPrivateMessage(txn, m, c)) return false;
|
if(!db.addPrivateMessage(txn, m, c)) return false;
|
||||||
MessageId id = m.getId();
|
MessageId id = m.getId();
|
||||||
if(incoming) db.setStatus(txn, c, id, SEEN);
|
if(incoming) db.addStatus(txn, c, id, true);
|
||||||
else db.setStatus(txn, c, id, NEW);
|
else db.addStatus(txn, c, id, false);
|
||||||
// Count the bytes stored
|
// Count the bytes stored
|
||||||
synchronized(spaceLock) {
|
synchronized(spaceLock) {
|
||||||
bytesStoredSinceLastCheck += m.getSerialised().length;
|
bytesStoredSinceLastCheck += m.getSerialised().length;
|
||||||
@@ -526,7 +524,8 @@ DatabaseCleaner.Callback {
|
|||||||
try {
|
try {
|
||||||
T txn = db.startTransaction();
|
T txn = db.startTransaction();
|
||||||
try {
|
try {
|
||||||
db.addOutstandingMessages(txn, c, ids);
|
// FIXME: Calculate the expiry time
|
||||||
|
db.addOutstandingMessages(txn, c, ids, Long.MAX_VALUE);
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
} catch(DbException e) {
|
} catch(DbException e) {
|
||||||
db.abortTransaction(txn);
|
db.abortTransaction(txn);
|
||||||
@@ -585,7 +584,8 @@ DatabaseCleaner.Callback {
|
|||||||
try {
|
try {
|
||||||
T txn = db.startTransaction();
|
T txn = db.startTransaction();
|
||||||
try {
|
try {
|
||||||
db.addOutstandingMessages(txn, c, ids);
|
// FIXME: Calculate the expiry time
|
||||||
|
db.addOutstandingMessages(txn, c, ids, Long.MAX_VALUE);
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
} catch(DbException e) {
|
} catch(DbException e) {
|
||||||
db.abortTransaction(txn);
|
db.abortTransaction(txn);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import java.sql.Connection;
|
|||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
import net.sf.briar.api.clock.Clock;
|
import net.sf.briar.api.clock.Clock;
|
||||||
|
import net.sf.briar.api.clock.SystemClock;
|
||||||
import net.sf.briar.api.db.DatabaseComponent;
|
import net.sf.briar.api.db.DatabaseComponent;
|
||||||
import net.sf.briar.api.db.DatabaseConfig;
|
import net.sf.briar.api.db.DatabaseConfig;
|
||||||
import net.sf.briar.api.db.DatabaseExecutor;
|
import net.sf.briar.api.db.DatabaseExecutor;
|
||||||
@@ -41,7 +42,7 @@ public class DatabaseModule extends AbstractModule {
|
|||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
Database<Connection> getDatabase(DatabaseConfig config) {
|
Database<Connection> getDatabase(DatabaseConfig config) {
|
||||||
return new H2Database(config);
|
return new H2Database(config, new SystemClock());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides @Singleton
|
@Provides @Singleton
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import java.sql.SQLException;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import net.sf.briar.api.clock.Clock;
|
||||||
import net.sf.briar.api.crypto.Password;
|
import net.sf.briar.api.crypto.Password;
|
||||||
import net.sf.briar.api.db.DatabaseConfig;
|
import net.sf.briar.api.db.DatabaseConfig;
|
||||||
import net.sf.briar.api.db.DbException;
|
import net.sf.briar.api.db.DbException;
|
||||||
@@ -29,8 +30,8 @@ class H2Database extends JdbcDatabase {
|
|||||||
private final long maxSize;
|
private final long maxSize;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
H2Database(DatabaseConfig config) {
|
H2Database(DatabaseConfig config, Clock clock) {
|
||||||
super(HASH_TYPE, BINARY_TYPE, COUNTER_TYPE, SECRET_TYPE);
|
super(HASH_TYPE, BINARY_TYPE, COUNTER_TYPE, SECRET_TYPE, clock);
|
||||||
home = new File(config.getDataDirectory(), "db");
|
home = new File(config.getDataDirectory(), "db");
|
||||||
url = "jdbc:h2:split:" + home.getPath()
|
url = "jdbc:h2:split:" + home.getPath()
|
||||||
+ ";CIPHER=AES;MULTI_THREADED=1;DB_CLOSE_ON_EXIT=false";
|
+ ";CIPHER=AES;MULTI_THREADED=1;DB_CLOSE_ON_EXIT=false";
|
||||||
|
|||||||
@@ -5,9 +5,6 @@ import static java.util.logging.Level.INFO;
|
|||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static net.sf.briar.api.Rating.UNRATED;
|
import static net.sf.briar.api.Rating.UNRATED;
|
||||||
import static net.sf.briar.db.DatabaseConstants.RETENTION_MODULUS;
|
import static net.sf.briar.db.DatabaseConstants.RETENTION_MODULUS;
|
||||||
import static net.sf.briar.db.Status.NEW;
|
|
||||||
import static net.sf.briar.db.Status.SEEN;
|
|
||||||
import static net.sf.briar.db.Status.SENT;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
@@ -31,6 +28,7 @@ import net.sf.briar.api.ContactId;
|
|||||||
import net.sf.briar.api.Rating;
|
import net.sf.briar.api.Rating;
|
||||||
import net.sf.briar.api.TransportConfig;
|
import net.sf.briar.api.TransportConfig;
|
||||||
import net.sf.briar.api.TransportProperties;
|
import net.sf.briar.api.TransportProperties;
|
||||||
|
import net.sf.briar.api.clock.Clock;
|
||||||
import net.sf.briar.api.db.DbClosedException;
|
import net.sf.briar.api.db.DbClosedException;
|
||||||
import net.sf.briar.api.db.DbException;
|
import net.sf.briar.api.db.DbException;
|
||||||
import net.sf.briar.api.db.MessageHeader;
|
import net.sf.briar.api.db.MessageHeader;
|
||||||
@@ -157,7 +155,9 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
"CREATE TABLE statuses"
|
"CREATE TABLE statuses"
|
||||||
+ " (messageId HASH NOT NULL,"
|
+ " (messageId HASH NOT NULL,"
|
||||||
+ " contactId INT NOT NULL,"
|
+ " contactId INT NOT NULL,"
|
||||||
+ " status SMALLINT NOT NULL,"
|
+ " seen BOOLEAN NOT NULL,"
|
||||||
|
+ " transmissionCount INT NOT NULL,"
|
||||||
|
+ " expiry BIGINT NOT NULL,"
|
||||||
+ " PRIMARY KEY (messageId, contactId),"
|
+ " PRIMARY KEY (messageId, contactId),"
|
||||||
+ " FOREIGN KEY (messageId)"
|
+ " FOREIGN KEY (messageId)"
|
||||||
+ " REFERENCES messages (messageId)"
|
+ " REFERENCES messages (messageId)"
|
||||||
@@ -298,6 +298,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
|
|
||||||
// Different database libraries use different names for certain types
|
// Different database libraries use different names for certain types
|
||||||
private final String hashType, binaryType, counterType, secretType;
|
private final String hashType, binaryType, counterType, secretType;
|
||||||
|
private final Clock clock;
|
||||||
|
|
||||||
private final LinkedList<Connection> connections =
|
private final LinkedList<Connection> connections =
|
||||||
new LinkedList<Connection>(); // Locking: self
|
new LinkedList<Connection>(); // Locking: self
|
||||||
@@ -308,11 +309,12 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
protected abstract Connection createConnection() throws SQLException;
|
protected abstract Connection createConnection() throws SQLException;
|
||||||
|
|
||||||
JdbcDatabase(String hashType, String binaryType, String counterType,
|
JdbcDatabase(String hashType, String binaryType, String counterType,
|
||||||
String secretType) {
|
String secretType, Clock clock) {
|
||||||
this.hashType = hashType;
|
this.hashType = hashType;
|
||||||
this.binaryType = binaryType;
|
this.binaryType = binaryType;
|
||||||
this.counterType = counterType;
|
this.counterType = counterType;
|
||||||
this.secretType = secretType;
|
this.secretType = secretType;
|
||||||
|
this.clock = clock;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void open(boolean resume, File dir, String driverClass)
|
protected void open(boolean resume, File dir, String driverClass)
|
||||||
@@ -646,18 +648,19 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void addOutstandingMessages(Connection txn, ContactId c,
|
public void addOutstandingMessages(Connection txn, ContactId c,
|
||||||
Collection<MessageId> sent) throws DbException {
|
Collection<MessageId> sent, long expiry) throws DbException {
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
try {
|
try {
|
||||||
// Set the status of each message to SENT if it's currently NEW
|
// Update the transmission count and expiry time of each message
|
||||||
String sql = "UPDATE statuses SET status = ?"
|
String sql = "UPDATE statuses SET expiry = ?,"
|
||||||
+ " WHERE messageId = ? AND contactId = ? AND status = ?";
|
+ " transmissionCount = transmissionCount + ?"
|
||||||
|
+ " WHERE messageId = ? AND contactId = ?";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setShort(1, (short) SENT.ordinal());
|
ps.setLong(1, expiry);
|
||||||
ps.setInt(3, c.getInt());
|
ps.setInt(2, 1);
|
||||||
ps.setShort(4, (short) NEW.ordinal());
|
ps.setInt(4, c.getInt());
|
||||||
for(MessageId m : sent) {
|
for(MessageId m : sent) {
|
||||||
ps.setBytes(2, m.getBytes());
|
ps.setBytes(3, m.getBytes());
|
||||||
ps.addBatch();
|
ps.addBatch();
|
||||||
}
|
}
|
||||||
int[] batchAffected = ps.executeBatch();
|
int[] batchAffected = ps.executeBatch();
|
||||||
@@ -705,6 +708,26 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addStatus(Connection txn, ContactId c, MessageId m,
|
||||||
|
boolean seen) throws DbException {
|
||||||
|
PreparedStatement ps = null;
|
||||||
|
try {
|
||||||
|
String sql = "INSERT INTO statuses"
|
||||||
|
+ " (messageId, contactId, seen, transmissionCount, expiry)"
|
||||||
|
+ " VALUES (?, ?, ?, ZERO(), ZERO())";
|
||||||
|
ps = txn.prepareStatement(sql);
|
||||||
|
ps.setBytes(1, m.getBytes());
|
||||||
|
ps.setInt(2, c.getInt());
|
||||||
|
ps.setBoolean(3, seen);
|
||||||
|
int affected = ps.executeUpdate();
|
||||||
|
if(affected != 1) throw new DbStateException();
|
||||||
|
ps.close();
|
||||||
|
} catch(SQLException e) {
|
||||||
|
tryToClose(ps);
|
||||||
|
throw new DbException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void addSubscription(Connection txn, Group g) throws DbException {
|
public void addSubscription(Connection txn, Group g) throws DbException {
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
try {
|
try {
|
||||||
@@ -1220,6 +1243,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
|
|
||||||
public Collection<MessageId> getMessagesToOffer(Connection txn,
|
public Collection<MessageId> getMessagesToOffer(Connection txn,
|
||||||
ContactId c, int maxMessages) throws DbException {
|
ContactId c, int maxMessages) throws DbException {
|
||||||
|
long now = clock.currentTimeMillis();
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
try {
|
try {
|
||||||
@@ -1227,11 +1251,11 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
String sql = "SELECT m.messageId FROM messages AS m"
|
String sql = "SELECT m.messageId FROM messages AS m"
|
||||||
+ " JOIN statuses AS s"
|
+ " JOIN statuses AS s"
|
||||||
+ " ON m.messageId = s.messageId"
|
+ " ON m.messageId = s.messageId"
|
||||||
+ " WHERE m.contactId = ? AND status = ?"
|
+ " WHERE m.contactId = ? AND seen = FALSE AND expiry < ?"
|
||||||
+ " ORDER BY timestamp DESC LIMIT ?";
|
+ " ORDER BY timestamp DESC LIMIT ?";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setInt(1, c.getInt());
|
ps.setInt(1, c.getInt());
|
||||||
ps.setShort(2, (short) NEW.ordinal());
|
ps.setLong(2, now);
|
||||||
ps.setInt(3, maxMessages);
|
ps.setInt(3, maxMessages);
|
||||||
rs = ps.executeQuery();
|
rs = ps.executeQuery();
|
||||||
List<MessageId> ids = new ArrayList<MessageId>();
|
List<MessageId> ids = new ArrayList<MessageId>();
|
||||||
@@ -1254,12 +1278,12 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " AND cg.contactId = s.contactId"
|
+ " AND cg.contactId = s.contactId"
|
||||||
+ " WHERE cg.contactId = ?"
|
+ " WHERE cg.contactId = ?"
|
||||||
+ " AND timestamp >= retention"
|
+ " AND timestamp >= retention"
|
||||||
+ " AND status = ?"
|
+ " AND seen = FALSE AND expiry < ?"
|
||||||
+ " AND sendability > ZERO()"
|
+ " AND sendability > ZERO()"
|
||||||
+ " ORDER BY timestamp DESC LIMIT ?";
|
+ " ORDER BY timestamp DESC LIMIT ?";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setInt(1, c.getInt());
|
ps.setInt(1, c.getInt());
|
||||||
ps.setShort(2, (short) NEW.ordinal());
|
ps.setLong(2, now);
|
||||||
ps.setInt(3, maxMessages - ids.size());
|
ps.setInt(3, maxMessages - ids.size());
|
||||||
rs = ps.executeQuery();
|
rs = ps.executeQuery();
|
||||||
while(rs.next()) ids.add(new MessageId(rs.getBytes(2)));
|
while(rs.next()) ids.add(new MessageId(rs.getBytes(2)));
|
||||||
@@ -1383,6 +1407,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
|
|
||||||
public byte[] getRawMessageIfSendable(Connection txn, ContactId c,
|
public byte[] getRawMessageIfSendable(Connection txn, ContactId c,
|
||||||
MessageId m) throws DbException {
|
MessageId m) throws DbException {
|
||||||
|
long now = clock.currentTimeMillis();
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
try {
|
try {
|
||||||
@@ -1391,11 +1416,11 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " JOIN statuses AS s"
|
+ " JOIN statuses AS s"
|
||||||
+ " ON m.messageId = s.messageId"
|
+ " ON m.messageId = s.messageId"
|
||||||
+ " WHERE m.messageId = ? AND m.contactId = ?"
|
+ " WHERE m.messageId = ? AND m.contactId = ?"
|
||||||
+ " AND status = ?";
|
+ " AND seen = FALSE AND expiry < ?";
|
||||||
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());
|
||||||
ps.setShort(3, (short) NEW.ordinal());
|
ps.setLong(3, now);
|
||||||
rs = ps.executeQuery();
|
rs = ps.executeQuery();
|
||||||
byte[] raw = null;
|
byte[] raw = null;
|
||||||
if(rs.next()) {
|
if(rs.next()) {
|
||||||
@@ -1422,12 +1447,12 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " WHERE m.messageId = ?"
|
+ " WHERE m.messageId = ?"
|
||||||
+ " AND cg.contactId = ?"
|
+ " AND cg.contactId = ?"
|
||||||
+ " AND timestamp >= retention"
|
+ " AND timestamp >= retention"
|
||||||
+ " AND status = ?"
|
+ " AND seen = FALSE AND expiry < ?"
|
||||||
+ " AND sendability > ZERO()";
|
+ " AND sendability > ZERO()";
|
||||||
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());
|
||||||
ps.setShort(3, (short) NEW.ordinal());
|
ps.setLong(3, now);
|
||||||
rs = ps.executeQuery();
|
rs = ps.executeQuery();
|
||||||
if(rs.next()) {
|
if(rs.next()) {
|
||||||
int length = rs.getInt(1);
|
int length = rs.getInt(1);
|
||||||
@@ -1631,6 +1656,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
|
|
||||||
public Collection<MessageId> getSendableMessages(Connection txn,
|
public Collection<MessageId> getSendableMessages(Connection txn,
|
||||||
ContactId c, int maxLength) throws DbException {
|
ContactId c, int maxLength) throws DbException {
|
||||||
|
long now = clock.currentTimeMillis();
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
try {
|
try {
|
||||||
@@ -1638,11 +1664,11 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
String sql = "SELECT length, m.messageId FROM messages AS m"
|
String sql = "SELECT length, m.messageId FROM messages AS m"
|
||||||
+ " JOIN statuses AS s"
|
+ " JOIN statuses AS s"
|
||||||
+ " ON m.messageId = s.messageId"
|
+ " ON m.messageId = s.messageId"
|
||||||
+ " WHERE m.contactId = ? AND status = ?"
|
+ " WHERE m.contactId = ? AND seen = FALSE AND expiry < ?"
|
||||||
+ " ORDER BY timestamp DESC";
|
+ " ORDER BY timestamp DESC";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setInt(1, c.getInt());
|
ps.setInt(1, c.getInt());
|
||||||
ps.setShort(2, (short) NEW.ordinal());
|
ps.setLong(2, now);
|
||||||
rs = ps.executeQuery();
|
rs = ps.executeQuery();
|
||||||
List<MessageId> ids = new ArrayList<MessageId>();
|
List<MessageId> ids = new ArrayList<MessageId>();
|
||||||
int total = 0;
|
int total = 0;
|
||||||
@@ -1669,12 +1695,12 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " AND cg.contactId = s.contactId"
|
+ " AND cg.contactId = s.contactId"
|
||||||
+ " WHERE cg.contactId = ?"
|
+ " WHERE cg.contactId = ?"
|
||||||
+ " AND timestamp >= retention"
|
+ " AND timestamp >= retention"
|
||||||
+ " AND status = ?"
|
+ " AND seen = FALSE AND expiry < ?"
|
||||||
+ " AND sendability > ZERO()"
|
+ " AND sendability > ZERO()"
|
||||||
+ " ORDER BY timestamp DESC";
|
+ " ORDER BY timestamp DESC";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setInt(1, c.getInt());
|
ps.setInt(1, c.getInt());
|
||||||
ps.setShort(2, (short) NEW.ordinal());
|
ps.setLong(2, now);
|
||||||
rs = ps.executeQuery();
|
rs = ps.executeQuery();
|
||||||
while(rs.next()) {
|
while(rs.next()) {
|
||||||
int length = rs.getInt(1);
|
int length = rs.getInt(1);
|
||||||
@@ -1988,6 +2014,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
|
|
||||||
public boolean hasSendableMessages(Connection txn, ContactId c)
|
public boolean hasSendableMessages(Connection txn, ContactId c)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
|
long now = clock.currentTimeMillis();
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
try {
|
try {
|
||||||
@@ -1995,11 +2022,11 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
String sql = "SELECT m.messageId FROM messages AS m"
|
String sql = "SELECT m.messageId FROM messages AS m"
|
||||||
+ " JOIN statuses AS s"
|
+ " JOIN statuses AS s"
|
||||||
+ " ON m.messageId = s.messageId"
|
+ " ON m.messageId = s.messageId"
|
||||||
+ " WHERE m.contactId = ? AND status = ?"
|
+ " WHERE m.contactId = ? AND seen = FALSE AND expiry < ?"
|
||||||
+ " LIMIT ?";
|
+ " LIMIT ?";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setInt(1, c.getInt());
|
ps.setInt(1, c.getInt());
|
||||||
ps.setShort(2, (short) NEW.ordinal());
|
ps.setLong(2, now);
|
||||||
ps.setInt(3, 1);
|
ps.setInt(3, 1);
|
||||||
rs = ps.executeQuery();
|
rs = ps.executeQuery();
|
||||||
boolean found = rs.next();
|
boolean found = rs.next();
|
||||||
@@ -2021,12 +2048,12 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " AND cg.contactId = s.contactId"
|
+ " AND cg.contactId = s.contactId"
|
||||||
+ " WHERE cg.contactId = ?"
|
+ " WHERE cg.contactId = ?"
|
||||||
+ " AND timestamp >= retention"
|
+ " AND timestamp >= retention"
|
||||||
+ " AND status = ?"
|
+ " AND seen = FALSE AND expiry < ?"
|
||||||
+ " AND sendability > ZERO()"
|
+ " AND sendability > ZERO()"
|
||||||
+ " LIMIT ?";
|
+ " LIMIT ?";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setInt(1, c.getInt());
|
ps.setInt(1, c.getInt());
|
||||||
ps.setShort(2, (short) NEW.ordinal());
|
ps.setLong(2, now);
|
||||||
ps.setInt(3, 1);
|
ps.setInt(3, 1);
|
||||||
rs = ps.executeQuery();
|
rs = ps.executeQuery();
|
||||||
found = rs.next();
|
found = rs.next();
|
||||||
@@ -2100,13 +2127,11 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
Collection<MessageId> acked) throws DbException {
|
Collection<MessageId> acked) throws DbException {
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
try {
|
try {
|
||||||
// Set the status of each message to SEEN if it's currently SENT
|
// Set the status of each message to seen = true
|
||||||
String sql = "UPDATE statuses SET status = ?"
|
String sql = "UPDATE statuses SET seen = TRUE"
|
||||||
+ " WHERE messageId = ? AND contactId = ? AND status = ?";
|
+ " WHERE messageId = ? AND contactId = ?";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setShort(1, (short) SEEN.ordinal());
|
ps.setInt(1, c.getInt());
|
||||||
ps.setInt(3, c.getInt());
|
|
||||||
ps.setShort(4, (short) SENT.ordinal());
|
|
||||||
for(MessageId m : acked) {
|
for(MessageId m : acked) {
|
||||||
ps.setBytes(2, m.getBytes());
|
ps.setBytes(2, m.getBytes());
|
||||||
ps.addBatch();
|
ps.addBatch();
|
||||||
@@ -2612,55 +2637,6 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStatus(Connection txn, ContactId c, MessageId m, Status s)
|
|
||||||
throws DbException {
|
|
||||||
PreparedStatement ps = null;
|
|
||||||
ResultSet rs = null;
|
|
||||||
try {
|
|
||||||
String sql = "SELECT status FROM statuses"
|
|
||||||
+ " WHERE messageId = ? AND contactId = ?";
|
|
||||||
ps = txn.prepareStatement(sql);
|
|
||||||
ps.setBytes(1, m.getBytes());
|
|
||||||
ps.setInt(2, c.getInt());
|
|
||||||
rs = ps.executeQuery();
|
|
||||||
if(rs.next()) {
|
|
||||||
// A status row exists - update it if necessary
|
|
||||||
Status old = Status.values()[rs.getByte(1)];
|
|
||||||
if(rs.next()) throw new DbStateException();
|
|
||||||
rs.close();
|
|
||||||
ps.close();
|
|
||||||
if(old != SEEN && old != s) {
|
|
||||||
sql = "UPDATE statuses SET status = ?"
|
|
||||||
+ " WHERE messageId = ? AND contactId = ?";
|
|
||||||
ps = txn.prepareStatement(sql);
|
|
||||||
ps.setShort(1, (short) s.ordinal());
|
|
||||||
ps.setBytes(2, m.getBytes());
|
|
||||||
ps.setInt(3, c.getInt());
|
|
||||||
int affected = ps.executeUpdate();
|
|
||||||
if(affected != 1) throw new DbStateException();
|
|
||||||
ps.close();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// No status row exists - create one
|
|
||||||
rs.close();
|
|
||||||
ps.close();
|
|
||||||
sql = "INSERT INTO statuses (messageId, contactId, status)"
|
|
||||||
+ " VALUES (?, ?, ?)";
|
|
||||||
ps = txn.prepareStatement(sql);
|
|
||||||
ps.setBytes(1, m.getBytes());
|
|
||||||
ps.setInt(2, c.getInt());
|
|
||||||
ps.setShort(3, (short) s.ordinal());
|
|
||||||
int affected = ps.executeUpdate();
|
|
||||||
if(affected != 1) throw new DbStateException();
|
|
||||||
ps.close();
|
|
||||||
}
|
|
||||||
} catch(SQLException e) {
|
|
||||||
tryToClose(rs);
|
|
||||||
tryToClose(ps);
|
|
||||||
throw new DbException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean setStatusSeenIfVisible(Connection txn, ContactId c,
|
public boolean setStatusSeenIfVisible(Connection txn, ContactId c,
|
||||||
MessageId m) throws DbException {
|
MessageId m) throws DbException {
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
@@ -2686,10 +2662,10 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
rs.close();
|
rs.close();
|
||||||
ps.close();
|
ps.close();
|
||||||
if(!found) return false;
|
if(!found) return false;
|
||||||
sql = "UPDATE statuses SET status = ?"
|
sql = "UPDATE statuses SET seen = ?"
|
||||||
+ " WHERE messageId = ? AND contactId = ?";
|
+ " WHERE messageId = ? AND contactId = ?";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setShort(1, (short) SEEN.ordinal());
|
ps.setBoolean(1, true);
|
||||||
ps.setBytes(2, m.getBytes());
|
ps.setBytes(2, m.getBytes());
|
||||||
ps.setInt(3, c.getInt());
|
ps.setInt(3, c.getInt());
|
||||||
int affected = ps.executeUpdate();
|
int affected = ps.executeUpdate();
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
package net.sf.briar.db;
|
|
||||||
|
|
||||||
/** The status of a message with respect to a particular contact. */
|
|
||||||
enum Status {
|
|
||||||
/** The message has not been sent, received, or acked. */
|
|
||||||
NEW,
|
|
||||||
/** The message has been sent, but not received or acked. */
|
|
||||||
SENT,
|
|
||||||
/** The message has been received or acked. */
|
|
||||||
SEEN
|
|
||||||
}
|
|
||||||
@@ -2,8 +2,6 @@ package net.sf.briar.db;
|
|||||||
|
|
||||||
import static net.sf.briar.api.Rating.GOOD;
|
import static net.sf.briar.api.Rating.GOOD;
|
||||||
import static net.sf.briar.api.Rating.UNRATED;
|
import static net.sf.briar.api.Rating.UNRATED;
|
||||||
import static net.sf.briar.db.Status.NEW;
|
|
||||||
import static net.sf.briar.db.Status.SEEN;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -364,7 +362,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
|
|||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
oneOf(database).getContacts(txn);
|
oneOf(database).getContacts(txn);
|
||||||
will(returnValue(Collections.singletonList(contactId)));
|
will(returnValue(Collections.singletonList(contactId)));
|
||||||
oneOf(database).setStatus(txn, contactId, messageId, NEW);
|
oneOf(database).addStatus(txn, contactId, messageId, false);
|
||||||
// The author is unrated and there are no sendable children
|
// The author is unrated and there are no sendable children
|
||||||
oneOf(database).getRating(txn, authorId);
|
oneOf(database).getRating(txn, authorId);
|
||||||
will(returnValue(UNRATED));
|
will(returnValue(UNRATED));
|
||||||
@@ -399,7 +397,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
|
|||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
oneOf(database).getContacts(txn);
|
oneOf(database).getContacts(txn);
|
||||||
will(returnValue(Collections.singletonList(contactId)));
|
will(returnValue(Collections.singletonList(contactId)));
|
||||||
oneOf(database).setStatus(txn, contactId, messageId, NEW);
|
oneOf(database).addStatus(txn, contactId, messageId, false);
|
||||||
// The author is rated GOOD and there are two sendable children
|
// The author is rated GOOD and there are two sendable children
|
||||||
oneOf(database).getRating(txn, authorId);
|
oneOf(database).getRating(txn, authorId);
|
||||||
will(returnValue(GOOD));
|
will(returnValue(GOOD));
|
||||||
@@ -460,7 +458,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
|
|||||||
// addLocalPrivateMessage(privateMessage, contactId)
|
// addLocalPrivateMessage(privateMessage, contactId)
|
||||||
oneOf(database).addPrivateMessage(txn, privateMessage, contactId);
|
oneOf(database).addPrivateMessage(txn, privateMessage, contactId);
|
||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
oneOf(database).setStatus(txn, contactId, messageId, NEW);
|
oneOf(database).addStatus(txn, contactId, messageId, false);
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, cleaner,
|
DatabaseComponent db = createDatabaseComponent(database, cleaner,
|
||||||
shutdown);
|
shutdown);
|
||||||
@@ -698,7 +696,9 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
|
|||||||
oneOf(database).getRawMessage(txn, messageId1);
|
oneOf(database).getRawMessage(txn, messageId1);
|
||||||
will(returnValue(raw1));
|
will(returnValue(raw1));
|
||||||
// Record the outstanding messages
|
// Record the outstanding messages
|
||||||
oneOf(database).addOutstandingMessages(txn, contactId, sendable);
|
// FIXME: Calculate the expiry time
|
||||||
|
oneOf(database).addOutstandingMessages(txn, contactId, sendable,
|
||||||
|
Long.MAX_VALUE);
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, cleaner,
|
DatabaseComponent db = createDatabaseComponent(database, cleaner,
|
||||||
shutdown);
|
shutdown);
|
||||||
@@ -734,8 +734,9 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
|
|||||||
oneOf(database).getRawMessageIfSendable(txn, contactId, messageId2);
|
oneOf(database).getRawMessageIfSendable(txn, contactId, messageId2);
|
||||||
will(returnValue(null)); // Message is not sendable
|
will(returnValue(null)); // Message is not sendable
|
||||||
// Record the outstanding messages
|
// Record the outstanding messages
|
||||||
|
// FIXME: Calculate the expiry time
|
||||||
oneOf(database).addOutstandingMessages(txn, contactId,
|
oneOf(database).addOutstandingMessages(txn, contactId,
|
||||||
Collections.singletonList(messageId1));
|
Collections.singletonList(messageId1), Long.MAX_VALUE);
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, cleaner,
|
DatabaseComponent db = createDatabaseComponent(database, cleaner,
|
||||||
shutdown);
|
shutdown);
|
||||||
@@ -922,7 +923,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
|
|||||||
// The message is stored
|
// The message is stored
|
||||||
oneOf(database).addPrivateMessage(txn, privateMessage, contactId);
|
oneOf(database).addPrivateMessage(txn, privateMessage, contactId);
|
||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
oneOf(database).setStatus(txn, contactId, messageId, SEEN);
|
oneOf(database).addStatus(txn, contactId, messageId, true);
|
||||||
// The message must be acked
|
// The message must be acked
|
||||||
oneOf(database).addMessageToAck(txn, contactId, messageId);
|
oneOf(database).addMessageToAck(txn, contactId, messageId);
|
||||||
}});
|
}});
|
||||||
@@ -1011,7 +1012,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
|
|||||||
// The message is stored, but it's a duplicate
|
// The message is stored, but it's a duplicate
|
||||||
oneOf(database).addGroupMessage(txn, message);
|
oneOf(database).addGroupMessage(txn, message);
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
oneOf(database).setStatus(txn, contactId, messageId, SEEN);
|
oneOf(database).addStatus(txn, contactId, messageId, true);
|
||||||
// The message must be acked
|
// The message must be acked
|
||||||
oneOf(database).addMessageToAck(txn, contactId, messageId);
|
oneOf(database).addMessageToAck(txn, contactId, messageId);
|
||||||
}});
|
}});
|
||||||
@@ -1043,8 +1044,8 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
|
|||||||
// The message is stored, and it's not a duplicate
|
// The message is stored, and it's not a duplicate
|
||||||
oneOf(database).addGroupMessage(txn, message);
|
oneOf(database).addGroupMessage(txn, message);
|
||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
oneOf(database).setStatus(txn, contactId, messageId, SEEN);
|
oneOf(database).addStatus(txn, contactId, messageId, true);
|
||||||
// Set the status to NEW for all other contacts (there are none)
|
// Set the status to seen = true for all other contacts (none)
|
||||||
oneOf(database).getContacts(txn);
|
oneOf(database).getContacts(txn);
|
||||||
will(returnValue(Collections.singletonList(contactId)));
|
will(returnValue(Collections.singletonList(contactId)));
|
||||||
// Calculate the sendability - zero, so ancestors aren't updated
|
// Calculate the sendability - zero, so ancestors aren't updated
|
||||||
@@ -1085,8 +1086,8 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
|
|||||||
// The message is stored, and it's not a duplicate
|
// The message is stored, and it's not a duplicate
|
||||||
oneOf(database).addGroupMessage(txn, message);
|
oneOf(database).addGroupMessage(txn, message);
|
||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
oneOf(database).setStatus(txn, contactId, messageId, SEEN);
|
oneOf(database).addStatus(txn, contactId, messageId, true);
|
||||||
// Set the status to NEW for all other contacts (there are none)
|
// Set the status to seen = true for all other contacts (none)
|
||||||
oneOf(database).getContacts(txn);
|
oneOf(database).getContacts(txn);
|
||||||
will(returnValue(Collections.singletonList(contactId)));
|
will(returnValue(Collections.singletonList(contactId)));
|
||||||
// Calculate the sendability - ancestors are updated
|
// Calculate the sendability - ancestors are updated
|
||||||
@@ -1214,7 +1215,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
|
|||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
oneOf(database).getContacts(txn);
|
oneOf(database).getContacts(txn);
|
||||||
will(returnValue(Collections.singletonList(contactId)));
|
will(returnValue(Collections.singletonList(contactId)));
|
||||||
oneOf(database).setStatus(txn, contactId, messageId, NEW);
|
oneOf(database).addStatus(txn, contactId, messageId, false);
|
||||||
oneOf(database).getRating(txn, authorId);
|
oneOf(database).getRating(txn, authorId);
|
||||||
will(returnValue(UNRATED));
|
will(returnValue(UNRATED));
|
||||||
oneOf(database).getNumberOfSendableChildren(txn, messageId);
|
oneOf(database).getNumberOfSendableChildren(txn, messageId);
|
||||||
@@ -1250,7 +1251,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
|
|||||||
// addLocalPrivateMessage(privateMessage, contactId)
|
// addLocalPrivateMessage(privateMessage, contactId)
|
||||||
oneOf(database).addPrivateMessage(txn, privateMessage, contactId);
|
oneOf(database).addPrivateMessage(txn, privateMessage, contactId);
|
||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
oneOf(database).setStatus(txn, contactId, messageId, NEW);
|
oneOf(database).addStatus(txn, contactId, messageId, false);
|
||||||
// The message was added, so the listener should be called
|
// The message was added, so the listener should be called
|
||||||
oneOf(listener).eventOccurred(with(any(MessageAddedEvent.class)));
|
oneOf(listener).eventOccurred(with(any(MessageAddedEvent.class)));
|
||||||
}});
|
}});
|
||||||
|
|||||||
@@ -3,9 +3,6 @@ package net.sf.briar.db;
|
|||||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||||
import static net.sf.briar.api.Rating.GOOD;
|
import static net.sf.briar.api.Rating.GOOD;
|
||||||
import static net.sf.briar.api.Rating.UNRATED;
|
import static net.sf.briar.api.Rating.UNRATED;
|
||||||
import static net.sf.briar.db.Status.NEW;
|
|
||||||
import static net.sf.briar.db.Status.SEEN;
|
|
||||||
import static net.sf.briar.db.Status.SENT;
|
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -29,6 +26,7 @@ import net.sf.briar.TestUtils;
|
|||||||
import net.sf.briar.api.ContactId;
|
import net.sf.briar.api.ContactId;
|
||||||
import net.sf.briar.api.TransportConfig;
|
import net.sf.briar.api.TransportConfig;
|
||||||
import net.sf.briar.api.TransportProperties;
|
import net.sf.briar.api.TransportProperties;
|
||||||
|
import net.sf.briar.api.clock.SystemClock;
|
||||||
import net.sf.briar.api.db.DbException;
|
import net.sf.briar.api.db.DbException;
|
||||||
import net.sf.briar.api.db.MessageHeader;
|
import net.sf.briar.api.db.MessageHeader;
|
||||||
import net.sf.briar.api.messaging.AuthorId;
|
import net.sf.briar.api.messaging.AuthorId;
|
||||||
@@ -224,7 +222,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSendablePrivateMessagesMustHaveStatusNew()
|
public void testSendablePrivateMessagesMustHaveSeenFlagFalse()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
Database<Connection> db = open(false);
|
Database<Connection> db = open(false);
|
||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
@@ -239,25 +237,14 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator();
|
db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator();
|
||||||
assertFalse(it.hasNext());
|
assertFalse(it.hasNext());
|
||||||
|
|
||||||
// Changing the status to NEW should make the message sendable
|
// Adding a status with seen = false should make the message sendable
|
||||||
db.setStatus(txn, contactId, messageId1, NEW);
|
db.addStatus(txn, contactId, messageId1, false);
|
||||||
assertTrue(db.hasSendableMessages(txn, contactId));
|
assertTrue(db.hasSendableMessages(txn, contactId));
|
||||||
it = db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator();
|
it = db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator();
|
||||||
assertTrue(it.hasNext());
|
assertTrue(it.hasNext());
|
||||||
assertEquals(messageId1, it.next());
|
assertEquals(messageId1, it.next());
|
||||||
assertFalse(it.hasNext());
|
assertFalse(it.hasNext());
|
||||||
|
|
||||||
// Changing the status to SENT should make the message unsendable
|
|
||||||
db.setStatus(txn, contactId, messageId1, SENT);
|
|
||||||
assertFalse(db.hasSendableMessages(txn, contactId));
|
|
||||||
it = db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator();
|
|
||||||
assertFalse(it.hasNext());
|
|
||||||
|
|
||||||
// Changing the status to SEEN should also make the message unsendable
|
|
||||||
db.setStatus(txn, contactId, messageId1, SEEN);
|
|
||||||
it = db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator();
|
|
||||||
assertFalse(it.hasNext());
|
|
||||||
|
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
@@ -271,7 +258,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
// Add a contact and store a private message
|
// Add a contact and store a private message
|
||||||
assertEquals(contactId, db.addContact(txn));
|
assertEquals(contactId, db.addContact(txn));
|
||||||
db.addPrivateMessage(txn, privateMessage, contactId);
|
db.addPrivateMessage(txn, privateMessage, contactId);
|
||||||
db.setStatus(txn, contactId, messageId1, NEW);
|
db.addStatus(txn, contactId, messageId1, false);
|
||||||
|
|
||||||
// The message is sendable, but too large to send
|
// The message is sendable, but too large to send
|
||||||
assertTrue(db.hasSendableMessages(txn, contactId));
|
assertTrue(db.hasSendableMessages(txn, contactId));
|
||||||
@@ -302,7 +289,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
db.addVisibility(txn, contactId, groupId);
|
db.addVisibility(txn, contactId, groupId);
|
||||||
db.setSubscriptions(txn, contactId, Arrays.asList(group), 1);
|
db.setSubscriptions(txn, contactId, Arrays.asList(group), 1);
|
||||||
db.addGroupMessage(txn, message);
|
db.addGroupMessage(txn, message);
|
||||||
db.setStatus(txn, contactId, messageId, NEW);
|
db.addStatus(txn, contactId, messageId, false);
|
||||||
|
|
||||||
// The message should not be sendable
|
// The message should not be sendable
|
||||||
assertFalse(db.hasSendableMessages(txn, contactId));
|
assertFalse(db.hasSendableMessages(txn, contactId));
|
||||||
@@ -329,7 +316,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSendableGroupMessagesMustHaveStatusNew()
|
public void testSendableGroupMessagesMustHaveSeenFlagFalse()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
Database<Connection> db = open(false);
|
Database<Connection> db = open(false);
|
||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
@@ -348,25 +335,20 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator();
|
db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator();
|
||||||
assertFalse(it.hasNext());
|
assertFalse(it.hasNext());
|
||||||
|
|
||||||
// Changing the status to NEW should make the message sendable
|
// Adding a status with seen = false should make the message sendable
|
||||||
db.setStatus(txn, contactId, messageId, NEW);
|
db.addStatus(txn, contactId, messageId, false);
|
||||||
assertTrue(db.hasSendableMessages(txn, contactId));
|
assertTrue(db.hasSendableMessages(txn, contactId));
|
||||||
it = db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator();
|
it = db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator();
|
||||||
assertTrue(it.hasNext());
|
assertTrue(it.hasNext());
|
||||||
assertEquals(messageId, it.next());
|
assertEquals(messageId, it.next());
|
||||||
assertFalse(it.hasNext());
|
assertFalse(it.hasNext());
|
||||||
|
|
||||||
// Changing the status to SENT should make the message unsendable
|
// Changing the status to seen = true should make the message unsendable
|
||||||
db.setStatus(txn, contactId, messageId, SENT);
|
db.setStatusSeenIfVisible(txn, contactId, messageId);
|
||||||
assertFalse(db.hasSendableMessages(txn, contactId));
|
assertFalse(db.hasSendableMessages(txn, contactId));
|
||||||
it = db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator();
|
it = db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator();
|
||||||
assertFalse(it.hasNext());
|
assertFalse(it.hasNext());
|
||||||
|
|
||||||
// Changing the status to SEEN should also make the message unsendable
|
|
||||||
db.setStatus(txn, contactId, messageId, SEEN);
|
|
||||||
it = db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator();
|
|
||||||
assertFalse(it.hasNext());
|
|
||||||
|
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
@@ -382,7 +364,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
db.addVisibility(txn, contactId, groupId);
|
db.addVisibility(txn, contactId, groupId);
|
||||||
db.addGroupMessage(txn, message);
|
db.addGroupMessage(txn, message);
|
||||||
db.setSendability(txn, messageId, 1);
|
db.setSendability(txn, messageId, 1);
|
||||||
db.setStatus(txn, contactId, messageId, NEW);
|
db.addStatus(txn, contactId, messageId, 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
|
||||||
assertFalse(db.hasSendableMessages(txn, contactId));
|
assertFalse(db.hasSendableMessages(txn, contactId));
|
||||||
@@ -420,7 +402,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
db.setSubscriptions(txn, contactId, Arrays.asList(group), 1);
|
db.setSubscriptions(txn, contactId, Arrays.asList(group), 1);
|
||||||
db.addGroupMessage(txn, message);
|
db.addGroupMessage(txn, message);
|
||||||
db.setSendability(txn, messageId, 1);
|
db.setSendability(txn, messageId, 1);
|
||||||
db.setStatus(txn, contactId, messageId, NEW);
|
db.addStatus(txn, contactId, messageId, false);
|
||||||
|
|
||||||
// The message is sendable, but too large to send
|
// The message is sendable, but too large to send
|
||||||
assertTrue(db.hasSendableMessages(txn, contactId));
|
assertTrue(db.hasSendableMessages(txn, contactId));
|
||||||
@@ -450,7 +432,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
db.setSubscriptions(txn, contactId, Arrays.asList(group), 1);
|
db.setSubscriptions(txn, contactId, Arrays.asList(group), 1);
|
||||||
db.addGroupMessage(txn, message);
|
db.addGroupMessage(txn, message);
|
||||||
db.setSendability(txn, messageId, 1);
|
db.setSendability(txn, messageId, 1);
|
||||||
db.setStatus(txn, contactId, messageId, NEW);
|
db.addStatus(txn, contactId, messageId, false);
|
||||||
|
|
||||||
// The subscription is not visible to the contact, so the message
|
// The subscription is not visible to the contact, so the message
|
||||||
// should not be sendable
|
// should not be sendable
|
||||||
@@ -534,7 +516,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
db.setSubscriptions(txn, contactId, Arrays.asList(group), 1);
|
db.setSubscriptions(txn, contactId, Arrays.asList(group), 1);
|
||||||
db.addGroupMessage(txn, message);
|
db.addGroupMessage(txn, message);
|
||||||
db.setSendability(txn, messageId, 1);
|
db.setSendability(txn, messageId, 1);
|
||||||
db.setStatus(txn, contactId, messageId, NEW);
|
db.addStatus(txn, contactId, messageId, 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 =
|
Iterator<MessageId> it =
|
||||||
@@ -542,9 +524,9 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
assertTrue(it.hasNext());
|
assertTrue(it.hasNext());
|
||||||
assertEquals(messageId, it.next());
|
assertEquals(messageId, it.next());
|
||||||
assertFalse(it.hasNext());
|
assertFalse(it.hasNext());
|
||||||
db.setStatus(txn, contactId, messageId, SENT);
|
// FIXME: Calculate the expiry time
|
||||||
db.addOutstandingMessages(txn, contactId,
|
db.addOutstandingMessages(txn, contactId,
|
||||||
Collections.singletonList(messageId));
|
Collections.singletonList(messageId), Long.MAX_VALUE);
|
||||||
|
|
||||||
// The message should no longer be sendable
|
// The message should no longer be sendable
|
||||||
it = db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator();
|
it = db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator();
|
||||||
@@ -913,11 +895,11 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
db.setSubscriptions(txn, contactId, Arrays.asList(group), 1);
|
db.setSubscriptions(txn, contactId, Arrays.asList(group), 1);
|
||||||
db.addGroupMessage(txn, message);
|
db.addGroupMessage(txn, message);
|
||||||
|
|
||||||
// Set the sendability to > 0 and the status to SEEN
|
// Set the sendability to > 0 and the status to seen = true
|
||||||
db.setSendability(txn, messageId, 1);
|
db.setSendability(txn, messageId, 1);
|
||||||
db.setStatus(txn, contactId, messageId, SEEN);
|
db.addStatus(txn, contactId, messageId, true);
|
||||||
|
|
||||||
// The message is not sendable because its status is SEEN
|
// The message is not sendable because its status is seen = true
|
||||||
assertNull(db.getRawMessageIfSendable(txn, contactId, messageId));
|
assertNull(db.getRawMessageIfSendable(txn, contactId, messageId));
|
||||||
|
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
@@ -936,9 +918,9 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
db.setSubscriptions(txn, contactId, Arrays.asList(group), 1);
|
db.setSubscriptions(txn, contactId, Arrays.asList(group), 1);
|
||||||
db.addGroupMessage(txn, message);
|
db.addGroupMessage(txn, message);
|
||||||
|
|
||||||
// Set the sendability to 0 and the status to NEW
|
// Set the sendability to 0 and the status to seen = false
|
||||||
db.setSendability(txn, messageId, 0);
|
db.setSendability(txn, messageId, 0);
|
||||||
db.setStatus(txn, contactId, messageId, NEW);
|
db.addStatus(txn, contactId, messageId, false);
|
||||||
|
|
||||||
// The message is not sendable because its sendability is 0
|
// The message is not sendable because its sendability is 0
|
||||||
assertNull(db.getRawMessageIfSendable(txn, contactId, messageId));
|
assertNull(db.getRawMessageIfSendable(txn, contactId, messageId));
|
||||||
@@ -961,9 +943,9 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
db.setRetentionTime(txn, contactId, timestamp + 1, 1);
|
db.setRetentionTime(txn, contactId, timestamp + 1, 1);
|
||||||
db.addGroupMessage(txn, message);
|
db.addGroupMessage(txn, message);
|
||||||
|
|
||||||
// Set the sendability to > 0 and the status to NEW
|
// Set the sendability to > 0 and the status to seen = false
|
||||||
db.setSendability(txn, messageId, 1);
|
db.setSendability(txn, messageId, 1);
|
||||||
db.setStatus(txn, contactId, messageId, NEW);
|
db.addStatus(txn, contactId, messageId, false);
|
||||||
|
|
||||||
// The message is not sendable because it's too old
|
// The message is not sendable because it's too old
|
||||||
assertNull(db.getRawMessageIfSendable(txn, contactId, messageId));
|
assertNull(db.getRawMessageIfSendable(txn, contactId, messageId));
|
||||||
@@ -984,9 +966,9 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
db.setSubscriptions(txn, contactId, Arrays.asList(group), 1);
|
db.setSubscriptions(txn, contactId, Arrays.asList(group), 1);
|
||||||
db.addGroupMessage(txn, message);
|
db.addGroupMessage(txn, message);
|
||||||
|
|
||||||
// Set the sendability to > 0 and the status to NEW
|
// Set the sendability to > 0 and the status to seen = false
|
||||||
db.setSendability(txn, messageId, 1);
|
db.setSendability(txn, messageId, 1);
|
||||||
db.setStatus(txn, contactId, messageId, NEW);
|
db.addStatus(txn, contactId, messageId, false);
|
||||||
|
|
||||||
// The message is sendable so it should be returned
|
// The message is sendable so it should be returned
|
||||||
byte[] b = db.getRawMessageIfSendable(txn, contactId, messageId);
|
byte[] b = db.getRawMessageIfSendable(txn, contactId, messageId);
|
||||||
@@ -1042,7 +1024,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
assertEquals(contactId, db.addContact(txn));
|
assertEquals(contactId, db.addContact(txn));
|
||||||
db.addSubscription(txn, group);
|
db.addSubscription(txn, group);
|
||||||
db.addGroupMessage(txn, message);
|
db.addGroupMessage(txn, message);
|
||||||
db.setStatus(txn, contactId, messageId, NEW);
|
db.addStatus(txn, contactId, messageId, false);
|
||||||
|
|
||||||
// There's no contact subscription for the group
|
// There's no contact subscription for the group
|
||||||
assertFalse(db.setStatusSeenIfVisible(txn, contactId, messageId));
|
assertFalse(db.setStatusSeenIfVisible(txn, contactId, messageId));
|
||||||
@@ -1062,7 +1044,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
db.addSubscription(txn, group);
|
db.addSubscription(txn, group);
|
||||||
db.addGroupMessage(txn, message);
|
db.addGroupMessage(txn, message);
|
||||||
db.setSubscriptions(txn, contactId, Arrays.asList(group), 1);
|
db.setSubscriptions(txn, contactId, Arrays.asList(group), 1);
|
||||||
db.setStatus(txn, contactId, messageId, NEW);
|
db.addStatus(txn, contactId, messageId, false);
|
||||||
|
|
||||||
// The subscription is not visible
|
// The subscription is not visible
|
||||||
assertFalse(db.setStatusSeenIfVisible(txn, contactId, messageId));
|
assertFalse(db.setStatusSeenIfVisible(txn, contactId, messageId));
|
||||||
@@ -1085,7 +1067,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
db.addGroupMessage(txn, message);
|
db.addGroupMessage(txn, message);
|
||||||
|
|
||||||
// The message has already been seen by the contact
|
// The message has already been seen by the contact
|
||||||
db.setStatus(txn, contactId, messageId, SEEN);
|
db.addStatus(txn, contactId, messageId, true);
|
||||||
|
|
||||||
assertTrue(db.setStatusSeenIfVisible(txn, contactId, messageId));
|
assertTrue(db.setStatusSeenIfVisible(txn, contactId, messageId));
|
||||||
|
|
||||||
@@ -1107,7 +1089,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
db.addGroupMessage(txn, message);
|
db.addGroupMessage(txn, message);
|
||||||
|
|
||||||
// The message has not been seen by the contact
|
// The message has not been seen by the contact
|
||||||
db.setStatus(txn, contactId, messageId, NEW);
|
db.addStatus(txn, contactId, messageId, false);
|
||||||
|
|
||||||
assertTrue(db.setStatusSeenIfVisible(txn, contactId, messageId));
|
assertTrue(db.setStatusSeenIfVisible(txn, contactId, messageId));
|
||||||
|
|
||||||
@@ -1828,7 +1810,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
|
|
||||||
private Database<Connection> open(boolean resume) throws Exception {
|
private Database<Connection> open(boolean resume) throws Exception {
|
||||||
Database<Connection> db = new H2Database(new TestDatabaseConfig(testDir,
|
Database<Connection> db = new H2Database(new TestDatabaseConfig(testDir,
|
||||||
MAX_SIZE));
|
MAX_SIZE), new SystemClock());
|
||||||
db.open(resume);
|
db.open(resume);
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user