private boolean hasCaughtUpWithOldMessages = false;
private boolean ignoreAttachments = false;
+ private Thread receiveThread;
+ private final Set<ReceiveMessageHandler> messageHandlers = new HashSet<>();
+ private boolean isReceivingSynchronous;
+
ManagerImpl(
SignalAccount account,
PathConfig pathConfig,
return actions;
}
+ @Override
+ public void addReceiveHandler(final ReceiveMessageHandler handler) {
+ if (isReceivingSynchronous) {
+ throw new IllegalStateException("Already receiving message synchronously.");
+ }
+ synchronized (messageHandlers) {
+ messageHandlers.add(handler);
+
+ startReceiveThreadIfRequired();
+ }
+ }
+
+ private void startReceiveThreadIfRequired() {
+ if (receiveThread != null) {
+ return;
+ }
+ receiveThread = new Thread(() -> {
+ while (!Thread.interrupted()) {
+ try {
+ receiveMessagesInternal(1L, TimeUnit.HOURS, false, (envelope, decryptedContent, e) -> {
+ synchronized (messageHandlers) {
+ for (ReceiveMessageHandler h : messageHandlers) {
+ try {
+ h.handleMessage(envelope, decryptedContent, e);
+ } catch (Exception ex) {
+ logger.warn("Message handler failed, ignoring", ex);
+ }
+ }
+ }
+ });
+ break;
+ } catch (IOException e) {
+ logger.warn("Receiving messages failed, retrying", e);
+ }
+ }
+ hasCaughtUpWithOldMessages = false;
+ synchronized (messageHandlers) {
+ receiveThread = null;
+
+ // Check if in the meantime another handler has been registered
+ if (!messageHandlers.isEmpty()) {
+ startReceiveThreadIfRequired();
+ }
+ }
+ });
+
+ receiveThread.start();
+ }
+
+ @Override
+ public void removeReceiveHandler(final ReceiveMessageHandler handler) {
+ final Thread thread;
+ synchronized (messageHandlers) {
+ thread = receiveThread;
+ receiveThread = null;
+ messageHandlers.remove(handler);
+ if (!messageHandlers.isEmpty() || isReceivingSynchronous) {
+ return;
+ }
+ }
+
+ stopReceiveThread(thread);
+ }
+
+ private void stopReceiveThread(final Thread thread) {
+ thread.interrupt();
+ try {
+ thread.join();
+ } catch (InterruptedException ignored) {
+ }
+ }
+
+ @Override
+ public boolean isReceiving() {
+ if (isReceivingSynchronous) {
+ return true;
+ }
+ synchronized (messageHandlers) {
+ return messageHandlers.size() > 0;
+ }
+ }
+
@Override
public void receiveMessages(long timeout, TimeUnit unit, ReceiveMessageHandler handler) throws IOException {
receiveMessages(timeout, unit, true, handler);
private void receiveMessages(
long timeout, TimeUnit unit, boolean returnOnTimeout, ReceiveMessageHandler handler
+ ) throws IOException {
+ if (isReceiving()) {
+ throw new IllegalStateException("Already receiving message.");
+ }
+ isReceivingSynchronous = true;
+ receiveThread = Thread.currentThread();
+ try {
+ receiveMessagesInternal(timeout, unit, returnOnTimeout, handler);
+ } finally {
+ receiveThread = null;
+ hasCaughtUpWithOldMessages = false;
+ isReceivingSynchronous = false;
+ }
+ }
+
+ private void receiveMessagesInternal(
+ long timeout, TimeUnit unit, boolean returnOnTimeout, ReceiveMessageHandler handler
) throws IOException {
retryFailedReceivedMessages(handler);
}
private void close(boolean closeAccount) throws IOException {
+ Thread thread;
+ synchronized (messageHandlers) {
+ messageHandlers.clear();
+ thread = receiveThread;
+ receiveThread = null;
+ }
+ if (thread != null) {
+ stopReceiveThread(thread);
+ }
executor.shutdown();
dependencies.getSignalWebSocket().disconnect();
try {
t.join();
+ synchronized (this) {
+ wait();
+ }
} catch (InterruptedException ignored) {
}
} catch (DBusException | IOException e) {
logger.info("Exported dbus object: " + objectPath);
- final var thread = new Thread(() -> {
- while (!Thread.interrupted()) {
- try {
- final var receiveMessageHandler = outputWriter instanceof JsonWriter
- ? new JsonDbusReceiveMessageHandler(m, (JsonWriter) outputWriter, conn, objectPath)
- : new DbusReceiveMessageHandler(m, (PlainTextWriter) outputWriter, conn, objectPath);
- m.receiveMessages(receiveMessageHandler);
- break;
- } catch (IOException e) {
- logger.warn("Receiving messages failed, retrying", e);
- }
- }
- try {
- initThread.join();
- } catch (InterruptedException ignored) {
- }
- signal.close();
- });
-
- thread.start();
-
- return thread;
+ final var receiveMessageHandler = outputWriter instanceof JsonWriter ? new JsonDbusReceiveMessageHandler(m,
+ (JsonWriter) outputWriter,
+ conn,
+ objectPath) : new DbusReceiveMessageHandler(m, (PlainTextWriter) outputWriter, conn, objectPath);
+ m.addReceiveHandler(receiveMessageHandler);
+ return initThread;
}
}
final var objectMapper = Util.createJsonObjectMapper();
final var jsonRpcSender = new JsonRpcSender((JsonWriter) outputWriter);
- final var receiveThread = receiveMessages(s -> jsonRpcSender.sendRequest(JsonRpcRequest.forNotification(
- "receive",
- objectMapper.valueToTree(s),
- null)), m);
+ final var receiveMessageHandler = new JsonReceiveMessageHandler(m,
+ s -> jsonRpcSender.sendRequest(JsonRpcRequest.forNotification("receive",
+ objectMapper.valueToTree(s),
+ null)));
+ m.addReceiveHandler(receiveMessageHandler);
// Maybe this should be handled inside the Manager
while (!m.hasCaughtUpWithOldMessages()) {
jsonRpcReader.readRequests((method, params) -> handleRequest(m, objectMapper, method, params),
response -> logger.debug("Received unexpected response for id {}", response.getId()));
- receiveThread.interrupt();
- try {
- receiveThread.join();
- } catch (InterruptedException ignored) {
- }
+ m.removeReceiveHandler(receiveMessageHandler);
}
private JsonNode handleRequest(
}
command.handleCommand(requestParams, m, outputWriter);
}
-
- private Thread receiveMessages(JsonWriter jsonWriter, Manager m) {
- final var thread = new Thread(() -> {
- while (!Thread.interrupted()) {
- try {
- final var receiveMessageHandler = new JsonReceiveMessageHandler(m, jsonWriter);
- m.receiveMessages(receiveMessageHandler);
- break;
- } catch (IOException e) {
- logger.warn("Receiving messages failed, retrying", e);
- }
- }
- });
-
- thread.start();
-
- return thread;
- }
}