...18import org.asynchttpclient.AsyncHttpClient;19import org.asynchttpclient.ListenableFuture;20import org.asynchttpclient.ws.WebSocketListener;21import org.asynchttpclient.ws.WebSocketUpgradeHandler;22import org.openqa.selenium.remote.http.BinaryMessage;23import org.openqa.selenium.remote.http.ClientConfig;24import org.openqa.selenium.remote.http.CloseMessage;25import org.openqa.selenium.remote.http.ConnectionFailedException;26import org.openqa.selenium.remote.http.Filter;27import org.openqa.selenium.remote.http.HttpRequest;28import org.openqa.selenium.remote.http.HttpResponse;29import org.openqa.selenium.remote.http.Message;30import org.openqa.selenium.remote.http.TextMessage;31import org.openqa.selenium.remote.http.WebSocket;32import java.net.MalformedURLException;33import java.net.URI;34import java.net.URISyntaxException;35import java.net.URL;36import java.util.Objects;37import java.util.concurrent.ExecutionException;38import java.util.concurrent.atomic.AtomicReference;39import java.util.function.BiFunction;40import java.util.function.Function;41import java.util.logging.Level;42import java.util.logging.Logger;43class NettyWebSocket implements WebSocket {44 private static final Logger log = Logger.getLogger(NettyWebSocket.class.getName());45 private final org.asynchttpclient.ws.WebSocket socket;46 private NettyWebSocket(AsyncHttpClient client, org.asynchttpclient.Request request, Listener listener) {47 Objects.requireNonNull(client, "HTTP client to use must be set.");48 Objects.requireNonNull(listener, "WebSocket listener must be set.");49 try {50 URL origUrl = new URL(request.getUrl());51 URI wsUri = new URI("ws", null, origUrl.getHost(), origUrl.getPort(), origUrl.getPath(), null, null);52 ListenableFuture<org.asynchttpclient.netty.ws.NettyWebSocket> future = client.prepareGet(wsUri.toString())53 .execute(new WebSocketUpgradeHandler.Builder()54 .addWebSocketListener(new WebSocketListener() {55 @Override56 public void onOpen(org.asynchttpclient.ws.WebSocket websocket) {57 }58 @Override59 public void onClose(org.asynchttpclient.ws.WebSocket websocket, int code, String reason) {60 listener.onClose(code, reason);61 }62 @Override63 public void onError(Throwable t) {64 listener.onError(t);65 }66 @Override67 public void onTextFrame(String payload, boolean finalFragment, int rsv) {68 if (payload != null) {69 listener.onText(payload);70 }71 }72 }).build());73 socket = future.toCompletableFuture()74 .exceptionally(t -> {t.printStackTrace(); return null;})75 .get();76 if (socket == null) {77 throw new ConnectionFailedException("Unable to establish websocket connection to " + request.getUrl());78 }79 } catch (InterruptedException e) {80 Thread.currentThread().interrupt();81 log.log(Level.WARNING, "NettyWebSocket initial request interrupted", e);82 throw new ConnectionFailedException("NettyWebSocket initial request interrupted", e);83 } catch (ExecutionException | MalformedURLException | URISyntaxException e) {84 throw new ConnectionFailedException("NettyWebSocket initial request execution error", e);85 }86 }87 static BiFunction<HttpRequest, Listener, WebSocket> create(ClientConfig config, AsyncHttpClient client) {88 Filter filter = config.filter();89 Function<HttpRequest, HttpRequest> filterRequest = req -> {90 AtomicReference<HttpRequest> ref = new AtomicReference<>();91 filter.andFinally(in -> {92 ref.set(in);93 return new HttpResponse();94 }).execute(req);95 return ref.get();96 };97 return (req, listener) -> {98 HttpRequest filtered = filterRequest.apply(req);99 org.asynchttpclient.Request nettyReq = NettyMessages.toNettyRequest(config.baseUri(), filtered);100 return new NettyWebSocket(client, nettyReq, listener);101 };102 }103 @Override104 public WebSocket send(Message message) {105 if (message instanceof BinaryMessage) {106 socket.sendBinaryFrame(((BinaryMessage) message).data());107 } else if (message instanceof CloseMessage) {108 socket.sendCloseFrame(((CloseMessage) message).code(), ((CloseMessage) message).reason());109 } else if (message instanceof TextMessage) {110 socket.sendTextFrame(((TextMessage) message).text());111 }112 return this;113 }114 @Override115 public WebSocket sendText(CharSequence data) {116 socket.sendTextFrame(data.toString());117 return this;118 }119 @Override120 public void close() {...