use of org.whispersystems.signalservice.internal.websocket.WebSocketProtos.WebSocketRequestMessage in project libsignal-service-java by signalapp.
the class SignalServiceMessagePipe method read.
/**
* A blocking call that reads a message off the pipe (see {@link #read(long, java.util.concurrent.TimeUnit)}
*
* Unlike {@link #read(long, java.util.concurrent.TimeUnit)}, this method allows you
* to specify a callback that will be called before the received message is acknowledged.
* This allows you to write the received message to durable storage before acknowledging
* receipt of it to the server.
*
* @param timeout The timeout to wait for.
* @param unit The timeout time unit.
* @param callback A callback that will be called before the message receipt is
* acknowledged to the server.
* @return The message read (same as the message sent through the callback).
* @throws TimeoutException
* @throws IOException
* @throws InvalidVersionException
*/
public SignalServiceEnvelope read(long timeout, TimeUnit unit, MessagePipeCallback callback) throws TimeoutException, IOException, InvalidVersionException {
while (true) {
WebSocketRequestMessage request = websocket.readRequest(unit.toMillis(timeout));
WebSocketResponseMessage response = createWebSocketResponse(request);
try {
if (isSignalServiceEnvelope(request)) {
SignalServiceEnvelope envelope = new SignalServiceEnvelope(request.getBody().toByteArray(), credentialsProvider.getSignalingKey());
callback.onMessage(envelope);
return envelope;
}
} finally {
websocket.sendResponse(response);
}
}
}
use of org.whispersystems.signalservice.internal.websocket.WebSocketProtos.WebSocketRequestMessage in project libsignal-service-java by signalapp.
the class SignalServiceMessagePipe method send.
public SendMessageResponse send(OutgoingPushMessageList list) throws IOException {
try {
WebSocketRequestMessage requestMessage = WebSocketRequestMessage.newBuilder().setId(SecureRandom.getInstance("SHA1PRNG").nextLong()).setVerb("PUT").setPath(String.format("/v1/messages/%s", list.getDestination())).addHeaders("content-type:application/json").setBody(ByteString.copyFrom(JsonUtil.toJson(list).getBytes())).build();
Pair<Integer, String> response = websocket.sendRequest(requestMessage).get(10, TimeUnit.SECONDS);
if (response.first() < 200 || response.first() >= 300) {
throw new IOException("Non-successful response: " + response.first());
}
if (Util.isEmpty(response.second()))
return new SendMessageResponse(false);
else
return JsonUtil.fromJson(response.second(), SendMessageResponse.class);
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
throw new IOException(e);
}
}
use of org.whispersystems.signalservice.internal.websocket.WebSocketProtos.WebSocketRequestMessage in project libsignal-service-java by signalapp.
the class SignalServiceMessagePipe method getProfile.
public SignalServiceProfile getProfile(SignalServiceAddress address) throws IOException {
try {
WebSocketRequestMessage requestMessage = WebSocketRequestMessage.newBuilder().setId(SecureRandom.getInstance("SHA1PRNG").nextLong()).setVerb("GET").setPath(String.format("/v1/profile/%s", address.getNumber())).build();
Pair<Integer, String> response = websocket.sendRequest(requestMessage).get(10, TimeUnit.SECONDS);
if (response.first() < 200 || response.first() >= 300) {
throw new IOException("Non-successful response: " + response.first());
}
return JsonUtil.fromJson(response.second(), SignalServiceProfile.class);
} catch (NoSuchAlgorithmException nsae) {
throw new AssertionError(nsae);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
throw new IOException(e);
}
}
use of org.whispersystems.signalservice.internal.websocket.WebSocketProtos.WebSocketRequestMessage in project Signal-Android by WhisperSystems.
the class SignalWebSocket method readOrEmpty.
/**
* <p>
* A blocking call that reads a message off the pipe. When this call returns, the message has been
* acknowledged and will not be retransmitted. This will return {@link Optional#absent()} when an
* empty response is hit, which indicates the WebSocket is empty.
* <p>
* You can specify a {@link MessageReceivedCallback} that will be called before the received message is acknowledged.
* This allows you to write the received message to durable storage before acknowledging receipt of it to the
* server.
* <p>
* Important: The empty response will only be hit once for each connection. That means if you get
* an empty response and call readOrEmpty() again on the same instance, you will not get an empty
* response, and instead will block until you get an actual message. This will, however, reset if
* connection breaks (if, for instance, you lose and regain network).
*
* @param timeout The timeout to wait for.
* @param callback A callback that will be called before the message receipt is acknowledged to the server.
* @return The message read (same as the message sent through the callback).
*/
@SuppressWarnings("DuplicateThrows")
public Optional<SignalServiceEnvelope> readOrEmpty(long timeout, MessageReceivedCallback callback) throws TimeoutException, WebSocketUnavailableException, IOException {
while (true) {
WebSocketRequestMessage request = getWebSocket().readRequest(timeout);
WebSocketResponseMessage response = createWebSocketResponse(request);
try {
if (isSignalServiceEnvelope(request)) {
Optional<String> timestampHeader = findHeader(request);
long timestamp = 0;
if (timestampHeader.isPresent()) {
try {
timestamp = Long.parseLong(timestampHeader.get());
} catch (NumberFormatException e) {
Log.w(TAG, "Failed to parse " + SERVER_DELIVERED_TIMESTAMP_HEADER);
}
}
SignalServiceEnvelope envelope = new SignalServiceEnvelope(request.getBody().toByteArray(), timestamp);
callback.onMessage(envelope);
return Optional.of(envelope);
} else if (isSocketEmptyRequest(request)) {
return Optional.absent();
}
} finally {
getWebSocket().sendResponse(response);
}
}
}
use of org.whispersystems.signalservice.internal.websocket.WebSocketProtos.WebSocketRequestMessage in project Signal-Android by WhisperSystems.
the class MessagingService method sendToGroup.
public Single<ServiceResponse<SendGroupMessageResponse>> sendToGroup(byte[] body, byte[] joinedUnidentifiedAccess, long timestamp, boolean online) {
List<String> headers = new LinkedList<String>() {
{
add("content-type:application/vnd.signal-messenger.mrm");
add("Unidentified-Access-Key:" + Base64.encodeBytes(joinedUnidentifiedAccess));
}
};
String path = String.format(Locale.US, "/v1/messages/multi_recipient?ts=%s&online=%s", timestamp, online);
WebSocketRequestMessage requestMessage = WebSocketRequestMessage.newBuilder().setId(new SecureRandom().nextLong()).setVerb("PUT").setPath(path).addAllHeaders(headers).setBody(ByteString.copyFrom(body)).build();
return signalWebSocket.request(requestMessage).map(DefaultResponseMapper.extend(SendGroupMessageResponse.class).withCustomError(401, (status, errorBody, getHeader) -> new InvalidUnidentifiedAccessHeaderException()).withCustomError(404, (status, errorBody, getHeader) -> new NotFoundException("At least one unregistered user in message send.")).withCustomError(409, (status, errorBody, getHeader) -> {
GroupMismatchedDevices[] mismatchedDevices = JsonUtil.fromJsonResponse(errorBody, GroupMismatchedDevices[].class);
return new GroupMismatchedDevicesException(mismatchedDevices);
}).withCustomError(410, (status, errorBody, getHeader) -> {
GroupStaleDevices[] staleDevices = JsonUtil.fromJsonResponse(errorBody, GroupStaleDevices[].class);
return new GroupStaleDevicesException(staleDevices);
}).build()::map).onErrorReturn(ServiceResponse::forUnknownError);
}
Aggregations