]> nmode's Git Repositories - signal-cli/commitdiff
Handle send failures as non fatal and return detailed results in json output
authorAsamK <asamk@gmx.de>
Sat, 11 Dec 2021 11:44:11 +0000 (12:44 +0100)
committerAsamK <asamk@gmx.de>
Sat, 11 Dec 2021 11:44:11 +0000 (12:44 +0100)
Fixes #348

13 files changed:
graalvm-config-dir/reflect-config.json
src/main/java/org/asamk/signal/commands/JoinGroupCommand.java
src/main/java/org/asamk/signal/commands/QuitGroupCommand.java
src/main/java/org/asamk/signal/commands/RemoteDeleteCommand.java
src/main/java/org/asamk/signal/commands/SendCommand.java
src/main/java/org/asamk/signal/commands/SendReactionCommand.java
src/main/java/org/asamk/signal/commands/SendReceiptCommand.java
src/main/java/org/asamk/signal/commands/SendTypingCommand.java
src/main/java/org/asamk/signal/commands/UpdateGroupCommand.java
src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java
src/main/java/org/asamk/signal/json/JsonRecipientAddress.java [new file with mode: 0644]
src/main/java/org/asamk/signal/json/JsonSendMessageResult.java [new file with mode: 0644]
src/main/java/org/asamk/signal/util/SendMessageResultUtils.java [moved from src/main/java/org/asamk/signal/util/ErrorUtils.java with 53% similarity]

index a6d831652cc293f55cbd93c247d39adbacd2eac9..cb75cbd9ea9c317dda85cab46534d0bea89b0947 100644 (file)
   "allDeclaredMethods":true,
   "allDeclaredConstructors":true}
 ,
+{
+  "name":"org.asamk.signal.json.JsonRecipientAddress",
+  "allDeclaredFields":true,
+  "queryAllDeclaredMethods":true,
+  "queryAllDeclaredConstructors":true,
+  "methods":[
+    {"name":"number","parameterTypes":[] }, 
+    {"name":"uuid","parameterTypes":[] }
+  ]}
+,
 {
   "name":"org.asamk.signal.json.JsonRemoteDelete",
   "allDeclaredFields":true,
   "allDeclaredMethods":true,
   "allDeclaredConstructors":true}
 ,
+{
+  "name":"org.asamk.signal.json.JsonSendMessageResult",
+  "allDeclaredFields":true,
+  "queryAllDeclaredMethods":true,
+  "queryAllDeclaredConstructors":true,
+  "methods":[
+    {"name":"groupId","parameterTypes":[] }, 
+    {"name":"recipientAddress","parameterTypes":[] }, 
+    {"name":"retryAfterSeconds","parameterTypes":[] }, 
+    {"name":"token","parameterTypes":[] }, 
+    {"name":"type","parameterTypes":[] }
+  ]}
+,
+{
+  "name":"org.asamk.signal.json.JsonSendMessageResult$Type",
+  "allDeclaredFields":true,
+  "queryAllDeclaredMethods":true}
+,
 {
   "name":"org.asamk.signal.json.JsonSharedContact",
   "allDeclaredFields":true,
index e04fca068bcdfda9ebe69f7df739177f0d5defc7..31fc4caf7ecc1018d7e8d4ed1b587f5783d16e8e 100644 (file)
@@ -13,13 +13,12 @@ import org.asamk.signal.manager.groups.GroupInviteLinkUrl;
 import org.asamk.signal.output.JsonWriter;
 import org.asamk.signal.output.OutputWriter;
 import org.asamk.signal.output.PlainTextWriter;
+import org.asamk.signal.util.SendMessageResultUtils;
 import org.freedesktop.dbus.exceptions.DBusExecutionException;
 
 import java.io.IOException;
 import java.util.Map;
 
-import static org.asamk.signal.util.ErrorUtils.handleSendMessageResults;
-
 public class JoinGroupCommand implements JsonRpcLocalCommand {
 
     @Override
@@ -55,10 +54,23 @@ public class JoinGroupCommand implements JsonRpcLocalCommand {
             final var results = m.joinGroup(linkUrl);
             var newGroupId = results.first();
             if (outputWriter instanceof JsonWriter writer) {
+                var jsonResults = SendMessageResultUtils.getJsonSendMessageResults(results.second().results());
                 if (!m.getGroup(newGroupId).isMember()) {
-                    writer.write(Map.of("groupId", newGroupId.toBase64(), "onlyRequested", true));
+                    writer.write(Map.of("timestamp",
+                            results.second().timestamp(),
+                            "results",
+                            jsonResults,
+                            "groupId",
+                            newGroupId.toBase64(),
+                            "onlyRequested",
+                            true));
                 } else {
-                    writer.write(Map.of("groupId", newGroupId.toBase64()));
+                    writer.write(Map.of("timestamp",
+                            results.second().timestamp(),
+                            "results",
+                            jsonResults,
+                            "groupId",
+                            newGroupId.toBase64()));
                 }
             } else {
                 final var writer = (PlainTextWriter) outputWriter;
@@ -67,8 +79,10 @@ public class JoinGroupCommand implements JsonRpcLocalCommand {
                 } else {
                     writer.println("Joined group \"{}\"", newGroupId.toBase64());
                 }
+                var errors = SendMessageResultUtils.getErrorMessagesFromSendMessageResults(results.second().results());
+                SendMessageResultUtils.printSendMessageResultErrors(writer, errors);
+                writer.println("{}", results.second().timestamp());
             }
-            handleSendMessageResults(results.second().results());
         } catch (IOException e) {
             throw new IOErrorException("Failed to send message: "
                     + e.getMessage()
index 801a2640cb14b5a68bb03e133c42694fee0bc099..6266a603c6de5136e535fac2941f54bfe418934b 100644 (file)
@@ -11,17 +11,14 @@ import org.asamk.signal.manager.Manager;
 import org.asamk.signal.manager.groups.GroupNotFoundException;
 import org.asamk.signal.manager.groups.LastGroupAdminException;
 import org.asamk.signal.manager.groups.NotAGroupMemberException;
-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;
 
 import java.io.IOException;
-import java.util.Map;
 
-import static org.asamk.signal.util.ErrorUtils.handleSendMessageResults;
+import static org.asamk.signal.util.SendMessageResultUtils.outputResult;
 
 public class QuitGroupCommand implements JsonRpcLocalCommand {
 
@@ -55,9 +52,7 @@ public class QuitGroupCommand implements JsonRpcLocalCommand {
         try {
             try {
                 final var results = m.quitGroup(groupId, groupAdmins);
-                final var timestamp = results.timestamp();
-                outputResult(outputWriter, timestamp);
-                handleSendMessageResults(results.results());
+                outputResult(outputWriter, results);
             } catch (NotAGroupMemberException e) {
                 logger.info("User is not a group member");
             }
@@ -77,13 +72,4 @@ public class QuitGroupCommand implements JsonRpcLocalCommand {
             throw new UserErrorException("You need to specify a new admin with --admin: " + e.getMessage());
         }
     }
-
-    private void outputResult(final OutputWriter outputWriter, final long timestamp) {
-        if (outputWriter instanceof PlainTextWriter writer) {
-            writer.println("{}", timestamp);
-        } else {
-            final var writer = (JsonWriter) outputWriter;
-            writer.write(Map.of("timestamp", timestamp));
-        }
-    }
 }
index 54a8d6fb6bf1aae2a57e379ab3be14e7131d9b00..85d2dcd4a5e06d8bda63028429568fbd92eefef1 100644 (file)
@@ -11,14 +11,12 @@ import org.asamk.signal.manager.Manager;
 import org.asamk.signal.manager.groups.GroupNotFoundException;
 import org.asamk.signal.manager.groups.GroupSendingNotAllowedException;
 import org.asamk.signal.manager.groups.NotAGroupMemberException;
-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.asamk.signal.util.ErrorUtils;
 
 import java.io.IOException;
-import java.util.Map;
+
+import static org.asamk.signal.util.SendMessageResultUtils.outputResult;
 
 public class RemoteDeleteCommand implements JsonRpcLocalCommand {
 
@@ -56,8 +54,7 @@ public class RemoteDeleteCommand implements JsonRpcLocalCommand {
 
         try {
             final var results = m.sendRemoteDeleteMessage(targetTimestamp, recipientIdentifiers);
-            outputResult(outputWriter, results.timestamp());
-            ErrorUtils.handleSendMessageResults(results.results());
+            outputResult(outputWriter, results);
         } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) {
             throw new UserErrorException(e.getMessage());
         } catch (IOException e) {
@@ -65,13 +62,4 @@ public class RemoteDeleteCommand implements JsonRpcLocalCommand {
                     .getSimpleName() + ")", e);
         }
     }
-
-    private void outputResult(final OutputWriter outputWriter, final long timestamp) {
-        if (outputWriter instanceof PlainTextWriter writer) {
-            writer.println("{}", timestamp);
-        } else {
-            final var writer = (JsonWriter) outputWriter;
-            writer.write(Map.of("timestamp", timestamp));
-        }
-    }
 }
index 1af21d5324cf294545a8919b5157d7ad9d06e428..08f2d9a33b6f104125d8aab29d0cb94ad3bfcd69 100644 (file)
@@ -14,11 +14,8 @@ import org.asamk.signal.manager.api.RecipientIdentifier;
 import org.asamk.signal.manager.groups.GroupNotFoundException;
 import org.asamk.signal.manager.groups.GroupSendingNotAllowedException;
 import org.asamk.signal.manager.groups.NotAGroupMemberException;
-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.asamk.signal.util.ErrorUtils;
 import org.asamk.signal.util.IOUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -27,11 +24,12 @@ import java.io.IOException;
 import java.nio.charset.Charset;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
 import java.util.Optional;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
+import static org.asamk.signal.util.SendMessageResultUtils.outputResult;
+
 public class SendCommand implements JsonRpcLocalCommand {
 
     private final static Logger logger = LoggerFactory.getLogger(SendCommand.class);
@@ -93,8 +91,7 @@ public class SendCommand implements JsonRpcLocalCommand {
 
             try {
                 final var results = m.sendEndSessionMessage(singleRecipients);
-                outputResult(outputWriter, results.timestamp());
-                ErrorUtils.handleSendMessageResults(results.results());
+                outputResult(outputWriter, results);
                 return;
             } catch (IOException e) {
                 throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
@@ -140,8 +137,7 @@ public class SendCommand implements JsonRpcLocalCommand {
         try {
             var results = m.sendMessage(new Message(messageText, attachments, mentions, Optional.ofNullable(quote)),
                     recipientIdentifiers);
-            outputResult(outputWriter, results.timestamp());
-            ErrorUtils.handleSendMessageResults(results.results());
+            outputResult(outputWriter, results);
         } catch (AttachmentInvalidException | IOException e) {
             throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
                     .getSimpleName() + ")", e);
@@ -168,13 +164,4 @@ public class SendCommand implements JsonRpcLocalCommand {
         }
         return mentions;
     }
-
-    private void outputResult(final OutputWriter outputWriter, final long timestamp) {
-        if (outputWriter instanceof PlainTextWriter writer) {
-            writer.println("{}", timestamp);
-        } else {
-            final var writer = (JsonWriter) outputWriter;
-            writer.write(Map.of("timestamp", timestamp));
-        }
-    }
 }
index d6275726fc00b780659b10543a17228cf3f849fd..e445a9918ec33f9d7ec0c89f504c3b9a8b2f6272 100644 (file)
@@ -11,14 +11,12 @@ import org.asamk.signal.manager.Manager;
 import org.asamk.signal.manager.groups.GroupNotFoundException;
 import org.asamk.signal.manager.groups.GroupSendingNotAllowedException;
 import org.asamk.signal.manager.groups.NotAGroupMemberException;
-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.asamk.signal.util.ErrorUtils;
 
 import java.io.IOException;
-import java.util.Map;
+
+import static org.asamk.signal.util.SendMessageResultUtils.outputResult;
 
 public class SendReactionCommand implements JsonRpcLocalCommand {
 
@@ -72,8 +70,7 @@ public class SendReactionCommand implements JsonRpcLocalCommand {
                     CommandUtil.getSingleRecipientIdentifier(targetAuthor, m.getSelfNumber()),
                     targetTimestamp,
                     recipientIdentifiers);
-            outputResult(outputWriter, results.timestamp());
-            ErrorUtils.handleSendMessageResults(results.results());
+            outputResult(outputWriter, results);
         } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) {
             throw new UserErrorException(e.getMessage());
         } catch (IOException e) {
@@ -81,13 +78,4 @@ public class SendReactionCommand implements JsonRpcLocalCommand {
                     .getSimpleName() + ")", e);
         }
     }
-
-    private void outputResult(final OutputWriter outputWriter, final long timestamp) {
-        if (outputWriter instanceof PlainTextWriter writer) {
-            writer.println("{}", timestamp);
-        } else {
-            final var writer = (JsonWriter) outputWriter;
-            writer.write(Map.of("timestamp", timestamp));
-        }
-    }
 }
index bc2ef37943be68ceeac8dfacc3bb200742025ab1..6ba8a40cf451cb2b0b4034ddc0e205e8ee33e1ea 100644 (file)
@@ -7,14 +7,12 @@ import org.asamk.signal.commands.exceptions.CommandException;
 import org.asamk.signal.commands.exceptions.UserErrorException;
 import org.asamk.signal.manager.Manager;
 import org.asamk.signal.manager.api.SendMessageResults;
-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.asamk.signal.util.ErrorUtils;
 
 import java.io.IOException;
-import java.util.Map;
+
+import static org.asamk.signal.util.SendMessageResultUtils.outputResult;
 
 public class SendReceiptCommand implements JsonRpcLocalCommand {
 
@@ -55,20 +53,10 @@ public class SendReceiptCommand implements JsonRpcLocalCommand {
             } else {
                 throw new UserErrorException("Unknown receipt type: " + type);
             }
-            outputResult(outputWriter, results.timestamp());
-            ErrorUtils.handleSendMessageResults(results.results());
+            outputResult(outputWriter, results);
         } catch (IOException e) {
             throw new UserErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
                     .getSimpleName() + ")");
         }
     }
-
-    private void outputResult(final OutputWriter outputWriter, final long timestamp) {
-        if (outputWriter instanceof PlainTextWriter writer) {
-            writer.println("{}", timestamp);
-        } else {
-            final var writer = (JsonWriter) outputWriter;
-            writer.write(Map.of("timestamp", timestamp));
-        }
-    }
 }
index f55981e3dfce919a4d7d5431e2da9a13b78bc15c..4a2a038ca00b835b583c558eb56f7e96a20c2c72 100644 (file)
@@ -12,15 +12,13 @@ import org.asamk.signal.manager.api.TypingAction;
 import org.asamk.signal.manager.groups.GroupNotFoundException;
 import org.asamk.signal.manager.groups.GroupSendingNotAllowedException;
 import org.asamk.signal.manager.groups.NotAGroupMemberException;
-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.asamk.signal.util.ErrorUtils;
 
 import java.io.IOException;
 import java.util.HashSet;
-import java.util.Map;
+
+import static org.asamk.signal.util.SendMessageResultUtils.outputResult;
 
 public class SendTypingCommand implements JsonRpcLocalCommand {
 
@@ -61,8 +59,7 @@ public class SendTypingCommand implements JsonRpcLocalCommand {
 
         try {
             final var results = m.sendTypingMessage(action, recipientIdentifiers);
-            outputResult(outputWriter, results.timestamp());
-            ErrorUtils.handleSendMessageResults(results.results());
+            outputResult(outputWriter, results);
         } catch (IOException e) {
             throw new UserErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
                     .getSimpleName() + ")");
@@ -70,13 +67,4 @@ public class SendTypingCommand implements JsonRpcLocalCommand {
             throw new UserErrorException("Failed to send to group: " + e.getMessage());
         }
     }
-
-    private void outputResult(final OutputWriter outputWriter, final long timestamp) {
-        if (outputWriter instanceof PlainTextWriter writer) {
-            writer.println("{}", timestamp);
-        } else {
-            final var writer = (JsonWriter) outputWriter;
-            writer.write(Map.of("timestamp", timestamp));
-        }
-    }
 }
index ed3897197541cc558eca17acd3180913d3bcf557..f4f2db0bc3ed53a03269d44184e7d0510db76b5d 100644 (file)
@@ -9,6 +9,7 @@ import org.asamk.signal.commands.exceptions.UnexpectedErrorException;
 import org.asamk.signal.commands.exceptions.UserErrorException;
 import org.asamk.signal.manager.AttachmentInvalidException;
 import org.asamk.signal.manager.Manager;
+import org.asamk.signal.manager.api.SendGroupMessageResults;
 import org.asamk.signal.manager.api.UpdateGroup;
 import org.asamk.signal.manager.groups.GroupId;
 import org.asamk.signal.manager.groups.GroupLinkState;
@@ -20,13 +21,15 @@ 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.asamk.signal.util.ErrorUtils;
+import org.asamk.signal.util.SendMessageResultUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.File;
 import java.io.IOException;
 import java.util.HashMap;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 public class UpdateGroupCommand implements JsonRpcLocalCommand {
 
@@ -121,14 +124,13 @@ public class UpdateGroupCommand implements JsonRpcLocalCommand {
 
         try {
             boolean isNewGroup = false;
-            Long timestamp = null;
+            SendGroupMessageResults groupMessageResults = null;
             if (groupId == null) {
                 isNewGroup = true;
                 var results = m.createGroup(groupName,
                         groupMembers,
                         groupAvatar == null ? null : new File(groupAvatar));
-                timestamp = results.second().timestamp();
-                ErrorUtils.handleSendMessageResults(results.second().results());
+                groupMessageResults = results.second();
                 groupId = results.first();
                 groupName = null;
                 groupMembers = null;
@@ -154,10 +156,15 @@ public class UpdateGroupCommand implements JsonRpcLocalCommand {
                                     : groupSendMessagesPermission == GroupPermission.ONLY_ADMINS)
                             .build());
             if (results != null) {
-                timestamp = results.timestamp();
-                ErrorUtils.handleSendMessageResults(results.results());
+                if (groupMessageResults == null) {
+                    groupMessageResults = results;
+                } else {
+                    groupMessageResults = new SendGroupMessageResults(results.timestamp(),
+                            Stream.concat(groupMessageResults.results().stream(), results.results().stream())
+                                    .collect(Collectors.toList()));
+                }
             }
-            outputResult(outputWriter, timestamp, isNewGroup ? groupId : null);
+            outputResult(outputWriter, groupMessageResults, isNewGroup ? groupId : null);
         } catch (AttachmentInvalidException e) {
             throw new UserErrorException("Failed to add avatar attachment for group\": " + e.getMessage());
         } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) {
@@ -168,24 +175,30 @@ public class UpdateGroupCommand implements JsonRpcLocalCommand {
         }
     }
 
-    private void outputResult(final OutputWriter outputWriter, final Long timestamp, final GroupId groupId) {
+    private void outputResult(
+            final OutputWriter outputWriter, final SendGroupMessageResults results, final GroupId groupId
+    ) {
         if (outputWriter instanceof PlainTextWriter writer) {
             if (groupId != null) {
                 writer.println("Created new group: \"{}\"", groupId.toBase64());
             }
-            if (timestamp != null) {
-                writer.println("{}", timestamp);
+            if (results != null) {
+                var errors = SendMessageResultUtils.getErrorMessagesFromSendMessageResults(results.results());
+                SendMessageResultUtils.printSendMessageResultErrors(writer, errors);
+                writer.println("{}", results.timestamp());
             }
         } else {
             final var writer = (JsonWriter) outputWriter;
-            final var result = new HashMap<>();
-            if (timestamp != null) {
-                result.put("timestamp", timestamp);
+            final var response = new HashMap<>();
+            if (results != null) {
+                response.put("timestamp", results.timestamp());
+                var jsonResults = SendMessageResultUtils.getJsonSendMessageResults(results.results());
+                response.put("results", jsonResults);
             }
             if (groupId != null) {
-                result.put("groupId", groupId.toBase64());
+                response.put("groupId", groupId.toBase64());
             }
-            writer.write(result);
+            writer.write(response);
         }
     }
 }
index e59c7f86ade88784d8462b7ddf5edaceef02e7bd..0c59429c9db8439c70a357b6c8642c7772447c9d 100644 (file)
@@ -26,7 +26,7 @@ import org.asamk.signal.manager.groups.LastGroupAdminException;
 import org.asamk.signal.manager.groups.NotAGroupMemberException;
 import org.asamk.signal.manager.storage.recipients.Profile;
 import org.asamk.signal.manager.storage.recipients.RecipientAddress;
-import org.asamk.signal.util.ErrorUtils;
+import org.asamk.signal.util.SendMessageResultUtils;
 import org.freedesktop.dbus.DBusPath;
 import org.freedesktop.dbus.connections.impl.DBusConnection;
 import org.freedesktop.dbus.exceptions.DBusException;
@@ -781,7 +781,7 @@ public class DbusSignalImpl implements Signal {
     }
 
     private static void checkSendMessageResult(long timestamp, SendMessageResult result) throws DBusExecutionException {
-        var error = ErrorUtils.getErrorMessageFromSendMessageResult(result);
+        var error = SendMessageResultUtils.getErrorMessageFromSendMessageResult(result);
 
         if (error == null) {
             return;
@@ -805,7 +805,7 @@ public class DbusSignalImpl implements Signal {
             return;
         }
 
-        var errors = ErrorUtils.getErrorMessagesFromSendMessageResults(results);
+        var errors = SendMessageResultUtils.getErrorMessagesFromSendMessageResults(results);
         if (errors.size() == 0) {
             return;
         }
@@ -828,7 +828,7 @@ public class DbusSignalImpl implements Signal {
             return;
         }
 
-        var errors = ErrorUtils.getErrorMessagesFromSendMessageResults(results);
+        var errors = SendMessageResultUtils.getErrorMessagesFromSendMessageResults(results);
         if (errors.size() == 0) {
             return;
         }
diff --git a/src/main/java/org/asamk/signal/json/JsonRecipientAddress.java b/src/main/java/org/asamk/signal/json/JsonRecipientAddress.java
new file mode 100644 (file)
index 0000000..1bd09e8
--- /dev/null
@@ -0,0 +1,12 @@
+package org.asamk.signal.json;
+
+import org.asamk.signal.manager.storage.recipients.RecipientAddress;
+
+import java.util.UUID;
+
+public record JsonRecipientAddress(String uuid, String number) {
+
+    public static JsonRecipientAddress from(RecipientAddress address) {
+        return new JsonRecipientAddress(address.uuid().map(UUID::toString).orElse(null), address.number().orElse(null));
+    }
+}
diff --git a/src/main/java/org/asamk/signal/json/JsonSendMessageResult.java b/src/main/java/org/asamk/signal/json/JsonSendMessageResult.java
new file mode 100644 (file)
index 0000000..9b80a3a
--- /dev/null
@@ -0,0 +1,38 @@
+package org.asamk.signal.json;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+
+import org.asamk.signal.manager.api.SendMessageResult;
+import org.asamk.signal.manager.groups.GroupId;
+
+public record JsonSendMessageResult(
+        JsonRecipientAddress recipientAddress,
+        @JsonInclude(JsonInclude.Include.NON_NULL) String groupId,
+        Type type,
+        @JsonInclude(JsonInclude.Include.NON_NULL) String token,
+        @JsonInclude(JsonInclude.Include.NON_NULL) Long retryAfterSeconds
+) {
+
+    public static JsonSendMessageResult from(SendMessageResult result) {
+        return from(result, null);
+    }
+
+    public static JsonSendMessageResult from(SendMessageResult result, GroupId groupId) {
+        return new JsonSendMessageResult(JsonRecipientAddress.from(result.address()),
+                groupId != null ? groupId.toBase64() : null,
+                result.isSuccess()
+                        ? Type.SUCCESS
+                        : result.isNetworkFailure()
+                                ? Type.NETWORK_FAILURE
+                                : result.isUnregisteredFailure() ? Type.UNREGISTERED_FAILURE : Type.IDENTITY_FAILURE,
+                result.proofRequiredFailure() != null ? result.proofRequiredFailure().getToken() : null,
+                result.proofRequiredFailure() != null ? result.proofRequiredFailure().getRetryAfterSeconds() : null);
+    }
+
+    public enum Type {
+        SUCCESS,
+        NETWORK_FAILURE,
+        UNREGISTERED_FAILURE,
+        IDENTITY_FAILURE,
+    }
+}
similarity index 53%
rename from src/main/java/org/asamk/signal/util/ErrorUtils.java
rename to src/main/java/org/asamk/signal/util/SendMessageResultUtils.java
index 3ca731630f0e05ccbf60ee29ee4415df5ee636a7..0e13a20091cddab85f9739f005d36f9706caf19a 100644 (file)
@@ -1,10 +1,14 @@
 package org.asamk.signal.util;
 
-import org.asamk.signal.commands.exceptions.CommandException;
-import org.asamk.signal.commands.exceptions.IOErrorException;
+import org.asamk.signal.json.JsonSendMessageResult;
 import org.asamk.signal.manager.api.ProofRequiredException;
 import org.asamk.signal.manager.api.RecipientIdentifier;
+import org.asamk.signal.manager.api.SendGroupMessageResults;
 import org.asamk.signal.manager.api.SendMessageResult;
+import org.asamk.signal.manager.api.SendMessageResults;
+import org.asamk.signal.output.JsonWriter;
+import org.asamk.signal.output.OutputWriter;
+import org.asamk.signal.output.PlainTextWriter;
 
 import java.util.Collection;
 import java.util.List;
@@ -12,23 +16,33 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.stream.Collectors;
 
-public class ErrorUtils {
+public class SendMessageResultUtils {
 
-    private ErrorUtils() {
+    private SendMessageResultUtils() {
     }
 
-    public static void handleSendMessageResults(
-            Map<RecipientIdentifier, List<SendMessageResult>> mapResults
-    ) throws CommandException {
-        var errors = getErrorMessagesFromSendMessageResults(mapResults);
-        handleSendMessageResultErrors(errors);
+    public static void outputResult(final OutputWriter outputWriter, final SendGroupMessageResults sendMessageResults) {
+        if (outputWriter instanceof PlainTextWriter writer) {
+            var errors = getErrorMessagesFromSendMessageResults(sendMessageResults.results());
+            printSendMessageResultErrors(writer, errors);
+            writer.println("{}", sendMessageResults.timestamp());
+        } else {
+            final var writer = (JsonWriter) outputWriter;
+            var results = getJsonSendMessageResults(sendMessageResults.results());
+            writer.write(Map.of("timestamp", sendMessageResults.timestamp(), "results", results));
+        }
     }
 
-    public static void handleSendMessageResults(
-            Collection<SendMessageResult> results
-    ) throws CommandException {
-        var errors = getErrorMessagesFromSendMessageResults(results);
-        handleSendMessageResultErrors(errors);
+    public static void outputResult(final OutputWriter outputWriter, final SendMessageResults sendMessageResults) {
+        if (outputWriter instanceof PlainTextWriter writer) {
+            var errors = getErrorMessagesFromSendMessageResults(sendMessageResults.results());
+            printSendMessageResultErrors(writer, errors);
+            writer.println("{}", sendMessageResults.timestamp());
+        } else {
+            final var writer = (JsonWriter) outputWriter;
+            var results = getJsonSendMessageResults(sendMessageResults.results());
+            writer.write(Map.of("timestamp", sendMessageResults.timestamp(), "results", results));
+        }
     }
 
     public static List<String> getErrorMessagesFromSendMessageResults(final Map<RecipientIdentifier, List<SendMessageResult>> mapResults) {
@@ -36,7 +50,7 @@ public class ErrorUtils {
                 .stream()
                 .flatMap(entry -> entry.getValue()
                         .stream()
-                        .map(ErrorUtils::getErrorMessageFromSendMessageResult)
+                        .map(SendMessageResultUtils::getErrorMessageFromSendMessageResult)
                         .filter(Objects::nonNull)
                         .map(error -> entry.getKey().getIdentifier() + ": " + error))
                 .collect(Collectors.toList());
@@ -44,7 +58,7 @@ public class ErrorUtils {
 
     public static List<String> getErrorMessagesFromSendMessageResults(Collection<SendMessageResult> results) {
         return results.stream()
-                .map(ErrorUtils::getErrorMessageFromSendMessageResult)
+                .map(SendMessageResultUtils::getErrorMessageFromSendMessageResult)
                 .filter(Objects::nonNull)
                 .collect(Collectors.toList());
     }
@@ -82,15 +96,24 @@ public class ErrorUtils {
         return null;
     }
 
-    private static void handleSendMessageResultErrors(List<String> errors) throws CommandException {
+    public static void printSendMessageResultErrors(PlainTextWriter writer, List<String> errors) {
         if (errors.size() == 0) {
             return;
         }
-        var message = new StringBuilder();
-        message.append("Failed to send (some) messages:\n");
+        writer.println("Failed to send (some) messages:");
         for (var error : errors) {
-            message.append(error).append("\n");
+            writer.println(error);
         }
-        throw new IOErrorException(message.toString(), null);
+    }
+
+    public static List<JsonSendMessageResult> getJsonSendMessageResults(final Map<RecipientIdentifier, List<SendMessageResult>> mapResults) {
+        return mapResults.entrySet().stream().flatMap(entry -> {
+            final var groupId = entry.getKey() instanceof RecipientIdentifier.Group g ? g.groupId() : null;
+            return entry.getValue().stream().map(r -> JsonSendMessageResult.from(r, groupId));
+        }).collect(Collectors.toList());
+    }
+
+    public static List<JsonSendMessageResult> getJsonSendMessageResults(Collection<SendMessageResult> results) {
+        return results.stream().map(JsonSendMessageResult::from).collect(Collectors.toList());
     }
 }