use of io.micronaut.websocket.bind.WebSocketState 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);
}
}
use of io.micronaut.websocket.bind.WebSocketState 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.websocket.bind.WebSocketState in project micronaut-core by micronaut-projects.
the class AbstractNettyWebSocketHandler method bindMethod.
private BoundExecutable bindMethod(HttpRequest<?> request, ArgumentBinderRegistry<WebSocketState> binderRegistry, MethodExecutionHandle<?, ?> openMethod, List<?> parameters) {
ExecutableMethod<?, ?> executable = openMethod.getExecutableMethod();
Map<Argument<?>, Object> preBound = prepareBoundVariables(executable, parameters);
ExecutableBinder<WebSocketState> executableBinder = new DefaultExecutableBinder<>(preBound);
return executableBinder.bind(executable, binderRegistry, new WebSocketState(getSession(), request));
}
Aggregations