Added a flag for making groups visible to future contacts.

This commit is contained in:
akwizgran
2013-04-13 19:27:39 +01:00
parent f2e01d88a8
commit bbdfe30e78
6 changed files with 162 additions and 13 deletions

View File

@@ -791,6 +791,13 @@ interface Database<T> {
void setTransportUpdateAcked(T txn, ContactId c, TransportId t,
long version) throws DbException;
/**
* Makes the given group visible or invisible to future contacts by default.
* <p>
* Locking: subscription write.
*/
void setVisibleToAll(T txn, GroupId g, boolean visible) throws DbException;
/**
* Updates the expiry times of the given messages with respect to the given
* contact, using the given transmission counts and the latency of the

View File

@@ -1982,22 +1982,61 @@ DatabaseCleaner.Callback {
if(!db.containsSubscription(txn, g))
throw new NoSuchSubscriptionException();
// Use HashSets for O(1) lookups, O(n) overall running time
HashSet<ContactId> newVisible =
new HashSet<ContactId>(visible);
HashSet<ContactId> oldVisible =
new HashSet<ContactId>(db.getVisibility(txn, g));
HashSet<ContactId> now = new HashSet<ContactId>(visible);
Collection<ContactId> before = db.getVisibility(txn, g);
before = new HashSet<ContactId>(before);
// Set the group's visibility for each current contact
for(ContactId c : db.getContactIds(txn)) {
boolean then = oldVisible.contains(c);
boolean now = newVisible.contains(c);
if(!then && now) {
boolean wasBefore = before.contains(c);
boolean isNow = now.contains(c);
if(!wasBefore && isNow) {
db.addVisibility(txn, c, g);
affected.add(c);
} else if(then && !now) {
} else if(wasBefore && !isNow) {
db.removeVisibility(txn, c, g);
affected.add(c);
}
}
// Make the group invisible to future contacts
db.setVisibleToAll(txn, g, false);
db.commitTransaction(txn);
} catch(DbException e) {
db.abortTransaction(txn);
throw e;
}
} finally {
subscriptionLock.writeLock().unlock();
}
} finally {
contactLock.readLock().unlock();
}
if(!affected.isEmpty())
callListeners(new LocalSubscriptionsUpdatedEvent(affected));
}
public void setVisibleToAll(GroupId g, boolean visible) throws DbException {
Collection<ContactId> affected = new ArrayList<ContactId>();
contactLock.readLock().lock();
try {
subscriptionLock.writeLock().lock();
try {
T txn = db.startTransaction();
try {
if(!db.containsSubscription(txn, g))
throw new NoSuchSubscriptionException();
// Make the group visible or invisible to future contacts
db.setVisibleToAll(txn, g, visible);
if(visible) {
// Make the group visible to all current contacts
Collection<ContactId> before = db.getVisibility(txn, g);
before = new HashSet<ContactId>(before);
for(ContactId c : db.getContactIds(txn)) {
if(!before.contains(c)) {
db.addVisibility(txn, c, g);
affected.add(c);
}
}
}
db.commitTransaction(txn);
} catch(DbException e) {
db.abortTransaction(txn);

View File

@@ -103,6 +103,7 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " (groupId HASH NOT NULL,"
+ " name VARCHAR NOT NULL,"
+ " publicKey BINARY," // Null for unrestricted groups
+ " visibleToAll BOOLEAN NOT NULL,"
+ " PRIMARY KEY (groupId))";
// Locking: subscription
@@ -573,6 +574,27 @@ abstract class JdbcDatabase implements Database<Connection> {
if(rs.next()) throw new DbStateException();
rs.close();
ps.close();
// Make groups that are visible to everyone visible to this contact
sql = "SELECT groupId FROM groups WHERE visibleToAll = TRUE";
ps = txn.prepareStatement(sql);
rs = ps.executeQuery();
Collection<byte[]> ids = new ArrayList<byte[]>();
while(rs.next()) ids.add(rs.getBytes(1));
rs.close();
ps.close();
if(!ids.isEmpty()) {
sql = "INSERT INTO groupVisibilities (contactId, groupId)"
+ " VALUES (?, ?)";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
for(byte[] id : ids) {
ps.setBytes(2, id);
ps.addBatch();
}
affected = ps.executeUpdate();
if(affected != ids.size()) throw new DbStateException();
ps.close();
}
// Create a connection time row
sql = "INSERT INTO connectionTimes (contactId, lastConnected)"
+ " VALUES (?, ?)";
@@ -893,8 +915,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
if(count > MAX_SUBSCRIPTIONS) throw new DbStateException();
if(count == MAX_SUBSCRIPTIONS) return false;
sql = "INSERT INTO groups (groupId, name, publicKey)"
+ " VALUES (?, ?, ?)";
sql = "INSERT INTO groups (groupId, name, publicKey, visibleToAll)"
+ " VALUES (?, ?, ?, FALSE)";
ps = txn.prepareStatement(sql);
ps.setBytes(1, g.getId().getBytes());
ps.setString(2, g.getName());
@@ -3376,6 +3398,23 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
public void setVisibleToAll(Connection txn, GroupId g, boolean visible)
throws DbException {
PreparedStatement ps = null;
try {
String sql = "UPDATE groups SET visibleToAll = ? WHERE groupId = ?";
ps = txn.prepareStatement(sql);
ps.setBoolean(1, visible);
ps.setBytes(2, g.getBytes());
int affected = ps.executeUpdate();
if(affected > 1) throw new DbStateException();
ps.close();
} catch(SQLException e) {
tryToClose(ps);
throw new DbException(e);
}
}
public void updateExpiryTimes(Connection txn, ContactId c,
Map<MessageId, Integer> sent, long maxLatency) throws DbException {
long now = clock.currentTimeMillis();