From 7cd24a74af29468f67ebfdaed450bda06753b851 Mon Sep 17 00:00:00 2001 From: AsamK Date: Sun, 15 Oct 2023 19:02:59 +0200 Subject: [PATCH] Improve handling of CDSI resource exhaustion --- .../main/java/org/asamk/signal/manager/Manager.java | 2 +- .../asamk/signal/manager/internal/ManagerImpl.java | 13 +++++++++++-- .../asamk/signal/commands/GetUserStatusCommand.java | 6 ++++++ .../java/org/asamk/signal/dbus/DbusSignalImpl.java | 8 +++++++- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/lib/src/main/java/org/asamk/signal/manager/Manager.java b/lib/src/main/java/org/asamk/signal/manager/Manager.java index 7cba24f8..defe7155 100644 --- a/lib/src/main/java/org/asamk/signal/manager/Manager.java +++ b/lib/src/main/java/org/asamk/signal/manager/Manager.java @@ -86,7 +86,7 @@ public interface Manager extends Closeable { * @return A map of numbers to canonicalized number and uuid. If a number is not registered the uuid is null. * @throws IOException if it's unable to get the contacts to check if they're registered */ - Map getUserStatus(Set numbers) throws IOException; + Map getUserStatus(Set numbers) throws IOException, RateLimitException; void updateAccountAttributes(String deviceName) throws IOException; 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 a91a6099..189e4fe9 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 @@ -64,6 +64,7 @@ import org.asamk.signal.manager.api.UserStatus; import org.asamk.signal.manager.config.ServiceEnvironmentConfig; import org.asamk.signal.manager.helper.AccountFileUpdater; import org.asamk.signal.manager.helper.Context; +import org.asamk.signal.manager.helper.RecipientHelper.RegisteredUser; import org.asamk.signal.manager.storage.AttachmentStore; import org.asamk.signal.manager.storage.AvatarStore; import org.asamk.signal.manager.storage.SignalAccount; @@ -89,6 +90,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceTypingMessage; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.ServiceIdType; +import org.whispersystems.signalservice.api.push.exceptions.CdsiResourceExhaustedException; import org.whispersystems.signalservice.api.util.DeviceNameUtil; import org.whispersystems.signalservice.api.util.InvalidNumberException; import org.whispersystems.signalservice.api.util.PhoneNumberFormatter; @@ -216,7 +218,7 @@ public class ManagerImpl implements Manager { } @Override - public Map getUserStatus(Set numbers) throws IOException { + public Map getUserStatus(Set numbers) throws IOException, RateLimitException { final var canonicalizedNumbers = numbers.stream().collect(Collectors.toMap(n -> n, n -> { try { final var canonicalizedNumber = PhoneNumberFormatter.formatNumber(n, account.getNumber()); @@ -234,7 +236,14 @@ public class ManagerImpl implements Manager { .stream() .filter(s -> !s.isEmpty()) .collect(Collectors.toSet()); - final var registeredUsers = context.getRecipientHelper().getRegisteredUsers(canonicalizedNumbersSet); + + final Map registeredUsers; + try { + registeredUsers = context.getRecipientHelper().getRegisteredUsers(canonicalizedNumbersSet); + } catch (CdsiResourceExhaustedException e) { + logger.debug("CDSI resource exhausted: {}", e.getMessage()); + throw new RateLimitException(System.currentTimeMillis() + e.getRetryAfterSeconds() * 1000L); + } return numbers.stream().collect(Collectors.toMap(n -> n, n -> { final var number = canonicalizedNumbers.get(n); diff --git a/src/main/java/org/asamk/signal/commands/GetUserStatusCommand.java b/src/main/java/org/asamk/signal/commands/GetUserStatusCommand.java index 8c89dd4f..30fe7bf2 100644 --- a/src/main/java/org/asamk/signal/commands/GetUserStatusCommand.java +++ b/src/main/java/org/asamk/signal/commands/GetUserStatusCommand.java @@ -5,11 +5,14 @@ import net.sourceforge.argparse4j.inf.Subparser; import org.asamk.signal.commands.exceptions.CommandException; import org.asamk.signal.commands.exceptions.IOErrorException; +import org.asamk.signal.commands.exceptions.RateLimitErrorException; import org.asamk.signal.manager.Manager; +import org.asamk.signal.manager.api.RateLimitException; import org.asamk.signal.manager.api.UserStatus; import org.asamk.signal.output.JsonWriter; import org.asamk.signal.output.OutputWriter; import org.asamk.signal.output.PlainTextWriter; +import org.asamk.signal.util.CommandUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,6 +43,9 @@ public class GetUserStatusCommand implements JsonRpcLocalCommand { Map registered; try { registered = m.getUserStatus(new HashSet<>(ns.getList("recipient"))); + } catch (RateLimitException e) { + final var message = CommandUtil.getRateLimitMessage(e); + throw new RateLimitErrorException(message, e); } catch (IOException e) { throw new IOErrorException("Unable to check if users are registered: " + e.getMessage() diff --git a/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java b/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java index 608ed581..2223c96a 100644 --- a/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java +++ b/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java @@ -21,6 +21,7 @@ import org.asamk.signal.manager.api.Message; import org.asamk.signal.manager.api.NotAGroupMemberException; import org.asamk.signal.manager.api.NotPrimaryDeviceException; import org.asamk.signal.manager.api.PendingAdminApprovalException; +import org.asamk.signal.manager.api.RateLimitException; import org.asamk.signal.manager.api.RecipientAddress; import org.asamk.signal.manager.api.RecipientIdentifier; import org.asamk.signal.manager.api.SendMessageResult; @@ -31,6 +32,7 @@ import org.asamk.signal.manager.api.UnregisteredRecipientException; import org.asamk.signal.manager.api.UpdateGroup; import org.asamk.signal.manager.api.UpdateProfile; import org.asamk.signal.manager.api.UserStatus; +import org.asamk.signal.util.DateUtils; import org.asamk.signal.util.SendMessageResultUtils; import org.freedesktop.dbus.DBusPath; import org.freedesktop.dbus.connections.impl.DBusConnection; @@ -681,6 +683,10 @@ public class DbusSignalImpl implements Signal { registered = m.getUserStatus(new HashSet<>(numbers)); } catch (IOException e) { throw new Error.Failure(e.getMessage()); + } catch (RateLimitException e) { + throw new Error.Failure(e.getMessage() + + ", retry at " + + DateUtils.formatTimestamp(e.getNextAttemptTimestamp())); } return numbers.stream().map(number -> registered.get(number).uuid() != null).toList(); @@ -893,7 +899,7 @@ public class DbusSignalImpl implements Signal { } var errors = SendMessageResultUtils.getErrorMessagesFromSendMessageResults(results); - if (errors.size() == 0 || errors.size() < results.size()) { + if (errors.isEmpty() || errors.size() < results.size()) { return; } -- 2.50.1