mirror of
https://github.com/AsamK/signal-cli
synced 2025-08-29 02:20:39 +00:00
Improve performance when fetching multiple profiles
This commit is contained in:
parent
365323f574
commit
c8cc428e3f
2 changed files with 51 additions and 20 deletions
|
@ -33,6 +33,7 @@ import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import io.reactivex.rxjava3.core.Flowable;
|
||||||
import io.reactivex.rxjava3.core.Maybe;
|
import io.reactivex.rxjava3.core.Maybe;
|
||||||
import io.reactivex.rxjava3.core.Single;
|
import io.reactivex.rxjava3.core.Single;
|
||||||
|
|
||||||
|
@ -59,16 +60,16 @@ public final class ProfileHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ProfileKeyCredential> getRecipientProfileKeyCredential(List<RecipientId> recipientIds) {
|
public List<ProfileKeyCredential> getRecipientProfileKeyCredential(List<RecipientId> recipientIds) {
|
||||||
final var profileFetches = recipientIds.stream().map(recipientId -> {
|
try {
|
||||||
var profileKeyCredential = account.getProfileStore().getProfileKeyCredential(recipientId);
|
account.getRecipientStore().setBulkUpdating(true);
|
||||||
if (profileKeyCredential != null) {
|
final var profileFetches = Flowable.fromIterable(recipientIds)
|
||||||
return null;
|
.filter(recipientId -> account.getProfileStore().getProfileKeyCredential(recipientId) == null)
|
||||||
}
|
.map(recipientId -> retrieveProfile(recipientId,
|
||||||
|
SignalServiceProfile.RequestType.PROFILE_AND_CREDENTIAL).onErrorComplete());
|
||||||
return retrieveProfile(recipientId,
|
Maybe.merge(profileFetches, 10).blockingSubscribe();
|
||||||
SignalServiceProfile.RequestType.PROFILE_AND_CREDENTIAL).onErrorComplete();
|
} finally {
|
||||||
}).filter(Objects::nonNull).toList();
|
account.getRecipientStore().setBulkUpdating(false);
|
||||||
Maybe.merge(profileFetches).blockingSubscribe();
|
}
|
||||||
|
|
||||||
return recipientIds.stream().map(r -> account.getProfileStore().getProfileKeyCredential(r)).toList();
|
return recipientIds.stream().map(r -> account.getProfileStore().getProfileKeyCredential(r)).toList();
|
||||||
}
|
}
|
||||||
|
@ -158,15 +159,16 @@ public final class ProfileHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Profile> getRecipientProfile(List<RecipientId> recipientIds) {
|
public List<Profile> getRecipientProfile(List<RecipientId> recipientIds) {
|
||||||
final var profileFetches = recipientIds.stream().map(recipientId -> {
|
try {
|
||||||
var profile = account.getProfileStore().getProfile(recipientId);
|
account.getRecipientStore().setBulkUpdating(true);
|
||||||
if (!isProfileRefreshRequired(profile)) {
|
final var profileFetches = Flowable.fromIterable(recipientIds)
|
||||||
return null;
|
.filter(recipientId -> isProfileRefreshRequired(account.getProfileStore().getProfile(recipientId)))
|
||||||
}
|
.map(recipientId -> retrieveProfile(recipientId,
|
||||||
|
SignalServiceProfile.RequestType.PROFILE).onErrorComplete());
|
||||||
return retrieveProfile(recipientId, SignalServiceProfile.RequestType.PROFILE).onErrorComplete();
|
Maybe.merge(profileFetches, 10).blockingSubscribe();
|
||||||
}).filter(Objects::nonNull).toList();
|
} finally {
|
||||||
Maybe.merge(profileFetches).blockingSubscribe();
|
account.getRecipientStore().setBulkUpdating(false);
|
||||||
|
}
|
||||||
|
|
||||||
return recipientIds.stream().map(r -> account.getProfileStore().getProfile(r)).toList();
|
return recipientIds.stream().map(r -> account.getProfileStore().getProfile(r)).toList();
|
||||||
}
|
}
|
||||||
|
@ -215,6 +217,7 @@ public final class ProfileHelper {
|
||||||
) {
|
) {
|
||||||
var profile = account.getProfileStore().getProfile(recipientId);
|
var profile = account.getProfileStore().getProfile(recipientId);
|
||||||
if (profile == null || !Objects.equals(avatarPath, profile.getAvatarUrlPath())) {
|
if (profile == null || !Objects.equals(avatarPath, profile.getAvatarUrlPath())) {
|
||||||
|
logger.trace("Downloading profile avatar for {}", recipientId);
|
||||||
downloadProfileAvatar(context.getRecipientHelper().resolveSignalServiceAddress(recipientId),
|
downloadProfileAvatar(context.getRecipientHelper().resolveSignalServiceAddress(recipientId),
|
||||||
avatarPath,
|
avatarPath,
|
||||||
profileKey);
|
profileKey);
|
||||||
|
@ -243,11 +246,17 @@ public final class ProfileHelper {
|
||||||
var unidentifiedAccess = getUnidentifiedAccess(recipientId);
|
var unidentifiedAccess = getUnidentifiedAccess(recipientId);
|
||||||
var profileKey = Optional.fromNullable(account.getProfileStore().getProfileKey(recipientId));
|
var profileKey = Optional.fromNullable(account.getProfileStore().getProfileKey(recipientId));
|
||||||
|
|
||||||
|
logger.trace("Retrieving profile for {} {}",
|
||||||
|
recipientId,
|
||||||
|
profileKey.isPresent() ? "with profile key" : "without profile key");
|
||||||
final var address = context.getRecipientHelper().resolveSignalServiceAddress(recipientId);
|
final var address = context.getRecipientHelper().resolveSignalServiceAddress(recipientId);
|
||||||
return retrieveProfile(address, profileKey, unidentifiedAccess, requestType).doOnSuccess(p -> {
|
return retrieveProfile(address, profileKey, unidentifiedAccess, requestType).doOnSuccess(p -> {
|
||||||
|
logger.trace("Got new profile for {}", recipientId);
|
||||||
final var encryptedProfile = p.getProfile();
|
final var encryptedProfile = p.getProfile();
|
||||||
|
|
||||||
if (requestType == SignalServiceProfile.RequestType.PROFILE_AND_CREDENTIAL) {
|
if (requestType == SignalServiceProfile.RequestType.PROFILE_AND_CREDENTIAL
|
||||||
|
|| account.getProfileStore().getProfileKeyCredential(recipientId) == null) {
|
||||||
|
logger.trace("Storing profile credential");
|
||||||
final var profileKeyCredential = p.getProfileKeyCredential().orNull();
|
final var profileKeyCredential = p.getProfileKeyCredential().orNull();
|
||||||
account.getProfileStore().storeProfileKeyCredential(recipientId, profileKeyCredential);
|
account.getProfileStore().storeProfileKeyCredential(recipientId, profileKeyCredential);
|
||||||
}
|
}
|
||||||
|
@ -256,6 +265,7 @@ public final class ProfileHelper {
|
||||||
|
|
||||||
Profile newProfile = null;
|
Profile newProfile = null;
|
||||||
if (profileKey.isPresent()) {
|
if (profileKey.isPresent()) {
|
||||||
|
logger.trace("Decrypting profile");
|
||||||
newProfile = decryptProfileAndDownloadAvatar(recipientId, profileKey.get(), encryptedProfile);
|
newProfile = decryptProfileAndDownloadAvatar(recipientId, profileKey.get(), encryptedProfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,15 +278,18 @@ public final class ProfileHelper {
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.trace("Storing profile");
|
||||||
account.getProfileStore().storeProfile(recipientId, newProfile);
|
account.getProfileStore().storeProfile(recipientId, newProfile);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
logger.trace("Storing identity");
|
||||||
var newIdentity = account.getIdentityKeyStore()
|
var newIdentity = account.getIdentityKeyStore()
|
||||||
.saveIdentity(recipientId,
|
.saveIdentity(recipientId,
|
||||||
new IdentityKey(Base64.getDecoder().decode(encryptedProfile.getIdentityKey())),
|
new IdentityKey(Base64.getDecoder().decode(encryptedProfile.getIdentityKey())),
|
||||||
new Date());
|
new Date());
|
||||||
|
|
||||||
if (newIdentity) {
|
if (newIdentity) {
|
||||||
|
logger.trace("Archiving old sessions");
|
||||||
account.getSessionStore().archiveSessions(recipientId);
|
account.getSessionStore().archiveSessions(recipientId);
|
||||||
account.getSenderKeyStore().deleteSharedWith(recipientId);
|
account.getSenderKeyStore().deleteSharedWith(recipientId);
|
||||||
}
|
}
|
||||||
|
@ -284,6 +297,7 @@ public final class ProfileHelper {
|
||||||
logger.warn("Got invalid identity key in profile for {}",
|
logger.warn("Got invalid identity key in profile for {}",
|
||||||
context.getRecipientHelper().resolveSignalServiceAddress(recipientId).getIdentifier());
|
context.getRecipientHelper().resolveSignalServiceAddress(recipientId).getIdentifier());
|
||||||
}
|
}
|
||||||
|
logger.trace("Done handling retrieved profile");
|
||||||
}).doOnError(e -> {
|
}).doOnError(e -> {
|
||||||
logger.warn("Failed to retrieve profile, ignoring: {}", e.getMessage());
|
logger.warn("Failed to retrieve profile, ignoring: {}", e.getMessage());
|
||||||
final var profile = account.getProfileStore().getProfile(recipientId);
|
final var profile = account.getProfileStore().getProfile(recipientId);
|
||||||
|
|
|
@ -47,6 +47,7 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
|
||||||
private final Map<Long, Long> recipientsMerged = new HashMap<>();
|
private final Map<Long, Long> recipientsMerged = new HashMap<>();
|
||||||
|
|
||||||
private long lastId;
|
private long lastId;
|
||||||
|
private boolean isBulkUpdating;
|
||||||
|
|
||||||
public static RecipientStore load(File file, RecipientMergeHandler recipientMergeHandler) throws IOException {
|
public static RecipientStore load(File file, RecipientMergeHandler recipientMergeHandler) throws IOException {
|
||||||
final var objectMapper = Utils.createStorageObjectMapper();
|
final var objectMapper = Utils.createStorageObjectMapper();
|
||||||
|
@ -130,6 +131,19 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
|
||||||
this.lastId = lastId;
|
this.lastId = lastId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isBulkUpdating() {
|
||||||
|
return isBulkUpdating;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBulkUpdating(final boolean bulkUpdating) {
|
||||||
|
isBulkUpdating = bulkUpdating;
|
||||||
|
if (!bulkUpdating) {
|
||||||
|
synchronized (recipients) {
|
||||||
|
saveLocked();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public RecipientAddress resolveRecipientAddress(RecipientId recipientId) {
|
public RecipientAddress resolveRecipientAddress(RecipientId recipientId) {
|
||||||
synchronized (recipients) {
|
synchronized (recipients) {
|
||||||
return getRecipient(recipientId).getAddress();
|
return getRecipient(recipientId).getAddress();
|
||||||
|
@ -483,6 +497,9 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveLocked() {
|
private void saveLocked() {
|
||||||
|
if (isBulkUpdating) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
final var base64 = Base64.getEncoder();
|
final var base64 = Base64.getEncoder();
|
||||||
var storage = new Storage(recipients.entrySet().stream().map(pair -> {
|
var storage = new Storage(recipients.entrySet().stream().map(pair -> {
|
||||||
final var recipient = pair.getValue();
|
final var recipient = pair.getValue();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue