import org.asamk.signal.manager.api.Pair;
import org.asamk.signal.manager.api.PendingAdminApprovalException;
import org.asamk.signal.manager.api.PhoneNumberSharingMode;
+import org.asamk.signal.manager.api.PinLockMissingException;
import org.asamk.signal.manager.api.PinLockedException;
import org.asamk.signal.manager.api.Profile;
import org.asamk.signal.manager.api.RateLimitException;
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;
private final List<Runnable> closedListeners = new ArrayList<>();
private final List<Runnable> addressChangedListeners = new ArrayList<>();
private final CompositeDisposable disposable = new CompositeDisposable();
+ private final AtomicLong lastMessageTimestamp = new AtomicLong();
public ManagerImpl(
SignalAccount account,
}
@Override
- public Map<String, UsernameStatus> getUsernameStatus(Set<String> usernames) {
+ public Map<String, UsernameStatus> getUsernameStatus(Set<String> usernames) throws IOException {
final var registeredUsers = new HashMap<String, RecipientAddress>();
for (final var username : usernames) {
try {
String newNumber,
String verificationCode,
String pin
- ) throws IncorrectPinException, PinLockedException, IOException, NotPrimaryDeviceException {
+ ) throws IncorrectPinException, PinLockedException, IOException, NotPrimaryDeviceException, PinLockMissingException {
if (!account.isPrimaryDevice()) {
throw new NotPrimaryDeviceException();
}
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<RecipientIdentifier> recipients,
Optional<Long> editTargetTimestamp
) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException {
var results = new HashMap<RecipientIdentifier, List<SendMessageResult>>();
- long timestamp = System.currentTimeMillis();
+ long timestamp = getNextMessageTimestamp();
messageBuilder.withTimestamp(timestamp);
for (final var recipient : recipients) {
if (recipient instanceof RecipientIdentifier.NoteToSelf || (
Set<RecipientIdentifier> recipients
) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException {
var results = new HashMap<RecipientIdentifier, List<SendMessageResult>>();
- 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());
@Override
public SendMessageResults sendReadReceipt(RecipientIdentifier.Single sender, List<Long> messageIds) {
- final var timestamp = System.currentTimeMillis();
+ final var timestamp = getNextMessageTimestamp();
var receiptMessage = new SignalServiceReceiptMessage(SignalServiceReceiptMessage.Type.READ,
messageIds,
timestamp);
@Override
public SendMessageResults sendViewedReceipt(RecipientIdentifier.Single sender, List<Long> messageIds) {
- final var timestamp = System.currentTimeMillis();
+ final var timestamp = getNextMessageTimestamp();
var receiptMessage = new SignalServiceReceiptMessage(SignalServiceReceiptMessage.Type.VIEWED,
messageIds,
timestamp);