From bf87fcc652bc37a9843b4dc79f985005452a1c41 Mon Sep 17 00:00:00 2001 From: AsamK Date: Tue, 3 Jun 2025 22:22:51 +0200 Subject: [PATCH] Ensure messages are created with a unique timestamp Fixes #1783 --- .../signal/manager/internal/ManagerImpl.java | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/lib/src/main/java/org/asamk/signal/manager/internal/ManagerImpl.java b/lib/src/main/java/org/asamk/signal/manager/internal/ManagerImpl.java index c5a7552f..0a67e0a0 100644 --- a/lib/src/main/java/org/asamk/signal/manager/internal/ManagerImpl.java +++ b/lib/src/main/java/org/asamk/signal/manager/internal/ManagerImpl.java @@ -131,6 +131,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -160,6 +161,7 @@ public class ManagerImpl implements Manager { private final List closedListeners = new ArrayList<>(); private final List addressChangedListeners = new ArrayList<>(); private final CompositeDisposable disposable = new CompositeDisposable(); + private final AtomicLong lastMessageTimestamp = new AtomicLong(); public ManagerImpl( SignalAccount account, @@ -598,6 +600,24 @@ public class ManagerImpl implements Manager { return context.getGroupHelper().joinGroup(inviteLinkUrl); } + private long getNextMessageTimestamp() { + while (true) { + final var last = lastMessageTimestamp.get(); + final var timestamp = System.currentTimeMillis(); + if (last == timestamp) { + try { + Thread.sleep(1); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + continue; + } + if (lastMessageTimestamp.compareAndSet(last, timestamp)) { + return timestamp; + } + } + } + private SendMessageResults sendMessage( SignalServiceDataMessage.Builder messageBuilder, Set recipients, @@ -613,7 +633,7 @@ public class ManagerImpl implements Manager { Optional editTargetTimestamp ) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException { var results = new HashMap>(); - long timestamp = System.currentTimeMillis(); + long timestamp = getNextMessageTimestamp(); messageBuilder.withTimestamp(timestamp); for (final var recipient : recipients) { if (recipient instanceof RecipientIdentifier.NoteToSelf || ( @@ -653,7 +673,7 @@ public class ManagerImpl implements Manager { Set recipients ) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException { var results = new HashMap>(); - final var timestamp = System.currentTimeMillis(); + final var timestamp = getNextMessageTimestamp(); for (var recipient : recipients) { if (recipient instanceof RecipientIdentifier.Single single) { final var message = new SignalServiceTypingMessage(action, timestamp, Optional.empty()); @@ -685,7 +705,7 @@ public class ManagerImpl implements Manager { @Override public SendMessageResults sendReadReceipt(RecipientIdentifier.Single sender, List messageIds) { - final var timestamp = System.currentTimeMillis(); + final var timestamp = getNextMessageTimestamp(); var receiptMessage = new SignalServiceReceiptMessage(SignalServiceReceiptMessage.Type.READ, messageIds, timestamp); @@ -695,7 +715,7 @@ public class ManagerImpl implements Manager { @Override public SendMessageResults sendViewedReceipt(RecipientIdentifier.Single sender, List messageIds) { - final var timestamp = System.currentTimeMillis(); + final var timestamp = getNextMessageTimestamp(); var receiptMessage = new SignalServiceReceiptMessage(SignalServiceReceiptMessage.Type.VIEWED, messageIds, timestamp); -- 2.50.1