Improve stop receive handling

Only interrupt the receive thread if it is currently waiting for new
messages from the server, otherwise just set a stop flag.
This commit is contained in:
AsamK 2022-02-12 12:26:42 +01:00
parent bb3b9692e3
commit cf0cc50e32
5 changed files with 55 additions and 35 deletions

View file

@ -58,6 +58,12 @@
{ {
"pattern":"\\Qcom/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CH\\E" "pattern":"\\Qcom/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CH\\E"
}, },
{
"pattern":"\\Qcom/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CI\\E"
},
{
"pattern":"\\Qcom/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CL\\E"
},
{ {
"pattern":"\\Qcom/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CN\\E" "pattern":"\\Qcom/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CN\\E"
}, },
@ -169,6 +175,9 @@
{ {
"pattern":"\\Qcom/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_TH\\E" "pattern":"\\Qcom/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_TH\\E"
}, },
{
"pattern":"\\Qcom/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_TR\\E"
},
{ {
"pattern":"\\Qcom/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_UA\\E" "pattern":"\\Qcom/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_UA\\E"
}, },
@ -178,6 +187,9 @@
{ {
"pattern":"\\Qcom/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_US\\E" "pattern":"\\Qcom/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_US\\E"
}, },
{
"pattern":"\\Qcom/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_VE\\E"
},
{ {
"pattern":"\\Qcom/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_XK\\E" "pattern":"\\Qcom/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_XK\\E"
}, },
@ -210,6 +222,7 @@
"name":"net.sourceforge.argparse4j.internal.ArgumentParserImpl", "name":"net.sourceforge.argparse4j.internal.ArgumentParserImpl",
"locales":[ "locales":[
"", "",
"en",
"und" "und"
] ]
}] }]

View file

@ -765,9 +765,7 @@ class ManagerImpl implements Manager {
} }
receiveThread = new Thread(() -> { receiveThread = new Thread(() -> {
logger.debug("Starting receiving messages"); logger.debug("Starting receiving messages");
while (!Thread.interrupted()) { context.getReceiveHelper().receiveMessagesContinuously((envelope, e) -> {
try {
context.getReceiveHelper().receiveMessages(Duration.ofMinutes(1), false, (envelope, e) -> {
synchronized (messageHandlers) { synchronized (messageHandlers) {
Stream.concat(messageHandlers.stream(), weakHandlers.stream()).forEach(h -> { Stream.concat(messageHandlers.stream(), weakHandlers.stream()).forEach(h -> {
try { try {
@ -778,11 +776,6 @@ class ManagerImpl implements Manager {
}); });
} }
}); });
break;
} catch (IOException e) {
logger.warn("Receiving messages failed, retrying", e);
}
}
logger.debug("Finished receiving messages"); logger.debug("Finished receiving messages");
synchronized (messageHandlers) { synchronized (messageHandlers) {
receiveThread = null; receiveThread = null;
@ -816,7 +809,10 @@ class ManagerImpl implements Manager {
} }
private void stopReceiveThread(final Thread thread) { private void stopReceiveThread(final Thread thread) {
if (context.getReceiveHelper().requestStopReceiveMessages()) {
logger.debug("Receive stop requested, interrupting read from server.");
thread.interrupt(); thread.interrupt();
}
try { try {
thread.join(); thread.join();
} catch (InterruptedException ignored) { } catch (InterruptedException ignored) {
@ -1030,14 +1026,15 @@ class ManagerImpl implements Manager {
dependencies.getSignalWebSocket().disconnect(); dependencies.getSignalWebSocket().disconnect();
disposable.dispose(); disposable.dispose();
if (account != null) {
account.close();
}
synchronized (closedListeners) { synchronized (closedListeners) {
closedListeners.forEach(Runnable::run); closedListeners.forEach(Runnable::run);
closedListeners.clear(); closedListeners.clear();
} }
if (account != null) {
account.close();
}
account = null; account = null;
} }
} }

View file

@ -347,9 +347,6 @@ public final class ProfileHelper {
.storeProfileAvatar(address, .storeProfileAvatar(address,
outputStream -> retrieveProfileAvatar(avatarPath, profileKey, outputStream)); outputStream -> retrieveProfileAvatar(avatarPath, profileKey, outputStream));
} catch (Throwable e) { } catch (Throwable e) {
if (e instanceof AssertionError && e.getCause() instanceof InterruptedException) {
Thread.currentThread().interrupt();
}
logger.warn("Failed to download profile avatar, ignoring: {}", e.getMessage()); logger.warn("Failed to download profile avatar, ignoring: {}", e.getMessage());
} }
} }

View file

@ -2,8 +2,8 @@ package org.asamk.signal.manager.helper;
import org.asamk.signal.manager.Manager; import org.asamk.signal.manager.Manager;
import org.asamk.signal.manager.SignalDependencies; import org.asamk.signal.manager.SignalDependencies;
import org.asamk.signal.manager.api.UntrustedIdentityException;
import org.asamk.signal.manager.actions.HandleAction; import org.asamk.signal.manager.actions.HandleAction;
import org.asamk.signal.manager.api.UntrustedIdentityException;
import org.asamk.signal.manager.storage.SignalAccount; import org.asamk.signal.manager.storage.SignalAccount;
import org.asamk.signal.manager.storage.messageCache.CachedMessage; import org.asamk.signal.manager.storage.messageCache.CachedMessage;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -37,6 +37,8 @@ public class ReceiveHelper {
private boolean ignoreAttachments = false; private boolean ignoreAttachments = false;
private boolean needsToRetryFailedMessages = false; private boolean needsToRetryFailedMessages = false;
private boolean hasCaughtUpWithOldMessages = false; private boolean hasCaughtUpWithOldMessages = false;
private boolean isWaitingForMessage = false;
private boolean shouldStop = false;
private Callable authenticationFailureListener; private Callable authenticationFailureListener;
private Callable caughtUpWithOldMessagesListener; private Callable caughtUpWithOldMessagesListener;
@ -66,6 +68,22 @@ public class ReceiveHelper {
this.caughtUpWithOldMessagesListener = caughtUpWithOldMessagesListener; this.caughtUpWithOldMessagesListener = caughtUpWithOldMessagesListener;
} }
public boolean requestStopReceiveMessages() {
this.shouldStop = true;
return isWaitingForMessage;
}
public void receiveMessagesContinuously(Manager.ReceiveMessageHandler handler) {
while (!shouldStop) {
try {
receiveMessages(Duration.ofMinutes(1), false, handler);
break;
} catch (IOException e) {
logger.warn("Receiving messages failed, retrying", e);
}
}
}
public void receiveMessages( public void receiveMessages(
Duration timeout, boolean returnOnTimeout, Manager.ReceiveMessageHandler handler Duration timeout, boolean returnOnTimeout, Manager.ReceiveMessageHandler handler
) throws IOException { ) throws IOException {
@ -92,6 +110,7 @@ public class ReceiveHelper {
queuedActions.clear(); queuedActions.clear();
dependencies.getSignalWebSocket().disconnect(); dependencies.getSignalWebSocket().disconnect();
webSocketStateDisposable.dispose(); webSocketStateDisposable.dispose();
shouldStop = false;
} }
} }
@ -104,8 +123,9 @@ public class ReceiveHelper {
final var signalWebSocket = dependencies.getSignalWebSocket(); final var signalWebSocket = dependencies.getSignalWebSocket();
var backOffCounter = 0; var backOffCounter = 0;
isWaitingForMessage = false;
while (!Thread.interrupted()) { while (!shouldStop) {
if (needsToRetryFailedMessages) { if (needsToRetryFailedMessages) {
retryFailedReceivedMessages(handler); retryFailedReceivedMessages(handler);
needsToRetryFailedMessages = false; needsToRetryFailedMessages = false;
@ -118,13 +138,16 @@ public class ReceiveHelper {
} }
logger.debug("Checking for new message from server"); logger.debug("Checking for new message from server");
try { try {
isWaitingForMessage = true;
var result = signalWebSocket.readOrEmpty(timeout.toMillis(), envelope1 -> { var result = signalWebSocket.readOrEmpty(timeout.toMillis(), envelope1 -> {
isWaitingForMessage = false;
final var recipientId = envelope1.hasSourceUuid() ? account.getRecipientStore() final var recipientId = envelope1.hasSourceUuid() ? account.getRecipientStore()
.resolveRecipient(envelope1.getSourceAddress()) : null; .resolveRecipient(envelope1.getSourceAddress()) : null;
logger.trace("Storing new message from {}", recipientId); logger.trace("Storing new message from {}", recipientId);
// 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, recipientId); cachedMessage[0] = account.getMessageCache().cacheMessage(envelope1, recipientId);
}); });
isWaitingForMessage = false;
backOffCounter = 0; backOffCounter = 0;
if (result.isPresent()) { if (result.isPresent()) {
@ -143,7 +166,6 @@ public class ReceiveHelper {
} }
} catch (AssertionError e) { } catch (AssertionError e) {
if (e.getCause() instanceof InterruptedException) { if (e.getCause() instanceof InterruptedException) {
Thread.currentThread().interrupt();
break; break;
} else { } else {
throw e; throw e;
@ -255,23 +277,14 @@ public class ReceiveHelper {
private void handleQueuedActions(final Collection<HandleAction> queuedActions) { private void handleQueuedActions(final Collection<HandleAction> queuedActions) {
logger.debug("Handling message actions"); logger.debug("Handling message actions");
var interrupted = false;
for (var action : queuedActions) { for (var action : queuedActions) {
logger.debug("Executing action {}", action.getClass().getSimpleName()); logger.debug("Executing action {}", action.getClass().getSimpleName());
try { try {
action.execute(context); action.execute(context);
} catch (Throwable e) { } catch (Throwable e) {
if ((e instanceof AssertionError || e instanceof RuntimeException)
&& e.getCause() instanceof InterruptedException) {
interrupted = true;
continue;
}
logger.warn("Message action failed.", e); logger.warn("Message action failed.", e);
} }
} }
if (interrupted) {
Thread.currentThread().interrupt();
}
} }
private void onWebSocketStateChange(final WebSocketConnectionState s) { private void onWebSocketStateChange(final WebSocketConnectionState s) {

View file

@ -49,7 +49,7 @@ public class MessageSendLogStore implements AutoCloseable {
this.cleanupThread = new Thread(() -> { this.cleanupThread = new Thread(() -> {
try { try {
final var interval = Duration.ofHours(1).toMillis(); final var interval = Duration.ofHours(1).toMillis();
while (true) { while (!Thread.interrupted()) {
try (final var connection = database.getConnection()) { try (final var connection = database.getConnection()) {
deleteOutdatedEntries(connection); deleteOutdatedEntries(connection);
} catch (SQLException e) { } catch (SQLException e) {