Fix storage sync issues

This commit is contained in:
AsamK 2024-01-28 11:46:34 +01:00
parent f92466f6be
commit 90df256e85
8 changed files with 67 additions and 51 deletions

View file

@ -155,7 +155,7 @@ public class StorageHelper {
if (updated > 0) { if (updated > 0) {
logger.warn( logger.warn(
"Found {} records that were deleted remotely but only marked unregistered locally. Removed those from local store. Recalculating diff.", "Found {} records that were deleted remotely but only marked unregistered locally. Removed those from local store.",
updated); updated);
} }
} }
@ -502,7 +502,7 @@ public class StorageHelper {
final var remote = remoteByRawId.get(rawId); final var remote = remoteByRawId.get(rawId);
final var local = localByRawId.get(rawId); final var local = localByRawId.get(rawId);
if (remote.getType() != local.getType()) { if (remote.getType() != local.getType() && local.getType() != 0) {
remoteOnlyRawIds.remove(rawId); remoteOnlyRawIds.remove(rawId);
localOnlyRawIds.remove(rawId); localOnlyRawIds.remove(rawId);
hasTypeMismatch = true; hasTypeMismatch = true;

View file

@ -324,7 +324,12 @@ public class SyncHelper {
final var recipientId = account.getRecipientTrustedResolver().resolveRecipientTrusted(c.getAddress()); final var recipientId = account.getRecipientTrustedResolver().resolveRecipientTrusted(c.getAddress());
var contact = account.getContactStore().getContact(recipientId); var contact = account.getContactStore().getContact(recipientId);
final var builder = contact == null ? Contact.newBuilder() : Contact.newBuilder(contact); final var builder = contact == null ? Contact.newBuilder() : Contact.newBuilder(contact);
if (c.getName().isPresent()) { if (c.getName().isPresent() && (
contact == null || (
contact.givenName() == null
&& contact.familyName() == null
)
)) {
builder.withGivenName(c.getName().get()); builder.withGivenName(c.getName().get());
builder.withFamilyName(null); builder.withFamilyName(null);
} }

View file

@ -1355,8 +1355,8 @@ public class ManagerImpl implements Manager {
if (thread != null) { if (thread != null) {
stopReceiveThread(thread); stopReceiveThread(thread);
} }
executor.close();
context.close(); context.close();
executor.close();
dependencies.getSignalWebSocket().disconnect(); dependencies.getSignalWebSocket().disconnect();
dependencies.getPushServiceSocket().close(); dependencies.getPushServiceSocket().close();

View file

@ -362,7 +362,7 @@ public class SignalAccount implements Closeable {
} }
private void init() { private void init() {
this.selfRecipientId = getRecipientResolver().resolveRecipient(getSelfRecipientAddress()); this.selfRecipientId = getRecipientTrustedResolver().resolveSelfRecipientTrusted(getSelfRecipientAddress());
} }
private void migrateLegacyConfigs() { private void migrateLegacyConfigs() {

View file

@ -122,13 +122,25 @@ public class GroupStore {
public void storeStorageRecord( public void storeStorageRecord(
final Connection connection, final GroupId groupId, final StorageId storageId, final byte[] storageRecord final Connection connection, final GroupId groupId, final StorageId storageId, final byte[] storageRecord
) throws SQLException { ) throws SQLException {
final var groupTable = groupId instanceof GroupIdV1 ? TABLE_GROUP_V1 : TABLE_GROUP_V2;
final var deleteSql = (
"""
UPDATE %s
SET storage_id = NULL
WHERE storage_id = ?
"""
).formatted(groupTable);
try (final var statement = connection.prepareStatement(deleteSql)) {
statement.setBytes(1, storageId.getRaw());
statement.executeUpdate();
}
final var sql = ( final var sql = (
""" """
UPDATE %s UPDATE %s
SET storage_id = ?, storage_record = ? SET storage_id = ?, storage_record = ?
WHERE group_id = ? WHERE group_id = ?
""" """
).formatted(groupId instanceof GroupIdV1 ? TABLE_GROUP_V1 : TABLE_GROUP_V2); ).formatted(groupTable);
try (final var statement = connection.prepareStatement(sql)) { try (final var statement = connection.prepareStatement(sql)) {
statement.setBytes(1, storageId.getRaw()); statement.setBytes(1, storageId.getRaw());
if (storageRecord == null) { if (storageRecord == null) {

View file

@ -37,8 +37,6 @@ import java.util.Set;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.asamk.signal.manager.config.ServiceConfig.UNREGISTERED_LIFESPAN;
public class RecipientStore implements RecipientIdCreator, RecipientResolver, RecipientTrustedResolver, ContactsStore, ProfileStore { public class RecipientStore implements RecipientIdCreator, RecipientResolver, RecipientTrustedResolver, ContactsStore, ProfileStore {
private static final Logger logger = LoggerFactory.getLogger(RecipientStore.class); private static final Logger logger = LoggerFactory.getLogger(RecipientStore.class);
@ -524,7 +522,7 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
""" """
SELECT r._id SELECT r._id
FROM %s r FROM %s r
WHERE r.storage_id IS NULL AND (r.unregistered_timestamp IS NULL OR r.unregistered_timestamp > ?) WHERE r.storage_id IS NULL AND r.unregistered_timestamp IS NULL
""" """
).formatted(TABLE_RECIPIENT); ).formatted(TABLE_RECIPIENT);
final var updateSql = ( final var updateSql = (
@ -537,7 +535,6 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
try (final var connection = database.getConnection()) { try (final var connection = database.getConnection()) {
connection.setAutoCommit(false); connection.setAutoCommit(false);
try (final var selectStmt = connection.prepareStatement(selectSql)) { try (final var selectStmt = connection.prepareStatement(selectSql)) {
selectStmt.setLong(1, System.currentTimeMillis() - UNREGISTERED_LIFESPAN);
final var recipientIds = Utils.executeQueryForStream(selectStmt, this::getRecipientIdFromResultSet) final var recipientIds = Utils.executeQueryForStream(selectStmt, this::getRecipientIdFromResultSet)
.toList(); .toList();
try (final var updateStmt = connection.prepareStatement(updateSql)) { try (final var updateStmt = connection.prepareStatement(updateSql)) {
@ -735,14 +732,25 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
final StorageId storageId, final StorageId storageId,
final byte[] storageRecord final byte[] storageRecord
) throws SQLException { ) throws SQLException {
final var sql = ( final var deleteSql = (
"""
UPDATE %s
SET storage_id = NULL
WHERE storage_id = ?
"""
).formatted(TABLE_RECIPIENT);
try (final var statement = connection.prepareStatement(deleteSql)) {
statement.setBytes(1, storageId.getRaw());
statement.executeUpdate();
}
final var insertSql = (
""" """
UPDATE %s UPDATE %s
SET storage_id = ?, storage_record = ? SET storage_id = ?, storage_record = ?
WHERE _id = ? WHERE _id = ?
""" """
).formatted(TABLE_RECIPIENT); ).formatted(TABLE_RECIPIENT);
try (final var statement = connection.prepareStatement(sql)) { try (final var statement = connection.prepareStatement(insertSql)) {
statement.setBytes(1, storageId.getRaw()); statement.setBytes(1, storageId.getRaw());
if (storageRecord == null) { if (storageRecord == null) {
statement.setNull(2, Types.BLOB); statement.setNull(2, Types.BLOB);
@ -846,7 +854,7 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
""" """
UPDATE %s UPDATE %s
SET storage_id = NULL SET storage_id = NULL
WHERE storage_id = ? AND storage_id IS NOT NULL AND unregistered_timestamp IS NOT NULL WHERE storage_id = ? AND unregistered_timestamp IS NOT NULL
""" """
).formatted(TABLE_RECIPIENT); ).formatted(TABLE_RECIPIENT);
var count = 0; var count = 0;
@ -1002,6 +1010,7 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
} }
if (!pair.second().isEmpty()) { if (!pair.second().isEmpty()) {
logger.debug("Resolved address {}, merging {} other recipients", address, pair.second().size());
try (final var connection = database.getConnection()) { try (final var connection = database.getConnection()) {
connection.setAutoCommit(false); connection.setAutoCommit(false);
mergeRecipients(connection, pair.first(), pair.second()); mergeRecipients(connection, pair.first(), pair.second());

View file

@ -105,8 +105,12 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
IdentityState identityState; IdentityState identityState;
byte[] identityKey; byte[] identityKey;
if ((remote.getIdentityState() != local.getIdentityState() && remote.getIdentityKey().isPresent()) if (remote.getIdentityKey().isPresent() && (
|| (remote.getIdentityKey().isPresent() && local.getIdentityKey().isEmpty())) { remote.getIdentityState() != local.getIdentityState()
|| local.getIdentityKey().isEmpty()
|| !account.isPrimaryDevice()
)) {
identityState = remote.getIdentityState(); identityState = remote.getIdentityState();
identityKey = remote.getIdentityKey().get(); identityKey = remote.getIdentityKey().get();
} else { } else {
@ -114,9 +118,10 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
identityKey = local.getIdentityKey().orElse(null); identityKey = local.getIdentityKey().orElse(null);
} }
if (local.getAci().isPresent() && identityKey != null && remote.getIdentityKey().isPresent() && !Arrays.equals( if (local.getAci().isPresent()
identityKey, && local.getIdentityKey().isPresent()
remote.getIdentityKey().get())) { && remote.getIdentityKey().isPresent()
&& !Arrays.equals(local.getIdentityKey().get(), remote.getIdentityKey().get())) {
logger.debug("The local and remote identity keys do not match for {}. Enqueueing a profile fetch.", logger.debug("The local and remote identity keys do not match for {}. Enqueueing a profile fetch.",
local.getAci().orElse(null)); local.getAci().orElse(null));
final var address = getRecipientAddress(local); final var address = getRecipientAddress(local);
@ -141,13 +146,12 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
PNI pni; PNI pni;
String e164; String e164;
if (!account.isPrimaryDevice() && (e164sMatchButPnisDont || pnisMatchButE164sDont)) {
if (e164sMatchButPnisDont) { if (e164sMatchButPnisDont) {
logger.debug("Matching E164s, but the PNIs differ! Trusting our local pair."); logger.debug("Matching E164s, but the PNIs differ! Trusting our local pair.");
// TODO [pnp] Schedule CDS fetch?
pni = local.getPni().get();
e164 = local.getNumber().get();
} else if (pnisMatchButE164sDont) { } else if (pnisMatchButE164sDont) {
logger.debug("Matching PNIs, but the E164s differ! Trusting our local pair."); logger.debug("Matching PNIs, but the E164s differ! Trusting our local pair.");
}
// TODO [pnp] Schedule CDS fetch? // TODO [pnp] Schedule CDS fetch?
pni = local.getPni().get(); pni = local.getPni().get();
e164 = local.getNumber().get(); e164 = local.getNumber().get();
@ -235,41 +239,25 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
|| profileShared != contactRecord.isProfileSharingEnabled() || profileShared != contactRecord.isProfileSharingEnabled()
|| archived != contactRecord.isArchived() || archived != contactRecord.isArchived()
|| hidden != contactRecord.isHidden() || hidden != contactRecord.isHidden()
|| ( || !Objects.equals(contactRecord.getSystemGivenName().orElse(null), contactGivenName)
contactRecord.getSystemGivenName().isPresent() && !contactRecord.getSystemGivenName() || !Objects.equals(contactRecord.getSystemFamilyName().orElse(null), contactFamilyName)) {
.get()
.equals(contactGivenName)
)
|| (
contactRecord.getSystemFamilyName().isPresent() && !contactRecord.getSystemFamilyName()
.get()
.equals(contactFamilyName)
)) {
logger.debug("Storing new or updated contact {}", recipientId); logger.debug("Storing new or updated contact {}", recipientId);
final var contactBuilder = contact == null ? Contact.newBuilder() : Contact.newBuilder(contact); final var contactBuilder = contact == null ? Contact.newBuilder() : Contact.newBuilder(contact);
final var newContact = contactBuilder.withIsBlocked(contactRecord.isBlocked()) final var newContact = contactBuilder.withIsBlocked(contactRecord.isBlocked())
.withIsProfileSharingEnabled(contactRecord.isProfileSharingEnabled()) .withIsProfileSharingEnabled(contactRecord.isProfileSharingEnabled())
.withIsArchived(contactRecord.isArchived()) .withIsArchived(contactRecord.isArchived())
.withIsHidden(contactRecord.isHidden()); .withIsHidden(contactRecord.isHidden())
if (contactRecord.getSystemGivenName().isPresent() || contactRecord.getSystemFamilyName().isPresent()) { .withGivenName(contactRecord.getSystemGivenName().orElse(null))
newContact.withGivenName(contactRecord.getSystemGivenName().orElse(null))
.withFamilyName(contactRecord.getSystemFamilyName().orElse(null)); .withFamilyName(contactRecord.getSystemFamilyName().orElse(null));
}
account.getRecipientStore().storeContact(connection, recipientId, newContact.build()); account.getRecipientStore().storeContact(connection, recipientId, newContact.build());
} }
final var profile = recipient.getProfile(); final var profile = recipient.getProfile();
final var profileGivenName = profile == null ? null : profile.getGivenName(); final var profileGivenName = profile == null ? null : profile.getGivenName();
final var profileFamilyName = profile == null ? null : profile.getFamilyName(); final var profileFamilyName = profile == null ? null : profile.getFamilyName();
if (( if (!Objects.equals(contactRecord.getProfileGivenName().orElse(null), profileGivenName) || !Objects.equals(
contactRecord.getProfileGivenName().isPresent() && !contactRecord.getProfileGivenName() contactRecord.getProfileFamilyName().orElse(null),
.get() profileFamilyName)) {
.equals(profileGivenName)
) || (
contactRecord.getProfileFamilyName().isPresent() && !contactRecord.getProfileFamilyName()
.get()
.equals(profileFamilyName)
)) {
final var profileBuilder = profile == null ? Profile.newBuilder() : Profile.newBuilder(profile); final var profileBuilder = profile == null ? Profile.newBuilder() : Profile.newBuilder(profile);
final var newProfile = profileBuilder.withGivenName(contactRecord.getProfileGivenName().orElse(null)) final var newProfile = profileBuilder.withGivenName(contactRecord.getProfileGivenName().orElse(null))
.withFamilyName(contactRecord.getProfileFamilyName().orElse(null)) .withFamilyName(contactRecord.getProfileFamilyName().orElse(null))
@ -285,7 +273,7 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
logger.warn("Received invalid contact profile key from storage"); logger.warn("Received invalid contact profile key from storage");
} }
} }
if (contactRecord.getIdentityKey().isPresent() && contactRecord.getAci().orElse(null) != null) { if (contactRecord.getIdentityKey().isPresent() && contactRecord.getAci().isPresent()) {
try { try {
logger.trace("Storing identity key {}", recipientId); logger.trace("Storing identity key {}", recipientId);
final var identityKey = new IdentityKey(contactRecord.getIdentityKey().get()); final var identityKey = new IdentityKey(contactRecord.getIdentityKey().get());

View file

@ -55,7 +55,9 @@ abstract class DefaultStorageRecordProcessor<E extends SignalRecord> implements
} }
if (matchedRecords.contains(local.get())) { if (matchedRecords.contains(local.get())) {
debug(remote.getId(), remote, "Multiple remote records map to the same local record! Ignoring this one."); debug(remote.getId(),
remote,
"Multiple remote records map to the same local record " + local.get() + "! Ignoring this one.");
return; return;
} }