Search in sources :

Example 1 with WebSocketSessionException

use of io.micronaut.websocket.exceptions.WebSocketSessionException in project micronaut-core by micronaut-projects.

the class NettyWebSocketClientHandler method channelRead0.

@Override
protected void channelRead0(ChannelHandlerContext ctx, Object msg) {
    final Channel ch = ctx.channel();
    if (!handshaker.isHandshakeComplete()) {
        // web socket client connected
        FullHttpResponse res = (FullHttpResponse) msg;
        this.handshakeResponse = res;
        try {
            handshaker.finishHandshake(ch, res);
        } catch (Exception e) {
            try {
                emitter.error(new WebSocketClientException("Error finishing WebSocket handshake: " + e.getMessage(), e));
            } finally {
                // clientSession isn't set yet, so we do the close manually instead of through session.close
                ch.writeAndFlush(new CloseWebSocketFrame(CloseReason.INTERNAL_ERROR.getCode(), CloseReason.INTERNAL_ERROR.getReason()));
                ch.close();
            }
            return;
        }
        handshakeFuture.setSuccess();
        this.clientSession = createWebSocketSession(ctx);
        T targetBean = genericWebSocketBean.getTarget();
        if (targetBean instanceof WebSocketSessionAware) {
            ((WebSocketSessionAware) targetBean).setWebSocketSession(clientSession);
        }
        ExecutableBinder<WebSocketState> binder = new DefaultExecutableBinder<>();
        BoundExecutable<?, ?> bound = binder.tryBind(messageHandler.getExecutableMethod(), webSocketBinder, new WebSocketState(clientSession, originatingRequest));
        List<Argument<?>> unboundArguments = bound.getUnboundArguments();
        if (unboundArguments.size() == 1) {
            this.clientBodyArgument = unboundArguments.iterator().next();
        } else {
            this.clientBodyArgument = null;
            try {
                emitter.error(new WebSocketClientException("WebSocket @OnMessage method " + targetBean.getClass().getSimpleName() + "." + messageHandler.getExecutableMethod() + " should define exactly 1 message parameter, but found 2 possible candidates: " + unboundArguments));
            } finally {
                if (getSession().isOpen()) {
                    getSession().close(CloseReason.INTERNAL_ERROR);
                }
            }
            return;
        }
        if (pongHandler != null) {
            BoundExecutable<?, ?> boundPong = binder.tryBind(pongHandler.getExecutableMethod(), webSocketBinder, new WebSocketState(clientSession, originatingRequest));
            List<Argument<?>> unboundPongArguments = boundPong.getUnboundArguments();
            if (unboundPongArguments.size() == 1 && unboundPongArguments.get(0).isAssignableFrom(WebSocketPongMessage.class)) {
                this.clientPongArgument = unboundPongArguments.get(0);
            } else {
                this.clientPongArgument = null;
                try {
                    emitter.error(new WebSocketClientException("WebSocket @OnMessage pong handler method " + targetBean.getClass().getSimpleName() + "." + messageHandler.getExecutableMethod() + " should define exactly 1 pong message parameter, but found: " + unboundArguments));
                } finally {
                    if (getSession().isOpen()) {
                        getSession().close(CloseReason.INTERNAL_ERROR);
                    }
                }
                return;
            }
        }
        Optional<? extends MethodExecutionHandle<?, ?>> opt = webSocketBean.openMethod();
        if (opt.isPresent()) {
            MethodExecutionHandle<?, ?> openMethod = opt.get();
            WebSocketState webSocketState = new WebSocketState(clientSession, originatingRequest);
            try {
                BoundExecutable openMethodBound = binder.bind(openMethod.getExecutableMethod(), webSocketStateBinderRegistry, webSocketState);
                Object target = openMethod.getTarget();
                Object result = openMethodBound.invoke(target);
                if (Publishers.isConvertibleToPublisher(result)) {
                    Publisher<?> reactiveSequence = Publishers.convertPublisher(result, Publisher.class);
                    Flux.from(reactiveSequence).subscribe(o -> {
                    }, error -> emitter.error(new WebSocketSessionException("Error opening WebSocket client session: " + error.getMessage(), error)), () -> {
                        emitter.next(targetBean);
                        emitter.complete();
                    });
                } else {
                    emitter.next(targetBean);
                    emitter.complete();
                }
            } catch (Throwable e) {
                emitter.error(new WebSocketClientException("Error opening WebSocket client session: " + e.getMessage(), e));
                if (getSession().isOpen()) {
                    getSession().close(CloseReason.INTERNAL_ERROR);
                }
            }
        } else {
            emitter.next(targetBean);
            emitter.complete();
        }
        return;
    }
    if (msg instanceof WebSocketFrame) {
        handleWebSocketFrame(ctx, (WebSocketFrame) msg);
    } else {
        ctx.fireChannelRead(msg);
    }
}
Also used : CloseWebSocketFrame(io.netty.handler.codec.http.websocketx.CloseWebSocketFrame) Argument(io.micronaut.core.type.Argument) DefaultExecutableBinder(io.micronaut.core.bind.DefaultExecutableBinder) Channel(io.netty.channel.Channel) WebSocketClientException(io.micronaut.websocket.exceptions.WebSocketClientException) WebSocketSessionException(io.micronaut.websocket.exceptions.WebSocketSessionException) WebSocketSessionAware(io.micronaut.websocket.interceptor.WebSocketSessionAware) WebSocketClientException(io.micronaut.websocket.exceptions.WebSocketClientException) WebSocketSessionException(io.micronaut.websocket.exceptions.WebSocketSessionException) BoundExecutable(io.micronaut.core.bind.BoundExecutable) FullHttpResponse(io.netty.handler.codec.http.FullHttpResponse) CloseWebSocketFrame(io.netty.handler.codec.http.websocketx.CloseWebSocketFrame) WebSocketFrame(io.netty.handler.codec.http.websocketx.WebSocketFrame) WebSocketPongMessage(io.micronaut.websocket.WebSocketPongMessage) WebSocketState(io.micronaut.websocket.bind.WebSocketState)

Example 2 with WebSocketSessionException

use of io.micronaut.websocket.exceptions.WebSocketSessionException in project micronaut-core by micronaut-projects.

the class NettyWebSocketSession method sendAsync.

@Override
public <T> CompletableFuture<T> sendAsync(T message, MediaType mediaType) {
    if (isOpen()) {
        if (message != null) {
            CompletableFuture<T> future = new CompletableFuture<>();
            WebSocketFrame frame;
            if (message instanceof WebSocketFrame) {
                frame = (WebSocketFrame) message;
            } else {
                frame = messageEncoder.encodeMessage(message, mediaType);
            }
            channel.writeAndFlush(frame).addListener(f -> {
                if (f.isSuccess()) {
                    future.complete(message);
                } else {
                    future.completeExceptionally(new WebSocketSessionException("Send Failure: " + f.cause().getMessage(), f.cause()));
                }
            });
            return future;
        } else {
            return CompletableFuture.completedFuture(null);
        }
    } else {
        throw new WebSocketSessionException("Session closed");
    }
}
Also used : CompletableFuture(java.util.concurrent.CompletableFuture) WebSocketSessionException(io.micronaut.websocket.exceptions.WebSocketSessionException) CloseWebSocketFrame(io.netty.handler.codec.http.websocketx.CloseWebSocketFrame) WebSocketFrame(io.netty.handler.codec.http.websocketx.WebSocketFrame) PingWebSocketFrame(io.netty.handler.codec.http.websocketx.PingWebSocketFrame)

Example 3 with WebSocketSessionException

use of io.micronaut.websocket.exceptions.WebSocketSessionException in project micronaut-core by micronaut-projects.

the class NettyServerWebSocketBroadcaster method broadcast.

@Override
public <T> Publisher<T> broadcast(T message, MediaType mediaType, Predicate<WebSocketSession> filter) {
    return Flux.create(emitter -> {
        try {
            WebSocketFrame frame = webSocketMessageEncoder.encodeMessage(message, mediaType);
            webSocketSessionRepository.getChannelGroup().writeAndFlush(frame, ch -> {
                Attribute<NettyWebSocketSession> attr = ch.attr(NettyWebSocketSession.WEB_SOCKET_SESSION_KEY);
                NettyWebSocketSession s = attr.get();
                return s != null && s.isOpen() && filter.test(s);
            }).addListener(future -> {
                if (!future.isSuccess()) {
                    Throwable cause = extractBroadcastFailure(future.cause());
                    if (cause != null) {
                        emitter.error(new WebSocketSessionException("Broadcast Failure: " + cause.getMessage(), cause));
                        return;
                    }
                }
                emitter.next(message);
                emitter.complete();
            });
        } catch (Throwable e) {
            emitter.error(new WebSocketSessionException("Broadcast Failure: " + e.getMessage(), e));
        }
    }, FluxSink.OverflowStrategy.BUFFER);
}
Also used : Attribute(io.netty.util.Attribute) ChannelGroupException(io.netty.channel.group.ChannelGroupException) WebSocketFrame(io.netty.handler.codec.http.websocketx.WebSocketFrame) ClosedChannelException(java.nio.channels.ClosedChannelException) Predicate(java.util.function.Predicate) Publisher(org.reactivestreams.Publisher) FluxSink(reactor.core.publisher.FluxSink) Singleton(jakarta.inject.Singleton) Channel(io.netty.channel.Channel) Flux(reactor.core.publisher.Flux) MediaType(io.micronaut.http.MediaType) Nullable(io.micronaut.core.annotation.Nullable) Map(java.util.Map) WebSocketBroadcaster(io.micronaut.websocket.WebSocketBroadcaster) Requires(io.micronaut.context.annotation.Requires) WebSocketSessionException(io.micronaut.websocket.exceptions.WebSocketSessionException) WebSocketSession(io.micronaut.websocket.WebSocketSession) Attribute(io.netty.util.Attribute) WebSocketSessionException(io.micronaut.websocket.exceptions.WebSocketSessionException) WebSocketFrame(io.netty.handler.codec.http.websocketx.WebSocketFrame)

Example 4 with WebSocketSessionException

use of io.micronaut.websocket.exceptions.WebSocketSessionException in project micronaut-core by micronaut-projects.

the class NettyWebSocketSession method send.

@Override
public <T> Flux<T> send(T message, MediaType mediaType) {
    if (message == null) {
        return Flux.empty();
    }
    return Flux.create(emitter -> {
        if (!isOpen()) {
            emitter.error(new WebSocketSessionException("Session closed"));
        } else {
            WebSocketFrame frame;
            if (message instanceof WebSocketFrame) {
                frame = (WebSocketFrame) message;
            } else {
                frame = messageEncoder.encodeMessage(message, mediaType);
            }
            ChannelFuture channelFuture = channel.writeAndFlush(frame);
            channelFuture.addListener(future -> {
                if (future.isSuccess()) {
                    emitter.next(message);
                    emitter.complete();
                } else {
                    emitter.error(new WebSocketSessionException("Send Failure: " + future.cause().getMessage(), future.cause()));
                }
            });
        }
    }, FluxSink.OverflowStrategy.ERROR);
}
Also used : ChannelFuture(io.netty.channel.ChannelFuture) WebSocketSessionException(io.micronaut.websocket.exceptions.WebSocketSessionException) CloseWebSocketFrame(io.netty.handler.codec.http.websocketx.CloseWebSocketFrame) WebSocketFrame(io.netty.handler.codec.http.websocketx.WebSocketFrame) PingWebSocketFrame(io.netty.handler.codec.http.websocketx.PingWebSocketFrame)

Example 5 with WebSocketSessionException

use of io.micronaut.websocket.exceptions.WebSocketSessionException in project micronaut-core by micronaut-projects.

the class NettyWebSocketSession method sendPingAsync.

@NonNull
@Override
public CompletableFuture<?> sendPingAsync(@NonNull byte[] content) {
    if (isOpen()) {
        ByteBuf messageBuffer = channel.alloc().buffer(content.length);
        messageBuffer.writeBytes(content);
        PingWebSocketFrame frame = new PingWebSocketFrame(messageBuffer);
        CompletableFuture<Object> future = new CompletableFuture<>();
        channel.writeAndFlush(frame).addListener(f -> {
            if (f.isSuccess()) {
                future.complete(null);
            } else {
                future.completeExceptionally(new WebSocketSessionException("Send Failure: " + f.cause().getMessage(), f.cause()));
            }
        });
        return future;
    } else {
        throw new WebSocketSessionException("Session closed");
    }
}
Also used : CompletableFuture(java.util.concurrent.CompletableFuture) WebSocketSessionException(io.micronaut.websocket.exceptions.WebSocketSessionException) ByteBuf(io.netty.buffer.ByteBuf) PingWebSocketFrame(io.netty.handler.codec.http.websocketx.PingWebSocketFrame) NonNull(io.micronaut.core.annotation.NonNull)

Aggregations

WebSocketSessionException (io.micronaut.websocket.exceptions.WebSocketSessionException)7 WebSocketFrame (io.netty.handler.codec.http.websocketx.WebSocketFrame)5 CloseWebSocketFrame (io.netty.handler.codec.http.websocketx.CloseWebSocketFrame)4 PingWebSocketFrame (io.netty.handler.codec.http.websocketx.PingWebSocketFrame)4 NonNull (io.micronaut.core.annotation.NonNull)2 Nullable (io.micronaut.core.annotation.Nullable)2 Argument (io.micronaut.core.type.Argument)2 MediaType (io.micronaut.http.MediaType)2 ByteBuf (io.netty.buffer.ByteBuf)2 Attribute (io.netty.util.Attribute)2 Publisher (org.reactivestreams.Publisher)2 Flux (reactor.core.publisher.Flux)2 FluxSink (reactor.core.publisher.FluxSink)2 NettyByteBufferFactory (io.micronaut.buffer.netty.NettyByteBufferFactory)1 Requires (io.micronaut.context.annotation.Requires)1 AnnotationMetadata (io.micronaut.core.annotation.AnnotationMetadata)1 AnnotationMetadataResolver (io.micronaut.core.annotation.AnnotationMetadataResolver)1 Internal (io.micronaut.core.annotation.Internal)1 Publishers (io.micronaut.core.async.publisher.Publishers)1 BeanMap (io.micronaut.core.beans.BeanMap)1