use of io.smallrye.graphql.client.InvalidResponseException in project smallrye-graphql by smallrye.
the class GraphQLTransportWSSubprotocolHandler method initialize.
private Uni<Void> initialize() {
return Uni.createFrom().emitter(initializationEmitter -> {
if (log.isTraceEnabled()) {
log.trace("Initializing websocket with graphql-transport-ws protocol");
}
connectionInitMessage = Json.createObjectBuilder().add("type", "connection_init").build();
pongMessage = Json.createObjectBuilder().add("type", "pong").add("payload", Json.createObjectBuilder().add("message", "keepalive")).build();
webSocket.closeHandler((v) -> {
onClose.run();
if (webSocket.closeStatusCode() != null) {
if (webSocket.closeStatusCode() == 1000) {
log.debug("WebSocket closed with status code 1000");
// even if the status code is OK, any unfinished single-result operation
// should be marked as failed
uniOperations.forEach((id, emitter) -> emitter.fail(new InvalidResponseException("Connection closed before data was received")));
multiOperations.forEach((id, emitter) -> emitter.complete());
} else {
InvalidResponseException exception = new InvalidResponseException("Server closed the websocket connection with code: " + webSocket.closeStatusCode() + " and reason: " + webSocket.closeReason());
uniOperations.forEach((id, emitter) -> emitter.fail(exception));
multiOperations.forEach((id, emitter) -> emitter.fail(exception));
}
} else {
InvalidResponseException exception = new InvalidResponseException("Connection closed");
uniOperations.forEach((id, emitter) -> emitter.fail(exception));
multiOperations.forEach((id, emitter) -> emitter.fail(exception));
}
});
webSocket.exceptionHandler(this::failAllActiveOperationsWith);
send(webSocket, connectionInitMessage);
// set up a timeout for subscription initialization
Cancellable timeoutWaitingForConnectionAckMessage = null;
if (connectionInitializationTimeout != null) {
timeoutWaitingForConnectionAckMessage = Uni.createFrom().item(1).onItem().delayIt().by(Duration.ofMillis(connectionInitializationTimeout)).subscribe().with(timeout -> {
initializationEmitter.fail(new InvalidResponseException("Server did not send a connection_ack message"));
webSocket.close((short) 1002, "Timeout waiting for a connection_ack message");
});
}
// make an effectively final copy of this value to use it in a lambda expression
Cancellable finalTimeoutWaitingForConnectionAckMessage = timeoutWaitingForConnectionAckMessage;
webSocket.handler(text -> {
if (log.isTraceEnabled()) {
log.trace("<<< " + text);
}
try {
JsonObject message = parseIncomingMessage(text.toString());
MessageType messageType = getMessageType(message);
switch(messageType) {
case PING:
send(webSocket, pongMessage);
break;
case CONNECTION_ACK:
// TODO: somehow protect against this being invoked multiple times?
if (finalTimeoutWaitingForConnectionAckMessage != null) {
finalTimeoutWaitingForConnectionAckMessage.cancel();
}
initializationEmitter.complete(null);
break;
case NEXT:
handleData(message.getString("id"), message.getJsonObject("payload"));
break;
case ERROR:
handleOperationError(message.getString("id"), message.getJsonArray("payload"));
break;
case COMPLETE:
handleComplete(message.getString("id"));
break;
case CONNECTION_INIT:
case PONG:
case SUBSCRIBE:
break;
}
} catch (JsonParsingException | IllegalArgumentException e) {
log.error("Unexpected message from server: " + text);
// should we fail the operations here?
}
});
});
}
use of io.smallrye.graphql.client.InvalidResponseException in project smallrye-graphql by smallrye.
the class GraphQLWSSubprotocolHandler method handleComplete.
private void handleComplete(String operationId) {
UniEmitter<? super String> emitter = uniOperations.remove(operationId);
if (emitter != null) {
// For a uni operation, we should have received a 'next' message before the 'complete' message.
// If that happened, the emitter was already completed and operation removed from the map.
// If that didn't happen, then this is an issue with the server, let's fail the operation then.
emitter.fail(new InvalidResponseException("Protocol error: received a 'complete' message for" + " this operation before the actual data"));
} else {
MultiEmitter<? super String> multiEmitter = multiOperations.remove(operationId);
if (multiEmitter != null) {
log.debug("Completed operation " + operationId);
multiEmitter.complete();
}
}
}
use of io.smallrye.graphql.client.InvalidResponseException in project smallrye-graphql by smallrye.
the class JsonStringReader method formattedNumber.
private Number formattedNumber(String input) {
String locale = null;
String format = null;
JsonbNumberFormat jsonbNumberFormat = field.getAnnotation(JsonbNumberFormat.class);
if (jsonbNumberFormat != null) {
locale = jsonbNumberFormat.locale();
format = jsonbNumberFormat.value();
}
NumberFormat numberFormat = field.getAnnotation(NumberFormat.class);
if (numberFormat != null) {
locale = numberFormat.locale();
format = numberFormat.value();
}
java.text.NumberFormat nf;
if (format != null && !format.isEmpty()) {
nf = new DecimalFormat(format);
} else if (locale != null && !locale.isEmpty()) {
nf = java.text.NumberFormat.getInstance(Locale.forLanguageTag(locale));
} else {
nf = new DecimalFormat();
}
try {
return nf.parse(input);
} catch (ParseException e) {
throw new InvalidResponseException("Can't parse number", e);
}
}
use of io.smallrye.graphql.client.InvalidResponseException in project smallrye-graphql by smallrye.
the class NestedBehavior method shouldFailToCallWrappedInvalidByteQuery.
@Test
void shouldFailToCallWrappedInvalidByteQuery() {
fixture.returnsData("'container':{'code':{'value':1000},'count':3}");
WrappedByteApi api = fixture.build(WrappedByteApi.class);
InvalidResponseException thrown = catchThrowableOfType(api::container, InvalidResponseException.class);
then(thrown).hasMessage("invalid java.lang.Byte value for " + WrappedByteApi.class.getName() + "#container.code.value: 1000");
}
use of io.smallrye.graphql.client.InvalidResponseException in project smallrye-graphql by smallrye.
the class NestedBehavior method shouldFailToSetMissingNonNullField.
@Test
void shouldFailToSetMissingNonNullField() {
fixture.returnsData("'call':{'foo':'a'}");
MissingNonNullFieldApi api = fixture.build(MissingNonNullFieldApi.class);
InvalidResponseException thrown = catchThrowableOfType(api::call, InvalidResponseException.class);
then(thrown).hasMessage("missing java.lang.String value for " + MissingNonNullFieldApi.class.getName() + "#call.bar");
}
Aggregations