@Override public void close() { close(CloseReason.NORMAL); }
@Override public String toString() { return "WebSocket Session: " + getId(); }
@Override public void close(CloseReason closeReason) { super.close(closeReason); webSocketSessionRepository.removeChannel(ctx.channel()); }
@Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { if (evt instanceof IdleStateEvent) { IdleStateEvent idleStateEvent = (IdleStateEvent) evt; if (idleStateEvent.state() == IdleState.ALL_IDLE) { // close the connection if it is idle for too long if (clientSession != null && clientSession.isOpen()) { clientSession.close(CloseReason.NORMAL); } } } else { super.userEventTriggered(ctx, evt); } }
@Override public <T> void broadcastSync(T message, MediaType mediaType, Predicate<WebSocketSession> filter) { WebSocketFrame frame = webSocketMessageEncoder.encodeMessage(message, mediaType); try { webSocketSessionRepository.getChannelGroup().writeAndFlush(frame, ch -> { Attribute<NettyRxWebSocketSession> attr = ch.attr(NettyRxWebSocketSession.WEB_SOCKET_SESSION_KEY); NettyRxWebSocketSession s = attr.get(); return s != null && s.isOpen() && filter.test(s); }).sync(); } catch (InterruptedException e) { throw new WebSocketSessionException("Broadcast Interrupted"); } }
@Override public <T> CompletableFuture<T> sendAsync(T message, MediaType mediaType) { if (isOpen()) { if (message != null) { CompletableFuture<T> future = new CompletableFuture<>(); WebSocketFrame 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"); } }
if (getSession().isOpen()) { if (LOG.isDebugEnabled()) { LOG.debug("Closing WebSocket session {} with reason {}", getSession(), cr); try { BoundExecutable boundExecutable = bindMethod( originatingRequest, webSocketBinder, ); invokeAndClose(ctx, target, boundExecutable, methodExecutionHandle, true); } catch (Throwable e) { if (LOG.isErrorEnabled()) {
@Override public Set<? extends RxWebSocketSession> getOpenSessions() { return webSocketSessionRepository.getChannelGroup().stream().flatMap((Function<Channel, Stream<RxWebSocketSession>>) ch -> { NettyRxWebSocketSession s = ch.attr(NettyRxWebSocketSession.WEB_SOCKET_SESSION_KEY).get(); if (s != null && s.isOpen()) { return Stream.of(s); } return Stream.empty(); }).collect(Collectors.toSet()); }
@Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { if (evt instanceof IdleStateEvent) { writeCloseFrameAndTerminate(ctx, CloseReason.GOING_AWAY); } else { super.userEventTriggered(ctx, evt); } }
@Override public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) { if (!handshakeFuture.isDone()) { handshakeFuture.setFailure(cause); } super.exceptionCaught(ctx, cause); }
@Override public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { Channel channel = ctx.channel(); channel.attr(NettyRxWebSocketSession.WEB_SOCKET_SESSION_KEY).set(null); if (LOG.isDebugEnabled()) { LOG.debug("Removing WebSocket Server session: " + session); } webSocketSessionRepository.removeChannel(channel); try { eventPublisher.publishEvent(new WebSocketSessionClosedEvent(session)); } catch (Exception e) { if (LOG.isErrorEnabled()) { LOG.error("Error publishing WebSocket closed event: " + e.getMessage(), e); } } super.handlerRemoved(ctx); }
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)); }
/** * Writes the give close reason and terminates the session. * @param ctx The context * @param closeReason The reason */ protected void writeCloseFrameAndTerminate(ChannelHandlerContext ctx, CloseReason closeReason) { final int code = closeReason.getCode(); final String reason = closeReason.getReason(); writeCloseFrameAndTerminate(ctx, code, reason); }
@Override protected void channelRead0(ChannelHandlerContext ctx, Object msg) { if (msg instanceof WebSocketFrame) { handleWebSocketFrame(ctx, (WebSocketFrame) msg); } else { ctx.fireChannelRead(msg); } }
private void writeCloseFrameAndTerminate(ChannelHandlerContext ctx, int code, String reason) { final CloseWebSocketFrame closeFrame = new CloseWebSocketFrame(code, reason); ctx.channel().writeAndFlush(closeFrame) .addListener(future -> handleCloseFrame(ctx, new CloseWebSocketFrame(code, reason))); } }
private void handleCloseFrame(ChannelHandlerContext ctx, CloseWebSocketFrame cwsf) { if (closed.compareAndSet(false, true)) { CloseReason cr = new CloseReason(cwsf.statusCode(), cwsf.reasonText()); handleCloseReason(ctx, cr); } }
@Override public <T> Flowable<T> broadcast(T message, MediaType mediaType, Predicate<WebSocketSession> filter) { return Flowable.create(emitter -> { try { WebSocketFrame frame = webSocketMessageEncoder.encodeMessage(message, mediaType); webSocketSessionRepository.getChannelGroup().writeAndFlush(frame, ch -> { Attribute<NettyRxWebSocketSession> attr = ch.attr(NettyRxWebSocketSession.WEB_SOCKET_SESSION_KEY); NettyRxWebSocketSession s = attr.get(); return s != null && s.isOpen() && filter.test(s); }).addListener(future -> { if (future.isSuccess()) { emitter.onNext(message); emitter.onComplete(); } else { Throwable cause = future.cause(); emitter.onError(new WebSocketSessionException("Broadcast Failure: " + cause.getMessage(), cause)); } }); } catch (Throwable e) { emitter.onError(new WebSocketSessionException("Broadcast Failure: " + e.getMessage(), e)); } }, BackpressureStrategy.BUFFER); } }
@Override public void sendSync(Object message, MediaType mediaType) { if (isOpen()) { if (message != null) { try { WebSocketFrame frame = messageEncoder.encodeMessage(message, mediaType); channel.writeAndFlush(frame).sync().get(); } catch (InterruptedException e) { throw new WebSocketSessionException("Send interrupt: " + e.getMessage(), e); } catch (ExecutionException e) { throw new WebSocketSessionException("Send Failure: " + e.getMessage(), e); } } } else { throw new WebSocketSessionException("Session closed"); } }
private void handleUnexpected(ChannelHandlerContext ctx, Throwable cause) { if (cause instanceof IOException) { String msg = cause.getMessage(); if (msg != null && msg.contains("Connection reset")) { // ignore client connection drops return; } } if (LOG.isErrorEnabled()) { LOG.error("Unexpected Exception in WebSocket [" + webSocketBean.getTarget() + "]: " + cause.getMessage(), cause); } Channel channel = ctx.channel(); if (channel.isOpen()) { final CloseReason internalError = CloseReason.INTERNAL_ERROR; writeCloseFrameAndTerminate(ctx, internalError); } }
@Override public <T> Flowable<T> send(T message, MediaType mediaType) { if (message == null) { return Flowable.empty(); } return Flowable.create(emitter -> { if (!isOpen()) { emitter.onError(new WebSocketSessionException("Session closed")); } else { WebSocketFrame frame = messageEncoder.encodeMessage(message, mediaType); ChannelFuture channelFuture = channel.writeAndFlush(frame); channelFuture.addListener(future -> { if (future.isSuccess()) { emitter.onNext(message); emitter.onComplete(); } else { emitter.onError(new WebSocketSessionException("Send Failure: " + future.cause().getMessage(), future.cause())); } }); } }, BackpressureStrategy.ERROR); }