package org.asamk.signal;
-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 com.fasterxml.jackson.databind.node.ObjectNode;
-
import org.asamk.signal.json.JsonError;
import org.asamk.signal.json.JsonMessageEnvelope;
import org.asamk.signal.manager.Manager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.messages.SignalServiceContent;
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
public class JsonReceiveMessageHandler implements Manager.ReceiveMessageHandler {
- final Manager m;
- private final ObjectMapper jsonProcessor;
+ private final static Logger logger = LoggerFactory.getLogger(JsonReceiveMessageHandler.class);
+
+ protected final Manager m;
+ private final JsonWriter jsonWriter;
public JsonReceiveMessageHandler(Manager m) {
this.m = m;
- this.jsonProcessor = new ObjectMapper();
- jsonProcessor.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
- jsonProcessor.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
+ jsonWriter = new JsonWriter(System.out);
}
@Override
public void handleMessage(SignalServiceEnvelope envelope, SignalServiceContent content, Throwable exception) {
- ObjectNode result = jsonProcessor.createObjectNode();
+ final Map<String, Object> object = new HashMap<>();
if (exception != null) {
- result.putPOJO("error", new JsonError(exception));
+ object.put("error", new JsonError(exception));
}
if (envelope != null) {
- result.putPOJO("envelope", new JsonMessageEnvelope(envelope, content, m));
+ object.put("envelope", new JsonMessageEnvelope(envelope, content, m));
}
try {
- jsonProcessor.writeValue(System.out, result);
- System.out.println();
+ jsonWriter.write(object);
} catch (IOException e) {
- e.printStackTrace();
+ logger.error("Failed to write json object: {}", e.getMessage());
}
}
}
--- /dev/null
+package org.asamk.signal;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.nio.charset.StandardCharsets;
+
+public class JsonWriter {
+
+ private final OutputStreamWriter writer;
+ private final ObjectMapper objectMapper;
+
+ public JsonWriter(final OutputStream writer) {
+ this.writer = new OutputStreamWriter(writer, StandardCharsets.UTF_8);
+
+ objectMapper = new ObjectMapper();
+ objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+ objectMapper.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
+ }
+
+ public void write(final Object object) throws IOException {
+ try {
+ objectMapper.writeValue(writer, object);
+ } catch (JsonProcessingException e) {
+ // Some issue with json serialization, probably caused by a bug
+ throw new AssertionError(e);
+ }
+ writer.write(System.lineSeparator());
+ writer.flush();
+ }
+}
package org.asamk.signal.commands;
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
import net.sourceforge.argparse4j.impl.Arguments;
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+import org.asamk.signal.JsonWriter;
import org.asamk.signal.OutputType;
import org.asamk.signal.manager.Manager;
import org.slf4j.Logger;
public class GetUserStatusCommand implements LocalCommand {
- // TODO delete later when "json" variable is removed
private final static Logger logger = LoggerFactory.getLogger(GetUserStatusCommand.class);
@Override
@Override
public int handleCommand(final Namespace ns, final Manager m) {
// Setup the json object mapper
- ObjectMapper jsonProcessor = new ObjectMapper();
- jsonProcessor.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
-
boolean inJson = ns.get("output") == OutputType.JSON || ns.getBoolean("json");
// TODO delete later when "json" variable is removed
// Output
if (inJson) {
- List<JsonIsRegistered> objects = registered.entrySet()
+ final JsonWriter jsonWriter = new JsonWriter(System.out);
+
+ List<JsonUserStatus> jsonUserStatuses = registered.entrySet()
.stream()
- .map(entry -> new JsonIsRegistered(entry.getKey(), entry.getValue()))
+ .map(entry -> new JsonUserStatus(entry.getKey(), entry.getValue()))
.collect(Collectors.toList());
try {
- jsonProcessor.writeValue(System.out, objects);
- System.out.println();
+ jsonWriter.write(jsonUserStatuses);
} catch (IOException e) {
- System.err.println(e.getMessage());
+ logger.error("Failed to write json object: {}", e.getMessage());
+ return 3;
}
} else {
for (Map.Entry<String, Boolean> entry : registered.entrySet()) {
return 0;
}
- private static final class JsonIsRegistered {
+ private static final class JsonUserStatus {
public String name;
public boolean isRegistered;
- public JsonIsRegistered(String name, boolean isRegistered) {
+ public JsonUserStatus(String name, boolean isRegistered) {
this.name = name;
this.isRegistered = isRegistered;
}
package org.asamk.signal.commands;
-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 net.sourceforge.argparse4j.impl.Arguments;
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+import org.asamk.signal.JsonWriter;
import org.asamk.signal.OutputType;
import org.asamk.signal.manager.Manager;
import org.asamk.signal.manager.groups.GroupInviteLinkUrl;
import org.asamk.signal.manager.storage.groups.GroupInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import java.io.IOException;
public class ListGroupsCommand implements LocalCommand {
+ private final static Logger logger = LoggerFactory.getLogger(ListGroupsCommand.class);
+
private static Set<String> resolveMembers(Manager m, Set<SignalServiceAddress> addresses) {
return addresses.stream()
.map(m::resolveSignalServiceAddress)
.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 3;
- }
-
- return 0;
- }
-
private static void printGroupPlainText(Manager m, GroupInfo group, boolean detailed) {
if (detailed) {
final GroupInviteLinkUrl groupInviteLink = group.getGroupInviteLink();
@Override
public int handleCommand(final Namespace ns, final Manager m) {
if (ns.get("output") == OutputType.JSON) {
- final ObjectMapper jsonProcessor = new ObjectMapper();
- jsonProcessor.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
- jsonProcessor.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
+ final JsonWriter jsonWriter = new JsonWriter(System.out);
- List<JsonGroup> objects = new ArrayList<>();
+ List<JsonGroup> jsonGroups = new ArrayList<>();
for (GroupInfo group : m.getGroups()) {
final GroupInviteLinkUrl groupInviteLink = group.getGroupInviteLink();
- objects.add(new JsonGroup(group.getGroupId().toBase64(),
+ jsonGroups.add(new JsonGroup(group.getGroupId().toBase64(),
group.getTitle(),
group.isMember(m.getSelfAddress()),
group.isBlocked(),
resolveMembers(m, group.getRequestingMembers()),
groupInviteLink == null ? null : groupInviteLink.getUrl()));
}
- return printGroupsJson(jsonProcessor, objects);
+
+ try {
+ jsonWriter.write(jsonGroups);
+ } catch (IOException e) {
+ logger.error("Failed to write json object: {}", e.getMessage());
+ return 3;
+ }
+
+ return 0;
} else {
boolean detailed = ns.getBoolean("detailed");
for (GroupInfo group : m.getGroups()) {
package org.asamk.signal.commands;
-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 com.fasterxml.jackson.databind.node.ObjectNode;
-
import net.sourceforge.argparse4j.impl.Arguments;
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
import org.asamk.Signal;
import org.asamk.signal.JsonReceiveMessageHandler;
+import org.asamk.signal.JsonWriter;
import org.asamk.signal.OutputType;
import org.asamk.signal.ReceiveMessageHandler;
import org.asamk.signal.json.JsonMessageEnvelope;
import java.io.IOException;
import java.util.Base64;
+import java.util.Map;
import java.util.concurrent.TimeUnit;
import static org.asamk.signal.util.ErrorUtils.handleAssertionError;
public class ReceiveCommand implements ExtendedDbusCommand, LocalCommand {
- // TODO delete later when "json" variable is removed
private final static Logger logger = LoggerFactory.getLogger(ReceiveCommand.class);
@Override
}
public int handleCommand(final Namespace ns, final Signal signal, DBusConnection dbusconnection) {
- final ObjectMapper jsonProcessor;
-
boolean inJson = ns.get("output") == OutputType.JSON || ns.getBoolean("json");
// TODO delete later when "json" variable is removed
logger.warn("\"--json\" option has been deprecated, please use the global \"--output=json\" instead.");
}
- if (inJson) {
- jsonProcessor = new ObjectMapper();
- jsonProcessor.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
- jsonProcessor.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
- } else {
- jsonProcessor = null;
- }
+ final JsonWriter jsonWriter = inJson ? new JsonWriter(System.out) : null;
try {
dbusconnection.addSigHandler(Signal.MessageReceived.class, messageReceived -> {
- if (jsonProcessor != null) {
+ if (jsonWriter != null) {
JsonMessageEnvelope envelope = new JsonMessageEnvelope(messageReceived);
- ObjectNode result = jsonProcessor.createObjectNode();
- result.putPOJO("envelope", envelope);
+ final Map<String, JsonMessageEnvelope> object = Map.of("envelope", envelope);
try {
- jsonProcessor.writeValue(System.out, result);
- System.out.println();
+ jsonWriter.write(object);
} catch (IOException e) {
- e.printStackTrace();
+ logger.error("Failed to write json object: {}", e.getMessage());
}
} else {
System.out.print(String.format("Envelope from: %s\nTimestamp: %s\nBody: %s\n",
});
dbusconnection.addSigHandler(Signal.ReceiptReceived.class, receiptReceived -> {
- if (jsonProcessor != null) {
+ if (jsonWriter != null) {
JsonMessageEnvelope envelope = new JsonMessageEnvelope(receiptReceived);
- ObjectNode result = jsonProcessor.createObjectNode();
- result.putPOJO("envelope", envelope);
+ final Map<String, JsonMessageEnvelope> object = Map.of("envelope", envelope);
try {
- jsonProcessor.writeValue(System.out, result);
- System.out.println();
+ jsonWriter.write(object);
} catch (IOException e) {
- e.printStackTrace();
+ logger.error("Failed to write json object: {}", e.getMessage());
}
} else {
System.out.print(String.format("Receipt from: %s\nTimestamp: %s\n",
});
dbusconnection.addSigHandler(Signal.SyncMessageReceived.class, syncReceived -> {
- if (jsonProcessor != null) {
+ if (jsonWriter != null) {
JsonMessageEnvelope envelope = new JsonMessageEnvelope(syncReceived);
- ObjectNode result = jsonProcessor.createObjectNode();
- result.putPOJO("envelope", envelope);
+ final Map<String, JsonMessageEnvelope> object = Map.of("envelope", envelope);
try {
- jsonProcessor.writeValue(System.out, result);
- System.out.println();
+ jsonWriter.write(object);
} catch (IOException e) {
- e.printStackTrace();
+ logger.error("Failed to write json object: {}", e.getMessage());
}
} else {
System.out.print(String.format("Sync Envelope from: %s to: %s\nTimestamp: %s\nBody: %s\n",
this.fileChannel = fileChannel;
this.lock = lock;
jsonProcessor.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE); // disable autodetect
- jsonProcessor.enable(SerializationFeature.INDENT_OUTPUT); // for pretty print, you can disable it.
+ jsonProcessor.enable(SerializationFeature.INDENT_OUTPUT); // for pretty print
jsonProcessor.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
jsonProcessor.disable(JsonParser.Feature.AUTO_CLOSE_SOURCE);
jsonProcessor.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);