Fall back straight to APN.

// FREEBIE
This commit is contained in:
Moxie Marlinspike 2015-05-27 16:19:56 -07:00
parent 4cb43415a1
commit 6ad705b40e
4 changed files with 19 additions and 65 deletions

View File

@ -55,4 +55,9 @@ public class ApnMessage {
public boolean isVoip() { public boolean isVoip() {
return voip; return voip;
} }
@VisibleForTesting
public String getMessage() {
return message;
}
} }

View File

@ -30,13 +30,8 @@ public class ApnFallbackManager implements Managed, Runnable {
private static final Meter voipOneDelivery = metricRegistry.meter(name(ApnFallbackManager.class, "voip_one_failure")); private static final Meter voipOneDelivery = metricRegistry.meter(name(ApnFallbackManager.class, "voip_one_failure"));
private static final Histogram voipOneSuccessHistogram = metricRegistry.histogram(name(ApnFallbackManager.class, "voip_one_success_histogram")); private static final Histogram voipOneSuccessHistogram = metricRegistry.histogram(name(ApnFallbackManager.class, "voip_one_success_histogram"));
private static final Meter voipTwoSuccess = metricRegistry.meter(name(ApnFallbackManager.class, "voip_two_success"));
private static final Meter voipTwoDelivery = metricRegistry.meter(name(ApnFallbackManager.class, "voip_two_failure"));
private static final Histogram voipTwoSuccessHistogram = metricRegistry.histogram(name(ApnFallbackManager.class, "voip_two_success_histogram"));
static { static {
metricRegistry.register(name(ApnFallbackManager.class, "voip_one_success_ratio"), new VoipRatioGauge(voipOneSuccess, voipOneDelivery)); metricRegistry.register(name(ApnFallbackManager.class, "voip_one_success_ratio"), new VoipRatioGauge(voipOneSuccess, voipOneDelivery));
metricRegistry.register(name(ApnFallbackManager.class, "voip_two_success_ratio"), new VoipRatioGauge(voipTwoSuccess, voipTwoDelivery));
} }
private final ApnFallbackTaskQueue taskQueue = new ApnFallbackTaskQueue(); private final ApnFallbackTaskQueue taskQueue = new ApnFallbackTaskQueue();
@ -47,9 +42,7 @@ public class ApnFallbackManager implements Managed, Runnable {
} }
public void schedule(final WebsocketAddress address, ApnFallbackTask task) { public void schedule(final WebsocketAddress address, ApnFallbackTask task) {
if (task.getRetryCount() == 0) voipOneDelivery.mark(); voipOneDelivery.mark();
else if (task.getRetryCount() == 1) voipTwoDelivery.mark();
taskQueue.put(address, task); taskQueue.put(address, task);
} }
@ -57,13 +50,8 @@ public class ApnFallbackManager implements Managed, Runnable {
ApnFallbackTask task = taskQueue.remove(address); ApnFallbackTask task = taskQueue.remove(address);
if (task != null) { if (task != null) {
if (task.getRetryCount() == 0) {
voipOneSuccess.mark(); voipOneSuccess.mark();
voipOneSuccessHistogram.update(System.currentTimeMillis() - task.getScheduledTime()); voipOneSuccessHistogram.update(System.currentTimeMillis() - task.getScheduledTime());
} else if (task.getRetryCount() == 1) {
voipTwoSuccess.mark();
voipTwoSuccessHistogram.update(System.currentTimeMillis() - task.getScheduledTime());
}
} }
} }
@ -83,15 +71,7 @@ public class ApnFallbackManager implements Managed, Runnable {
try { try {
Entry<WebsocketAddress, ApnFallbackTask> taskEntry = taskQueue.get(); Entry<WebsocketAddress, ApnFallbackTask> taskEntry = taskQueue.get();
ApnFallbackTask task = taskEntry.getValue(); ApnFallbackTask task = taskEntry.getValue();
int retryCount = task.getRetryCount();
if (retryCount == 0) {
pushServiceClient.send(task.getMessage());
schedule(taskEntry.getKey(), new ApnFallbackTask(task.getApnId(), task.getMessage(),
retryCount + 1, task.getDelay()));
} else if (retryCount == 1) {
pushServiceClient.send(new ApnMessage(task.getMessage(), task.getApnId(), false)); pushServiceClient.send(new ApnMessage(task.getMessage(), task.getApnId(), false));
}
} catch (Throwable e) { } catch (Throwable e) {
logger.warn("ApnFallbackThread", e); logger.warn("ApnFallbackThread", e);
} }
@ -104,19 +84,17 @@ public class ApnFallbackManager implements Managed, Runnable {
private final long scheduledTime; private final long scheduledTime;
private final String apnId; private final String apnId;
private final ApnMessage message; private final ApnMessage message;
private final int retryCount;
public ApnFallbackTask(String apnId, ApnMessage message, int retryCount) { public ApnFallbackTask(String apnId, ApnMessage message) {
this(apnId, message, retryCount, TimeUnit.SECONDS.toMillis(15)); this(apnId, message, TimeUnit.SECONDS.toMillis(15));
} }
@VisibleForTesting @VisibleForTesting
public ApnFallbackTask(String apnId, ApnMessage message, int retryCount, long delay) { public ApnFallbackTask(String apnId, ApnMessage message, long delay) {
this.scheduledTime = System.currentTimeMillis(); this.scheduledTime = System.currentTimeMillis();
this.delay = delay; this.delay = delay;
this.apnId = apnId; this.apnId = apnId;
this.message = message; this.message = message;
this.retryCount = retryCount;
} }
public String getApnId() { public String getApnId() {
@ -127,10 +105,6 @@ public class ApnFallbackManager implements Managed, Runnable {
return message; return message;
} }
public int getRetryCount() {
return retryCount;
}
public long getScheduledTime() { public long getScheduledTime() {
return scheduledTime; return scheduledTime;
} }

View File

@ -116,7 +116,7 @@ public class PushSender {
if (isVoip) { if (isVoip) {
apnFallbackManager.schedule(new WebsocketAddress(account.getNumber(), device.getId()), apnFallbackManager.schedule(new WebsocketAddress(account.getNumber(), device.getId()),
new ApnFallbackTask(device.getApnId(), apnMessage, 0)); new ApnFallbackTask(device.getApnId(), apnMessage));
} }
pushServiceClient.send(apnMessage); pushServiceClient.send(apnMessage);

View File

@ -9,11 +9,8 @@ import org.whispersystems.textsecuregcm.push.PushServiceClient;
import org.whispersystems.textsecuregcm.util.Util; import org.whispersystems.textsecuregcm.util.Util;
import org.whispersystems.textsecuregcm.websocket.WebsocketAddress; import org.whispersystems.textsecuregcm.websocket.WebsocketAddress;
import java.util.List;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
public class ApnFallbackManagerTest { public class ApnFallbackManagerTest {
@ -23,7 +20,7 @@ public class ApnFallbackManagerTest {
PushServiceClient pushServiceClient = mock(PushServiceClient.class); PushServiceClient pushServiceClient = mock(PushServiceClient.class);
WebsocketAddress address = mock(WebsocketAddress.class ); WebsocketAddress address = mock(WebsocketAddress.class );
ApnMessage message = new ApnMessage("bar", "123", 1, "hmm", true); ApnMessage message = new ApnMessage("bar", "123", 1, "hmm", true);
ApnFallbackTask task = new ApnFallbackTask("foo", message, 0, 500); ApnFallbackTask task = new ApnFallbackTask("foo", message, 500);
ApnFallbackManager apnFallbackManager = new ApnFallbackManager(pushServiceClient); ApnFallbackManager apnFallbackManager = new ApnFallbackManager(pushServiceClient);
apnFallbackManager.start(); apnFallbackManager.start();
@ -33,33 +30,11 @@ public class ApnFallbackManagerTest {
Util.sleep(1100); Util.sleep(1100);
ArgumentCaptor<ApnMessage> captor = ArgumentCaptor.forClass(ApnMessage.class); ArgumentCaptor<ApnMessage> captor = ArgumentCaptor.forClass(ApnMessage.class);
verify(pushServiceClient, times(2)).send(captor.capture()); verify(pushServiceClient, times(1)).send(captor.capture());
List<ApnMessage> messages = captor.getAllValues(); assertEquals(captor.getValue().getMessage(), message.getMessage());
assertEquals(messages.get(0), message); assertEquals(captor.getValue().getApnId(), task.getApnId());
assertEquals(messages.get(1).getApnId(), task.getApnId()); assertFalse(captor.getValue().isVoip());
assertFalse(messages.get(1).isVoip());
}
@Test
public void testPartialFallback() throws Exception {
PushServiceClient pushServiceClient = mock(PushServiceClient.class);
WebsocketAddress address = mock(WebsocketAddress.class );
ApnMessage message = new ApnMessage("bar", "123", 1, "hmm", true);
ApnFallbackTask task = new ApnFallbackTask ("foo", message, 0, 500);
ApnFallbackManager apnFallbackManager = new ApnFallbackManager(pushServiceClient);
apnFallbackManager.start();
apnFallbackManager.schedule(address, task);
Util.sleep(600);
apnFallbackManager.cancel(address);
Util.sleep(600);
verify(pushServiceClient, times(1)).send(eq(message));
} }
@Test @Test
@ -67,7 +42,7 @@ public class ApnFallbackManagerTest {
PushServiceClient pushServiceClient = mock(PushServiceClient.class); PushServiceClient pushServiceClient = mock(PushServiceClient.class);
WebsocketAddress address = mock(WebsocketAddress.class ); WebsocketAddress address = mock(WebsocketAddress.class );
ApnMessage message = new ApnMessage("bar", "123", 1, "hmm", true); ApnMessage message = new ApnMessage("bar", "123", 1, "hmm", true);
ApnFallbackTask task = new ApnFallbackTask ("foo", message, 0, 500); ApnFallbackTask task = new ApnFallbackTask ("foo", message, 500);
ApnFallbackManager apnFallbackManager = new ApnFallbackManager(pushServiceClient); ApnFallbackManager apnFallbackManager = new ApnFallbackManager(pushServiceClient);
apnFallbackManager.start(); apnFallbackManager.start();