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

io.gravitee.gateway.reactive.http.vertx.ws.VertxWebSocket Maven / Gradle / Ivy

/*
 * Copyright © 2015 The Gravitee team (http://gravitee.io)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.gravitee.gateway.reactive.http.vertx.ws;

import static io.vertx.rxjava3.core.http.WebSocketFrame.binaryFrame;
import static io.vertx.rxjava3.core.http.WebSocketFrame.continuationFrame;
import static io.vertx.rxjava3.core.http.WebSocketFrame.pingFrame;
import static io.vertx.rxjava3.core.http.WebSocketFrame.pongFrame;
import static io.vertx.rxjava3.core.http.WebSocketFrame.textFrame;

import io.gravitee.gateway.api.buffer.Buffer;
import io.gravitee.gateway.api.handler.Handler;
import io.gravitee.gateway.reactive.api.ws.WebSocket;
import io.reactivex.rxjava3.core.Completable;
import io.reactivex.rxjava3.core.Flowable;
import io.reactivex.rxjava3.core.Single;
import io.vertx.core.http.HttpClosedException;
import io.vertx.rxjava3.core.http.HttpServerRequest;
import io.vertx.rxjava3.core.http.ServerWebSocket;
import io.vertx.rxjava3.core.http.WebSocketFrame;

/**
 * @author Jeoffrey HAEYAERT (jeoffrey.haeyaert at graviteesource.com)
 * @author GraviteeSource Team
 */
public class VertxWebSocket implements WebSocket {

    private final HttpServerRequest httpServerRequest;

    private boolean upgraded;
    private ServerWebSocket webSocket;

    public VertxWebSocket(final HttpServerRequest httpServerRequest) {
        this.httpServerRequest = httpServerRequest;
    }

    public ServerWebSocket getDelegate() {
        return webSocket;
    }

    @Override
    public Single upgrade() {
        if (!upgraded) {
            return Single.defer(() ->
                httpServerRequest
                    .rxToWebSocket()
                    .doOnSuccess(serverWebSocket -> {
                        webSocket = serverWebSocket;
                        upgraded = true;
                    })
                    .map(serverWebSocket -> this)
            );
        }

        return Single.just(this);
    }

    @Override
    public Completable write(Buffer buffer) {
        if (isValid()) {
            return webSocket.rxWrite(io.vertx.rxjava3.core.buffer.Buffer.buffer(buffer.getNativeBuffer()));
        }

        return Completable.complete();
    }

    @Override
    public Completable writePing() {
        if (isValid()) {
            return webSocket.writePing(io.vertx.rxjava3.core.buffer.Buffer.buffer("ping_pong"));
        }
        return Completable.complete();
    }

    public Completable writeFrame(io.gravitee.gateway.api.ws.WebSocketFrame frame) {
        if (isValid()) {
            final WebSocketFrame webSocketFrame = convert(frame);

            if (webSocketFrame == null) {
                return this.close();
            }
            return webSocket.rxWriteFrame(webSocketFrame);
        }

        return Completable.complete();
    }

    public void frameHandler(Handler frameHandler) {
        if (isValid()) {
            webSocket.frameHandler(frame -> frameHandler.handle(new VertxWebSocketFrame(frame)));
        }
    }

    public void closeHandler(Handler closeHandler) {
        if (isValid()) {
            webSocket.closeHandler(closeHandler::handle);
        }
    }

    @Override
    public Flowable read() {
        if (isValid()) {
            return webSocket
                .toFlowable()
                .map(Buffer::buffer)
                .onErrorResumeNext(t -> {
                    if (t instanceof HttpClosedException) {
                        // Ends the flow properly if connection is closed by the client.
                        return Flowable.empty();
                    }

                    // Propagate in case of any other error.
                    return Flowable.error(t);
                });
        }

        return Flowable.empty();
    }

    @Override
    public Completable close() {
        if (isValid()) {
            return webSocket.rxClose();
        }

        return Completable.complete();
    }

    @Override
    public Completable close(int status) {
        if (isValid()) {
            return webSocket.rxClose((short) status);
        }

        return Completable.complete();
    }

    @Override
    public Completable close(int status, String reason) {
        if (isValid()) {
            return webSocket.rxClose((short) status, reason);
        }

        return Completable.complete();
    }

    @Override
    public boolean upgraded() {
        return upgraded;
    }

    @Override
    public boolean closed() {
        return webSocket.isClosed();
    }

    private boolean isValid() {
        return upgraded && !webSocket.isClosed();
    }

    private io.vertx.rxjava3.core.http.WebSocketFrame convert(io.gravitee.gateway.api.ws.WebSocketFrame frame) {
        switch (frame.type()) {
            case BINARY:
                return binaryFrame(io.vertx.rxjava3.core.buffer.Buffer.buffer(frame.data().getNativeBuffer()), frame.isFinal());
            case TEXT:
                return textFrame(frame.data().toString(), frame.isFinal());
            case CONTINUATION:
                return continuationFrame(io.vertx.rxjava3.core.buffer.Buffer.buffer(frame.data().toString()), frame.isFinal());
            case PING:
                return pingFrame(io.vertx.rxjava3.core.buffer.Buffer.buffer(frame.data().toString()));
            case PONG:
                return pongFrame(io.vertx.rxjava3.core.buffer.Buffer.buffer(frame.data().toString()));
            default:
                return null;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy