Temporarily support `IncomingMessage.online` (#404)
iOS versions prior to 5.5.0.7 send `online` on `IncomingMessage`, rather than on the top-level entity. This adds a temporary server-side adaptation, to prevent client-side issues, like persistent typing indicators.
This commit is contained in:
parent
ec783133c1
commit
aa8525385a
|
@ -194,8 +194,17 @@ public class MessageController {
|
||||||
validateCompleteDeviceList(destination.get(), messages.getMessages(), isSyncMessage);
|
validateCompleteDeviceList(destination.get(), messages.getMessages(), isSyncMessage);
|
||||||
validateRegistrationIds(destination.get(), messages.getMessages());
|
validateRegistrationIds(destination.get(), messages.getMessages());
|
||||||
|
|
||||||
|
// iOS versions prior to 5.5.0.7 send `online` on IncomingMessageList.message, rather on the top-level entity.
|
||||||
|
// This causes some odd client behaviors, such as persisted typing indicators, so we have a temporary
|
||||||
|
// server-side adaptation.
|
||||||
|
final boolean online = messages.getMessages()
|
||||||
|
.stream()
|
||||||
|
.findFirst()
|
||||||
|
.map(IncomingMessage::isOnline)
|
||||||
|
.orElse(messages.isOnline());
|
||||||
|
|
||||||
final List<Tag> tags = List.of(UserAgentTagUtil.getPlatformTag(userAgent),
|
final List<Tag> tags = List.of(UserAgentTagUtil.getPlatformTag(userAgent),
|
||||||
Tag.of(EPHEMERAL_TAG_NAME, String.valueOf(messages.isOnline())),
|
Tag.of(EPHEMERAL_TAG_NAME, String.valueOf(online)),
|
||||||
Tag.of(SENDER_TYPE_TAG_NAME, senderType));
|
Tag.of(SENDER_TYPE_TAG_NAME, senderType));
|
||||||
|
|
||||||
for (IncomingMessage incomingMessage : messages.getMessages()) {
|
for (IncomingMessage incomingMessage : messages.getMessages()) {
|
||||||
|
@ -203,7 +212,7 @@ public class MessageController {
|
||||||
|
|
||||||
if (destinationDevice.isPresent()) {
|
if (destinationDevice.isPresent()) {
|
||||||
Metrics.counter(SENT_MESSAGE_COUNTER_NAME, tags).increment();
|
Metrics.counter(SENT_MESSAGE_COUNTER_NAME, tags).increment();
|
||||||
sendMessage(source, destination.get(), destinationDevice.get(), messages.getTimestamp(), messages.isOnline(), incomingMessage);
|
sendMessage(source, destination.get(), destinationDevice.get(), messages.getTimestamp(), online, incomingMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,9 @@ public class IncomingMessage {
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private long timestamp; // deprecated
|
private long timestamp; // deprecated
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private Boolean online; // use IncomingMessageList.online - this is a temporary adaptation for older clients
|
||||||
|
|
||||||
public String getDestination() {
|
public String getDestination() {
|
||||||
return destination;
|
return destination;
|
||||||
}
|
}
|
||||||
|
@ -60,4 +63,7 @@ public class IncomingMessage {
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean isOnline() {
|
||||||
|
return online;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import io.dropwizard.auth.PolymorphicAuthValueFactoryProvider;
|
import io.dropwizard.auth.PolymorphicAuthValueFactoryProvider;
|
||||||
import io.dropwizard.testing.junit.ResourceTestRule;
|
import io.dropwizard.testing.junit.ResourceTestRule;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -39,11 +40,14 @@ import java.util.concurrent.TimeUnit;
|
||||||
import javax.ws.rs.client.Entity;
|
import javax.ws.rs.client.Entity;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
import junitparams.JUnitParamsRunner;
|
||||||
|
import junitparams.Parameters;
|
||||||
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
|
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.ArgumentMatcher;
|
import org.mockito.ArgumentMatcher;
|
||||||
import org.whispersystems.textsecuregcm.auth.AmbiguousIdentifier;
|
import org.whispersystems.textsecuregcm.auth.AmbiguousIdentifier;
|
||||||
|
@ -71,6 +75,7 @@ import org.whispersystems.textsecuregcm.storage.MessagesManager;
|
||||||
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
||||||
import org.whispersystems.textsecuregcm.util.Base64;
|
import org.whispersystems.textsecuregcm.util.Base64;
|
||||||
|
|
||||||
|
@RunWith(JUnitParamsRunner.class)
|
||||||
public class MessageControllerTest {
|
public class MessageControllerTest {
|
||||||
|
|
||||||
private static final String SINGLE_DEVICE_RECIPIENT = "+14151111111";
|
private static final String SINGLE_DEVICE_RECIPIENT = "+14151111111";
|
||||||
|
@ -381,4 +386,34 @@ public class MessageControllerTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Parameters(method = "argumentsForTestOnlineMessage")
|
||||||
|
public void testOnlineMessage(final String fixture, final boolean expectedOnline) throws Exception {
|
||||||
|
|
||||||
|
final Response response =
|
||||||
|
resources.getJerseyTest()
|
||||||
|
.target(String.format("/v1/messages/%s", SINGLE_DEVICE_RECIPIENT))
|
||||||
|
.request()
|
||||||
|
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
|
||||||
|
.put(Entity.entity(mapper.readValue(jsonFixture(fixture), IncomingMessageList.class),
|
||||||
|
MediaType.APPLICATION_JSON_TYPE));
|
||||||
|
|
||||||
|
assertThat("Good Response", response.getStatus(), is(equalTo(200)));
|
||||||
|
|
||||||
|
verify(messageSender, times(1)).sendMessage(any(Account.class), any(Device.class), any(Envelope.class), eq(expectedOnline));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Object argumentsForTestOnlineMessage() {
|
||||||
|
return new Object[] {
|
||||||
|
new Object[] { "fixtures/current_message_single_device.json", false }, // default to `false` when absent
|
||||||
|
new Object[] { "fixtures/online_message_true.json", true },
|
||||||
|
new Object[] { "fixtures/online_message_false.json", false },
|
||||||
|
// iOS versions prior to 5.5.0.7 send `online` on IncomingMessageList.message, rather on the top-level entity.
|
||||||
|
// This causes some odd client behaviors, such as persisted typing indicators, so we have a temporary
|
||||||
|
// server-side adaptation.
|
||||||
|
new Object[] { "fixtures/online_message_true_nested_property.json", true },
|
||||||
|
new Object[] { "fixtures/online_message_false_nested_property.json", false },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"online": false,
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"type": 1,
|
||||||
|
"destinationDeviceId": 1,
|
||||||
|
"body": "Zm9vYmFyego",
|
||||||
|
"timestamp": 1234
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"type": 1,
|
||||||
|
"destinationDeviceId": 1,
|
||||||
|
"body": "Zm9vYmFyego",
|
||||||
|
"timestamp": 1234,
|
||||||
|
"online": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"online": true,
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"type": 1,
|
||||||
|
"destinationDeviceId": 1,
|
||||||
|
"body": "Zm9vYmFyego",
|
||||||
|
"timestamp": 1234
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"type": 1,
|
||||||
|
"destinationDeviceId": 1,
|
||||||
|
"body": "Zm9vYmFyego",
|
||||||
|
"timestamp": 1234,
|
||||||
|
"online": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in New Issue