import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException;
+import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
import org.whispersystems.signalservice.api.util.DeviceNameUtil;
import org.whispersystems.signalservice.api.util.InvalidNumberException;
import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.SignatureException;
+import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
private final Set<ReceiveMessageHandler> messageHandlers = new HashSet<>();
private final List<Runnable> closedListeners = new ArrayList<>();
private boolean isReceivingSynchronous;
+ private boolean needsToRetryFailedMessages = false;
ManagerImpl(
SignalAccount account,
avatarStore,
unidentifiedAccessHelper::getAccessFor,
this::resolveSignalServiceAddress);
- final GroupV2Helper groupV2Helper = new GroupV2Helper(profileHelper::getRecipientProfileKeyCredential,
- this::getRecipientProfile,
+ final GroupV2Helper groupV2Helper = new GroupV2Helper(profileHelper,
account::getSelfRecipientId,
dependencies.getGroupsV2Operations(),
dependencies.getGroupsV2Api(),
account.getRecipientStore(),
this::handleIdentityFailure,
this::getGroupInfo,
+ profileHelper,
this::refreshRegisteredUser);
this.groupHelper = new GroupHelper(account,
dependencies,
contactHelper,
attachmentHelper,
syncHelper,
- this::getRecipientProfile,
+ profileHelper::getRecipientProfile,
jobExecutor);
this.identityHelper = new IdentityHelper(account,
dependencies,
try {
preKeyHelper.refreshPreKeysIfNecessary();
if (account.getAci() == null) {
- account.setAci(dependencies.getAccountManager().getOwnAci());
+ account.setAci(ACI.parseOrNull(dependencies.getAccountManager().getWhoAmI().getAci()));
}
updateAccountAttributes(null);
} catch (AuthorizationFailedException e) {
d.getCreated(),
d.getLastSeen(),
d.getId() == account.getDeviceId());
- }).collect(Collectors.toList());
+ }).toList();
}
@Override
@Override
public List<Group> getGroups() {
- return account.getGroupStore().getGroups().stream().map(this::toGroup).collect(Collectors.toList());
+ return account.getGroupStore().getGroups().stream().map(this::toGroup).toList();
}
private Group toGroup(final GroupInfo groupInfo) {
.map(sendMessageResult -> SendMessageResult.from(sendMessageResult,
account.getRecipientStore(),
account.getRecipientStore()::resolveRecipientAddress))
- .collect(Collectors.toList()));
+ .toList());
}
}
return new SendMessageResults(timestamp, results);
.map(r -> SendMessageResult.from(r,
account.getRecipientStore(),
account.getRecipientStore()::resolveRecipientAddress))
- .collect(Collectors.toList()));
+ .toList());
}
}
return new SendMessageResults(timestamp, results);
try {
aciMap = getRegisteredUsers(Set.of(number));
} catch (NumberFormatException e) {
- throw new IOException(number, e);
+ throw new UnregisteredUserException(number, e);
}
final var uuid = aciMap.get(number);
if (uuid == null) {
- throw new IOException(number, null);
+ throw new UnregisteredUserException(number, null);
}
return uuid;
}
logger.debug("Starting receiving messages");
while (!Thread.interrupted()) {
try {
- receiveMessagesInternal(1L, TimeUnit.HOURS, false, (envelope, e) -> {
+ receiveMessagesInternal(Duration.ofMinutes(1), false, (envelope, e) -> {
synchronized (messageHandlers) {
Stream.concat(messageHandlers.stream(), weakHandlers.stream()).forEach(h -> {
try {
}
@Override
- public void receiveMessages(long timeout, TimeUnit unit, ReceiveMessageHandler handler) throws IOException {
- receiveMessages(timeout, unit, true, handler);
+ public void receiveMessages(Duration timeout, ReceiveMessageHandler handler) throws IOException {
+ receiveMessages(timeout, true, handler);
}
@Override
public void receiveMessages(ReceiveMessageHandler handler) throws IOException {
- receiveMessages(1L, TimeUnit.HOURS, false, handler);
+ receiveMessages(Duration.ofMinutes(1), false, handler);
}
private void receiveMessages(
- long timeout, TimeUnit unit, boolean returnOnTimeout, ReceiveMessageHandler handler
+ Duration timeout, 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);
+ receiveMessagesInternal(timeout, returnOnTimeout, handler);
} finally {
receiveThread = null;
hasCaughtUpWithOldMessages = false;
}
private void receiveMessagesInternal(
- long timeout, TimeUnit unit, boolean returnOnTimeout, ReceiveMessageHandler handler
+ Duration timeout, boolean returnOnTimeout, ReceiveMessageHandler handler
) throws IOException {
- retryFailedReceivedMessages(handler);
+ needsToRetryFailedMessages = true;
// Use a Map here because java Set doesn't have a get method ...
Map<HandleAction, HandleAction> queuedActions = new HashMap<>();
final var MAX_BACKOFF_COUNTER = 9;
while (!Thread.interrupted()) {
+ if (needsToRetryFailedMessages) {
+ retryFailedReceivedMessages(handler);
+ needsToRetryFailedMessages = false;
+ }
SignalServiceEnvelope envelope;
final CachedMessage[] cachedMessage = {null};
final var nowMillis = System.currentTimeMillis();
}
logger.debug("Checking for new message from server");
try {
- var result = signalWebSocket.readOrEmpty(unit.toMillis(timeout), envelope1 -> {
+ var result = signalWebSocket.readOrEmpty(timeout.toMillis(), envelope1 -> {
final var recipientId = envelope1.hasSourceUuid()
? resolveRecipient(envelope1.getSourceAddress())
: null;
logger.debug("Handling message actions");
var interrupted = false;
for (var action : queuedActions) {
+ logger.debug("Executing action {}", action.getClass().getSimpleName());
try {
action.execute(context);
} catch (Throwable e) {
.getContacts()
.stream()
.map(p -> new Pair<>(account.getRecipientStore().resolveRecipientAddress(p.first()), p.second()))
- .collect(Collectors.toList());
+ .toList();
}
@Override
@Override
public List<Identity> getIdentities() {
- return account.getIdentityKeyStore()
- .getIdentities()
- .stream()
- .map(this::toIdentity)
- .collect(Collectors.toList());
+ return account.getIdentityKeyStore().getIdentities().stream().map(this::toIdentity).toList();
}
private Identity toIdentity(final IdentityInfo identityInfo) {
} catch (IOException e) {
return false;
}
- return identityHelper.trustIdentityVerified(recipientId, fingerprint);
+ final var updated = identityHelper.trustIdentityVerified(recipientId, fingerprint);
+ if (updated && this.isReceiving()) {
+ needsToRetryFailedMessages = true;
+ }
+ return updated;
}
/**
} catch (IOException e) {
return false;
}
- return identityHelper.trustIdentityVerifiedSafetyNumber(recipientId, safetyNumber);
+ final var updated = identityHelper.trustIdentityVerifiedSafetyNumber(recipientId, safetyNumber);
+ if (updated && this.isReceiving()) {
+ needsToRetryFailedMessages = true;
+ }
+ return updated;
}
/**
} catch (IOException e) {
return false;
}
- return identityHelper.trustIdentityVerifiedSafetyNumber(recipientId, safetyNumber);
+ final var updated = identityHelper.trustIdentityVerifiedSafetyNumber(recipientId, safetyNumber);
+ if (updated && this.isReceiving()) {
+ needsToRetryFailedMessages = true;
+ }
+ return updated;
}
/**
} catch (IOException e) {
return false;
}
- return identityHelper.trustIdentityAllKeys(recipientId);
+ final var updated = identityHelper.trustIdentityAllKeys(recipientId);
+ if (updated && this.isReceiving()) {
+ needsToRetryFailedMessages = true;
+ }
+ return updated;
}
@Override
private SignalServiceAddress resolveSignalServiceAddress(RecipientId recipientId) {
final var address = account.getRecipientStore().resolveRecipientAddress(recipientId);
- if (address.getUuid().isPresent()) {
+ if (address.uuid().isPresent()) {
return address.toSignalServiceAddress();
}
// Address in recipient store doesn't have a uuid, this shouldn't happen
// Try to retrieve the uuid from the server
- final var number = address.getNumber().get();
+ final var number = address.number().get();
final ACI aci;
try {
aci = getRegisteredUser(number);