Adjust requeue message logic to avoid redis assumptions

// FREEBIE
This commit is contained in:
Moxie Marlinspike
2015-12-04 11:39:33 -08:00
parent d376035557
commit fb5e0242d0
5 changed files with 165 additions and 37 deletions

View File

@@ -249,7 +249,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
FilterRegistration.Dynamic filter = environment.servlets().addFilter("CORS", CrossOriginFilter.class);
filter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "/*");
filter.setInitParameter("allowedOrigins", "*");
filter.setInitParameter("allowedHeaders", "Content-Type,Authorization,X-Requested-With,Content-Length,Accept,Origin");
filter.setInitParameter("allowedHeaders", "Content-Type,Authorization,X-Requested-With,Content-Length,Accept,Origin,X-Signal-Agent");
filter.setInitParameter("allowedMethods", "GET,PUT,POST,DELETE,OPTIONS");
filter.setInitParameter("preflightMaxAge", "5184000");
filter.setInitParameter("allowCredentials", "true");

View File

@@ -19,8 +19,6 @@ package org.whispersystems.textsecuregcm.push;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.entities.ApnMessage;
import org.whispersystems.textsecuregcm.entities.CryptoEncodingException;
import org.whispersystems.textsecuregcm.entities.EncryptedOutgoingMessage;
import org.whispersystems.textsecuregcm.entities.GcmMessage;
import org.whispersystems.textsecuregcm.push.ApnFallbackManager.ApnFallbackTask;
import org.whispersystems.textsecuregcm.push.WebsocketSender.DeliveryStatus;
@@ -58,54 +56,68 @@ public class PushSender {
else throw new NotPushRegisteredException("No delivery possible!");
}
public void sendQueuedNotification(Account account, Device device, int messageQueueDepth)
throws NotPushRegisteredException, TransientPushFailureException
{
if (device.getGcmId() != null) sendGcmNotification(account, device);
else if (device.getApnId() != null) sendApnNotification(account, device, messageQueueDepth);
else if (!device.getFetchesMessages()) throw new NotPushRegisteredException("No notification possible!");
}
public WebsocketSender getWebSocketSender() {
return webSocketSender;
}
private void sendGcmMessage(Account account, Device device, Envelope message)
throws TransientPushFailureException
{
sendNotificationGcmMessage(account, device, message);
}
private void sendNotificationGcmMessage(Account account, Device device, Envelope message)
throws TransientPushFailureException
{
DeliveryStatus deliveryStatus = webSocketSender.sendMessage(account, device, message, WebsocketSender.Type.GCM);
if (!deliveryStatus.isDelivered()) {
GcmMessage gcmMessage = new GcmMessage(device.getGcmId(), account.getNumber(),
(int)device.getId(), "", false, true);
pushServiceClient.send(gcmMessage);
sendGcmNotification(account, device);
}
}
private void sendGcmNotification(Account account, Device device)
throws TransientPushFailureException
{
GcmMessage gcmMessage = new GcmMessage(device.getGcmId(), account.getNumber(),
(int)device.getId(), "", false, true);
pushServiceClient.send(gcmMessage);
}
private void sendApnMessage(Account account, Device device, Envelope outgoingMessage)
throws TransientPushFailureException
{
DeliveryStatus deliveryStatus = webSocketSender.sendMessage(account, device, outgoingMessage, WebsocketSender.Type.APN);
if (!deliveryStatus.isDelivered() && outgoingMessage.getType() != Envelope.Type.RECEIPT) {
ApnMessage apnMessage;
if (!Util.isEmpty(device.getVoipApnId())) {
apnMessage = new ApnMessage(device.getVoipApnId(), account.getNumber(), (int)device.getId(),
String.format(APN_PAYLOAD, deliveryStatus.getMessageQueueDepth()),
true, System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(30));
apnFallbackManager.schedule(new WebsocketAddress(account.getNumber(), device.getId()),
new ApnFallbackTask(device.getApnId(), apnMessage));
} else {
apnMessage = new ApnMessage(device.getApnId(), account.getNumber(), (int)device.getId(),
String.format(APN_PAYLOAD, deliveryStatus.getMessageQueueDepth()),
false, ApnMessage.MAX_EXPIRATION);
}
pushServiceClient.send(apnMessage);
sendApnNotification(account, device, deliveryStatus.getMessageQueueDepth());
}
}
private void sendApnNotification(Account account, Device device, int messageQueueDepth)
throws TransientPushFailureException
{
ApnMessage apnMessage;
if (!Util.isEmpty(device.getVoipApnId())) {
apnMessage = new ApnMessage(device.getVoipApnId(), account.getNumber(), (int)device.getId(),
String.format(APN_PAYLOAD, messageQueueDepth),
true, System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(30));
apnFallbackManager.schedule(new WebsocketAddress(account.getNumber(), device.getId()),
new ApnFallbackTask(device.getApnId(), apnMessage));
} else {
apnMessage = new ApnMessage(device.getApnId(), account.getNumber(), (int)device.getId(),
String.format(APN_PAYLOAD, messageQueueDepth),
false, ApnMessage.MAX_EXPIRATION);
}
pushServiceClient.send(apnMessage);
}
private void sendWebSocketMessage(Account account, Device device, Envelope outgoingMessage)
{
webSocketSender.sendMessage(account, device, outgoingMessage, WebsocketSender.Type.WEB);

View File

@@ -46,6 +46,7 @@ public class WebsocketSender {
private final MetricRegistry metricRegistry = SharedMetricRegistries.getOrCreate(Constants.METRICS_NAME);
private final Meter websocketRequeueMeter = metricRegistry.meter(name(getClass(), "ws_requeue"));
private final Meter websocketOnlineMeter = metricRegistry.meter(name(getClass(), "ws_online" ));
private final Meter websocketOfflineMeter = metricRegistry.meter(name(getClass(), "ws_offline" ));
@@ -84,15 +85,24 @@ public class WebsocketSender {
else if (channel == Type.GCM) gcmOfflineMeter.mark();
else websocketOfflineMeter.mark();
int queueDepth = messagesManager.insert(account.getNumber(), device.getId(), message);
pubSubManager.publish(address, PubSubMessage.newBuilder()
.setType(PubSubMessage.Type.QUERY_DB)
.build());
int queueDepth = queueMessage(account, device, message);
return new DeliveryStatus(false, queueDepth);
}
}
public int queueMessage(Account account, Device device, Envelope message) {
websocketRequeueMeter.mark();
WebsocketAddress address = new WebsocketAddress(account.getNumber(), device.getId());
int queueDepth = messagesManager.insert(account.getNumber(), device.getId(), message);
pubSubManager.publish(address, PubSubMessage.newBuilder()
.setType(PubSubMessage.Type.QUERY_DB)
.build());
return queueDepth;
}
public boolean sendProvisioningMessage(ProvisioningAddress address, byte[] body) {
PubSubMessage pubSubMessage = PubSubMessage.newBuilder()
.setType(PubSubMessage.Type.DELIVER)

View File

@@ -127,11 +127,12 @@ public class WebSocketConnection implements DispatchChannel {
}
private void requeueMessage(Envelope message) {
int queueDepth = pushSender.getWebSocketSender().queueMessage(account, device, message);
try {
pushSender.sendMessage(account, device, message);
pushSender.sendQueuedNotification(account, device, queueDepth);
} catch (NotPushRegisteredException | TransientPushFailureException e) {
logger.warn("requeueMessage", e);
messagesManager.insert(account.getNumber(), device.getId(), message);
}
}