Server side support for delivery receipts.

This commit is contained in:
Moxie Marlinspike
2014-07-25 15:48:34 -07:00
parent 160c0bfe14
commit 4eb88a3e02
23 changed files with 1259 additions and 558 deletions

View File

@@ -19,13 +19,13 @@ package org.whispersystems.textsecuregcm.push;
import com.codahale.metrics.Meter;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.SharedMetricRegistries;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Optional;
import com.notnoop.apns.APNS;
import com.notnoop.apns.ApnsService;
import com.notnoop.exceptions.NetworkIOException;
import net.spy.memcached.MemcachedClient;
import org.bouncycastle.openssl.PEMReader;
import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.entities.PendingMessage;
@@ -36,6 +36,7 @@ import org.whispersystems.textsecuregcm.storage.PubSubManager;
import org.whispersystems.textsecuregcm.storage.PubSubMessage;
import org.whispersystems.textsecuregcm.storage.StoredMessages;
import org.whispersystems.textsecuregcm.util.Constants;
import org.whispersystems.textsecuregcm.util.SystemMapper;
import org.whispersystems.textsecuregcm.util.Util;
import org.whispersystems.textsecuregcm.websocket.WebsocketAddress;
@@ -69,7 +70,7 @@ public class APNSender implements Managed {
private static final String MESSAGE_BODY = "m";
private static final ObjectMapper mapper = new ObjectMapper();
private static final ObjectMapper mapper = SystemMapper.getMapper();
private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
@@ -112,7 +113,10 @@ public class APNSender implements Managed {
} else {
memcacheSet(registrationId, account.getNumber());
storedMessages.insert(account.getId(), device.getId(), message);
sendPush(registrationId, serializedPendingMessage);
if (!message.isReceipt()) {
sendPush(registrationId, serializedPendingMessage);
}
}
} catch (IOException e) {
throw new TransientPushFailureException(e);

View File

@@ -87,9 +87,11 @@ public class GCMSender implements Managed, PacketListener {
public void sendMessage(String messageId, UnacknowledgedMessage message) {
try {
boolean isReceipt = message.getPendingMessage().isReceipt();
Map<String, String> dataObject = new HashMap<>();
dataObject.put("type", "message");
dataObject.put("message", message.getPendingMessage().getEncryptedOutgoingMessage());
dataObject.put(isReceipt ? "receipt" : "message", message.getPendingMessage().getEncryptedOutgoingMessage());
Map<String, Object> messageObject = new HashMap<>();
messageObject.put("to", message.getRegistrationId());

View File

@@ -25,6 +25,8 @@ import org.whispersystems.textsecuregcm.entities.PendingMessage;
import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.Device;
import static org.whispersystems.textsecuregcm.entities.MessageProtos.OutgoingMessageSignal;
public class PushSender {
private final Logger logger = LoggerFactory.getLogger(PushSender.class);
@@ -42,13 +44,17 @@ public class PushSender {
this.webSocketSender = websocketSender;
}
public void sendMessage(Account account, Device device, MessageProtos.OutgoingMessageSignal message)
public void sendMessage(Account account, Device device, OutgoingMessageSignal message)
throws NotPushRegisteredException, TransientPushFailureException
{
try {
boolean isReceipt = message.getType() == OutgoingMessageSignal.Type.RECEIPT_VALUE;
String signalingKey = device.getSignalingKey();
EncryptedOutgoingMessage encryptedMessage = new EncryptedOutgoingMessage(message, signalingKey);
PendingMessage pendingMessage = new PendingMessage(message.getSource(), message.getTimestamp(), encryptedMessage.serialize());
PendingMessage pendingMessage = new PendingMessage(message.getSource(),
message.getTimestamp(),
isReceipt,
encryptedMessage.serialize());
sendMessage(account, device, pendingMessage);
} catch (CryptoEncodingException e) {

View File

@@ -31,6 +31,7 @@ import org.whispersystems.textsecuregcm.storage.PubSubManager;
import org.whispersystems.textsecuregcm.storage.PubSubMessage;
import org.whispersystems.textsecuregcm.storage.StoredMessages;
import org.whispersystems.textsecuregcm.util.Constants;
import org.whispersystems.textsecuregcm.util.SystemMapper;
import org.whispersystems.textsecuregcm.websocket.WebsocketAddress;
import static com.codahale.metrics.MetricRegistry.name;
@@ -43,7 +44,7 @@ public class WebsocketSender {
private final Meter onlineMeter = metricRegistry.meter(name(getClass(), "online"));
private final Meter offlineMeter = metricRegistry.meter(name(getClass(), "offline"));
private static final ObjectMapper mapper = new ObjectMapper();
private static final ObjectMapper mapper = SystemMapper.getMapper();
private final StoredMessages storedMessages;
private final PubSubManager pubSubManager;