Use fingerprints to minimize transfers
This commit is contained in:
parent
f906de8127
commit
aef28e9fe9
|
|
@ -15,6 +15,7 @@ import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import org.adde0109.ambassador.Forge.ForgeConnection;
|
import org.adde0109.ambassador.Forge.ForgeConnection;
|
||||||
import org.adde0109.ambassador.Forge.ForgeHandshakeHandler;
|
import org.adde0109.ambassador.Forge.ForgeHandshakeHandler;
|
||||||
|
import org.adde0109.ambassador.Forge.ForgeHandshakeUtils;
|
||||||
import org.adde0109.ambassador.Forge.ForgeServerConnection;
|
import org.adde0109.ambassador.Forge.ForgeServerConnection;
|
||||||
import org.checkerframework.checker.index.qual.PolyUpperBound;
|
import org.checkerframework.checker.index.qual.PolyUpperBound;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
@ -53,6 +54,7 @@ public class Ambassador {
|
||||||
logger.warn("Ambassador will be disabled because of errors");
|
logger.warn("Ambassador will be disabled because of errors");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ForgeHandshakeUtils.HandshakeReceiver.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
|
|
@ -70,7 +72,7 @@ public class Ambassador {
|
||||||
if (ex != null) {
|
if (ex != null) {
|
||||||
continuation.resume();
|
continuation.resume();
|
||||||
} else {
|
} else {
|
||||||
if (Arrays.equals(msg.modListPacket,forgeConnection.get().getTransmittedHandshake().modListPacket)) {
|
if (msg.equals(forgeConnection.get().getTransmittedHandshake())) {
|
||||||
continuation.resume();
|
continuation.resume();
|
||||||
} else {
|
} else {
|
||||||
event.setResult(ServerPreConnectEvent.ServerResult.denied());
|
event.setResult(ServerPreConnectEvent.ServerResult.denied());
|
||||||
|
|
|
||||||
|
|
@ -28,77 +28,112 @@ public class ForgeHandshakeUtils {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class handshakeReceiver {
|
public static class HandshakeReceiver {
|
||||||
|
|
||||||
private int partLength;
|
private int partLength;
|
||||||
|
|
||||||
private final Logger logger;
|
public static Logger logger;
|
||||||
|
|
||||||
private int numberOfRecivedParts;
|
private int numberOfRecivedParts;
|
||||||
private byte[] recivedParts;
|
|
||||||
private int recivedBytes;
|
private int recivedBytes;
|
||||||
private final RegisteredServer forgeServer;
|
|
||||||
|
|
||||||
public handshakeReceiver(RegisteredServer server, Logger logger) {
|
private final int numberOfParts;
|
||||||
|
private final long checksum;
|
||||||
|
private final int[] separators;
|
||||||
|
private final byte[] recivedParts;
|
||||||
|
|
||||||
this.logger = logger;
|
|
||||||
this.forgeServer = server;
|
|
||||||
|
|
||||||
|
private HandshakeReceiver(ServerPing serverPing) throws Exception {
|
||||||
|
if ((serverPing.getModinfo().isEmpty()) || (!Objects.equals(serverPing.getModinfo().get().getType(), "ambassador"))) {
|
||||||
|
throw new Exception("The specified Forge server is not running the Forge-side version of this plugin!");
|
||||||
|
}
|
||||||
|
|
||||||
|
ModInfo.Mod pair = serverPing.getModinfo().orElseThrow(IllegalAccessError::new).getMods().get(0);
|
||||||
|
|
||||||
|
this.separators = Arrays.stream(pair.getVersion().substring(pair.getVersion().indexOf(":") + 1).split(":")).map(Integer::parseInt).mapToInt(x -> x).toArray();
|
||||||
|
this.checksum = Long.parseUnsignedLong((pair.getVersion().split(":")[0].split("-"))[3],16);
|
||||||
|
this.numberOfParts = Integer.parseInt((pair.getVersion().split(":")[0].split("-"))[1]);
|
||||||
|
int totalLength = Integer.parseInt((pair.getVersion().split(":")[0].split("-"))[2]);
|
||||||
|
this.recivedParts = new byte[totalLength];
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompletableFuture<CachedServerHandshake> downloadHandshake() {
|
|
||||||
|
|
||||||
|
public static CompletableFuture<CachedServerHandshake> downloadHandshake(RegisteredServer forgeServer) {
|
||||||
CompletableFuture<CachedServerHandshake> future = new CompletableFuture<CachedServerHandshake>();
|
CompletableFuture<CachedServerHandshake> future = new CompletableFuture<CachedServerHandshake>();
|
||||||
ping(future);
|
|
||||||
return future;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ping(CompletableFuture<CachedServerHandshake> future) {
|
|
||||||
forgeServer.ping().whenComplete((msg,ex) -> {
|
forgeServer.ping().whenComplete((msg,ex) -> {
|
||||||
if (ex != null) {
|
if (ex != null) {
|
||||||
future.completeExceptionally(ex);
|
future.completeExceptionally(ex);
|
||||||
} else {
|
} else {
|
||||||
onBackendPong(msg, future);
|
try {
|
||||||
|
HandshakeReceiver handshakeReceiver = new HandshakeReceiver(msg);
|
||||||
|
handshakeReceiver.handle(msg);
|
||||||
|
handshakeReceiver.downloadLoop(forgeServer,future);
|
||||||
|
} catch (Exception e) {
|
||||||
|
future.completeExceptionally(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
return future;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onBackendPong(ServerPing status, CompletableFuture<CachedServerHandshake> future) {
|
public static CompletableFuture<CachedServerHandshake> downloadHandshake(RegisteredServer forgeServer, CachedServerHandshake oldHandshake) {
|
||||||
numberOfRecivedParts++;
|
CompletableFuture<CachedServerHandshake> future = new CompletableFuture<CachedServerHandshake>();
|
||||||
if ((status.getModinfo().isEmpty()) || (!Objects.equals(status.getModinfo().get().getType(), "ambassador"))) {
|
forgeServer.ping().whenComplete((msg,ex) -> {
|
||||||
future.completeExceptionally(new Exception("The specified Forge server is not running the Forge-side version of this plugin!"));
|
if (ex != null) {
|
||||||
return;
|
future.completeExceptionally(ex);
|
||||||
}
|
} else {
|
||||||
|
try {
|
||||||
|
HandshakeReceiver handshakeReceiver = new HandshakeReceiver(msg);
|
||||||
|
if (handshakeReceiver.getChecksum() == oldHandshake.fingerprint) {
|
||||||
|
future.complete(oldHandshake);
|
||||||
|
} else {
|
||||||
|
handshakeReceiver.handle(msg);
|
||||||
|
handshakeReceiver.downloadLoop(forgeServer,future);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
future.completeExceptionally(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return future;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long getChecksum() {
|
||||||
|
return checksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void downloadLoop(RegisteredServer server, CompletableFuture<CachedServerHandshake> future) {
|
||||||
|
if (numberOfRecivedParts < numberOfParts) {
|
||||||
|
server.ping().whenComplete((msg,ex) -> {
|
||||||
|
if (ex != null) {
|
||||||
|
future.completeExceptionally(ex);
|
||||||
|
} else {
|
||||||
|
handle(msg);
|
||||||
|
downloadLoop(server, future);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
List<byte[]> packets = splitPackets(recivedParts,separators);
|
||||||
|
future.complete(new CachedServerHandshake(checksum,packets.get(0),packets.subList(1,packets.size()-1)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void handle(ServerPing status) {
|
||||||
|
numberOfRecivedParts++;
|
||||||
|
|
||||||
ModInfo.Mod pair = status.getModinfo().orElseThrow(IllegalAccessError::new).getMods().get(0);
|
ModInfo.Mod pair = status.getModinfo().orElseThrow(IllegalAccessError::new).getMods().get(0);
|
||||||
|
|
||||||
int[] values = Arrays.stream(pair.getVersion().substring(pair.getVersion().indexOf(":") + 1).split(":")).map(Integer::parseInt).mapToInt(x -> x).toArray();
|
|
||||||
|
|
||||||
int totalLength = Integer.parseInt((pair.getVersion().split(":")[0].split("-"))[2]);
|
|
||||||
int parts = Integer.parseInt((pair.getVersion().split(":")[0].split("-"))[1]);
|
|
||||||
int recivedPartNr = Integer.parseInt((pair.getVersion().split(":")[0].split("-"))[0]);
|
int recivedPartNr = Integer.parseInt((pair.getVersion().split(":")[0].split("-"))[0]);
|
||||||
|
|
||||||
logger.info("Downloaded part " + String.valueOf(numberOfRecivedParts) + " out of " + String.valueOf(parts));
|
|
||||||
|
|
||||||
if(recivedParts == null) {
|
|
||||||
recivedParts = new byte[totalLength];
|
|
||||||
partLength = pair.getId().getBytes(StandardCharsets.ISO_8859_1).length;
|
|
||||||
}
|
|
||||||
|
|
||||||
placePartInArray(pair.getId().getBytes(StandardCharsets.ISO_8859_1), recivedPartNr - 1);
|
placePartInArray(pair.getId().getBytes(StandardCharsets.ISO_8859_1), recivedPartNr - 1);
|
||||||
|
|
||||||
if (numberOfRecivedParts >= parts) {
|
logger.info("Downloaded part " + String.valueOf(numberOfRecivedParts) + " out of " + String.valueOf(numberOfParts));
|
||||||
List<byte[]> packets = splitPackets(recivedParts,values);
|
|
||||||
future.complete(new CachedServerHandshake("",packets.get(0),packets.subList(1,packets.size()-1)));
|
|
||||||
} else {
|
|
||||||
ping(future);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void placePartInArray(byte[] temp, int partNr) {
|
private void placePartInArray(byte[] temp, int partNr) {
|
||||||
int head = partNr * partLength;
|
int head = (partNr == numberOfParts-1) ? recivedParts.length-temp.length : partNr*temp.length;
|
||||||
for (byte b : temp) {
|
for (byte b : temp) {
|
||||||
recivedParts[head] = b;
|
recivedParts[head] = b;
|
||||||
head++;
|
head++;
|
||||||
|
|
@ -129,14 +164,18 @@ public class ForgeHandshakeUtils {
|
||||||
|
|
||||||
}
|
}
|
||||||
public static class CachedServerHandshake {
|
public static class CachedServerHandshake {
|
||||||
private String sessionID;
|
private long fingerprint;
|
||||||
public byte[] modListPacket;
|
public byte[] modListPacket;
|
||||||
public List<byte[]> otherPackets;
|
public List<byte[]> otherPackets;
|
||||||
|
|
||||||
private CachedServerHandshake(String sessionID,byte[] modListPacket,List<byte[]> otherPackets) {
|
private CachedServerHandshake(long fingerprint,byte[] modListPacket,List<byte[]> otherPackets) {
|
||||||
this.sessionID = sessionID;
|
this.fingerprint = fingerprint;
|
||||||
this.modListPacket = modListPacket;
|
this.modListPacket = modListPacket;
|
||||||
this.otherPackets = otherPackets;
|
this.otherPackets = otherPackets;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean equals(CachedServerHandshake cachedServerHandshake) {
|
||||||
|
return this.fingerprint == cachedServerHandshake.fingerprint;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,19 +29,15 @@ public class ForgeServerConnection {
|
||||||
|
|
||||||
public CompletableFuture<ForgeHandshakeUtils.CachedServerHandshake> getHandshake() {
|
public CompletableFuture<ForgeHandshakeUtils.CachedServerHandshake> getHandshake() {
|
||||||
CompletableFuture<ForgeHandshakeUtils.CachedServerHandshake> future;
|
CompletableFuture<ForgeHandshakeUtils.CachedServerHandshake> future;
|
||||||
if (handshakeServer.getPlayersConnected().isEmpty() || (handshake == null)) {
|
if (handshake == null) {
|
||||||
ForgeHandshakeUtils.handshakeReceiver
|
future = ForgeHandshakeUtils.HandshakeReceiver.downloadHandshake(handshakeServer);
|
||||||
receiver = new ForgeHandshakeUtils.handshakeReceiver(handshakeServer, logger);
|
|
||||||
future = receiver.downloadHandshake();
|
|
||||||
future.thenAccept(p -> {
|
|
||||||
handshake = p;
|
|
||||||
});
|
|
||||||
return future;
|
|
||||||
} else {
|
} else {
|
||||||
future = new CompletableFuture<>();
|
future = ForgeHandshakeUtils.HandshakeReceiver.downloadHandshake(handshakeServer,handshake);
|
||||||
future.complete(handshake);
|
|
||||||
return future;
|
|
||||||
}
|
}
|
||||||
|
future.thenAccept(p -> {
|
||||||
|
handshake = p;
|
||||||
|
});
|
||||||
|
return future;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handle(ServerLoginPluginMessageEvent event, Continuation continuation) {
|
public void handle(ServerLoginPluginMessageEvent event, Continuation continuation) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user