mirror of
https://github.com/AsamK/signal-cli
synced 2025-08-29 18:40:39 +00:00
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:
parent
bb3b9692e3
commit
cf0cc50e32
5 changed files with 55 additions and 35 deletions
|
@ -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"
|
||||||
]
|
]
|
||||||
}]
|
}]
|
||||||
|
|
|
@ -765,24 +765,17 @@ 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 {
|
synchronized (messageHandlers) {
|
||||||
context.getReceiveHelper().receiveMessages(Duration.ofMinutes(1), false, (envelope, e) -> {
|
Stream.concat(messageHandlers.stream(), weakHandlers.stream()).forEach(h -> {
|
||||||
synchronized (messageHandlers) {
|
try {
|
||||||
Stream.concat(messageHandlers.stream(), weakHandlers.stream()).forEach(h -> {
|
h.handleMessage(envelope, e);
|
||||||
try {
|
} catch (Exception ex) {
|
||||||
h.handleMessage(envelope, e);
|
logger.warn("Message handler failed, ignoring", ex);
|
||||||
} catch (Exception ex) {
|
|
||||||
logger.warn("Message handler failed, ignoring", ex);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
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) {
|
||||||
thread.interrupt();
|
if (context.getReceiveHelper().requestStopReceiveMessages()) {
|
||||||
|
logger.debug("Receive stop requested, interrupting read from server.");
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue