use of io.micronaut.buffer.netty.NettyByteBufferFactory 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);
}
}
use of io.micronaut.buffer.netty.NettyByteBufferFactory in project micronaut-core by micronaut-projects.
the class RoutingInBoundHandler method mapToHttpContent.
private Flux<HttpContent> mapToHttpContent(NettyHttpRequest<?> request, MutableHttpResponse<?> response, Object body, ChannelHandlerContext context) {
final RouteInfo<?> routeInfo = response.getAttribute(HttpAttributes.ROUTE_INFO, RouteInfo.class).orElse(null);
final boolean hasRouteInfo = routeInfo != null;
MediaType mediaType = response.getContentType().orElse(null);
if (mediaType == null && hasRouteInfo) {
mediaType = routeExecutor.resolveDefaultResponseContentType(request, routeInfo);
}
boolean isJson = mediaType != null && mediaType.getExtension().equals(MediaType.EXTENSION_JSON) && isJsonFormattable(hasRouteInfo ? routeInfo.getBodyType() : null);
NettyByteBufferFactory byteBufferFactory = new NettyByteBufferFactory(context.alloc());
Flux<Object> bodyPublisher = Flux.from(Publishers.convertPublisher(body, Publisher.class));
MediaType finalMediaType = mediaType;
Flux<HttpContent> httpContentPublisher = bodyPublisher.map(message -> {
HttpContent httpContent;
if (message instanceof ByteBuf) {
httpContent = new DefaultHttpContent((ByteBuf) message);
} else if (message instanceof ByteBuffer) {
ByteBuffer<?> byteBuffer = (ByteBuffer<?>) message;
Object nativeBuffer = byteBuffer.asNativeBuffer();
if (nativeBuffer instanceof ByteBuf) {
httpContent = new DefaultHttpContent((ByteBuf) nativeBuffer);
} else {
httpContent = new DefaultHttpContent(Unpooled.copiedBuffer(byteBuffer.asNioBuffer()));
}
} else if (message instanceof byte[]) {
httpContent = new DefaultHttpContent(Unpooled.copiedBuffer((byte[]) message));
} else if (message instanceof HttpContent) {
httpContent = (HttpContent) message;
} else {
MediaTypeCodec codec = mediaTypeCodecRegistry.findCodec(finalMediaType, message.getClass()).orElse(new TextPlainCodec(serverConfiguration.getDefaultCharset()));
if (LOG.isTraceEnabled()) {
LOG.trace("Encoding emitted response object [{}] using codec: {}", message, codec);
}
ByteBuffer<ByteBuf> encoded;
if (hasRouteInfo) {
// noinspection unchecked
final Argument<Object> bodyType = (Argument<Object>) routeInfo.getBodyType();
if (bodyType.isInstance(message)) {
encoded = codec.encode(bodyType, message, byteBufferFactory);
} else {
encoded = codec.encode(message, byteBufferFactory);
}
} else {
encoded = codec.encode(message, byteBufferFactory);
}
httpContent = new DefaultHttpContent(encoded.asNativeBuffer());
}
return httpContent;
});
if (isJson) {
// if the Publisher is returning JSON then in order for it to be valid JSON for each emitted element
// we must wrap the JSON in array and delimit the emitted items
httpContentPublisher = JsonSubscriber.lift(httpContentPublisher);
}
httpContentPublisher = httpContentPublisher.contextWrite(reactorContext -> reactorContext.put(ServerRequestContext.KEY, request)).doOnNext(httpContent -> context.read()).doAfterTerminate(() -> cleanupRequest(context, request));
return httpContentPublisher;
}
Aggregations