/* * Copyright (C) 2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ro.pippo.undertow.websocket; import io.undertow.websockets.WebSocketConnectionCallback; import io.undertow.websockets.core.AbstractReceiveListener; import io.undertow.websockets.core.BufferedBinaryMessage; import io.undertow.websockets.core.BufferedTextMessage; import io.undertow.websockets.core.CloseMessage; import io.undertow.websockets.core.WebSocketChannel; import io.undertow.websockets.core.WebSockets; import io.undertow.websockets.spi.WebSocketHttpExchange; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xnio.Pooled; import ro.pippo.core.websocket.WebSocketConnection; import ro.pippo.core.websocket.WebSocketContext; import ro.pippo.core.websocket.WebSocketHandler; import java.io.IOException; import java.net.SocketTimeoutException; import java.nio.ByteBuffer; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; /** * Bridge between two incompatible interfaces: {@link WebSocketHandler} from Pippo and * {@link WebSocketConnectionCallback}, {@link AbstractReceiveListener} from Undertow. * * @author Decebal Suiu */ public class UndertowWebSocketAdapter extends AbstractReceiveListener implements WebSocketConnectionCallback { private static final Logger log = LoggerFactory.getLogger(UndertowWebSocketAdapter.class); private static List<WebSocketConnection> connections = new CopyOnWriteArrayList<>(); private final WebSocketHandler handler; private WebSocketContext context; private WebSocketConnection connection; public UndertowWebSocketAdapter(WebSocketHandler handler) { this.handler = handler; } @Override public void onConnect(WebSocketHttpExchange exchange, WebSocketChannel channel) { channel.getReceiveSetter().set(this); channel.resumeReceives(); connection = new UndertowWebSocketConnection(exchange, channel); connections.add(connection); context = new WebSocketContext(connections, connection); handler.onOpen(context); } @Override protected void onCloseMessage(CloseMessage cm, WebSocketChannel channel) { handler.onClose(context, cm.getCode(), cm.getReason()); connections.remove(connection); } @Override protected void onError(WebSocketChannel channel, Throwable error) { super.onError(channel, error); if (error instanceof SocketTimeoutException) { handler.onTimeout(context); } else { log.error("An error occurred when using WebSocket", error); handler.onError(context, error); } } @Override protected void onFullTextMessage(WebSocketChannel channel, BufferedTextMessage message) throws IOException { handler.onMessage(context, message.getData()); } @Override protected void onFullBinaryMessage(WebSocketChannel channel, BufferedBinaryMessage message) throws IOException { Pooled<ByteBuffer[]> pulledData = message.getData(); try { ByteBuffer[] resource = pulledData.getResource(); ByteBuffer buffer = WebSockets.mergeBuffers(resource); handler.onMessage(context, buffer.array()); } finally { pulledData.discard(); } } }