Search in sources :

Example 26 with Cancellable

use of io.smallrye.mutiny.subscription.Cancellable in project smallrye-graphql by smallrye.

the class GraphQLWSSubprotocolHandler method initialize.

private Uni<Void> initialize() {
    return Uni.createFrom().emitter(initializationEmitter -> {
        if (log.isTraceEnabled()) {
            log.trace("Initializing websocket with graphql-ws protocol");
        }
        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, createConnectionInitMessage());
        // set up a timeout for subscription initialization
        Cancellable timeoutWaitingForConnectionAckMessage = null;
        if (subscriptionInitializationTimeout != null) {
            timeoutWaitingForConnectionAckMessage = Uni.createFrom().item(1).onItem().delayIt().by(Duration.ofMillis(subscriptionInitializationTimeout)).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 GQL_CONNECTION_ERROR:
                        failAllActiveOperationsWith(new InvalidResponseException(message.get("payload").toString()));
                        webSocket.close();
                        break;
                    case GQL_CONNECTION_ACK:
                        if (finalTimeoutWaitingForConnectionAckMessage != null) {
                            finalTimeoutWaitingForConnectionAckMessage.cancel();
                        }
                        initializationEmitter.complete(null);
                        break;
                    case GQL_DATA:
                        handleData(message.getString("id"), message.getJsonObject("payload"));
                        break;
                    case GQL_ERROR:
                        handleOperationError(message.getString("id"), message.getJsonObject("payload"));
                        break;
                    case GQL_COMPLETE:
                        handleComplete(message.getString("id"));
                        break;
                    case GQL_START:
                    case GQL_STOP:
                    case GQL_CONNECTION_KEEP_ALIVE:
                    case GQL_CONNECTION_INIT:
                    case GQL_CONNECTION_TERMINATE:
                        break;
                }
            } catch (JsonParsingException | IllegalArgumentException e) {
                log.error("Unexpected message from server: " + text);
            // should we fail the operations here?
            }
        });
    });
}
Also used : JsonObject(javax.json.JsonObject) WebSocketSubprotocolHandler(io.smallrye.graphql.client.vertx.websocket.WebSocketSubprotocolHandler) GraphQLClientException(io.smallrye.graphql.client.GraphQLClientException) MultiEmitter(io.smallrye.mutiny.subscription.MultiEmitter) Logger(org.jboss.logging.Logger) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) UniEmitter(io.smallrye.mutiny.subscription.UniEmitter) CompletableFuture(java.util.concurrent.CompletableFuture) WebSocket(io.vertx.core.http.WebSocket) JsonString(javax.json.JsonString) Uni(io.smallrye.mutiny.Uni) JsonValue(javax.json.JsonValue) ResponseReader(io.smallrye.graphql.client.impl.ResponseReader) IncrementingNumberOperationIDGenerator(io.smallrye.graphql.client.vertx.websocket.opid.IncrementingNumberOperationIDGenerator) StringReader(java.io.StringReader) GraphQLError(io.smallrye.graphql.client.GraphQLError) OperationIDGenerator(io.smallrye.graphql.client.vertx.websocket.opid.OperationIDGenerator) Duration(java.time.Duration) Map(java.util.Map) Json(javax.json.Json) Cancellable(io.smallrye.mutiny.subscription.Cancellable) JsonParsingException(javax.json.stream.JsonParsingException) JsonObjectBuilder(javax.json.JsonObjectBuilder) InvalidResponseException(io.smallrye.graphql.client.InvalidResponseException) Cancellable(io.smallrye.mutiny.subscription.Cancellable) JsonObject(javax.json.JsonObject) InvalidResponseException(io.smallrye.graphql.client.InvalidResponseException) JsonParsingException(javax.json.stream.JsonParsingException)

Aggregations

Cancellable (io.smallrye.mutiny.subscription.Cancellable)26 Test (org.junit.jupiter.api.Test)17 AtomicReference (java.util.concurrent.atomic.AtomicReference)11 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)9 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)8 Uni (io.smallrye.mutiny.Uni)5 IOException (java.io.IOException)5 Duration (java.time.Duration)4 UniEmitter (io.smallrye.mutiny.subscription.UniEmitter)3 CompletableFuture (java.util.concurrent.CompletableFuture)3 GraphQLClientException (io.smallrye.graphql.client.GraphQLClientException)2 GraphQLError (io.smallrye.graphql.client.GraphQLError)2 InvalidResponseException (io.smallrye.graphql.client.InvalidResponseException)2 ResponseReader (io.smallrye.graphql.client.impl.ResponseReader)2 WebSocketSubprotocolHandler (io.smallrye.graphql.client.vertx.websocket.WebSocketSubprotocolHandler)2 IncrementingNumberOperationIDGenerator (io.smallrye.graphql.client.vertx.websocket.opid.IncrementingNumberOperationIDGenerator)2 OperationIDGenerator (io.smallrye.graphql.client.vertx.websocket.opid.OperationIDGenerator)2 MultiEmitter (io.smallrye.mutiny.subscription.MultiEmitter)2 WebSocket (io.vertx.core.http.WebSocket)2 StringReader (java.io.StringReader)2