mirror of
https://github.com/AsamK/signal-cli
synced 2025-08-29 18:40:39 +00:00
Added JSON output to listGroups and allowed json to be activated with -j (#401)
* Added json output to listGroups and allowed json to be activated with -j * Renamed classes * Added AsamK's suggestions * Removed isRegisted check since that is causing a conflict with upstream * Fixed an issue in the help message for listGroupsCommand * Re-enabled --json for receive and getUserStatuses commands as deprecated * Added better depricated warning message and clarified some java doc stuff
This commit is contained in:
parent
c9fa28d844
commit
90f5cd79c9
6 changed files with 134 additions and 41 deletions
|
@ -299,6 +299,9 @@ public class Main {
|
|||
mut.addArgument("--dbus").help("Make request via user dbus.").action(Arguments.storeTrue());
|
||||
mut.addArgument("--dbus-system").help("Make request via system dbus.").action(Arguments.storeTrue());
|
||||
|
||||
parser.addArgument("-o", "--output").help("Choose to output in plain text or JSON")
|
||||
.choices("plain-text", "json").setDefault("plain-text");
|
||||
|
||||
Subparsers subparsers = parser.addSubparsers()
|
||||
.title("subcommands")
|
||||
.dest("command")
|
||||
|
|
|
@ -8,6 +8,8 @@ import net.sourceforge.argparse4j.inf.Namespace;
|
|||
import net.sourceforge.argparse4j.inf.Subparser;
|
||||
|
||||
import org.asamk.signal.manager.Manager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
|
@ -17,12 +19,15 @@ import java.util.stream.Collectors;
|
|||
|
||||
public class GetUserStatusCommand implements LocalCommand {
|
||||
|
||||
// TODO delete later when "json" variable is removed
|
||||
final static Logger logger = LoggerFactory.getLogger(GetUserStatusCommand.class);
|
||||
|
||||
@Override
|
||||
public void attachToSubparser(final Subparser subparser) {
|
||||
subparser.addArgument("number").help("Phone number").nargs("+");
|
||||
subparser.help("Check if the specified phone number/s have been registered");
|
||||
subparser.addArgument("--json")
|
||||
.help("Output received messages in json format, one json object per line.")
|
||||
.help("WARNING: This parameter is now deprecated! Please use the \"output\" option instead.\n\nOutput received messages in json format, one json object per line.")
|
||||
.action(Arguments.storeTrue());
|
||||
}
|
||||
|
||||
|
@ -32,6 +37,13 @@ public class GetUserStatusCommand implements LocalCommand {
|
|||
ObjectMapper jsonProcessor = new ObjectMapper();
|
||||
jsonProcessor.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
|
||||
|
||||
boolean inJson = ns.getString("output").equals("json");
|
||||
|
||||
// TODO delete later when "json" variable is removed
|
||||
if (ns.getBoolean("json")) {
|
||||
logger.warn("\"--json\" option has been deprecated, please use \"output\" instead.");
|
||||
}
|
||||
|
||||
// Get a map of registration statuses
|
||||
Map<String, Boolean> registered;
|
||||
try {
|
||||
|
@ -42,7 +54,7 @@ public class GetUserStatusCommand implements LocalCommand {
|
|||
}
|
||||
|
||||
// Output
|
||||
if (ns.getBoolean("json")) {
|
||||
if (inJson) {
|
||||
List<JsonIsRegistered> objects = registered.entrySet()
|
||||
.stream()
|
||||
.map(entry -> new JsonIsRegistered(entry.getKey(), entry.getValue()))
|
||||
|
|
|
@ -9,32 +9,39 @@ import org.asamk.signal.manager.groups.GroupInviteLinkUrl;
|
|||
import org.asamk.signal.manager.storage.groups.GroupInfo;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ListGroupsCommand implements LocalCommand {
|
||||
|
||||
private static void printGroup(Manager m, GroupInfo group, boolean detailed) {
|
||||
private static Set<String> resolveMembers(Manager m, Set<SignalServiceAddress> addresses) {
|
||||
return addresses.stream().map(m::resolveSignalServiceAddress)
|
||||
.map(SignalServiceAddress::getLegacyIdentifier)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private static int printGroupsJson(ObjectMapper jsonProcessor, List<?> objects) {
|
||||
try {
|
||||
jsonProcessor.writeValue(System.out, objects);
|
||||
System.out.println();
|
||||
} catch (IOException e) {
|
||||
System.err.println(e.getMessage());
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static void printGroupPlainText(Manager m, GroupInfo group, boolean detailed) {
|
||||
if (detailed) {
|
||||
Set<String> members = group.getMembers()
|
||||
.stream()
|
||||
.map(m::resolveSignalServiceAddress)
|
||||
.map(SignalServiceAddress::getLegacyIdentifier)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
Set<String> pendingMembers = group.getPendingMembers()
|
||||
.stream()
|
||||
.map(m::resolveSignalServiceAddress)
|
||||
.map(SignalServiceAddress::getLegacyIdentifier)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
Set<String> requestingMembers = group.getRequestingMembers()
|
||||
.stream()
|
||||
.map(m::resolveSignalServiceAddress)
|
||||
.map(SignalServiceAddress::getLegacyIdentifier)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
final GroupInviteLinkUrl groupInviteLink = group.getGroupInviteLink();
|
||||
|
||||
System.out.println(String.format(
|
||||
|
@ -43,9 +50,9 @@ public class ListGroupsCommand implements LocalCommand {
|
|||
group.getTitle(),
|
||||
group.isMember(m.getSelfAddress()),
|
||||
group.isBlocked(),
|
||||
members,
|
||||
pendingMembers,
|
||||
requestingMembers,
|
||||
resolveMembers(m, group.getMembers()),
|
||||
resolveMembers(m, group.getPendingMembers()),
|
||||
resolveMembers(m, group.getRequestingMembers()),
|
||||
groupInviteLink == null ? '-' : groupInviteLink.getUrl()));
|
||||
} else {
|
||||
System.out.println(String.format("Id: %s Name: %s Active: %s Blocked: %b",
|
||||
|
@ -58,18 +65,68 @@ public class ListGroupsCommand implements LocalCommand {
|
|||
|
||||
@Override
|
||||
public void attachToSubparser(final Subparser subparser) {
|
||||
subparser.addArgument("-d", "--detailed").action(Arguments.storeTrue()).help("List members of each group");
|
||||
subparser.help("List group name and ids");
|
||||
subparser.addArgument("-d", "--detailed").action(Arguments.storeTrue())
|
||||
.help("List the members and group invite links of each group. If output=json, then this is always set");
|
||||
|
||||
subparser.help("List group information including names, ids, active status, blocked status and members");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int handleCommand(final Namespace ns, final Manager m) {
|
||||
List<GroupInfo> groups = m.getGroups();
|
||||
boolean detailed = ns.getBoolean("detailed");
|
||||
if (ns.getString("output").equals("json")) {
|
||||
final ObjectMapper jsonProcessor = new ObjectMapper();
|
||||
jsonProcessor.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
|
||||
jsonProcessor.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
|
||||
|
||||
for (GroupInfo group : groups) {
|
||||
printGroup(m, group, detailed);
|
||||
List<JsonGroup> objects = new ArrayList<>();
|
||||
for (GroupInfo group : m.getGroups()) {
|
||||
final GroupInviteLinkUrl groupInviteLink = group.getGroupInviteLink();
|
||||
|
||||
objects.add(new JsonGroup(group.getGroupId().toBase64(),
|
||||
group.getTitle(),
|
||||
group.isMember(m.getSelfAddress()),
|
||||
group.isBlocked(),
|
||||
resolveMembers(m, group.getMembers()),
|
||||
resolveMembers(m, group.getPendingMembers()),
|
||||
resolveMembers(m, group.getRequestingMembers()),
|
||||
groupInviteLink == null ? null : groupInviteLink.getUrl()));
|
||||
}
|
||||
return printGroupsJson(jsonProcessor, objects);
|
||||
} else {
|
||||
boolean detailed = ns.getBoolean("detailed");
|
||||
for (GroupInfo group : m.getGroups()) {
|
||||
printGroupPlainText(m, group, detailed);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static final class JsonGroup {
|
||||
|
||||
public String id;
|
||||
public String name;
|
||||
public boolean isMember;
|
||||
public boolean isBlocked;
|
||||
|
||||
public Set<String> members;
|
||||
public Set<String> pendingMembers;
|
||||
public Set<String> requestingMembers;
|
||||
public String groupInviteLink;
|
||||
|
||||
public JsonGroup(String id, String name, boolean isMember, boolean isBlocked,
|
||||
Set<String> members, Set<String> pendingMembers,
|
||||
Set<String> requestingMembers, String groupInviteLink)
|
||||
{
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.isMember = isMember;
|
||||
this.isBlocked = isBlocked;
|
||||
|
||||
this.members = members;
|
||||
this.pendingMembers = pendingMembers;
|
||||
this.requestingMembers = requestingMembers;
|
||||
this.groupInviteLink = groupInviteLink;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,10 @@ import org.freedesktop.dbus.connections.impl.DBusConnection;
|
|||
import org.freedesktop.dbus.exceptions.DBusException;
|
||||
import org.whispersystems.util.Base64;
|
||||
|
||||
// TODO delete later when "json" variable is removed
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
@ -27,6 +31,9 @@ import static org.asamk.signal.util.ErrorUtils.handleAssertionError;
|
|||
|
||||
public class ReceiveCommand implements ExtendedDbusCommand, LocalCommand {
|
||||
|
||||
// TODO delete later when "json" variable is removed
|
||||
final static Logger logger = LoggerFactory.getLogger(ReceiveCommand.class);
|
||||
|
||||
@Override
|
||||
public void attachToSubparser(final Subparser subparser) {
|
||||
subparser.addArgument("-t", "--timeout")
|
||||
|
@ -36,13 +43,21 @@ public class ReceiveCommand implements ExtendedDbusCommand, LocalCommand {
|
|||
.help("Don’t download attachments of received messages.")
|
||||
.action(Arguments.storeTrue());
|
||||
subparser.addArgument("--json")
|
||||
.help("Output received messages in json format, one json object per line.")
|
||||
.help("WARNING: This parameter is now deprecated! Please use the \"output\" option instead.\n\nOutput received messages in json format, one json object per line.")
|
||||
.action(Arguments.storeTrue());
|
||||
}
|
||||
|
||||
public int handleCommand(final Namespace ns, final Signal signal, DBusConnection dbusconnection) {
|
||||
final ObjectMapper jsonProcessor;
|
||||
|
||||
boolean inJson = ns.getString("output").equals("json") || ns.getBoolean("json");
|
||||
|
||||
// TODO delete later when "json" variable is removed
|
||||
if (ns.getBoolean("json")) {
|
||||
logger.warn("\"--json\" option has been deprecated, please use \"output\" instead.");
|
||||
}
|
||||
|
||||
if (inJson) {
|
||||
jsonProcessor = new ObjectMapper();
|
||||
jsonProcessor.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
|
||||
jsonProcessor.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
|
||||
|
@ -146,6 +161,13 @@ public class ReceiveCommand implements ExtendedDbusCommand, LocalCommand {
|
|||
|
||||
@Override
|
||||
public int handleCommand(final Namespace ns, final Manager m) {
|
||||
boolean inJson = ns.getString("output").equals("json") || ns.getBoolean("json");
|
||||
|
||||
// TODO delete later when "json" variable is removed
|
||||
if (ns.getBoolean("json")) {
|
||||
logger.warn("\"--json\" option has been deprecated, please use \"output\" instead.");
|
||||
}
|
||||
|
||||
double timeout = 5;
|
||||
if (ns.getDouble("timeout") != null) {
|
||||
timeout = ns.getDouble("timeout");
|
||||
|
@ -157,7 +179,7 @@ public class ReceiveCommand implements ExtendedDbusCommand, LocalCommand {
|
|||
}
|
||||
boolean ignoreAttachments = ns.getBoolean("ignore_attachments");
|
||||
try {
|
||||
final Manager.ReceiveMessageHandler handler = ns.getBoolean("json")
|
||||
final Manager.ReceiveMessageHandler handler = inJson
|
||||
? new JsonReceiveMessageHandler(m)
|
||||
: new ReceiveMessageHandler(m);
|
||||
m.receiveMessages((long) (timeout * 1000),
|
||||
|
|
|
@ -312,7 +312,7 @@ public class Manager implements Closeable {
|
|||
*
|
||||
* @param numbers The set of phone number in question
|
||||
* @return A map of numbers to booleans. True if registered, false otherwise. Should never be null
|
||||
* @throws IOException if its unable to check if the users are registered
|
||||
* @throws IOException if its unable to get the contacts to check if they're registered
|
||||
*/
|
||||
public Map<String, Boolean> areUsersRegistered(Set<String> numbers) throws IOException {
|
||||
// Note "contactDetails" has no optionals. It only gives us info on users who are registered
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue