basic WebSocketProxy implementation
Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
parent
41bf9534eb
commit
d7598f3ff2
|
@ -0,0 +1,272 @@
|
|||
package org.eclipse.jetty.websocket.tests.proxy;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.eclipse.jetty.util.FutureCallback;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketConnectionListener;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPartialListener;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPingPongListener;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
|
||||
public class WebSocketProxy
|
||||
{
|
||||
private final WebSocketClient client = new WebSocketClient();
|
||||
private final URI serverUri = URI.create("ws://echo.websocket.org");
|
||||
private final ClientToProxy clientToProxy = new ClientToProxy();
|
||||
private final ProxyToServer proxyToServer = new ProxyToServer();
|
||||
|
||||
public WebSocketProxy()
|
||||
{
|
||||
LifeCycle.start(client);
|
||||
}
|
||||
|
||||
public WebSocketConnectionListener getWebSocketConnectionListener()
|
||||
{
|
||||
return clientToProxy;
|
||||
}
|
||||
|
||||
public class ClientToProxy implements WebSocketPartialListener, WebSocketPingPongListener
|
||||
{
|
||||
private Session session;
|
||||
private FutureCallback pongWait;
|
||||
|
||||
public Session getSession()
|
||||
{
|
||||
return session;
|
||||
}
|
||||
|
||||
public void receivedPong()
|
||||
{
|
||||
if (pongWait != null)
|
||||
{
|
||||
pongWait.succeeded();
|
||||
pongWait = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketConnect(Session session)
|
||||
{
|
||||
Future<Session> connect = null;
|
||||
try
|
||||
{
|
||||
this.session = session;
|
||||
connect = client.connect(proxyToServer, serverUri);
|
||||
connect.get();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (connect != null)
|
||||
connect.cancel(true);
|
||||
throw new WebSocketException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketPartialBinary(ByteBuffer payload, boolean fin)
|
||||
{
|
||||
try
|
||||
{
|
||||
proxyToServer.getSession().getRemote().sendPartialBytes(payload, fin);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new WebSocketException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketPartialText(String payload, boolean fin)
|
||||
{
|
||||
try
|
||||
{
|
||||
proxyToServer.getSession().getRemote().sendPartialString(payload, fin);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new WebSocketException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketPing(ByteBuffer payload)
|
||||
{
|
||||
try
|
||||
{
|
||||
proxyToServer.getSession().getRemote().sendPing(payload);
|
||||
// Block until we get pong response back from server.
|
||||
// An automatic pong will occur from the implementation after we exit from here.
|
||||
pongWait.get();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new WebSocketException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketPong(ByteBuffer payload)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Notify the other side we have received a Pong.
|
||||
proxyToServer.receivedPong();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new WebSocketException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketError(Throwable cause)
|
||||
{
|
||||
cause.printStackTrace();
|
||||
|
||||
try
|
||||
{
|
||||
// TODO: need to fail ProxyToServer as well.
|
||||
if (pongWait != null)
|
||||
pongWait.cancel(true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new WebSocketException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketClose(int statusCode, String reason)
|
||||
{
|
||||
try
|
||||
{
|
||||
Session session = proxyToServer.getSession();
|
||||
if (session != null)
|
||||
session.close(statusCode, reason);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new WebSocketException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ProxyToServer implements WebSocketPartialListener, WebSocketPingPongListener
|
||||
{
|
||||
private Session session;
|
||||
private FutureCallback pongWait;
|
||||
|
||||
public Session getSession()
|
||||
{
|
||||
return session;
|
||||
}
|
||||
|
||||
public void receivedPong()
|
||||
{
|
||||
if (pongWait != null)
|
||||
{
|
||||
pongWait.succeeded();
|
||||
pongWait = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketConnect(Session session)
|
||||
{
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketPartialBinary(ByteBuffer payload, boolean fin)
|
||||
{
|
||||
try
|
||||
{
|
||||
clientToProxy.getSession().getRemote().sendPartialBytes(payload, fin);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new WebSocketException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketPartialText(String payload, boolean fin)
|
||||
{
|
||||
try
|
||||
{
|
||||
clientToProxy.getSession().getRemote().sendPartialString(payload, fin);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new WebSocketException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketPing(ByteBuffer payload)
|
||||
{
|
||||
try
|
||||
{
|
||||
clientToProxy.getSession().getRemote().sendPing(payload);
|
||||
// Block until we get pong response back from client.
|
||||
// An automatic pong will occur from the implementation after we exit from here.
|
||||
pongWait.get();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new WebSocketException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketPong(ByteBuffer payload)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Notify the other side we have received a Pong.
|
||||
clientToProxy.receivedPong();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new WebSocketException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketError(Throwable cause)
|
||||
{
|
||||
cause.printStackTrace();
|
||||
|
||||
try
|
||||
{
|
||||
// TODO: need to fail ProxyToServer as well.
|
||||
if (pongWait != null)
|
||||
pongWait.cancel(true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new WebSocketException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketClose(int statusCode, String reason)
|
||||
{
|
||||
try
|
||||
{
|
||||
Session session = clientToProxy.getSession();
|
||||
if (session != null)
|
||||
session.close(statusCode, reason);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new WebSocketException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package org.eclipse.jetty.websocket.tests.proxy;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.websocket.server.NativeWebSocketServletContainerInitializer;
|
||||
import org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class WebSocketProxyTest
|
||||
{
|
||||
private Server server;
|
||||
private URI serverUri;
|
||||
|
||||
@BeforeEach
|
||||
public void before() throws Exception
|
||||
{
|
||||
server = new Server();
|
||||
ServerConnector connector = new ServerConnector(server);
|
||||
connector.setPort(8080); // TODO: remove...
|
||||
server.addConnector(connector);
|
||||
|
||||
ServletContextHandler contextHandler = new ServletContextHandler();
|
||||
WebSocketUpgradeFilter.configure(contextHandler);
|
||||
NativeWebSocketServletContainerInitializer.configure(contextHandler, ((context, container) ->
|
||||
{
|
||||
container.addMapping("/*", (req, resp) -> new WebSocketProxy().getWebSocketConnectionListener());
|
||||
}));
|
||||
|
||||
server.setHandler(contextHandler);
|
||||
server.start();
|
||||
serverUri = URI.create("ws://localhost:" + connector.getLocalPort());
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void after() throws Exception
|
||||
{
|
||||
server.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() throws Exception
|
||||
{
|
||||
server.join();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue