parent
1fef812c67
commit
aa84ab66af
2
pom.xml
2
pom.xml
|
@ -129,7 +129,7 @@
|
|||
<dependency>
|
||||
<groupId>org.whispersystems</groupId>
|
||||
<artifactId>websocket-resources</artifactId>
|
||||
<version>0.2.0</version>
|
||||
<version>0.2.1</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
|
|
@ -197,10 +197,14 @@ public class AccountController {
|
|||
@PUT
|
||||
@Path("/gcm/")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void setGcmRegistrationId(@Auth Account account, @Valid GcmRegistrationId registrationId) {
|
||||
public void setGcmRegistrationId(@Auth Account account, @Valid GcmRegistrationId registrationId) {
|
||||
Device device = account.getAuthenticatedDevice().get();
|
||||
device.setApnId(null);
|
||||
device.setGcmId(registrationId.getGcmRegistrationId());
|
||||
|
||||
if (registrationId.isWebSocketChannel()) device.setFetchesMessages(true);
|
||||
else device.setFetchesMessages(false);
|
||||
|
||||
accounts.update(account);
|
||||
}
|
||||
|
||||
|
@ -210,6 +214,7 @@ public class AccountController {
|
|||
public void deleteGcmRegistrationId(@Auth Account account) {
|
||||
Device device = account.getAuthenticatedDevice().get();
|
||||
device.setGcmId(null);
|
||||
device.setFetchesMessages(false);
|
||||
accounts.update(account);
|
||||
}
|
||||
|
||||
|
@ -221,6 +226,7 @@ public class AccountController {
|
|||
Device device = account.getAuthenticatedDevice().get();
|
||||
device.setApnId(registrationId.getApnRegistrationId());
|
||||
device.setGcmId(null);
|
||||
device.setFetchesMessages(true);
|
||||
accounts.update(account);
|
||||
}
|
||||
|
||||
|
@ -230,6 +236,25 @@ public class AccountController {
|
|||
public void deleteApnRegistrationId(@Auth Account account) {
|
||||
Device device = account.getAuthenticatedDevice().get();
|
||||
device.setApnId(null);
|
||||
device.setFetchesMessages(false);
|
||||
accounts.update(account);
|
||||
}
|
||||
|
||||
@Timed
|
||||
@PUT
|
||||
@Path("/wsc/")
|
||||
public void setWebSocketChannelSupported(@Auth Account account) {
|
||||
Device device = account.getAuthenticatedDevice().get();
|
||||
device.setFetchesMessages(true);
|
||||
accounts.update(account);
|
||||
}
|
||||
|
||||
@Timed
|
||||
@DELETE
|
||||
@Path("/wsc/")
|
||||
public void deleteWebSocketChannel(@Auth Account account) {
|
||||
Device device = account.getAuthenticatedDevice().get();
|
||||
device.setFetchesMessages(false);
|
||||
accounts.update(account);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,20 +20,23 @@ public class GcmMessage {
|
|||
private int deviceId;
|
||||
|
||||
@JsonProperty
|
||||
@NotEmpty
|
||||
private String message;
|
||||
|
||||
@JsonProperty
|
||||
private boolean receipt;
|
||||
|
||||
@JsonProperty
|
||||
private boolean notification;
|
||||
|
||||
public GcmMessage() {}
|
||||
|
||||
public GcmMessage(String gcmId, String number, int deviceId, String message, boolean receipt) {
|
||||
this.gcmId = gcmId;
|
||||
this.number = number;
|
||||
this.deviceId = deviceId;
|
||||
this.message = message;
|
||||
this.receipt = receipt;
|
||||
public GcmMessage(String gcmId, String number, int deviceId, String message, boolean receipt, boolean notification) {
|
||||
this.gcmId = gcmId;
|
||||
this.number = number;
|
||||
this.deviceId = deviceId;
|
||||
this.message = message;
|
||||
this.receipt = receipt;
|
||||
this.notification = notification;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -25,9 +25,15 @@ public class GcmRegistrationId {
|
|||
@NotEmpty
|
||||
private String gcmRegistrationId;
|
||||
|
||||
@JsonProperty
|
||||
private boolean webSocketChannel;
|
||||
|
||||
public String getGcmRegistrationId() {
|
||||
return gcmRegistrationId;
|
||||
}
|
||||
|
||||
public boolean isWebSocketChannel() {
|
||||
return webSocketChannel;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -57,6 +57,13 @@ public class PushSender {
|
|||
|
||||
private void sendGcmMessage(Account account, Device device, OutgoingMessageSignal message)
|
||||
throws TransientPushFailureException, NotPushRegisteredException
|
||||
{
|
||||
if (device.getFetchesMessages()) sendNotificationGcmMessage(account, device, message);
|
||||
else sendPayloadGcmMessage(account, device, message);
|
||||
}
|
||||
|
||||
private void sendPayloadGcmMessage(Account account, Device device, OutgoingMessageSignal message)
|
||||
throws TransientPushFailureException, NotPushRegisteredException
|
||||
{
|
||||
try {
|
||||
String number = account.getNumber();
|
||||
|
@ -65,7 +72,7 @@ public class PushSender {
|
|||
boolean isReceipt = message.getType() == OutgoingMessageSignal.Type.RECEIPT_VALUE;
|
||||
EncryptedOutgoingMessage encryptedMessage = new EncryptedOutgoingMessage(message, device.getSignalingKey());
|
||||
GcmMessage gcmMessage = new GcmMessage(registrationId, number, (int) deviceId,
|
||||
encryptedMessage.toEncodedString(), isReceipt);
|
||||
encryptedMessage.toEncodedString(), isReceipt, false);
|
||||
|
||||
pushServiceClient.send(gcmMessage);
|
||||
} catch (CryptoEncodingException e) {
|
||||
|
@ -73,10 +80,26 @@ public class PushSender {
|
|||
}
|
||||
}
|
||||
|
||||
private void sendNotificationGcmMessage(Account account, Device device, OutgoingMessageSignal 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);
|
||||
} else {
|
||||
logger.warn("Delivered!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void sendApnMessage(Account account, Device device, OutgoingMessageSignal outgoingMessage)
|
||||
throws TransientPushFailureException
|
||||
{
|
||||
DeliveryStatus deliveryStatus = webSocketSender.sendMessage(account, device, outgoingMessage, true);
|
||||
DeliveryStatus deliveryStatus = webSocketSender.sendMessage(account, device, outgoingMessage, WebsocketSender.Type.APN);
|
||||
|
||||
if (!deliveryStatus.isDelivered() && outgoingMessage.getType() != OutgoingMessageSignal.Type.RECEIPT_VALUE) {
|
||||
ApnMessage apnMessage = new ApnMessage(device.getApnId(), account.getNumber(), (int)device.getId(),
|
||||
|
@ -87,6 +110,6 @@ public class PushSender {
|
|||
|
||||
private void sendWebSocketMessage(Account account, Device device, OutgoingMessageSignal outgoingMessage)
|
||||
{
|
||||
webSocketSender.sendMessage(account, device, outgoingMessage, false);
|
||||
webSocketSender.sendMessage(account, device, outgoingMessage, WebsocketSender.Type.WEB);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,12 @@ import static org.whispersystems.textsecuregcm.storage.PubSubProtos.PubSubMessag
|
|||
|
||||
public class WebsocketSender {
|
||||
|
||||
public static enum Type {
|
||||
APN,
|
||||
GCM,
|
||||
WEB
|
||||
}
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(WebsocketSender.class);
|
||||
|
||||
private final MetricRegistry metricRegistry = SharedMetricRegistries.getOrCreate(Constants.METRICS_NAME);
|
||||
|
@ -46,6 +52,9 @@ public class WebsocketSender {
|
|||
private final Meter apnOnlineMeter = metricRegistry.meter(name(getClass(), "apn_online" ));
|
||||
private final Meter apnOfflineMeter = metricRegistry.meter(name(getClass(), "apn_offline"));
|
||||
|
||||
private final Meter gcmOnlineMeter = metricRegistry.meter(name(getClass(), "gcm_online" ));
|
||||
private final Meter gcmOfflineMeter = metricRegistry.meter(name(getClass(), "gcm_offline"));
|
||||
|
||||
private final Meter provisioningOnlineMeter = metricRegistry.meter(name(getClass(), "provisioning_online" ));
|
||||
private final Meter provisioningOfflineMeter = metricRegistry.meter(name(getClass(), "provisioning_offline"));
|
||||
|
||||
|
@ -57,7 +66,7 @@ public class WebsocketSender {
|
|||
this.pubSubManager = pubSubManager;
|
||||
}
|
||||
|
||||
public DeliveryStatus sendMessage(Account account, Device device, OutgoingMessageSignal message, boolean apn) {
|
||||
public DeliveryStatus sendMessage(Account account, Device device, OutgoingMessageSignal message, Type channel) {
|
||||
WebsocketAddress address = new WebsocketAddress(account.getNumber(), device.getId());
|
||||
PubSubMessage pubSubMessage = PubSubMessage.newBuilder()
|
||||
.setType(PubSubMessage.Type.DELIVER)
|
||||
|
@ -65,13 +74,15 @@ public class WebsocketSender {
|
|||
.build();
|
||||
|
||||
if (pubSubManager.publish(address, pubSubMessage)) {
|
||||
if (apn) apnOnlineMeter.mark();
|
||||
else websocketOnlineMeter.mark();
|
||||
if (channel == Type.APN) apnOnlineMeter.mark();
|
||||
else if (channel == Type.GCM) gcmOnlineMeter.mark();
|
||||
else websocketOnlineMeter.mark();
|
||||
|
||||
return new DeliveryStatus(true, 0);
|
||||
} else {
|
||||
if (apn) apnOfflineMeter.mark();
|
||||
else websocketOfflineMeter.mark();
|
||||
if (channel == Type.APN) apnOfflineMeter.mark();
|
||||
else if (channel == Type.GCM) gcmOfflineMeter.mark();
|
||||
else websocketOfflineMeter.mark();
|
||||
|
||||
int queueDepth = messagesManager.insert(account.getNumber(), device.getId(), message);
|
||||
pubSubManager.publish(address, PubSubMessage.newBuilder()
|
||||
|
|
|
@ -33,30 +33,17 @@ public class AuthenticatedConnectListener implements WebSocketConnectListener {
|
|||
|
||||
@Override
|
||||
public void onWebSocketConnect(WebSocketSessionContext context) {
|
||||
Optional<Account> account = context.getAuthenticated(Account.class);
|
||||
Account account = context.getAuthenticated(Account.class).get();
|
||||
Device device = account.getAuthenticatedDevice().get();
|
||||
|
||||
if (!account.isPresent()) {
|
||||
logger.debug("WS Connection with no authentication...");
|
||||
context.getClient().close(4001, "Authentication failed");
|
||||
return;
|
||||
}
|
||||
|
||||
Optional<Device> device = account.get().getAuthenticatedDevice();
|
||||
|
||||
if (!device.isPresent()) {
|
||||
logger.debug("WS Connection with no authenticated device...");
|
||||
context.getClient().close(4001, "Device authentication failed");
|
||||
return;
|
||||
}
|
||||
|
||||
if (device.get().getLastSeen() != Util.todayInMillis()) {
|
||||
device.get().setLastSeen(Util.todayInMillis());
|
||||
accountsManager.update(account.get());
|
||||
if (device.getLastSeen() != Util.todayInMillis()) {
|
||||
device.setLastSeen(Util.todayInMillis());
|
||||
accountsManager.update(account);
|
||||
}
|
||||
|
||||
final WebSocketConnection connection = new WebSocketConnection(accountsManager, pushSender,
|
||||
messagesManager, pubSubManager,
|
||||
account.get(), device.get(),
|
||||
account, device,
|
||||
context.getClient());
|
||||
|
||||
connection.onConnected();
|
||||
|
|
|
@ -34,7 +34,9 @@ public class WebSocketAccountAuthenticator implements WebSocketAuthenticator<Acc
|
|||
return Optional.absent();
|
||||
}
|
||||
|
||||
BasicCredentials credentials = new BasicCredentials(usernames[0], passwords[0]);
|
||||
BasicCredentials credentials = new BasicCredentials(usernames[0].replace(" ", "+"),
|
||||
passwords[0].replace(" ", "+"));
|
||||
|
||||
return accountAuthenticator.authenticate(credentials);
|
||||
} catch (io.dropwizard.auth.AuthenticationException e) {
|
||||
throw new AuthenticationException(e);
|
||||
|
|
|
@ -32,6 +32,7 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
|
||||
import io.dropwizard.auth.basic.BasicCredentials;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
@ -101,15 +102,16 @@ public class WebSocketConnectionTest {
|
|||
}});
|
||||
|
||||
account = webSocketAuthenticator.authenticate(upgradeRequest);
|
||||
when(sessionContext.getAuthenticated(Account.class)).thenReturn(account);
|
||||
|
||||
WebSocketClient client = mock(WebSocketClient.class);
|
||||
when(sessionContext.getClient()).thenReturn(client);
|
||||
|
||||
connectListener.onWebSocketConnect(sessionContext);
|
||||
|
||||
verify(sessionContext, times(1)).addListener(any(WebSocketSessionContext.WebSocketEventListener.class));
|
||||
verify(client).close(eq(4001), anyString());
|
||||
assertFalse(account.isPresent());
|
||||
// when(sessionContext.getAuthenticated(Account.class)).thenReturn(account);
|
||||
//
|
||||
// WebSocketClient client = mock(WebSocketClient.class);
|
||||
// when(sessionContext.getClient()).thenReturn(client);
|
||||
//
|
||||
// connectListener.onWebSocketConnect(sessionContext);
|
||||
//
|
||||
// verify(sessionContext, times(1)).addListener(any(WebSocketSessionContext.WebSocketEventListener.class));
|
||||
// verify(client).close(eq(4001), anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in New Issue