Implement a contacts store and contacts sync

This commit is contained in:
AsamK 2016-04-22 21:17:02 +02:00
parent 543dd98453
commit 32beb8a0bd
3 changed files with 123 additions and 9 deletions

View file

@ -0,0 +1,11 @@
package org.asamk.signal;
import com.fasterxml.jackson.annotation.JsonProperty;
public class ContactInfo {
@JsonProperty
public String name;
@JsonProperty
public String number;
}

View file

@ -0,0 +1,57 @@
package org.asamk.signal;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class JsonContactsStore {
@JsonProperty("contacts")
@JsonSerialize(using = JsonContactsStore.MapToListSerializer.class)
@JsonDeserialize(using = ContactsDeserializer.class)
private Map<String, ContactInfo> contacts = new HashMap<>();
private static final ObjectMapper jsonProcessot = new ObjectMapper();
void updateContact(ContactInfo contact) {
contacts.put(contact.number, contact);
}
ContactInfo getContact(String number) {
ContactInfo c = contacts.get(number);
return c;
}
List<ContactInfo> getContacts() {
return new ArrayList<>(contacts.values());
}
public static class MapToListSerializer extends JsonSerializer<Map<?, ?>> {
@Override
public void serialize(final Map<?, ?> value, final JsonGenerator jgen, final SerializerProvider provider) throws IOException {
jgen.writeObject(value.values());
}
}
public static class ContactsDeserializer extends JsonDeserializer<Map<String, ContactInfo>> {
@Override
public Map<String, ContactInfo> deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
Map<String, ContactInfo> contacts = new HashMap<>();
JsonNode node = jsonParser.getCodec().readTree(jsonParser);
for (JsonNode n : node) {
ContactInfo c = jsonProcessot.treeToValue(n, ContactInfo.class);
contacts.put(c.number, c);
}
return contacts;
}
}
}

View file

@ -90,6 +90,7 @@ class Manager implements Signal {
private SignalProtocolStore signalProtocolStore;
private SignalServiceAccountManager accountManager;
private JsonGroupStore groupStore;
private JsonContactsStore contactStore;
public Manager(String username, String settingsPath) {
this.username = username;
@ -168,6 +169,14 @@ class Manager implements Signal {
if (groupStore == null) {
groupStore = new JsonGroupStore();
}
JsonNode contactStoreNode = rootNode.get("contactStore");
if (contactStoreNode != null) {
contactStore = jsonProcessot.convertValue(contactStoreNode, JsonContactsStore.class);
}
if (contactStore == null) {
contactStore = new JsonContactsStore();
}
accountManager = new SignalServiceAccountManager(URL, TRUST_STORE, username, password, deviceId, USER_AGENT);
try {
if (registered && accountManager.getPreKeysCount() < PREKEY_MINIMUM_COUNT) {
@ -193,6 +202,7 @@ class Manager implements Signal {
.put("registered", registered)
.putPOJO("axolotlStore", signalProtocolStore)
.putPOJO("groupStore", groupStore)
.putPOJO("contactStore", contactStore)
;
try {
jsonProcessot.writeValue(new File(getFileName()), rootNode);
@ -714,7 +724,13 @@ class Manager implements Signal {
if (syncMessage.getRequest().isPresent()) {
RequestMessage rm = syncMessage.getRequest().get();
if (rm.isContactsRequest()) {
// TODO implement when we have contacts
try {
sendContacts();
} catch (EncapsulatedExceptions encapsulatedExceptions) {
encapsulatedExceptions.printStackTrace();
} catch (UntrustedIdentityException e) {
e.printStackTrace();
}
}
if (rm.isGroupsRequest()) {
try {
@ -759,11 +775,12 @@ class Manager implements Signal {
DeviceContactsInputStream s = new DeviceContactsInputStream(retrieveAttachmentAsStream(syncMessage.getContacts().get().asPointer()));
DeviceContact c;
while ((c = s.read()) != null) {
// TODO implement when we have contact storage
ContactInfo contact = new ContactInfo();
contact.number = c.getNumber();
if (c.getName().isPresent()) {
c.getName().get();
contact.name = c.getName().get();
}
c.getNumber();
contactStore.updateContact(contact);
if (c.getAvatar().isPresent()) {
byte[] ava = new byte[(int) c.getAvatar().get().getLength()];
@ -868,20 +885,49 @@ class Manager implements Signal {
}
private void sendGroups() throws IOException, EncapsulatedExceptions, UntrustedIdentityException {
File contactsFile = File.createTempFile("multidevice-contact-update", ".tmp");
File groupsFile = File.createTempFile("multidevice-group-update", ".tmp");
try {
DeviceGroupsOutputStream out = new DeviceGroupsOutputStream(new FileOutputStream(contactsFile));
DeviceGroupsOutputStream out = new DeviceGroupsOutputStream(new FileOutputStream(groupsFile));
try {
for (GroupInfo record : groupStore.getGroups()) {
out.write(new DeviceGroup(record.groupId, Optional.fromNullable(record.name),
new ArrayList<>(record.members), Optional.of(new SignalServiceAttachmentStream(new FileInputStream("/home/sebastian/Bilder/00026_150512_14-00-18.JPG"), "octet", new File("/home/sebastian/Bilder/00026_150512_14-00-18.JPG").length(), null)),
new ArrayList<>(record.members), Optional.<SignalServiceAttachmentStream>absent(), // TODO
record.active));
}
} finally {
out.close();
}
if (groupsFile.exists() && groupsFile.length() > 0) {
FileInputStream contactsFileStream = new FileInputStream(groupsFile);
SignalServiceAttachmentStream attachmentStream = SignalServiceAttachment.newStreamBuilder()
.withStream(contactsFileStream)
.withContentType("application/octet-stream")
.withLength(groupsFile.length())
.build();
sendMessage(SignalServiceSyncMessage.forGroups(attachmentStream));
}
} finally {
groupsFile.delete();
}
}
private void sendContacts() throws IOException, EncapsulatedExceptions, UntrustedIdentityException {
File contactsFile = File.createTempFile("multidevice-contact-update", ".tmp");
try {
DeviceContactsOutputStream out = new DeviceContactsOutputStream(new FileOutputStream(contactsFile));
try {
for (ContactInfo record : contactStore.getContacts()) {
out.write(new DeviceContact(record.number, Optional.fromNullable(record.name),
Optional.<SignalServiceAttachmentStream>absent())); // TODO
}
} finally {
out.close();
}
if (contactsFile.exists() && contactsFile.length() > 0) {
FileInputStream contactsFileStream = new FileInputStream(contactsFile);
SignalServiceAttachmentStream attachmentStream = SignalServiceAttachment.newStreamBuilder()
@ -890,10 +936,10 @@ class Manager implements Signal {
.withLength(contactsFile.length())
.build();
sendMessage(SignalServiceSyncMessage.forGroups(attachmentStream));
sendMessage(SignalServiceSyncMessage.forContacts(attachmentStream));
}
} finally {
if (contactsFile != null) contactsFile.delete();
contactsFile.delete();
}
}
}