aboutsummaryrefslogtreecommitdiff
path: root/spark-common
diff options
context:
space:
mode:
authorembeddedt <42941056+embeddedt@users.noreply.github.com>2023-05-24 11:54:08 -0400
committerembeddedt <42941056+embeddedt@users.noreply.github.com>2023-05-24 11:54:08 -0400
commitc1b0988d774a623ce785990282caf3ef48c52a46 (patch)
tree0db6c29e938332ab7ca3f63821d06c6625c59d1c /spark-common
parent67c1d7ba2f63cda64ea54e9630238e2b3a963a17 (diff)
downloadspark-c1b0988d774a623ce785990282caf3ef48c52a46.tar.gz
spark-c1b0988d774a623ce785990282caf3ef48c52a46.tar.bz2
spark-c1b0988d774a623ce785990282caf3ef48c52a46.zip
Write custom BytesocksClient implementation for Java 8
Diffstat (limited to 'spark-common')
-rw-r--r--spark-common/build.gradle3
-rw-r--r--spark-common/src/main/java/me/lucko/spark/common/SparkPlatform.java4
-rw-r--r--spark-common/src/main/java/me/lucko/spark/common/legacy/LegacyBytesocksClient.java155
-rw-r--r--spark-common/src/main/java/me/lucko/spark/common/legacy/LegacyBytesocksClientFactory.java9
4 files changed, 168 insertions, 3 deletions
diff --git a/spark-common/build.gradle b/spark-common/build.gradle
index 1713168..514c5dd 100644
--- a/spark-common/build.gradle
+++ b/spark-common/build.gradle
@@ -20,7 +20,8 @@ dependencies {
implementation 'org.ow2.asm:asm:9.1'
implementation 'net.bytebuddy:byte-buddy-agent:1.11.0'
implementation 'com.google.protobuf:protobuf-javalite:3.21.11'
- implementation 'me.lucko:bytesocks-java-client:1.0-SNAPSHOT'
+ implementation 'me.lucko:bytesocks-java-client-api:1.0-SNAPSHOT'
+ implementation 'com.neovisionaries:nv-websocket-client:2.14'
api('net.kyori:adventure-api:4.12.0') {
exclude(module: 'adventure-bom')
diff --git a/spark-common/src/main/java/me/lucko/spark/common/SparkPlatform.java b/spark-common/src/main/java/me/lucko/spark/common/SparkPlatform.java
index 84f435a..24b879a 100644
--- a/spark-common/src/main/java/me/lucko/spark/common/SparkPlatform.java
+++ b/spark-common/src/main/java/me/lucko/spark/common/SparkPlatform.java
@@ -24,7 +24,6 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import me.lucko.bytesocks.client.BytesocksClient;
-import me.lucko.bytesocks.client.BytesocksClientFactory;
import me.lucko.spark.common.activitylog.ActivityLog;
import me.lucko.spark.common.api.SparkApi;
import me.lucko.spark.common.command.Arguments;
@@ -40,6 +39,7 @@ import me.lucko.spark.common.command.modules.TickMonitoringModule;
import me.lucko.spark.common.command.sender.CommandSender;
import me.lucko.spark.common.command.tabcomplete.CompletionSupplier;
import me.lucko.spark.common.command.tabcomplete.TabCompleter;
+import me.lucko.spark.common.legacy.LegacyBytesocksClientFactory;
import me.lucko.spark.common.monitor.cpu.CpuMonitor;
import me.lucko.spark.common.monitor.memory.GarbageCollectorStatistics;
import me.lucko.spark.common.monitor.net.NetworkMonitor;
@@ -128,7 +128,7 @@ public class SparkPlatform {
String bytesocksHost = this.configuration.getString("bytesocksHost", "spark-usersockets.lucko.me");
this.bytebinClient = new BytebinClient(bytebinUrl, "spark-plugin");
- this.bytesocksClient = BytesocksClientFactory.newClient(bytesocksHost, "spark-plugin");
+ this.bytesocksClient = LegacyBytesocksClientFactory.newClient(bytesocksHost, "spark-plugin");
this.trustedKeyStore = new TrustedKeyStore(this.configuration);
this.disableResponseBroadcast = this.configuration.getBoolean("disableResponseBroadcast", false);
diff --git a/spark-common/src/main/java/me/lucko/spark/common/legacy/LegacyBytesocksClient.java b/spark-common/src/main/java/me/lucko/spark/common/legacy/LegacyBytesocksClient.java
new file mode 100644
index 0000000..e552b0e
--- /dev/null
+++ b/spark-common/src/main/java/me/lucko/spark/common/legacy/LegacyBytesocksClient.java
@@ -0,0 +1,155 @@
+package me.lucko.spark.common.legacy;
+
+import com.neovisionaries.ws.client.*;
+import me.lucko.bytesocks.client.BytesocksClient;
+
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.net.URL;
+import java.util.List;
+import java.util.Map;
+import java.util.WeakHashMap;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * Implementation of BytesocksClient that works on Java 8.
+ */
+public class LegacyBytesocksClient implements BytesocksClient {
+ /* The bytesocks urls */
+ private final String httpUrl;
+ private final String wsUrl;
+
+ /** The client user agent */
+ private final String userAgent;
+
+ LegacyBytesocksClient(String host, String userAgent) {
+
+ this.httpUrl = "https://" + host + "/";
+ this.wsUrl = "wss://" + host + "/";
+ this.userAgent = userAgent;
+ }
+
+ @Override
+ public BytesocksClient.Socket createAndConnect(BytesocksClient.Listener listener) throws Exception {
+ HttpURLConnection con = (HttpURLConnection) new URL(this.httpUrl + "create").openConnection();
+ con.setRequestMethod("GET");
+ con.setRequestProperty("User-Agent", this.userAgent);
+ if (con.getResponseCode() != 201) {
+ throw new RuntimeException("Request failed");
+ }
+
+ String channelId = null;
+
+ for(Map.Entry<String, List<String>> entry : con.getHeaderFields().entrySet()) {
+ String key = entry.getKey();
+ List<String> value = entry.getValue();
+ if(key != null && key.equalsIgnoreCase("Location") && value != null && value.size() > 0) {
+ channelId = value.get(0);
+ if(channelId != null)
+ break;
+ }
+ }
+
+ if(channelId == null) {
+ throw new RuntimeException("Location header not returned");
+ }
+
+ return connect(channelId, listener);
+ }
+
+ @Override
+ public BytesocksClient.Socket connect(String channelId, BytesocksClient.Listener listener) throws Exception {
+ WebSocketFactory factory = new WebSocketFactory()
+ .setConnectionTimeout(5000);
+ WebSocket socket = factory.createSocket(URI.create(this.wsUrl + channelId))
+ .addHeader("User-Agent", this.userAgent)
+ .addListener(new ListenerImpl(listener))
+ .connect();
+
+ return new SocketImpl(channelId, socket);
+ }
+
+ private static final class SocketImpl implements BytesocksClient.Socket {
+ private final String id;
+ private final WebSocket ws;
+ private final WeakHashMap<WebSocketFrame, CompletableFuture<?>> frameFutures = new WeakHashMap<>();
+
+ private SocketImpl(String id, WebSocket ws) {
+ this.id = id;
+ this.ws = ws;
+ this.ws.addListener(new WebSocketAdapter() {
+ @Override
+ public void onFrameSent(WebSocket websocket, WebSocketFrame frame) throws Exception {
+ synchronized (frameFutures) {
+ CompletableFuture<?> future = frameFutures.remove(frame);
+ if(future != null)
+ future.complete(null);
+ }
+ }
+
+ @Override
+ public void onFrameUnsent(WebSocket websocket, WebSocketFrame frame) throws Exception {
+ synchronized (frameFutures) {
+ CompletableFuture<?> future = frameFutures.remove(frame);
+ if(future != null)
+ future.completeExceptionally(new Exception("Failed to send frame"));
+ }
+ }
+ });
+ }
+
+ @Override
+ public String getChannelId() {
+ return this.id;
+ }
+
+ @Override
+ public boolean isOpen() {
+ return this.ws.isOpen();
+ }
+
+ @Override
+ public CompletableFuture<?> send(CharSequence msg) {
+ WebSocketFrame targetFrame = WebSocketFrame.createTextFrame(msg.toString());
+ CompletableFuture<?> future = new CompletableFuture<>();
+ synchronized (frameFutures) {
+ frameFutures.put(targetFrame, future);
+ }
+ this.ws.sendText(msg.toString());
+ return future;
+ }
+
+ @Override
+ public void close(int statusCode, String reason) {
+ this.ws.sendClose(statusCode, reason);
+ }
+ }
+
+ private static final class ListenerImpl extends WebSocketAdapter {
+ private final Listener listener;
+
+ private ListenerImpl(Listener listener) {
+ this.listener = listener;
+ }
+
+ @Override
+ public void onConnected(WebSocket websocket, Map<String, List<String>> headers) throws Exception {
+ this.listener.onOpen();
+ }
+
+ @Override
+ public void onDisconnected(WebSocket websocket, WebSocketFrame serverCloseFrame, WebSocketFrame clientCloseFrame, boolean closedByServer) throws Exception {
+ this.listener.onClose(serverCloseFrame.getCloseCode(), serverCloseFrame.getCloseReason());
+ }
+
+ @Override
+ public void onError(WebSocket websocket, WebSocketException cause) throws Exception {
+ this.listener.onError(cause);
+ }
+
+ @Override
+ public void onTextMessage(WebSocket websocket, String text) throws Exception {
+ this.listener.onText(text);
+ }
+ }
+}
diff --git a/spark-common/src/main/java/me/lucko/spark/common/legacy/LegacyBytesocksClientFactory.java b/spark-common/src/main/java/me/lucko/spark/common/legacy/LegacyBytesocksClientFactory.java
new file mode 100644
index 0000000..91f2628
--- /dev/null
+++ b/spark-common/src/main/java/me/lucko/spark/common/legacy/LegacyBytesocksClientFactory.java
@@ -0,0 +1,9 @@
+package me.lucko.spark.common.legacy;
+
+import me.lucko.bytesocks.client.BytesocksClient;
+
+public class LegacyBytesocksClientFactory {
+ public static BytesocksClient newClient(String host, String userAgent) {
+ return new LegacyBytesocksClient(host, userAgent);
+ }
+}