mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-17 21:29:54 +01:00
Added lastConnected timestamp to Contact, for display in contact list.
This commit is contained in:
@@ -4,10 +4,12 @@ public class Contact {
|
|||||||
|
|
||||||
private final ContactId id;
|
private final ContactId id;
|
||||||
private final String name;
|
private final String name;
|
||||||
|
private final long lastConnected;
|
||||||
|
|
||||||
public Contact(ContactId id, String name) {
|
public Contact(ContactId id, String name, long lastConnected) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
this.lastConnected = lastConnected;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ContactId getId() {
|
public ContactId getId() {
|
||||||
@@ -18,6 +20,10 @@ public class Contact {
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getLastConnected() {
|
||||||
|
return lastConnected;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return id.hashCode();
|
return id.hashCode();
|
||||||
|
|||||||
@@ -81,7 +81,8 @@ interface Database<T> {
|
|||||||
* Adds a contact with the given name to the database and returns an ID for
|
* Adds a contact with the given name to the database and returns an ID for
|
||||||
* the contact.
|
* the contact.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: contact write, subscription write.
|
* Locking: contact write, retention write, subscription write, transport
|
||||||
|
* write, window write.
|
||||||
*/
|
*/
|
||||||
ContactId addContact(T txn, String name) throws DbException;
|
ContactId addContact(T txn, String name) throws DbException;
|
||||||
|
|
||||||
@@ -210,7 +211,7 @@ interface Database<T> {
|
|||||||
/**
|
/**
|
||||||
* Returns all contacts.
|
* Returns all contacts.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: contact read.
|
* Locking: contact read, window read.
|
||||||
*/
|
*/
|
||||||
Collection<Contact> getContacts(T txn) throws DbException;
|
Collection<Contact> getContacts(T txn) throws DbException;
|
||||||
|
|
||||||
@@ -239,6 +240,14 @@ interface Database<T> {
|
|||||||
*/
|
*/
|
||||||
MessageId getGroupMessageParent(T txn, MessageId m) throws DbException;
|
MessageId getGroupMessageParent(T txn, MessageId m) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the time at which a connection to the given contact was last
|
||||||
|
* opened or closed.
|
||||||
|
* <p>
|
||||||
|
* Locking: contact read, window read.
|
||||||
|
*/
|
||||||
|
long getLastConnected(T txn, ContactId c) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the local transport properties for the given transport.
|
* Returns the local transport properties for the given transport.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -526,8 +535,8 @@ interface Database<T> {
|
|||||||
/**
|
/**
|
||||||
* Removes a contact (and all associated state) from the database.
|
* Removes a contact (and all associated state) from the database.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: contact write, message write, subscription write,
|
* Locking: contact write, message write, retention write,
|
||||||
* transport write, window write.
|
* subscription write, transport write, window write.
|
||||||
*/
|
*/
|
||||||
void removeContact(T txn, ContactId c) throws DbException;
|
void removeContact(T txn, ContactId c) throws DbException;
|
||||||
|
|
||||||
@@ -587,6 +596,14 @@ interface Database<T> {
|
|||||||
void setConnectionWindow(T txn, ContactId c, TransportId t, long period,
|
void setConnectionWindow(T txn, ContactId c, TransportId t, long period,
|
||||||
long centre, byte[] bitmap) throws DbException;
|
long centre, byte[] bitmap) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the time at which a connection to the given contact was last
|
||||||
|
* opened or closed.
|
||||||
|
* <p>
|
||||||
|
* Locking: contact read, window write.
|
||||||
|
*/
|
||||||
|
void setLastConnected(T txn, ContactId c, long now) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the user's rating for the given author.
|
* Sets the user's rating for the given author.
|
||||||
* <p>
|
* <p>
|
||||||
|
|||||||
@@ -176,18 +176,33 @@ DatabaseCleaner.Callback {
|
|||||||
ContactId c;
|
ContactId c;
|
||||||
contactLock.writeLock().lock();
|
contactLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
subscriptionLock.writeLock().lock();
|
retentionLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
T txn = db.startTransaction();
|
subscriptionLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
c = db.addContact(txn, name);
|
transportLock.writeLock().lock();
|
||||||
db.commitTransaction(txn);
|
try {
|
||||||
} catch(DbException e) {
|
windowLock.writeLock().lock();
|
||||||
db.abortTransaction(txn);
|
try {
|
||||||
throw e;
|
T txn = db.startTransaction();
|
||||||
|
try {
|
||||||
|
c = db.addContact(txn, name);
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
windowLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
transportLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
subscriptionLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
subscriptionLock.writeLock().unlock();
|
retentionLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
contactLock.writeLock().unlock();
|
contactLock.writeLock().unlock();
|
||||||
@@ -805,14 +820,19 @@ DatabaseCleaner.Callback {
|
|||||||
public Collection<Contact> getContacts() throws DbException {
|
public Collection<Contact> getContacts() throws DbException {
|
||||||
contactLock.readLock().lock();
|
contactLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
T txn = db.startTransaction();
|
windowLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
Collection<Contact> contacts = db.getContacts(txn);
|
T txn = db.startTransaction();
|
||||||
db.commitTransaction(txn);
|
try {
|
||||||
return contacts;
|
Collection<Contact> contacts = db.getContacts(txn);
|
||||||
} catch(DbException e) {
|
db.commitTransaction(txn);
|
||||||
db.abortTransaction(txn);
|
return contacts;
|
||||||
throw e;
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
windowLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
contactLock.readLock().unlock();
|
contactLock.readLock().unlock();
|
||||||
@@ -1140,6 +1160,7 @@ DatabaseCleaner.Callback {
|
|||||||
throw new NoSuchTransportException();
|
throw new NoSuchTransportException();
|
||||||
long counter = db.incrementConnectionCounter(txn, c, t,
|
long counter = db.incrementConnectionCounter(txn, c, t,
|
||||||
period);
|
period);
|
||||||
|
db.setLastConnected(txn, c, clock.currentTimeMillis());
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
return counter;
|
return counter;
|
||||||
} catch(DbException e) {
|
} catch(DbException e) {
|
||||||
@@ -1467,30 +1488,35 @@ DatabaseCleaner.Callback {
|
|||||||
try {
|
try {
|
||||||
messageLock.writeLock().lock();
|
messageLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
subscriptionLock.writeLock().lock();
|
retentionLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
transportLock.writeLock().lock();
|
subscriptionLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
windowLock.writeLock().lock();
|
transportLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
T txn = db.startTransaction();
|
windowLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
if(!db.containsContact(txn, c))
|
T txn = db.startTransaction();
|
||||||
throw new NoSuchContactException();
|
try {
|
||||||
db.removeContact(txn, c);
|
if(!db.containsContact(txn, c))
|
||||||
db.commitTransaction(txn);
|
throw new NoSuchContactException();
|
||||||
} catch(DbException e) {
|
db.removeContact(txn, c);
|
||||||
db.abortTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
throw e;
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
windowLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
windowLock.writeLock().unlock();
|
transportLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
transportLock.writeLock().unlock();
|
subscriptionLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
subscriptionLock.writeLock().unlock();
|
retentionLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
messageLock.writeLock().unlock();
|
messageLock.writeLock().unlock();
|
||||||
@@ -1536,6 +1562,7 @@ DatabaseCleaner.Callback {
|
|||||||
throw new NoSuchTransportException();
|
throw new NoSuchTransportException();
|
||||||
db.setConnectionWindow(txn, c, t, period, centre,
|
db.setConnectionWindow(txn, c, t, period, centre,
|
||||||
bitmap);
|
bitmap);
|
||||||
|
db.setLastConnected(txn, c, clock.currentTimeMillis());
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
} catch(DbException e) {
|
} catch(DbException e) {
|
||||||
db.abortTransaction(txn);
|
db.abortTransaction(txn);
|
||||||
|
|||||||
@@ -305,6 +305,16 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " REFERENCES transports (transportId)"
|
+ " REFERENCES transports (transportId)"
|
||||||
+ " ON DELETE CASCADE)";
|
+ " ON DELETE CASCADE)";
|
||||||
|
|
||||||
|
// Locking: contact read, window
|
||||||
|
private static final String CREATE_CONNECTION_TIMES =
|
||||||
|
"CREATE TABLE connectionTimes"
|
||||||
|
+ " (contactId INT NOT NULL,"
|
||||||
|
+ " lastConnected BIGINT NOT NULL,"
|
||||||
|
+ " PRIMARY KEY (contactId),"
|
||||||
|
+ " FOREIGN KEY (contactId)"
|
||||||
|
+ " REFERENCES contacts (contactId)"
|
||||||
|
+ " ON DELETE CASCADE)";
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(JdbcDatabase.class.getName());
|
Logger.getLogger(JdbcDatabase.class.getName());
|
||||||
|
|
||||||
@@ -383,6 +393,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
s.executeUpdate(insertTypeNames(CREATE_CONTACT_TRANSPORT_VERSIONS));
|
s.executeUpdate(insertTypeNames(CREATE_CONTACT_TRANSPORT_VERSIONS));
|
||||||
s.executeUpdate(insertTypeNames(CREATE_ENDPOINTS));
|
s.executeUpdate(insertTypeNames(CREATE_ENDPOINTS));
|
||||||
s.executeUpdate(insertTypeNames(CREATE_SECRETS));
|
s.executeUpdate(insertTypeNames(CREATE_SECRETS));
|
||||||
|
s.executeUpdate(insertTypeNames(CREATE_CONNECTION_TIMES));
|
||||||
s.close();
|
s.close();
|
||||||
} catch(SQLException e) {
|
} catch(SQLException e) {
|
||||||
tryToClose(s);
|
tryToClose(s);
|
||||||
@@ -519,6 +530,15 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
if(rs.next()) throw new DbStateException();
|
if(rs.next()) throw new DbStateException();
|
||||||
rs.close();
|
rs.close();
|
||||||
ps.close();
|
ps.close();
|
||||||
|
// Create a connection time row
|
||||||
|
sql = "INSERT INTO connectionTimes (contactId, lastConnected)"
|
||||||
|
+ " VALUES (?, ?)";
|
||||||
|
ps = txn.prepareStatement(sql);
|
||||||
|
ps.setInt(1, c.getInt());
|
||||||
|
ps.setLong(2, clock.currentTimeMillis());
|
||||||
|
affected = ps.executeUpdate();
|
||||||
|
if(affected != 1) throw new DbStateException();
|
||||||
|
ps.close();
|
||||||
// Create a retention version row
|
// Create a retention version row
|
||||||
sql = "INSERT INTO retentionVersions (contactId, retention,"
|
sql = "INSERT INTO retentionVersions (contactId, retention,"
|
||||||
+ " localVersion, localAcked, remoteVersion, remoteAcked,"
|
+ " localVersion, localAcked, remoteVersion, remoteAcked,"
|
||||||
@@ -1032,14 +1052,18 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
try {
|
try {
|
||||||
String sql = "SELECT contactId, name FROM contacts";
|
String sql = "SELECT contactId, name, lastConnected"
|
||||||
|
+ " FROM contacts AS c"
|
||||||
|
+ " JOIN connectionTimes AS ct"
|
||||||
|
+ " ON c.contactId = ct.contactId";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
rs = ps.executeQuery();
|
rs = ps.executeQuery();
|
||||||
List<Contact> contacts = new ArrayList<Contact>();
|
List<Contact> contacts = new ArrayList<Contact>();
|
||||||
while(rs.next()) {
|
while(rs.next()) {
|
||||||
ContactId id = new ContactId(rs.getInt(1));
|
ContactId id = new ContactId(rs.getInt(1));
|
||||||
String name = rs.getString(2);
|
String name = rs.getString(2);
|
||||||
contacts.add(new Contact(id, name));
|
long lastConnected = rs.getLong(3);
|
||||||
|
contacts.add(new Contact(id, name, lastConnected));
|
||||||
}
|
}
|
||||||
rs.close();
|
rs.close();
|
||||||
ps.close();
|
ps.close();
|
||||||
@@ -1116,6 +1140,29 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getLastConnected(Connection txn, ContactId c)
|
||||||
|
throws DbException {
|
||||||
|
PreparedStatement ps = null;
|
||||||
|
ResultSet rs = null;
|
||||||
|
try {
|
||||||
|
String sql = "SELECT lastConnected FROM connectionTimes"
|
||||||
|
+ " WHERE contactId = ?";
|
||||||
|
ps = txn.prepareStatement(sql);
|
||||||
|
ps.setInt(1, c.getInt());
|
||||||
|
rs = ps.executeQuery();
|
||||||
|
if(!rs.next()) throw new DbStateException();
|
||||||
|
long lastConnected = rs.getLong(1);
|
||||||
|
if(rs.next()) throw new DbStateException();
|
||||||
|
rs.close();
|
||||||
|
ps.close();
|
||||||
|
return lastConnected;
|
||||||
|
} catch(SQLException e) {
|
||||||
|
tryToClose(rs);
|
||||||
|
tryToClose(ps);
|
||||||
|
throw new DbException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public TransportProperties getLocalProperties(Connection txn, TransportId t)
|
public TransportProperties getLocalProperties(Connection txn, TransportId t)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
@@ -2508,6 +2555,24 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setLastConnected(Connection txn, ContactId c, long now)
|
||||||
|
throws DbException {
|
||||||
|
PreparedStatement ps = null;
|
||||||
|
try {
|
||||||
|
String sql = "UPDATE connectionTimes SET lastConnected = ?"
|
||||||
|
+ " WHERE contactId = ?";
|
||||||
|
ps = txn.prepareStatement(sql);
|
||||||
|
ps.setLong(1, now);
|
||||||
|
ps.setInt(2, c.getInt());
|
||||||
|
int affected = ps.executeUpdate();
|
||||||
|
if(affected < 1) throw new DbStateException();
|
||||||
|
ps.close();
|
||||||
|
} catch(SQLException e) {
|
||||||
|
tryToClose(ps);
|
||||||
|
throw new DbException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Rating setRating(Connection txn, AuthorId a, Rating r)
|
public Rating setRating(Connection txn, AuthorId a, Rating r)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
|
|||||||
timestamp = System.currentTimeMillis();
|
timestamp = System.currentTimeMillis();
|
||||||
size = 1234;
|
size = 1234;
|
||||||
raw = new byte[size];
|
raw = new byte[size];
|
||||||
contact = new Contact(contactId, contactName);
|
contact = new Contact(contactId, contactName, timestamp);
|
||||||
message = new TestMessage(messageId, null, groupId, authorId, subject,
|
message = new TestMessage(messageId, null, groupId, authorId, subject,
|
||||||
timestamp, raw);
|
timestamp, raw);
|
||||||
privateMessage = new TestMessage(messageId, null, null, null, subject,
|
privateMessage = new TestMessage(messageId, null, null, null, subject,
|
||||||
|
|||||||
Reference in New Issue
Block a user