[bramble] Add support for contact aliases

Foundation for #41
This commit is contained in:
Torsten Grote
2018-10-24 18:10:53 -03:00
parent 22eed91019
commit 8fc622f85d
23 changed files with 312 additions and 46 deletions

View File

@@ -18,9 +18,13 @@ import java.util.Collection;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
import javax.inject.Inject;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.bramble.util.StringUtils.toUtf8;
@ThreadSafe
@NotNullByDefault
class ContactManagerImpl implements ContactManager {
@@ -148,6 +152,17 @@ class ContactManagerImpl implements ContactManager {
db.setContactActive(txn, c, active);
}
@Override
public void setContactAlias(ContactId c, @Nullable String alias)
throws DbException {
if (alias != null) {
int aliasLength = toUtf8(alias).length;
if (aliasLength == 0 || aliasLength > MAX_AUTHOR_NAME_LENGTH)
throw new IllegalArgumentException();
}
db.transaction(false, txn -> db.setContactAlias(txn, c, alias));
}
@Override
public boolean contactExists(Transaction txn, AuthorId remoteAuthorId,
AuthorId localAuthorId) throws DbException {

View File

@@ -616,6 +616,12 @@ interface Database<T> {
void setContactActive(T txn, ContactId c, boolean active)
throws DbException;
/**
* Sets an alias name for a contact.
*/
void setContactAlias(T txn, ContactId c, @Nullable String alias)
throws DbException;
/**
* Sets the given group's visibility to the given contact to either
* {@link Visibility VISIBLE} or {@link Visibility SHARED}.

View File

@@ -859,6 +859,16 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
transaction.attach(new ContactStatusChangedEvent(c, active));
}
@Override
public void setContactAlias(Transaction transaction, ContactId c,
String alias) throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction);
if (!db.containsContact(txn, c))
throw new NoSuchContactException();
db.setContactAlias(txn, c, alias);
}
@Override
public void setGroupVisibility(Transaction transaction, ContactId c,
GroupId g, Visibility v) throws DbException {

View File

@@ -56,6 +56,7 @@ import java.util.logging.Logger;
import javax.annotation.Nullable;
import static java.sql.Types.INTEGER;
import static java.sql.Types.VARCHAR;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.api.db.Metadata.REMOVE;
@@ -83,7 +84,7 @@ import static org.briarproject.bramble.util.LogUtils.now;
abstract class JdbcDatabase implements Database<Connection> {
// Package access for testing
static final int CODE_SCHEMA_VERSION = 40;
static final int CODE_SCHEMA_VERSION = 41;
// Rotation period offsets for incoming transport keys
private static final int OFFSET_PREV = -1;
@@ -113,6 +114,7 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " authorId _HASH NOT NULL,"
+ " formatVersion INT NOT NULL,"
+ " name _STRING NOT NULL,"
+ " alias _STRING," // Null if no alias exists
+ " publicKey _BINARY NOT NULL,"
+ " localAuthorId _HASH NOT NULL,"
+ " verified BOOLEAN NOT NULL,"
@@ -427,7 +429,11 @@ abstract class JdbcDatabase implements Database<Connection> {
// Package access for testing
List<Migration<Connection>> getMigrations() {
return Arrays.asList(new Migration38_39(), new Migration39_40());
return Arrays.asList(
new Migration38_39(),
new Migration39_40(),
new Migration40_41()
);
}
private boolean isCompactionDue(Settings s) {
@@ -1258,8 +1264,8 @@ abstract class JdbcDatabase implements Database<Connection> {
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT authorId, formatVersion, name, publicKey,"
+ " localAuthorId, verified, active"
String sql = "SELECT authorId, formatVersion, name, alias,"
+ " publicKey, localAuthorId, verified, active"
+ " FROM contacts"
+ " WHERE contactId = ?";
ps = txn.prepareStatement(sql);
@@ -1269,15 +1275,17 @@ abstract class JdbcDatabase implements Database<Connection> {
AuthorId authorId = new AuthorId(rs.getBytes(1));
int formatVersion = rs.getInt(2);
String name = rs.getString(3);
byte[] publicKey = rs.getBytes(4);
AuthorId localAuthorId = new AuthorId(rs.getBytes(5));
boolean verified = rs.getBoolean(6);
boolean active = rs.getBoolean(7);
String alias = rs.getString(4);
byte[] publicKey = rs.getBytes(5);
AuthorId localAuthorId = new AuthorId(rs.getBytes(6));
boolean verified = rs.getBoolean(7);
boolean active = rs.getBoolean(8);
rs.close();
ps.close();
Author author =
new Author(authorId, formatVersion, name, publicKey);
return new Contact(c, author, localAuthorId, verified, active);
return new Contact(c, author, localAuthorId, alias, verified,
active);
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
@@ -1292,7 +1300,7 @@ abstract class JdbcDatabase implements Database<Connection> {
ResultSet rs = null;
try {
String sql = "SELECT contactId, authorId, formatVersion, name,"
+ " publicKey, localAuthorId, verified, active"
+ " alias, publicKey, localAuthorId, verified, active"
+ " FROM contacts";
ps = txn.prepareStatement(sql);
rs = ps.executeQuery();
@@ -1302,14 +1310,15 @@ abstract class JdbcDatabase implements Database<Connection> {
AuthorId authorId = new AuthorId(rs.getBytes(2));
int formatVersion = rs.getInt(3);
String name = rs.getString(4);
byte[] publicKey = rs.getBytes(5);
String alias = rs.getString(5);
byte[] publicKey = rs.getBytes(6);
Author author =
new Author(authorId, formatVersion, name, publicKey);
AuthorId localAuthorId = new AuthorId(rs.getBytes(6));
boolean verified = rs.getBoolean(7);
boolean active = rs.getBoolean(8);
AuthorId localAuthorId = new AuthorId(rs.getBytes(7));
boolean verified = rs.getBoolean(8);
boolean active = rs.getBoolean(9);
contacts.add(new Contact(contactId, author, localAuthorId,
verified, active));
alias, verified, active));
}
rs.close();
ps.close();
@@ -1350,8 +1359,8 @@ abstract class JdbcDatabase implements Database<Connection> {
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT contactId, formatVersion, name, publicKey,"
+ " localAuthorId, verified, active"
String sql = "SELECT contactId, formatVersion, name, alias,"
+ " publicKey, localAuthorId, verified, active"
+ " FROM contacts"
+ " WHERE authorId = ?";
ps = txn.prepareStatement(sql);
@@ -1362,14 +1371,15 @@ abstract class JdbcDatabase implements Database<Connection> {
ContactId c = new ContactId(rs.getInt(1));
int formatVersion = rs.getInt(2);
String name = rs.getString(3);
byte[] publicKey = rs.getBytes(4);
AuthorId localAuthorId = new AuthorId(rs.getBytes(5));
boolean verified = rs.getBoolean(6);
boolean active = rs.getBoolean(7);
String alias = rs.getString(4);
byte[] publicKey = rs.getBytes(5);
AuthorId localAuthorId = new AuthorId(rs.getBytes(6));
boolean verified = rs.getBoolean(7);
boolean active = rs.getBoolean(8);
Author author =
new Author(remote, formatVersion, name, publicKey);
contacts.add(new Contact(c, author, localAuthorId, verified,
active));
contacts.add(new Contact(c, author, localAuthorId, alias,
verified, active));
}
rs.close();
ps.close();
@@ -2794,6 +2804,25 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
@Override
public void setContactAlias(Connection txn, ContactId c,
@Nullable String alias) throws DbException {
PreparedStatement ps = null;
try {
String sql = "UPDATE contacts SET alias = ? WHERE contactId = ?";
ps = txn.prepareStatement(sql);
if (alias == null) ps.setNull(1, VARCHAR);
else ps.setString(1, alias);
ps.setInt(2, c.getInt());
int affected = ps.executeUpdate();
if (affected < 0 || affected > 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
throw new DbException(e);
}
}
@Override
public void setGroupVisibility(Connection txn, ContactId c, GroupId g,
boolean shared) throws DbException {

View File

@@ -0,0 +1,51 @@
package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DbException;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.LogUtils.logException;
class Migration40_41 implements Migration<Connection> {
private static final Logger LOG = getLogger(Migration40_41.class.getName());
@Override
public int getStartVersion() {
return 40;
}
@Override
public int getEndVersion() {
return 41;
}
@Override
public void migrate(Connection txn) throws DbException {
Statement s = null;
try {
s = txn.createStatement();
s.execute("ALTER TABLE contacts"
// TODO how to insertTypeNames _STRING ?
+ " ADD alias VARCHAR");
} catch (SQLException e) {
tryToClose(s);
throw new DbException(e);
}
}
private void tryToClose(@Nullable Statement s) {
try {
if (s != null) s.close();
} catch (SQLException e) {
logException(LOG, WARNING, e);
}
}
}