Search in sources :

Example 1 with ExecutableBinder

use of io.micronaut.core.bind.ExecutableBinder in project micronaut-core by micronaut-projects.

the class AbstractNettyWebSocketHandler method handleWebSocketFrame.

/**
 * Handles WebSocket frame request.
 *
 * @param ctx The context
 * @param msg The frame
 */
protected void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame msg) {
    if (msg instanceof TextWebSocketFrame || msg instanceof BinaryWebSocketFrame || msg instanceof ContinuationWebSocketFrame) {
        if (messageHandler == null) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("WebSocket bean [" + webSocketBean.getTarget() + "] received message, but defined no @OnMessage handler. Dropping frame...");
            }
            writeCloseFrameAndTerminate(ctx, CloseReason.UNSUPPORTED_DATA);
        } else {
            ByteBuf msgContent = msg.content().retain();
            if (!msg.isFinalFragment()) {
                frameBuffer.updateAndGet((buffer) -> {
                    if (buffer == null) {
                        buffer = ctx.alloc().compositeBuffer();
                    }
                    buffer.addComponent(true, msgContent);
                    return buffer;
                });
                return;
            }
            ByteBuf content;
            CompositeByteBuf buffer = frameBuffer.getAndSet(null);
            if (buffer == null) {
                content = msgContent;
            } else {
                buffer.addComponent(true, msgContent);
                content = buffer;
            }
            Argument<?> bodyArgument = this.getBodyArgument();
            Optional<?> converted = ConversionService.SHARED.convert(content, bodyArgument);
            content.release();
            if (!converted.isPresent()) {
                MediaType mediaType;
                try {
                    mediaType = messageHandler.stringValue(Consumes.class).map(MediaType::of).orElse(MediaType.APPLICATION_JSON_TYPE);
                } catch (IllegalArgumentException e) {
                    exceptionCaught(ctx, e);
                    return;
                }
                try {
                    converted = mediaTypeCodecRegistry.findCodec(mediaType).map(codec -> codec.decode(bodyArgument, new NettyByteBufferFactory(ctx.alloc()).wrap(msg.content())));
                } catch (CodecException e) {
                    messageProcessingException(ctx, e);
                    return;
                }
            }
            if (converted.isPresent()) {
                Object v = converted.get();
                NettyWebSocketSession currentSession = getSession();
                ExecutableBinder<WebSocketState> executableBinder = new DefaultExecutableBinder<>(Collections.singletonMap(bodyArgument, v));
                try {
                    BoundExecutable boundExecutable = executableBinder.bind(messageHandler.getExecutableMethod(), webSocketBinder, new WebSocketState(currentSession, originatingRequest));
                    Object result = invokeExecutable(boundExecutable, messageHandler);
                    if (Publishers.isConvertibleToPublisher(result)) {
                        Flux<?> flowable = Flux.from(instrumentPublisher(ctx, result));
                        flowable.subscribe(o -> {
                        }, error -> messageProcessingException(ctx, error), () -> messageHandled(ctx, session, v));
                    } else {
                        messageHandled(ctx, session, v);
                    }
                } catch (Throwable e) {
                    messageProcessingException(ctx, e);
                }
            } else {
                writeCloseFrameAndTerminate(ctx, CloseReason.UNSUPPORTED_DATA.getCode(), CloseReason.UNSUPPORTED_DATA.getReason() + ": " + "Received data cannot be converted to target type: " + bodyArgument);
            }
        }
    } else if (msg instanceof PingWebSocketFrame) {
        // respond with pong
        PingWebSocketFrame frame = (PingWebSocketFrame) msg.retain();
        ctx.writeAndFlush(new PongWebSocketFrame(frame.content()));
    } else if (msg instanceof PongWebSocketFrame) {
        if (pongHandler != null) {
            ByteBuf content = msg.content();
            WebSocketPongMessage message = new WebSocketPongMessage(NettyByteBufferFactory.DEFAULT.wrap(content));
            NettyWebSocketSession currentSession = getSession();
            ExecutableBinder<WebSocketState> executableBinder = new DefaultExecutableBinder<>(Collections.singletonMap(getPongArgument(), message));
            try {
                BoundExecutable boundExecutable = executableBinder.bind(pongHandler.getExecutableMethod(), webSocketBinder, new WebSocketState(currentSession, originatingRequest));
                Object result = invokeExecutable(boundExecutable, pongHandler);
                if (Publishers.isConvertibleToPublisher(result)) {
                    // delay the buffer release until the publisher has completed
                    content.retain();
                    Flux<?> flowable = Flux.from(instrumentPublisher(ctx, result));
                    flowable.subscribe(o -> {
                    }, error -> {
                        if (LOG.isErrorEnabled()) {
                            LOG.error("Error Processing WebSocket Pong Message [" + webSocketBean + "]: " + error.getMessage(), error);
                        }
                        exceptionCaught(ctx, error);
                    }, content::release);
                }
            } catch (Throwable e) {
                if (LOG.isErrorEnabled()) {
                    LOG.error("Error Processing WebSocket Message [" + webSocketBean + "]: " + e.getMessage(), e);
                }
                exceptionCaught(ctx, e);
            }
        }
    } else if (msg instanceof CloseWebSocketFrame) {
        CloseWebSocketFrame cwsf = (CloseWebSocketFrame) msg;
        handleCloseFrame(ctx, cwsf);
    } else {
        writeCloseFrameAndTerminate(ctx, CloseReason.UNSUPPORTED_DATA);
    }
}
Also used : Publishers(io.micronaut.core.async.publisher.Publishers) ArgumentBinderRegistry(io.micronaut.core.bind.ArgumentBinderRegistry) LoggerFactory(org.slf4j.LoggerFactory) Internal(io.micronaut.core.annotation.Internal) UnsatisfiedArgumentException(io.micronaut.core.bind.exceptions.UnsatisfiedArgumentException) CloseReason(io.micronaut.websocket.CloseReason) MediaType(io.micronaut.http.MediaType) Map(java.util.Map) RequestBinderRegistry(io.micronaut.http.bind.RequestBinderRegistry) DefaultExecutableBinder(io.micronaut.core.bind.DefaultExecutableBinder) CodecException(io.micronaut.http.codec.CodecException) ContinuationWebSocketFrame(io.netty.handler.codec.http.websocketx.ContinuationWebSocketFrame) WebSocketState(io.micronaut.websocket.bind.WebSocketState) CompositeByteBuf(io.netty.buffer.CompositeByteBuf) List(java.util.List) Optional(java.util.Optional) NettyByteBufferFactory(io.micronaut.buffer.netty.NettyByteBufferFactory) WebSocketBean(io.micronaut.websocket.context.WebSocketBean) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HashMap(java.util.HashMap) AtomicReference(java.util.concurrent.atomic.AtomicReference) ExecutableMethod(io.micronaut.inject.ExecutableMethod) ChannelHandlerContext(io.netty.channel.ChannelHandlerContext) WebSocketVersion(io.netty.handler.codec.http.websocketx.WebSocketVersion) ExecutableBinder(io.micronaut.core.bind.ExecutableBinder) ByteBuf(io.netty.buffer.ByteBuf) PongWebSocketFrame(io.netty.handler.codec.http.websocketx.PongWebSocketFrame) Schedulers(reactor.core.scheduler.Schedulers) CloseWebSocketFrame(io.netty.handler.codec.http.websocketx.CloseWebSocketFrame) Argument(io.micronaut.core.type.Argument) HttpRequest(io.micronaut.http.HttpRequest) BoundExecutable(io.micronaut.core.bind.BoundExecutable) ConversionService(io.micronaut.core.convert.ConversionService) MediaTypeCodecRegistry(io.micronaut.http.codec.MediaTypeCodecRegistry) Logger(org.slf4j.Logger) WebSocketFrame(io.netty.handler.codec.http.websocketx.WebSocketFrame) PingWebSocketFrame(io.netty.handler.codec.http.websocketx.PingWebSocketFrame) Publisher(org.reactivestreams.Publisher) IOException(java.io.IOException) MethodExecutionHandle(io.micronaut.inject.MethodExecutionHandle) Channel(io.netty.channel.Channel) BinaryWebSocketFrame(io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame) Consumer(java.util.function.Consumer) Flux(reactor.core.publisher.Flux) WebSocketStateBinderRegistry(io.micronaut.websocket.bind.WebSocketStateBinderRegistry) TextWebSocketFrame(io.netty.handler.codec.http.websocketx.TextWebSocketFrame) SimpleChannelInboundHandler(io.netty.channel.SimpleChannelInboundHandler) Consumes(io.micronaut.http.annotation.Consumes) WebSocketPongMessage(io.micronaut.websocket.WebSocketPongMessage) Collections(java.util.Collections) BinaryWebSocketFrame(io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame) CompositeByteBuf(io.netty.buffer.CompositeByteBuf) ByteBuf(io.netty.buffer.ByteBuf) PingWebSocketFrame(io.netty.handler.codec.http.websocketx.PingWebSocketFrame) CompositeByteBuf(io.netty.buffer.CompositeByteBuf) PongWebSocketFrame(io.netty.handler.codec.http.websocketx.PongWebSocketFrame) Consumes(io.micronaut.http.annotation.Consumes) TextWebSocketFrame(io.netty.handler.codec.http.websocketx.TextWebSocketFrame) MediaType(io.micronaut.http.MediaType) CodecException(io.micronaut.http.codec.CodecException) CloseWebSocketFrame(io.netty.handler.codec.http.websocketx.CloseWebSocketFrame) NettyByteBufferFactory(io.micronaut.buffer.netty.NettyByteBufferFactory) ContinuationWebSocketFrame(io.netty.handler.codec.http.websocketx.ContinuationWebSocketFrame) DefaultExecutableBinder(io.micronaut.core.bind.DefaultExecutableBinder) BoundExecutable(io.micronaut.core.bind.BoundExecutable) WebSocketPongMessage(io.micronaut.websocket.WebSocketPongMessage) WebSocketState(io.micronaut.websocket.bind.WebSocketState)

Aggregations

NettyByteBufferFactory (io.micronaut.buffer.netty.NettyByteBufferFactory)1 Internal (io.micronaut.core.annotation.Internal)1 Publishers (io.micronaut.core.async.publisher.Publishers)1 ArgumentBinderRegistry (io.micronaut.core.bind.ArgumentBinderRegistry)1 BoundExecutable (io.micronaut.core.bind.BoundExecutable)1 DefaultExecutableBinder (io.micronaut.core.bind.DefaultExecutableBinder)1 ExecutableBinder (io.micronaut.core.bind.ExecutableBinder)1 UnsatisfiedArgumentException (io.micronaut.core.bind.exceptions.UnsatisfiedArgumentException)1 ConversionService (io.micronaut.core.convert.ConversionService)1 Argument (io.micronaut.core.type.Argument)1 HttpRequest (io.micronaut.http.HttpRequest)1 MediaType (io.micronaut.http.MediaType)1 Consumes (io.micronaut.http.annotation.Consumes)1 RequestBinderRegistry (io.micronaut.http.bind.RequestBinderRegistry)1 CodecException (io.micronaut.http.codec.CodecException)1 MediaTypeCodecRegistry (io.micronaut.http.codec.MediaTypeCodecRegistry)1 ExecutableMethod (io.micronaut.inject.ExecutableMethod)1 MethodExecutionHandle (io.micronaut.inject.MethodExecutionHandle)1 CloseReason (io.micronaut.websocket.CloseReason)1 WebSocketPongMessage (io.micronaut.websocket.WebSocketPongMessage)1