All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.quarkus.reactivemessaging.http.runtime.ReactiveWebSocketHandlerBean Maven / Gradle / Ivy

package io.quarkus.reactivemessaging.http.runtime;

import java.util.Collection;

import jakarta.inject.Inject;
import jakarta.inject.Singleton;

import org.jboss.logging.Logger;

import io.quarkus.reactivemessaging.http.runtime.config.ReactiveHttpConfig;
import io.quarkus.reactivemessaging.http.runtime.config.WebSocketStreamConfig;
import io.quarkus.reactivemessaging.http.runtime.serializers.DeserializerFactoryBase;
import io.smallrye.mutiny.Multi;
import io.smallrye.mutiny.subscription.MultiEmitter;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.ServerWebSocket;
import io.vertx.ext.web.RoutingContext;

/**
 * a bean that handles incoming web socket messages
 */
@Singleton
public class ReactiveWebSocketHandlerBean extends ReactiveHandlerBeanBase> {

    private static final Logger log = Logger.getLogger(ReactiveWebSocketHandlerBean.class);

    @Inject
    ReactiveHttpConfig config;

    @Inject
    DeserializerFactoryBase deserializerFactory;

    @Override
    protected void handleRequest(RoutingContext event, MultiEmitter> emitter,
            StrictQueueSizeGuard guard, String path, String deserializerName) {
        event.request().toWebSocket(
                webSocket -> {
                    if (webSocket.failed()) {
                        log.error("failed to connect web socket", webSocket.cause());
                    } else {
                        ServerWebSocket serverWebSocket = webSocket.result();
                        serverWebSocket.handler(
                                b -> {
                                    if (emitter == null) {
                                        onUnexpectedError(serverWebSocket, null,
                                                "No consumer subscribed for messages sent to " +
                                                        "Reactive Messaging WebSocket endpoint on path: " + path);
                                    } else if (guard.prepareToEmit()) {
                                        try {
                                            emitter.emit(new WebSocketMessage<>(
                                                    deserializerFactory.getDeserializer(deserializerName)
                                                            .map(d -> d.deserialize(b)).orElse(b),
                                                    new RequestMetadata(event),
                                                    () -> serverWebSocket.write(Buffer.buffer("ACK")),
                                                    error -> onUnexpectedError(serverWebSocket, error,
                                                            "Failed to process incoming web socket message.")));
                                        } catch (Exception error) {
                                            guard.dequeue();
                                            onUnexpectedError(serverWebSocket, error, "Emitting message failed");
                                        }
                                    } else {
                                        serverWebSocket.write(Buffer.buffer("BUFFER_OVERFLOW"));
                                    }
                                });
                    }
                });
    }

    @Override
    protected String description(WebSocketStreamConfig config) {
        return String.format("path %s", config.path);
    }

    @Override
    protected String key(WebSocketStreamConfig config) {
        return config.path;
    }

    @Override
    protected String key(RoutingContext context) {
        return context.currentRoute().getPath();
    }

    @Override
    protected Collection configs() {
        return config.getWebSocketConfigs();
    }

    private void onUnexpectedError(ServerWebSocket serverWebSocket, Throwable error, String message) {
        log.error(message, error);
        // TODO some error message for the client? exception mapper would be best...
        serverWebSocket.close((short) 3500, "Unexpected error while processing the message");
    }

    Multi> getProcessor(String path) {
        Bundle> bundle = processors.get(path);
        if (bundle == null) {
            throw new IllegalStateException("No incoming stream defined for path " + path);
        }
        return bundle.getProcessor();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy