mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-17 05:09:53 +01:00
Reset message status when contact unsubscribes from group. Dev task #68.
This commit is contained in:
@@ -703,7 +703,7 @@ interface Database<T> {
|
|||||||
* true, unless an update with an equal or higher version number has
|
* true, unless an update with an equal or higher version number has
|
||||||
* already been received from the contact.
|
* already been received from the contact.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: subscription write.
|
* Locking: message write, subscription write.
|
||||||
*/
|
*/
|
||||||
boolean setGroups(T txn, ContactId c, Collection<Group> groups,
|
boolean setGroups(T txn, ContactId c, Collection<Group> groups,
|
||||||
long version) throws DbException;
|
long version) throws DbException;
|
||||||
|
|||||||
@@ -1500,22 +1500,27 @@ DatabaseCleaner.Callback {
|
|||||||
boolean updated;
|
boolean updated;
|
||||||
contactLock.readLock().lock();
|
contactLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
subscriptionLock.writeLock().lock();
|
messageLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
T txn = db.startTransaction();
|
subscriptionLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
if(!db.containsContact(txn, c))
|
T txn = db.startTransaction();
|
||||||
throw new NoSuchContactException();
|
try {
|
||||||
Collection<Group> groups = u.getGroups();
|
if(!db.containsContact(txn, c))
|
||||||
long version = u.getVersion();
|
throw new NoSuchContactException();
|
||||||
updated = db.setGroups(txn, c, groups, version);
|
Collection<Group> groups = u.getGroups();
|
||||||
db.commitTransaction(txn);
|
long version = u.getVersion();
|
||||||
} catch(DbException e) {
|
updated = db.setGroups(txn, c, groups, version);
|
||||||
db.abortTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
throw e;
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
subscriptionLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
subscriptionLock.writeLock().unlock();
|
messageLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
contactLock.readLock().unlock();
|
contactLock.readLock().unlock();
|
||||||
|
|||||||
@@ -21,10 +21,12 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
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;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@@ -2896,8 +2898,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
throws DbException {
|
throws DbException {
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
try {
|
try {
|
||||||
String sql = "UPDATE statuses"
|
String sql = "UPDATE statuses SET expiry = 0, txCount = 0"
|
||||||
+ " SET expiry = 0, txCount = 0"
|
|
||||||
+ " WHERE messageId = ? AND contactId = ?";
|
+ " WHERE messageId = ? AND contactId = ?";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setBytes(1, m.getBytes());
|
ps.setBytes(1, m.getBytes());
|
||||||
@@ -2949,6 +2950,43 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
ps.close();
|
ps.close();
|
||||||
// Return false if the update is obsolete
|
// Return false if the update is obsolete
|
||||||
if(affected == 0) return false;
|
if(affected == 0) return false;
|
||||||
|
// Find any messages in groups that are being removed
|
||||||
|
Set<GroupId> newIds = new HashSet<GroupId>();
|
||||||
|
for(Group g : groups) newIds.add(g.getId());
|
||||||
|
sql = "SELECT messageId, m.groupId"
|
||||||
|
+ " FROM messages AS m"
|
||||||
|
+ " JOIN contactGroups AS cg"
|
||||||
|
+ " ON m.groupId = cg.groupId"
|
||||||
|
+ " WHERE contactId = ?";
|
||||||
|
ps = txn.prepareStatement(sql);
|
||||||
|
ps.setInt(1, c.getInt());
|
||||||
|
rs = ps.executeQuery();
|
||||||
|
List<MessageId> removed = new ArrayList<MessageId>();
|
||||||
|
while(rs.next()) {
|
||||||
|
if(!newIds.contains(new GroupId(rs.getBytes(2))))
|
||||||
|
removed.add(new MessageId(rs.getBytes(1)));
|
||||||
|
}
|
||||||
|
rs.close();
|
||||||
|
ps.close();
|
||||||
|
// Reset any statuses for messages in groups that are being removed
|
||||||
|
if(!removed.isEmpty()) {
|
||||||
|
sql = "UPDATE statuses SET ack = FALSE, seen = FALSE,"
|
||||||
|
+ " requested = FALSE, expiry = 0, txCount = 0"
|
||||||
|
+ " WHERE contactId = ? AND messageId = ?";
|
||||||
|
ps = txn.prepareStatement(sql);
|
||||||
|
ps.setInt(1, c.getInt());
|
||||||
|
for(MessageId m : removed) {
|
||||||
|
ps.setBytes(2, m.getBytes());
|
||||||
|
ps.addBatch();
|
||||||
|
}
|
||||||
|
int[] batchAffected = ps.executeBatch();
|
||||||
|
if(batchAffected.length != removed.size())
|
||||||
|
throw new DbStateException();
|
||||||
|
for(int i = 0; i < batchAffected.length; i++) {
|
||||||
|
if(batchAffected[i] < 0) throw new DbStateException();
|
||||||
|
}
|
||||||
|
ps.close();
|
||||||
|
}
|
||||||
// Delete the existing subscriptions, if any
|
// Delete the existing subscriptions, if any
|
||||||
sql = "DELETE FROM contactGroups WHERE contactId = ?";
|
sql = "DELETE FROM contactGroups WHERE contactId = ?";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
|
|||||||
@@ -1577,6 +1577,46 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testContactUnsubscribingResetsMessageStatus() throws Exception {
|
||||||
|
Database<Connection> db = open(false);
|
||||||
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
|
// Add a contact who subscribes to a group
|
||||||
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
|
||||||
|
db.setGroups(txn, contactId, Arrays.asList(group), 1);
|
||||||
|
|
||||||
|
// Subscribe to the group and make it visible to the contact
|
||||||
|
db.addGroup(txn, group);
|
||||||
|
db.addVisibility(txn, contactId, groupId);
|
||||||
|
|
||||||
|
// Add a message - it should be sendable to the contact
|
||||||
|
db.addMessage(txn, message, true);
|
||||||
|
db.addStatus(txn, contactId, messageId, false, false);
|
||||||
|
Collection<MessageId> sendable = db.getMessagesToSend(txn, contactId,
|
||||||
|
ONE_MEGABYTE);
|
||||||
|
assertEquals(Arrays.asList(messageId), sendable);
|
||||||
|
|
||||||
|
// Mark the message as seen - it should no longer be sendable
|
||||||
|
db.raiseSeenFlag(txn, contactId, messageId);
|
||||||
|
sendable = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
||||||
|
assertEquals(Collections.emptyList(), sendable);
|
||||||
|
|
||||||
|
// The contact unsubscribes - the message should not be sendable
|
||||||
|
db.setGroups(txn, contactId, Collections.<Group>emptyList(), 2);
|
||||||
|
sendable = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
||||||
|
assertEquals(Collections.emptyList(), sendable);
|
||||||
|
|
||||||
|
// The contact resubscribes - the message should be sendable again
|
||||||
|
db.setGroups(txn, contactId, Arrays.asList(group), 3);
|
||||||
|
sendable = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
||||||
|
assertEquals(Arrays.asList(messageId), sendable);
|
||||||
|
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExceptionHandling() throws Exception {
|
public void testExceptionHandling() throws Exception {
|
||||||
Database<Connection> db = open(false);
|
Database<Connection> db = open(false);
|
||||||
|
|||||||
Reference in New Issue
Block a user