summary refs log tree commit diff stats
path: root/src/main/java/ganarchy/friendcode/client/I2PSamPinger.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/ganarchy/friendcode/client/I2PSamPinger.java')
-rw-r--r--src/main/java/ganarchy/friendcode/client/I2PSamPinger.java113
1 files changed, 113 insertions, 0 deletions
diff --git a/src/main/java/ganarchy/friendcode/client/I2PSamPinger.java b/src/main/java/ganarchy/friendcode/client/I2PSamPinger.java
new file mode 100644
index 0000000..96448db
--- /dev/null
+++ b/src/main/java/ganarchy/friendcode/client/I2PSamPinger.java
@@ -0,0 +1,113 @@
+package ganarchy.friendcode.client;
+
+import ganarchy.friendcode.FriendCode;
+import ganarchy.friendcode.sam.I2PSamControl;
+import ganarchy.friendcode.sam.I2PSamStreamForwarder;
+import net.minecraft.client.network.LanServerPinger;
+
+import java.io.*;
+
+public class I2PSamPinger extends LanServerPinger implements LanSendPing {
+    private final I2PSamControl sam;
+    private I2PSamStreamForwarder stream;
+    private final String port;
+    private volatile Status status = Status.IDLE;
+    private boolean hasWarned;
+    private volatile boolean stopSam;
+
+    public I2PSamPinger(String motd, String port) throws IOException {
+        super(motd, port);
+        // cba to mixin
+        this.port = port;
+        this.sam = new I2PSamControl(true);
+    }
+
+    @Override
+    public void run() {
+        try (final I2PSamControl sam = this.sam) {
+            if (!sam.connect()) {
+                this.status = Status.CONNECTION_FAILED;
+                // fall back to LAN server.
+                super.run();
+                return;
+            }
+
+            if (!sam.start()) {
+                this.status = Status.SETUP_FAILED;
+                // fall back to LAN server.
+                super.run();
+                return;
+            }
+
+            try (final I2PSamStreamForwarder stream = this.stream = sam.forwardStream(this.port)) {
+                if (!stream.connect()) {
+                    this.status = Status.CONNECTION_FAILED;
+                    super.run();
+                    return;
+                }
+
+                if (!stream.start()) {
+                    this.status = Status.SETUP_FAILED;
+                    super.run();
+                    return;
+                }
+
+                this.status = Status.RUNNING;
+                super.run();
+            } catch (IOException ignored) {
+            }
+        } catch (IOException ignored) {
+        }
+    }
+
+    @Override
+    public void friendcodeSendPing() {
+        if (this.stopSam) {
+            if (this.stream != null) {
+                try {
+                    this.stream.close();
+                } catch (IOException ignored) {
+                }
+            }
+            try {
+                this.sam.close();
+            } catch (IOException ignored) {
+            }
+            this.status = Status.CONNECTION_CLOSED;
+            this.hasWarned = true;
+            return;
+        }
+        if (this.sam.sendPing() < 0) {
+            this.status = Status.CONNECTION_CLOSED;
+        }
+        if (this.stream != null) {
+            if (this.stream.sendPing() < 0) {
+                this.status = Status.CONNECTION_CLOSED;
+            }
+        }
+        if (this.status == Status.CONNECTION_CLOSED && !this.hasWarned) {
+            this.hasWarned = true;
+            FriendCode.LOGGER.warn("Friend Code connection closed!");
+        }
+    }
+
+    public Status status() {
+        return this.status;
+    }
+
+    public String pubkey() {
+        return this.sam.pubkey();
+    }
+
+    public void stopSam() {
+        this.stopSam = true;
+    }
+
+    public enum Status {
+        IDLE,
+        RUNNING,
+        CONNECTION_FAILED,
+        SETUP_FAILED,
+        CONNECTION_CLOSED;
+    }
+}