From 5eef92055400c7e2c06d425effdf0a12521fb1f5 Mon Sep 17 00:00:00 2001 From: LAX1DUDE Date: Sun, 14 Aug 2022 01:25:13 -0700 Subject: [PATCH] implemented relay connection interface --- .../net/lax1dude/eaglercraft/RelayQuery.java | 18 +- .../eaglercraft/RelayServerSocket.java | 21 ++ .../eaglercraft/RelayWorldsQuery.java | 13 +- .../adapter/EaglerAdapterImpl2.java | 223 +++++++++++++++++- 4 files changed, 260 insertions(+), 15 deletions(-) create mode 100644 src/main/java/net/lax1dude/eaglercraft/RelayServerSocket.java diff --git a/src/main/java/net/lax1dude/eaglercraft/RelayQuery.java b/src/main/java/net/lax1dude/eaglercraft/RelayQuery.java index 63a9b85..b105491 100644 --- a/src/main/java/net/lax1dude/eaglercraft/RelayQuery.java +++ b/src/main/java/net/lax1dude/eaglercraft/RelayQuery.java @@ -11,16 +11,16 @@ public interface RelayQuery { } } - public boolean isQueryOpen(); - public boolean isQueryFailed(); - public RateLimit isQueryRateLimit(); - public void close(); + boolean isQueryOpen(); + boolean isQueryFailed(); + RateLimit isQueryRateLimit(); + void close(); - public int getVersion(); - public String getComment(); - public String getBrand(); - public long getPing(); + int getVersion(); + String getComment(); + String getBrand(); + long getPing(); - public VersionMismatch getCompatible(); + VersionMismatch getCompatible(); } diff --git a/src/main/java/net/lax1dude/eaglercraft/RelayServerSocket.java b/src/main/java/net/lax1dude/eaglercraft/RelayServerSocket.java new file mode 100644 index 0000000..066ea0d --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/RelayServerSocket.java @@ -0,0 +1,21 @@ +package net.lax1dude.eaglercraft; + +import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.RateLimit; +import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket; + +public interface RelayServerSocket { + + boolean isOpen(); + boolean isClosed(); + void close(); + + boolean isFailed(); + Throwable getException(); + + void writePacket(IPacket pkt); + + IPacket readPacket(); + + RateLimit getRatelimitHistory(); + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/RelayWorldsQuery.java b/src/main/java/net/lax1dude/eaglercraft/RelayWorldsQuery.java index f36eb59..0e15460 100644 --- a/src/main/java/net/lax1dude/eaglercraft/RelayWorldsQuery.java +++ b/src/main/java/net/lax1dude/eaglercraft/RelayWorldsQuery.java @@ -2,16 +2,19 @@ package net.lax1dude.eaglercraft; import java.util.List; +import net.lax1dude.eaglercraft.RelayQuery.VersionMismatch; import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.RateLimit; import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket07LocalWorlds.LocalWorld; public interface RelayWorldsQuery { - public boolean isQueryOpen(); - public boolean isQueryFailed(); - public RateLimit isQueryRateLimit(); - public void close(); + boolean isQueryOpen(); + boolean isQueryFailed(); + RateLimit isQueryRateLimit(); + void close(); - public List getWorlds(); + List getWorlds(); + + VersionMismatch getCompatible(); } diff --git a/src/teavm/java/net/lax1dude/eaglercraft/adapter/EaglerAdapterImpl2.java b/src/teavm/java/net/lax1dude/eaglercraft/adapter/EaglerAdapterImpl2.java index 05920cf..bab1edf 100644 --- a/src/teavm/java/net/lax1dude/eaglercraft/adapter/EaglerAdapterImpl2.java +++ b/src/teavm/java/net/lax1dude/eaglercraft/adapter/EaglerAdapterImpl2.java @@ -93,9 +93,11 @@ import net.lax1dude.eaglercraft.IntegratedServer; import net.lax1dude.eaglercraft.LocalStorageManager; import net.lax1dude.eaglercraft.PKT; import net.lax1dude.eaglercraft.RelayQuery; +import net.lax1dude.eaglercraft.RelayServerSocket; import net.lax1dude.eaglercraft.RelayWorldsQuery; import net.lax1dude.eaglercraft.ServerQuery; import net.lax1dude.eaglercraft.Voice; +import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.RateLimit; import net.lax1dude.eaglercraft.adapter.teavm.EaglercraftLANClient; import net.lax1dude.eaglercraft.adapter.teavm.EaglercraftLANServer; import net.lax1dude.eaglercraft.adapter.teavm.EaglercraftVoiceClient; @@ -2984,6 +2986,7 @@ public class EaglerAdapterImpl2 { connectionOpenedAt = 0l; sock = null; open = false; + failed = true; return; } sock = s; @@ -3245,6 +3248,7 @@ public class EaglerAdapterImpl2 { }catch(Throwable t) { sock = null; open = false; + failed = true; return; } sock = s; @@ -3382,6 +3386,11 @@ public class EaglerAdapterImpl2 { public List getWorlds() { return worlds; } + + @Override + public RelayQuery.VersionMismatch getCompatible() { + return versError; + } } @@ -3416,7 +3425,11 @@ public class EaglerAdapterImpl2 { public List getWorlds() { return new ArrayList(0); } - + + @Override + public RelayQuery.VersionMismatch getCompatible() { + return RelayQuery.VersionMismatch.COMPATIBLE; + } } public static final RelayWorldsQuery openRelayWorldsQuery(String addr) { @@ -3434,6 +3447,214 @@ public class EaglerAdapterImpl2 { return new RelayWorldsQueryImpl(addr); } + + private static class RelayServerSocketImpl implements RelayServerSocket { + + private final WebSocket sock; + private final String uri; + + private boolean open; + private boolean closed; + private boolean failed; + + private boolean hasRecievedAnyData; + + private final List exceptions = new LinkedList(); + private final List packets = new LinkedList(); + + private RelayServerSocketImpl(String uri) { + this.uri = uri; + WebSocket s = null; + try { + s = WebSocket.create(uri); + s.setBinaryType("arraybuffer"); + open = false; + closed = false; + failed = false; + }catch(Throwable t) { + exceptions.add(t); + sock = null; + open = false; + closed = true; + failed = true; + return; + } + sock = s; + sock.onOpen(new EventListener() { + @Override + public void handleEvent(MessageEvent evt) { + open = true; + } + }); + sock.onMessage(new EventListener() { + @Override + public void handleEvent(MessageEvent evt) { + if(evt.getData() != null && !isString(evt.getData())) { + hasRecievedAnyData = true; + Uint8Array buf = Uint8Array.create(evt.getDataAsArray()); + byte[] arr = new byte[buf.getLength()]; + for(int i = 0; i < arr.length; ++i) { + arr[i] = (byte)buf.get(i); + } + try { + packets.add(IPacket.readPacket(new DataInputStream(new ByteArrayInputStream(arr)))); + } catch (IOException e) { + exceptions.add(e); + System.err.println("Relay Socket Error: " + e.toString()); + e.printStackTrace(); + open = false; + failed = true; + closed = true; + sock.close(); + } + } + } + }); + sock.onClose(new EventListener() { + @Override + public void handleEvent(CloseEvent evt) { + if(!hasRecievedAnyData) { + failed = true; + } + open = false; + closed = true; + } + }); + } + + @Override + public boolean isOpen() { + return open; + } + + @Override + public boolean isClosed() { + return closed; + } + + @Override + public void close() { + if(open && sock != null) { + sock.close(); + } + open = false; + closed = true; + } + + @Override + public boolean isFailed() { + return failed; + } + + @Override + public Throwable getException() { + if(exceptions.size() > 0) { + return exceptions.remove(0); + }else { + return null; + } + } + + @Override + public void writePacket(IPacket pkt) { + try { + nativeBinarySend(sock, convertToArrayBuffer(IPacket.writePacket(pkt))); + } catch (Throwable e) { + System.err.println("Relay connection error: " + e.toString()); + e.printStackTrace(); + exceptions.add(e); + failed = true; + open = false; + closed = true; + sock.close(); + } + } + + @Override + public IPacket readPacket() { + if(packets.size() > 0) { + return packets.remove(0); + }else { + return null; + } + } + + @Override + public RateLimit getRatelimitHistory() { + if(relayQueryBlocked.containsKey(uri)) { + return RateLimit.LOCKED; + } + if(relayQueryLimited.containsKey(uri)) { + return RateLimit.BLOCKED; + } + return RateLimit.NONE; + } + + } + + private static class RelayServerSocketRatelimitDummy implements RelayServerSocket { + + private final RateLimit limit; + + private RelayServerSocketRatelimitDummy(RateLimit limit) { + this.limit = limit; + } + + @Override + public boolean isOpen() { + return false; + } + + @Override + public boolean isClosed() { + return true; + } + + @Override + public void close() { + } + + @Override + public boolean isFailed() { + return true; + } + + @Override + public Throwable getException() { + return null; + } + + @Override + public void writePacket(IPacket pkt) { + } + + @Override + public IPacket readPacket() { + return null; + } + + @Override + public RateLimit getRatelimitHistory() { + return limit; + } + + } + + public static final RelayServerSocket openRelayConnection(String addr) { + long millis = System.currentTimeMillis(); + + Long l = relayQueryBlocked.get(addr); + if(l != null && millis - l.longValue() < 60000l) { + return new RelayServerSocketRatelimitDummy(RateLimit.LOCKED); + } + + l = relayQueryLimited.get(addr); + if(l != null && millis - l.longValue() < 10000l) { + return new RelayServerSocketRatelimitDummy(RateLimit.BLOCKED); + } + + return new RelayServerSocketImpl(addr); + } private static EaglercraftLANClient rtcLANClient = null;