Store messages in cache by recipient id

This commit is contained in:
AsamK 2021-04-21 18:06:48 +02:00
parent 8a0c6cae15
commit 2ef59d692a
4 changed files with 86 additions and 13 deletions

View file

@ -1629,6 +1629,15 @@ public class Manager implements Closeable {
try { try {
content = decryptMessage(envelope); content = decryptMessage(envelope);
} catch (org.whispersystems.libsignal.UntrustedIdentityException e) { } catch (org.whispersystems.libsignal.UntrustedIdentityException e) {
if (!envelope.hasSource()) {
final var recipientId = resolveRecipient(((org.whispersystems.libsignal.UntrustedIdentityException) e)
.getName());
try {
account.getMessageCache().replaceSender(cachedMessage, recipientId);
} catch (IOException ioException) {
logger.warn("Failed to move cached message to recipient folder: {}", ioException.getMessage());
}
}
return; return;
} catch (Exception er) { } catch (Exception er) {
// All other errors are not recoverable, so delete the cached message // All other errors are not recoverable, so delete the cached message
@ -1671,8 +1680,11 @@ public class Manager implements Closeable {
final CachedMessage[] cachedMessage = {null}; final CachedMessage[] cachedMessage = {null};
try { try {
var result = messagePipe.readOrEmpty(timeout, unit, envelope1 -> { var result = messagePipe.readOrEmpty(timeout, unit, envelope1 -> {
final var recipientId = envelope1.hasSource()
? resolveRecipient(envelope1.getSourceIdentifier())
: null;
// store message on disk, before acknowledging receipt to the server // store message on disk, before acknowledging receipt to the server
cachedMessage[0] = account.getMessageCache().cacheMessage(envelope1); cachedMessage[0] = account.getMessageCache().cacheMessage(envelope1, recipientId);
}); });
if (result.isPresent()) { if (result.isPresent()) {
envelope = result.get(); envelope = result.get();
@ -1703,8 +1715,7 @@ public class Manager implements Closeable {
if (envelope.hasSource()) { if (envelope.hasSource()) {
// Store uuid if we don't have it already // Store uuid if we don't have it already
var source = envelope.getSourceAddress(); resolveRecipientTrusted(envelope.getSourceAddress());
resolveSignalServiceAddress(source);
} }
if (!envelope.isReceipt()) { if (!envelope.isReceipt()) {
try { try {
@ -1736,8 +1747,19 @@ public class Manager implements Closeable {
} else { } else {
handler.handleMessage(envelope, content, exception); handler.handleMessage(envelope, content, exception);
} }
if (!(exception instanceof org.whispersystems.libsignal.UntrustedIdentityException)) {
if (cachedMessage[0] != null) { if (cachedMessage[0] != null) {
if (exception instanceof org.whispersystems.libsignal.UntrustedIdentityException) {
if (!envelope.hasSource()) {
final var recipientId = resolveRecipient(((org.whispersystems.libsignal.UntrustedIdentityException) exception)
.getName());
try {
cachedMessage[0] = account.getMessageCache().replaceSender(cachedMessage[0], recipientId);
} catch (IOException ioException) {
logger.warn("Failed to move cached message to recipient folder: {}",
ioException.getMessage());
}
}
} else {
cachedMessage[0].delete(); cachedMessage[0].delete();
} }
} }
@ -2461,7 +2483,12 @@ public class Manager implements Closeable {
var canonicalizedNumber = UuidUtil.isUuid(identifier) var canonicalizedNumber = UuidUtil.isUuid(identifier)
? identifier ? identifier
: PhoneNumberFormatter.formatNumber(identifier, account.getUsername()); : PhoneNumberFormatter.formatNumber(identifier, account.getUsername());
var address = Utils.getSignalServiceAddressFromIdentifier(canonicalizedNumber);
return resolveRecipient(canonicalizedNumber);
}
private RecipientId resolveRecipient(final String identifier) {
var address = Utils.getSignalServiceAddressFromIdentifier(identifier);
return resolveRecipient(address); return resolveRecipient(address);
} }

View file

@ -244,6 +244,7 @@ public class SignalAccount implements Closeable {
private void mergeRecipients(RecipientId recipientId, RecipientId toBeMergedRecipientId) { private void mergeRecipients(RecipientId recipientId, RecipientId toBeMergedRecipientId) {
sessionStore.mergeRecipients(recipientId, toBeMergedRecipientId); sessionStore.mergeRecipients(recipientId, toBeMergedRecipientId);
identityKeyStore.mergeRecipients(recipientId, toBeMergedRecipientId); identityKeyStore.mergeRecipients(recipientId, toBeMergedRecipientId);
messageCache.mergeRecipients(recipientId, toBeMergedRecipientId);
} }
public static File getFileName(File dataPath, String username) { public static File getFileName(File dataPath, String username) {

View file

@ -19,6 +19,10 @@ public final class CachedMessage {
this.file = file; this.file = file;
} }
File getFile() {
return file;
}
public SignalServiceEnvelope loadEnvelope() { public SignalServiceEnvelope loadEnvelope() {
try { try {
return MessageCacheUtils.loadEnvelope(file); return MessageCacheUtils.loadEnvelope(file);
@ -34,5 +38,10 @@ public final class CachedMessage {
} catch (IOException e) { } catch (IOException e) {
logger.warn("Failed to delete cached message file “{}”, ignoring: {}", file, e.getMessage()); logger.warn("Failed to delete cached message file “{}”, ignoring: {}", file, e.getMessage());
} }
// Delete parent directory, if empty
try {
Files.delete(file.toPath().getParent());
} catch (IOException ignored) {
}
} }
} }

View file

@ -1,5 +1,6 @@
package org.asamk.signal.manager.storage.messageCache; package org.asamk.signal.manager.storage.messageCache;
import org.asamk.signal.manager.storage.recipients.RecipientId;
import org.asamk.signal.manager.util.IOUtils; import org.asamk.signal.manager.util.IOUtils;
import org.asamk.signal.manager.util.MessageCacheUtils; import org.asamk.signal.manager.util.MessageCacheUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -49,12 +50,11 @@ public class MessageCache {
}).map(CachedMessage::new).collect(Collectors.toList()); }).map(CachedMessage::new).collect(Collectors.toList());
} }
public CachedMessage cacheMessage(SignalServiceEnvelope envelope) { public CachedMessage cacheMessage(SignalServiceEnvelope envelope, RecipientId recipientId) {
final var now = new Date().getTime(); final var now = new Date().getTime();
final var source = envelope.hasSource() ? envelope.getSourceAddress().getLegacyIdentifier() : "";
try { try {
var cacheFile = getMessageCacheFile(source, now, envelope.getTimestamp()); var cacheFile = getMessageCacheFile(recipientId, now, envelope.getTimestamp());
MessageCacheUtils.storeEnvelope(envelope, cacheFile); MessageCacheUtils.storeEnvelope(envelope, cacheFile);
return new CachedMessage(cacheFile); return new CachedMessage(cacheFile);
} catch (IOException e) { } catch (IOException e) {
@ -63,17 +63,53 @@ public class MessageCache {
} }
} }
private File getMessageCachePath(String sender) { public CachedMessage replaceSender(CachedMessage cachedMessage, RecipientId sender) throws IOException {
if (sender == null || sender.isEmpty()) { final var cacheFile = getMessageCacheFile(sender, cachedMessage.getFile().getName());
if (cacheFile.equals(cachedMessage.getFile())) {
return cachedMessage;
}
Files.move(cachedMessage.getFile().toPath(), cacheFile.toPath());
return new CachedMessage(cacheFile);
}
private File getMessageCachePath(RecipientId recipientId) {
if (recipientId == null) {
return messageCachePath; return messageCachePath;
} }
var sender = String.valueOf(recipientId.getId());
return new File(messageCachePath, sender.replace("/", "_")); return new File(messageCachePath, sender.replace("/", "_"));
} }
private File getMessageCacheFile(String sender, long now, long timestamp) throws IOException { private File getMessageCacheFile(RecipientId recipientId, String filename) throws IOException {
var cachePath = getMessageCachePath(sender); var cachePath = getMessageCachePath(recipientId);
IOUtils.createPrivateDirectories(cachePath);
return new File(cachePath, filename);
}
private File getMessageCacheFile(RecipientId recipientId, long now, long timestamp) throws IOException {
var cachePath = getMessageCachePath(recipientId);
IOUtils.createPrivateDirectories(cachePath); IOUtils.createPrivateDirectories(cachePath);
return new File(cachePath, now + "_" + timestamp); return new File(cachePath, now + "_" + timestamp);
} }
public void mergeRecipients(final RecipientId recipientId, final RecipientId toBeMergedRecipientId) {
final var toBeMergedMessageCachePath = getMessageCachePath(toBeMergedRecipientId);
if (!toBeMergedMessageCachePath.exists()) {
return;
}
for (var file : Objects.requireNonNull(toBeMergedMessageCachePath.listFiles())) {
if (!file.isFile()) {
continue;
}
try {
final var cacheFile = getMessageCacheFile(recipientId, file.getName());
Files.move(file.toPath(), cacheFile.toPath());
} catch (IOException e) {
logger.warn("Failed to move cache file “{}”, ignoring: {}", file, e.getMessage());
}
}
}
} }