Implement json output for receive

This commit is contained in:
AsamK 2017-06-15 23:45:14 +02:00
parent a1f0d74a99
commit 8717665d1d
9 changed files with 225 additions and 2 deletions

View file

@ -0,0 +1,21 @@
package org.asamk.signal;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer;
class JsonAttachment {
String contentType;
long id;
int size;
JsonAttachment(SignalServiceAttachment attachment) {
this.contentType = attachment.getContentType();
final SignalServiceAttachmentPointer pointer = attachment.asPointer();
if (attachment.isPointer()) {
this.id = pointer.getId();
if (pointer.getSize().isPresent()) {
this.size = pointer.getSize().get();
}
}
}
}

View file

@ -0,0 +1,31 @@
package org.asamk.signal;
import org.whispersystems.signalservice.api.messages.calls.*;
import java.util.List;
class JsonCallMessage {
OfferMessage offerMessage;
AnswerMessage answerMessage;
BusyMessage busyMessage;
HangupMessage hangupMessage;
List<IceUpdateMessage> iceUpdateMessages;
JsonCallMessage(SignalServiceCallMessage callMessage) {
if (callMessage.getOfferMessage().isPresent()) {
this.offerMessage = callMessage.getOfferMessage().get();
}
if (callMessage.getAnswerMessage().isPresent()) {
this.answerMessage = callMessage.getAnswerMessage().get();
}
if (callMessage.getBusyMessage().isPresent()) {
this.busyMessage = callMessage.getBusyMessage().get();
}
if (callMessage.getHangupMessage().isPresent()) {
this.hangupMessage = callMessage.getHangupMessage().get();
}
if (callMessage.getIceUpdateMessages().isPresent()) {
this.iceUpdateMessages = callMessage.getIceUpdateMessages().get();
}
}
}

View file

@ -0,0 +1,34 @@
package org.asamk.signal;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
import java.util.ArrayList;
import java.util.List;
class JsonDataMessage {
long timestamp;
String message;
int expiresInSeconds;
List<JsonAttachment> attachments;
JsonGroupInfo groupInfo;
JsonDataMessage(SignalServiceDataMessage dataMessage) {
this.timestamp = dataMessage.getTimestamp();
if (dataMessage.getGroupInfo().isPresent()) {
this.groupInfo = new JsonGroupInfo(dataMessage.getGroupInfo().get());
}
if (dataMessage.getBody().isPresent()) {
this.message = dataMessage.getBody().get();
}
this.expiresInSeconds = dataMessage.getExpiresInSeconds();
if (dataMessage.getAttachments().isPresent()) {
this.attachments = new ArrayList<>(dataMessage.getAttachments().get().size());
for (SignalServiceAttachment attachment : dataMessage.getAttachments().get()) {
this.attachments.add(new JsonAttachment(attachment));
}
} else {
this.attachments = new ArrayList<>();
}
}
}

View file

@ -0,0 +1,9 @@
package org.asamk.signal;
class JsonError {
String message;
JsonError(Throwable exception) {
this.message = exception.getMessage();
}
}

View file

@ -0,0 +1,24 @@
package org.asamk.signal;
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
import org.whispersystems.signalservice.internal.util.Base64;
import java.util.List;
class JsonGroupInfo {
String groupId;
List<String> members;
String name;
String type;
JsonGroupInfo(SignalServiceGroup groupInfo) {
this.groupId = Base64.encodeBytes(groupInfo.getGroupId());
if (groupInfo.getMembers().isPresent()) {
this.members = groupInfo.getMembers().get();
}
if (groupInfo.getName().isPresent()) {
this.name = groupInfo.getName().get();
}
this.type = groupInfo.getType().toString();
}
}

View file

@ -0,0 +1,36 @@
package org.asamk.signal;
import org.whispersystems.signalservice.api.messages.SignalServiceContent;
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
class JsonMessageEnvelope {
String source;
int sourceDevice;
String relay;
long timestamp;
boolean isReceipt;
JsonDataMessage dataMessage;
JsonSyncMessage syncMessage;
JsonCallMessage callMessage;
public JsonMessageEnvelope(SignalServiceEnvelope envelope, SignalServiceContent content) {
SignalServiceAddress source = envelope.getSourceAddress();
this.source = source.getNumber();
this.sourceDevice = envelope.getSourceDevice();
this.relay = source.getRelay().isPresent() ? source.getRelay().get() : null;
this.timestamp = envelope.getTimestamp();
this.isReceipt = envelope.isReceipt();
if (content != null) {
if (content.getDataMessage().isPresent()) {
this.dataMessage = new JsonDataMessage(content.getDataMessage().get());
}
if (content.getSyncMessage().isPresent()) {
this.syncMessage = new JsonSyncMessage(content.getSyncMessage().get());
}
if (content.getCallMessage().isPresent()) {
this.callMessage = new JsonCallMessage(content.getCallMessage().get());
}
}
}
}

View file

@ -0,0 +1,24 @@
package org.asamk.signal;
import org.whispersystems.signalservice.api.messages.multidevice.ReadMessage;
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
import java.util.List;
class JsonSyncMessage {
JsonDataMessage sentMessage;
List<String> blockedNumbers;
List<ReadMessage> readMessages;
JsonSyncMessage(SignalServiceSyncMessage syncMessage) {
if (syncMessage.getSent().isPresent()) {
this.sentMessage = new JsonDataMessage(syncMessage.getSent().get().getMessage());
}
if (syncMessage.getBlockedList().isPresent()) {
this.blockedNumbers = syncMessage.getBlockedList().get().getNumbers();
}
if (syncMessage.getRead().isPresent()) {
this.readMessages = syncMessage.getRead().get();
}
}
}

View file

@ -16,6 +16,13 @@
*/ */
package org.asamk.signal; 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.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.ObjectNode;
import net.sourceforge.argparse4j.ArgumentParsers; import net.sourceforge.argparse4j.ArgumentParsers;
import net.sourceforge.argparse4j.impl.Arguments; import net.sourceforge.argparse4j.impl.Arguments;
import net.sourceforge.argparse4j.inf.*; import net.sourceforge.argparse4j.inf.*;
@ -420,7 +427,8 @@ public class Main {
} }
boolean ignoreAttachments = ns.getBoolean("ignore_attachments"); boolean ignoreAttachments = ns.getBoolean("ignore_attachments");
try { try {
m.receiveMessages((long) (timeout * 1000), TimeUnit.MILLISECONDS, returnOnTimeout, ignoreAttachments, new ReceiveMessageHandler(m)); final Manager.ReceiveMessageHandler handler = ns.getBoolean("json") ? new JsonReceiveMessageHandler(m) : new ReceiveMessageHandler(m);
m.receiveMessages((long) (timeout * 1000), TimeUnit.MILLISECONDS, returnOnTimeout, ignoreAttachments, handler);
} catch (IOException e) { } catch (IOException e) {
System.err.println("Error while receiving messages: " + e.getMessage()); System.err.println("Error while receiving messages: " + e.getMessage());
return 3; return 3;
@ -822,6 +830,9 @@ public class Main {
parserReceive.addArgument("--ignore-attachments") parserReceive.addArgument("--ignore-attachments")
.help("Dont download attachments of received messages.") .help("Dont download attachments of received messages.")
.action(Arguments.storeTrue()); .action(Arguments.storeTrue());
parserReceive.addArgument("--json")
.help("Output received messages in json format, one json object per line.")
.action(Arguments.storeTrue());
Subparser parserDaemon = subparsers.addParser("daemon"); Subparser parserDaemon = subparsers.addParser("daemon");
parserDaemon.addArgument("--system") parserDaemon.addArgument("--system")
@ -1116,7 +1127,37 @@ public class Main {
} }
} }
} }
}
private static class JsonReceiveMessageHandler implements Manager.ReceiveMessageHandler {
final Manager m;
final ObjectMapper jsonProcessor;
public JsonReceiveMessageHandler(Manager m) {
this.m = m;
this.jsonProcessor = new ObjectMapper();
jsonProcessor.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); // disable autodetect
jsonProcessor.enable(SerializationFeature.WRITE_NULL_MAP_VALUES);
jsonProcessor.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
jsonProcessor.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
}
@Override
public void handleMessage(SignalServiceEnvelope envelope, SignalServiceContent content, Throwable exception) {
ObjectNode result = jsonProcessor.createObjectNode();
if (exception != null) {
result.putPOJO("error", new JsonError(exception));
}
if (envelope != null) {
result.putPOJO("envelope", new JsonMessageEnvelope(envelope, content));
}
try {
jsonProcessor.writeValue(System.out, result);
System.out.println();
} catch (IOException e) {
e.printStackTrace();
}
}
} }
private static String formatTimestamp(long timestamp) { private static String formatTimestamp(long timestamp) {

View file

@ -8,7 +8,10 @@ import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.libsignal.IdentityKeyPair; import org.whispersystems.libsignal.IdentityKeyPair;
import org.whispersystems.libsignal.InvalidKeyIdException; import org.whispersystems.libsignal.InvalidKeyIdException;
import org.whispersystems.libsignal.SignalProtocolAddress; import org.whispersystems.libsignal.SignalProtocolAddress;
import org.whispersystems.libsignal.state.*; import org.whispersystems.libsignal.state.PreKeyRecord;
import org.whispersystems.libsignal.state.SessionRecord;
import org.whispersystems.libsignal.state.SignalProtocolStore;
import org.whispersystems.libsignal.state.SignedPreKeyRecord;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;